Skip to content

Commit ad260ff

Browse files
committedJun 15, 2017
Review comments
- generate error instead of warning - remove `RewindPoint` and just keep a copy of `Parser` to rewind state. - `dont_parse_generics: bool` -> `parse_generics: bool` - remove `eat_lt` - move error handling code to separate method
1 parent 46a6af1 commit ad260ff

10 files changed

+83
-109
lines changed
 

‎src/libsyntax/parse/parser.rs

+71-99
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
150150
lhs
151151
}
152152

153-
#[derive(PartialEq)]
153+
#[derive(Clone, PartialEq)]
154154
enum PrevTokenKind {
155155
DocComment,
156156
Comma,
@@ -162,6 +162,7 @@ enum PrevTokenKind {
162162

163163
/* ident is handled by common.rs */
164164

165+
#[derive(Clone)]
165166
pub struct Parser<'a> {
166167
pub sess: &'a ParseSess,
167168
/// the current token:
@@ -441,15 +442,6 @@ fn dummy_arg(span: Span) -> Arg {
441442
Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
442443
}
443444

444-
struct RewindPoint {
445-
token: token::Token,
446-
span: Span,
447-
meta_var_span: Option<Span>,
448-
prev_span: Span,
449-
token_cursor: TokenCursor,
450-
expected_tokens: Vec<TokenType>,
451-
}
452-
453445
impl<'a> Parser<'a> {
454446
pub fn new(sess: &'a ParseSess,
455447
tokens: TokenStream,
@@ -798,13 +790,6 @@ impl<'a> Parser<'a> {
798790
}
799791
}
800792

801-
fn is_lt(&mut self) -> bool {
802-
match self.token {
803-
token::Lt | token::BinOp(token::Shl) => true,
804-
_ => false,
805-
}
806-
}
807-
808793
/// Attempt to consume a `<`. If `<<` is seen, replace it with a single
809794
/// `<` and continue. If a `<` is not seen, return false.
810795
///
@@ -1743,7 +1728,7 @@ impl<'a> Parser<'a> {
17431728

17441729
let segments = match mode {
17451730
PathStyle::Type => {
1746-
self.parse_path_segments_without_colons(false)?
1731+
self.parse_path_segments_without_colons(true)?
17471732
}
17481733
PathStyle::Expr => {
17491734
self.parse_path_segments_with_colons()?
@@ -1764,14 +1749,14 @@ impl<'a> Parser<'a> {
17641749
/// bounds are permitted and whether `::` must precede type parameter
17651750
/// groups.
17661751
pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
1767-
self.parse_path_common(mode, false)
1752+
self.parse_path_common(mode, true)
17681753
}
17691754

17701755
pub fn parse_path_without_generics(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
1771-
self.parse_path_common(mode, true)
1756+
self.parse_path_common(mode, false)
17721757
}
17731758

1774-
fn parse_path_common(&mut self, mode: PathStyle, dont_parse_generics: bool)
1759+
fn parse_path_common(&mut self, mode: PathStyle, parse_generics: bool)
17751760
-> PResult<'a, ast::Path>
17761761
{
17771762
maybe_whole!(self, NtPath, |x| x);
@@ -1784,7 +1769,7 @@ impl<'a> Parser<'a> {
17841769
// A bound set is a set of type parameter bounds.
17851770
let mut segments = match mode {
17861771
PathStyle::Type => {
1787-
self.parse_path_segments_without_colons(dont_parse_generics)?
1772+
self.parse_path_segments_without_colons(parse_generics)?
17881773
}
17891774
PathStyle::Expr => {
17901775
self.parse_path_segments_with_colons()?
@@ -1829,7 +1814,7 @@ impl<'a> Parser<'a> {
18291814
/// - `a::b<T,U>::c<V,W>`
18301815
/// - `a::b<T,U>::c(V) -> W`
18311816
/// - `a::b<T,U>::c(V)`
1832-
pub fn parse_path_segments_without_colons(&mut self, dont_parse_generics: bool)
1817+
pub fn parse_path_segments_without_colons(&mut self, parse_generics: bool)
18331818
-> PResult<'a, Vec<PathSegment>>
18341819
{
18351820
let mut segments = Vec::new();
@@ -1850,8 +1835,7 @@ impl<'a> Parser<'a> {
18501835
}
18511836

18521837
// Parse types, optionally.
1853-
let parameters = if self.is_lt() && !dont_parse_generics {
1854-
let _ = self.eat_lt();
1838+
let parameters = if parse_generics && self.eat_lt() {
18551839
let (lifetimes, types, bindings) = self.parse_generic_args()?;
18561840
self.expect_gt()?;
18571841
ast::AngleBracketedParameterData {
@@ -2832,60 +2816,7 @@ impl<'a> Parser<'a> {
28322816
if op == AssocOp::As {
28332817
// Save the state of the parser before parsing type normally, in case there is a
28342818
// LessThan comparison after this cast.
2835-
let rp = self.get_rewind_point();
2836-
match self.parse_ty_no_plus() {
2837-
Ok(rhs) => {
2838-
lhs = self.mk_expr(lhs_span.to(rhs.span),
2839-
ExprKind::Cast(lhs, rhs), ThinVec::new());
2840-
}
2841-
Err(mut err) => {
2842-
// Rewind to before attempting to parse the type with generics, to get
2843-
// arround #22644.
2844-
let rp_err = self.get_rewind_point();
2845-
let sp = rp_err.span.clone();
2846-
self.rewind(rp);
2847-
let lo = self.span;
2848-
let path = match self.parse_path_without_generics(PathStyle::Type) {
2849-
Ok(path) => {
2850-
// Successfully parsed the type leaving a `<` yet to parse
2851-
err.cancel();
2852-
let codemap = self.sess.codemap();
2853-
let suggestion_span = lhs_span.to(self.prev_span);
2854-
let suggestion = match codemap.span_to_snippet(suggestion_span) {
2855-
Ok(lstring) => format!("({})", lstring),
2856-
_ => format!("(<expression>)")
2857-
};
2858-
let warn_message = match codemap.span_to_snippet(self.prev_span) {
2859-
Ok(lstring) => format!("`{}`", lstring),
2860-
_ => "a type".to_string(),
2861-
};
2862-
let msg = format!("`<` is interpreted as a start of generic \
2863-
arguments for {}, not a comparison",
2864-
warn_message);
2865-
let mut warn = self.sess.span_diagnostic.struct_span_warn(sp, &msg);
2866-
warn.span_label(sp, "interpreted as generic argument");
2867-
warn.span_label(self.span, "not interpreted as comparison");
2868-
warn.span_suggestion(suggestion_span,
2869-
"if you want to compare the casted value \
2870-
then write:",
2871-
suggestion);
2872-
warn.emit();
2873-
path
2874-
}
2875-
Err(mut path_err) => {
2876-
// Still couldn't parse, return original error and parser state
2877-
path_err.cancel();
2878-
self.rewind(rp_err);
2879-
return Err(err);
2880-
}
2881-
};
2882-
let path = TyKind::Path(None, path);
2883-
let span = lo.to(self.prev_span);
2884-
let rhs = P(Ty { node: path, span: span, id: ast::DUMMY_NODE_ID });
2885-
lhs = self.mk_expr(lhs_span.to(rhs.span),
2886-
ExprKind::Cast(lhs, rhs), ThinVec::new());
2887-
}
2888-
};
2819+
lhs = self.parse_assoc_op_as(lhs, lhs_span)?;
28892820
continue
28902821
} else if op == AssocOp::Colon {
28912822
let rhs = self.parse_ty_no_plus()?;
@@ -2983,6 +2914,67 @@ impl<'a> Parser<'a> {
29832914
Ok(lhs)
29842915
}
29852916

2917+
fn parse_assoc_op_as(&mut self, lhs: P<Expr>, lhs_span: Span) -> PResult<'a, P<Expr>> {
2918+
let rp = self.clone();
2919+
match self.parse_ty_no_plus() {
2920+
Ok(rhs) => {
2921+
Ok(self.mk_expr(lhs_span.to(rhs.span),
2922+
ExprKind::Cast(lhs, rhs),
2923+
ThinVec::new()))
2924+
}
2925+
Err(mut err) => {
2926+
let rp_err = self.clone();
2927+
let sp = rp_err.span.clone();
2928+
2929+
// Rewind to before attempting to parse the type with generics, to get
2930+
// arround #22644.
2931+
mem::replace(self, rp);
2932+
let lo = self.span;
2933+
match self.parse_path_without_generics(PathStyle::Type) {
2934+
Ok(path) => {
2935+
// Successfully parsed the type leaving a `<` yet to parse
2936+
err.cancel();
2937+
let codemap = self.sess.codemap();
2938+
let suggestion_span = lhs_span.to(self.prev_span);
2939+
let suggestion = match codemap.span_to_snippet(suggestion_span) {
2940+
Ok(lstring) => format!("({})", lstring),
2941+
_ => format!("(<expression> as <type>)")
2942+
};
2943+
let warn_message = match codemap.span_to_snippet(self.prev_span) {
2944+
Ok(lstring) => format!("`{}`", lstring),
2945+
_ => "a type".to_string(),
2946+
};
2947+
let msg = format!("`<` is interpreted as a start of generic \
2948+
arguments for {}, not a comparison",
2949+
warn_message);
2950+
let mut err = self.sess.span_diagnostic.struct_span_err(sp, &msg);
2951+
err.span_label(sp, "interpreted as generic argument");
2952+
err.span_label(self.span, "not interpreted as comparison");
2953+
err.span_suggestion(suggestion_span,
2954+
"if you want to compare the casted value then write:",
2955+
suggestion);
2956+
err.emit();
2957+
2958+
let path = TyKind::Path(None, path);
2959+
let span = lo.to(self.prev_span);
2960+
let rhs = P(Ty { node: path, span: span, id: ast::DUMMY_NODE_ID });
2961+
// Letting the parser accept the recovered type to avoid further errors,
2962+
// but the code will still not compile due to the error emitted above.
2963+
Ok(self.mk_expr(lhs_span.to(rhs.span),
2964+
ExprKind::Cast(lhs, rhs),
2965+
ThinVec::new()))
2966+
}
2967+
Err(mut path_err) => {
2968+
// Still couldn't parse, return original error and parser state
2969+
path_err.cancel();
2970+
mem::replace(self, rp_err);
2971+
Err(err)
2972+
}
2973+
}
2974+
}
2975+
}
2976+
}
2977+
29862978
/// Produce an error if comparison operators are chained (RFC #558).
29872979
/// We only need to check lhs, not rhs, because all comparison ops
29882980
/// have same precedence and are left-associative
@@ -6264,24 +6256,4 @@ impl<'a> Parser<'a> {
62646256
_ => Err(self.fatal("expected string literal"))
62656257
}
62666258
}
6267-
6268-
fn get_rewind_point(&mut self) -> RewindPoint {
6269-
RewindPoint {
6270-
token: self.token.clone(),
6271-
span: self.span,
6272-
meta_var_span: self.meta_var_span,
6273-
prev_span: self.prev_span,
6274-
token_cursor: self.token_cursor.clone(),
6275-
expected_tokens: self.expected_tokens.clone(),
6276-
}
6277-
}
6278-
6279-
fn rewind(&mut self, rp: RewindPoint) {
6280-
self.token = rp.token;
6281-
self.span = rp.span;
6282-
self.meta_var_span = rp.meta_var_span;
6283-
self.prev_span = rp.prev_span;
6284-
self.token_cursor = rp.token_cursor;
6285-
self.expected_tokens = rp.expected_tokens;
6286-
}
62876259
}

‎src/test/parse-fail/better-expected.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
// compile-flags: -Z parse-only
1212

1313
fn main() {
14-
let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, or `]`, found `3`
14+
let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3`
1515
}

‎src/test/parse-fail/bounds-type-where.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ type A where T: Trait + Trait = u8; // OK
1818
type A where = u8; // OK
1919
type A where T: Trait + = u8; // OK
2020
type A where T, = u8;
21-
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `:`, `==`, or `=`, found `,`
21+
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `:`, `<`, `==`, or `=`, found `,`
2222

2323
fn main() {}

‎src/test/parse-fail/closure-return-syntax.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313

1414
fn main() {
1515
let x = || -> i32 22;
16-
//~^ ERROR expected one of `!`, `(`, `::`, or `{`, found `22`
16+
//~^ ERROR expected one of `!`, `(`, `::`, `<`, or `{`, found `22`
1717
}

‎src/test/parse-fail/empty-impl-semicolon.rs

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

1111
// compile-flags: -Z parse-only
1212

13-
impl Foo; //~ ERROR expected one of `!`, `(`, `+`, `::`, `for`, `where`, or `{`, found `;`
13+
impl Foo; //~ ERROR expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `;`

‎src/test/parse-fail/multitrait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct S {
1515
}
1616

1717
impl Cmp, ToString for S {
18-
//~^ ERROR: expected one of `!`, `(`, `+`, `::`, `for`, `where`, or `{`, found `,`
18+
//~^ ERROR: expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found `,`
1919
fn eq(&&other: S) { false }
2020
fn to_string(&self) -> String { "hi".to_string() }
2121
}

‎src/test/parse-fail/removed-syntax-closure-lifetime.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
// compile-flags: -Z parse-only
1212

1313
type closure = Box<lt/fn()>;
14-
//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, or `>`, found `/`
14+
//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/`

‎src/test/parse-fail/removed-syntax-fixed-vec.rs

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

1111
// compile-flags: -Z parse-only
1212

13-
type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, or `]`, found `*`
13+
type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*`

‎src/test/parse-fail/removed-syntax-ptr-lifetime.rs

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

1111
// compile-flags: -Z parse-only
1212

13-
type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, or `;`, found `/`
13+
type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, or `<`, found `/`

‎src/test/ui/issue-22644.stderr

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
1+
error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
22
--> $DIR/issue-22644.rs:16:33
33
|
44
16 | println!("{}", a as usize < b);
@@ -9,7 +9,7 @@ warning: `<` is interpreted as a start of generic arguments for `usize`, not a c
99
help: if you want to compare the casted value then write:
1010
| println!("{}", (a as usize) < b);
1111

12-
warning: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
12+
error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
1313
--> $DIR/issue-22644.rs:17:33
1414
|
1515
17 | println!("{}", a as usize < 4);
@@ -20,3 +20,5 @@ warning: `<` is interpreted as a start of generic arguments for `usize`, not a c
2020
help: if you want to compare the casted value then write:
2121
| println!("{}", (a as usize) < 4);
2222

23+
error: aborting due to previous error(s)
24+

0 commit comments

Comments
 (0)
Please sign in to comment.