Skip to content

Commit

Permalink
better error for binder on associated type bound
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Apr 10, 2022
1 parent 1f7fb64 commit b65265b
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 13 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GenericParam>,

/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`.
Expand Down
48 changes: 36 additions & 12 deletions compiler/rustc_parse/src/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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(())
}
}
11 changes: 11 additions & 0 deletions src/test/ui/associated-type-bounds/binder-on-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![feature(generic_associated_types)]

trait Trait {
type Bound<'a>;
}

fn foo() where Trait<for<'a> Bound<'a> = &'a ()> {
//~^ ERROR `for<...>` is not allowed on associated type bounds
}

fn main() {}
8 changes: 8 additions & 0 deletions src/test/ui/associated-type-bounds/binder-on-bound.stderr
Original file line number Diff line number Diff line change
@@ -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<for<'a> Bound<'a> = &'a ()> {
| ^^^^^^^^^^^^^^^^^

error: aborting due to previous error

0 comments on commit b65265b

Please sign in to comment.