Skip to content

Commit e4a9b8b

Browse files
camelidGrigorenkoPV
authored andcommitted
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
1 parent 7042c26 commit e4a9b8b

13 files changed

+259
-41
lines changed

compiler/rustc_parse/src/parser/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1472,8 +1472,8 @@ impl<'a> Parser<'a> {
14721472
err
14731473
},
14741474
)
1475-
} else if this.check_inline_const(0) {
1476-
this.parse_const_block(lo.to(this.token.span), false)
1475+
} else if this.eat_keyword(kw::Const) {
1476+
this.parse_const_block(lo.to(this.prev_token.span), false)
14771477
} else if this.may_recover() && this.is_do_catch_block() {
14781478
this.recover_do_catch()
14791479
} else if this.is_try_block() {

compiler/rustc_parse/src/parser/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1302,12 +1302,11 @@ impl<'a> Parser<'a> {
13021302
}
13031303
}
13041304

1305-
/// Parses inline const expressions.
1305+
/// Parses inline const expressions. The `const` keyword was already eaten.
13061306
fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, P<Expr>> {
13071307
if pat {
13081308
self.psess.gated_spans.gate(sym::inline_const_pat, span);
13091309
}
1310-
self.expect_keyword(kw::Const)?;
13111310
let (attrs, blk) = self.parse_inner_attrs_and_block()?;
13121311
let anon_const = AnonConst {
13131312
id: DUMMY_NODE_ID,

compiler/rustc_parse/src/parser/pat.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -730,9 +730,9 @@ impl<'a> Parser<'a> {
730730
self.parse_pat_ident(BindingMode(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)?
731731
} else if self.eat_keyword(kw::Box) {
732732
self.parse_pat_box()?
733-
} else if self.check_inline_const(0) {
734-
// Parse `const pat`
735-
let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
733+
} else if self.eat_keyword(kw::Const) {
734+
// Parse `const { pat }`
735+
let const_expr = self.parse_const_block(lo.to(self.prev_token.span), true)?;
736736

737737
if let Some(re) = self.parse_range_end() {
738738
self.parse_pat_range_begin_with(const_expr, re)?
@@ -1220,7 +1220,9 @@ impl<'a> Parser<'a> {
12201220
.then_some(self.prev_token.span);
12211221

12221222
let bound = if self.check_inline_const(0) {
1223-
self.parse_const_block(self.token.span, true)
1223+
let _eaten = self.eat_keyword(kw::Const);
1224+
debug_assert!(_eaten);
1225+
self.parse_const_block(self.prev_token.span, true)
12241226
} else if self.check_path() {
12251227
let lo = self.token.span;
12261228
let (qself, path) = if self.eat_lt() {

compiler/rustc_parse/src/parser/stmt.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -495,15 +495,21 @@ impl<'a> Parser<'a> {
495495
//
496496
// the place-inside-a-block suggestion would be more likely wrong than right.
497497
//
498+
// But we don't want to trigger this if we just parsed a pattern,
499+
// so this only triggers if the current token is neither `=>` nor `=`.
500+
//
498501
// FIXME(compiler-errors): this should probably parse an arbitrary expr and not
499502
// just lookahead one token, so we can see if there's a brace after _that_,
500503
// since we want to protect against:
501504
// `if 1 1 + 1 {` being suggested as `if { 1 } 1 + 1 {`
502505
// + +
503506
Ok(Some(_))
504-
if (!self.token.is_keyword(kw::Else)
505-
&& self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)))
506-
|| do_not_suggest_help => {}
507+
if do_not_suggest_help
508+
|| (self.token != token::FatArrow
509+
&& self.token != token::Eq
510+
&& self.look_ahead(1, |t| {
511+
t == &token::OpenDelim(token::Delimiter::Brace)
512+
})) => {}
507513
// Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836).
508514
Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
509515
Ok(Some(stmt)) => {
@@ -520,7 +526,7 @@ impl<'a> Parser<'a> {
520526
(stmt_span.shrink_to_lo(), "{ ".to_string()),
521527
(stmt_span.shrink_to_hi(), " }".to_string()),
522528
],
523-
// Speculative; has been misleading in the past (#46836).
529+
// Speculative; has been misleading in the past (see #46836).
524530
Applicability::MaybeIncorrect,
525531
);
526532
}

tests/ui/parser/bad-if-statements.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,6 @@ note: the `if` expression is missing a block after this condition
6565
|
6666
LL | if true x else {}
6767
| ^^^^
68-
help: try placing this code inside a block
69-
|
70-
LL | if true { x } else {}
71-
| + +
7268

7369
error: this `if` expression is missing a block after the condition
7470
--> $DIR/bad-if-statements.rs:34:5

tests/ui/parser/block-no-opening-brace.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ edition:2018
22

3-
#![feature(try_blocks)]
3+
#![feature(try_blocks, inline_const_pat)]
44

55
fn main() {}
66

@@ -35,15 +35,14 @@ fn in_async() {
3535

3636
// FIXME(#78168)
3737
fn in_const() {
38-
let x = const 2; //~ ERROR expected expression, found keyword `const`
38+
let x = const 2; //~ ERROR expected `{`, found `2`
3939
}
4040

4141
// FIXME(#78168)
4242
fn in_const_in_match() {
4343
let x = 2;
4444
match x {
4545
const 2 => {}
46-
//~^ ERROR expected identifier, found keyword `const`
47-
//~| ERROR expected one of `=>`, `if`, or `|`, found `2`
46+
//~^ ERROR expected `{`, found `2`
4847
}
4948
}

tests/ui/parser/block-no-opening-brace.stderr

+15-11
Original file line numberDiff line numberDiff line change
@@ -51,23 +51,27 @@ LL | async
5151
LL | let x = 0;
5252
| ^^^ unexpected token
5353

54-
error: expected expression, found keyword `const`
55-
--> $DIR/block-no-opening-brace.rs:38:13
54+
error: expected `{`, found `2`
55+
--> $DIR/block-no-opening-brace.rs:38:19
5656
|
5757
LL | let x = const 2;
58-
| ^^^^^ expected expression
59-
60-
error: expected identifier, found keyword `const`
61-
--> $DIR/block-no-opening-brace.rs:45:9
58+
| ^ expected `{`
6259
|
63-
LL | const 2 => {}
64-
| ^^^^^ expected identifier, found keyword
60+
help: try placing this code inside a block
61+
|
62+
LL | let x = const { 2 };
63+
| + +
6564

66-
error: expected one of `=>`, `if`, or `|`, found `2`
65+
error: expected `{`, found `2`
6766
--> $DIR/block-no-opening-brace.rs:45:15
6867
|
6968
LL | const 2 => {}
70-
| ^ expected one of `=>`, `if`, or `|`
69+
| ^ expected `{`
70+
|
71+
help: try placing this code inside a block
72+
|
73+
LL | const { 2 } => {}
74+
| + +
7175

72-
error: aborting due to 8 previous errors
76+
error: aborting due to 7 previous errors
7377

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ run-pass
2+
3+
#![feature(inline_const_pat)]
4+
5+
fn if_let_1() -> i32 {
6+
let x = 2;
7+
const Y: i32 = 3;
8+
9+
if let const { (Y + 1) / 2 } = x {
10+
x
11+
} else {
12+
0
13+
}
14+
}
15+
16+
fn if_let_2() -> i32 {
17+
let x = 2;
18+
19+
if let const { 1 + 2 } = x {
20+
const { 1 + 2 }
21+
} else {
22+
0
23+
}
24+
}
25+
26+
fn main() {
27+
assert_eq!(if_let_1(), 2);
28+
assert_eq!(if_let_2(), 0);
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//@ run-rustfix
2+
3+
// See issue #78168.
4+
5+
#![feature(inline_const_pat)]
6+
7+
// FIXME(#78171): the lint has to be allowed because of a bug
8+
#[allow(dead_code)]
9+
const fn one() -> i32 {
10+
1
11+
}
12+
13+
fn foo() -> i32 {
14+
let x = 2;
15+
16+
match x {
17+
const { 2 } => {}
18+
//~^ ERROR expected `{`, found `2`
19+
//~| HELP try placing this code inside a block
20+
_ => {}
21+
}
22+
23+
match x {
24+
const { 1 + 2 * 3 / 4 } => {}
25+
//~^ ERROR expected `{`, found `1`
26+
//~| HELP try placing this code inside a block
27+
_ => {}
28+
}
29+
30+
match x {
31+
const { one() } => {}
32+
//~^ ERROR expected `{`, found `one`
33+
//~| HELP try placing this code inside a block
34+
_ => {}
35+
}
36+
37+
x
38+
}
39+
40+
fn bar() -> i32 {
41+
let x = const { 2 };
42+
//~^ ERROR expected `{`, found `2`
43+
//~| HELP try placing this code inside a block
44+
45+
x
46+
}
47+
48+
fn baz() -> i32 {
49+
let y = const { 1 + 2 * 3 / 4 };
50+
//~^ ERROR expected `{`, found `1`
51+
//~| HELP try placing this code inside a block
52+
53+
y
54+
}
55+
56+
fn main() {
57+
foo();
58+
bar();
59+
baz();
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//@ run-rustfix
2+
3+
// See issue #78168.
4+
5+
#![feature(inline_const_pat)]
6+
7+
// FIXME(#78171): the lint has to be allowed because of a bug
8+
#[allow(dead_code)]
9+
const fn one() -> i32 {
10+
1
11+
}
12+
13+
fn foo() -> i32 {
14+
let x = 2;
15+
16+
match x {
17+
const 2 => {}
18+
//~^ ERROR expected `{`, found `2`
19+
//~| HELP try placing this code inside a block
20+
_ => {}
21+
}
22+
23+
match x {
24+
const 1 + 2 * 3 / 4 => {}
25+
//~^ ERROR expected `{`, found `1`
26+
//~| HELP try placing this code inside a block
27+
_ => {}
28+
}
29+
30+
match x {
31+
const one() => {}
32+
//~^ ERROR expected `{`, found `one`
33+
//~| HELP try placing this code inside a block
34+
_ => {}
35+
}
36+
37+
x
38+
}
39+
40+
fn bar() -> i32 {
41+
let x = const 2;
42+
//~^ ERROR expected `{`, found `2`
43+
//~| HELP try placing this code inside a block
44+
45+
x
46+
}
47+
48+
fn baz() -> i32 {
49+
let y = const 1 + 2 * 3 / 4;
50+
//~^ ERROR expected `{`, found `1`
51+
//~| HELP try placing this code inside a block
52+
53+
y
54+
}
55+
56+
fn main() {
57+
foo();
58+
bar();
59+
baz();
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
error: expected `{`, found `2`
2+
--> $DIR/inline-const-without-block.rs:17:15
3+
|
4+
LL | const 2 => {}
5+
| ^ expected `{`
6+
|
7+
help: try placing this code inside a block
8+
|
9+
LL | const { 2 } => {}
10+
| + +
11+
12+
error: expected `{`, found `1`
13+
--> $DIR/inline-const-without-block.rs:24:15
14+
|
15+
LL | const 1 + 2 * 3 / 4 => {}
16+
| ^ expected `{`
17+
|
18+
help: try placing this code inside a block
19+
|
20+
LL | const { 1 + 2 * 3 / 4 } => {}
21+
| + +
22+
23+
error: expected `{`, found `one`
24+
--> $DIR/inline-const-without-block.rs:31:15
25+
|
26+
LL | const one() => {}
27+
| ^^^ expected `{`
28+
|
29+
help: try placing this code inside a block
30+
|
31+
LL | const { one() } => {}
32+
| + +
33+
34+
error: expected `{`, found `2`
35+
--> $DIR/inline-const-without-block.rs:41:19
36+
|
37+
LL | let x = const 2;
38+
| ^ expected `{`
39+
|
40+
help: try placing this code inside a block
41+
|
42+
LL | let x = const { 2 };
43+
| + +
44+
45+
error: expected `{`, found `1`
46+
--> $DIR/inline-const-without-block.rs:49:19
47+
|
48+
LL | let y = const 1 + 2 * 3 / 4;
49+
| ^ expected `{`
50+
|
51+
help: try placing this code inside a block
52+
|
53+
LL | let y = const { 1 + 2 * 3 / 4 };
54+
| + +
55+
56+
error: aborting due to 5 previous errors
57+
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// This file was auto-generated using 'src/etc/generate-keyword-tests.py const'
2-
31
fn main() {
4-
let const = "foo"; //~ error: expected identifier, found keyword `const`
2+
let const = "foo";
3+
//~^ ERROR expected `{`, found `=`
4+
//~| ERROR inline-const in pattern position is experimental [E0658]
55
}

0 commit comments

Comments
 (0)