Change:
, we should provide a structured suggestion as we already do when . <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
seems easy enough, claim

Discussion:
match snapshot.parse_array_or_repeat_expr(attrs, token::Brace) { Ok(arr) => { let hi = snapshot.prev_token.span; <del> 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(); </del> <ins> self.struct_span_err(arr.span, "this is a block expression, not an array") .multipart_suggestion( "to make an array, use square brackets instead of curly braces", vec![(lo, "[".to_owned()), (hi, "]".to_owned())], Applicability::MaybeIncorrect, ) .emit(); </ins> self.restore_snapshot(snapshot); Some(self.mk_expr_err(arr.span))

self.suggest_no_capture_closure(err, expected, expr_ty); self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty); self.suggest_missing_parentheses(err, expr); <ins> self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected); </ins> self.note_need_for_fn_pointer(err, expected, expr_ty); self.note_internal_mutation_in_method(err, expr, expected, expr_ty); self.report_closure_inferred_return_type(err, expected);

let prev_diverges = self.diverges.get(); let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; <del> let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { for (pos, s) in blk.stmts.iter().enumerate() { self.check_stmt(s, blk.stmts.len() - 1 == pos); } </del> <ins> let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { for (pos, s) in blk.stmts.iter().enumerate() { self.check_stmt(s, blk.stmts.len() - 1 == pos); } </ins> <del> // check the tail expression **without** holding the // `enclosing_breakables` lock below. let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); let ctxt = enclosing_breakables.find_breakable(blk.hir_id); let coerce = ctxt.coerce.as_mut().unwrap(); if let Some(tail_expr_ty) = tail_expr_ty { let tail_expr = tail_expr.unwrap(); let span = self.get_expr_coercion_span(tail_expr); let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); coerce.coerce(self, &cause, tail_expr, tail_expr_ty); } else { // Subtle: if there is no explicit tail expression, // that is typically equivalent to a tail expression // of `()` -- except if the block diverges. In that // case, there is no value supplied from the tail // expression (assuming there are no other breaks, // this implies that the type of the block will be // `!`). // // #41425 -- label the implicit `()` as being the // "found type" here, rather than the "expected type". if !self.diverges.get().is_always() { // #50009 -- Do not point at the entire fn block span, point at the return type // span, as it is the cause of the requirement, and // `consider_hint_about_removing_semicolon` will point at the last expression // if it were a relevant part of the error. This improves usability in editors // that highlight errors inline. let mut sp = blk.span; let mut fn_span = None; if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { let ret_sp = decl.output.span(); if let Some(block_sp) = self.parent_item_span(blk.hir_id) { // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the // output would otherwise be incorrect and even misleading. Make sure // the span we're aiming at correspond to a `fn` body. if block_sp == blk.span { sp = ret_sp; fn_span = Some(ident.span); } </del> <ins> // check the tail expression **without** holding the // `enclosing_breakables` lock below. let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); let ctxt = enclosing_breakables.find_breakable(blk.hir_id); let coerce = ctxt.coerce.as_mut().unwrap(); if let Some(tail_expr_ty) = tail_expr_ty { let tail_expr = tail_expr.unwrap(); let span = self.get_expr_coercion_span(tail_expr); let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); let ty_for_diagnostic = coerce.merged_ty(); // We use coerce_inner here because we want to augment the error // suggesting to wrap the block in square brackets if it might've // been mistaken array syntax coerce.coerce_inner( self, &cause, Some(tail_expr), tail_expr_ty, Some(&mut |diag: &mut Diagnostic| { self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic); }), false, ); } else { // Subtle: if there is no explicit tail expression, // that is typically equivalent to a tail expression // of `()` -- except if the block diverges. In that // case, there is no value supplied from the tail // expression (assuming there are no other breaks, // this implies that the type of the block will be // `!`). // // #41425 -- label the implicit `()` as being the // "found type" here, rather than the "expected type". if !self.diverges.get().is_always() { // #50009 -- Do not point at the entire fn block span, point at the return type // span, as it is the cause of the requirement, and // `consider_hint_about_removing_semicolon` will point at the last expression // if it were a relevant part of the error. This improves usability in editors // that highlight errors inline. let mut sp = blk.span; let mut fn_span = None; if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { let ret_sp = decl.output.span(); if let Some(block_sp) = self.parent_item_span(blk.hir_id) { // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the // output would otherwise be incorrect and even misleading. Make sure // the span we're aiming at correspond to a `fn` body. if block_sp == blk.span { sp = ret_sp; fn_span = Some(ident.span); </ins> } } <del> coerce.coerce_forced_unit( </del> <ins> } coerce.coerce_forced_unit( </ins> self, &self.misc(sp), &mut |err| {

// Our block must be a `assign desugar local; assignment` if let Some(hir::Node::Block(hir::Block { stmts: <del> [hir::Stmt { kind: hir::StmtKind::Local(hir::Local { source: hir::LocalSource::AssignDesugar(_), .. }), .. }, hir::Stmt { kind: hir::StmtKind::Expr(hir::Expr { kind: hir::ExprKind::Assign(..), .. }), .. }], </del> <ins> [ hir::Stmt { kind: hir::StmtKind::Local(hir::Local { source: hir::LocalSource::AssignDesugar(_), .. }), .. }, hir::Stmt { kind: hir::StmtKind::Expr(hir::Expr { kind: hir::ExprKind::Assign(..), .. }), .. }, ], </ins> .. })) = self.tcx.hir().find(blk.hir_id) {

}, false, ); <del> } </del> } <del> }); </del> <ins> } }); </ins> if ctxt.may_break { // If we can break from the block, then the block's exit is always reachable

} } <ins> /// Given an expression type mismatch, peel any `&` expressions until we get to /// a block expression, and then suggest replacing the braces with square braces /// if it was possibly mistaken array syntax. pub(crate) fn suggest_block_to_brackets_peeling_refs( &self, diag: &mut Diagnostic, mut expr: &hir::Expr<'_>, mut expr_ty: Ty<'tcx>, mut expected_ty: Ty<'tcx>, ) { loop { match (&expr.kind, expr_ty.kind(), expected_ty.kind()) { ( hir::ExprKind::AddrOf(_, _, inner_expr), ty::Ref(_, inner_expr_ty, _), ty::Ref(_, inner_expected_ty, _), ) => { expr = *inner_expr; expr_ty = *inner_expr_ty; expected_ty = *inner_expected_ty; } (hir::ExprKind::Block(blk, _), _, _) => { self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty); break; } _ => break, } } } /// Suggest wrapping the block in square brackets instead of curly braces /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. pub(crate) fn suggest_block_to_brackets( &self, diag: &mut Diagnostic, blk: &hir::Block<'_>, blk_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, ) { if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() { if self.can_coerce(blk_ty, *elem_ty) && blk.stmts.is_empty() && blk.rules == hir::BlockCheckMode::DefaultBlock { let source_map = self.tcx.sess.source_map(); if let Ok(snippet) = source_map.span_to_snippet(blk.span) { if snippet.starts_with('{') && snippet.ends_with('}') { diag.multipart_suggestion_verbose( "to create an array, use square brackets instead of curly braces", vec![ ( blk.span .shrink_to_lo() .with_hi(rustc_span::BytePos(blk.span.lo().0 + 1)), "[".to_string(), ), ( blk.span .shrink_to_hi() .with_lo(rustc_span::BytePos(blk.span.hi().0 - 1)), "]".to_string(), ), ], Applicability::MachineApplicable, ); } } } } } </ins> fn is_loop(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. }))

