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
This commit is contained in:
commit
e7958d35ca
@ -1204,7 +1204,7 @@ impl<'a> Parser<'a> {
|
|||||||
} else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
|
} else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
|
||||||
self.parse_closure_expr(attrs)
|
self.parse_closure_expr(attrs)
|
||||||
} else if self.check(&token::OpenDelim(token::Bracket)) {
|
} else if self.check(&token::OpenDelim(token::Bracket)) {
|
||||||
self.parse_array_or_repeat_expr(attrs)
|
self.parse_array_or_repeat_expr(attrs, token::Bracket)
|
||||||
} else if self.check_path() {
|
} else if self.check_path() {
|
||||||
self.parse_path_start_expr(attrs)
|
self.parse_path_start_expr(attrs)
|
||||||
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
|
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
|
||||||
@ -1322,11 +1322,15 @@ impl<'a> Parser<'a> {
|
|||||||
self.maybe_recover_from_bad_qpath(expr, true)
|
self.maybe_recover_from_bad_qpath(expr, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
fn parse_array_or_repeat_expr(
|
||||||
|
&mut self,
|
||||||
|
attrs: AttrVec,
|
||||||
|
close_delim: token::DelimToken,
|
||||||
|
) -> PResult<'a, P<Expr>> {
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
self.bump(); // `[`
|
self.bump(); // `[` or other open delim
|
||||||
|
|
||||||
let close = &token::CloseDelim(token::Bracket);
|
let close = &token::CloseDelim(close_delim);
|
||||||
let kind = if self.eat(close) {
|
let kind = if self.eat(close) {
|
||||||
// Empty vector
|
// Empty vector
|
||||||
ExprKind::Array(Vec::new())
|
ExprKind::Array(Vec::new())
|
||||||
@ -1752,6 +1756,46 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_array_like_block(&mut self) -> bool {
|
||||||
|
self.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
|
||||||
|
&& self.look_ahead(2, |t| t == &token::Comma)
|
||||||
|
&& self.look_ahead(3, |t| t.can_begin_expr())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits a suggestion if it looks like the user meant an array but
|
||||||
|
/// accidentally used braces, causing the code to be interpreted as a block
|
||||||
|
/// expression.
|
||||||
|
fn maybe_suggest_brackets_instead_of_braces(
|
||||||
|
&mut self,
|
||||||
|
lo: Span,
|
||||||
|
attrs: AttrVec,
|
||||||
|
) -> Option<P<Expr>> {
|
||||||
|
let mut snapshot = self.clone();
|
||||||
|
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) {
|
||||||
|
Ok(arr) => {
|
||||||
|
let hi = snapshot.prev_token.span;
|
||||||
|
self.struct_span_err(
|
||||||
|
arr.span,
|
||||||
|
"this code is interpreted as a block expression, not an array",
|
||||||
|
)
|
||||||
|
.multipart_suggestion(
|
||||||
|
"try using [] instead of {}",
|
||||||
|
vec![(lo, "[".to_owned()), (hi, "]".to_owned())],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
)
|
||||||
|
.note("to define an array, one would use square brackets instead of curly braces")
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
*self = snapshot;
|
||||||
|
Some(self.mk_expr_err(arr.span))
|
||||||
|
}
|
||||||
|
Err(mut e) => {
|
||||||
|
e.cancel();
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses a block or unsafe block.
|
/// Parses a block or unsafe block.
|
||||||
pub(super) fn parse_block_expr(
|
pub(super) fn parse_block_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -1760,6 +1804,12 @@ impl<'a> Parser<'a> {
|
|||||||
blk_mode: BlockCheckMode,
|
blk_mode: BlockCheckMode,
|
||||||
mut attrs: AttrVec,
|
mut attrs: AttrVec,
|
||||||
) -> PResult<'a, P<Expr>> {
|
) -> PResult<'a, P<Expr>> {
|
||||||
|
if self.is_array_like_block() {
|
||||||
|
if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo, attrs.clone()) {
|
||||||
|
return Ok(arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(label) = opt_label {
|
if let Some(label) = opt_label {
|
||||||
self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
|
self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
fn main() {}
|
||||||
|
|
||||||
|
const FOO: [u8; 3] = { //~ ERROR this code is interpreted as a block expression
|
||||||
|
1, 2, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const BAR: [&str; 3] = {"one", "two", "three"};
|
||||||
|
//~^ ERROR this code is interpreted as a block expression
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
{1, 2, 3};
|
||||||
|
//~^ ERROR this code is interpreted as a block expression
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
1, 2, 3 //~ ERROR expected one of
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
error: this code is interpreted as a block expression, not an array
|
||||||
|
--> $DIR/issue-87830-try-brackets-for-arrays.rs:3:22
|
||||||
|
|
|
||||||
|
LL | const FOO: [u8; 3] = {
|
||||||
|
| ______________________^
|
||||||
|
LL | | 1, 2, 3
|
||||||
|
LL | | };
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
= note: to define an array, one would use square brackets instead of curly braces
|
||||||
|
help: try using [] instead of {}
|
||||||
|
|
|
||||||
|
LL ~ const FOO: [u8; 3] = [
|
||||||
|
LL | 1, 2, 3
|
||||||
|
LL ~ ];
|
||||||
|
|
|
||||||
|
|
||||||
|
error: this code is interpreted as a block expression, not an array
|
||||||
|
--> $DIR/issue-87830-try-brackets-for-arrays.rs:7:24
|
||||||
|
|
|
||||||
|
LL | const BAR: [&str; 3] = {"one", "two", "three"};
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: to define an array, one would use square brackets instead of curly braces
|
||||||
|
help: try using [] instead of {}
|
||||||
|
|
|
||||||
|
LL | const BAR: [&str; 3] = ["one", "two", "three"];
|
||||||
|
| ~ ~
|
||||||
|
|
||||||
|
error: this code is interpreted as a block expression, not an array
|
||||||
|
--> $DIR/issue-87830-try-brackets-for-arrays.rs:11:5
|
||||||
|
|
|
||||||
|
LL | {1, 2, 3};
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: to define an array, one would use square brackets instead of curly braces
|
||||||
|
help: try using [] instead of {}
|
||||||
|
|
|
||||||
|
LL | [1, 2, 3];
|
||||||
|
| ~ ~
|
||||||
|
|
||||||
|
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
|
||||||
|
--> $DIR/issue-87830-try-brackets-for-arrays.rs:16:6
|
||||||
|
|
|
||||||
|
LL | 1, 2, 3
|
||||||
|
| ^ expected one of `.`, `;`, `?`, `}`, or an operator
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user