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:
parent
042c8ae40e
commit
ac1a27043a
3 changed files with 71 additions and 7 deletions
|
@ -587,16 +587,64 @@ impl<'a> Parser<'a> {
|
||||||
self.replace_token(token::BINOP(token::OR), lo, self.span.hi)
|
self.replace_token(token::BINOP(token::OR), lo, self.span.hi)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let token_str = self.this_token_to_str();
|
let found_token = self.this_token_to_str();
|
||||||
let found_token =
|
let token_str =
|
||||||
Parser::token_to_str(&token::BINOP(token::OR));
|
Parser::token_to_str(&token::BINOP(token::OR));
|
||||||
self.fatal(format!("expected `{}`, found `{}`",
|
self.fatal(format!("expected `{}`, found `{}`",
|
||||||
found_token,
|
token_str, found_token))
|
||||||
token_str))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 `|`.
|
// Parse a sequence bracketed by `|` and `|`, stopping before the `|`.
|
||||||
fn parse_seq_to_before_or<T>(
|
fn parse_seq_to_before_or<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1500,7 +1548,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// Parse the `<` before the lifetime and types, if applicable.
|
// Parse the `<` before the lifetime and types, if applicable.
|
||||||
let (any_lifetime_or_types, lifetimes, types) = {
|
let (any_lifetime_or_types, lifetimes, types) = {
|
||||||
if mode != NoTypesAllowed && self.eat(&token::LT) {
|
if mode != NoTypesAllowed && self.eat_lt(false) {
|
||||||
let (lifetimes, types) =
|
let (lifetimes, types) =
|
||||||
self.parse_generic_values_after_lt();
|
self.parse_generic_values_after_lt();
|
||||||
(true, lifetimes, OwnedSlice::from_vec(types))
|
(true, lifetimes, OwnedSlice::from_vec(types))
|
||||||
|
@ -1948,7 +1996,7 @@ impl<'a> Parser<'a> {
|
||||||
hi = self.span.hi;
|
hi = self.span.hi;
|
||||||
self.bump();
|
self.bump();
|
||||||
let (_, tys) = if self.eat(&token::MOD_SEP) {
|
let (_, tys) = if self.eat(&token::MOD_SEP) {
|
||||||
self.expect(&token::LT);
|
self.expect_lt();
|
||||||
self.parse_generic_values_after_lt()
|
self.parse_generic_values_after_lt()
|
||||||
} else {
|
} else {
|
||||||
(Vec::new(), Vec::new())
|
(Vec::new(), Vec::new())
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// ignore-pretty
|
||||||
|
|
||||||
fn match_ref(v: Option<int>) -> int {
|
fn match_ref(v: Option<int>) -> int {
|
||||||
match v {
|
match v {
|
||||||
Some(ref i) => {
|
Some(ref i) => {
|
||||||
|
|
|
@ -43,6 +43,12 @@ fn g<'a>(a: &'a int, f: proc<'b>(&'b int) -> &'b int) -> &'a int {
|
||||||
f(a)
|
f(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct A;
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn foo<T>(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
fn bar<'b>() {
|
fn bar<'b>() {
|
||||||
foo::<||>();
|
foo::<||>();
|
||||||
foo::<|| -> ()>();
|
foo::<|| -> ()>();
|
||||||
|
@ -58,17 +64,25 @@ fn bar<'b>() {
|
||||||
foo::<proc():Share>();
|
foo::<proc():Share>();
|
||||||
foo::<proc<'a>(int, f32, &'a int):'static + Share -> &'a int>();
|
foo::<proc<'a>(int, f32, &'a int):'static + Share -> &'a int>();
|
||||||
|
|
||||||
|
foo::<<'a>||>();
|
||||||
|
|
||||||
// issue #11209
|
// issue #11209
|
||||||
let _: ||: 'b; // for comparison
|
let _: ||: 'b; // for comparison
|
||||||
let _: <'a> ||;
|
let _: <'a> ||;
|
||||||
|
|
||||||
let _: Option<||:'b>;
|
let _: Option<||:'b>;
|
||||||
// let _: Option<<'a>||>;
|
let _: Option<<'a>||>;
|
||||||
let _: Option< <'a>||>;
|
let _: Option< <'a>||>;
|
||||||
|
|
||||||
// issue #11210
|
// issue #11210
|
||||||
let _: ||: 'static;
|
let _: ||: 'static;
|
||||||
|
|
||||||
|
let a = A;
|
||||||
|
a.foo::<<'a>||>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct B<T>;
|
||||||
|
impl<'b> B<<'a>||: 'b> {}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue