From 52acaa69743be657f7d3003ca2a2abf7f1cd7a2e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 3 Dec 2019 10:19:58 +0100 Subject: [PATCH] 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 +++--- ...sue-54109-and_instead_of_ampersands.stderr | 95 +++++++++++-------- 5 files changed, 100 insertions(+), 92 deletions(-) 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::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 @@ fn tokens_to_string(tokens: &[TokenType]) -> String { }; 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 @@ fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { /// /// 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::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 @@ fn error_block_no_opening_brace(&mut self) -> PResult<'a, T> { 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`. -- 2.44.0