Skip to content

Commit ddaebe9

Browse files
committed
Auto merge of #45904 - sunjay:gat-parser, r=nikomatsakis
Generic Associated Types Parsing & Name Resolution Hi! This PR adds parsing for generic associated types! 🎉 🎉 🎉 Tracking Issue: #44265 ## Notes For Reviewers * [x] I still need to add the stdout and stderr files to my ui tests. It takes me a *long* time to compile the compiler locally, so I'm going to add this as soon as possible in the next day or so. * [ ] My current ui tests aren't very good or very thorough. I'm reusing the `parse_generics` and `parse_where_clause` methods from elsewhere in the parser, so my changes work without being particularly complex. I'm not sure if I should duplicate all of the generics test cases for generic associated types. It might actually be appropriate to duplicate everything here, since we don't want to rely on an implementation detail in case it changes in the future. If you think so too, I'll adapt all of the generics test cases into the generic associated types test cases. * [ ] There is still more work required to make the run-pass tests pass here. In particular, we need to make the following errors disappear: ``` error[E0110]: lifetime parameters are not allowed on this type --> ./src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs:23:41 | 23 | bar: <T as StreamingIterator>::Item<'static>, | ^^^^^^^ lifetime parameter not allowed on this type ``` ``` error[E0261]: use of undeclared lifetime name `'a` --> ./src/test/run-pass/rfc1598-generic-associated-types/iterable.rs:15:47 | 15 | type Iter<'a>: Iterator<Item = Self::Item<'a>>; | ^^ undeclared lifetime ``` There is a FIXME comment in streaming_iterator. If you uncomment that line, you get the following: ``` error: expected one of `!`, `+`, `,`, `::`, or `>`, found `=` --> ./src/test/run-pass/rfc1598-generic-associated-types/streaming_iterator.rs:29:45 | 29 | fn foo<T: for<'a> StreamingIterator<Item<'a>=&'a [i32]>>(iter: T) { /* ... */ } | ^ expected one of `!`, `+`, `,`, `::`, or `>` here ``` r? @nikomatsakis
2 parents 7051754 + 9d5592b commit ddaebe9

18 files changed

+486
-80
lines changed

src/librustc_resolve/lib.rs

+70-73
Original file line numberDiff line numberDiff line change
@@ -734,8 +734,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
734734
FnKind::ItemFn(..) => {
735735
ItemRibKind
736736
}
737-
FnKind::Method(_, sig, _, _) => {
738-
MethodRibKind(!sig.decl.has_self())
737+
FnKind::Method(_, _, _, _) => {
738+
TraitOrImplItemRibKind
739739
}
740740
FnKind::Closure(_) => ClosureRibKind(node_id),
741741
};
@@ -823,12 +823,10 @@ enum RibKind<'a> {
823823
ClosureRibKind(NodeId /* func id */),
824824

825825
// We passed through an impl or trait and are now in one of its
826-
// methods. Allow references to ty params that impl or trait
826+
// methods or associated types. Allow references to ty params that impl or trait
827827
// binds. Disallow any other upvars (including other ty params that are
828828
// upvars).
829-
//
830-
// The boolean value represents the fact that this method is static or not.
831-
MethodRibKind(bool),
829+
TraitOrImplItemRibKind,
832830

