Skip to content

Commit b65265b

Browse files
better error for binder on associated type bound
1 parent 1f7fb64 commit b65265b

File tree

4 files changed

+56
-13
lines changed

4 files changed

+56
-13
lines changed

Diff for: compiler/rustc_ast/src/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2483,7 +2483,7 @@ pub struct TraitRef {
24832483

24842484
#[derive(Clone, Encodable, Decodable, Debug)]
24852485
pub struct PolyTraitRef {
2486-
/// The `'a` in `<'a> Foo<&'a T>`.
2486+
/// The `'a` in `for<'a> Foo<&'a T>`.
24872487
pub bound_generic_params: Vec<GenericParam>,
24882488

24892489
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`.

Diff for: compiler/rustc_parse/src/parser/path.rs

+36-12
Original file line numberDiff line numberDiff line change
@@ -518,10 +518,20 @@ impl<'a> Parser<'a> {
518518
match arg {
519519
Some(arg) => {
520520
if self.check(&token::Colon) | self.check(&token::Eq) {
521-
let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) {
521+
let arg_span = arg.span();
522+
let (binder, ident, gen_args) = match self.get_ident_from_generic_arg(&arg) {
522523
Ok(ident_gen_args) => ident_gen_args,
523-
Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))),
524+
Err(()) => return Ok(Some(AngleBracketedArg::Arg(arg))),
524525
};
526+
if binder.is_some() {
527+
// FIXME(compiler-errors): this could be improved by suggesting lifting
528+
// this up to the trait, at least before this becomes real syntax.
529+
// e.g. `Trait<for<'a> Assoc = Ty>` -> `for<'a> Trait<Assoc = Ty>`
530+
return Err(self.struct_span_err(
531+
arg_span,
532+
"`for<...>` is not allowed on associated type bounds",
533+
));
534+
}
525535
let kind = if self.eat(&token::Colon) {
526536
// Parse associated type constraint bound.
527537

@@ -700,18 +710,32 @@ impl<'a> Parser<'a> {
700710
Ok(Some(arg))
701711
}
702712

713+
/// Given a arg inside of generics, we try to destructure it as if it were the LHS in
714+
/// `LHS = ...`, i.e. an associated type binding.
715+
/// This returns (optionally, if they are present) any `for<'a, 'b>` binder args, the
716+
/// identifier, and any GAT arguments.
703717
fn get_ident_from_generic_arg(
704718
&self,
705-
gen_arg: GenericArg,
706-
) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
707-
if let GenericArg::Type(ty) = &gen_arg
708-
&& let ast::TyKind::Path(qself, path) = &ty.kind
709-
&& qself.is_none()
710-
&& path.segments.len() == 1
711-
{
712-
let seg = &path.segments[0];
713-
return Ok((seg.ident, seg.args.as_deref().cloned()));
719+
gen_arg: &GenericArg,
720+
) -> Result<(Option<Vec<ast::GenericParam>>, Ident, Option<GenericArgs>), ()> {
721+
if let GenericArg::Type(ty) = gen_arg {
722+
if let ast::TyKind::Path(qself, path) = &ty.kind
723+
&& qself.is_none()
724+
&& let [seg] = path.segments.as_slice()
725+
{
726+
return Ok((None, seg.ident, seg.args.as_deref().cloned()));
727+
} else if let ast::TyKind::TraitObject(bounds, ast::TraitObjectSyntax::None) = &ty.kind
728+
&& let [ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)] =
729+
bounds.as_slice()
730+
&& let [seg] = trait_ref.trait_ref.path.segments.as_slice()
731+
{
732+
return Ok((
733+
Some(trait_ref.bound_generic_params.clone()),
734+
seg.ident,
735+
seg.args.as_deref().cloned(),
736+
));
737+
}
714738
}
715-
Err(gen_arg)
739+
Err(())
716740
}
717741
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(generic_associated_types)]
2+
3+
trait Trait {
4+
type Bound<'a>;
5+
}
6+
7+
fn foo() where Trait<for<'a> Bound<'a> = &'a ()> {
8+
//~^ ERROR `for<...>` is not allowed on associated type bounds
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: `for<...>` is not allowed on associated type bounds
2+
--> $DIR/binder-on-bound.rs:7:22
3+
|
4+
LL | fn foo() where Trait<for<'a> Bound<'a> = &'a ()> {
5+
| ^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)