syntax: Fix parsing << with closure types

This uses the trick of replacing the << token with a < token to parse closure
types correctly.

Closes #13324
This commit is contained in:
Alex Crichton 2014-05-10 21:27:44 -07:00
parent 042c8ae40e
commit ac1a27043a
3 changed files with 71 additions and 7 deletions

View File

@ -587,16 +587,64 @@ impl<'a> Parser<'a> {
self.replace_token(token::BINOP(token::OR), lo, self.span.hi)
}
_ => {
let token_str = self.this_token_to_str();
let found_token =
let found_token = self.this_token_to_str();
let token_str =
Parser::token_to_str(&token::BINOP(token::OR));
self.fatal(format!("expected `{}`, found `{}`",
found_token,
token_str))
token_str, found_token))
}
}
}
// Attempt to consume a `<`. If `<<` is seen, replace it with a single
// `<` 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 {
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 lo = self.span.lo + BytePos(1);
self.replace_token(token::LT, lo, self.span.hi);
true
} else {
false
}
}
_ => false,
}
}
fn expect_lt(&mut self) {
if !self.eat_lt(true) {
let found_token = self.this_token_to_str();
let token_str = Parser::token_to_str(&token::LT);
self.fatal(format!("expected `{}`, found `{}`",
token_str, found_token))
}
}
// Parse a sequence bracketed by `|` and `|`, stopping before the `|`.
fn parse_seq_to_before_or<T>(
&mut self,
@ -1500,7 +1548,7 @@ impl<'a> Parser<'a> {
// Parse the `<` before the lifetime and types, if applicable.
let (any_lifetime_or_types, lifetimes, types) = {
if mode != NoTypesAllowed && self.eat(&token::LT) {
if mode != NoTypesAllowed && self.eat_lt(false) {
let (lifetimes, types) =
self.parse_generic_values_after_lt();
(true, lifetimes, OwnedSlice::from_vec(types))
@ -1948,7 +1996,7 @@ impl<'a> Parser<'a> {
hi = self.span.hi;
self.bump();
let (_, tys) = if self.eat(&token::MOD_SEP) {
self.expect(&token::LT);
self.expect_lt();
self.parse_generic_values_after_lt()
} else {
(Vec::new(), Vec::new())

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-pretty
fn match_ref(v: Option<int>) -> int {
match v {
Some(ref i) => {

View File

@ -43,6 +43,12 @@ fn g<'a>(a: &'a int, f: proc<'b>(&'b int) -> &'b int) -> &'a int {
f(a)
}
struct A;
impl A {
fn foo<T>(&self) {}
}
fn bar<'b>() {
foo::<||>();
foo::<|| -> ()>();
@ -58,17 +64,25 @@ fn bar<'b>() {
foo::<proc():Share>();
foo::<proc<'a>(int, f32, &'a int):'static + Share -> &'a int>();
foo::<<'a>||>();
// issue #11209
let _: ||: 'b; // for comparison
let _: <'a> ||;
let _: Option<||:'b>;
// let _: Option<<'a>||>;
let _: Option<<'a>||>;
let _: Option< <'a>||>;
// issue #11210
let _: ||: 'static;
let a = A;
a.foo::<<'a>||>();
}
struct B<T>;
impl<'b> B<<'a>||: 'b> {}
pub fn main() {
}