Parse fully-qualified associated types in generics without whitespace

This breaks code that looks like this:

    let x = foo as bar << 13;

Change such code to look like this:

    let x = (foo as bar) << 13;

Closes #17362.

[breaking-change]
This commit is contained in:
P1start 2014-12-23 13:13:49 +13:00
parent 7e11b22713
commit d9769ec383
10 changed files with 53 additions and 59 deletions

View file

@ -669,45 +669,22 @@ impl<'a> Parser<'a> {
/// `<` and continue. If a `<` is not seen, return false.
///
/// This is meant to be used when parsing generics on a path to get the
/// starting token. The `force` parameter is used to forcefully break up a
/// `<<` token. If `force` is false, then `<<` is only broken when a lifetime
/// shows up next. For example, consider the expression:
///
/// foo as bar << test
///
/// The parser needs to know if `bar <<` is the start of a generic path or if
/// it's a left-shift token. If `test` were a lifetime, then it's impossible
/// for the token to be a left-shift, but if it's not a lifetime, then it's
/// considered a left-shift.
///
/// The reason for this is that the only current ambiguity with `<<` is when
/// parsing closure types:
///
/// foo::<<'a> ||>();
/// impl Foo<<'a> ||>() { ... }
fn eat_lt(&mut self, force: bool) -> bool {
/// starting token.
fn eat_lt(&mut self) -> bool {
match self.token {
token::Lt => { self.bump(); true }
token::BinOp(token::Shl) => {
let next_lifetime = self.look_ahead(1, |t| match *t {
token::Lifetime(..) => true,
_ => false,
});
if force || next_lifetime {
let span = self.span;
let lo = span.lo + BytePos(1);
self.replace_token(token::Lt, lo, span.hi);
true
} else {
false
}
let span = self.span;
let lo = span.lo + BytePos(1);
self.replace_token(token::Lt, lo, span.hi);
true
}
_ => false,
}
}
fn expect_lt(&mut self) {
if !self.eat_lt(true) {
if !self.eat_lt() {
let found_token = self.this_token_to_string();
let token_str = Parser::token_to_string(&token::Lt);
self.fatal(format!("expected `{}`, found `{}`",
@ -1582,9 +1559,8 @@ impl<'a> Parser<'a> {
TyTypeof(e)
} else if self.eat_keyword(keywords::Proc) {
self.parse_proc_type(Vec::new())
} else if self.check(&token::Lt) {
} else if self.eat_lt() {
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
self.bump();
let self_type = self.parse_ty_sum();
self.expect_keyword(keywords::As);
let trait_ref = self.parse_trait_ref();
@ -1870,7 +1846,7 @@ impl<'a> Parser<'a> {
let identifier = self.parse_ident();
// Parse types, optionally.
let parameters = if self.eat_lt(false) {
let parameters = if self.eat_lt() {
let (lifetimes, types, bindings) = self.parse_generic_values_after_lt();
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
@ -1931,7 +1907,7 @@ impl<'a> Parser<'a> {
}
// Check for a type segment.
if self.eat_lt(false) {
if self.eat_lt() {
// Consumed `a::b::<`, go look for types
let (lifetimes, types, bindings) = self.parse_generic_values_after_lt();
segments.push(ast::PathSegment {