diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-09-21 17:11:09 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-09-21 17:11:09 -0700 |
| commit | 60560bc2a2c149e179cd7e58a8b48e06c2c4e3f4 (patch) | |
| tree | b7acfb3124b7b045a8493f677b7c94a3ec4cc80d /src/libsyntax/parse/parser/generics.rs | |
| parent | 9ad1e7c46cf690b7ec6953b142430d21ca2d8799 (diff) | |
| download | rust-60560bc2a2c149e179cd7e58a8b48e06c2c4e3f4.tar.gz rust-60560bc2a2c149e179cd7e58a8b48e06c2c4e3f4.zip | |
Parse assoc type bounds in generic params and provide custom diagnostic
Diffstat (limited to 'src/libsyntax/parse/parser/generics.rs')
| -rw-r--r-- | src/libsyntax/parse/parser/generics.rs | 99 |
1 files changed, 61 insertions, 38 deletions
diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs index 3e6118ad86f..1ffdda19c80 100644 --- a/src/libsyntax/parse/parser/generics.rs +++ b/src/libsyntax/parse/parser/generics.rs @@ -100,13 +100,31 @@ impl<'a> Parser<'a> { } else if self.check_ident() { // Parse type parameter. 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 { // Check for trailing attributes and stop parsing. if !attrs.is_empty() { if !params.is_empty() { self.struct_span_err( attrs[0].span, - &format!("trailing attribute after generic parameter"), + "trailing attribute after generic parameter", ) .span_label(attrs[0].span, "attributes must go before parameters") .emit(); @@ -202,43 +220,7 @@ impl<'a> Parser<'a> { } )); } else if self.check_type() { - // Parse optional `for<'a, 'b>`. - // This `for` is parsed greedily and applies to the whole predicate, - // the bounded type can have its own `for` applying only to it. - // Examples: - // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>` - // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>` - // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>` - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - // Parse type with mandatory colon and (possibly empty) bounds, - // or with mandatory equality sign and the second type. - let ty = self.parse_ty()?; - if self.eat(&token::Colon) { - let bounds = self.parse_generic_bounds(Some(self.prev_span))?; - where_clause.predicates.push(ast::WherePredicate::BoundPredicate( - ast::WhereBoundPredicate { - span: lo.to(self.prev_span), - bound_generic_params: lifetime_defs, - bounded_ty: ty, - bounds, - } - )); - // FIXME: Decide what should be used here, `=` or `==`. - // FIXME: We are just dropping the binders in lifetime_defs on the floor here. - } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { - let rhs_ty = self.parse_ty()?; - where_clause.predicates.push(ast::WherePredicate::EqPredicate( - ast::WhereEqPredicate { - span: lo.to(self.prev_span), - lhs_ty: ty, - rhs_ty, - id: ast::DUMMY_NODE_ID, - } - )); - } else { - return self.unexpected(); - } + where_clause.predicates.push(self.parse_ty_where_predicate()?); } else { break } @@ -252,6 +234,47 @@ impl<'a> Parser<'a> { Ok(where_clause) } + fn parse_ty_where_predicate(&mut self) -> PResult<'a, ast::WherePredicate> { + let lo = self.token.span; + // Parse optional `for<'a, 'b>`. + // This `for` is parsed greedily and applies to the whole predicate, + // the bounded type can have its own `for` applying only to it. + // Examples: + // * `for<'a> Trait1<'a>: Trait2<'a /* ok */>` + // * `(for<'a> Trait1<'a>): Trait2<'a /* not ok */>` + // * `for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /* ok */, 'b /* not ok */>` + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + + // Parse type with mandatory colon and (possibly empty) bounds, + // or with mandatory equality sign and the second type. + let ty = self.parse_ty()?; + if self.eat(&token::Colon) { + let bounds = self.parse_generic_bounds(Some(self.prev_span))?; + Ok(ast::WherePredicate::BoundPredicate( + ast::WhereBoundPredicate { + span: lo.to(self.prev_span), + bound_generic_params: lifetime_defs, + bounded_ty: ty, + bounds, + } + )) + // FIXME: Decide what should be used here, `=` or `==`. + // FIXME: We are just dropping the binders in lifetime_defs on the floor here. + } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { + let rhs_ty = self.parse_ty()?; + Ok(ast::WherePredicate::EqPredicate( + ast::WhereEqPredicate { + span: lo.to(self.prev_span), + lhs_ty: ty, + rhs_ty, + id: ast::DUMMY_NODE_ID, + } + )) + } else { + self.unexpected() + } + } + pub(super) fn choose_generics_over_qpath(&self) -> bool { // There's an ambiguity between generic parameters and qualified paths in impls. // If we see `<` it may start both, so we have to inspect some following tokens. |
