1
Fork 0

Parse assoc type bounds in generic params and provide custom diagnostic

This commit is contained in:
Esteban Küber 2019-09-21 17:11:09 -07:00
parent 9ad1e7c46c
commit 60560bc2a2
3 changed files with 80 additions and 38 deletions

View file

@ -100,13 +100,31 @@ impl<'a> Parser<'a> {
} else if self.check_ident() { } else if self.check_ident() {
// Parse type parameter. // Parse type parameter.
params.push(self.parse_ty_param(attrs)?); params.push(self.parse_ty_param(attrs)?);
} else if self.token.can_begin_type() {
// Trying to write an associated type bound? (#26271)
let snapshot = self.clone();
match self.parse_ty_where_predicate() {
Ok(where_predicate) => {
self.struct_span_err(
where_predicate.span(),
"associated type bounds do not belong here",
)
.span_label(where_predicate.span(), "belongs in `where` clause")
.emit();
}
Err(mut err) => {
err.cancel();
std::mem::replace(self, snapshot);
break
}
}
} else { } else {
// Check for trailing attributes and stop parsing. // Check for trailing attributes and stop parsing.
if !attrs.is_empty() { if !attrs.is_empty() {
if !params.is_empty() { if !params.is_empty() {
self.struct_span_err( self.struct_span_err(
attrs[0].span, attrs[0].span,
&format!("trailing attribute after generic parameter"), "trailing attribute after generic parameter",
) )
.span_label(attrs[0].span, "attributes must go before parameters") .span_label(attrs[0].span, "attributes must go before parameters")
.emit(); .emit();
@ -202,6 +220,22 @@ impl<'a> Parser<'a> {
} }
)); ));
} else if self.check_type() { } else if self.check_type() {
where_clause.predicates.push(self.parse_ty_where_predicate()?);
} else {
break
}
if !self.eat(&token::Comma) {
break
}
}
where_clause.span = lo.to(self.prev_span);
Ok(where_clause)
}
fn parse_ty_where_predicate(&mut self) -> PResult<'a, ast::WherePredicate> {
let lo = self.token.span;
// Parse optional `for<'a, 'b>`. // Parse optional `for<'a, 'b>`.
// This `for` is parsed greedily and applies to the whole predicate, // This `for` is parsed greedily and applies to the whole predicate,
// the bounded type can have its own `for` applying only to it. // the bounded type can have its own `for` applying only to it.
@ -216,40 +250,29 @@ impl<'a> Parser<'a> {
let ty = self.parse_ty()?; let ty = self.parse_ty()?;
if self.eat(&token::Colon) { if self.eat(&token::Colon) {
let bounds = self.parse_generic_bounds(Some(self.prev_span))?; let bounds = self.parse_generic_bounds(Some(self.prev_span))?;
where_clause.predicates.push(ast::WherePredicate::BoundPredicate( Ok(ast::WherePredicate::BoundPredicate(
ast::WhereBoundPredicate { ast::WhereBoundPredicate {
span: lo.to(self.prev_span), span: lo.to(self.prev_span),
bound_generic_params: lifetime_defs, bound_generic_params: lifetime_defs,
bounded_ty: ty, bounded_ty: ty,
bounds, bounds,
} }
)); ))
// FIXME: Decide what should be used here, `=` or `==`. // FIXME: Decide what should be used here, `=` or `==`.
// FIXME: We are just dropping the binders in lifetime_defs on the floor here. // FIXME: We are just dropping the binders in lifetime_defs on the floor here.
} else if self.eat(&token::Eq) || self.eat(&token::EqEq) { } else if self.eat(&token::Eq) || self.eat(&token::EqEq) {
let rhs_ty = self.parse_ty()?; let rhs_ty = self.parse_ty()?;
where_clause.predicates.push(ast::WherePredicate::EqPredicate( Ok(ast::WherePredicate::EqPredicate(
ast::WhereEqPredicate { ast::WhereEqPredicate {
span: lo.to(self.prev_span), span: lo.to(self.prev_span),
lhs_ty: ty, lhs_ty: ty,
rhs_ty, rhs_ty,
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
} }
)); ))
} else { } else {
return self.unexpected(); self.unexpected()
} }
} else {
break
}
if !self.eat(&token::Comma) {
break
}
}
where_clause.span = lo.to(self.prev_span);
Ok(where_clause)
} }
pub(super) fn choose_generics_over_qpath(&self) -> bool { pub(super) fn choose_generics_over_qpath(&self) -> bool {

View file

@ -0,0 +1,11 @@
trait Tr {
type TrSubtype;
}
struct Bar<'a, Item: Tr, <Item as Tr>::TrSubtype: 'a> {
//~^ ERROR associated type bounds do not belong here
item: Item,
item_sub: &'a <Item as Tr>::TrSubtype,
}
fn main() {}

View file

@ -0,0 +1,8 @@
error: associated type bounds do not belong here
--> $DIR/assoc-type-in-type-arg.rs:5:26
|
LL | struct Bar<'a, Item: Tr, <Item as Tr>::TrSubtype: 'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ belongs in `where` clause
error: aborting due to previous error