From aa868afc84a89817ff243d715935b855d9932851 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Sun, 5 Nov 2017 16:14:22 -0500 Subject: [PATCH 01/12] Parsing generics in both trait items and impl items --- src/libsyntax/parse/parser.rs | 39 ++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c1819307928ba..0259f3b089ab8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1293,9 +1293,10 @@ impl<'a> Parser<'a> { let lo = self.span; let (name, node, generics) = if self.eat_keyword(keywords::Type) { - let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?; + let (generics, TyParam {ident, bounds, default, ..}) = + self.parse_trait_item_assoc_ty(vec![])?; self.expect(&token::Semi)?; - (ident, TraitItemKind::Type(bounds, default), ast::Generics::default()) + (ident, TraitItemKind::Type(bounds, default), generics) } else if self.is_const_item() { self.expect_keyword(keywords::Const)?; let ident = self.parse_ident()?; @@ -4433,6 +4434,36 @@ impl<'a> Parser<'a> { }) } + fn parse_trait_item_assoc_ty(&mut self, preceding_attrs: Vec) + -> PResult<'a, (Generics, TyParam)> { + let span = self.span; + let ident = self.parse_ident()?; + let mut generics = self.parse_generics()?; + + // Parse optional colon and param bounds. + let bounds = if self.eat(&token::Colon) { + self.parse_ty_param_bounds()? + } else { + Vec::new() + }; + + let default = if self.eat(&token::Eq) { + Some(self.parse_ty()?) + } else { + None + }; + generics.where_clause = self.parse_where_clause()?; + + Ok((Generics, TyParam { + attrs: preceding_attrs.into(), + ident, + id: ast::DUMMY_NODE_ID, + bounds, + default, + span, + })) + } + /// Parses (possibly empty) list of lifetime and type parameters, possibly including /// trailing comma and erroneous trailing attributes. pub fn parse_generic_params(&mut self) -> PResult<'a, (Vec, Vec)> { @@ -4975,10 +5006,12 @@ impl<'a> Parser<'a> { let defaultness = self.parse_defaultness()?; let (name, node, generics) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; + let mut generics = self.parse_generics()?; self.expect(&token::Eq)?; let typ = self.parse_ty()?; + generics.where_clause = self.parse_where_clause()?; self.expect(&token::Semi)?; - (name, ast::ImplItemKind::Type(typ), ast::Generics::default()) + (name, ast::ImplItemKind::Type(typ), generics) } else if self.is_const_item() { self.expect_keyword(keywords::Const)?; let name = self.parse_ident()?; From 789aaa053b3f2c8e16281e5ba0e20bc64ac40df4 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Thu, 9 Nov 2017 18:15:02 -0500 Subject: [PATCH 02/12] Added run-pass tests for associated generic types --- src/libsyntax/parse/parser.rs | 4 +- .../construct_with_other_type.rs | 23 ++++++++++ .../iterable.rs | 18 ++++++++ .../pointer_family.rs | 42 +++++++++++++++++++ .../streaming_iterator.rs | 29 +++++++++++++ .../rfc1598-generic-associated-types/where.rs | 30 +++++++++++++ 6 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs create mode 100644 src/test/run-pass/rfc1598-generic-associated-types/iterable.rs create mode 100644 src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs create mode 100644 src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs create mode 100644 src/test/run-pass/rfc1598-generic-associated-types/where.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0259f3b089ab8..40a8fcdfa0e0e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4435,7 +4435,7 @@ impl<'a> Parser<'a> { } fn parse_trait_item_assoc_ty(&mut self, preceding_attrs: Vec) - -> PResult<'a, (Generics, TyParam)> { + -> PResult<'a, (ast::Generics, TyParam)> { let span = self.span; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -4454,7 +4454,7 @@ impl<'a> Parser<'a> { }; generics.where_clause = self.parse_where_clause()?; - Ok((Generics, TyParam { + Ok((generics, TyParam { attrs: preceding_attrs.into(), ident, id: ast::DUMMY_NODE_ID, diff --git a/src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs b/src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs new file mode 100644 index 0000000000000..d31023605326d --- /dev/null +++ b/src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs @@ -0,0 +1,23 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + type Bar<'a, 'b>; +} + +trait Baz { + type Quux<'a>; +} + +impl Baz for T where T: Foo { + type Quux<'a> = ::Bar<'a, 'static>; +} + +fn main() {} diff --git a/src/test/run-pass/rfc1598-generic-associated-types/iterable.rs b/src/test/run-pass/rfc1598-generic-associated-types/iterable.rs new file mode 100644 index 0000000000000..f52a77fb25812 --- /dev/null +++ b/src/test/run-pass/rfc1598-generic-associated-types/iterable.rs @@ -0,0 +1,18 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Iterable { + type Item<'a>; + type Iter<'a>: Iterator>; + + fn iter<'a>(&'a self) -> Self::Iter<'a>; +} + +fn main() {} diff --git a/src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs b/src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs new file mode 100644 index 0000000000000..4ec6b418c058a --- /dev/null +++ b/src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs @@ -0,0 +1,42 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::rc::Rc; +use std::sync::Arc; +use std::ops::Deref; + +trait PointerFamily { + type Pointer: Deref; + fn new(value: T) -> Self::Pointer; +} + +struct ArcFamily; + +impl PointerFamily for ArcFamily { + type Pointer = Arc; + fn new(value: T) -> Self::Pointer { + Arc::new(value) + } +} + +struct RcFamily; + +impl PointerFamily for RcFamily { + type Pointer = Rc; + fn new(value: T) -> Self::Pointer { + Rc::new(value) + } +} + +struct Foo { + bar: P::Pointer, +} + +fn main() {} diff --git a/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs b/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs new file mode 100644 index 0000000000000..33be5c1cc6364 --- /dev/null +++ b/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs @@ -0,0 +1,29 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt::Display; + +trait StreamingIterator { + type Item<'a>; + // Applying the lifetime parameter `'a` to `Self::Item` inside the trait. + fn next<'a>(&'a self) -> Option>; +} + +struct Foo { + // Applying a concrete lifetime to the constructor outside the trait. + bar: ::Item<'static>, +} + +// Users can bound parameters by the type constructed by that trait's associated type constructor +// of a trait using HRTB. Both type equality bounds and trait bounds of this kind are valid: +//fn foo StreamingIterator=&'a [i32]>>(iter: T) { ... } +fn foo(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ } + +fn main() {} diff --git a/src/test/run-pass/rfc1598-generic-associated-types/where.rs b/src/test/run-pass/rfc1598-generic-associated-types/where.rs new file mode 100644 index 0000000000000..8fe7ebc13090c --- /dev/null +++ b/src/test/run-pass/rfc1598-generic-associated-types/where.rs @@ -0,0 +1,30 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checking the interaction with this other feature +#![feature(associated_type_defaults)] + +use std::fmt::{Display, Debug}; + +trait Foo { + type Assoc where Self: Sized; + type Assoc2 where T: Display; + type WithDefault = Iterator where T: Debug; +} + +struct Bar; + +impl Foo for Bar { + type Assoc = usize; + type Assoc2 = Vec; + type WithDefault<'a, T> = &'a Iterator; +} + +fn main() {} From 4e00e0a9c03451af7a2be89eb4dbaab9e9943f30 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Thu, 9 Nov 2017 21:40:14 -0500 Subject: [PATCH 03/12] Adding feature gate --- src/libsyntax/feature_gate.rs | 8 ++++++++ .../compile-fail/generic-associated-types.rs | 17 +++++++++++++++++ .../construct_with_other_type.rs | 2 ++ .../iterable.rs | 2 ++ .../pointer_family.rs | 2 ++ .../streaming_iterator.rs | 2 ++ .../rfc1598-generic-associated-types/where.rs | 2 ++ 7 files changed, 35 insertions(+) create mode 100644 src/test/compile-fail/generic-associated-types.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 5c7450baa2f7d..7c6b5efe52a08 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -420,6 +420,8 @@ declare_features! ( // #![wasm_import_memory] attribute (active, wasm_import_memory, "1.22.0", None), + // generic associated types (RFC 1598) + (active, generic_associated_types, "1.23.0", Some(44265)), ); declare_features! ( @@ -1611,6 +1613,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, associated_type_defaults, ti.span, "associated type defaults are unstable"); } + _ if ti.generics.is_parameterized() => { + gate_feature_post!(&self, generic_associated_types, ti.span, "generic associated types are unstable"); + } _ => {} } visit::walk_trait_item(self, ti); @@ -1629,6 +1634,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } + _ if ii.generics.is_parameterized() => { + gate_feature_post!(&self, generic_associated_types, ii.span, "generic associated types are unstable"); + } _ => {} } visit::walk_impl_item(self, ii); diff --git a/src/test/compile-fail/generic-associated-types.rs b/src/test/compile-fail/generic-associated-types.rs new file mode 100644 index 0000000000000..a8fc8226f316a --- /dev/null +++ b/src/test/compile-fail/generic-associated-types.rs @@ -0,0 +1,17 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +trait PointerFamily { + type Pointer: Deref; +} + +fn main() {} diff --git a/src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs b/src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs index d31023605326d..81475c6888d3f 100644 --- a/src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs +++ b/src/test/run-pass/rfc1598-generic-associated-types/construct_with_other_type.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(generic_associated_types)] + trait Foo { type Bar<'a, 'b>; } diff --git a/src/test/run-pass/rfc1598-generic-associated-types/iterable.rs b/src/test/run-pass/rfc1598-generic-associated-types/iterable.rs index f52a77fb25812..40b1d1312927c 100644 --- a/src/test/run-pass/rfc1598-generic-associated-types/iterable.rs +++ b/src/test/run-pass/rfc1598-generic-associated-types/iterable.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(generic_associated_types)] + trait Iterable { type Item<'a>; type Iter<'a>: Iterator>; diff --git a/src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs b/src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs index 4ec6b418c058a..0d0f1396969f3 100644 --- a/src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs +++ b/src/test/run-pass/rfc1598-generic-associated-types/pointer_family.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(generic_associated_types)] + use std::rc::Rc; use std::sync::Arc; use std::ops::Deref; diff --git a/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs b/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs index 33be5c1cc6364..fd476e2592dc4 100644 --- a/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs +++ b/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(generic_associated_types)] + use std::fmt::Display; trait StreamingIterator { diff --git a/src/test/run-pass/rfc1598-generic-associated-types/where.rs b/src/test/run-pass/rfc1598-generic-associated-types/where.rs index 8fe7ebc13090c..269e5dc26fc8e 100644 --- a/src/test/run-pass/rfc1598-generic-associated-types/where.rs +++ b/src/test/run-pass/rfc1598-generic-associated-types/where.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(generic_associated_types)] + // Checking the interaction with this other feature #![feature(associated_type_defaults)] From ca454e8f84e5d807ef99385e205d6fe0de127377 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Thu, 9 Nov 2017 22:21:53 -0500 Subject: [PATCH 04/12] Fixed tidy errors --- src/libsyntax/feature_gate.rs | 6 ++++-- ...ed-types.rs => feature-gate-generic_associated_types.rs} | 0 2 files changed, 4 insertions(+), 2 deletions(-) rename src/test/compile-fail/{generic-associated-types.rs => feature-gate-generic_associated_types.rs} (100%) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7c6b5efe52a08..e97fefb39da69 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1614,7 +1614,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "associated type defaults are unstable"); } _ if ti.generics.is_parameterized() => { - gate_feature_post!(&self, generic_associated_types, ti.span, "generic associated types are unstable"); + gate_feature_post!(&self, generic_associated_types, ti.span, + "generic associated types are unstable"); } _ => {} } @@ -1635,7 +1636,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } _ if ii.generics.is_parameterized() => { - gate_feature_post!(&self, generic_associated_types, ii.span, "generic associated types are unstable"); + gate_feature_post!(&self, generic_associated_types, ii.span, + "generic associated types are unstable"); } _ => {} } diff --git a/src/test/compile-fail/generic-associated-types.rs b/src/test/compile-fail/feature-gate-generic_associated_types.rs similarity index 100% rename from src/test/compile-fail/generic-associated-types.rs rename to src/test/compile-fail/feature-gate-generic_associated_types.rs From db3ecd9c5f6d8e36e49fe24fc6e03d5e8cdc7d40 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Thu, 9 Nov 2017 22:42:29 -0500 Subject: [PATCH 05/12] More testing for generic associated types parsing --- ...e.rs => generic-associated-types-where.rs} | 0 .../streaming_iterator.rs | 3 +- .../whitespace-before-generics.rs | 35 +++++++++++++++++++ .../empty_generics.rs | 17 +++++++++ .../generic_associated_types_equals.rs | 18 ++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) rename src/test/run-pass/rfc1598-generic-associated-types/{where.rs => generic-associated-types-where.rs} (100%) create mode 100644 src/test/run-pass/rfc1598-generic-associated-types/whitespace-before-generics.rs create mode 100644 src/test/ui/rfc1598-generic-associated-types/empty_generics.rs create mode 100644 src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.rs diff --git a/src/test/run-pass/rfc1598-generic-associated-types/where.rs b/src/test/run-pass/rfc1598-generic-associated-types/generic-associated-types-where.rs similarity index 100% rename from src/test/run-pass/rfc1598-generic-associated-types/where.rs rename to src/test/run-pass/rfc1598-generic-associated-types/generic-associated-types-where.rs diff --git a/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs b/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs index fd476e2592dc4..58ec14d10756e 100644 --- a/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs +++ b/src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs @@ -25,7 +25,8 @@ struct Foo { // Users can bound parameters by the type constructed by that trait's associated type constructor // of a trait using HRTB. Both type equality bounds and trait bounds of this kind are valid: -//fn foo StreamingIterator=&'a [i32]>>(iter: T) { ... } +//FIXME(sunjay): This next line should parse and be valid +//fn foo StreamingIterator=&'a [i32]>>(iter: T) { /* ... */ } fn foo(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ } fn main() {} diff --git a/src/test/run-pass/rfc1598-generic-associated-types/whitespace-before-generics.rs b/src/test/run-pass/rfc1598-generic-associated-types/whitespace-before-generics.rs new file mode 100644 index 0000000000000..892a925f3d569 --- /dev/null +++ b/src/test/run-pass/rfc1598-generic-associated-types/whitespace-before-generics.rs @@ -0,0 +1,35 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_associated_types)] + +// Checking the interaction with this other feature +#![feature(associated_type_defaults)] + +use std::fmt::{Display, Debug}; + +trait Foo { + type Assoc where Self: Sized; + type Assoc2 where T: Display; + type WithDefault = Iterator where T: Debug; + // No generics on this associated type + type NoGenerics; +} + +struct Bar; + +impl Foo for Bar { + type Assoc = usize; + type Assoc2 = Vec; + type WithDefault<'a, T> = &'a Iterator; + type NoGenerics = f64; +} + +fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/empty_generics.rs b/src/test/ui/rfc1598-generic-associated-types/empty_generics.rs new file mode 100644 index 0000000000000..a80875d28b3a7 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/empty_generics.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_associated_types)] + +trait Foo { + type Bar<,>; +} + +fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.rs b/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.rs new file mode 100644 index 0000000000000..6cb2aaf47ae37 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_associated_types)] + +trait Foo { + type Bar; + type X where T = f64; +} + +fn main() {} From 5691b318e34c22f3a7035dfde5b9097439db5195 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Thu, 9 Nov 2017 23:52:44 -0500 Subject: [PATCH 06/12] Added stderr files for ui tests --- .../empty_generics.stderr | 8 +++++++ .../generic_associated_types_equals.stderr | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr create mode 100644 src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.stderr diff --git a/src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr b/src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr new file mode 100644 index 0000000000000..de0c1e310bcb8 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr @@ -0,0 +1,8 @@ +error: expected one of `>`, identifier, or lifetime, found `,` + --> $DIR/empty_generics.rs:14:14 + | +14 | type Bar<,>; + | ^ expected one of `>`, identifier, or lifetime here + +error: aborting due to previous error + diff --git a/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.stderr b/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.stderr new file mode 100644 index 0000000000000..152c239d8f749 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.stderr @@ -0,0 +1,24 @@ +error: equality constraints are not yet supported in where clauses (#20041) + --> $DIR/generic_associated_types_equals.rs:15:21 + | +15 | type X where T = f64; + | ^^^^^^^ + +error[E0412]: cannot find type `T` in this scope + --> $DIR/generic_associated_types_equals.rs:15:21 + | +15 | type X where T = f64; + | ^ not found in this scope + +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions. + --> $DIR/generic_associated_types_equals.rs:14:14 + | +14 | type Bar; + | ^ + | + = note: #[deny(invalid_type_param_default)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + +error: aborting due to 3 previous errors + From 493e813ea53fc168d2680b9649db4b1c2e245b63 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 14 Nov 2017 12:17:28 -0500 Subject: [PATCH 07/12] demonstrate how we can write "successful parse" tests quite easily --- .../parse/in-trait-impl.rs | 19 ++++++++++++++ .../parse/in-trait.rs | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/ui/rfc1598-generic-associated-types/parse/in-trait-impl.rs create mode 100644 src/test/ui/rfc1598-generic-associated-types/parse/in-trait.rs diff --git a/src/test/ui/rfc1598-generic-associated-types/parse/in-trait-impl.rs b/src/test/ui/rfc1598-generic-associated-types/parse/in-trait-impl.rs new file mode 100644 index 0000000000000..bb4a285ec71ea --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/parse/in-trait-impl.rs @@ -0,0 +1,19 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Zparse-only + +#![feature(generic_associated_types)] + +impl Baz for T where T: Foo { + type Quux<'a> = ::Bar<'a, 'static>; +} + +fn main() {} diff --git a/src/test/ui/rfc1598-generic-associated-types/parse/in-trait.rs b/src/test/ui/rfc1598-generic-associated-types/parse/in-trait.rs new file mode 100644 index 0000000000000..3c3f20b9ff601 --- /dev/null +++ b/src/test/ui/rfc1598-generic-associated-types/parse/in-trait.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Zparse-only + +#![feature(generic_associated_types)] + +trait Foo { + type Bar<'a>; + type Bar<'a, 'b>; + type Bar<'a, 'b,>; + type Bar<'a, 'b, T>; + type Bar<'a, 'b, T, U>; + type Bar<'a, 'b, T, U,>; + type Bar<'a, 'b, T: Debug, U,>; +} + +fn main() {} From d480a7538a0cc4758de1c6cbe45757b6f0953302 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Sun, 19 Nov 2017 00:00:15 -0500 Subject: [PATCH 08/12] Specifically gating generic_associated_types feature on associated Type declarations --- src/libsyntax/feature_gate.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e97fefb39da69..05b8d35130152 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1609,13 +1609,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } } - ast::TraitItemKind::Type(_, Some(_)) => { - gate_feature_post!(&self, associated_type_defaults, ti.span, - "associated type defaults are unstable"); - } - _ if ti.generics.is_parameterized() => { - gate_feature_post!(&self, generic_associated_types, ti.span, - "generic associated types are unstable"); + ast::TraitItemKind::Type(_, default) => { + // We use two if statements instead of something like match guards so that both + // of these errors can be emitted if both cases apply. + if default.is_some() { + gate_feature_post!(&self, associated_type_defaults, ti.span, + "associated type defaults are unstable"); + } + if ti.generics.is_parameterized() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "generic associated types are unstable"); + } } _ => {} } @@ -1635,7 +1639,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } - _ if ii.generics.is_parameterized() => { + ast::ImplItemKind::Type(_) if ii.generics.is_parameterized() => { gate_feature_post!(&self, generic_associated_types, ii.span, "generic associated types are unstable"); } From b0124952ff69096ead1b51c848b954c52bfbdb84 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Sun, 19 Nov 2017 00:18:43 -0500 Subject: [PATCH 09/12] Parsing where clauses correctly and documenting the grammar being parsed --- src/libsyntax/feature_gate.rs | 1 + src/libsyntax/parse/parser.rs | 10 ++++++++-- .../generic-associated-types-where.rs | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 05b8d35130152..73023fc19e239 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -420,6 +420,7 @@ declare_features! ( // #![wasm_import_memory] attribute (active, wasm_import_memory, "1.22.0", None), + // generic associated types (RFC 1598) (active, generic_associated_types, "1.23.0", Some(44265)), ); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 40a8fcdfa0e0e..01b462e898164 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4434,6 +4434,8 @@ impl<'a> Parser<'a> { }) } + /// Parses the following grammar: + /// TraitItemAssocTy = Ident ["<"...">"] [":" [TyParamBounds]] ["where" ...] ["=" Ty] fn parse_trait_item_assoc_ty(&mut self, preceding_attrs: Vec) -> PResult<'a, (ast::Generics, TyParam)> { let span = self.span; @@ -4446,13 +4448,13 @@ impl<'a> Parser<'a> { } else { Vec::new() }; + generics.where_clause = self.parse_where_clause()?; let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; - generics.where_clause = self.parse_where_clause()?; Ok((generics, TyParam { attrs: preceding_attrs.into(), @@ -5005,14 +5007,18 @@ impl<'a> Parser<'a> { let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node, generics) = if self.eat_keyword(keywords::Type) { + // This parses the grammar: + // ImplItemAssocTy = Ident ["<"...">"] ["where" ...] "=" Ty ";" let name = self.parse_ident()?; let mut generics = self.parse_generics()?; + generics.where_clause = self.parse_where_clause()?; self.expect(&token::Eq)?; let typ = self.parse_ty()?; - generics.where_clause = self.parse_where_clause()?; self.expect(&token::Semi)?; (name, ast::ImplItemKind::Type(typ), generics) } else if self.is_const_item() { + // This parses the grammar: + // ImplItemConst = "const" Ident ":" Ty "=" Expr ";" self.expect_keyword(keywords::Const)?; let name = self.parse_ident()?; self.expect(&token::Colon)?; diff --git a/src/test/run-pass/rfc1598-generic-associated-types/generic-associated-types-where.rs b/src/test/run-pass/rfc1598-generic-associated-types/generic-associated-types-where.rs index 269e5dc26fc8e..cad8a96b8f081 100644 --- a/src/test/run-pass/rfc1598-generic-associated-types/generic-associated-types-where.rs +++ b/src/test/run-pass/rfc1598-generic-associated-types/generic-associated-types-where.rs @@ -18,7 +18,7 @@ use std::fmt::{Display, Debug}; trait Foo { type Assoc where Self: Sized; type Assoc2 where T: Display; - type WithDefault = Iterator where T: Debug; + type WithDefault where T: Debug = Iterator; } struct Bar; From 28fd354fc95bffed576ad2f078779b952bce6e00 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Tue, 21 Nov 2017 02:30:39 -0500 Subject: [PATCH 10/12] Preventing moving out of the trait item kind --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 73023fc19e239..83c7efc3d7ab3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1610,7 +1610,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } } - ast::TraitItemKind::Type(_, default) => { + ast::TraitItemKind::Type(_, ref default) => { // We use two if statements instead of something like match guards so that both // of these errors can be emitted if both cases apply. if default.is_some() { From d43e97250fb0fab1dd80f0350d86106466382732 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Tue, 21 Nov 2017 01:46:55 -0500 Subject: [PATCH 11/12] Adding type paramter ribs for generic associated types --- src/librustc_resolve/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8207057fd0aae..ace125ab38aef 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1895,7 +1895,9 @@ impl<'a> Resolver<'a> { }); } TraitItemKind::Type(..) => { - this.with_type_parameter_rib(NoTypeParameters, |this| { + let type_parameters = HasTypeParameters(&trait_item.generics, + ItemRibKind); + this.with_type_parameter_rib(type_parameters, |this| { visit::walk_trait_item(this, trait_item) }); } @@ -2121,7 +2123,13 @@ impl<'a> Resolver<'a> { impl_item.span, |n, s| ResolutionError::TypeNotMemberOfTrait(n, s)); - this.visit_ty(ty); + // We also need a new scope for the associated type + // specific type parameters. + let type_parameters = + HasTypeParameters(&impl_item.generics, ItemRibKind); + this.with_type_parameter_rib(type_parameters, |this| { + this.visit_ty(ty); + }); } ImplItemKind::Macro(_) => panic!("unexpanded macro in resolve!"), From d9879bfbcaaf0bd0acde6e0102c8534c16a8d531 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Wed, 22 Nov 2017 13:15:05 -0500 Subject: [PATCH 12/12] Renaming MethodRibKind to TraitOrImplItemRibKind and removing its field which was never used. Lifting the HasTypeParameters rib to all trait item kinds and all impl item kinds --- src/librustc_resolve/lib.rs | 149 +++++++++++++++++------------------- 1 file changed, 69 insertions(+), 80 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ace125ab38aef..21ed2ab017ee2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -722,8 +722,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { FnKind::ItemFn(..) => { ItemRibKind } - FnKind::Method(_, sig, _, _) => { - MethodRibKind(!sig.decl.has_self()) + FnKind::Method(_, _, _, _) => { + TraitOrImplItemRibKind } FnKind::Closure(_) => ClosureRibKind(node_id), }; @@ -811,12 +811,10 @@ enum RibKind<'a> { ClosureRibKind(NodeId /* func id */), // We passed through an impl or trait and are now in one of its - // methods. Allow references to ty params that impl or trait + // methods or associated types. Allow references to ty params that impl or trait // binds. Disallow any other upvars (including other ty params that are // upvars). - // - // The boolean value represents the fact that this method is static or not. - MethodRibKind(bool), + TraitOrImplItemRibKind, // We passed through an item scope. Disallow upvars. ItemRibKind, @@ -1873,36 +1871,33 @@ impl<'a> Resolver<'a> { for trait_item in trait_items { this.check_proc_macro_attrs(&trait_item.attrs); - match trait_item.node { - TraitItemKind::Const(ref ty, ref default) => { - this.visit_ty(ty); - - // Only impose the restrictions of - // ConstRibKind for an actual constant - // expression in a provided default. - if let Some(ref expr) = *default{ - this.with_constant_rib(|this| { - this.visit_expr(expr); - }); + let type_parameters = HasTypeParameters(&trait_item.generics, + TraitOrImplItemRibKind); + this.with_type_parameter_rib(type_parameters, |this| { + match trait_item.node { + TraitItemKind::Const(ref ty, ref default) => { + this.visit_ty(ty); + + // Only impose the restrictions of + // ConstRibKind for an actual constant + // expression in a provided default. + if let Some(ref expr) = *default{ + this.with_constant_rib(|this| { + this.visit_expr(expr); + }); + } } - } - TraitItemKind::Method(ref sig, _) => { - let type_parameters = - HasTypeParameters(&trait_item.generics, - MethodRibKind(!sig.decl.has_self())); - this.with_type_parameter_rib(type_parameters, |this| { + TraitItemKind::Method(_, _) => { visit::walk_trait_item(this, trait_item) - }); - } - TraitItemKind::Type(..) => { - let type_parameters = HasTypeParameters(&trait_item.generics, - ItemRibKind); - this.with_type_parameter_rib(type_parameters, |this| { + } + TraitItemKind::Type(..) => { visit::walk_trait_item(this, trait_item) - }); - } - TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"), - }; + } + TraitItemKind::Macro(_) => { + panic!("unexpanded macro in resolve!") + } + }; + }); } }); }); @@ -2086,54 +2081,48 @@ impl<'a> Resolver<'a> { for impl_item in impl_items { this.check_proc_macro_attrs(&impl_item.attrs); this.resolve_visibility(&impl_item.vis); - match impl_item.node { - ImplItemKind::Const(..) => { - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item(impl_item.ident, - ValueNS, - impl_item.span, - |n, s| ResolutionError::ConstNotMemberOfTrait(n, s)); - this.with_constant_rib(|this| - visit::walk_impl_item(this, impl_item) - ); - } - ImplItemKind::Method(ref sig, _) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident, - ValueNS, - impl_item.span, - |n, s| ResolutionError::MethodNotMemberOfTrait(n, s)); - - // We also need a new scope for the method- - // specific type parameters. - let type_parameters = - HasTypeParameters(&impl_item.generics, - MethodRibKind(!sig.decl.has_self())); - this.with_type_parameter_rib(type_parameters, |this| { + + // We also need a new scope for the impl item type parameters. + let type_parameters = HasTypeParameters(&impl_item.generics, + TraitOrImplItemRibKind); + this.with_type_parameter_rib(type_parameters, |this| { + use self::ResolutionError::*; + match impl_item.node { + ImplItemKind::Const(..) => { + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item(impl_item.ident, + ValueNS, + impl_item.span, + |n, s| ConstNotMemberOfTrait(n, s)); + this.with_constant_rib(|this| + visit::walk_impl_item(this, impl_item) + ); + } + ImplItemKind::Method(_, _) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident, + ValueNS, + impl_item.span, + |n, s| MethodNotMemberOfTrait(n, s)); + visit::walk_impl_item(this, impl_item); - }); - } - ImplItemKind::Type(ref ty) => { - // If this is a trait impl, ensure the type - // exists in trait - this.check_trait_item(impl_item.ident, - TypeNS, - impl_item.span, - |n, s| ResolutionError::TypeNotMemberOfTrait(n, s)); - - // We also need a new scope for the associated type - // specific type parameters. - let type_parameters = - HasTypeParameters(&impl_item.generics, ItemRibKind); - this.with_type_parameter_rib(type_parameters, |this| { + } + ImplItemKind::Type(ref ty) => { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item(impl_item.ident, + TypeNS, + impl_item.span, + |n, s| TypeNotMemberOfTrait(n, s)); + this.visit_ty(ty); - }); + } + ImplItemKind::Macro(_) => + panic!("unexpanded macro in resolve!"), } - ImplItemKind::Macro(_) => - panic!("unexpanded macro in resolve!"), - } + }); } }); }); @@ -3023,7 +3012,7 @@ impl<'a> Resolver<'a> { seen.insert(node_id, depth); } } - ItemRibKind | MethodRibKind(_) => { + ItemRibKind | TraitOrImplItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -3047,7 +3036,7 @@ impl<'a> Resolver<'a> { Def::TyParam(..) | Def::SelfTy(..) => { for rib in ribs { match rib.kind { - NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) | + NormalRibKind | TraitOrImplItemRibKind | ClosureRibKind(..) | ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind | ConstantItemRibKind => { // Nothing to do. Continue.