From 4980b77c8fecebe69862510c65f5ab400671b779 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 20 Oct 2020 16:48:04 -0700 Subject: [PATCH] Suggest adding missing braces in `const` block pattern Previously it would only suggest wrapping the code in braces in regular expressions; now it does it in patterns too. This is a squashed rebase of #78173 --- compiler/rustc_parse/src/parser/expr.rs | 4 +- compiler/rustc_parse/src/parser/mod.rs | 3 +- compiler/rustc_parse/src/parser/pat.rs | 10 ++-- compiler/rustc_parse/src/parser/stmt.rs | 14 +++-- tests/ui/parser/bad-if-statements.stderr | 4 -- tests/ui/parser/inline-const-pat-let.rs | 29 +++++++++ .../parser/inline-const-without-block.fixed | 60 +++++++++++++++++++ tests/ui/parser/inline-const-without-block.rs | 60 +++++++++++++++++++ .../parser/inline-const-without-block.stderr | 57 ++++++++++++++++++ .../ui/parser/keyword-const-as-identifier.rs | 6 +- .../parser/keyword-const-as-identifier.stderr | 20 ++++--- 11 files changed, 241 insertions(+), 26 deletions(-) create mode 100644 tests/ui/parser/inline-const-pat-let.rs create mode 100644 tests/ui/parser/inline-const-without-block.fixed create mode 100644 tests/ui/parser/inline-const-without-block.rs create mode 100644 tests/ui/parser/inline-const-without-block.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0ac6133e8289f..d67a69eee77cb 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1472,8 +1472,8 @@ impl<'a> Parser<'a> { err }, ) - } else if this.check_inline_const(0) { - this.parse_const_block(lo.to(this.token.span), false) + } else if this.eat_keyword(kw::Const) { + this.parse_const_block(lo.to(this.prev_token.span), false) } else if this.may_recover() && this.is_do_catch_block() { this.recover_do_catch() } else if this.is_try_block() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 186828baf01ed..965d9458c26bd 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1299,12 +1299,11 @@ impl<'a> Parser<'a> { } } - /// Parses inline const expressions. + /// Parses inline const expressions. The `const` keyword was already eaten. fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P> { if pat { self.psess.gated_spans.gate(sym::inline_const_pat, span); } - self.expect_keyword(kw::Const)?; let (attrs, blk) = self.parse_inner_attrs_and_block()?; let anon_const = AnonConst { id: DUMMY_NODE_ID, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index bd2ffaa0a892a..6dd670d7194a7 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -730,9 +730,9 @@ impl<'a> Parser<'a> { self.parse_pat_ident(BindingMode(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)? } else if self.eat_keyword(kw::Box) { self.parse_pat_box()? - } else if self.check_inline_const(0) { - // Parse `const pat` - let const_expr = self.parse_const_block(lo.to(self.token.span), true)?; + } else if self.eat_keyword(kw::Const) { + // Parse `const { pat }` + let const_expr = self.parse_const_block(lo.to(self.prev_token.span), true)?; if let Some(re) = self.parse_range_end() { self.parse_pat_range_begin_with(const_expr, re)? @@ -1220,7 +1220,9 @@ impl<'a> Parser<'a> { .then_some(self.prev_token.span); let bound = if self.check_inline_const(0) { - self.parse_const_block(self.token.span, true) + let _eaten = self.eat_keyword(kw::Const); + debug_assert!(_eaten); + self.parse_const_block(self.prev_token.span, true) } else if self.check_path() { let lo = self.token.span; let (qself, path) = if self.eat_lt() { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index b7cdae3e3e123..241dd7031b8d5 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -495,15 +495,21 @@ impl<'a> Parser<'a> { // // the place-inside-a-block suggestion would be more likely wrong than right. // + // But we don't want to trigger this if we just parsed a pattern, + // so this only triggers if the current token is neither `=>` nor `=`. + // // FIXME(compiler-errors): this should probably parse an arbitrary expr and not // just lookahead one token, so we can see if there's a brace after _that_, // since we want to protect against: // `if 1 1 + 1 {` being suggested as `if { 1 } 1 + 1 {` // + + Ok(Some(_)) - if (!self.token.is_keyword(kw::Else) - && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))) - || do_not_suggest_help => {} + if do_not_suggest_help + || (self.token != token::FatArrow + && self.token != token::Eq + && self.look_ahead(1, |t| { + t == &token::OpenDelim(token::Delimiter::Brace) + })) => {} // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836). Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {} Ok(Some(stmt)) => { @@ -520,7 +526,7 @@ impl<'a> Parser<'a> { (stmt_span.shrink_to_lo(), "{ ".to_string()), (stmt_span.shrink_to_hi(), " }".to_string()), ], - // Speculative; has been misleading in the past (#46836). + // Speculative; has been misleading in the past (see #46836). Applicability::MaybeIncorrect, ); } diff --git a/tests/ui/parser/bad-if-statements.stderr b/tests/ui/parser/bad-if-statements.stderr index ee839db645509..961666891794d 100644 --- a/tests/ui/parser/bad-if-statements.stderr +++ b/tests/ui/parser/bad-if-statements.stderr @@ -65,10 +65,6 @@ note: the `if` expression is missing a block after this condition | LL | if true x else {} | ^^^^ -help: try placing this code inside a block - | -LL | if true { x } else {} - | + + error: this `if` expression is missing a block after the condition --> $DIR/bad-if-statements.rs:34:5 diff --git a/tests/ui/parser/inline-const-pat-let.rs b/tests/ui/parser/inline-const-pat-let.rs new file mode 100644 index 0000000000000..a813f9646b5ef --- /dev/null +++ b/tests/ui/parser/inline-const-pat-let.rs @@ -0,0 +1,29 @@ +//@ run-pass + +#![feature(inline_const_pat)] + +fn if_let_1() -> i32 { + let x = 2; + const Y: i32 = 3; + + if let const { (Y + 1) / 2 } = x { + x + } else { + 0 + } +} + +fn if_let_2() -> i32 { + let x = 2; + + if let const { 1 + 2 } = x { + const { 1 + 2 } + } else { + 0 + } +} + +fn main() { + assert_eq!(if_let_1(), 2); + assert_eq!(if_let_2(), 0); +} diff --git a/tests/ui/parser/inline-const-without-block.fixed b/tests/ui/parser/inline-const-without-block.fixed new file mode 100644 index 0000000000000..9137edc35354e --- /dev/null +++ b/tests/ui/parser/inline-const-without-block.fixed @@ -0,0 +1,60 @@ +//@ run-rustfix + +// See issue #78168. + +#![feature(inline_const_pat)] + +// FIXME(#78171): the lint has to be allowed because of a bug +#[allow(dead_code)] +const fn one() -> i32 { + 1 +} + +fn foo() -> i32 { + let x = 2; + + match x { + const { 2 } => {} + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const { 1 + 2 * 3 / 4 } => {} + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const { one() } => {} + //~^ ERROR expected `{`, found `one` + //~| HELP try placing this code inside a block + _ => {} + } + + x +} + +fn bar() -> i32 { + let x = const { 2 }; + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + + x +} + +fn baz() -> i32 { + let y = const { 1 + 2 * 3 / 4 }; + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + + y +} + +fn main() { + foo(); + bar(); + baz(); +} diff --git a/tests/ui/parser/inline-const-without-block.rs b/tests/ui/parser/inline-const-without-block.rs new file mode 100644 index 0000000000000..048605c10b286 --- /dev/null +++ b/tests/ui/parser/inline-const-without-block.rs @@ -0,0 +1,60 @@ +//@ run-rustfix + +// See issue #78168. + +#![feature(inline_const_pat)] + +// FIXME(#78171): the lint has to be allowed because of a bug +#[allow(dead_code)] +const fn one() -> i32 { + 1 +} + +fn foo() -> i32 { + let x = 2; + + match x { + const 2 => {} + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const 1 + 2 * 3 / 4 => {} + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const one() => {} + //~^ ERROR expected `{`, found `one` + //~| HELP try placing this code inside a block + _ => {} + } + + x +} + +fn bar() -> i32 { + let x = const 2; + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + + x +} + +fn baz() -> i32 { + let y = const 1 + 2 * 3 / 4; + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + + y +} + +fn main() { + foo(); + bar(); + baz(); +} diff --git a/tests/ui/parser/inline-const-without-block.stderr b/tests/ui/parser/inline-const-without-block.stderr new file mode 100644 index 0000000000000..860afe72266cc --- /dev/null +++ b/tests/ui/parser/inline-const-without-block.stderr @@ -0,0 +1,57 @@ +error: expected `{`, found `2` + --> $DIR/inline-const-without-block.rs:17:15 + | +LL | const 2 => {} + | ^ expected `{` + | +help: try placing this code inside a block + | +LL | const { 2 } => {} + | + + + +error: expected `{`, found `1` + --> $DIR/inline-const-without-block.rs:24:15 + | +LL | const 1 + 2 * 3 / 4 => {} + | ^ expected `{` + | +help: try placing this code inside a block + | +LL | const { 1 + 2 * 3 / 4 } => {} + | + + + +error: expected `{`, found `one` + --> $DIR/inline-const-without-block.rs:31:15 + | +LL | const one() => {} + | ^^^ expected `{` + | +help: try placing this code inside a block + | +LL | const { one() } => {} + | + + + +error: expected `{`, found `2` + --> $DIR/inline-const-without-block.rs:41:19 + | +LL | let x = const 2; + | ^ expected `{` + | +help: try placing this code inside a block + | +LL | let x = const { 2 }; + | + + + +error: expected `{`, found `1` + --> $DIR/inline-const-without-block.rs:49:19 + | +LL | let y = const 1 + 2 * 3 / 4; + | ^ expected `{` + | +help: try placing this code inside a block + | +LL | let y = const { 1 + 2 * 3 / 4 }; + | + + + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/keyword-const-as-identifier.rs b/tests/ui/parser/keyword-const-as-identifier.rs index 6a2d926bf5796..52f878f36e465 100644 --- a/tests/ui/parser/keyword-const-as-identifier.rs +++ b/tests/ui/parser/keyword-const-as-identifier.rs @@ -1,5 +1,5 @@ -// This file was auto-generated using 'src/etc/generate-keyword-tests.py const' - fn main() { - let const = "foo"; //~ error: expected identifier, found keyword `const` + let const = "foo"; + //~^ ERROR expected `{`, found `=` + //~| ERROR inline-const in pattern position is experimental [E0658] } diff --git a/tests/ui/parser/keyword-const-as-identifier.stderr b/tests/ui/parser/keyword-const-as-identifier.stderr index 61e454174dd78..0d3661f8c7f83 100644 --- a/tests/ui/parser/keyword-const-as-identifier.stderr +++ b/tests/ui/parser/keyword-const-as-identifier.stderr @@ -1,13 +1,19 @@ -error: expected identifier, found keyword `const` - --> $DIR/keyword-const-as-identifier.rs:4:9 +error: expected `{`, found `=` + --> $DIR/keyword-const-as-identifier.rs:2:15 | LL | let const = "foo"; - | ^^^^^ expected identifier, found keyword + | ^ expected `{` + +error[E0658]: inline-const in pattern position is experimental + --> $DIR/keyword-const-as-identifier.rs:2:9 | -help: escape `const` to use it as an identifier +LL | let const = "foo"; + | ^^^^^ | -LL | let r#const = "foo"; - | ++ + = note: see issue #76001 for more information + = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0658`.