Skip to content

Commit fea630e

Browse files
committed
Tweak path parsing logic
1 parent 65ff4ca commit fea630e

10 files changed

+93
-36
lines changed

Diff for: src/libsyntax/parse/parser.rs

+23-15
Original file line numberDiff line numberDiff line change
@@ -3620,7 +3620,7 @@ impl<'a> Parser<'a> {
36203620
// Parse box pat
36213621
let subpat = self.parse_pat()?;
36223622
pat = PatKind::Box(subpat);
3623-
} else if self.token.is_ident() && self.token.is_path_start() &&
3623+
} else if self.token.is_ident() && !self.token.is_any_keyword() &&
36243624
self.look_ahead(1, |t| match *t {
36253625
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
36263626
token::DotDotDot | token::ModSep | token::Not => false,
@@ -3871,6 +3871,11 @@ impl<'a> Parser<'a> {
38713871
})
38723872
}
38733873

3874+
fn is_union_item(&mut self) -> bool {
3875+
self.token.is_keyword(keywords::Union) &&
3876+
self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword())
3877+
}
3878+
38743879
fn parse_stmt_without_recovery(&mut self,
38753880
macro_legacy_warnings: bool)
38763881
-> PResult<'a, Option<Stmt>> {
@@ -3885,10 +3890,10 @@ impl<'a> Parser<'a> {
38853890
node: StmtKind::Local(self.parse_local(attrs.into())?),
38863891
span: mk_sp(lo, self.prev_span.hi),
38873892
}
3888-
} else if self.token.is_path_start() && self.token != token::Lt && {
3889-
!self.check_keyword(keywords::Union) ||
3890-
self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep)
3891-
} {
3893+
// Starts like a simple path, but not a union item.
3894+
} else if self.token.is_path_start() &&
3895+
!self.token.is_qpath_start() &&
3896+
!self.is_union_item() {
38923897
let pth = self.parse_path(PathStyle::Expr)?;
38933898

38943899
if !self.eat(&token::Not) {
@@ -4599,6 +4604,10 @@ impl<'a> Parser<'a> {
45994604
token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) }
46004605
_ => unreachable!()
46014606
};
4607+
let isolated_self = |this: &mut Self, n| {
4608+
this.look_ahead(n, |t| t.is_keyword(keywords::SelfValue)) &&
4609+
this.look_ahead(n + 1, |t| t != &token::ModSep)
4610+
};
46024611

