2 use crate::astconv
::AstConv
;
3 use crate::errors
::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}
;
5 use rustc_ast
::util
::parser
::ExprPrecedence
;
6 use rustc_errors
::{Applicability, Diagnostic, MultiSpan}
;
8 use rustc_hir
::def
::{CtorOf, DefKind}
;
9 use rustc_hir
::lang_items
::LangItem
;
11 Expr
, ExprKind
, GenericBound
, Node
, Path
, QPath
, Stmt
, StmtKind
, TyKind
, WherePredicate
,
13 use rustc_infer
::infer
::{self, TyCtxtInferExt}
;
14 use rustc_infer
::traits
;
15 use rustc_middle
::lint
::in_external_macro
;
16 use rustc_middle
::ty
::subst
::GenericArgKind
;
17 use rustc_middle
::ty
::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}
;
18 use rustc_span
::symbol
::sym
;
20 use rustc_trait_selection
::traits
::query
::evaluate_obligation
::InferCtxtExt
;
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 self.suggest_missing_semicolon(err
, expr
, expected
, false);
49 let mut pointing_at_return_type
= false;
50 if let Some((fn_decl
, can_suggest
)) = self.get_fn_decl(blk_id
) {
51 let fn_id
= self.tcx
.hir().get_return_block(blk_id
).unwrap();
52 pointing_at_return_type
= self.suggest_missing_return_type(
60 self.suggest_missing_break_or_return_expr(
61 err
, expr
, &fn_decl
, expected
, found
, blk_id
, fn_id
,
64 pointing_at_return_type
67 /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
68 /// the ctor would successfully solve the type mismatch and if so, suggest it:
69 /// ```compile_fail,E0308
70 /// fn foo(x: usize) -> usize { x }
71 /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)`
80 let (def_id
, output
, inputs
) = match *found
.kind() {
81 ty
::FnDef(def_id
, _
) => {
82 let fn_sig
= found
.fn_sig(self.tcx
);
83 (def_id
, fn_sig
.output(), fn_sig
.inputs().skip_binder().len())
85 ty
::Closure(def_id
, substs
) => {
86 let fn_sig
= substs
.as_closure().sig();
87 (def_id
, fn_sig
.output(), fn_sig
.inputs().skip_binder().len() - 1)
89 ty
::Opaque(def_id
, substs
) => {
90 let sig
= self.tcx
.bound_item_bounds(def_id
).subst(self.tcx
, substs
).iter().find_map(|pred
| {
91 if let ty
::PredicateKind
::Projection(proj
) = pred
.kind().skip_binder()
92 && Some(proj
.projection_ty
.item_def_id
) == self.tcx
.lang_items().fn_once_output()
93 // args tuple will always be substs[1]
94 && let ty
::Tuple(args
) = proj
.projection_ty
.substs
.type_at(1).kind()
97 pred
.kind().rebind(proj
.term
.ty().unwrap()),
104 if let Some((output
, inputs
)) = sig
{
105 (def_id
, output
, inputs
)
113 let output
= self.replace_bound_vars_with_fresh_vars(expr
.span
, infer
::FnCall
, output
);
114 let output
= self.normalize_associated_types_in(expr
.span
, output
);
115 if !output
.is_ty_var() && self.can_coerce(output
, expected
) {
116 let (sugg_call
, mut applicability
) = match inputs
{
117 0 => ("".to_string(), Applicability
::MachineApplicable
),
119 (0..inputs
).map(|_
| "_").collect
::<Vec
<_
>>().join(", "),
120 Applicability
::MachineApplicable
,
122 _
=> ("...".to_string(), Applicability
::HasPlaceholders
),
125 let msg
= match self.tcx
.def_kind(def_id
) {
126 DefKind
::Fn
=> "call this function",
127 DefKind
::Closure
| DefKind
::OpaqueTy
=> "call this closure",
128 DefKind
::Ctor(CtorOf
::Struct
, _
) => "instantiate this tuple struct",
129 DefKind
::Ctor(CtorOf
::Variant
, _
) => "instantiate this tuple variant",
130 _
=> "call this function",
133 let sugg
= match expr
.kind
{
134 hir
::ExprKind
::Call(..)
135 | hir
::ExprKind
::Path(..)
136 | hir
::ExprKind
::Index(..)
137 | hir
::ExprKind
::Lit(..) => {
138 vec
![(expr
.span
.shrink_to_hi(), format
!("({sugg_call})"))]
140 hir
::ExprKind
::Closure { .. }
=> {
141 // Might be `{ expr } || { bool }`
142 applicability
= Applicability
::MaybeIncorrect
;
144 (expr
.span
.shrink_to_lo(), "(".to_string()),
145 (expr
.span
.shrink_to_hi(), format
!(")({sugg_call})")),
150 (expr
.span
.shrink_to_lo(), "(".to_string()),
151 (expr
.span
.shrink_to_hi(), format
!(")({sugg_call})")),
156 err
.multipart_suggestion_verbose(
157 format
!("use parentheses to {msg}"),
167 pub fn suggest_deref_ref_or_into(
169 err
: &mut Diagnostic
,
170 expr
: &hir
::Expr
<'tcx
>,
173 expected_ty_expr
: Option
<&'tcx hir
::Expr
<'tcx
>>,
175 let expr
= expr
.peel_blocks();
176 if let Some((sp
, msg
, suggestion
, applicability
, verbose
)) =
177 self.check_ref(expr
, found
, expected
)
180 err
.span_suggestion_verbose(sp
, &msg
, suggestion
, applicability
);
182 err
.span_suggestion(sp
, &msg
, suggestion
, applicability
);
184 } else if let (ty
::FnDef(def_id
, ..), true) =
185 (&found
.kind(), self.suggest_fn_call(err
, expr
, expected
, found
))
187 if let Some(sp
) = self.tcx
.hir().span_if_local(*def_id
) {
188 let sp
= self.sess().source_map().guess_head_span(sp
);
189 err
.span_label(sp
, &format
!("{} defined here", found
));
191 } else if !self.check_for_cast(err
, expr
, found
, expected
, expected_ty_expr
) {
192 let is_struct_pat_shorthand_field
=
193 self.maybe_get_struct_pattern_shorthand_field(expr
).is_some();
194 let methods
= self.get_conversion_methods(expr
.span
, expected
, found
, expr
.hir_id
);
195 if !methods
.is_empty() {
196 if let Ok(expr_text
) = self.sess().source_map().span_to_snippet(expr
.span
) {
197 let mut suggestions
= iter
::zip(iter
::repeat(&expr_text
), &methods
)
198 .filter_map(|(receiver
, method
)| {
199 let method_call
= format
!(".{}()", method
.name
);
200 if receiver
.ends_with(&method_call
) {
201 None
// do not suggest code that is already there (#53348)
203 let method_call_list
= [".to_vec()", ".to_string()"];
204 let mut sugg
= if receiver
.ends_with(".clone()")
205 && method_call_list
.contains(&method_call
.as_str())
207 let max_len
= receiver
.rfind('
.'
).unwrap();
210 format
!("{}{}", &receiver
[..max_len
], method_call
),
213 if expr
.precedence().order()
214 < ExprPrecedence
::MethodCall
.order()
217 (expr
.span
.shrink_to_lo(), "(".to_string()),
218 (expr
.span
.shrink_to_hi(), format
!("){}", method_call
)),
221 vec
![(expr
.span
.shrink_to_hi(), method_call
)]
224 if is_struct_pat_shorthand_field
{
227 (expr
.span
.shrink_to_lo(), format
!("{}: ", receiver
)),
234 if suggestions
.peek().is_some() {
235 err
.multipart_suggestions(
236 "try using a conversion method",
238 Applicability
::MaybeIncorrect
,
242 } else if found
.to_string().starts_with("Option<")
243 && expected
.to_string() == "Option<&str>"
245 if let ty
::Adt(_def
, subst
) = found
.kind() {
246 if subst
.len() != 0 {
247 if let GenericArgKind
::Type(ty
) = subst
[0].unpack() {
248 let peeled
= ty
.peel_refs().to_string();
249 if peeled
== "String" {
250 let ref_cnt
= ty
.to_string().len() - peeled
.len();
251 let result
= format
!(".map(|x| &*{}x)", "*".repeat(ref_cnt
));
252 err
.span_suggestion_verbose(
253 expr
.span
.shrink_to_hi(),
254 "try converting the passed type into a `&str`",
256 Applicability
::MaybeIncorrect
,
266 /// When encountering the expected boxed value allocated in the stack, suggest allocating it
267 /// in the heap by calling `Box::new()`.
268 pub(in super::super) fn suggest_boxing_when_appropriate(
270 err
: &mut Diagnostic
,
271 expr
: &hir
::Expr
<'_
>,
275 if self.tcx
.hir().is_inside_const_context(expr
.hir_id
) {
276 // Do not suggest `Box::new` in const context.
279 if !expected
.is_box() || found
.is_box() {
282 let boxed_found
= self.tcx
.mk_box(found
);
283 if self.can_coerce(boxed_found
, expected
) {
284 err
.multipart_suggestion(
285 "store this in the heap by calling `Box::new`",
287 (expr
.span
.shrink_to_lo(), "Box::new(".to_string()),
288 (expr
.span
.shrink_to_hi(), ")".to_string()),
290 Applicability
::MachineApplicable
,
293 "for more on the distinction between the stack and the heap, read \
294 https://doc.rust-lang.org/book/ch15-01-box.html, \
295 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
296 https://doc.rust-lang.org/std/boxed/index.html",
301 /// When encountering a closure that captures variables, where a FnPtr is expected,
302 /// suggest a non-capturing closure
303 pub(in super::super) fn suggest_no_capture_closure(
305 err
: &mut Diagnostic
,
309 if let (ty
::FnPtr(_
), ty
::Closure(def_id
, _
)) = (expected
.kind(), found
.kind()) {
310 if let Some(upvars
) = self.tcx
.upvars_mentioned(*def_id
) {
311 // Report upto four upvars being captured to reduce the amount error messages
312 // reported back to the user.
313 let spans_and_labels
= upvars
316 .map(|(var_hir_id
, upvar
)| {
317 let var_name
= self.tcx
.hir().name(*var_hir_id
).to_string();
318 let msg
= format
!("`{}` captured here", var_name
);
321 .collect
::<Vec
<_
>>();
323 let mut multi_span
: MultiSpan
=
324 spans_and_labels
.iter().map(|(sp
, _
)| *sp
).collect
::<Vec
<_
>>().into();
325 for (sp
, label
) in spans_and_labels
{
326 multi_span
.push_span_label(sp
, label
);
330 "closures can only be coerced to `fn` types if they do not capture any variables"
336 /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
337 #[instrument(skip(self, err))]
338 pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
340 err
: &mut Diagnostic
,
341 expr
: &hir
::Expr
<'_
>,
347 if self.tcx
.hir().is_inside_const_context(expr
.hir_id
) {
348 // Do not suggest `Box::new` in const context.
351 let pin_did
= self.tcx
.lang_items().pin_type();
352 // This guards the `unwrap` and `mk_box` below.
353 if pin_did
.is_none() || self.tcx
.lang_items().owned_box().is_none() {
356 let box_found
= self.tcx
.mk_box(found
);
357 let pin_box_found
= self.tcx
.mk_lang_item(box_found
, LangItem
::Pin
).unwrap();
358 let pin_found
= self.tcx
.mk_lang_item(found
, LangItem
::Pin
).unwrap();
359 match expected
.kind() {
360 ty
::Adt(def
, _
) if Some(def
.did()) == pin_did
=> {
361 if self.can_coerce(pin_box_found
, expected
) {
362 debug
!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found
, expected
);
364 ty
::Adt(def
, _
) if def
.is_box() => {
365 err
.help("use `Box::pin`");
368 err
.multipart_suggestion(
369 "you need to pin and box this expression",
371 (expr
.span
.shrink_to_lo(), "Box::pin(".to_string()),
372 (expr
.span
.shrink_to_hi(), ")".to_string()),
374 Applicability
::MaybeIncorrect
,
379 } else if self.can_coerce(pin_found
, expected
) {
381 ty
::Adt(def
, _
) if def
.is_box() => {
382 err
.help("use `Box::pin`");
391 ty
::Adt(def
, _
) if def
.is_box() && self.can_coerce(box_found
, expected
) => {
392 // Check if the parent expression is a call to Pin::new. If it
393 // is and we were expecting a Box, ergo Pin<Box<expected>>, we
394 // can suggest Box::pin.
395 let parent
= self.tcx
.hir().get_parent_node(expr
.hir_id
);
396 let Some(Node
::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }
)) = self.tcx
.hir().find(parent
) else {
400 ExprKind
::Path(QPath
::TypeRelative(
402 kind
: TyKind
::Path(QPath
::Resolved(_
, Path { res: recv_ty, .. }
)),
406 )) if recv_ty
.opt_def_id() == pin_did
&& method
.ident
.name
== sym
::new
=> {
409 "use `Box::pin` to pin and box this expression",
411 Applicability
::MachineApplicable
,
422 /// A common error is to forget to add a semicolon at the end of a block, e.g.,
424 /// ```compile_fail,E0308
425 /// # fn bar_that_returns_u32() -> u32 { 4 }
427 /// bar_that_returns_u32()
431 /// This routine checks if the return expression in a block would make sense on its own as a
432 /// statement and the return type has been left as default or has been specified as `()`. If so,
433 /// it suggests adding a semicolon.
435 /// If the expression is the expression of a closure without block (`|| expr`), a
436 /// block is needed to be added too (`|| { expr; }`). This is denoted by `needs_block`.
437 pub fn suggest_missing_semicolon(
439 err
: &mut Diagnostic
,
440 expression
: &'tcx hir
::Expr
<'tcx
>,
444 if expected
.is_unit() {
445 // `BlockTailExpression` only relevant if the tail expr would be
446 // useful on its own.
447 match expression
.kind
{
449 | ExprKind
::MethodCall(..)
452 | ExprKind
::Match(..)
453 | ExprKind
::Block(..)
454 if expression
.can_have_side_effects()
455 // If the expression is from an external macro, then do not suggest
456 // adding a semicolon, because there's nowhere to put it.
458 && !in_external_macro(self.tcx
.sess
, expression
.span
) =>
461 err
.multipart_suggestion(
462 "consider using a semicolon here",
464 (expression
.span
.shrink_to_lo(), "{ ".to_owned()),
465 (expression
.span
.shrink_to_hi(), "; }".to_owned()),
467 Applicability
::MachineApplicable
,
471 expression
.span
.shrink_to_hi(),
472 "consider using a semicolon here",
474 Applicability
::MachineApplicable
,
483 /// A possible error is to forget to add a return type that is needed:
485 /// ```compile_fail,E0308
486 /// # fn bar_that_returns_u32() -> u32 { 4 }
488 /// bar_that_returns_u32()
492 /// This routine checks if the return type is left as default, the method is not part of an
493 /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
495 pub(in super::super) fn suggest_missing_return_type(
497 err
: &mut Diagnostic
,
498 fn_decl
: &hir
::FnDecl
<'_
>,
505 self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found
));
506 // Only suggest changing the return type for methods that
507 // haven't set a return type at all (and aren't `fn main()` or an impl).
508 match (&fn_decl
.output
, found
.is_suggestable(self.tcx
), can_suggest
, expected
.is_unit()) {
509 (&hir
::FnRetTy
::DefaultReturn(span
), true, true, true) => {
510 err
.subdiagnostic(AddReturnTypeSuggestion
::Add { span, found }
);
513 (&hir
::FnRetTy
::DefaultReturn(span
), false, true, true) => {
514 // FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest
516 err
.subdiagnostic(AddReturnTypeSuggestion
::MissingHere { span }
);
519 (&hir
::FnRetTy
::DefaultReturn(span
), _
, false, true) => {
520 // `fn main()` must return `()`, do not suggest changing return type
521 err
.subdiagnostic(ExpectedReturnTypeLabel
::Unit { span }
);
524 // expectation was caused by something else, not the default return
525 (&hir
::FnRetTy
::DefaultReturn(_
), _
, _
, false) => false,
526 (&hir
::FnRetTy
::Return(ref ty
), _
, _
, _
) => {
527 // Only point to return type if the expected type is the return type, as if they
528 // are not, the expectation must have been caused by something else.
529 debug
!("suggest_missing_return_type: return type {:?} node {:?}", ty
, ty
.kind
);
531 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, ty
);
532 debug
!("suggest_missing_return_type: return type {:?}", ty
);
533 debug
!("suggest_missing_return_type: expected type {:?}", ty
);
534 let bound_vars
= self.tcx
.late_bound_vars(fn_id
);
535 let ty
= Binder
::bind_with_vars(ty
, bound_vars
);
536 let ty
= self.normalize_associated_types_in(span
, ty
);
537 let ty
= self.tcx
.erase_late_bound_regions(ty
);
538 if self.can_coerce(expected
, ty
) {
539 err
.subdiagnostic(ExpectedReturnTypeLabel
::Other { span, expected }
);
540 self.try_suggest_return_impl_trait(err
, expected
, ty
, fn_id
);
548 /// check whether the return type is a generic type with a trait bound
549 /// only suggest this if the generic param is not present in the arguments
550 /// if this is true, hint them towards changing the return type to `impl Trait`
551 /// ```compile_fail,E0308
552 /// fn cant_name_it<T: Fn() -> u32>() -> T {
556 fn try_suggest_return_impl_trait(
558 err
: &mut Diagnostic
,
563 // Only apply the suggestion if:
564 // - the return type is a generic parameter
565 // - the generic param is not used as a fn param
566 // - the generic param has at least one bound
567 // - the generic param doesn't appear in any other bounds where it's not the Self type
569 // - Changing the return type to be `impl <all bounds>`
571 debug
!("try_suggest_return_impl_trait, expected = {:?}, found = {:?}", expected
, found
);
573 let ty
::Param(expected_ty_as_param
) = expected
.kind() else { return }
;
575 let fn_node
= self.tcx
.hir().find(fn_id
);
577 let Some(hir
::Node
::Item(hir
::Item
{
580 hir
::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }
, .. },
581 hir
::Generics { params, predicates, .. }
,
585 })) = fn_node
else { return }
;
587 if params
.get(expected_ty_as_param
.index
as usize).is_none() {
591 // get all where BoundPredicates here, because they are used in to cases below
592 let where_predicates
= predicates
594 .filter_map(|p
| match p
{
595 WherePredicate
::BoundPredicate(hir
::WhereBoundPredicate
{
600 // FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below)
601 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, bounded_ty
);
606 .map(|(ty
, bounds
)| match ty
.kind() {
607 ty
::Param(param_ty
) if param_ty
== expected_ty_as_param
=> Ok(Some(bounds
)),
608 // check whether there is any predicate that contains our `T`, like `Option<T>: Send`
609 _
=> match ty
.contains(expected
) {
614 .collect
::<Result
<Vec
<_
>, _
>>();
616 let Ok(where_predicates
) = where_predicates
else { return }
;
618 // now get all predicates in the same types as the where bounds, so we can chain them
619 let predicates_from_where
=
620 where_predicates
.iter().flatten().flat_map(|bounds
| bounds
.iter());
622 // extract all bounds from the source code using their spans
623 let all_matching_bounds_strs
= predicates_from_where
624 .filter_map(|bound
| match bound
{
625 GenericBound
::Trait(_
, _
) => {
626 self.tcx
.sess
.source_map().span_to_snippet(bound
.span()).ok()
630 .collect
::<Vec
<String
>>();
632 if all_matching_bounds_strs
.len() == 0 {
636 let all_bounds_str
= all_matching_bounds_strs
.join(" + ");
638 let ty_param_used_in_fn_params
= fn_parameters
.iter().any(|param
| {
639 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, param
);
640 matches
!(ty
.kind(), ty
::Param(fn_param_ty_param
) if expected_ty_as_param
== fn_param_ty_param
)
643 if ty_param_used_in_fn_params
{
649 "consider using an impl return type",
650 format
!("impl {}", all_bounds_str
),
651 Applicability
::MaybeIncorrect
,
655 pub(in super::super) fn suggest_missing_break_or_return_expr(
657 err
: &mut Diagnostic
,
658 expr
: &'tcx hir
::Expr
<'tcx
>,
659 fn_decl
: &hir
::FnDecl
<'_
>,
665 if !expected
.is_unit() {
668 let found
= self.resolve_vars_with_obligations(found
);
670 let in_loop
= self.is_loop(id
)
671 || self.tcx
.hir().parent_iter(id
).any(|(parent_id
, _
)| self.is_loop(parent_id
));
673 let in_local_statement
= self.is_local_statement(id
)
678 .any(|(parent_id
, _
)| self.is_local_statement(parent_id
));
680 if in_loop
&& in_local_statement
{
681 err
.multipart_suggestion(
682 "you might have meant to break the loop with this value",
684 (expr
.span
.shrink_to_lo(), "break ".to_string()),
685 (expr
.span
.shrink_to_hi(), ";".to_string()),
687 Applicability
::MaybeIncorrect
,
692 if let hir
::FnRetTy
::Return(ty
) = fn_decl
.output
{
693 let ty
= <dyn AstConv
<'_
>>::ast_ty_to_ty(self, ty
);
694 let bound_vars
= self.tcx
.late_bound_vars(fn_id
);
695 let ty
= self.tcx
.erase_late_bound_regions(Binder
::bind_with_vars(ty
, bound_vars
));
696 let ty
= self.normalize_associated_types_in(expr
.span
, ty
);
697 let ty
= match self.tcx
.asyncness(fn_id
.owner
) {
698 hir
::IsAsync
::Async
=> self
702 infcx
.get_impl_future_output_ty(ty
).unwrap_or_else(|| {
704 fn_decl
.output
.span(),
705 "failed to get output type of async function"
710 hir
::IsAsync
::NotAsync
=> ty
,
712 if self.can_coerce(found
, ty
) {
713 err
.multipart_suggestion(
714 "you might have meant to return this value",
716 (expr
.span
.shrink_to_lo(), "return ".to_string()),
717 (expr
.span
.shrink_to_hi(), ";".to_string()),
719 Applicability
::MaybeIncorrect
,
725 pub(in super::super) fn suggest_missing_parentheses(
727 err
: &mut Diagnostic
,
728 expr
: &hir
::Expr
<'_
>,
730 let sp
= self.tcx
.sess
.source_map().start_point(expr
.span
);
731 if let Some(sp
) = self.tcx
.sess
.parse_sess
.ambiguous_block_expr_parse
.borrow().get(&sp
) {
732 // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
733 self.tcx
.sess
.parse_sess
.expr_parentheses_needed(err
, *sp
);
737 /// Given an expression type mismatch, peel any `&` expressions until we get to
738 /// a block expression, and then suggest replacing the braces with square braces
739 /// if it was possibly mistaken array syntax.
740 pub(crate) fn suggest_block_to_brackets_peeling_refs(
742 diag
: &mut Diagnostic
,
743 mut expr
: &hir
::Expr
<'_
>,
744 mut expr_ty
: Ty
<'tcx
>,
745 mut expected_ty
: Ty
<'tcx
>,
748 match (&expr
.kind
, expr_ty
.kind(), expected_ty
.kind()) {
750 hir
::ExprKind
::AddrOf(_
, _
, inner_expr
),
751 ty
::Ref(_
, inner_expr_ty
, _
),
752 ty
::Ref(_
, inner_expected_ty
, _
),
755 expr_ty
= *inner_expr_ty
;
756 expected_ty
= *inner_expected_ty
;
758 (hir
::ExprKind
::Block(blk
, _
), _
, _
) => {
759 self.suggest_block_to_brackets(diag
, *blk
, expr_ty
, expected_ty
);
767 /// Suggest wrapping the block in square brackets instead of curly braces
768 /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
769 pub(crate) fn suggest_block_to_brackets(
771 diag
: &mut Diagnostic
,
772 blk
: &hir
::Block
<'_
>,
774 expected_ty
: Ty
<'tcx
>,
776 if let ty
::Slice(elem_ty
) | ty
::Array(elem_ty
, _
) = expected_ty
.kind() {
777 if self.can_coerce(blk_ty
, *elem_ty
)
778 && blk
.stmts
.is_empty()
779 && blk
.rules
== hir
::BlockCheckMode
::DefaultBlock
781 let source_map
= self.tcx
.sess
.source_map();
782 if let Ok(snippet
) = source_map
.span_to_snippet(blk
.span
) {
783 if snippet
.starts_with('{') && snippet.ends_with('}'
) {
784 diag
.multipart_suggestion_verbose(
785 "to create an array, use square brackets instead of curly braces",
790 .with_hi(rustc_span
::BytePos(blk
.span
.lo().0 + 1)),
796 .with_lo(rustc_span
::BytePos(blk
.span
.hi().0 - 1)),
800 Applicability
::MachineApplicable
,
808 fn is_loop(&self, id
: hir
::HirId
) -> bool
{
809 let node
= self.tcx
.hir().get(id
);
810 matches
!(node
, Node
::Expr(Expr { kind: ExprKind::Loop(..), .. }
))
813 fn is_local_statement(&self, id
: hir
::HirId
) -> bool
{
814 let node
= self.tcx
.hir().get(id
);
815 matches
!(node
, Node
::Stmt(Stmt { kind: StmtKind::Local(..), .. }
))
818 /// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,
819 /// which is a side-effect of autoref.
820 pub(crate) fn note_type_is_not_clone(
822 diag
: &mut Diagnostic
,
823 expected_ty
: Ty
<'tcx
>,
825 expr
: &hir
::Expr
<'_
>,
827 let hir
::ExprKind
::MethodCall(segment
, &[ref callee_expr
], _
) = expr
.kind
else { return; }
;
828 let Some(clone_trait_did
) = self.tcx
.lang_items().clone_trait() else { return; }
;
829 let ty
::Ref(_
, pointee_ty
, _
) = found_ty
.kind() else { return }
;
830 let results
= self.typeck_results
.borrow();
831 // First, look for a `Clone::clone` call
832 if segment
.ident
.name
== sym
::clone
833 && results
.type_dependent_def_id(expr
.hir_id
).map_or(
836 self.tcx
.associated_item(did
).container
837 == ty
::AssocItemContainer
::TraitContainer(clone_trait_did
)
840 // If that clone call hasn't already dereferenced the self type (i.e. don't give this
841 // diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
842 && !results
.expr_adjustments(callee_expr
).iter().any(|adj
| matches
!(adj
.kind
, ty
::adjustment
::Adjust
::Deref(..)))
843 // Check that we're in fact trying to clone into the expected type
844 && self.can_coerce(*pointee_ty
, expected_ty
)
845 // And the expected type doesn't implement `Clone`
846 && !self.predicate_must_hold_considering_regions(&traits
::Obligation
{
847 cause
: traits
::ObligationCause
::dummy(),
848 param_env
: self.param_env
,
850 predicate
: ty
::Binder
::dummy(ty
::TraitRef
{
851 def_id
: clone_trait_did
,
852 substs
: self.tcx
.mk_substs([expected_ty
.into()].iter()),
855 .to_predicate(self.tcx
),
861 "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"