Tweak path parsing logic
This commit is contained in:
parent
65ff4ca294
commit
fea630ef9d
10 changed files with 93 additions and 36 deletions
|
@ -3620,7 +3620,7 @@ impl<'a> Parser<'a> {
|
||||||
// Parse box pat
|
// Parse box pat
|
||||||
let subpat = self.parse_pat()?;
|
let subpat = self.parse_pat()?;
|
||||||
pat = PatKind::Box(subpat);
|
pat = PatKind::Box(subpat);
|
||||||
} else if self.token.is_ident() && self.token.is_path_start() &&
|
} else if self.token.is_ident() && !self.token.is_any_keyword() &&
|
||||||
self.look_ahead(1, |t| match *t {
|
self.look_ahead(1, |t| match *t {
|
||||||
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
|
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
|
||||||
token::DotDotDot | token::ModSep | token::Not => false,
|
token::DotDotDot | token::ModSep | token::Not => false,
|
||||||
|
@ -3871,6 +3871,11 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_union_item(&mut self) -> bool {
|
||||||
|
self.token.is_keyword(keywords::Union) &&
|
||||||
|
self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword())
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_stmt_without_recovery(&mut self,
|
fn parse_stmt_without_recovery(&mut self,
|
||||||
macro_legacy_warnings: bool)
|
macro_legacy_warnings: bool)
|
||||||
-> PResult<'a, Option<Stmt>> {
|
-> PResult<'a, Option<Stmt>> {
|
||||||
|
@ -3885,10 +3890,10 @@ impl<'a> Parser<'a> {
|
||||||
node: StmtKind::Local(self.parse_local(attrs.into())?),
|
node: StmtKind::Local(self.parse_local(attrs.into())?),
|
||||||
span: mk_sp(lo, self.prev_span.hi),
|
span: mk_sp(lo, self.prev_span.hi),
|
||||||
}
|
}
|
||||||
} else if self.token.is_path_start() && self.token != token::Lt && {
|
// Starts like a simple path, but not a union item.
|
||||||
!self.check_keyword(keywords::Union) ||
|
} else if self.token.is_path_start() &&
|
||||||
self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep)
|
!self.token.is_qpath_start() &&
|
||||||
} {
|
!self.is_union_item() {
|
||||||
let pth = self.parse_path(PathStyle::Expr)?;
|
let pth = self.parse_path(PathStyle::Expr)?;
|
||||||
|
|
||||||
if !self.eat(&token::Not) {
|
if !self.eat(&token::Not) {
|
||||||
|
@ -4599,6 +4604,10 @@ impl<'a> Parser<'a> {
|
||||||
token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) }
|
token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) }
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
|
let isolated_self = |this: &mut Self, n| {
|
||||||
|
this.look_ahead(n, |t| t.is_keyword(keywords::SelfValue)) &&
|
||||||
|
this.look_ahead(n + 1, |t| t != &token::ModSep)
|
||||||
|
};
|
||||||
|
|
||||||
// Parse optional self parameter of a method.
|
// Parse optional self parameter of a method.
|
||||||
// Only a limited set of initial token sequences is considered self parameters, anything
|
// Only a limited set of initial token sequences is considered self parameters, anything
|
||||||
|
@ -4611,22 +4620,22 @@ impl<'a> Parser<'a> {
|
||||||
// &'lt self
|
// &'lt self
|
||||||
// &'lt mut self
|
// &'lt mut self
|
||||||
// ¬_self
|
// ¬_self
|
||||||
if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
|
if isolated_self(self, 1) {
|
||||||
self.bump();
|
self.bump();
|
||||||
(SelfKind::Region(None, Mutability::Immutable), expect_ident(self))
|
(SelfKind::Region(None, Mutability::Immutable), expect_ident(self))
|
||||||
} else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
|
} else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
|
||||||
self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
|
isolated_self(self, 2) {
|
||||||
self.bump();
|
self.bump();
|
||||||
self.bump();
|
self.bump();
|
||||||
(SelfKind::Region(None, Mutability::Mutable), expect_ident(self))
|
(SelfKind::Region(None, Mutability::Mutable), expect_ident(self))
|
||||||
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
||||||
self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
|
isolated_self(self, 2) {
|
||||||
self.bump();
|
self.bump();
|
||||||
let lt = self.parse_lifetime()?;
|
let lt = self.parse_lifetime()?;
|
||||||
(SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
|
(SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
|
||||||
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
|
||||||
self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
|
self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
|
||||||
self.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) {
|
isolated_self(self, 3) {
|
||||||
self.bump();
|
self.bump();
|
||||||
let lt = self.parse_lifetime()?;
|
let lt = self.parse_lifetime()?;
|
||||||
self.bump();
|
self.bump();
|
||||||
|
@ -4641,12 +4650,12 @@ impl<'a> Parser<'a> {
|
||||||
// *mut self
|
// *mut self
|
||||||
// *not_self
|
// *not_self
|
||||||
// Emit special error for `self` cases.
|
// Emit special error for `self` cases.
|
||||||
if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
|
if isolated_self(self, 1) {
|
||||||
self.bump();
|
self.bump();
|
||||||
self.span_err(self.span, "cannot pass `self` by raw pointer");
|
self.span_err(self.span, "cannot pass `self` by raw pointer");
|
||||||
(SelfKind::Value(Mutability::Immutable), expect_ident(self))
|
(SelfKind::Value(Mutability::Immutable), expect_ident(self))
|
||||||
} else if self.look_ahead(1, |t| t.is_mutability()) &&
|
} else if self.look_ahead(1, |t| t.is_mutability()) &&
|
||||||
self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
|
isolated_self(self, 2) {
|
||||||
self.bump();
|
self.bump();
|
||||||
self.bump();
|
self.bump();
|
||||||
self.span_err(self.span, "cannot pass `self` by raw pointer");
|
self.span_err(self.span, "cannot pass `self` by raw pointer");
|
||||||
|
@ -4656,7 +4665,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
token::Ident(..) => {
|
token::Ident(..) => {
|
||||||
if self.token.is_keyword(keywords::SelfValue) {
|
if isolated_self(self, 0) {
|
||||||
// self
|
// self
|
||||||
// self: TYPE
|
// self: TYPE
|
||||||
let eself_ident = expect_ident(self);
|
let eself_ident = expect_ident(self);
|
||||||
|
@ -4667,7 +4676,7 @@ impl<'a> Parser<'a> {
|
||||||
(SelfKind::Value(Mutability::Immutable), eself_ident)
|
(SelfKind::Value(Mutability::Immutable), eself_ident)
|
||||||
}
|
}
|
||||||
} else if self.token.is_keyword(keywords::Mut) &&
|
} else if self.token.is_keyword(keywords::Mut) &&
|
||||||
self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
|
isolated_self(self, 1) {
|
||||||
// mut self
|
// mut self
|
||||||
// mut self: TYPE
|
// mut self: TYPE
|
||||||
self.bump();
|
self.bump();
|
||||||
|
@ -5958,8 +5967,7 @@ impl<'a> Parser<'a> {
|
||||||
maybe_append(attrs, extra_attrs));
|
maybe_append(attrs, extra_attrs));
|
||||||
return Ok(Some(item));
|
return Ok(Some(item));
|
||||||
}
|
}
|
||||||
if self.check_keyword(keywords::Union) &&
|
if self.is_union_item() {
|
||||||
self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
|
|
||||||
// UNION ITEM
|
// UNION ITEM
|
||||||
self.bump();
|
self.bump();
|
||||||
let (ident, item_, extra_attrs) = self.parse_item_union()?;
|
let (ident, item_, extra_attrs) = self.parse_item_union()?;
|
||||||
|
|
|
@ -159,10 +159,8 @@ impl Token {
|
||||||
/// Returns `true` if the token can appear at the start of an expression.
|
/// Returns `true` if the token can appear at the start of an expression.
|
||||||
pub fn can_begin_expr(&self) -> bool {
|
pub fn can_begin_expr(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
OpenDelim(_) => true,
|
OpenDelim(..) => true,
|
||||||
Ident(..) => true,
|
Ident(..) => true,
|
||||||
Underscore => true,
|
|
||||||
Tilde => true,
|
|
||||||
Literal(..) => true,
|
Literal(..) => true,
|
||||||
Not => true,
|
Not => true,
|
||||||
BinOp(Minus) => true,
|
BinOp(Minus) => true,
|
||||||
|
@ -172,6 +170,7 @@ impl Token {
|
||||||
OrOr => true, // in lambda syntax
|
OrOr => true, // in lambda syntax
|
||||||
AndAnd => true, // double borrow
|
AndAnd => true, // double borrow
|
||||||
DotDot | DotDotDot => true, // range notation
|
DotDot | DotDotDot => true, // range notation
|
||||||
|
Lt | BinOp(Shl) => true, // associated path
|
||||||
ModSep => true,
|
ModSep => true,
|
||||||
Interpolated(NtExpr(..)) => true,
|
Interpolated(NtExpr(..)) => true,
|
||||||
Interpolated(NtIdent(..)) => true,
|
Interpolated(NtIdent(..)) => true,
|
||||||
|
@ -236,8 +235,12 @@ impl Token {
|
||||||
self.is_keyword(keywords::Const)
|
self.is_keyword(keywords::Const)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_qpath_start(&self) -> bool {
|
||||||
|
self == &Lt || self == &BinOp(Shl)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_path_start(&self) -> bool {
|
pub fn is_path_start(&self) -> bool {
|
||||||
self == &ModSep || self == &Lt || self.is_path() ||
|
self == &ModSep || self.is_qpath_start() || self.is_path() ||
|
||||||
self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword()
|
self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
src/test/compile-fail/associated-path-shl.rs
Normal file
20
src/test/compile-fail/associated-path-shl.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that associated paths starting with `<<` are successfully parsed.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
|
||||||
|
let _ = <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
|
||||||
|
let <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
|
||||||
|
let 0 ... <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
|
||||||
|
//~^ ERROR only char and numeric types are allowed in range patterns
|
||||||
|
<<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
|
||||||
|
}
|
|
@ -8,8 +8,6 @@
|
||||||
// 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.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let Self = "foo"; //~ error: expected identifier, found keyword `Self`
|
let Self = "foo"; //~ ERROR unresolved unit struct/variant or constant `Self`
|
||||||
}
|
}
|
|
@ -8,8 +8,6 @@
|
||||||
// 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.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let super = "foo"; //~ error: expected identifier, found keyword `super`
|
let super = "foo"; //~ ERROR unresolved unit struct/variant or constant `super`
|
||||||
}
|
}
|
|
@ -8,8 +8,6 @@
|
||||||
// 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.
|
||||||
|
|
||||||
// compile-flags: -Z parse-only
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let super: isize; //~ ERROR expected identifier, found keyword `super`
|
let super: isize; //~ ERROR unresolved unit struct/variant or constant `super`
|
||||||
}
|
}
|
23
src/test/compile-fail/self-vs-path-ambiguity.rs
Normal file
23
src/test/compile-fail/self-vs-path-ambiguity.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that `self::foo` is parsed as a general pattern and not a self argument.
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn f(self::S: S) {}
|
||||||
|
fn g(&self::S: &S) {}
|
||||||
|
fn h(&mut self::S: &mut S) {}
|
||||||
|
fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern
|
||||||
|
//~^ ERROR expected one of `)` or `mut`, found `'a`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -10,4 +10,14 @@
|
||||||
|
|
||||||
use self::Self as Foo; //~ ERROR unresolved import `self::Self`
|
use self::Self as Foo; //~ ERROR unresolved import `self::Self`
|
||||||
|
|
||||||
pub fn main() {}
|
pub fn main() {
|
||||||
|
let Self = 5;
|
||||||
|
//~^ ERROR unresolved unit struct/variant or constant `Self`
|
||||||
|
|
||||||
|
match 15 {
|
||||||
|
Self => (),
|
||||||
|
//~^ ERROR unresolved unit struct/variant or constant `Self`
|
||||||
|
Foo { x: Self } => (),
|
||||||
|
//~^ ERROR unresolved unit struct/variant or constant `Self`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,12 +17,7 @@ struct Bar<'Self>;
|
||||||
//~^ ERROR lifetimes cannot use keyword names
|
//~^ ERROR lifetimes cannot use keyword names
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let Self = 5;
|
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
|
||||||
|
|
||||||
match 15 {
|
match 15 {
|
||||||
Self => (),
|
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
|
||||||
ref Self => (),
|
ref Self => (),
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
//~^ ERROR expected identifier, found keyword `Self`
|
||||||
mut Self => (),
|
mut Self => (),
|
||||||
|
@ -31,8 +26,6 @@ pub fn main() {
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
//~^ ERROR expected identifier, found keyword `Self`
|
||||||
Self!() => (),
|
Self!() => (),
|
||||||
//~^ ERROR macro undefined: 'Self!'
|
//~^ ERROR macro undefined: 'Self!'
|
||||||
Foo { x: Self } => (),
|
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
|
||||||
Foo { Self } => (),
|
Foo { Self } => (),
|
||||||
//~^ ERROR expected identifier, found keyword `Self`
|
//~^ ERROR expected identifier, found keyword `Self`
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
|
|
||||||
#![feature(untagged_unions)]
|
#![feature(untagged_unions)]
|
||||||
|
|
||||||
|
macro_rules! union {
|
||||||
|
() => (struct S;)
|
||||||
|
}
|
||||||
|
|
||||||
|
union!();
|
||||||
|
|
||||||
fn union() {}
|
fn union() {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue