diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 75ccbc92be1..42ec206fc65 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2483,7 +2483,7 @@ pub struct TraitRef { #[derive(Clone, Encodable, Decodable, Debug)] pub struct PolyTraitRef { - /// The `'a` in `<'a> Foo<&'a T>`. + /// The `'a` in `for<'a> Foo<&'a T>`. pub bound_generic_params: Vec, /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 207ecd00e0c..b9e3adaac03 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -518,10 +518,20 @@ impl<'a> Parser<'a> { match arg { Some(arg) => { if self.check(&token::Colon) | self.check(&token::Eq) { - let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) { + let arg_span = arg.span(); + let (binder, ident, gen_args) = match self.get_ident_from_generic_arg(&arg) { Ok(ident_gen_args) => ident_gen_args, - Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))), + Err(()) => return Ok(Some(AngleBracketedArg::Arg(arg))), }; + if binder.is_some() { + // FIXME(compiler-errors): this could be improved by suggesting lifting + // this up to the trait, at least before this becomes real syntax. + // e.g. `Trait Assoc = Ty>` -> `for<'a> Trait` + return Err(self.struct_span_err( + arg_span, + "`for<...>` is not allowed on associated type bounds", + )); + } let kind = if self.eat(&token::Colon) { // Parse associated type constraint bound. @@ -700,18 +710,32 @@ impl<'a> Parser<'a> { Ok(Some(arg)) } + /// Given a arg inside of generics, we try to destructure it as if it were the LHS in + /// `LHS = ...`, i.e. an associated type binding. + /// This returns (optionally, if they are present) any `for<'a, 'b>` binder args, the + /// identifier, and any GAT arguments. fn get_ident_from_generic_arg( &self, - gen_arg: GenericArg, - ) -> Result<(Ident, Option), GenericArg> { - if let GenericArg::Type(ty) = &gen_arg - && let ast::TyKind::Path(qself, path) = &ty.kind - && qself.is_none() - && path.segments.len() == 1 - { - let seg = &path.segments[0]; - return Ok((seg.ident, seg.args.as_deref().cloned())); + gen_arg: &GenericArg, + ) -> Result<(Option>, Ident, Option), ()> { + if let GenericArg::Type(ty) = gen_arg { + if let ast::TyKind::Path(qself, path) = &ty.kind + && qself.is_none() + && let [seg] = path.segments.as_slice() + { + return Ok((None, seg.ident, seg.args.as_deref().cloned())); + } else if let ast::TyKind::TraitObject(bounds, ast::TraitObjectSyntax::None) = &ty.kind + && let [ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)] = + bounds.as_slice() + && let [seg] = trait_ref.trait_ref.path.segments.as_slice() + { + return Ok(( + Some(trait_ref.bound_generic_params.clone()), + seg.ident, + seg.args.as_deref().cloned(), + )); + } } - Err(gen_arg) + Err(()) } } diff --git a/src/test/ui/associated-type-bounds/binder-on-bound.rs b/src/test/ui/associated-type-bounds/binder-on-bound.rs new file mode 100644 index 00000000000..0b4b24b9820 --- /dev/null +++ b/src/test/ui/associated-type-bounds/binder-on-bound.rs @@ -0,0 +1,11 @@ +#![feature(generic_associated_types)] + +trait Trait { + type Bound<'a>; +} + +fn foo() where Trait Bound<'a> = &'a ()> { + //~^ ERROR `for<...>` is not allowed on associated type bounds +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/binder-on-bound.stderr b/src/test/ui/associated-type-bounds/binder-on-bound.stderr new file mode 100644 index 00000000000..3432672e03c --- /dev/null +++ b/src/test/ui/associated-type-bounds/binder-on-bound.stderr @@ -0,0 +1,8 @@ +error: `for<...>` is not allowed on associated type bounds + --> $DIR/binder-on-bound.rs:7:22 + | +LL | fn foo() where Trait Bound<'a> = &'a ()> { + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error +