2 use crate::astconv
::AstConv
;
4 use rustc_ast
::util
::parser
::ExprPrecedence
;
5 use rustc_span
::{self, MultiSpan, Span}
;
7 use rustc_errors
::{Applicability, Diagnostic}
;
9 use rustc_hir
::def
::{CtorOf, DefKind}
;
10 use rustc_hir
::lang_items
::LangItem
;
12 Expr
, ExprKind
, GenericBound
, ItemKind
, Node
, Path
, QPath
, Stmt
, StmtKind
, TyKind
,
15 use rustc_infer
::infer
::{self, TyCtxtInferExt}
;
17 use rustc_middle
::lint
::in_external_macro
;
18 use rustc_middle
::ty
::{self, Binder, Ty}
;
19 use rustc_span
::symbol
::{kw, sym}
;
21 use rustc_middle
::ty
::subst
::GenericArgKind
;
24 impl<'a
, 'tcx
> FnCtxt
<'a
, 'tcx
> {
25 pub(in super::super) fn suggest_semicolon_at_end(&self, span
: Span
, err
: &mut Diagnostic
) {
26 err
.span_suggestion_short(
28 "consider using a semicolon here",
30 Applicability
::MachineApplicable
,
34 /// On implicit return expressions with mismatched types, provides the following suggestions:
36 /// - Points out the method's return type as the reason for the expected type.
37 /// - Possible missing semicolon.
38 /// - Possible missing return type if the return type is the default, and not `fn main()`.
39 pub fn suggest_mismatched_types_on_tail(
42 expr
: &'tcx hir
::Expr
<'tcx
>,
47 let expr
= expr
.peel_drop_temps();
48 // If the expression is from an external macro, then do not suggest
49 // adding a semicolon, because there's nowhere to put it.
51 if expr
.can_have_side_effects() && !in_external_macro(self.tcx
.sess
, expr
.span
) {
52 self.suggest_missing_semicolon(err
, expr
, expected
);
54 let mut pointing_at_return_type
= false;
55 if let Some((fn_decl
, can_suggest
)) = self.get_fn_decl(blk_id
) {
56 let fn_id
= self.tcx
.hir().get_return_block(blk_id
).unwrap();
57 pointing_at_return_type
= self.suggest_missing_return_type(
65 self.suggest_missing_break_or_return_expr(
66 err
, expr
, &fn_decl
, expected
, found
, blk_id
, fn_id
,
69 pointing_at_return_type
72 /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
73 /// the ctor would successfully solve the type mismatch and if so, suggest it:
75 /// fn foo(x: usize) -> usize { x }
76 /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)`
85 let hir
= self.tcx
.hir();
86 let (def_id
, sig
) = match *found
.kind() {
87 ty
::FnDef(def_id
, _
) => (def_id
, found
.fn_sig(self.tcx
)),
88 ty
::Closure(def_id
, substs
) => (def_id
, substs
.as_closure().sig()),
92 let sig
= self.replace_bound_vars_with_fresh_vars(expr
.span
, infer
::FnCall
, sig
).0;
93 let sig
= self.normalize_associated_types_in(expr
.span
, sig
);
94 if self.can_coerce(sig
.output(), expected
) {
95 let (mut sugg_call
, applicability
) = if sig
.inputs().is_empty() {
96 (String
::new(), Applicability
::MachineApplicable
)
98 ("...".to_string(), Applicability
::HasPlaceholders
)
100 let mut msg
= "call this function";
101 match hir
.get_if_local(def_id
) {
103 Node
::Item(hir
::Item { kind: ItemKind::Fn(.., body_id), .. }
)
104 | Node
::ImplItem(hir
::ImplItem
{
105 kind
: hir
::ImplItemKind
::Fn(_
, body_id
), ..
107 | Node
::TraitItem(hir
::TraitItem
{
108 kind
: hir
::TraitItemKind
::Fn(.., hir
::TraitFn
::Provided(body_id
)),
112 let body
= hir
.body(*body_id
);
116 .map(|param
| match ¶m
.pat
.kind
{
117 hir
::PatKind
::Binding(_
, _
, ident
, None
)
118 if ident
.name
!= kw
::SelfLower
=>
122 _
=> "_".to_string(),
127 Some(Node
::Expr(hir
::Expr
{
128 kind
: ExprKind
::Closure(_
, _
, body_id
, _
, _
),
129 span
: full_closure_span
,
132 if *full_closure_span
== expr
.span
{
135 msg
= "call this closure";
136 let body
= hir
.body(*body_id
);
140 .map(|param
| match ¶m
.pat
.kind
{
141 hir
::PatKind
::Binding(_
, _
, ident
, None
)
142 if ident
.name
!= kw
::SelfLower
=>
146 _
=> "_".to_string(),
151 Some(Node
::Ctor(hir
::VariantData
::Tuple(fields
, _
))) => {
152 sugg_call
= fields
.iter().map(|_
| "_").collect
::<Vec
<_
>>().join(", ");
153 match def_id
.as_local().map(|def_id
| hir
.def_kind(def_id
)) {
154 Some(DefKind
::Ctor(hir
::def
::CtorOf
::Variant
, _
)) => {
155 msg
= "instantiate this tuple variant";
157 Some(DefKind
::Ctor(CtorOf
::Struct
, _
)) => {
158 msg
= "instantiate this tuple struct";
163 Some(Node
::ForeignItem(hir
::ForeignItem
{
164 kind
: hir
::ForeignItemKind
::Fn(_
, idents
, _
),
170 if ident
.name
!= kw
::SelfLower
{
179 Some(Node
::TraitItem(hir
::TraitItem
{
180 kind
: hir
::TraitItemKind
::Fn(.., hir
::TraitFn
::Required(idents
)),
186 if ident
.name
!= kw
::SelfLower
{
197 err
.span_suggestion_verbose(
198 expr
.span
.shrink_to_hi(),
199 &format
!("use parentheses to {}", msg
),
200 format
!("({})", sugg_call
),
208 pub fn suggest_deref_ref_or_into(
210 err
: &mut Diagnostic
,
211 expr
: &hir
::Expr
<'tcx
>,
214 expected_ty_expr
: Option
<&'tcx hir
::Expr
<'tcx
>>,
216 let expr
= expr
.peel_blocks();
217 if let Some((sp
, msg
, suggestion
, applicability
, verbose
)) =
218 self.check_ref(expr
, found
, expected
)
221 err
.span_suggestion_verbose(sp
, &msg
, suggestion
, applicability
);
223 err
.span_suggestion(sp
, &msg
, suggestion
, applicability
);
225 } else if let (ty
::FnDef(def_id
, ..), true) =
226 (&found
.kind(), self.suggest_fn_call(err
, expr
, expected
, found
))
228 if let Some(sp
) = self.tcx
.hir().span_if_local(*def_id
) {
229 let sp
= self.sess().source_map().guess_head_span(sp
);
230 err
.span_label(sp
, &format
!("{} defined here", found
));
232 } else if !self.check_for_cast(err
, expr
, found
, expected
, expected_ty_expr
) {
233 let is_struct_pat_shorthand_field
=
234 self.maybe_get_struct_pattern_shorthand_field(expr
).is_some();
235 let methods
= self.get_conversion_methods(expr
.span
, expected
, found
, expr
.hir_id
);
236 if !methods
.is_empty() {
237 if let Ok(expr_text
) = self.sess().source_map().span_to_snippet(expr
.span
) {
238 let mut suggestions
= iter
::zip(iter
::repeat(&expr_text
), &methods
)
239 .filter_map(|(receiver
, method
)| {
240 let method_call
= format
!(".{}()", method
.name
);
241 if receiver
.ends_with(&method_call
) {
242 None
// do not suggest code that is already there (#53348)
244 let method_call_list
= [".to_vec()", ".to_string()"];
245 let mut sugg
= if receiver
.ends_with(".clone()")
246 && method_call_list
.contains(&method_call
.as_str())
248 let max_len
= receiver
.rfind('
.'
).unwrap();
251 format
!("{}{}", &receiver
[..max_len
], method_call
),
254 if expr
.precedence().order()
255 < ExprPrecedence
::MethodCall
.order()
258 (expr
.span
.shrink_to_lo(), "(".to_string()),
259 (expr
.span
.shrink_to_hi(), format
!("){}", method_call
)),
262 vec
![(expr
.span
.shrink_to_hi(), method_call
)]
265 if is_struct_pat_shorthand_field
{
268 (expr
.span
.shrink_to_lo(), format
!("{}: ", receiver
)),
275 if suggestions
.peek().is_some() {
276 err
.multipart_suggestions(
277 "try using a conversion method",
279 Applicability
::MaybeIncorrect
,
283 } else if found
.to_string().starts_with("Option<")
284 && expected
.to_string() == "Option<&str>"
286 if let ty
::Adt(_def
, subst
) = found
.kind() {
287 if subst
.len() != 0 {
288 if let GenericArgKind
::Type(ty
) = subst
[0].unpack() {
289 let peeled
= ty
.peel_refs().to_string();
290 if peeled
== "String" {
291 let ref_cnt
= ty
.to_string().len() - peeled
.len();
292 let result
= format
!(".map(|x| &*{}x)", "*".repeat(ref_cnt
));
293 err
.span_suggestion_verbose(
294 expr
.span
.shrink_to_hi(),
295 "try converting the passed type into a `&str`",
297 Applicability
::MaybeIncorrect
,
307 /// When encountering the expected boxed value allocated in the stack, suggest allocating it
308 /// in the heap by calling `Box::new()`.
309 pub(in super::super) fn suggest_boxing_when_appropriate(
311 err
: &mut Diagnostic
,
312 expr
: &hir
::Expr
<'_
>,
316 if self.tcx
.hir().is_inside_const_context(expr
.hir_id
) {
317 // Do not suggest `Box::new` in const context.
320 if !expected
.is_box() || found
.is_box() {
323 let boxed_found
= self.tcx
.mk_box(found
);
324 if self.can_coerce(boxed_found
, expected
) {
325 err
.multipart_suggestion(
326 "store this in the heap by calling `Box::new`",
328 (expr
.span
.shrink_to_lo(), "Box::new(".to_string()),
329 (expr
.span
.shrink_to_hi(), ")".to_string()),
331 Applicability
::MachineApplicable
,
334 "for more on the distinction between the stack and the heap, read \
335 https://doc.rust-lang.org/book/ch15-01-box.html, \
336 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
337 https://doc.rust-lang.org/std/boxed/index.html",
342 /// When encountering a closure that captures variables, where a FnPtr is expected,
343 /// suggest a non-capturing closure
344 pub(in super::super) fn suggest_no_capture_closure(
346 err
: &mut Diagnostic
,
350 if let (ty
::FnPtr(_
), ty
::Closure(def_id
, _
)) = (expected
.kind(), found
.kind()) {
351 if let Some(upvars
) = self.tcx
.upvars_mentioned(*def_id
) {
352 // Report upto four upvars being captured to reduce the amount error messages
353 // reported back to the user.
354 let spans_and_labels
= upvars
357 .map(|(var_hir_id
, upvar
)| {
358 let var_name
= self.tcx
.hir().name(*var_hir_id
).to_string();
359 let msg
= format
!("`{}` captured here", var_name
);
362 .collect
::<Vec
<_
>>();
364 let mut multi_span
: MultiSpan
=
365 spans_and_labels
.iter().map(|(sp
, _
)| *sp
).collect
::<Vec
<_
>>().into();
366 for (sp
, label
) in spans_and_labels
{
367 multi_span
.push_span_label(sp
, label
);
371 "closures can only be coerced to `fn` types if they do not capture any variables"
377 /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
378 #[instrument(skip(self, err))]
379 pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
381 err
: &mut Diagnostic
,
382 expr
: &hir
::Expr
<'_
>,
388 if self.tcx
.hir().is_inside_const_context(expr
.hir_id
) {
389 // Do not suggest `Box::new` in const context.
392 let pin_did
= self.tcx
.lang_items().pin_type();
393 // This guards the `unwrap` and `mk_box` below.
394 if pin_did
.is_none() || self.tcx
.lang_items().owned_box().is_none() {
397 let box_found
= self.tcx
.mk_box(found
);
398 let pin_box_found
= self.tcx
.mk_lang_item(box_found
, LangItem
::Pin
).unwrap();
399 let pin_found
= self.tcx
.mk_lang_item(found
, LangItem
::Pin
).unwrap();
400 match expected
.kind() {
401 ty
::Adt(def
, _
) if Some(def
.did()) == pin_did
=> {
402 if self.can_coerce(pin_box_found
, expected
) {
403 debug
!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found
, expected
);
405 ty
::Adt(def
, _
) if def
.is_box() => {
406 err
.help("use `Box::pin`");
409 err
.multipart_suggestion(
410 "you need to pin and box this expression",
412 (expr
.span
.shrink_to_lo(), "Box::pin(".to_string()),
413 (expr
.span
.shrink_to_hi(), ")".to_string()),
415 Applicability
::MaybeIncorrect
,
420 } else if self.can_coerce(pin_found
, expected
) {
422 ty
::Adt(def
, _
) if def
.is_box() => {
423 err
.help("use `Box::pin`");
432 ty
::Adt(def
, _
) if def
.is_box() && self.can_coerce(box_found
, expected
) => {
433 // Check if the parent expression is a call to Pin::new. If it
434 // is and we were expecting a Box, ergo Pin<Box<expected>>, we
435 // can suggest Box::pin.
436 let parent
= self.tcx
.hir().get_parent_node(expr
.hir_id
);
437 let Some(Node
::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }
)) = self.tcx
.hir().find(parent
) else {
441 ExprKind
::Path(QPath
::TypeRelative(
443 kind
: TyKind
::Path(QPath
::Resolved(_
, Path { res: recv_ty, .. }
)),
447 )) if recv_ty
.opt_def_id() == pin_did
&& method
.ident
.name
== sym
::new
=> {
450 "use `Box::pin` to pin and box this expression",
451 "Box::pin".to_string(),
452 Applicability
::MachineApplicable
,
463 /// A common error is to forget to add a semicolon at the end of a block, e.g.,
467 /// bar_that_returns_u32()
471 /// This routine checks if the return expression in a block would make sense on its own as a
472 /// statement and the return type has been left as default or has been specified as `()`. If so,
473 /// it suggests adding a semicolon.
474 fn suggest_missing_semicolon(
476 err
: &mut Diagnostic
,
477 expression
: &'tcx hir
::Expr
<'tcx
>,
480 if expected
.is_unit() {
481 // `BlockTailExpression` only relevant if the tail expr would be
482 // useful on its own.
483 match expression
.kind
{
485 | ExprKind
::MethodCall(..)
488 | ExprKind
::Match(..)
489 | ExprKind
::Block(..)
490 if expression
.can_have_side_effects() =>
493 expression
.span
.shrink_to_hi(),
494 "consider using a semicolon here",
496 Applicability
::MachineApplicable
,
504 /// A possible error is to forget to add a return type that is needed:
508 /// bar_that_returns_u32()
512 /// This routine checks if the return type is left as default, the method is not part of an
513 /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
515 pub(in super::super) fn suggest_missing_return_type(
517 err
: &mut Diagnostic
,
518 fn_decl
: &hir
::FnDecl
<'_
>,
525 self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found
));
526 // Only suggest changing the return type for methods that
527 // haven't set a return type at all (and aren't `fn main()` or an impl).
528 match (&fn_decl
.output
, found
.is_suggestable(), can_suggest
, expected
.is_unit()) {
529 (&hir
::FnRetTy
::DefaultReturn(span
), true, true, true) => {
532 "try adding a return type",
533 format
!("-> {} ", found
),
534 Applicability
::MachineApplicable
,
538 (&hir
::FnRetTy
::DefaultReturn(span
), false, true, true) => {
539 // FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest
543 "a return type might be missing here",
545 Applicability
::HasPlaceholders
,
549 (&hir
::FnRetTy
::DefaultReturn(span
), _
, false, true) => {
550 // `fn main()` must return `()`, do not suggest changing return type
551 err
.span_label(span
, "expected `()` because of default return type");
554 // expectation was caused by something else, not the default return
555 (&hir
::FnRetTy
::DefaultReturn(_
), _
, _
, false) => false,
556 (&hir
::FnRetTy
::Return(ref ty
), _
, _
, _
) => {
557 // Only point to return type if the expected type is the return type, as if they
558 // are not, the expectation must have been caused by something else.
559 debug
!("suggest_missing_return_type: return type {:?} node {:?}", ty
, ty
.kind
);
561 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, ty
);
562 debug
!("suggest_missing_return_type: return type {:?}", ty
);
563 debug
!("suggest_missing_return_type: expected type {:?}", ty
);
564 let bound_vars
= self.tcx
.late_bound_vars(fn_id
);
565 let ty
= Binder
::bind_with_vars(ty
, bound_vars
);
566 let ty
= self.normalize_associated_types_in(sp
, ty
);
567 let ty
= self.tcx
.erase_late_bound_regions(ty
);
568 if self.can_coerce(expected
, ty
) {
569 err
.span_label(sp
, format
!("expected `{}` because of return type", expected
));
570 self.try_suggest_return_impl_trait(err
, expected
, ty
, fn_id
);
578 /// check whether the return type is a generic type with a trait bound
579 /// only suggest this if the generic param is not present in the arguments
580 /// if this is true, hint them towards changing the return type to `impl Trait`
582 /// fn cant_name_it<T: Fn() -> u32>() -> T {
586 fn try_suggest_return_impl_trait(
588 err
: &mut Diagnostic
,
593 // Only apply the suggestion if:
594 // - the return type is a generic parameter
595 // - the generic param is not used as a fn param
596 // - the generic param has at least one bound
597 // - the generic param doesn't appear in any other bounds where it's not the Self type
599 // - Changing the return type to be `impl <all bounds>`
601 debug
!("try_suggest_return_impl_trait, expected = {:?}, found = {:?}", expected
, found
);
603 let ty
::Param(expected_ty_as_param
) = expected
.kind() else { return }
;
605 let fn_node
= self.tcx
.hir().find(fn_id
);
607 let Some(hir
::Node
::Item(hir
::Item
{
610 hir
::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }
, .. },
611 hir
::Generics { params, where_clause, .. }
,
615 })) = fn_node
else { return }
;
617 let Some(expected_generic_param
) = params
.get(expected_ty_as_param
.index
as usize) else { return }
;
619 // get all where BoundPredicates here, because they are used in to cases below
620 let where_predicates
= where_clause
623 .filter_map(|p
| match p
{
624 WherePredicate
::BoundPredicate(hir
::WhereBoundPredicate
{
629 // FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below)
630 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, bounded_ty
);
635 .map(|(ty
, bounds
)| match ty
.kind() {
636 ty
::Param(param_ty
) if param_ty
== expected_ty_as_param
=> Ok(Some(bounds
)),
637 // check whether there is any predicate that contains our `T`, like `Option<T>: Send`
638 _
=> match ty
.contains(expected
) {
643 .collect
::<Result
<Vec
<_
>, _
>>();
645 let Ok(where_predicates
) = where_predicates
else { return }
;
647 // now get all predicates in the same types as the where bounds, so we can chain them
648 let predicates_from_where
=
649 where_predicates
.iter().flatten().map(|bounds
| bounds
.iter()).flatten();
651 // extract all bounds from the source code using their spans
652 let all_matching_bounds_strs
= expected_generic_param
655 .chain(predicates_from_where
)
656 .filter_map(|bound
| match bound
{
657 GenericBound
::Trait(_
, _
) => {
658 self.tcx
.sess
.source_map().span_to_snippet(bound
.span()).ok()
662 .collect
::<Vec
<String
>>();
664 if all_matching_bounds_strs
.len() == 0 {
668 let all_bounds_str
= all_matching_bounds_strs
.join(" + ");
670 let ty_param_used_in_fn_params
= fn_parameters
.iter().any(|param
| {
671 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, param
);
672 matches
!(ty
.kind(), ty
::Param(fn_param_ty_param
) if expected_ty_as_param
== fn_param_ty_param
)
675 if ty_param_used_in_fn_params
{
681 "consider using an impl return type",
682 format
!("impl {}", all_bounds_str
),
683 Applicability
::MaybeIncorrect
,
687 pub(in super::super) fn suggest_missing_break_or_return_expr(
689 err
: &mut Diagnostic
,
690 expr
: &'tcx hir
::Expr
<'tcx
>,
691 fn_decl
: &hir
::FnDecl
<'_
>,
697 if !expected
.is_unit() {
700 let found
= self.resolve_vars_with_obligations(found
);
702 let in_loop
= self.is_loop(id
)
703 || self.tcx
.hir().parent_iter(id
).any(|(parent_id
, _
)| self.is_loop(parent_id
));
705 let in_local_statement
= self.is_local_statement(id
)
710 .any(|(parent_id
, _
)| self.is_local_statement(parent_id
));
712 if in_loop
&& in_local_statement
{
713 err
.multipart_suggestion(
714 "you might have meant to break the loop with this value",
716 (expr
.span
.shrink_to_lo(), "break ".to_string()),
717 (expr
.span
.shrink_to_hi(), ";".to_string()),
719 Applicability
::MaybeIncorrect
,
724 if let hir
::FnRetTy
::Return(ty
) = fn_decl
.output
{
725 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, ty
);
726 let bound_vars
= self.tcx
.late_bound_vars(fn_id
);
727 let ty
= self.tcx
.erase_late_bound_regions(Binder
::bind_with_vars(ty
, bound_vars
));
728 let ty
= self.normalize_associated_types_in(expr
.span
, ty
);
729 let ty
= match self.tcx
.asyncness(fn_id
.owner
) {
730 hir
::IsAsync
::Async
=> self
734 infcx
.get_impl_future_output_ty(ty
).unwrap_or_else(|| {
736 fn_decl
.output
.span(),
737 "failed to get output type of async function"
742 hir
::IsAsync
::NotAsync
=> ty
,
744 if self.can_coerce(found
, ty
) {
745 err
.multipart_suggestion(
746 "you might have meant to return this value",
748 (expr
.span
.shrink_to_lo(), "return ".to_string()),
749 (expr
.span
.shrink_to_hi(), ";".to_string()),
751 Applicability
::MaybeIncorrect
,
757 pub(in super::super) fn suggest_missing_parentheses(
759 err
: &mut Diagnostic
,
760 expr
: &hir
::Expr
<'_
>,
762 let sp
= self.tcx
.sess
.source_map().start_point(expr
.span
);
763 if let Some(sp
) = self.tcx
.sess
.parse_sess
.ambiguous_block_expr_parse
.borrow().get(&sp
) {
764 // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
765 self.tcx
.sess
.parse_sess
.expr_parentheses_needed(err
, *sp
);
769 /// Given an expression type mismatch, peel any `&` expressions until we get to
770 /// a block expression, and then suggest replacing the braces with square braces
771 /// if it was possibly mistaken array syntax.
772 pub(crate) fn suggest_block_to_brackets_peeling_refs(
774 diag
: &mut Diagnostic
,
775 mut expr
: &hir
::Expr
<'_
>,
776 mut expr_ty
: Ty
<'tcx
>,
777 mut expected_ty
: Ty
<'tcx
>,
780 match (&expr
.kind
, expr_ty
.kind(), expected_ty
.kind()) {
782 hir
::ExprKind
::AddrOf(_
, _
, inner_expr
),
783 ty
::Ref(_
, inner_expr_ty
, _
),
784 ty
::Ref(_
, inner_expected_ty
, _
),
787 expr_ty
= *inner_expr_ty
;
788 expected_ty
= *inner_expected_ty
;
790 (hir
::ExprKind
::Block(blk
, _
), _
, _
) => {
791 self.suggest_block_to_brackets(diag
, *blk
, expr_ty
, expected_ty
);
799 /// Suggest wrapping the block in square brackets instead of curly braces
800 /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
801 pub(crate) fn suggest_block_to_brackets(
803 diag
: &mut Diagnostic
,
804 blk
: &hir
::Block
<'_
>,
806 expected_ty
: Ty
<'tcx
>,
808 if let ty
::Slice(elem_ty
) | ty
::Array(elem_ty
, _
) = expected_ty
.kind() {
809 if self.can_coerce(blk_ty
, *elem_ty
)
810 && blk
.stmts
.is_empty()
811 && blk
.rules
== hir
::BlockCheckMode
::DefaultBlock
813 let source_map
= self.tcx
.sess
.source_map();
814 if let Ok(snippet
) = source_map
.span_to_snippet(blk
.span
) {
815 if snippet
.starts_with('{') && snippet.ends_with('}'
) {
816 diag
.multipart_suggestion_verbose(
817 "to create an array, use square brackets instead of curly braces",
822 .with_hi(rustc_span
::BytePos(blk
.span
.lo().0 + 1)),
828 .with_lo(rustc_span
::BytePos(blk
.span
.hi().0 - 1)),
832 Applicability
::MachineApplicable
,
840 fn is_loop(&self, id
: hir
::HirId
) -> bool
{
841 let node
= self.tcx
.hir().get(id
);
842 matches
!(node
, Node
::Expr(Expr { kind: ExprKind::Loop(..), .. }
))
845 fn is_local_statement(&self, id
: hir
::HirId
) -> bool
{
846 let node
= self.tcx
.hir().get(id
);
847 matches
!(node
, Node
::Stmt(Stmt { kind: StmtKind::Local(..), .. }
))