From 903c9dfd1854d652dd5fb3e8c60231baeaec87bf Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 09:04:36 +0100 Subject: extract should_continue_as_assoc_expr --- src/librustc_parse/parser/expr.rs | 100 +++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 45 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index e4dff07e92c..f20d0aa2236 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -155,53 +155,13 @@ impl<'a> Parser<'a> { }; let last_type_ascription_set = self.last_type_ascription.is_some(); - match (self.expr_is_complete(&lhs), AssocOp::from_token(&self.token)) { - (true, None) => { - self.last_type_ascription = None; - // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 - return Ok(lhs); - } - (false, _) => {} // continue parsing the expression - // An exhaustive check is done in the following block, but these are checked first - // because they *are* ambiguous but also reasonable looking incorrect syntax, so we - // want to keep their span info to improve diagnostics in these cases in a later stage. - (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` - (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` - (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) - (true, Some(AssocOp::Add)) // `{ 42 } + 42 - // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: - // `if x { a } else { b } && if y { c } else { d }` - if !self.look_ahead(1, |t| t.is_reserved_ident()) => { - self.last_type_ascription = None; - // These cases are ambiguous and can't be identified in the parser alone - let sp = self.sess.source_map().start_point(self.token.span); - self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); - return Ok(lhs); - } - (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => { - self.last_type_ascription = None; - return Ok(lhs); - } - (true, Some(_)) => { - // We've found an expression that would be parsed as a statement, but the next - // token implies this should be parsed as an expression. - // For example: `if let Some(x) = x { x } else { 0 } / 2` - let mut err = self.struct_span_err(self.token.span, &format!( - "expected expression, found `{}`", - pprust::token_to_string(&self.token), - )); - err.span_label(self.token.span, "expected expression"); - self.sess.expr_parentheses_needed( - &mut err, - lhs.span, - Some(pprust::expr_to_string(&lhs), - )); - err.emit(); - } + if !self.should_continue_as_assoc_expr(&lhs) { + self.last_type_ascription = None; + return Ok(lhs); } - self.expected_tokens.push(TokenType::Operator); - while let Some(op) = AssocOp::from_token(&self.token) { + self.expected_tokens.push(TokenType::Operator); + while let Some(op) = self.check_assoc_op() { // Adjust the span for interpolated LHS to point to the `$lhs` token and not to what // it refers to. Interpolated identifiers are unwrapped early and never show up here // as `PrevTokenKind::Interpolated` so if LHS is a single identifier we always process @@ -338,6 +298,56 @@ impl<'a> Parser<'a> { Ok(lhs) } + fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool { + match (self.expr_is_complete(lhs), self.check_assoc_op()) { + // Semi-statement forms are odd: + // See https://github.com/rust-lang/rust/issues/29071 + (true, None) => false, + (false, _) => true, // Continue parsing the expression. + // An exhaustive check is done in the following block, but these are checked first + // because they *are* ambiguous but also reasonable looking incorrect syntax, so we + // want to keep their span info to improve diagnostics in these cases in a later stage. + (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` + (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` + (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) + (true, Some(AssocOp::Add)) // `{ 42 } + 42 + // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: + // `if x { a } else { b } && if y { c } else { d }` + if !self.look_ahead(1, |t| t.is_reserved_ident()) => { + // These cases are ambiguous and can't be identified in the parser alone. + let sp = self.sess.source_map().start_point(self.token.span); + self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); + false + } + (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => false, + (true, Some(_)) => { + self.error_found_expr_would_be_stmt(lhs); + true + } + } + } + + /// We've found an expression that would be parsed as a statement, + /// but the next token implies this should be parsed as an expression. + /// For example: `if let Some(x) = x { x } else { 0 } / 2`. + fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { + let mut err = self.struct_span_err(self.token.span, &format!( + "expected expression, found `{}`", + pprust::token_to_string(&self.token), + )); + err.span_label(self.token.span, "expected expression"); + self.sess.expr_parentheses_needed(&mut err, lhs.span, Some(pprust::expr_to_string(&lhs))); + err.emit(); + } + + /// Possibly translate the current token to an associative operator. + /// The method does not advance the current token. + /// + /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. + fn check_assoc_op(&self) -> Option { + AssocOp::from_token(&self.token) + } + /// Checks if this expression is a successfully parsed statement. fn expr_is_complete(&self, e: &Expr) -> bool { self.restrictions.contains(Restrictions::STMT_EXPR) && -- cgit 1.4.1-3-g733a5 From 52acaa69743be657f7d3003ca2a2abf7f1cd7a2e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 10:19:58 +0100 Subject: implement recovery in check_assoc_op --- src/librustc_parse/parser/diagnostics.rs | 18 +--- src/librustc_parse/parser/expr.rs | 26 +++++- src/librustc_parse/parser/stmt.rs | 22 +---- .../issue-54109-and_instead_of_ampersands.rs | 31 +++---- .../issue-54109-and_instead_of_ampersands.stderr | 95 +++++++++++++--------- 5 files changed, 100 insertions(+), 92 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index ba125cacab4..8b58fb03bf4 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -11,7 +11,7 @@ use syntax::ptr::P; use syntax::ThinVec; use syntax::util::parser::AssocOp; use syntax::struct_span_err; -use syntax_pos::symbol::{kw, sym}; +use syntax_pos::symbol::kw; use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; @@ -312,22 +312,6 @@ impl<'a> Parser<'a> { }; self.last_unexpected_token_span = Some(self.token.span); let mut err = self.fatal(&msg_exp); - if self.token.is_ident_named(sym::and) { - err.span_suggestion_short( - self.token.span, - "use `&&` instead of `and` for the boolean operator", - "&&".to_string(), - Applicability::MaybeIncorrect, - ); - } - if self.token.is_ident_named(sym::or) { - err.span_suggestion_short( - self.token.span, - "use `||` instead of `or` for the boolean operator", - "||".to_string(), - Applicability::MaybeIncorrect, - ); - } let sp = if self.token == token::Eof { // This is EOF; don't want to point at the following char, but rather the last token. self.prev_span diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index f20d0aa2236..0792f1b3b7f 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -345,7 +345,31 @@ impl<'a> Parser<'a> { /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. fn check_assoc_op(&self) -> Option { - AssocOp::from_token(&self.token) + match (AssocOp::from_token(&self.token), &self.token.kind) { + (op @ Some(_), _) => op, + (None, token::Ident(sym::and, false)) => { + self.error_bad_logical_op("and", "&&", "conjunction"); + Some(AssocOp::LAnd) + } + (None, token::Ident(sym::or, false)) => { + self.error_bad_logical_op("or", "||", "disjunction"); + Some(AssocOp::LOr) + } + _ => None, + } + } + + /// Error on `and` and `or` suggesting `&&` and `||` respectively. + fn error_bad_logical_op(&self, bad: &str, good: &str, english: &str) { + self.struct_span_err(self.token.span, &format!("`{}` is not a logical operator", bad)) + .span_suggestion( + self.token.span, + &format!("instead of `{}`, use `{}` to perform logical {}", bad, good, english), + good.to_string(), + Applicability::MachineApplicable, + ) + .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators") + .emit(); } /// Checks if this expression is a successfully parsed statement. diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index d1ed6968fb9..036badfe75d 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -15,7 +15,7 @@ use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac}; use syntax::util::classify; use syntax::token; use syntax_pos::source_map::{respan, Span}; -use syntax_pos::symbol::{kw, sym}; +use syntax_pos::symbol::kw; use std::mem; @@ -301,25 +301,7 @@ impl<'a> Parser<'a> { let sp = self.token.span; let tok = self.this_token_descr(); let mut e = self.span_fatal(sp, &format!("expected `{{`, found {}", tok)); - let do_not_suggest_help = - self.token.is_keyword(kw::In) || self.token == token::Colon; - - if self.token.is_ident_named(sym::and) { - e.span_suggestion_short( - self.token.span, - "use `&&` instead of `and` for the boolean operator", - "&&".to_string(), - Applicability::MaybeIncorrect, - ); - } - if self.token.is_ident_named(sym::or) { - e.span_suggestion_short( - self.token.span, - "use `||` instead of `or` for the boolean operator", - "||".to_string(), - Applicability::MaybeIncorrect, - ); - } + let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon; // Check to see if the user has written something like // diff --git a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs index 687479bad3f..44421b077fa 100644 --- a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs +++ b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs @@ -1,17 +1,25 @@ +fn main() {} + fn test_and() { let a = true; let b = false; - if a and b { - //~^ ERROR expected `{`, found `and` + + let _ = a and b; //~ ERROR `and` is not a logical operator + + if a and b { //~ ERROR `and` is not a logical operator println!("both"); } + + let _recovery_witness: () = 0; //~ ERROR mismatched types } fn test_or() { let a = true; let b = false; - if a or b { - //~^ ERROR expected `{`, found `or` + + let _ = a or b; //~ ERROR `or` is not a logical operator + + if a or b { //~ ERROR `or` is not a logical operator println!("both"); } } @@ -19,8 +27,7 @@ fn test_or() { fn test_and_par() { let a = true; let b = false; - if (a and b) { - //~^ ERROR expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and` + if (a and b) { //~ ERROR `and` is not a logical operator println!("both"); } } @@ -28,8 +35,7 @@ fn test_and_par() { fn test_or_par() { let a = true; let b = false; - if (a or b) { - //~^ ERROR expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `or` + if (a or b) { //~ ERROR `or` is not a logical operator println!("both"); } } @@ -37,8 +43,7 @@ fn test_or_par() { fn test_while_and() { let a = true; let b = false; - while a and b { - //~^ ERROR expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and` + while a and b { //~ ERROR `and` is not a logical operator println!("both"); } } @@ -46,11 +51,7 @@ fn test_while_and() { fn test_while_or() { let a = true; let b = false; - while a or b { - //~^ ERROR expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or` + while a or b { //~ ERROR `or` is not a logical operator println!("both"); } } - -fn main() { -} diff --git a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr index f230395f7a5..62c6204fb6f 100644 --- a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr +++ b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr @@ -1,58 +1,75 @@ -error: expected `{`, found `and` - --> $DIR/issue-54109-and_instead_of_ampersands.rs:4:10 +error: `and` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15 + | +LL | let _ = a and b; + | ^^^ help: instead of `and`, use `&&` to perform logical conjunction: `&&` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators + +error: `and` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10 | LL | if a and b { - | -- ^^^ - | | | - | | expected `{` - | | help: use `&&` instead of `and` for the boolean operator - | this `if` statement has a condition, but no block + | ^^^ help: instead of `and`, use `&&` to perform logical conjunction: `&&` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators + +error: `or` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15 + | +LL | let _ = a or b; + | ^^ help: instead of `or`, use `||` to perform logical disjunction: `||` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: expected `{`, found `or` - --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:10 +error: `or` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10 | LL | if a or b { - | -- ^^ - | | | - | | expected `{` - | | help: use `||` instead of `or` for the boolean operator - | this `if` statement has a condition, but no block + | ^^ help: instead of `or`, use `||` to perform logical disjunction: `||` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and` - --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:11 +error: `and` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11 | LL | if (a and b) { - | ^^^ - | | - | expected one of 8 possible tokens - | help: use `&&` instead of `and` for the boolean operator + | ^^^ help: instead of `and`, use `&&` to perform logical conjunction: `&&` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `or` - --> $DIR/issue-54109-and_instead_of_ampersands.rs:31:11 +error: `or` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11 | LL | if (a or b) { - | ^^ - | | - | expected one of 8 possible tokens - | help: use `||` instead of `or` for the boolean operator + | ^^ help: instead of `or`, use `||` to perform logical disjunction: `||` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and` - --> $DIR/issue-54109-and_instead_of_ampersands.rs:40:13 +error: `and` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13 | LL | while a and b { - | ^^^ - | | - | expected one of `!`, `.`, `::`, `?`, `{`, or an operator - | help: use `&&` instead of `and` for the boolean operator + | ^^^ help: instead of `and`, use `&&` to perform logical conjunction: `&&` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators -error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or` - --> $DIR/issue-54109-and_instead_of_ampersands.rs:49:13 +error: `or` is not a logical operator + --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13 | LL | while a or b { - | ^^ - | | - | expected one of `!`, `.`, `::`, `?`, `{`, or an operator - | help: use `||` instead of `or` for the boolean operator + | ^^ help: instead of `or`, use `||` to perform logical disjunction: `||` + | + = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators + +error[E0308]: mismatched types + --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33 + | +LL | let _recovery_witness: () = 0; + | -- ^ expected `()`, found integer + | | + | expected due to this -error: aborting due to 6 previous errors +error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From dd15904a4dc77a74046ffe47ce8592d06bea60a6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 10:30:40 +0100 Subject: parse_bottom_expr: use else if --- src/librustc_parse/parser/expr.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 0792f1b3b7f..7af9b7267a8 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1093,21 +1093,20 @@ impl<'a> Parser<'a> { let (await_hi, e_kind) = self.parse_incorrect_await_syntax(lo, self.prev_span)?; hi = await_hi; ex = e_kind; + } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { + // Don't complain about bare semicolons after unclosed braces + // recovery in order to keep the error count down. Fixing the + // delimiters will possibly also fix the bare semicolon found in + // expression context. For example, silence the following error: + // + // error: expected expression, found `;` + // --> file.rs:2:13 + // | + // 2 | foo(bar(; + // | ^ expected expression + self.bump(); + return Ok(self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new())); } else { - if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { - // Don't complain about bare semicolons after unclosed braces - // recovery in order to keep the error count down. Fixing the - // delimiters will possibly also fix the bare semicolon found in - // expression context. For example, silence the following error: - // - // error: expected expression, found `;` - // --> file.rs:2:13 - // | - // 2 | foo(bar(; - // | ^ expected expression - self.bump(); - return Ok(self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new())); - } parse_lit!() } } -- cgit 1.4.1-3-g733a5 From 0c32ee17815ee2ba77e44045f89c19a46580c785 Mon Sep 17 00:00:00 2001 From: A C Date: Mon, 16 Sep 2019 21:45:43 +0100 Subject: Clean up `parse_bottom_expr` --- src/librustc_parse/parser/expr.rs | 99 +++++++++++++++------------------------ 1 file changed, 39 insertions(+), 60 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 7af9b7267a8..1033a815985 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -91,24 +91,29 @@ impl<'a> Parser<'a> { self.parse_expr_res(Restrictions::empty(), None) } + fn parse_expr_catch_underscore(&mut self) -> PResult<'a, P> { + match self.parse_expr() { + Ok(expr) => Ok(expr), + Err(mut err) => match self.token.kind { + token::Ident(name, false) + if name == kw::Underscore && self.look_ahead(1, |t| { + t == &token::Comma + }) => { + // Special-case handling of `foo(_, _, _)` + err.emit(); + let sp = self.token.span; + self.bump(); + Ok(self.mk_expr(sp, ExprKind::Err, ThinVec::new())) + } + _ => Err(err), + }, + } + } + + /// Parses a sequence of expressions bounded by parentheses. fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { self.parse_paren_comma_seq(|p| { - match p.parse_expr() { - Ok(expr) => Ok(expr), - Err(mut err) => match p.token.kind { - token::Ident(name, false) - if name == kw::Underscore && p.look_ahead(1, |t| { - t == &token::Comma - }) => { - // Special-case handling of `foo(_, _, _)` - err.emit(); - let sp = p.token.span; - p.bump(); - Ok(p.mk_expr(sp, ExprKind::Err, ThinVec::new())) - } - _ => Err(err), - }, - } + p.parse_expr_catch_underscore() }).map(|(r, _)| r) } @@ -845,51 +850,25 @@ impl<'a> Parser<'a> { parse_lit!() } token::OpenDelim(token::Paren) => { - self.bump(); - - attrs.extend(self.parse_inner_attributes()?); - - // `(e)` is parenthesized `e`. - // `(e,)` is a tuple with only one field, `e`. - let mut es = vec![]; - let mut trailing_comma = false; - let mut recovered = false; - while self.token != token::CloseDelim(token::Paren) { - es.push(match self.parse_expr() { - Ok(es) => es, - Err(mut err) => { - // Recover from parse error in tuple list. - match self.token.kind { - token::Ident(name, false) - if name == kw::Underscore && self.look_ahead(1, |t| { - t == &token::Comma - }) => { - // Special-case handling of `Foo<(_, _, _)>` - err.emit(); - let sp = self.token.span; - self.bump(); - self.mk_expr(sp, ExprKind::Err, ThinVec::new()) - } - _ => return Ok( - self.recover_seq_parse_error(token::Paren, lo, Err(err)), - ), - } - } - }); - recovered = self.expect_one_of( - &[], - &[token::Comma, token::CloseDelim(token::Paren)], - )?; - if self.eat(&token::Comma) { - trailing_comma = true; - } else { - trailing_comma = false; - break; + let mut first = true; + let parse_leading_attr_expr = |this: &mut Parser<'a>| { + if first { + attrs.extend(this.parse_inner_attributes()?); + first = false; } - } - if !recovered { - self.bump(); - } + this.parse_expr_catch_underscore() + }; + + // (e) is parenthesized e + // (e,) is a tuple with only one field, e + let (es, trailing_comma) = + match self.parse_paren_comma_seq(parse_leading_attr_expr) + { + Ok(x) => x, + Err(err) => return Ok( + self.recover_seq_parse_error(token::Paren, lo, Err(err)), + ), + }; hi = self.prev_span; ex = if es.len() == 1 && !trailing_comma { -- cgit 1.4.1-3-g733a5 From 9cb2b08a5d9f458fdcb20ae38bace2a49e7759ff Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 11:36:40 +0100 Subject: extract parse_tuple_parens_expr --- src/librustc_parse/parser/expr.rs | 65 +++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 34 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 1033a815985..29778b73d4a 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -834,9 +834,7 @@ impl<'a> Parser<'a> { hi = self.prev_span; ex = ExprKind::Lit(literal); } - None => { - return Err(self.expected_expression_found()); - } + None => return Err(self.expected_expression_found()), } } } @@ -846,37 +844,8 @@ impl<'a> Parser<'a> { // This match arm is a special-case of the `_` match arm below and // could be removed without changing functionality, but it's faster // to have it here, especially for programs with large constants. - token::Literal(_) => { - parse_lit!() - } - token::OpenDelim(token::Paren) => { - let mut first = true; - let parse_leading_attr_expr = |this: &mut Parser<'a>| { - if first { - attrs.extend(this.parse_inner_attributes()?); - first = false; - } - this.parse_expr_catch_underscore() - }; - - // (e) is parenthesized e - // (e,) is a tuple with only one field, e - let (es, trailing_comma) = - match self.parse_paren_comma_seq(parse_leading_attr_expr) - { - Ok(x) => x, - Err(err) => return Ok( - self.recover_seq_parse_error(token::Paren, lo, Err(err)), - ), - }; - - hi = self.prev_span; - ex = if es.len() == 1 && !trailing_comma { - ExprKind::Paren(es.into_iter().nth(0).unwrap()) - } else { - ExprKind::Tup(es) - }; - } + token::Literal(_) => parse_lit!(), + token::OpenDelim(token::Paren) => return self.parse_tuple_parens_expr(), token::OpenDelim(token::Brace) => { return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs); } @@ -1095,6 +1064,34 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + fn parse_tuple_parens_expr(&mut self) -> PResult<'a, P> { + let lo = self.token.span; + let mut first = true; + let mut attrs = ThinVec::new(); + let parse_leading_attr_expr = |p: &mut Self| { + if first { + // `(#![foo] a, b, ...)` is OK... + attrs = p.parse_inner_attributes()?.into(); + // ...but not `(a, #![foo] b, ...)`. + first = false; + } + p.parse_expr_catch_underscore() + }; + let (es, trailing_comma) = match self.parse_paren_comma_seq(parse_leading_attr_expr) { + Ok(x) => x, + Err(err) => return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err))), + }; + let kind = if es.len() == 1 && !trailing_comma { + // `(e)` is parenthesized `e`. + ExprKind::Paren(es.into_iter().nth(0).unwrap()) + } else { + // `(e,)` is a tuple with only one field, `e`. + ExprKind::Tup(es) + }; + let expr = self.mk_expr(lo.to(self.prev_span), kind, attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. -- cgit 1.4.1-3-g733a5 From cb985ba60f87124c763e4db7d5f912771f9ad772 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 11:49:56 +0100 Subject: extract parse_array_or_repeat_expr --- src/librustc_parse/parser/expr.rs | 84 ++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 41 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 29778b73d4a..b0ff7987149 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -820,7 +820,7 @@ impl<'a> Parser<'a> { // // Therefore, prevent sub-parser from parsing // attributes by giving them a empty "already-parsed" list. - let mut attrs = ThinVec::new(); + let attrs = ThinVec::new(); let lo = self.token.span; let mut hi = self.token.span; @@ -849,46 +849,8 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Brace) => { return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs); } - token::BinOp(token::Or) | token::OrOr => { - return self.parse_closure_expr(attrs); - } - token::OpenDelim(token::Bracket) => { - self.bump(); - - attrs.extend(self.parse_inner_attributes()?); - - if self.eat(&token::CloseDelim(token::Bracket)) { - // Empty vector - ex = ExprKind::Array(Vec::new()); - } else { - // Non-empty vector - let first_expr = self.parse_expr()?; - if self.eat(&token::Semi) { - // Repeating array syntax: `[ 0; 512 ]` - let count = AnonConst { - id: DUMMY_NODE_ID, - value: self.parse_expr()?, - }; - self.expect(&token::CloseDelim(token::Bracket))?; - ex = ExprKind::Repeat(first_expr, count); - } else if self.eat(&token::Comma) { - // Vector with two or more elements - let remaining_exprs = self.parse_seq_to_end( - &token::CloseDelim(token::Bracket), - SeqSep::trailing_allowed(token::Comma), - |p| Ok(p.parse_expr()?) - )?; - let mut exprs = vec![first_expr]; - exprs.extend(remaining_exprs); - ex = ExprKind::Array(exprs); - } else { - // Vector with one element - self.expect(&token::CloseDelim(token::Bracket))?; - ex = ExprKind::Array(vec![first_expr]); - } - } - hi = self.prev_span; - } + token::BinOp(token::Or) | token::OrOr => return self.parse_closure_expr(attrs), + token::OpenDelim(token::Bracket) => return self.parse_array_or_repeat_expr(), _ => { if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; @@ -1092,6 +1054,46 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + fn parse_array_or_repeat_expr(&mut self) -> PResult<'a, P> { + let lo = self.token.span; + self.bump(); // `[` + + let attrs = self.parse_inner_attributes()?.into(); + + let kind = if self.eat(&token::CloseDelim(token::Bracket)) { + // Empty vector + ExprKind::Array(Vec::new()) + } else { + // Non-empty vector + let first_expr = self.parse_expr()?; + if self.eat(&token::Semi) { + // Repeating array syntax: `[ 0; 512 ]` + let count = AnonConst { + id: DUMMY_NODE_ID, + value: self.parse_expr()?, + }; + self.expect(&token::CloseDelim(token::Bracket))?; + ExprKind::Repeat(first_expr, count) + } else if self.eat(&token::Comma) { + // Vector with two or more elements. + let remaining_exprs = self.parse_seq_to_end( + &token::CloseDelim(token::Bracket), + SeqSep::trailing_allowed(token::Comma), + |p| Ok(p.parse_expr()?) + )?; + let mut exprs = vec![first_expr]; + exprs.extend(remaining_exprs); + ExprKind::Array(exprs) + } else { + // Vector with one element + self.expect(&token::CloseDelim(token::Bracket))?; + ExprKind::Array(vec![first_expr]) + } + }; + let expr = self.mk_expr(lo.to(self.prev_span), kind, attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. -- cgit 1.4.1-3-g733a5 From 5f0f86b6cae9a3ce8007eff5a655ae63899047dc Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 12:43:45 +0100 Subject: extract parse_path_start_expr --- src/librustc_parse/parser/expr.rs | 57 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index b0ff7987149..aaba59c520c 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -854,36 +854,11 @@ impl<'a> Parser<'a> { _ => { if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; - hi = path.span; + let hi = path.span; return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } if self.token.is_path_start() { - let path = self.parse_path(PathStyle::Expr)?; - - // `!`, as an operator, is prefix, so we know this isn't that. - if self.eat(&token::Not) { - // MACRO INVOCATION expression - let args = self.parse_mac_args()?; - hi = self.prev_span; - ex = ExprKind::Mac(Mac { - path, - args, - prior_type_ascription: self.last_type_ascription, - }); - } else if self.check(&token::OpenDelim(token::Brace)) { - if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) { - return expr; - } else { - hi = path.span; - ex = ExprKind::Path(None, path); - } - } else { - hi = path.span; - ex = ExprKind::Path(None, path); - } - - let expr = self.mk_expr(lo.to(hi), ex, attrs); - return self.maybe_recover_from_bad_qpath(expr, true); + return self.parse_path_start_expr(); } if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { return self.parse_closure_expr(attrs); @@ -1094,6 +1069,34 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + fn parse_path_start_expr(&mut self) -> PResult<'a, P> { + let attrs = ThinVec::new(); + let lo = self.token.span; + let path = self.parse_path(PathStyle::Expr)?; + + // `!`, as an operator, is prefix, so we know this isn't that. + let (hi, kind) = if self.eat(&token::Not) { + // MACRO INVOCATION expression + let mac = Mac { + path, + args: self.parse_mac_args()?, + prior_type_ascription: self.last_type_ascription, + }; + (self.prev_span, ExprKind::Mac(mac)) + } else if self.check(&token::OpenDelim(token::Brace)) { + if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) { + return expr; + } else { + (path.span, ExprKind::Path(None, path)) + } + } else { + (path.span, ExprKind::Path(None, path)) + }; + + let expr = self.mk_expr(lo.to(hi), kind, attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. -- cgit 1.4.1-3-g733a5 From 3ed5ba7fa867d84ca9e7bc9213a5b571fdb7c5ed Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 12:48:08 +0100 Subject: extract parse_labeled_expr --- src/librustc_parse/parser/expr.rs | 54 +++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 25 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index aaba59c520c..923e5d378c5 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -867,35 +867,13 @@ impl<'a> Parser<'a> { return self.parse_if_expr(attrs); } if self.eat_keyword(kw::For) { - let lo = self.prev_span; - return self.parse_for_expr(None, lo, attrs); + return self.parse_for_expr(None, self.prev_span, attrs); } if self.eat_keyword(kw::While) { - let lo = self.prev_span; - return self.parse_while_expr(None, lo, attrs); + return self.parse_while_expr(None, self.prev_span, attrs); } if let Some(label) = self.eat_label() { - let lo = label.ident.span; - self.expect(&token::Colon)?; - if self.eat_keyword(kw::While) { - return self.parse_while_expr(Some(label), lo, attrs) - } - if self.eat_keyword(kw::For) { - return self.parse_for_expr(Some(label), lo, attrs) - } - if self.eat_keyword(kw::Loop) { - return self.parse_loop_expr(Some(label), lo, attrs) - } - if self.token == token::OpenDelim(token::Brace) { - return self.parse_block_expr(Some(label), - lo, - BlockCheckMode::Default, - attrs); - } - let msg = "expected `while`, `for`, `loop` or `{` after a label"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - return Err(err); + return self.parse_labeled_expr(label, attrs); } if self.eat_keyword(kw::Loop) { let lo = self.prev_span; @@ -1097,6 +1075,32 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + fn parse_labeled_expr( + &mut self, + label: Label, + attrs: ThinVec, + ) -> PResult<'a, P> { + let lo = label.ident.span; + self.expect(&token::Colon)?; + if self.eat_keyword(kw::While) { + return self.parse_while_expr(Some(label), lo, attrs) + } + if self.eat_keyword(kw::For) { + return self.parse_for_expr(Some(label), lo, attrs) + } + if self.eat_keyword(kw::Loop) { + return self.parse_loop_expr(Some(label), lo, attrs) + } + if self.token == token::OpenDelim(token::Brace) { + return self.parse_block_expr(Some(label), lo, BlockCheckMode::Default, attrs); + } + + let msg = "expected `while`, `for`, `loop` or `{` after a label"; + let mut err = self.fatal(msg); + err.span_label(self.token.span, msg); + return Err(err); + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. -- cgit 1.4.1-3-g733a5 From 4e01b709640d9760758a19ef0dc3732991c14d30 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 13:11:34 +0100 Subject: add recovery to parse_labeled_expr --- src/librustc_parse/parser/expr.rs | 8 +++++--- src/test/ui/parser/recover-labeled-non-block-expr.rs | 5 +++++ .../ui/parser/recover-labeled-non-block-expr.stderr | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/parser/recover-labeled-non-block-expr.rs create mode 100644 src/test/ui/parser/recover-labeled-non-block-expr.stderr (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 923e5d378c5..bfb10dd0f3a 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1096,9 +1096,11 @@ impl<'a> Parser<'a> { } let msg = "expected `while`, `for`, `loop` or `{` after a label"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - return Err(err); + self.struct_span_err(self.token.span, msg) + .span_label(self.token.span, msg) + .emit(); + // Continue as an expression in an effort to recover on `'label: non_block_expr`. + self.parse_expr() } /// Returns a string literal if the next token is a string literal. diff --git a/src/test/ui/parser/recover-labeled-non-block-expr.rs b/src/test/ui/parser/recover-labeled-non-block-expr.rs new file mode 100644 index 00000000000..be92170acf0 --- /dev/null +++ b/src/test/ui/parser/recover-labeled-non-block-expr.rs @@ -0,0 +1,5 @@ +fn main() { + 'label: 1 + 1; //~ ERROR expected `while`, `for`, `loop` or `{` after a label + + let _recovery_witness: () = 0; //~ ERROR mismatched types +} diff --git a/src/test/ui/parser/recover-labeled-non-block-expr.stderr b/src/test/ui/parser/recover-labeled-non-block-expr.stderr new file mode 100644 index 00000000000..771a915288c --- /dev/null +++ b/src/test/ui/parser/recover-labeled-non-block-expr.stderr @@ -0,0 +1,17 @@ +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/recover-labeled-non-block-expr.rs:2:13 + | +LL | 'label: 1 + 1; + | ^ expected `while`, `for`, `loop` or `{` after a label + +error[E0308]: mismatched types + --> $DIR/recover-labeled-non-block-expr.rs:4:33 + | +LL | let _recovery_witness: () = 0; + | -- ^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From 32ac9d0e45fe3a8a6b3666cb2e065b8f935ee0a4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 13:14:50 +0100 Subject: pass attr as param in new methods --- src/librustc_parse/parser/expr.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index bfb10dd0f3a..b4d828ff849 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -845,12 +845,12 @@ impl<'a> Parser<'a> { // could be removed without changing functionality, but it's faster // to have it here, especially for programs with large constants. token::Literal(_) => parse_lit!(), - token::OpenDelim(token::Paren) => return self.parse_tuple_parens_expr(), + token::OpenDelim(token::Paren) => return self.parse_tuple_parens_expr(attrs), token::OpenDelim(token::Brace) => { return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs); } token::BinOp(token::Or) | token::OrOr => return self.parse_closure_expr(attrs), - token::OpenDelim(token::Bracket) => return self.parse_array_or_repeat_expr(), + token::OpenDelim(token::Bracket) => return self.parse_array_or_repeat_expr(attrs), _ => { if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; @@ -858,7 +858,7 @@ impl<'a> Parser<'a> { return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } if self.token.is_path_start() { - return self.parse_path_start_expr(); + return self.parse_path_start_expr(attrs); } if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { return self.parse_closure_expr(attrs); @@ -979,14 +979,13 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_tuple_parens_expr(&mut self) -> PResult<'a, P> { + fn parse_tuple_parens_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let lo = self.token.span; let mut first = true; - let mut attrs = ThinVec::new(); let parse_leading_attr_expr = |p: &mut Self| { if first { // `(#![foo] a, b, ...)` is OK... - attrs = p.parse_inner_attributes()?.into(); + attrs.extend(p.parse_inner_attributes()?); // ...but not `(a, #![foo] b, ...)`. first = false; } @@ -1007,11 +1006,14 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_array_or_repeat_expr(&mut self) -> PResult<'a, P> { + fn parse_array_or_repeat_expr( + &mut self, + mut attrs: ThinVec, + ) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `[` - let attrs = self.parse_inner_attributes()?.into(); + attrs.extend(self.parse_inner_attributes()?); let kind = if self.eat(&token::CloseDelim(token::Bracket)) { // Empty vector @@ -1047,8 +1049,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_path_start_expr(&mut self) -> PResult<'a, P> { - let attrs = ThinVec::new(); + fn parse_path_start_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.token.span; let path = self.parse_path(PathStyle::Expr)?; -- cgit 1.4.1-3-g733a5 From 327641e35c10624e7c728fce269885c6e4f6a602 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 13:35:05 +0100 Subject: recover on 'do catch { .. }' --- src/librustc_parse/parser/expr.rs | 44 ++++++++++++++++--------- src/test/ui/parser/do-catch-suggests-try.rs | 7 +++- src/test/ui/parser/do-catch-suggests-try.stderr | 17 +++++++--- 3 files changed, 47 insertions(+), 21 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index b4d828ff849..292d277a678 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -876,14 +876,11 @@ impl<'a> Parser<'a> { return self.parse_labeled_expr(label, attrs); } if self.eat_keyword(kw::Loop) { - let lo = self.prev_span; - return self.parse_loop_expr(None, lo, attrs); + return self.parse_loop_expr(None, self.prev_span, attrs); } if self.eat_keyword(kw::Continue) { - let label = self.eat_label(); - let ex = ExprKind::Continue(label); - let hi = self.prev_span; - return Ok(self.mk_expr(lo.to(hi), ex, attrs)); + let kind = ExprKind::Continue(self.eat_label()); + return Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs)); } if self.eat_keyword(kw::Match) { let match_sp = self.prev_span; @@ -893,20 +890,14 @@ impl<'a> Parser<'a> { }); } if self.eat_keyword(kw::Unsafe) { - return self.parse_block_expr( - None, - lo, - BlockCheckMode::Unsafe(ast::UserProvided), - attrs); + let mode = BlockCheckMode::Unsafe(ast::UserProvided); + return self.parse_block_expr(None, lo, mode, attrs); } if self.is_do_catch_block() { - let mut db = self.fatal("found removed `do catch` syntax"); - db.help("following RFC #2388, the new non-placeholder syntax is `try`"); - return Err(db); + return self.recover_do_catch(attrs); } if self.is_try_block() { - let lo = self.token.span; - assert!(self.eat_keyword(kw::Try)); + self.expect_keyword(kw::Try)?; return self.parse_try_block(lo, attrs); } @@ -1104,6 +1095,27 @@ impl<'a> Parser<'a> { self.parse_expr() } + /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. + fn recover_do_catch(&mut self, attrs: ThinVec) -> PResult<'a, P> { + let lo = self.token.span; + + self.bump(); // `do` + self.bump(); // `catch` + + let span_dc = lo.to(self.prev_span); + self.struct_span_err(span_dc, "found removed `do catch` syntax") + .span_suggestion( + span_dc, + "replace with the new syntax", + "try".to_string(), + Applicability::MachineApplicable, + ) + .note("following RFC #2388, the new non-placeholder syntax is `try`") + .emit(); + + self.parse_try_block(lo, attrs) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. diff --git a/src/test/ui/parser/do-catch-suggests-try.rs b/src/test/ui/parser/do-catch-suggests-try.rs index d805ab75882..f64568d06e9 100644 --- a/src/test/ui/parser/do-catch-suggests-try.rs +++ b/src/test/ui/parser/do-catch-suggests-try.rs @@ -1,5 +1,10 @@ +#![feature(try_blocks)] + fn main() { let _: Option<()> = do catch {}; //~^ ERROR found removed `do catch` syntax - //~^^ HELP following RFC #2388, the new non-placeholder syntax is `try` + //~| replace with the new syntax + //~| following RFC #2388, the new non-placeholder syntax is `try` + + let _recovery_witness: () = 1; //~ ERROR mismatched types } diff --git a/src/test/ui/parser/do-catch-suggests-try.stderr b/src/test/ui/parser/do-catch-suggests-try.stderr index e151d4cf8a6..cd8907b7eac 100644 --- a/src/test/ui/parser/do-catch-suggests-try.stderr +++ b/src/test/ui/parser/do-catch-suggests-try.stderr @@ -1,10 +1,19 @@ error: found removed `do catch` syntax - --> $DIR/do-catch-suggests-try.rs:2:25 + --> $DIR/do-catch-suggests-try.rs:4:25 | LL | let _: Option<()> = do catch {}; - | ^^ + | ^^^^^^^^ help: replace with the new syntax: `try` | - = help: following RFC #2388, the new non-placeholder syntax is `try` + = note: following RFC #2388, the new non-placeholder syntax is `try` -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/do-catch-suggests-try.rs:9:33 + | +LL | let _recovery_witness: () = 1; + | -- ^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From 2f9b191886457f16876fe9ef08369f8d0774e200 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 14:01:24 +0100 Subject: extract parse_{expr_opt, return_expr, yield_expr} --- src/librustc_parse/parser/expr.rs | 65 ++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 31 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 292d277a678..ea96143f4e8 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -823,24 +823,18 @@ impl<'a> Parser<'a> { let attrs = ThinVec::new(); let lo = self.token.span; - let mut hi = self.token.span; - - let ex: ExprKind; macro_rules! parse_lit { () => { match self.parse_opt_lit() { - Some(literal) => { - hi = self.prev_span; - ex = ExprKind::Lit(literal); - } + Some(literal) => (self.prev_span, ExprKind::Lit(literal)), None => return Err(self.expected_expression_found()), } } } // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. - match self.token.kind { + let (hi, ex) = match self.token.kind { // This match arm is a special-case of the `_` match arm below and // could be removed without changing functionality, but it's faster // to have it here, especially for programs with large constants. @@ -911,13 +905,7 @@ impl<'a> Parser<'a> { }; } if self.eat_keyword(kw::Return) { - if self.token.can_begin_expr() { - let e = self.parse_expr()?; - hi = e.span; - ex = ExprKind::Ret(Some(e)); - } else { - ex = ExprKind::Ret(None); - } + return self.parse_return_expr(attrs); } else if self.eat_keyword(kw::Break) { let label = self.eat_label(); let e = if self.token.can_begin_expr() @@ -928,25 +916,13 @@ impl<'a> Parser<'a> { } else { None }; - ex = ExprKind::Break(label, e); - hi = self.prev_span; + (self.prev_span, ExprKind::Break(label, e)) } else if self.eat_keyword(kw::Yield) { - if self.token.can_begin_expr() { - let e = self.parse_expr()?; - hi = e.span; - ex = ExprKind::Yield(Some(e)); - } else { - ex = ExprKind::Yield(None); - } - - let span = lo.to(hi); - self.sess.gated_spans.gate(sym::generators, span); + return self.parse_yield_expr(attrs); } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { - let (await_hi, e_kind) = self.parse_incorrect_await_syntax(lo, self.prev_span)?; - hi = await_hi; - ex = e_kind; + self.parse_incorrect_await_syntax(lo, self.prev_span)? } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { // Don't complain about bare semicolons after unclosed braces // recovery in order to keep the error count down. Fixing the @@ -964,7 +940,7 @@ impl<'a> Parser<'a> { parse_lit!() } } - } + }; let expr = self.mk_expr(lo.to(hi), ex, attrs); self.maybe_recover_from_bad_qpath(expr, true) @@ -1116,6 +1092,33 @@ impl<'a> Parser<'a> { self.parse_try_block(lo, attrs) } + /// Parse an expression if the token can begin one. + fn parse_expr_opt(&mut self) -> PResult<'a, Option>> { + Ok(if self.token.can_begin_expr() { + Some(self.parse_expr()?) + } else { + None + }) + } + + /// Parse `"return" expr?`. + fn parse_return_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + let lo = self.prev_span; + let kind = ExprKind::Ret(self.parse_expr_opt()?); + let expr = self.mk_expr(lo.to(self.prev_span), kind, attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + + /// Parse `"yield" expr?`. + fn parse_yield_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + let lo = self.prev_span; + let kind = ExprKind::Yield(self.parse_expr_opt()?); + let span = lo.to(self.prev_span); + self.sess.gated_spans.gate(sym::generators, span); + let expr = self.mk_expr(span, kind, attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. -- cgit 1.4.1-3-g733a5 From a3c0ef1a8bd3822a8008462a01056cc4090516af Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 14:21:03 +0100 Subject: refactor parse_incorrect_await_syntax --- src/librustc_parse/parser/diagnostics.rs | 36 ++++++++++++++++++++------------ src/librustc_parse/parser/expr.rs | 2 +- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 8b58fb03bf4..cea17e4d006 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{self, PResult, Applicability, DiagnosticBuilder, Handler, pluralize}; use rustc_error_codes::*; use syntax::ast::{self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item}; -use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind}; +use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, Attribute}; use syntax::token::{self, TokenKind, token_can_begin_expr}; use syntax::print::pprust; use syntax::ptr::P; @@ -970,21 +970,32 @@ impl<'a> Parser<'a> { /// Consumes alternative await syntaxes like `await!()`, `await `, /// `await? `, `await()`, and `await { }`. - pub(super) fn parse_incorrect_await_syntax( + pub(super) fn recover_incorrect_await_syntax( &mut self, lo: Span, await_sp: Span, - ) -> PResult<'a, (Span, ExprKind)> { - if self.token == token::Not { + attrs: ThinVec, + ) -> PResult<'a, P> { + let (hi, expr, is_question) = if self.token == token::Not { // Handle `await!()`. - self.expect(&token::Not)?; - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_expr()?; - self.expect(&token::CloseDelim(token::Paren))?; - let sp = self.error_on_incorrect_await(lo, self.prev_span, &expr, false); - return Ok((sp, ExprKind::Await(expr))) - } + self.recover_await_macro()? + } else { + self.recover_await_prefix(await_sp)? + }; + let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question); + let expr = self.mk_expr(lo.to(sp), ExprKind::Await(expr), attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + + fn recover_await_macro(&mut self) -> PResult<'a, (Span, P, bool)> { + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr()?; + self.expect(&token::CloseDelim(token::Paren))?; + Ok((self.prev_span, expr, false)) + } + fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P, bool)> { let is_question = self.eat(&token::Question); // Handle `await? `. let expr = if self.token == token::OpenDelim(token::Brace) { // Handle `await { }`. @@ -1002,8 +1013,7 @@ impl<'a> Parser<'a> { err.span_label(await_sp, "while parsing this incorrect await expression"); err })?; - let sp = self.error_on_incorrect_await(lo, expr.span, &expr, is_question); - Ok((sp, ExprKind::Await(expr))) + Ok((expr.span, expr, is_question)) } fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span { diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index ea96143f4e8..9bc89a6f240 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -922,7 +922,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { - self.parse_incorrect_await_syntax(lo, self.prev_span)? + return self.recover_incorrect_await_syntax(lo, self.prev_span, attrs); } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { // Don't complain about bare semicolons after unclosed braces // recovery in order to keep the error count down. Fixing the -- cgit 1.4.1-3-g733a5 From e9a4d94c4445552830f5f08ba0903d90f1b42c16 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 15:06:34 +0100 Subject: extract parse_break_expr --- src/librustc_parse/parser/expr.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 9bc89a6f240..1d3c35c6466 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -907,16 +907,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Return) { return self.parse_return_expr(attrs); } else if self.eat_keyword(kw::Break) { - let label = self.eat_label(); - let e = if self.token.can_begin_expr() - && !(self.token == token::OpenDelim(token::Brace) - && self.restrictions.contains( - Restrictions::NO_STRUCT_LITERAL)) { - Some(self.parse_expr()?) - } else { - None - }; - (self.prev_span, ExprKind::Break(label, e)) + return self.parse_break_expr(attrs); } else if self.eat_keyword(kw::Yield) { return self.parse_yield_expr(attrs); } else if self.eat_keyword(kw::Let) { @@ -1109,6 +1100,21 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + /// Parse `"('label ":")? break expr?`. + fn parse_break_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + let lo = self.prev_span; + let label = self.eat_label(); + let kind = if self.token != token::OpenDelim(token::Brace) + || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) + { + self.parse_expr_opt()? + } else { + None + }; + let expr = self.mk_expr(lo.to(self.prev_span), ExprKind::Break(label, kind), attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + /// Parse `"yield" expr?`. fn parse_yield_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; -- cgit 1.4.1-3-g733a5 From 4311a4d7f9ea6a6b0638d8fbc447825075d9be94 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 15:31:45 +0100 Subject: extract parse_lit_expr and simplify --- src/librustc_parse/parser/expr.rs | 143 +++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 79 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 1d3c35c6466..9a22641ce81 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -822,98 +822,62 @@ impl<'a> Parser<'a> { // attributes by giving them a empty "already-parsed" list. let attrs = ThinVec::new(); - let lo = self.token.span; - - macro_rules! parse_lit { - () => { - match self.parse_opt_lit() { - Some(literal) => (self.prev_span, ExprKind::Lit(literal)), - None => return Err(self.expected_expression_found()), - } - } - } - // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. - let (hi, ex) = match self.token.kind { + let lo = self.token.span; + match self.token.kind { // This match arm is a special-case of the `_` match arm below and // could be removed without changing functionality, but it's faster // to have it here, especially for programs with large constants. - token::Literal(_) => parse_lit!(), - token::OpenDelim(token::Paren) => return self.parse_tuple_parens_expr(attrs), + token::Literal(_) => self.parse_lit_expr(attrs), + token::OpenDelim(token::Paren) => self.parse_tuple_parens_expr(attrs), token::OpenDelim(token::Brace) => { - return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs); + self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs) } - token::BinOp(token::Or) | token::OrOr => return self.parse_closure_expr(attrs), - token::OpenDelim(token::Bracket) => return self.parse_array_or_repeat_expr(attrs), + token::BinOp(token::Or) | token::OrOr => self.parse_closure_expr(attrs), + token::OpenDelim(token::Bracket) => self.parse_array_or_repeat_expr(attrs), _ => { if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; - let hi = path.span; - return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); - } - if self.token.is_path_start() { - return self.parse_path_start_expr(attrs); - } - if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { - return self.parse_closure_expr(attrs); - } - if self.eat_keyword(kw::If) { - return self.parse_if_expr(attrs); - } - if self.eat_keyword(kw::For) { - return self.parse_for_expr(None, self.prev_span, attrs); - } - if self.eat_keyword(kw::While) { - return self.parse_while_expr(None, self.prev_span, attrs); - } - if let Some(label) = self.eat_label() { - return self.parse_labeled_expr(label, attrs); - } - if self.eat_keyword(kw::Loop) { - return self.parse_loop_expr(None, self.prev_span, attrs); - } - if self.eat_keyword(kw::Continue) { + Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs)) + } else if self.token.is_path_start() { + self.parse_path_start_expr(attrs) + } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { + self.parse_closure_expr(attrs) + } else if self.eat_keyword(kw::If) { + self.parse_if_expr(attrs) + } else if self.eat_keyword(kw::For) { + self.parse_for_expr(None, self.prev_span, attrs) + } else if self.eat_keyword(kw::While) { + self.parse_while_expr(None, self.prev_span, attrs) + } else if let Some(label) = self.eat_label() { + self.parse_labeled_expr(label, attrs) + } else if self.eat_keyword(kw::Loop) { + self.parse_loop_expr(None, self.prev_span, attrs) + } else if self.eat_keyword(kw::Continue) { let kind = ExprKind::Continue(self.eat_label()); - return Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs)); - } - if self.eat_keyword(kw::Match) { + Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs)) + } else if self.eat_keyword(kw::Match) { let match_sp = self.prev_span; - return self.parse_match_expr(attrs).map_err(|mut err| { + self.parse_match_expr(attrs).map_err(|mut err| { err.span_label(match_sp, "while parsing this match expression"); err - }); - } - if self.eat_keyword(kw::Unsafe) { + }) + } else if self.eat_keyword(kw::Unsafe) { let mode = BlockCheckMode::Unsafe(ast::UserProvided); - return self.parse_block_expr(None, lo, mode, attrs); - } - if self.is_do_catch_block() { - return self.recover_do_catch(attrs); - } - if self.is_try_block() { + self.parse_block_expr(None, lo, mode, attrs) + } else if self.is_do_catch_block() { + self.recover_do_catch(attrs) + } else if self.is_try_block() { self.expect_keyword(kw::Try)?; - return self.parse_try_block(lo, attrs); - } - - // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. - let is_span_rust_2018 = self.token.span.rust_2018(); - if is_span_rust_2018 && self.check_keyword(kw::Async) { - return if self.is_async_block() { // Check for `async {` and `async move {`. - self.parse_async_block(attrs) - } else { - self.parse_closure_expr(attrs) - }; - } - if self.eat_keyword(kw::Return) { - return self.parse_return_expr(attrs); + self.parse_try_block(lo, attrs) + } else if self.eat_keyword(kw::Return) { + self.parse_return_expr(attrs) } else if self.eat_keyword(kw::Break) { - return self.parse_break_expr(attrs); + self.parse_break_expr(attrs) } else if self.eat_keyword(kw::Yield) { - return self.parse_yield_expr(attrs); + self.parse_yield_expr(attrs) } else if self.eat_keyword(kw::Let) { - return self.parse_let_expr(attrs); - } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { - return self.recover_incorrect_await_syntax(lo, self.prev_span, attrs); + self.parse_let_expr(attrs) } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { // Don't complain about bare semicolons after unclosed braces // recovery in order to keep the error count down. Fixing the @@ -926,15 +890,36 @@ impl<'a> Parser<'a> { // 2 | foo(bar(; // | ^ expected expression self.bump(); - return Ok(self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new())); + Ok(self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new())) + } else if self.token.span.rust_2018() { + // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. + if self.check_keyword(kw::Async) { + if self.is_async_block() { // Check for `async {` and `async move {`. + self.parse_async_block(attrs) + } else { + self.parse_closure_expr(attrs) + } + } else if self.eat_keyword(kw::Await) { + self.recover_incorrect_await_syntax(lo, self.prev_span, attrs) + } else { + self.parse_lit_expr(attrs) + } } else { - parse_lit!() + self.parse_lit_expr(attrs) } } - }; + } + } - let expr = self.mk_expr(lo.to(hi), ex, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + fn parse_lit_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + let lo = self.token.span; + match self.parse_opt_lit() { + Some(literal) => { + let expr = self.mk_expr(lo.to(self.prev_span), ExprKind::Lit(literal), attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + None => return Err(self.expected_expression_found()), + } } fn parse_tuple_parens_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { -- cgit 1.4.1-3-g733a5 From 948ff674f927c571bd43acf65bda9a488b7f640e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 15:32:05 +0100 Subject: use mk_expr_err more --- src/librustc_parse/parser/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 9a22641ce81..955cdb7b8e3 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -890,7 +890,7 @@ impl<'a> Parser<'a> { // 2 | foo(bar(; // | ^ expected expression self.bump(); - Ok(self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new())) + Ok(self.mk_expr_err(self.token.span)) } else if self.token.span.rust_2018() { // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. if self.check_keyword(kw::Async) { -- cgit 1.4.1-3-g733a5 From 3d5dbcb44ad3e023e88959da0b301ee382b2f74f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 16:38:08 +0100 Subject: simplify parse_bottom_expr more --- src/librustc_parse/parser/expr.rs | 154 +++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 78 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 955cdb7b8e3..4edfbc4ec9f 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -824,90 +824,88 @@ impl<'a> Parser<'a> { // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. let lo = self.token.span; - match self.token.kind { + if let token::Literal(_) = self.token.kind { // This match arm is a special-case of the `_` match arm below and // could be removed without changing functionality, but it's faster // to have it here, especially for programs with large constants. - token::Literal(_) => self.parse_lit_expr(attrs), - token::OpenDelim(token::Paren) => self.parse_tuple_parens_expr(attrs), - token::OpenDelim(token::Brace) => { - self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs) - } - token::BinOp(token::Or) | token::OrOr => self.parse_closure_expr(attrs), - token::OpenDelim(token::Bracket) => self.parse_array_or_repeat_expr(attrs), - _ => { - if self.eat_lt() { - let (qself, path) = self.parse_qpath(PathStyle::Expr)?; - Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs)) - } else if self.token.is_path_start() { - self.parse_path_start_expr(attrs) - } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { - self.parse_closure_expr(attrs) - } else if self.eat_keyword(kw::If) { - self.parse_if_expr(attrs) - } else if self.eat_keyword(kw::For) { - self.parse_for_expr(None, self.prev_span, attrs) - } else if self.eat_keyword(kw::While) { - self.parse_while_expr(None, self.prev_span, attrs) - } else if let Some(label) = self.eat_label() { - self.parse_labeled_expr(label, attrs) - } else if self.eat_keyword(kw::Loop) { - self.parse_loop_expr(None, self.prev_span, attrs) - } else if self.eat_keyword(kw::Continue) { - let kind = ExprKind::Continue(self.eat_label()); - Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs)) - } else if self.eat_keyword(kw::Match) { - let match_sp = self.prev_span; - self.parse_match_expr(attrs).map_err(|mut err| { - err.span_label(match_sp, "while parsing this match expression"); - err - }) - } else if self.eat_keyword(kw::Unsafe) { - let mode = BlockCheckMode::Unsafe(ast::UserProvided); - self.parse_block_expr(None, lo, mode, attrs) - } else if self.is_do_catch_block() { - self.recover_do_catch(attrs) - } else if self.is_try_block() { - self.expect_keyword(kw::Try)?; - self.parse_try_block(lo, attrs) - } else if self.eat_keyword(kw::Return) { - self.parse_return_expr(attrs) - } else if self.eat_keyword(kw::Break) { - self.parse_break_expr(attrs) - } else if self.eat_keyword(kw::Yield) { - self.parse_yield_expr(attrs) - } else if self.eat_keyword(kw::Let) { - self.parse_let_expr(attrs) - } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { - // Don't complain about bare semicolons after unclosed braces - // recovery in order to keep the error count down. Fixing the - // delimiters will possibly also fix the bare semicolon found in - // expression context. For example, silence the following error: - // - // error: expected expression, found `;` - // --> file.rs:2:13 - // | - // 2 | foo(bar(; - // | ^ expected expression - self.bump(); - Ok(self.mk_expr_err(self.token.span)) - } else if self.token.span.rust_2018() { - // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. - if self.check_keyword(kw::Async) { - if self.is_async_block() { // Check for `async {` and `async move {`. - self.parse_async_block(attrs) - } else { - self.parse_closure_expr(attrs) - } - } else if self.eat_keyword(kw::Await) { - self.recover_incorrect_await_syntax(lo, self.prev_span, attrs) - } else { - self.parse_lit_expr(attrs) - } + self.parse_lit_expr(attrs) + } else if self.check(&token::OpenDelim(token::Paren)) { + self.parse_tuple_parens_expr(attrs) + } else if self.check(&token::OpenDelim(token::Brace)) { + self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs) + } else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) { + self.parse_closure_expr(attrs) + } else if self.check(&token::OpenDelim(token::Bracket)) { + self.parse_array_or_repeat_expr(attrs) + } else if self.eat_lt() { + let (qself, path) = self.parse_qpath(PathStyle::Expr)?; + Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs)) + } else if self.token.is_path_start() { + self.parse_path_start_expr(attrs) + } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { + self.parse_closure_expr(attrs) + } else if self.eat_keyword(kw::If) { + self.parse_if_expr(attrs) + } else if self.eat_keyword(kw::For) { + self.parse_for_expr(None, self.prev_span, attrs) + } else if self.eat_keyword(kw::While) { + self.parse_while_expr(None, self.prev_span, attrs) + } else if let Some(label) = self.eat_label() { + self.parse_labeled_expr(label, attrs) + } else if self.eat_keyword(kw::Loop) { + self.parse_loop_expr(None, self.prev_span, attrs) + } else if self.eat_keyword(kw::Continue) { + let kind = ExprKind::Continue(self.eat_label()); + Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs)) + } else if self.eat_keyword(kw::Match) { + let match_sp = self.prev_span; + self.parse_match_expr(attrs).map_err(|mut err| { + err.span_label(match_sp, "while parsing this match expression"); + err + }) + } else if self.eat_keyword(kw::Unsafe) { + self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs) + } else if self.is_do_catch_block() { + self.recover_do_catch(attrs) + } else if self.is_try_block() { + self.expect_keyword(kw::Try)?; + self.parse_try_block(lo, attrs) + } else if self.eat_keyword(kw::Return) { + self.parse_return_expr(attrs) + } else if self.eat_keyword(kw::Break) { + self.parse_break_expr(attrs) + } else if self.eat_keyword(kw::Yield) { + self.parse_yield_expr(attrs) + } else if self.eat_keyword(kw::Let) { + self.parse_let_expr(attrs) + } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { + // Don't complain about bare semicolons after unclosed braces + // recovery in order to keep the error count down. Fixing the + // delimiters will possibly also fix the bare semicolon found in + // expression context. For example, silence the following error: + // + // error: expected expression, found `;` + // --> file.rs:2:13 + // | + // 2 | foo(bar(; + // | ^ expected expression + self.bump(); + Ok(self.mk_expr_err(self.token.span)) + } else if self.token.span.rust_2018() { + // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. + if self.check_keyword(kw::Async) { + if self.is_async_block() { // Check for `async {` and `async move {`. + self.parse_async_block(attrs) } else { - self.parse_lit_expr(attrs) + self.parse_closure_expr(attrs) } + } else if self.eat_keyword(kw::Await) { + self.recover_incorrect_await_syntax(lo, self.prev_span, attrs) + } else { + self.parse_lit_expr(attrs) } + } else { + self.parse_lit_expr(attrs) } } -- cgit 1.4.1-3-g733a5 From a0d20935cc7dc9057c683bb62a4ba74475f32aa2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 16:38:34 +0100 Subject: introduce 'type AttrVec' --- src/librustc/hir/lowering.rs | 7 +- src/librustc/hir/lowering/expr.rs | 18 ++-- src/librustc/hir/lowering/item.rs | 13 ++- src/librustc/hir/mod.rs | 7 +- src/librustc_interface/util.rs | 7 +- src/librustc_parse/parser/diagnostics.rs | 15 ++-- src/librustc_parse/parser/expr.rs | 133 +++++++++++++----------------- src/librustc_parse/parser/item.rs | 7 +- src/librustc_parse/parser/mod.rs | 9 +- src/librustc_parse/parser/pat.rs | 11 ++- src/librustc_parse/parser/path.rs | 3 +- src/librustc_parse/parser/stmt.rs | 15 ++-- src/libsyntax/ast.rs | 19 +++-- src/libsyntax/attr/mod.rs | 5 +- src/libsyntax/lib.rs | 1 - src/libsyntax/mut_visit.rs | 3 +- src/libsyntax_expand/base.rs | 3 +- src/libsyntax_expand/build.rs | 15 ++-- src/libsyntax_expand/placeholders.rs | 5 +- src/libsyntax_ext/asm.rs | 3 +- src/libsyntax_ext/concat_idents.rs | 4 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 5 +- 23 files changed, 136 insertions(+), 176 deletions(-) (limited to 'src/librustc_parse/parser/expr.rs') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3f8085f2344..6b83788298e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -53,7 +53,6 @@ use crate::util::nodemap::{DefIdMap, NodeMap}; use errors::Applicability; use rustc_data_structures::fx::FxHashSet; use rustc_index::vec::IndexVec; -use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::sync::Lrc; use std::collections::BTreeMap; @@ -1205,7 +1204,7 @@ impl<'a> LoweringContext<'a> { id: ty.id, kind: ExprKind::Path(qself.clone(), path.clone()), span: ty.span, - attrs: ThinVec::new(), + attrs: AttrVec::new(), }; let ct = self.with_new_scopes(|this| { @@ -2751,7 +2750,7 @@ impl<'a> LoweringContext<'a> { /// has no attributes and is not targeted by a `break`. fn lower_block_expr(&mut self, b: &Block) -> hir::Expr { let block = self.lower_block(b, false); - self.expr_block(block, ThinVec::new()) + self.expr_block(block, AttrVec::new()) } fn lower_pat(&mut self, p: &Pat) -> P { @@ -3102,7 +3101,7 @@ impl<'a> LoweringContext<'a> { fn stmt_let_pat( &mut self, - attrs: ThinVec, + attrs: AttrVec, span: Span, init: Option>, pat: P, diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index f8465baeb13..04031710dc5 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -1318,8 +1318,7 @@ impl LoweringContext<'_> { &mut self, span: Span, expr: P, - attrs: ThinVec - ) -> hir::Expr { + attrs: AttrVec) -> hir::Expr { self.expr(span, hir::ExprKind::DropTemps(expr), attrs) } @@ -1333,7 +1332,7 @@ impl LoweringContext<'_> { self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new()) } - fn expr_break(&mut self, span: Span, attrs: ThinVec) -> P { + fn expr_break(&mut self, span: Span, attrs: AttrVec) -> P { let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None); P(self.expr(span, expr_break, attrs)) } @@ -1404,7 +1403,7 @@ impl LoweringContext<'_> { span: Span, components: &[Symbol], params: Option>, - attrs: ThinVec, + attrs: AttrVec, ) -> hir::Expr { let path = self.std_path(span, components, params, true); self.expr( @@ -1423,7 +1422,7 @@ impl LoweringContext<'_> { span: Span, ident: Ident, binding: hir::HirId, - attrs: ThinVec, + attrs: AttrVec, ) -> hir::Expr { let expr_path = hir::ExprKind::Path(hir::QPath::Resolved( None, @@ -1459,16 +1458,11 @@ impl LoweringContext<'_> { self.expr_block(P(blk), ThinVec::new()) } - pub(super) fn expr_block(&mut self, b: P, attrs: ThinVec) -> hir::Expr { + pub(super) fn expr_block(&mut self, b: P, attrs: AttrVec) -> hir::Expr { self.expr(b.span, hir::ExprKind::Block(b, None), attrs) } - pub(super) fn expr( - &mut self, - span: Span, - kind: hir::ExprKind, - attrs: ThinVec - ) -> hir::Expr { + pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind, attrs: AttrVec) -> hir::Expr { hir::Expr { hir_id: self.next_id(), kind, span, attrs } } diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index 46c944fa678..6cae8e2cc04 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -11,7 +11,6 @@ use crate::hir::def_id::DefId; use crate::hir::def::{Res, DefKind}; use crate::util::nodemap::NodeMap; -use rustc_data_structures::thin_vec::ThinVec; use rustc_target::spec::abi; use std::collections::BTreeSet; @@ -899,7 +898,7 @@ impl LoweringContext<'_> { /// Construct `ExprKind::Err` for the given `span`. fn expr_err(&mut self, span: Span) -> hir::Expr { - self.expr(span, hir::ExprKind::Err, ThinVec::new()) + self.expr(span, hir::ExprKind::Err, AttrVec::new()) } fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem { @@ -1182,7 +1181,7 @@ impl LoweringContext<'_> { // // If this is the simple case, this parameter will end up being the same as the // original parameter, but with a different pattern id. - let mut stmt_attrs = ThinVec::new(); + let mut stmt_attrs = AttrVec::new(); stmt_attrs.extend(parameter.attrs.iter().cloned()); let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident); let new_parameter = hir::Param { @@ -1226,7 +1225,7 @@ impl LoweringContext<'_> { desugared_span, ident, hir::BindingAnnotation::Mutable); let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id); let move_stmt = this.stmt_let_pat( - ThinVec::new(), + AttrVec::new(), desugared_span, Some(P(move_expr)), move_pat, @@ -1271,7 +1270,7 @@ impl LoweringContext<'_> { let user_body = this.expr_drop_temps( desugared_span, P(user_body), - ThinVec::new(), + AttrVec::new(), ); // As noted above, create the final block like @@ -1288,9 +1287,9 @@ impl LoweringContext<'_> { statements.into(), Some(P(user_body)), ); - this.expr_block(P(body), ThinVec::new()) + this.expr_block(P(body), AttrVec::new()) }); - (HirVec::from(parameters), this.expr(body_span, async_expr, ThinVec::new())) + (HirVec::from(parameters), this.expr(body_span, async_expr, AttrVec::new())) }) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b354b01518..17f4ec34441 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -20,7 +20,7 @@ use errors::FatalError; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use syntax::source_map::Spanned; use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect}; -use syntax::ast::{Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy}; +use syntax::ast::{AttrVec, Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy}; pub use syntax::ast::{Mutability, Constness, Unsafety, Movability, CaptureBy}; pub use syntax::ast::{IsAuto, ImplPolarity, BorrowKind}; use syntax::attr::{InlineAttr, OptimizeAttr}; @@ -29,7 +29,6 @@ use syntax::tokenstream::TokenStream; use syntax::util::parser::ExprPrecedence; use rustc_target::spec::abi::Abi; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; -use rustc_data_structures::thin_vec::ThinVec; use rustc_macros::HashStable; use rustc_serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::{BTreeSet, BTreeMap}; @@ -1274,7 +1273,7 @@ pub struct Local { pub init: Option>, pub hir_id: HirId, pub span: Span, - pub attrs: ThinVec, + pub attrs: AttrVec, /// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop /// desugaring. Otherwise will be `Normal`. pub source: LocalSource, @@ -1459,7 +1458,7 @@ pub struct AnonConst { pub struct Expr { pub hir_id: HirId, pub kind: ExprKind, - pub attrs: ThinVec, + pub attrs: AttrVec, pub span: Span, } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 4d686fc310f..a8800082c9a 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -10,7 +10,6 @@ use rustc_data_structures::jobserver; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_errors::registry::Registry; use rustc_metadata::dynamic_lib::DynamicLibrary; @@ -24,7 +23,7 @@ use std::ops::DerefMut; use smallvec::SmallVec; use syntax::ptr::P; use syntax::mut_visit::{*, MutVisitor, visit_clobber}; -use syntax::ast::BlockCheckMode; +use syntax::ast::{AttrVec, BlockCheckMode}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::source_map::{FileLoader, RealFileLoader, SourceMap}; use syntax::symbol::{Symbol, sym}; @@ -741,7 +740,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: resolver.next_node_id(), kind: ast::ExprKind::Block(P(b), None), span: syntax_pos::DUMMY_SP, - attrs: ThinVec::new(), + attrs: AttrVec::new(), }); ast::Stmt { @@ -756,7 +755,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { kind: ast::ExprKind::Loop(P(empty_block), None), id: self.resolver.next_node_id(), span: syntax_pos::DUMMY_SP, - attrs: ThinVec::new(), + attrs: AttrVec::new(), }); let loop_stmt = ast::Stmt { diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index cea17e4d006..16daefd1450 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -4,11 +4,10 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{self, PResult, Applicability, DiagnosticBuilder, Handler, pluralize}; use rustc_error_codes::*; use syntax::ast::{self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item}; -use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, Attribute}; +use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, AttrVec}; use syntax::token::{self, TokenKind, token_can_begin_expr}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::ThinVec; use syntax::util::parser::AssocOp; use syntax::struct_span_err; use syntax_pos::symbol::kw; @@ -32,7 +31,7 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { id: ast::DUMMY_NODE_ID }; Param { - attrs: ThinVec::default(), + attrs: AttrVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, @@ -164,7 +163,7 @@ impl RecoverQPath for Expr { Self { span: path.span, kind: ExprKind::Path(qself, path), - attrs: ThinVec::new(), + attrs: AttrVec::new(), id: ast::DUMMY_NODE_ID, } } @@ -551,7 +550,7 @@ impl<'a> Parser<'a> { ); let mk_err_expr = |this: &Self, span| { - Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new()))) + Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new()))) }; match lhs.kind { @@ -974,7 +973,7 @@ impl<'a> Parser<'a> { &mut self, lo: Span, await_sp: Span, - attrs: ThinVec, + attrs: AttrVec, ) -> PResult<'a, P> { let (hi, expr, is_question) = if self.token == token::Not { // Handle `await!()`. @@ -1005,7 +1004,7 @@ impl<'a> Parser<'a> { None, self.token.span, BlockCheckMode::Default, - ThinVec::new(), + AttrVec::new(), ) } else { self.parse_expr() @@ -1126,7 +1125,7 @@ impl<'a> Parser<'a> { err.emit(); // Recover from parse error, callers expect the closing delim to be consumed. self.consume_block(delim, ConsumeClosingDelim::Yes); - self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) + self.mk_expr(lo.to(self.prev_span), ExprKind::Err, AttrVec::new()) } } } diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 4edfbc4ec9f..7afa3d665d6 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -4,11 +4,10 @@ use super::pat::{GateOr, PARAM_EXPECTED}; use super::diagnostics::Error; use crate::maybe_recover_from_interpolated_ty_qpath; -use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{PResult, Applicability}; -use syntax::ast::{self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode}; -use syntax::ast::{Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind}; -use syntax::ast::{FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit}; +use syntax::ast::{self, DUMMY_NODE_ID, AttrVec, AttrStyle, Ident, CaptureBy, Field, Lit}; +use syntax::ast::{BlockCheckMode, Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm}; +use syntax::ast::{Ty, TyKind, FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst}; use syntax::token::{self, Token, TokenKind}; use syntax::print::pprust; use syntax::ptr::P; @@ -37,14 +36,14 @@ macro_rules! maybe_whole_expr { let path = path.clone(); $p.bump(); return Ok($p.mk_expr( - $p.token.span, ExprKind::Path(None, path), ThinVec::new() + $p.token.span, ExprKind::Path(None, path), AttrVec::new() )); } token::NtBlock(block) => { let block = block.clone(); $p.bump(); return Ok($p.mk_expr( - $p.token.span, ExprKind::Block(block, None), ThinVec::new() + $p.token.span, ExprKind::Block(block, None), AttrVec::new() )); } // N.B., `NtIdent(ident)` is normalized to `Ident` in `fn bump`. @@ -57,16 +56,16 @@ macro_rules! maybe_whole_expr { #[derive(Debug)] pub(super) enum LhsExpr { NotYetParsed, - AttributesParsed(ThinVec), + AttributesParsed(AttrVec), AlreadyParsed(P), } -impl From>> for LhsExpr { +impl From> for LhsExpr { /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)` /// and `None` into `LhsExpr::NotYetParsed`. /// /// This conversion does not allocate. - fn from(o: Option>) -> Self { + fn from(o: Option) -> Self { if let Some(attrs) = o { LhsExpr::AttributesParsed(attrs) } else { @@ -103,7 +102,7 @@ impl<'a> Parser<'a> { err.emit(); let sp = self.token.span; self.bump(); - Ok(self.mk_expr(sp, ExprKind::Err, ThinVec::new())) + Ok(self.mk_expr(sp, ExprKind::Err, AttrVec::new())) } _ => Err(err), }, @@ -122,7 +121,7 @@ impl<'a> Parser<'a> { pub(super) fn parse_expr_res( &mut self, r: Restrictions, - already_parsed_attrs: Option> + already_parsed_attrs: Option ) -> PResult<'a, P> { self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) } @@ -134,7 +133,7 @@ impl<'a> Parser<'a> { #[inline] fn parse_assoc_expr( &mut self, - already_parsed_attrs: Option>, + already_parsed_attrs: Option, ) -> PResult<'a, P> { self.parse_assoc_expr_with(0, already_parsed_attrs.into()) } @@ -237,7 +236,7 @@ impl<'a> Parser<'a> { }; let r = self.mk_range(Some(lhs), rhs, limits)?; - lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs_span), r, AttrVec::new()); break } @@ -271,9 +270,9 @@ impl<'a> Parser<'a> { AssocOp::Greater | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); - self.mk_expr(span, binary, ThinVec::new()) + self.mk_expr(span, binary, AttrVec::new()) } - AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), + AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), AttrVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, @@ -288,7 +287,7 @@ impl<'a> Parser<'a> { token::Shr => BinOpKind::Shr, }; let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs); - self.mk_expr(span, aopexpr, ThinVec::new()) + self.mk_expr(span, aopexpr, AttrVec::new()) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => { self.bug("AssocOp should have been handled by special case") @@ -398,7 +397,7 @@ impl<'a> Parser<'a> { /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`. fn parse_prefix_range_expr( &mut self, - already_parsed_attrs: Option> + already_parsed_attrs: Option ) -> PResult<'a, P> { // Check for deprecated `...` syntax. if self.token == token::DotDotDot { @@ -435,10 +434,7 @@ impl<'a> Parser<'a> { } /// Parses a prefix-unary-operator expr. - fn parse_prefix_expr( - &mut self, - already_parsed_attrs: Option> - ) -> PResult<'a, P> { + fn parse_prefix_expr(&mut self, already_parsed_attrs: Option) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; let lo = self.token.span; // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() @@ -549,7 +545,7 @@ impl<'a> Parser<'a> { expr_kind: fn(P, P) -> ExprKind) -> PResult<'a, P> { let mk_expr = |this: &mut Self, rhs: P| { - this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), ThinVec::new()) + this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), AttrVec::new()) }; // Save the state of the parser before parsing type normally, in case there is a @@ -650,7 +646,7 @@ impl<'a> Parser<'a> { /// Parses `a.b` or `a(13)` or `a[4]` or just `a`. fn parse_dot_or_call_expr( &mut self, - already_parsed_attrs: Option>, + already_parsed_attrs: Option, ) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; @@ -663,7 +659,7 @@ impl<'a> Parser<'a> { &mut self, e0: P, lo: Span, - mut attrs: ThinVec, + mut attrs: AttrVec, ) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code @@ -692,7 +688,7 @@ impl<'a> Parser<'a> { // expr? while self.eat(&token::Question) { let hi = self.prev_span; - e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new()); + e = self.mk_expr(lo.to(hi), ExprKind::Try(e), AttrVec::new()); } // expr.f @@ -705,7 +701,7 @@ impl<'a> Parser<'a> { let span = self.token.span; self.bump(); let field = ExprKind::Field(e, Ident::new(symbol, span)); - e = self.mk_expr(lo.to(span), field, ThinVec::new()); + e = self.mk_expr(lo.to(span), field, AttrVec::new()); self.expect_no_suffix(span, "a tuple index", suffix); } @@ -754,7 +750,7 @@ impl<'a> Parser<'a> { let seq = self.parse_paren_expr_seq().map(|es| { let nd = self.mk_call(e, es); let hi = self.prev_span; - self.mk_expr(lo.to(hi), nd, ThinVec::new()) + self.mk_expr(lo.to(hi), nd, AttrVec::new()) }); e = self.recover_seq_parse_error(token::Paren, lo, seq); } @@ -767,7 +763,7 @@ impl<'a> Parser<'a> { hi = self.token.span; self.expect(&token::CloseDelim(token::Bracket))?; let index = self.mk_index(e, ix); - e = self.mk_expr(lo.to(hi), index, ThinVec::new()) + e = self.mk_expr(lo.to(hi), index, AttrVec::new()) } _ => return Ok(e) } @@ -791,7 +787,7 @@ impl<'a> Parser<'a> { args.insert(0, self_arg); let span = lo.to(self.prev_span); - self.mk_expr(span, ExprKind::MethodCall(segment, args), ThinVec::new()) + self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new()) } _ => { // Field access `expr.f` @@ -801,7 +797,7 @@ impl<'a> Parser<'a> { } let span = lo.to(self.prev_span); - self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), ThinVec::new()) + self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new()) } }) } @@ -820,7 +816,7 @@ impl<'a> Parser<'a> { // // Therefore, prevent sub-parser from parsing // attributes by giving them a empty "already-parsed" list. - let attrs = ThinVec::new(); + let attrs = AttrVec::new(); // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. let lo = self.token.span; @@ -909,7 +905,7 @@ impl<'a> Parser<'a> { } } - fn parse_lit_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; match self.parse_opt_lit() { Some(literal) => { @@ -920,7 +916,7 @@ impl<'a> Parser<'a> { } } - fn parse_tuple_parens_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { + fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; let mut first = true; let parse_leading_attr_expr = |p: &mut Self| { @@ -947,10 +943,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_array_or_repeat_expr( - &mut self, - mut attrs: ThinVec, - ) -> PResult<'a, P> { + fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `[` @@ -990,7 +983,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_path_start_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; let path = self.parse_path(PathStyle::Expr)?; @@ -1017,11 +1010,7 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } - fn parse_labeled_expr( - &mut self, - label: Label, - attrs: ThinVec, - ) -> PResult<'a, P> { + fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P> { let lo = label.ident.span; self.expect(&token::Colon)?; if self.eat_keyword(kw::While) { @@ -1046,7 +1035,7 @@ impl<'a> Parser<'a> { } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. - fn recover_do_catch(&mut self, attrs: ThinVec) -> PResult<'a, P> { + fn recover_do_catch(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; self.bump(); // `do` @@ -1076,7 +1065,7 @@ impl<'a> Parser<'a> { } /// Parse `"return" expr?`. - fn parse_return_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_span; let kind = ExprKind::Ret(self.parse_expr_opt()?); let expr = self.mk_expr(lo.to(self.prev_span), kind, attrs); @@ -1084,7 +1073,7 @@ impl<'a> Parser<'a> { } /// Parse `"('label ":")? break expr?`. - fn parse_break_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_span; let label = self.eat_label(); let kind = if self.token != token::OpenDelim(token::Brace) @@ -1099,7 +1088,7 @@ impl<'a> Parser<'a> { } /// Parse `"yield" expr?`. - fn parse_yield_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { + fn parse_yield_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.prev_span; let kind = ExprKind::Yield(self.parse_expr_opt()?); let span = lo.to(self.prev_span); @@ -1307,12 +1296,12 @@ impl<'a> Parser<'a> { let lo = self.token.span; let literal = self.parse_lit()?; let hi = self.prev_span; - let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); + let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), AttrVec::new()); if minus_present { let minus_hi = self.prev_span; let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) + Ok(self.mk_expr(minus_lo.to(minus_hi), unary, AttrVec::new())) } else { Ok(expr) } @@ -1324,7 +1313,7 @@ impl<'a> Parser<'a> { opt_label: Option