46034612
// Parse optional self parameter of a method.
46044613
// Only a limited set of initial token sequences is considered self parameters, anything
@@ -4611,22 +4620,22 @@ impl<'a> Parser<'a> {
46114620
// &'lt self
46124621
// &'lt mut self
46134622
// &not_self
4614-
if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
4623+
if isolated_self(self, 1) {
46154624
self.bump();
46164625
(SelfKind::Region(None, Mutability::Immutable), expect_ident(self))
46174626
} else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
4618-
self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
4627+
isolated_self(self, 2) {
46194628
self.bump();
46204629
self.bump();
46214630
(SelfKind::Region(None, Mutability::Mutable), expect_ident(self))
46224631
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
4623-
self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
4632+
isolated_self(self, 2) {
46244633
self.bump();
46254634
let lt = self.parse_lifetime()?;
46264635
(SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
46274636
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
46284637
self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
4629-
self.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) {
4638+
isolated_self(self, 3) {
46304639
self.bump();
46314640
let lt = self.parse_lifetime()?;
46324641
self.bump();
@@ -4641,12 +4650,12 @@ impl<'a> Parser<'a> {
46414650
// *mut self
46424651
// *not_self
46434652
// Emit special error for `self` cases.
4644-
if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
4653+
if isolated_self(self, 1) {
46454654
self.bump();
46464655
self.span_err(self.span, "cannot pass `self` by raw pointer");
46474656
(SelfKind::Value(Mutability::Immutable), expect_ident(self))
46484657
} else if self.look_ahead(1, |t| t.is_mutability()) &&
4649-
self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) {
4658+
isolated_self(self, 2) {
46504659
self.bump();
46514660
self.bump();
46524661
self.span_err(self.span, "cannot pass `self` by raw pointer");
@@ -4656,7 +4665,7 @@ impl<'a> Parser<'a> {
46564665
}
46574666
}
46584667
token::Ident(..) => {
4659-
if self.token.is_keyword(keywords::SelfValue) {
4668+
if isolated_self(self, 0) {
46604669
// self
46614670
// self: TYPE
46624671
let eself_ident = expect_ident(self);
@@ -4667,7 +4676,7 @@ impl<'a> Parser<'a> {
46674676
(SelfKind::Value(Mutability::Immutable), eself_ident)
46684677
}
46694678
} else if self.token.is_keyword(keywords::Mut) &&
4670-
self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) {
4679+
isolated_self(self, 1) {
46714680
// mut self
46724681
// mut self: TYPE
46734682
self.bump();
@@ -5958,8 +5967,7 @@ impl<'a> Parser<'a> {
59585967
maybe_append(attrs, extra_attrs));
59595968
return Ok(Some(item));
59605969
}
5961-
if self.check_keyword(keywords::Union) &&
5962-
self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
5970+
if self.is_union_item() {
59635971
// UNION ITEM
59645972
self.bump();
59655973
let (ident, item_, extra_attrs) = self.parse_item_union()?;

Diff for: src/libsyntax/parse/token.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,8 @@ impl Token {
159159
/// Returns `true` if the token can appear at the start of an expression.
160160
pub fn can_begin_expr(&self) -> bool {
161161
match *self {
162-
OpenDelim(_) => true,
162+
OpenDelim(..) => true,
163163
Ident(..) => true,
164-
Underscore => true,
165-
Tilde => true,
166164
Literal(..) => true,
167165
Not => true,
168166
BinOp(Minus) => true,
@@ -172,6 +170,7 @@ impl Token {
172170
OrOr => true, // in lambda syntax
173171
AndAnd => true, // double borrow
174172
DotDot | DotDotDot => true, // range notation
173+
Lt | BinOp(Shl) => true, // associated path
175174
ModSep => true,
176175
Interpolated(NtExpr(..)) => true,
177176
Interpolated(NtIdent(..)) => true,
@@ -236,8 +235,12 @@ impl Token {
236235
self.is_keyword(keywords::Const)
237236
}
238237

238+
pub fn is_qpath_start(&self) -> bool {
239+
self == &Lt || self == &BinOp(Shl)
240+
}
241+
239242
pub fn is_path_start(&self) -> bool {
240-
self == &ModSep || self == &Lt || self.is_path() ||
243+
self == &ModSep || self.is_qpath_start() || self.is_path() ||
241244
self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword()
242245
}
243246

Diff for: src/test/compile-fail/associated-path-shl.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that associated paths starting with `<<` are successfully parsed.
12+
13+
fn main() {
14+
let _: <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
15+
let _ = <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
16+
let <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
17+
let 0 ... <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
18+
//~^ ERROR only char and numeric types are allowed in range patterns
19+
<<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
20+
}

Diff for: src/test/parse-fail/keyword-self-as-identifier.rs renamed to src/test/compile-fail/keyword-self-as-identifier.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// compile-flags: -Z parse-only
12-
1311
fn main() {
14-
let Self = "foo"; //~ error: expected identifier, found keyword `Self`
12+
let Self = "foo"; //~ ERROR unresolved unit struct/variant or constant `Self`
1513
}

Diff for: src/test/parse-fail/keyword-super-as-identifier.rs renamed to src/test/compile-fail/keyword-super-as-identifier.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// compile-flags: -Z parse-only
12-
1311
fn main() {
14-
let super = "foo"; //~ error: expected identifier, found keyword `super`
12+
let super = "foo"; //~ ERROR unresolved unit struct/variant or constant `super`
1513
}

Diff for: src/test/parse-fail/keyword-super.rs renamed to src/test/compile-fail/keyword-super.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// compile-flags: -Z parse-only
12-
1311
fn main() {
14-
let super: isize; //~ ERROR expected identifier, found keyword `super`
12+
let super: isize; //~ ERROR unresolved unit struct/variant or constant `super`
1513
}

Diff for: src/test/compile-fail/self-vs-path-ambiguity.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that `self::foo` is parsed as a general pattern and not a self argument.
12+
13+
struct S;
14+
15+
impl S {
16+
fn f(self::S: S) {}
17+
fn g(&self::S: &S) {}
18+
fn h(&mut self::S: &mut S) {}
19+
fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern
20+
//~^ ERROR expected one of `)` or `mut`, found `'a`
21+
}
22+
23+
fn main() {}

Diff for: src/test/compile-fail/self_type_keyword-2.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,14 @@
1010

1111
use self::Self as Foo; //~ ERROR unresolved import `self::Self`
1212

13-
pub fn main() {}
13+
pub fn main() {
14+
let Self = 5;
15+
//~^ ERROR unresolved unit struct/variant or constant `Self`
16+
17+
match 15 {
18+
Self => (),
19+
//~^ ERROR unresolved unit struct/variant or constant `Self`
20+
Foo { x: Self } => (),
21+
//~^ ERROR unresolved unit struct/variant or constant `Self`
22+
}
23+
}

Diff for: src/test/compile-fail/self_type_keyword.rs

-7
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ struct Bar<'Self>;
1717
//~^ ERROR lifetimes cannot use keyword names
1818

1919
pub fn main() {
20-
let Self = 5;
21-
//~^ ERROR expected identifier, found keyword `Self`
22-
2320
match 15 {
24-
Self => (),
25-
//~^ ERROR expected identifier, found keyword `Self`
2621
ref Self => (),
2722
//~^ ERROR expected identifier, found keyword `Self`
2823
mut Self => (),
@@ -31,8 +26,6 @@ pub fn main() {
3126
//~^ ERROR expected identifier, found keyword `Self`
3227
Self!() => (),
3328
//~^ ERROR macro undefined: 'Self!'
34-
Foo { x: Self } => (),
35-
//~^ ERROR expected identifier, found keyword `Self`
3629
Foo { Self } => (),
3730
//~^ ERROR expected identifier, found keyword `Self`
3831
}

Diff for: src/test/run-pass/union/union-backcomp.rs

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010

1111
#![feature(untagged_unions)]
1212

13+
macro_rules! union {
14+
() => (struct S;)
15+
}
16+
17+
union!();
18+
1319
fn union() {}
1420

1521
fn main() {

0 commit comments

Comments
 (0)