Skip to content

Commit e7958d3

Browse files
committed
Auto merge of #87830 - hkmatsumoto:suggest-brackets-for-array-esque-block-expr, r=estebank
Suggest replacing braces for brackets on array-esque invalid block expr Newcomers may write `{1, 2, 3}` for making arrays, and the current error message is not informative enough to quickly convince them what is needed to fix the error. This PR implements a diagnostic for this case, and its output looks like this: ```text error: this code is interpreted as a block expression, not an array --> src/lib.rs:1:22 | 1 | const FOO: [u8; 3] = { | ______________________^ 2 | | 1, 2, 3 3 | | }; | |_^ | = note: to define an array, one would use square brackets instead of curly braces help: try using [] instead of {} | 1 | const FOO: [u8; 3] = [ 2 | 1, 2, 3 3 | ]; | ``` Fix #87672
2 parents 60e70cc + 21eff8f commit e7958d3

File tree

3 files changed

+120
-4
lines changed

3 files changed

+120
-4
lines changed

Diff for: compiler/rustc_parse/src/parser/expr.rs

+54-4
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,7 @@ impl<'a> Parser<'a> {
12041204
} else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
12051205
self.parse_closure_expr(attrs)
12061206
} else if self.check(&token::OpenDelim(token::Bracket)) {
1207-
self.parse_array_or_repeat_expr(attrs)
1207+
self.parse_array_or_repeat_expr(attrs, token::Bracket)
12081208
} else if self.check_path() {
12091209
self.parse_path_start_expr(attrs)
12101210
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
@@ -1322,11 +1322,15 @@ impl<'a> Parser<'a> {
13221322
self.maybe_recover_from_bad_qpath(expr, true)
13231323
}
13241324

1325-
fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
1325+
fn parse_array_or_repeat_expr(
1326+
&mut self,
1327+
attrs: AttrVec,
1328+
close_delim: token::DelimToken,
1329+
) -> PResult<'a, P<Expr>> {
13261330
let lo = self.token.span;
1327-
self.bump(); // `[`
1331+
self.bump(); // `[` or other open delim
13281332

1329-
let close = &token::CloseDelim(token::Bracket);
1333+
let close = &token::CloseDelim(close_delim);
13301334
let kind = if self.eat(close) {
13311335
// Empty vector
13321336
ExprKind::Array(Vec::new())
@@ -1752,6 +1756,46 @@ impl<'a> Parser<'a> {
17521756
}
17531757
}
17541758

1759+
fn is_array_like_block(&mut self) -> bool {
1760+
self.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
1761+
&& self.look_ahead(2, |t| t == &token::Comma)
1762+
&& self.look_ahead(3, |t| t.can_begin_expr())
1763+
}
1764+
1765+
/// Emits a suggestion if it looks like the user meant an array but
1766+
/// accidentally used braces, causing the code to be interpreted as a block
1767+
/// expression.
1768+
fn maybe_suggest_brackets_instead_of_braces(
1769+
&mut self,
1770+
lo: Span,
1771+
attrs: AttrVec,
1772+
) -> Option<P<Expr>> {
1773+
let mut snapshot = self.clone();
1774+
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
1775+
Ok(arr) => {
1776+
let hi = snapshot.prev_token.span;
1777+
self.struct_span_err(
1778+
arr.span,
1779+
"this code is interpreted as a block expression, not an array",
1780+
)
1781+
.multipart_suggestion(
1782+
"try using [] instead of {}",
1783+
vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
1784+
Applicability::MaybeIncorrect,
1785+
)
1786+
.note("to define an array, one would use square brackets instead of curly braces")
1787+
.emit();
1788+
1789+
*self = snapshot;
1790+
Some(self.mk_expr_err(arr.span))
1791+
}
1792+
Err(mut e) => {
1793+
e.cancel();
1794+
None
1795+
}
1796+
}
1797+
}
1798+
17551799
/// Parses a block or unsafe block.
17561800
pub(super) fn parse_block_expr(
17571801
&mut self,
@@ -1760,6 +1804,12 @@ impl<'a> Parser<'a> {
17601804
blk_mode: BlockCheckMode,
17611805
mut attrs: AttrVec,
17621806
) -> PResult<'a, P<Expr>> {
1807+
if self.is_array_like_block() {
1808+
if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo, attrs.clone()) {
1809+
return Ok(arr);
1810+
}
1811+
}
1812+
17631813
if let Some(label) = opt_label {
17641814
self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
17651815
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fn main() {}
2+
3+
const FOO: [u8; 3] = { //~ ERROR this code is interpreted as a block expression
4+
1, 2, 3
5+
};
6+
7+
const BAR: [&str; 3] = {"one", "two", "three"};
8+
//~^ ERROR this code is interpreted as a block expression
9+
10+
fn foo() {
11+
{1, 2, 3};
12+
//~^ ERROR this code is interpreted as a block expression
13+
}
14+
15+
fn bar() {
16+
1, 2, 3 //~ ERROR expected one of
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
error: this code is interpreted as a block expression, not an array
2+
--> $DIR/issue-87830-try-brackets-for-arrays.rs:3:22
3+
|
4+
LL | const FOO: [u8; 3] = {
5+
| ______________________^
6+
LL | | 1, 2, 3
7+
LL | | };
8+
| |_^
9+
|
10+
= note: to define an array, one would use square brackets instead of curly braces
11+
help: try using [] instead of {}
12+
|
13+
LL ~ const FOO: [u8; 3] = [
14+
LL | 1, 2, 3
15+
LL ~ ];
16+
|
17+
18+
error: this code is interpreted as a block expression, not an array
19+
--> $DIR/issue-87830-try-brackets-for-arrays.rs:7:24
20+
|
21+
LL | const BAR: [&str; 3] = {"one", "two", "three"};
22+
| ^^^^^^^^^^^^^^^^^^^^^^^
23+
|
24+
= note: to define an array, one would use square brackets instead of curly braces
25+
help: try using [] instead of {}
26+
|
27+
LL | const BAR: [&str; 3] = ["one", "two", "three"];
28+
| ~ ~
29+
30+
error: this code is interpreted as a block expression, not an array
31+
--> $DIR/issue-87830-try-brackets-for-arrays.rs:11:5
32+
|
33+
LL | {1, 2, 3};
34+
| ^^^^^^^^^
35+
|
36+
= note: to define an array, one would use square brackets instead of curly braces
37+
help: try using [] instead of {}
38+
|
39+
LL | [1, 2, 3];
40+
| ~ ~
41+
42+
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
43+
--> $DIR/issue-87830-try-brackets-for-arrays.rs:16:6
44+
|
45+
LL | 1, 2, 3
46+
| ^ expected one of `.`, `;`, `?`, `}`, or an operator
47+
48+
error: aborting due to 4 previous errors
49+

0 commit comments

Comments
 (0)