<ins> const A: [&str; 1] = { "hello" }; //~^ ERROR mismatched types const B: &[u32] = &{ 1 }; //~^ ERROR mismatched types const C: &&[u32; 1] = &&{ 1 }; //~^ ERROR mismatched types fn main() {} </ins>

<ins> error[E0308]: mismatched types --> $DIR/brackets-to-braces-single-element.rs:1:24 | LL | const A: [&str; 1] = { "hello" }; |                        ^^^^^^^ expected array `[&'static str; 1]`, found `&str` | help: to create an array, use square brackets instead of curly braces | LL | const A: [&str; 1] = [ "hello" ]; |                      ~         ~ error[E0308]: mismatched types --> $DIR/brackets-to-braces-single-element.rs:4:19 | LL | const B: &[u32] = &{ 1 }; |                   ^^^^^^ expected slice `[u32]`, found integer | = note: expected reference `&'static [u32]` found reference `&{integer}` help: to create an array, use square brackets instead of curly braces | LL | const B: &[u32] = &[ 1 ]; |                    ~   ~ error[E0308]: mismatched types --> $DIR/brackets-to-braces-single-element.rs:7:27 | LL | const C: &&[u32; 1] = &&{ 1 }; |                           ^ expected array `[u32; 1]`, found integer | help: to create an array, use square brackets instead of curly braces | LL | const C: &&[u32; 1] = &&[ 1 ]; |                         ~   ~ error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. </ins>

