Skip to content

Commit

Permalink
Suggest adding missing braces in const block pattern
Browse files Browse the repository at this point in the history
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 rust-lang#78173
  • Loading branch information
camelid authored and GrigorenkoPV committed Sep 23, 2024
1 parent a772336 commit 4980b77
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 26 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Expr>> {
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,
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?
Expand Down Expand Up @@ -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() {
Expand Down
14 changes: 10 additions & 4 deletions compiler/rustc_parse/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) => {
Expand All @@ -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,
);
}
Expand Down
4 changes: 0 additions & 4 deletions tests/ui/parser/bad-if-statements.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions tests/ui/parser/inline-const-pat-let.rs
Original file line number Diff line number Diff line change
@@ -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);
}
60 changes: 60 additions & 0 deletions tests/ui/parser/inline-const-without-block.fixed
Original file line number Diff line number Diff line change
@@ -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();
}
60 changes: 60 additions & 0 deletions tests/ui/parser/inline-const-without-block.rs
Original file line number Diff line number Diff line change
@@ -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();
}
57 changes: 57 additions & 0 deletions tests/ui/parser/inline-const-without-block.stderr
Original file line number Diff line number Diff line change
@@ -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

6 changes: 3 additions & 3 deletions tests/ui/parser/keyword-const-as-identifier.rs
Original file line number Diff line number Diff line change
@@ -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]
}
20 changes: 13 additions & 7 deletions tests/ui/parser/keyword-const-as-identifier.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/rust-lang/rust/issues/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`.

0 comments on commit 4980b77

Please sign in to comment.