833831
// We passed through an item scope. Disallow upvars.
834832
ItemRibKind,
@@ -1888,34 +1886,33 @@ impl<'a> Resolver<'a> {
18881886
for trait_item in trait_items {
18891887
this.check_proc_macro_attrs(&trait_item.attrs);
18901888

1891-
match trait_item.node {
1892-
TraitItemKind::Const(ref ty, ref default) => {
1893-
this.visit_ty(ty);
1894-
1895-
// Only impose the restrictions of
1896-
// ConstRibKind for an actual constant
1897-
// expression in a provided default.
1898-
if let Some(ref expr) = *default{
1899-
this.with_constant_rib(|this| {
1900-
this.visit_expr(expr);
1901-
});
1889+
let type_parameters = HasTypeParameters(&trait_item.generics,
1890+
TraitOrImplItemRibKind);
1891+
this.with_type_parameter_rib(type_parameters, |this| {
1892+
match trait_item.node {
1893+
TraitItemKind::Const(ref ty, ref default) => {
1894+
this.visit_ty(ty);
1895+
1896+
// Only impose the restrictions of
1897+
// ConstRibKind for an actual constant
1898+
// expression in a provided default.
1899+
if let Some(ref expr) = *default{
1900+
this.with_constant_rib(|this| {
1901+
this.visit_expr(expr);
1902+
});
1903+
}
19021904
}
1903-
}
1904-
TraitItemKind::Method(ref sig, _) => {
1905-
let type_parameters =
1906-
HasTypeParameters(&trait_item.generics,
1907-
MethodRibKind(!sig.decl.has_self()));
1908-
this.with_type_parameter_rib(type_parameters, |this| {
1905+
TraitItemKind::Method(_, _) => {
19091906
visit::walk_trait_item(this, trait_item)
1910-
});
1911-
}
1912-
TraitItemKind::Type(..) => {
1913-
this.with_type_parameter_rib(NoTypeParameters, |this| {
1907+
}
1908+
TraitItemKind::Type(..) => {
19141909
visit::walk_trait_item(this, trait_item)
1915-
});
1916-
}
1917-
TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
1918-
};
1910+
}
1911+
TraitItemKind::Macro(_) => {
1912+
panic!("unexpanded macro in resolve!")
1913+
}
1914+
};
1915+
});
19191916
}
19201917
});
19211918
});
@@ -2123,48 +2120,48 @@ impl<'a> Resolver<'a> {
21232120
for impl_item in impl_items {
21242121
this.check_proc_macro_attrs(&impl_item.attrs);
21252122
this.resolve_visibility(&impl_item.vis);
2126-
match impl_item.node {
2127-
ImplItemKind::Const(..) => {
2128-
// If this is a trait impl, ensure the const
2129-
// exists in trait
2130-
this.check_trait_item(impl_item.ident,
2131-
ValueNS,
2132-
impl_item.span,
2133-
|n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
2134-
this.with_constant_rib(|this|
2135-
visit::walk_impl_item(this, impl_item)
2136-
);
2137-
}
2138-
ImplItemKind::Method(ref sig, _) => {
2139-
// If this is a trait impl, ensure the method
2140-
// exists in trait
2141-
this.check_trait_item(impl_item.ident,
2142-
ValueNS,
2143-
impl_item.span,
2144-
|n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
2145-
2146-
// We also need a new scope for the method-
2147-
// specific type parameters.
2148-
let type_parameters =
2149-
HasTypeParameters(&impl_item.generics,
2150-
MethodRibKind(!sig.decl.has_self()));
2151-
this.with_type_parameter_rib(type_parameters, |this| {
2152-
visit::walk_impl_item(this, impl_item);
2153-
});
2154-
}
2155-
ImplItemKind::Type(ref ty) => {
2156-
// If this is a trait impl, ensure the type
2157-
// exists in trait
2158-
this.check_trait_item(impl_item.ident,
2159-
TypeNS,
2160-
impl_item.span,
2161-
|n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
21622123

2163-
this.visit_ty(ty);
2124+
// We also need a new scope for the impl item type parameters.
2125+
let type_parameters = HasTypeParameters(&impl_item.generics,
2126+
TraitOrImplItemRibKind);
2127+
this.with_type_parameter_rib(type_parameters, |this| {
2128+
use self::ResolutionError::*;
2129+
match impl_item.node {
2130+
ImplItemKind::Const(..) => {
2131+
// If this is a trait impl, ensure the const
2132+
// exists in trait
2133+
this.check_trait_item(impl_item.ident,
2134+
ValueNS,
2135+
impl_item.span,
2136+
|n, s| ConstNotMemberOfTrait(n, s));
2137+
this.with_constant_rib(|this|
2138+
visit::walk_impl_item(this, impl_item)
2139+
);
2140+
}
2141+
ImplItemKind::Method(_, _) => {
2142+
// If this is a trait impl, ensure the method
2143+
// exists in trait
2144+
this.check_trait_item(impl_item.ident,
2145+
ValueNS,
2146+
impl_item.span,
2147+
|n, s| MethodNotMemberOfTrait(n, s));
2148+
2149+
visit::walk_impl_item(this, impl_item);
2150+
}
2151+
ImplItemKind::Type(ref ty) => {
2152+
// If this is a trait impl, ensure the type
2153+
// exists in trait
2154+
this.check_trait_item(impl_item.ident,
2155+
TypeNS,
2156+
impl_item.span,
2157+
|n, s| TypeNotMemberOfTrait(n, s));
2158+
2159+
this.visit_ty(ty);
2160+
}
2161+
ImplItemKind::Macro(_) =>
2162+
panic!("unexpanded macro in resolve!"),
21642163
}
2165-
ImplItemKind::Macro(_) =>
2166-
panic!("unexpanded macro in resolve!"),
2167-
}
2164+
});
21682165
}
21692166
});
21702167
});
@@ -3100,7 +3097,7 @@ impl<'a> Resolver<'a> {
31003097
seen.insert(node_id, depth);
31013098
}
31023099
}
3103-
ItemRibKind | MethodRibKind(_) => {
3100+
ItemRibKind | TraitOrImplItemRibKind => {
31043101
// This was an attempt to access an upvar inside a
31053102
// named function item. This is not allowed, so we
31063103
// report an error.
@@ -3124,7 +3121,7 @@ impl<'a> Resolver<'a> {
31243121
Def::TyParam(..) | Def::SelfTy(..) => {
31253122
for rib in ribs {
31263123
match rib.kind {
3127-
NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
3124+
NormalRibKind | TraitOrImplItemRibKind | ClosureRibKind(..) |
31283125
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
31293126
ConstantItemRibKind => {
31303127
// Nothing to do. Continue.

src/libsyntax/feature_gate.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ declare_features! (
431431

432432
// Nested groups in `use` (RFC 2128)
433433
(active, use_nested_groups, "1.23.0", Some(44494)),
434+
435+
// generic associated types (RFC 1598)
436+
(active, generic_associated_types, "1.23.0", Some(44265)),
434437
);
435438

436439
declare_features! (
@@ -1614,9 +1617,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
16141617
gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
16151618
}
16161619
}
1617-
ast::TraitItemKind::Type(_, Some(_)) => {
1618-
gate_feature_post!(&self, associated_type_defaults, ti.span,
1619-
"associated type defaults are unstable");
1620+
ast::TraitItemKind::Type(_, ref default) => {
1621+
// We use two if statements instead of something like match guards so that both
1622+
// of these errors can be emitted if both cases apply.
1623+
if default.is_some() {
1624+
gate_feature_post!(&self, associated_type_defaults, ti.span,
1625+
"associated type defaults are unstable");
1626+
}
1627+
if ti.generics.is_parameterized() {
1628+
gate_feature_post!(&self, generic_associated_types, ti.span,
1629+
"generic associated types are unstable");
1630+
}
16201631
}
16211632
_ => {}
16221633
}
@@ -1636,6 +1647,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
16361647
gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
16371648
}
16381649
}
1650+
ast::ImplItemKind::Type(_) if ii.generics.is_parameterized() => {
1651+
gate_feature_post!(&self, generic_associated_types, ii.span,
1652+
"generic associated types are unstable");
1653+
}
16391654
_ => {}
16401655
}
16411656
visit::walk_impl_item(self, ii);

src/libsyntax/parse/parser.rs

+43-4
Original file line numberDiff line numberDiff line change
@@ -1294,9 +1294,9 @@ impl<'a> Parser<'a> {
12941294
let lo = self.span;
12951295

12961296
let (name, node, generics) = if self.eat_keyword(keywords::Type) {
1297-
let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
1298-
self.expect(&token::Semi)?;
1299-
(ident, TraitItemKind::Type(bounds, default), ast::Generics::default())
1297+
let (generics, TyParam {ident, bounds, default, ..}) =
1298+
self.parse_trait_item_assoc_ty(vec![])?;
1299+
(ident, TraitItemKind::Type(bounds, default), generics)
13001300
} else if self.is_const_item() {
13011301
self.expect_keyword(keywords::Const)?;
13021302
let ident = self.parse_ident()?;
@@ -4451,6 +4451,39 @@ impl<'a> Parser<'a> {
44514451
})
44524452
}
44534453

4454+
/// Parses the following grammar:
4455+
/// TraitItemAssocTy = Ident ["<"...">"] [":" [TyParamBounds]] ["where" ...] ["=" Ty]
4456+
fn parse_trait_item_assoc_ty(&mut self, preceding_attrs: Vec<Attribute>)
4457+
-> PResult<'a, (ast::Generics, TyParam)> {
4458+
let span = self.span;
4459+
let ident = self.parse_ident()?;
4460+
let mut generics = self.parse_generics()?;
4461+
4462+
// Parse optional colon and param bounds.
4463+
let bounds = if self.eat(&token::Colon) {
4464+
self.parse_ty_param_bounds()?
4465+
} else {
4466+
Vec::new()
4467+
};
4468+
generics.where_clause = self.parse_where_clause()?;
4469+
4470+
let default = if self.eat(&token::Eq) {
4471+
Some(self.parse_ty()?)
4472+
} else {
4473+
None
4474+
};
4475+
self.expect(&token::Semi)?;
4476+
4477+
Ok((generics, TyParam {
4478+
attrs: preceding_attrs.into(),
4479+
ident,
4480+
id: ast::DUMMY_NODE_ID,
4481+
bounds,
4482+
default,
4483+
span,
4484+
}))
4485+
}
4486+
44544487
/// Parses (possibly empty) list of lifetime and type parameters, possibly including
44554488
/// trailing comma and erroneous trailing attributes.
44564489
pub fn parse_generic_params(&mut self) -> PResult<'a, (Vec<LifetimeDef>, Vec<TyParam>)> {
@@ -4992,12 +5025,18 @@ impl<'a> Parser<'a> {
49925025
let vis = self.parse_visibility(false)?;
49935026
let defaultness = self.parse_defaultness()?;
49945027
let (name, node, generics) = if self.eat_keyword(keywords::Type) {
5028+
// This parses the grammar:
5029+
// ImplItemAssocTy = Ident ["<"...">"] ["where" ...] "=" Ty ";"
49955030
let name = self.parse_ident()?;
5031+
let mut generics = self.parse_generics()?;
5032+
generics.where_clause = self.parse_where_clause()?;
49965033
self.expect(&token::Eq)?;
49975034
let typ = self.parse_ty()?;
49985035
self.expect(&token::Semi)?;
4999-
(name, ast::ImplItemKind::Type(typ), ast::Generics::default())
5036+
(name, ast::ImplItemKind::Type(typ), generics)
50005037
} else if self.is_const_item() {
5038+
// This parses the grammar:
5039+
// ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
50015040
self.expect_keyword(keywords::Const)?;
50025041
let name = self.parse_ident()?;
50035042
self.expect(&token::Colon)?;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::Deref;
12+
13+
trait PointerFamily<U> {
14+
type Pointer<T>: Deref<Target = T>;
15+
//~^ ERROR generic associated types are unstable
16+
type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
17+
//~^ ERROR generic associated types are unstable
18+
}
19+
20+
struct Foo;
21+
impl PointerFamily<u32> for Foo {
22+
type Pointer<usize> = Box<usize>;
23+
//~^ ERROR generic associated types are unstable
24+
type Pointer2<u32> = Box<u32>;
25+
//~^ ERROR generic associated types are unstable
26+
}
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_associated_types)]
12+
13+
//FIXME(#44265): "undeclared lifetime" errors will be addressed in a follow-up PR
14+
15+
trait Foo {
16+
type Bar<'a, 'b>;
17+
}
18+
19+
trait Baz {
20+
type Quux<'a>;
21+
}
22+
23+
impl<T> Baz for T where T: Foo {
24+
type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
25+
//~^ ERROR undeclared lifetime
26+
}
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error[E0261]: use of undeclared lifetime name `'a`
2+
--> $DIR/construct_with_other_type.rs:24:37
3+
|
4+
24 | type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
5+
| ^^ undeclared lifetime
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_associated_types)]
12+
13+
trait Foo {
14+
type Bar<,>;
15+
//~^ ERROR expected one of `>`, identifier, or lifetime, found `,`
16+
}
17+
18+
fn main() {}

0 commit comments

Comments
 (0)