fn main() {} <del> const FOO: [u8; 3] = { //~ ERROR this code is interpreted as a block expression </del> <ins> const FOO: [u8; 3] = { //~^ ERROR this is a block expression, not an array </ins> 1, 2, 3 }; const BAR: [&str; 3] = {"one", "two", "three"}; <del> //~^ ERROR this code is interpreted as a block expression </del> <ins> //~^ ERROR this is a block expression, not an array </ins> fn foo() { {1, 2, 3}; <del> //~^ ERROR this code is interpreted as a block expression </del> <ins> //~^ ERROR this is a block expression, not an array </ins> } fn bar() {

<del> error: this code is interpreted as a block expression, not an array </del> <ins> error: this is a block expression, not an array </ins> --> $DIR/issue-87830-try-brackets-for-arrays.rs:3:22 | LL |   const FOO: [u8; 3] = { |  ______________________^ <ins> LL | | </ins> LL | |     1, 2, 3 LL | | }; | |_^ | <del> = note: to define an array, one would use square brackets instead of curly braces help: try using [] instead of {} </del> <ins> help: to make an array, use square brackets instead of curly braces </ins> | LL ~ const FOO: [u8; 3] = [ <ins> LL | </ins> LL |     1, 2, 3 LL ~ ]; | <del> error: this code is interpreted as a block expression, not an array --> $DIR/issue-87830-try-brackets-for-arrays.rs:7:24 </del> <ins> error: this is a block expression, not an array --> $DIR/issue-87830-try-brackets-for-arrays.rs:8:24 </ins> | LL | const BAR: [&str; 3] = {"one", "two", "three"}; |                        ^^^^^^^^^^^^^^^^^^^^^^^ | <del> = note: to define an array, one would use square brackets instead of curly braces help: try using [] instead of {} </del> <ins> help: to make an array, use square brackets instead of curly braces </ins> | LL | const BAR: [&str; 3] = ["one", "two", "three"]; |                        ~                     ~ <del> error: this code is interpreted as a block expression, not an array --> $DIR/issue-87830-try-brackets-for-arrays.rs:11:5 </del> <ins> error: this is a block expression, not an array --> $DIR/issue-87830-try-brackets-for-arrays.rs:12:5 </ins> | LL |     {1, 2, 3}; |     ^^^^^^^^^ | <del> = note: to define an array, one would use square brackets instead of curly braces help: try using [] instead of {} </del> <ins> help: to make an array, use square brackets instead of curly braces </ins> | LL |     [1, 2, 3]; |     ~       ~ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` <del> --> $DIR/issue-87830-try-brackets-for-arrays.rs:16:6 </del> <ins> --> $DIR/issue-87830-try-brackets-for-arrays.rs:17:6 </ins> | LL |     1, 2, 3 |      ^ expected one of `.`, `;`, `?`, `}`, or an operator