diff options
| author | Michael Goulet <michael@errs.io> | 2022-04-06 23:08:22 -0700 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2022-04-10 16:41:15 -0700 |
| commit | b65265b5e1c70d8c1685efc3a899ce3d89362ad7 (patch) | |
| tree | 9845440efb6dbf2aa45d4eea497af03c3c3e959c /compiler/rustc_parse/src | |
| parent | 1f7fb6413d6d6c0c929b223e478e44c3db991b03 (diff) | |
| download | rust-b65265b5e1c70d8c1685efc3a899ce3d89362ad7.tar.gz rust-b65265b5e1c70d8c1685efc3a899ce3d89362ad7.zip | |
better error for binder on associated type bound
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/parser/path.rs | 48 |
1 files changed, 36 insertions, 12 deletions
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<for<'a> Assoc = Ty>` -> `for<'a> Trait<Assoc = Ty>` + 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<GenericArgs>), 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<Vec<ast::GenericParam>>, Ident, Option<GenericArgs>), ()> { + 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(()) } } |
