From 19e25b61d10e359ab1ef0778eb12c33b3f3437fb Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Sun, 5 Nov 2017 16:14:22 -0500 Subject: Parsing generics in both trait items and impl items --- src/libsyntax/parse/parser.rs | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 07956ecb5af..ad7d0d22f81 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()?; @@ -4442,6 +4443,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)> { @@ -4984,10 +5015,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()?; -- cgit 1.4.1-3-g733a5 From 6bd8ea1a6b88545e59442a3603f1b235cf57e3ba Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Thu, 9 Nov 2017 18:15:02 -0500 Subject: Added run-pass tests for associated generic types --- src/libsyntax/parse/parser.rs | 4 +-- .../construct_with_other_type.rs | 23 ++++++++++++ .../rfc1598-generic-associated-types/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 (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ad7d0d22f81..077e547e052 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4444,7 +4444,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()?; @@ -4463,7 +4463,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 00000000000..d3102360532 --- /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 00000000000..f52a77fb258 --- /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 00000000000..4ec6b418c05 --- /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 00000000000..33be5c1cc63 --- /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 00000000000..8fe7ebc1309 --- /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() {} -- cgit 1.4.1-3-g733a5 From 223d0917447b561269d102f957dc845572701b57 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Sun, 19 Nov 2017 00:18:43 -0500 Subject: Parsing where clauses correctly and documenting the grammar being parsed --- src/libsyntax/parse/parser.rs | 10 ++++++++-- .../generic-associated-types-where.rs | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 077e547e052..5a20c7f40e6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4443,6 +4443,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; @@ -4455,13 +4457,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(), @@ -5014,14 +5016,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 269e5dc26fc..cad8a96b8f0 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; -- cgit 1.4.1-3-g733a5 From 38c2a730170f94dfb458208c36be154ab5412ec7 Mon Sep 17 00:00:00 2001 From: Sunjay Varma Date: Sat, 25 Nov 2017 14:42:55 -0500 Subject: Testing and fixes --- src/libsyntax/parse/parser.rs | 2 +- .../feature-gate-generic_associated_types.rs | 9 +++++++- .../generic_associated_types_equals.rs | 18 ---------------- .../generic_associated_types_equals.stderr | 24 ---------------------- .../parse/in-trait-impl.rs | 3 ++- .../parse/in-trait.rs | 9 +++++++- 6 files changed, 19 insertions(+), 46 deletions(-) delete mode 100644 src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.rs delete mode 100644 src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5a20c7f40e6..2a80c0a05bf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1295,7 +1295,6 @@ impl<'a> Parser<'a> { let (name, node, generics) = if self.eat_keyword(keywords::Type) { let (generics, TyParam {ident, bounds, default, ..}) = self.parse_trait_item_assoc_ty(vec![])?; - self.expect(&token::Semi)?; (ident, TraitItemKind::Type(bounds, default), generics) } else if self.is_const_item() { self.expect_keyword(keywords::Const)?; @@ -4464,6 +4463,7 @@ impl<'a> Parser<'a> { } else { None }; + self.expect(&token::Semi)?; Ok((generics, TyParam { attrs: preceding_attrs.into(), diff --git a/src/test/compile-fail/feature-gate-generic_associated_types.rs b/src/test/compile-fail/feature-gate-generic_associated_types.rs index a8fc8226f31..e2643bafd38 100644 --- a/src/test/compile-fail/feature-gate-generic_associated_types.rs +++ b/src/test/compile-fail/feature-gate-generic_associated_types.rs @@ -10,8 +10,15 @@ use std::ops::Deref; -trait PointerFamily { +trait PointerFamily { type Pointer: Deref; + type Pointer2: Deref where T: Clone, U: Clone; +} + +struct Foo; +impl PointerFamily for Foo { + type Pointer = Box; + type Pointer2 = Box; } 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 deleted file mode 100644 index 6cb2aaf47ae..00000000000 --- a/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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() {} 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 deleted file mode 100644 index 152c239d8f7..00000000000 --- a/src/test/ui/rfc1598-generic-associated-types/generic_associated_types_equals.stderr +++ /dev/null @@ -1,24 +0,0 @@ -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 - 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 index bb4a285ec71..a7bdadd195d 100644 --- 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 @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Zparse-only +// compile-flags: -Z parse-only #![feature(generic_associated_types)] impl Baz for T where T: Foo { + //FIXME(sunjay): This should parse successfully type Quux<'a> = ::Bar<'a, 'static>; } 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 index 3c3f20b9ff6..fb239fb2a6e 100644 --- a/src/test/ui/rfc1598-generic-associated-types/parse/in-trait.rs +++ b/src/test/ui/rfc1598-generic-associated-types/parse/in-trait.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Zparse-only +// compile-flags: -Z parse-only #![feature(generic_associated_types)] +use std::ops::Deref; + trait Foo { type Bar<'a>; type Bar<'a, 'b>; @@ -20,6 +22,11 @@ trait Foo { type Bar<'a, 'b, T, U>; type Bar<'a, 'b, T, U,>; type Bar<'a, 'b, T: Debug, U,>; + type Bar<'a, 'b, T: Debug, U,>: Debug; + type Bar<'a, 'b, T: Debug, U,>: Deref + Into; + type Bar<'a, 'b, T: Debug, U,> where T: Deref, U: Into; + type Bar<'a, 'b, T: Debug, U,>: Deref + Into + where T: Deref, U: Into; } fn main() {} -- cgit 1.4.1-3-g733a5