From 06d577d8b25b5f2e131005a6bcc2e142748016e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 19 Sep 2018 16:23:21 -0700 Subject: [PATCH] Detect `for _ in in bar {}` typo --- src/libsyntax/parse/parser.rs | 34 ++++++++++++++----- ...sue-54109-and_instead_of_ampersands.stderr | 12 ++++--- src/test/ui/parser/if-in-in.rs | 5 +++ src/test/ui/parser/if-in-in.stderr | 13 +++++++ 4 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/parser/if-in-in.rs create mode 100644 src/test/ui/parser/if-in-in.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 48e034b117f18..daf1f0857d9bb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2702,8 +2702,8 @@ impl<'a> Parser<'a> { token::Literal(token::Float(n), _suf) => { self.bump(); let fstr = n.as_str(); - let mut err = self.diagnostic().struct_span_err(self.prev_span, - &format!("unexpected token: `{}`", n)); + let mut err = self.diagnostic() + .struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); err.span_label(self.prev_span, "unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::().ok() { @@ -2863,8 +2863,8 @@ impl<'a> Parser<'a> { let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; let span_of_tilde = lo; - let mut err = self.diagnostic().struct_span_err(span_of_tilde, - "`~` cannot be used as a unary operator"); + let mut err = self.diagnostic() + .struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator"); err.span_suggestion_short_with_applicability( span_of_tilde, "use `!` to perform bitwise negation", @@ -3422,6 +3422,24 @@ impl<'a> Parser<'a> { ); err.emit(); } + let in_span = self.prev_span; + if self.eat_keyword(keywords::In) { + // a common typo: `for _ in in bar {}` + let mut err = self.sess.span_diagnostic.struct_span_err( + self.prev_span, + "expected iterable, found keyword `in`", + ); + err.span_suggestion_short_with_applicability( + in_span.until(self.prev_span), + "remove the duplicated `in`", + String::new(), + Applicability::MachineApplicable, + ); + err.note("if you meant to use emplacement syntax, it is obsolete (for now, anyway)"); + err.note("for more information on the status of emplacement syntax, see <\ + https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>"); + err.emit(); + } let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); @@ -4760,12 +4778,9 @@ impl<'a> Parser<'a> { if !self.eat(&token::OpenDelim(token::Brace)) { let sp = self.span; let tok = self.this_token_to_string(); - let mut do_not_suggest_help = false; let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok)); - if self.token.is_keyword(keywords::In) || self.token == token::Colon { - do_not_suggest_help = true; - e.span_label(sp, "expected `{`"); - } + let do_not_suggest_help = + self.token.is_keyword(keywords::In) || self.token == token::Colon; if self.token.is_ident_named("and") { e.span_suggestion_short_with_applicability( @@ -4796,6 +4811,7 @@ impl<'a> Parser<'a> { || do_not_suggest_help { // if the next token is an open brace (e.g., `if a b {`), the place- // inside-a-block suggestion would be more likely wrong than right + e.span_label(sp, "expected `{`"); return Err(e); } let mut stmt_span = stmt.span; 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 22845775aed13..aa54425efa342 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 @@ -2,16 +2,20 @@ error: expected `{`, found `and` --> $DIR/issue-54109-and_instead_of_ampersands.rs:14:10 | LL | if a and b { - | -- ^^^ help: use `&&` instead of `and` for the boolean operator - | | + | -- ^^^ + | | | + | | expected `{` + | | help: use `&&` instead of `and` for the boolean operator | this `if` statement has a condition, but no block error: expected `{`, found `or` --> $DIR/issue-54109-and_instead_of_ampersands.rs:23:10 | LL | if a or b { - | -- ^^ help: use `||` instead of `or` for the boolean operator - | | + | -- ^^ + | | | + | | expected `{` + | | help: use `||` instead of `or` for the boolean operator | this `if` statement has a condition, but no block error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and` diff --git a/src/test/ui/parser/if-in-in.rs b/src/test/ui/parser/if-in-in.rs new file mode 100644 index 0000000000000..9bc9aaff298db --- /dev/null +++ b/src/test/ui/parser/if-in-in.rs @@ -0,0 +1,5 @@ +fn main() { + for i in in 1..2 { + println!("{}", i); + } +} diff --git a/src/test/ui/parser/if-in-in.stderr b/src/test/ui/parser/if-in-in.stderr new file mode 100644 index 0000000000000..9926fcc0858e5 --- /dev/null +++ b/src/test/ui/parser/if-in-in.stderr @@ -0,0 +1,13 @@ +error: expected iterable, found keyword `in` + --> $DIR/if-in-in.rs:2:14 + | +LL | for i in in 1..2 { + | ---^^ + | | + | help: remove the duplicated `in` + | + = note: if you meant to use emplacement syntax, it is obsolete (for now, anyway) + = note: for more information on the status of emplacement syntax, see + +error: aborting due to previous error +