• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::FnCtxt;
2 use rustc_ast::util::parser::PREC_POSTFIX;
3 use rustc_errors::MultiSpan;
4 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
5 use rustc_hir as hir;
6 use rustc_hir::def::{CtorKind, Res};
7 use rustc_hir::intravisit::Visitor;
8 use rustc_hir::lang_items::LangItem;
9 use rustc_hir::{is_range_literal, Node};
10 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
11 use rustc_middle::lint::in_external_macro;
12 use rustc_middle::middle::stability::EvalResult;
13 use rustc_middle::ty::adjustment::AllowTwoPhase;
14 use rustc_middle::ty::error::{ExpectedFound, TypeError};
15 use rustc_middle::ty::fold::BottomUpFolder;
16 use rustc_middle::ty::print::with_no_trimmed_paths;
17 use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable};
18 use rustc_span::symbol::{sym, Symbol};
19 use rustc_span::{BytePos, Span, DUMMY_SP};
20 use rustc_trait_selection::infer::InferCtxtExt as _;
21 use rustc_trait_selection::traits::ObligationCause;
22 
23 use super::method::probe;
24 
25 use std::cmp::min;
26 use std::iter;
27 
28 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
emit_type_mismatch_suggestions( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, error: Option<TypeError<'tcx>>, )29     pub fn emit_type_mismatch_suggestions(
30         &self,
31         err: &mut Diagnostic,
32         expr: &hir::Expr<'tcx>,
33         expr_ty: Ty<'tcx>,
34         expected: Ty<'tcx>,
35         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
36         error: Option<TypeError<'tcx>>,
37     ) {
38         if expr_ty == expected {
39             return;
40         }
41 
42         self.annotate_alternative_method_deref(err, expr, error);
43 
44         // Use `||` to give these suggestions a precedence
45         let suggested = self.suggest_missing_parentheses(err, expr)
46             || self.suggest_remove_last_method_call(err, expr, expected)
47             || self.suggest_associated_const(err, expr, expected)
48             || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
49             || self.suggest_option_to_bool(err, expr, expr_ty, expected)
50             || self.suggest_compatible_variants(err, expr, expected, expr_ty)
51             || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
52             || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
53             || self.suggest_no_capture_closure(err, expected, expr_ty)
54             || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, expected, expr_ty)
55             || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
56             || self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
57             || self.suggest_clone_for_ref(err, expr, expr_ty, expected)
58             || self.suggest_into(err, expr, expr_ty, expected)
59             || self.suggest_floating_point_literal(err, expr, expected)
60             || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
61             || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty);
62 
63         if !suggested {
64             self.note_source_of_type_mismatch_constraint(
65                 err,
66                 expr,
67                 TypeMismatchSource::Ty(expected),
68             );
69         }
70     }
71 
emit_coerce_suggestions( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, error: Option<TypeError<'tcx>>, )72     pub fn emit_coerce_suggestions(
73         &self,
74         err: &mut Diagnostic,
75         expr: &hir::Expr<'tcx>,
76         expr_ty: Ty<'tcx>,
77         expected: Ty<'tcx>,
78         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
79         error: Option<TypeError<'tcx>>,
80     ) {
81         if expr_ty == expected {
82             return;
83         }
84 
85         self.annotate_expected_due_to_let_ty(err, expr, error);
86 
87         if self.is_destruct_assignment_desugaring(expr) {
88             return;
89         }
90         self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
91         self.note_type_is_not_clone(err, expected, expr_ty, expr);
92         self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
93         self.suggest_method_call_on_range_literal(err, expr, expr_ty, expected);
94         self.suggest_return_binding_for_missing_tail_expr(err, expr, expr_ty, expected);
95         self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
96     }
97 
98     /// Really hacky heuristic to remap an `assert_eq!` error to the user
99     /// expressions provided to the macro.
adjust_expr_for_assert_eq_macro( &self, found_expr: &mut &'tcx hir::Expr<'tcx>, expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>, )100     fn adjust_expr_for_assert_eq_macro(
101         &self,
102         found_expr: &mut &'tcx hir::Expr<'tcx>,
103         expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
104     ) {
105         let Some(expected_expr) = expected_expr else { return; };
106 
107         if !found_expr.span.eq_ctxt(expected_expr.span) {
108             return;
109         }
110 
111         if !found_expr
112             .span
113             .ctxt()
114             .outer_expn_data()
115             .macro_def_id
116             .is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
117         {
118             return;
119         }
120 
121         let hir::ExprKind::Unary(
122             hir::UnOp::Deref,
123             hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
124         ) = found_expr.kind else { return; };
125         let hir::ExprKind::Unary(
126             hir::UnOp::Deref,
127             hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
128         ) = expected_expr.kind else { return; };
129 
130         for (path, name, idx, var) in [
131             (expected_path, "left_val", 0, expected_expr),
132             (found_path, "right_val", 1, found_expr),
133         ] {
134             if let hir::QPath::Resolved(_, path) = path
135                 && let [segment] = path.segments
136                 && segment.ident.name.as_str() == name
137                 && let Res::Local(hir_id) = path.res
138                 && let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
139                 && let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
140                 && let hir::ExprKind::Tup(exprs) = scrutinee.kind
141                 && let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
142             {
143                 *var = macro_arg;
144             }
145         }
146     }
147 
148     /// Requires that the two types unify, and prints an error message if
149     /// they don't.
demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>)150     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
151         if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
152             e.emit();
153         }
154     }
155 
demand_suptype_diag( &self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>156     pub fn demand_suptype_diag(
157         &self,
158         sp: Span,
159         expected: Ty<'tcx>,
160         actual: Ty<'tcx>,
161     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
162         self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
163     }
164 
165     #[instrument(skip(self), level = "debug")]
demand_suptype_with_origin( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>166     pub fn demand_suptype_with_origin(
167         &self,
168         cause: &ObligationCause<'tcx>,
169         expected: Ty<'tcx>,
170         actual: Ty<'tcx>,
171     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
172         match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) {
173             Ok(InferOk { obligations, value: () }) => {
174                 self.register_predicates(obligations);
175                 None
176             }
177             Err(e) => Some(self.err_ctxt().report_mismatched_types(&cause, expected, actual, e)),
178         }
179     }
180 
demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>)181     pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
182         if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) {
183             err.emit();
184         }
185     }
186 
demand_eqtype_diag( &self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>187     pub fn demand_eqtype_diag(
188         &self,
189         sp: Span,
190         expected: Ty<'tcx>,
191         actual: Ty<'tcx>,
192     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
193         self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
194     }
195 
demand_eqtype_with_origin( &self, cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>196     pub fn demand_eqtype_with_origin(
197         &self,
198         cause: &ObligationCause<'tcx>,
199         expected: Ty<'tcx>,
200         actual: Ty<'tcx>,
201     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
202         match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) {
203             Ok(InferOk { obligations, value: () }) => {
204                 self.register_predicates(obligations);
205                 None
206             }
207             Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)),
208         }
209     }
210 
demand_coerce( &self, expr: &'tcx hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Ty<'tcx>211     pub fn demand_coerce(
212         &self,
213         expr: &'tcx hir::Expr<'tcx>,
214         checked_ty: Ty<'tcx>,
215         expected: Ty<'tcx>,
216         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
217         allow_two_phase: AllowTwoPhase,
218     ) -> Ty<'tcx> {
219         let (ty, err) =
220             self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase);
221         if let Some(mut err) = err {
222             err.emit();
223         }
224         ty
225     }
226 
227     /// Checks that the type of `expr` can be coerced to `expected`.
228     ///
229     /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
230     /// will be permitted if the diverges flag is currently "always".
231     #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
demand_coerce_diag( &self, mut expr: &'tcx hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>)232     pub fn demand_coerce_diag(
233         &self,
234         mut expr: &'tcx hir::Expr<'tcx>,
235         checked_ty: Ty<'tcx>,
236         expected: Ty<'tcx>,
237         mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
238         allow_two_phase: AllowTwoPhase,
239     ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
240         let expected = self.resolve_vars_with_obligations(expected);
241 
242         let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
243             Ok(ty) => return (ty, None),
244             Err(e) => e,
245         };
246 
247         self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
248 
249         self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
250             expr.span,
251             "`TypeError` when attempting coercion but no error emitted",
252         ));
253         let expr = expr.peel_drop_temps();
254         let cause = self.misc(expr.span);
255         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
256         let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e);
257 
258         let is_insufficiently_polymorphic =
259             matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
260 
261         // FIXME(#73154): For now, we do leak check when coercing function
262         // pointers in typeck, instead of only during borrowck. This can lead
263         // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful.
264         if !is_insufficiently_polymorphic {
265             self.emit_coerce_suggestions(
266                 &mut err,
267                 expr,
268                 expr_ty,
269                 expected,
270                 expected_ty_expr,
271                 Some(e),
272             );
273         }
274 
275         (expected, Some(err))
276     }
277 
278     /// Notes the point at which a variable is constrained to some type incompatible
279     /// with some expectation given by `source`.
note_source_of_type_mismatch_constraint( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, source: TypeMismatchSource<'tcx>, ) -> bool280     pub fn note_source_of_type_mismatch_constraint(
281         &self,
282         err: &mut Diagnostic,
283         expr: &hir::Expr<'_>,
284         source: TypeMismatchSource<'tcx>,
285     ) -> bool {
286         let hir = self.tcx.hir();
287 
288         let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; };
289         let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; };
290         let hir::def::Res::Local(local_hir_id) = p.res else { return false; };
291         let hir::Node::Pat(pat) = hir.get(local_hir_id) else { return false; };
292         let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) {
293             hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
294             hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)),
295             _ => return false,
296         };
297         let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else { return false; };
298 
299         // Locate all the usages of the relevant binding.
300         struct FindExprs<'tcx> {
301             hir_id: hir::HirId,
302             uses: Vec<&'tcx hir::Expr<'tcx>>,
303         }
304         impl<'tcx> Visitor<'tcx> for FindExprs<'tcx> {
305             fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
306                 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind
307                     && let hir::def::Res::Local(hir_id) = path.res
308                     && hir_id == self.hir_id
309                 {
310                     self.uses.push(ex);
311                 }
312                 hir::intravisit::walk_expr(self, ex);
313             }
314         }
315 
316         let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() };
317         let body =
318             hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body"));
319         expr_finder.visit_expr(body.value);
320 
321         use rustc_infer::infer::type_variable::*;
322         use rustc_middle::infer::unify_key::*;
323         // Replaces all of the variables in the given type with a fresh inference variable.
324         let mut fudger = BottomUpFolder {
325             tcx: self.tcx,
326             ty_op: |ty| {
327                 if let ty::Infer(infer) = ty.kind() {
328                     match infer {
329                         ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin {
330                             kind: TypeVariableOriginKind::MiscVariable,
331                             span: DUMMY_SP,
332                         }),
333                         ty::InferTy::IntVar(_) => self.next_int_var(),
334                         ty::InferTy::FloatVar(_) => self.next_float_var(),
335                         _ => bug!(),
336                     }
337                 } else {
338                     ty
339                 }
340             },
341             lt_op: |_| self.tcx.lifetimes.re_erased,
342             ct_op: |ct| {
343                 if let ty::ConstKind::Infer(_) = ct.kind() {
344                     self.next_const_var(
345                         ct.ty(),
346                         ConstVariableOrigin {
347                             kind: ConstVariableOriginKind::MiscVariable,
348                             span: DUMMY_SP,
349                         },
350                     )
351                 } else {
352                     ct
353                 }
354             },
355         };
356 
357         let expected_ty = match source {
358             TypeMismatchSource::Ty(expected_ty) => expected_ty,
359             // Try to deduce what the possible value of `expr` would be if the
360             // incompatible arg were compatible. For example, given `Vec<i32>`
361             // and `vec.push(1u32)`, we ideally want to deduce that the type of
362             // `vec` *should* have been `Vec<u32>`. This will allow us to then
363             // run the subsequent code with this expectation, finding out exactly
364             // when this type diverged from our expectation.
365             TypeMismatchSource::Arg { call_expr, incompatible_arg: idx } => {
366                 let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else {
367                     return false;
368                 };
369                 let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
370                     return false;
371                 };
372                 let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| {
373                     let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
374                     // Fudge the receiver, so we can do new inference on it.
375                     let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
376                     let method = self
377                         .lookup_method_for_diagnostic(
378                             possible_rcvr_ty,
379                             segment,
380                             DUMMY_SP,
381                             call_expr,
382                             binding,
383                         )
384                         .ok()?;
385                     // Unify the method signature with our incompatible arg, to
386                     // do inference in the *opposite* direction and to find out
387                     // what our ideal rcvr ty would look like.
388                     let _ = self
389                         .at(&ObligationCause::dummy(), self.param_env)
390                         .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty)
391                         .ok()?;
392                     self.select_obligations_where_possible(|errs| {
393                         // Yeet the errors, we're already reporting errors.
394                         errs.clear();
395                     });
396                     Some(self.resolve_vars_if_possible(possible_rcvr_ty))
397                 });
398                 if let Some(rcvr_ty) = possible_rcvr_ty {
399                     rcvr_ty
400                 } else {
401                     return false;
402                 }
403             }
404         };
405 
406         // If our expected_ty does not equal init_ty, then it *began* as incompatible.
407         // No need to note in this case...
408         if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) {
409             return false;
410         }
411 
412         for window in expr_finder.uses.windows(2) {
413             // Bindings always update their recorded type after the fact, so we
414             // need to look at the *following* usage's type to see when the
415             // binding became incompatible.
416             let [binding, next_usage] = *window else { continue; };
417 
418             // Don't go past the binding (always gonna be a nonsense label if so)
419             if binding.hir_id == expr.hir_id {
420                 break;
421             }
422 
423             let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; };
424 
425             // If the type is not constrained in a way making it not possible to
426             // equate with `expected_ty` by this point, skip.
427             if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) {
428                 continue;
429             }
430 
431             if let hir::Node::Expr(parent_expr) = hir.get_parent(binding.hir_id)
432                 && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind
433                 && rcvr.hir_id == binding.hir_id
434             {
435                 // If our binding became incompatible while it was a receiver
436                 // to a method call, we may be able to make a better guess to
437                 // the source of a type mismatch.
438                 let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; };
439                 let rcvr_ty = rcvr_ty.fold_with(&mut fudger);
440                 let Ok(method) =
441                     self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
442                 else {
443                     continue;
444                 };
445 
446                 let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
447                 let ideal_method = self
448                     .lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr)
449                     .ok()
450                     .and_then(|method| {
451                         let _ = self.at(&ObligationCause::dummy(), self.param_env)
452                             .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty)
453                             .ok()?;
454                         Some(method)
455                     });
456 
457                 // Find what argument caused our rcvr to become incompatible
458                 // with the expected ty.
459                 for (idx, (expected_arg_ty, arg_expr)) in
460                     std::iter::zip(&method.sig.inputs()[1..], args).enumerate()
461                 {
462                     let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; };
463                     let arg_ty = arg_ty.fold_with(&mut fudger);
464                     let _ = self.try_coerce(
465                         arg_expr,
466                         arg_ty,
467                         *expected_arg_ty,
468                         AllowTwoPhase::No,
469                         None,
470                     );
471                     self.select_obligations_where_possible(|errs| {
472                         // Yeet the errors, we're already reporting errors.
473                         errs.clear();
474                     });
475                     // If our rcvr, after inference due to unifying the signature
476                     // with the expected argument type, is still compatible with
477                     // the rcvr, then it must've not been the source of blame.
478                     if self.can_eq(self.param_env, rcvr_ty, expected_ty) {
479                         continue;
480                     }
481                     err.span_label(arg_expr.span, format!("this argument has type `{arg_ty}`..."));
482                     err.span_label(
483                         binding.span,
484                         format!("... which causes `{ident}` to have type `{next_use_ty}`"),
485                     );
486                     // Using our "ideal" method signature, suggest a fix to this
487                     // blame arg, if possible. Don't do this if we're coming from
488                     // arg mismatch code, because we'll possibly suggest a mutually
489                     // incompatible fix at the original mismatch site.
490                     if matches!(source, TypeMismatchSource::Ty(_))
491                         && let Some(ideal_method) = ideal_method
492                     {
493                         self.emit_type_mismatch_suggestions(
494                             err,
495                             arg_expr,
496                             arg_ty,
497                             self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1]),
498                             None,
499                             None,
500                         );
501                     }
502                     return true;
503                 }
504             }
505             err.span_label(
506                 binding.span,
507                 format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"),
508             );
509             return true;
510         }
511 
512         // We must've not found something that constrained the expr.
513         false
514     }
515 
annotate_expected_due_to_let_ty( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, error: Option<TypeError<'tcx>>, )516     fn annotate_expected_due_to_let_ty(
517         &self,
518         err: &mut Diagnostic,
519         expr: &hir::Expr<'_>,
520         error: Option<TypeError<'tcx>>,
521     ) {
522         let parent = self.tcx.hir().parent_id(expr.hir_id);
523         match (self.tcx.hir().find(parent), error) {
524             (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
525                 if init.hir_id == expr.hir_id =>
526             {
527                 // Point at `let` assignment type.
528                 err.span_label(ty.span, "expected due to this");
529             }
530             (
531                 Some(hir::Node::Expr(hir::Expr {
532                     kind: hir::ExprKind::Assign(lhs, rhs, _), ..
533                 })),
534                 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
535             ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
536                 // We ignore closures explicitly because we already point at them elsewhere.
537                 // Point at the assigned-to binding.
538                 let mut primary_span = lhs.span;
539                 let mut secondary_span = lhs.span;
540                 let mut post_message = "";
541                 match lhs.kind {
542                     hir::ExprKind::Path(hir::QPath::Resolved(
543                         None,
544                         hir::Path {
545                             res:
546                                 hir::def::Res::Def(
547                                     hir::def::DefKind::Static(_) | hir::def::DefKind::Const,
548                                     def_id,
549                                 ),
550                             ..
551                         },
552                     )) => {
553                         if let Some(hir::Node::Item(hir::Item {
554                             ident,
555                             kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
556                             ..
557                         })) = self.tcx.hir().get_if_local(*def_id)
558                         {
559                             primary_span = ty.span;
560                             secondary_span = ident.span;
561                             post_message = " type";
562                         }
563                     }
564                     hir::ExprKind::Path(hir::QPath::Resolved(
565                         None,
566                         hir::Path { res: hir::def::Res::Local(hir_id), .. },
567                     )) => {
568                         if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) {
569                             primary_span = pat.span;
570                             secondary_span = pat.span;
571                             match self.tcx.hir().find_parent(pat.hir_id) {
572                                 Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
573                                     primary_span = ty.span;
574                                     post_message = " type";
575                                 }
576                                 Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
577                                     primary_span = init.span;
578                                     post_message = " value";
579                                 }
580                                 Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
581                                     primary_span = *ty_span;
582                                     post_message = " parameter type";
583                                 }
584                                 _ => {}
585                             }
586                         }
587                     }
588                     _ => {}
589                 }
590 
591                 if primary_span != secondary_span
592                     && self
593                         .tcx
594                         .sess
595                         .source_map()
596                         .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
597                 {
598                     // We are pointing at the binding's type or initializer value, but it's pattern
599                     // is in a different line, so we point at both.
600                     err.span_label(secondary_span, "expected due to the type of this binding");
601                     err.span_label(primary_span, format!("expected due to this{post_message}"));
602                 } else if post_message == "" {
603                     // We are pointing at either the assignment lhs or the binding def pattern.
604                     err.span_label(primary_span, "expected due to the type of this binding");
605                 } else {
606                     // We are pointing at the binding's type or initializer value.
607                     err.span_label(primary_span, format!("expected due to this{post_message}"));
608                 }
609 
610                 if !lhs.is_syntactic_place_expr() {
611                     // We already emitted E0070 "invalid left-hand side of assignment", so we
612                     // silence this.
613                     err.downgrade_to_delayed_bug();
614                 }
615             }
616             (
617                 Some(hir::Node::Expr(hir::Expr {
618                     kind: hir::ExprKind::Binary(_, lhs, rhs), ..
619                 })),
620                 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
621             ) if rhs.hir_id == expr.hir_id
622                 && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) =>
623             {
624                 err.span_label(lhs.span, format!("expected because this is `{expected}`"));
625             }
626             _ => {}
627         }
628     }
629 
annotate_alternative_method_deref( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, error: Option<TypeError<'tcx>>, )630     fn annotate_alternative_method_deref(
631         &self,
632         err: &mut Diagnostic,
633         expr: &hir::Expr<'_>,
634         error: Option<TypeError<'tcx>>,
635     ) {
636         let parent = self.tcx.hir().parent_id(expr.hir_id);
637         let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {return;};
638         let Some(hir::Node::Expr(hir::Expr {
639                     kind: hir::ExprKind::Assign(lhs, rhs, _), ..
640                 })) = self.tcx.hir().find(parent) else {return; };
641         if rhs.hir_id != expr.hir_id || expected.is_closure() {
642             return;
643         }
644         let hir::ExprKind::Unary(hir::UnOp::Deref, deref) = lhs.kind else { return; };
645         let hir::ExprKind::MethodCall(path, base, args, _) = deref.kind else { return; };
646         let Some(self_ty) = self.typeck_results.borrow().expr_ty_adjusted_opt(base) else { return; };
647 
648         let Ok(pick) = self
649             .lookup_probe_for_diagnostic(
650                 path.ident,
651                 self_ty,
652                 deref,
653                 probe::ProbeScope::TraitsInScope,
654                 None,
655             ) else {
656                 return;
657             };
658         let in_scope_methods = self.probe_for_name_many(
659             probe::Mode::MethodCall,
660             path.ident,
661             Some(expected),
662             probe::IsSuggestion(true),
663             self_ty,
664             deref.hir_id,
665             probe::ProbeScope::TraitsInScope,
666         );
667         let other_methods_in_scope: Vec<_> =
668             in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect();
669 
670         let all_methods = self.probe_for_name_many(
671             probe::Mode::MethodCall,
672             path.ident,
673             Some(expected),
674             probe::IsSuggestion(true),
675             self_ty,
676             deref.hir_id,
677             probe::ProbeScope::AllTraits,
678         );
679         let suggestions: Vec<_> = all_methods
680             .into_iter()
681             .filter(|c| c.item.def_id != pick.item.def_id)
682             .map(|c| {
683                 let m = c.item;
684                 let substs = ty::InternalSubsts::for_item(self.tcx, m.def_id, |param, _| {
685                     self.var_for_def(deref.span, param)
686                 });
687                 let mutability =
688                     match self.tcx.fn_sig(m.def_id).skip_binder().input(0).skip_binder().kind() {
689                         ty::Ref(_, _, hir::Mutability::Mut) => "&mut ",
690                         ty::Ref(_, _, _) => "&",
691                         _ => "",
692                     };
693                 vec![
694                     (
695                         deref.span.until(base.span),
696                         format!(
697                             "{}({}",
698                             with_no_trimmed_paths!(
699                                 self.tcx.def_path_str_with_substs(m.def_id, substs,)
700                             ),
701                             mutability,
702                         ),
703                     ),
704                     match &args[..] {
705                         [] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
706                         [first, ..] => (base.span.between(first.span), ", ".to_string()),
707                     },
708                 ]
709             })
710             .collect();
711         if suggestions.is_empty() {
712             return;
713         }
714         let mut path_span: MultiSpan = path.ident.span.into();
715         path_span.push_span_label(
716             path.ident.span,
717             with_no_trimmed_paths!(format!(
718                 "refers to `{}`",
719                 self.tcx.def_path_str(pick.item.def_id),
720             )),
721         );
722         let container_id = pick.item.container_id(self.tcx);
723         let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id));
724         for def_id in pick.import_ids {
725             let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
726             path_span.push_span_label(
727                 self.tcx.hir().span(hir_id),
728                 format!("`{container}` imported here"),
729             );
730         }
731         let tail = with_no_trimmed_paths!(match &other_methods_in_scope[..] {
732             [] => return,
733             [candidate] => format!(
734                 "the method of the same name on {} `{}`",
735                 match candidate.kind {
736                     probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for",
737                     _ => "trait",
738                 },
739                 self.tcx.def_path_str(candidate.item.container_id(self.tcx))
740             ),
741             [.., last] if other_methods_in_scope.len() < 5 => {
742                 format!(
743                     "the methods of the same name on {} and `{}`",
744                     other_methods_in_scope[..other_methods_in_scope.len() - 1]
745                         .iter()
746                         .map(|c| format!(
747                             "`{}`",
748                             self.tcx.def_path_str(c.item.container_id(self.tcx))
749                         ))
750                         .collect::<Vec<String>>()
751                         .join(", "),
752                     self.tcx.def_path_str(last.item.container_id(self.tcx))
753                 )
754             }
755             _ => format!(
756                 "the methods of the same name on {} other traits",
757                 other_methods_in_scope.len()
758             ),
759         });
760         err.span_note(
761             path_span,
762             format!(
763                 "the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
764                 path.ident,
765             ),
766         );
767         if suggestions.len() > other_methods_in_scope.len() {
768             err.note(format!(
769                 "additionally, there are {} other available methods that aren't in scope",
770                 suggestions.len() - other_methods_in_scope.len()
771             ));
772         }
773         err.multipart_suggestions(
774             format!(
775                 "you might have meant to call {}; you can use the fully-qualified path to call {} \
776                  explicitly",
777                 if suggestions.len() == 1 {
778                     "the other method"
779                 } else {
780                     "one of the other methods"
781                 },
782                 if suggestions.len() == 1 { "it" } else { "one of them" },
783             ),
784             suggestions,
785             Applicability::MaybeIncorrect,
786         );
787     }
788 
suggest_coercing_result_via_try_operator( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool789     pub(crate) fn suggest_coercing_result_via_try_operator(
790         &self,
791         err: &mut Diagnostic,
792         expr: &hir::Expr<'tcx>,
793         expected: Ty<'tcx>,
794         found: Ty<'tcx>,
795     ) -> bool {
796         let ty::Adt(e, substs_e) = expected.kind() else { return false; };
797         let ty::Adt(f, substs_f) = found.kind() else { return false; };
798         if e.did() != f.did() {
799             return false;
800         }
801         if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) {
802             return false;
803         }
804         let map = self.tcx.hir();
805         if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id)
806             && let hir::ExprKind::Ret(_) = expr.kind
807         {
808             // `return foo;`
809         } else if map.get_return_block(expr.hir_id).is_some() {
810             // Function's tail expression.
811         } else {
812             return false;
813         }
814         let e = substs_e.type_at(1);
815         let f = substs_f.type_at(1);
816         if self
817             .infcx
818             .type_implements_trait(
819                 self.tcx.get_diagnostic_item(sym::Into).unwrap(),
820                 [f, e],
821                 self.param_env,
822             )
823             .must_apply_modulo_regions()
824         {
825             err.multipart_suggestion(
826                 "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
827                  in `Ok` so the expression remains of type `Result`",
828                 vec![
829                     (expr.span.shrink_to_lo(), "Ok(".to_string()),
830                     (expr.span.shrink_to_hi(), "?)".to_string()),
831                 ],
832                 Applicability::MaybeIncorrect,
833             );
834             return true;
835         }
836         false
837     }
838 
839     /// If the expected type is an enum (Issue #55250) with any variants whose
840     /// sole field is of the found type, suggest such variants. (Issue #42764)
suggest_compatible_variants( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) -> bool841     fn suggest_compatible_variants(
842         &self,
843         err: &mut Diagnostic,
844         expr: &hir::Expr<'_>,
845         expected: Ty<'tcx>,
846         expr_ty: Ty<'tcx>,
847     ) -> bool {
848         if let ty::Adt(expected_adt, substs) = expected.kind() {
849             if let hir::ExprKind::Field(base, ident) = expr.kind {
850                 let base_ty = self.typeck_results.borrow().expr_ty(base);
851                 if self.can_eq(self.param_env, base_ty, expected)
852                     && let Some(base_span) = base.span.find_ancestor_inside(expr.span)
853                 {
854                     err.span_suggestion_verbose(
855                         expr.span.with_lo(base_span.hi()),
856                         format!("consider removing the tuple struct field `{ident}`"),
857                         "",
858                         Applicability::MaybeIncorrect,
859                     );
860                     return true;
861                 }
862             }
863 
864             // If the expression is of type () and it's the return expression of a block,
865             // we suggest adding a separate return expression instead.
866             // (To avoid things like suggesting `Ok(while .. { .. })`.)
867             if expr_ty.is_unit() {
868                 let mut id = expr.hir_id;
869                 let mut parent;
870 
871                 // Unroll desugaring, to make sure this works for `for` loops etc.
872                 loop {
873                     parent = self.tcx.hir().parent_id(id);
874                     if let Some(parent_span) = self.tcx.hir().opt_span(parent) {
875                         if parent_span.find_ancestor_inside(expr.span).is_some() {
876                             // The parent node is part of the same span, so is the result of the
877                             // same expansion/desugaring and not the 'real' parent node.
878                             id = parent;
879                             continue;
880                         }
881                     }
882                     break;
883                 }
884 
885                 if let Some(hir::Node::Block(&hir::Block {
886                     span: block_span, expr: Some(e), ..
887                 })) = self.tcx.hir().find(parent)
888                 {
889                     if e.hir_id == id {
890                         if let Some(span) = expr.span.find_ancestor_inside(block_span) {
891                             let return_suggestions = if self
892                                 .tcx
893                                 .is_diagnostic_item(sym::Result, expected_adt.did())
894                             {
895                                 vec!["Ok(())"]
896                             } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
897                                 vec!["None", "Some(())"]
898                             } else {
899                                 return false;
900                             };
901                             if let Some(indent) =
902                                 self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
903                             {
904                                 // Add a semicolon, except after `}`.
905                                 let semicolon =
906                                     match self.tcx.sess.source_map().span_to_snippet(span) {
907                                         Ok(s) if s.ends_with('}') => "",
908                                         _ => ";",
909                                     };
910                                 err.span_suggestions(
911                                     span.shrink_to_hi(),
912                                     "try adding an expression at the end of the block",
913                                     return_suggestions
914                                         .into_iter()
915                                         .map(|r| format!("{semicolon}\n{indent}{r}")),
916                                     Applicability::MaybeIncorrect,
917                                 );
918                             }
919                             return true;
920                         }
921                     }
922                 }
923             }
924 
925             let compatible_variants: Vec<(String, _, _, Option<String>)> = expected_adt
926                 .variants()
927                 .iter()
928                 .filter(|variant| {
929                     variant.fields.len() == 1
930                 })
931                 .filter_map(|variant| {
932                     let sole_field = &variant.single_field();
933 
934                     let field_is_local = sole_field.did.is_local();
935                     let field_is_accessible =
936                         sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
937                         // Skip suggestions for unstable public fields (for example `Pin::pointer`)
938                         && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
939 
940                     if !field_is_local && !field_is_accessible {
941                         return None;
942                     }
943 
944                     let note_about_variant_field_privacy = (field_is_local && !field_is_accessible)
945                         .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
946 
947                     let sole_field_ty = sole_field.ty(self.tcx, substs);
948                     if self.can_coerce(expr_ty, sole_field_ty) {
949                         let variant_path =
950                             with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
951                         // FIXME #56861: DRYer prelude filtering
952                         if let Some(path) = variant_path.strip_prefix("std::prelude::")
953                             && let Some((_, path)) = path.split_once("::")
954                         {
955                             return Some((path.to_string(), variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy));
956                         }
957                         Some((variant_path, variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy))
958                     } else {
959                         None
960                     }
961                 })
962                 .collect();
963 
964             let suggestions_for = |variant: &_, ctor_kind, field_name| {
965                 let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
966                     Some(ident) => format!("{ident}: "),
967                     None => String::new(),
968                 };
969 
970                 let (open, close) = match ctor_kind {
971                     Some(CtorKind::Fn) => ("(".to_owned(), ")"),
972                     None => (format!(" {{ {field_name}: "), " }"),
973 
974                     // unit variants don't have fields
975                     Some(CtorKind::Const) => unreachable!(),
976                 };
977 
978                 // Suggest constructor as deep into the block tree as possible.
979                 // This fixes https://github.com/rust-lang/rust/issues/101065,
980                 // and also just helps make the most minimal suggestions.
981                 let mut expr = expr;
982                 while let hir::ExprKind::Block(block, _) = &expr.kind
983                     && let Some(expr_) = &block.expr
984                 {
985                     expr = expr_
986                 }
987 
988                 vec![
989                     (expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
990                     (expr.span.shrink_to_hi(), close.to_owned()),
991                 ]
992             };
993 
994             match &compatible_variants[..] {
995                 [] => { /* No variants to format */ }
996                 [(variant, ctor_kind, field_name, note)] => {
997                     // Just a single matching variant.
998                     err.multipart_suggestion_verbose(
999                         format!(
1000                             "try wrapping the expression in `{variant}`{note}",
1001                             note = note.as_deref().unwrap_or("")
1002                         ),
1003                         suggestions_for(&**variant, *ctor_kind, *field_name),
1004                         Applicability::MaybeIncorrect,
1005                     );
1006                     return true;
1007                 }
1008                 _ => {
1009                     // More than one matching variant.
1010                     err.multipart_suggestions(
1011                         format!(
1012                             "try wrapping the expression in a variant of `{}`",
1013                             self.tcx.def_path_str(expected_adt.did())
1014                         ),
1015                         compatible_variants.into_iter().map(
1016                             |(variant, ctor_kind, field_name, _)| {
1017                                 suggestions_for(&variant, ctor_kind, field_name)
1018                             },
1019                         ),
1020                         Applicability::MaybeIncorrect,
1021                     );
1022                     return true;
1023                 }
1024             }
1025         }
1026 
1027         false
1028     }
1029 
suggest_non_zero_new_unwrap( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) -> bool1030     fn suggest_non_zero_new_unwrap(
1031         &self,
1032         err: &mut Diagnostic,
1033         expr: &hir::Expr<'_>,
1034         expected: Ty<'tcx>,
1035         expr_ty: Ty<'tcx>,
1036     ) -> bool {
1037         let tcx = self.tcx;
1038         let (adt, unwrap) = match expected.kind() {
1039             // In case Option<NonZero*> is wanted, but * is provided, suggest calling new
1040             ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
1041                 // Unwrap option
1042                 let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
1043 
1044                 (adt, "")
1045             }
1046             // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
1047             ty::Adt(adt, _) => (adt, ".unwrap()"),
1048             _ => return false,
1049         };
1050 
1051         let map = [
1052             (sym::NonZeroU8, tcx.types.u8),
1053             (sym::NonZeroU16, tcx.types.u16),
1054             (sym::NonZeroU32, tcx.types.u32),
1055             (sym::NonZeroU64, tcx.types.u64),
1056             (sym::NonZeroU128, tcx.types.u128),
1057             (sym::NonZeroI8, tcx.types.i8),
1058             (sym::NonZeroI16, tcx.types.i16),
1059             (sym::NonZeroI32, tcx.types.i32),
1060             (sym::NonZeroI64, tcx.types.i64),
1061             (sym::NonZeroI128, tcx.types.i128),
1062         ];
1063 
1064         let Some((s, _)) = map
1065             .iter()
1066             .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
1067             else { return false; };
1068 
1069         let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
1070 
1071         err.multipart_suggestion(
1072             format!("consider calling `{s}::new`"),
1073             vec![
1074                 (expr.span.shrink_to_lo(), format!("{path}::new(")),
1075                 (expr.span.shrink_to_hi(), format!("){unwrap}")),
1076             ],
1077             Applicability::MaybeIncorrect,
1078         );
1079 
1080         true
1081     }
1082 
get_conversion_methods( &self, span: Span, expected: Ty<'tcx>, checked_ty: Ty<'tcx>, hir_id: hir::HirId, ) -> Vec<AssocItem>1083     pub fn get_conversion_methods(
1084         &self,
1085         span: Span,
1086         expected: Ty<'tcx>,
1087         checked_ty: Ty<'tcx>,
1088         hir_id: hir::HirId,
1089     ) -> Vec<AssocItem> {
1090         let methods = self.probe_for_return_type(
1091             span,
1092             probe::Mode::MethodCall,
1093             expected,
1094             checked_ty,
1095             hir_id,
1096             |m| {
1097                 self.has_only_self_parameter(m)
1098                     && self
1099                         .tcx
1100                         // This special internal attribute is used to permit
1101                         // "identity-like" conversion methods to be suggested here.
1102                         //
1103                         // FIXME (#46459 and #46460): ideally
1104                         // `std::convert::Into::into` and `std::borrow:ToOwned` would
1105                         // also be `#[rustc_conversion_suggestion]`, if not for
1106                         // method-probing false-positives and -negatives (respectively).
1107                         //
1108                         // FIXME? Other potential candidate methods: `as_ref` and
1109                         // `as_mut`?
1110                         .has_attr(m.def_id, sym::rustc_conversion_suggestion)
1111             },
1112         );
1113 
1114         methods
1115     }
1116 
1117     /// This function checks whether the method is not static and does not accept other parameters than `self`.
has_only_self_parameter(&self, method: &AssocItem) -> bool1118     fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
1119         match method.kind {
1120             ty::AssocKind::Fn => {
1121                 method.fn_has_self_parameter
1122                     && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
1123                         == 1
1124             }
1125             _ => false,
1126         }
1127     }
1128 
1129     /// Identify some cases where `as_ref()` would be appropriate and suggest it.
1130     ///
1131     /// Given the following code:
1132     /// ```compile_fail,E0308
1133     /// struct Foo;
1134     /// fn takes_ref(_: &Foo) {}
1135     /// let ref opt = Some(Foo);
1136     ///
1137     /// opt.map(|param| takes_ref(param));
1138     /// ```
1139     /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead.
1140     ///
1141     /// It only checks for `Option` and `Result` and won't work with
1142     /// ```ignore (illustrative)
1143     /// opt.map(|param| { takes_ref(param) });
1144     /// ```
can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)>1145     fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> {
1146         let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else {
1147             return None;
1148         };
1149 
1150         let hir::def::Res::Local(local_id) = path.res else {
1151             return None;
1152         };
1153 
1154         let local_parent = self.tcx.hir().parent_id(local_id);
1155         let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = self.tcx.hir().find(local_parent) else {
1156             return None;
1157         };
1158 
1159         let param_parent = self.tcx.hir().parent_id(*param_hir_id);
1160         let Some(Node::Expr(hir::Expr {
1161             hir_id: expr_hir_id,
1162             kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
1163             ..
1164         })) = self.tcx.hir().find(param_parent) else {
1165             return None;
1166         };
1167 
1168         let expr_parent = self.tcx.hir().parent_id(*expr_hir_id);
1169         let hir = self.tcx.hir().find(expr_parent);
1170         let closure_params_len = closure_fn_decl.inputs.len();
1171         let (
1172             Some(Node::Expr(hir::Expr {
1173                 kind: hir::ExprKind::MethodCall(method_path, receiver, ..),
1174                 ..
1175             })),
1176             1,
1177         ) = (hir, closure_params_len) else {
1178             return None;
1179         };
1180 
1181         let self_ty = self.typeck_results.borrow().expr_ty(receiver);
1182         let name = method_path.ident.name;
1183         let is_as_ref_able = match self_ty.peel_refs().kind() {
1184             ty::Adt(def, _) => {
1185                 (self.tcx.is_diagnostic_item(sym::Option, def.did())
1186                     || self.tcx.is_diagnostic_item(sym::Result, def.did()))
1187                     && (name == sym::map || name == sym::and_then)
1188             }
1189             _ => false,
1190         };
1191         if is_as_ref_able {
1192             Some((
1193                 vec![(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())],
1194                 "consider using `as_ref` instead",
1195             ))
1196         } else {
1197             None
1198         }
1199     }
1200 
maybe_get_struct_pattern_shorthand_field( &self, expr: &hir::Expr<'_>, ) -> Option<Symbol>1201     pub(crate) fn maybe_get_struct_pattern_shorthand_field(
1202         &self,
1203         expr: &hir::Expr<'_>,
1204     ) -> Option<Symbol> {
1205         let hir = self.tcx.hir();
1206         let local = match expr {
1207             hir::Expr {
1208                 kind:
1209                     hir::ExprKind::Path(hir::QPath::Resolved(
1210                         None,
1211                         hir::Path {
1212                             res: hir::def::Res::Local(_),
1213                             segments: [hir::PathSegment { ident, .. }],
1214                             ..
1215                         },
1216                     )),
1217                 ..
1218             } => Some(ident),
1219             _ => None,
1220         }?;
1221 
1222         match hir.find_parent(expr.hir_id)? {
1223             Node::ExprField(field) => {
1224                 if field.ident.name == local.name && field.is_shorthand {
1225                     return Some(local.name);
1226                 }
1227             }
1228             _ => {}
1229         }
1230 
1231         None
1232     }
1233 
1234     /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
maybe_get_block_expr( &self, expr: &hir::Expr<'tcx>, ) -> Option<&'tcx hir::Expr<'tcx>>1235     pub(crate) fn maybe_get_block_expr(
1236         &self,
1237         expr: &hir::Expr<'tcx>,
1238     ) -> Option<&'tcx hir::Expr<'tcx>> {
1239         match expr {
1240             hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
1241             _ => None,
1242         }
1243     }
1244 
1245     /// Returns whether the given expression is an `else if`.
is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool1246     pub(crate) fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
1247         if let hir::ExprKind::If(..) = expr.kind {
1248             let parent_id = self.tcx.hir().parent_id(expr.hir_id);
1249             if let Some(Node::Expr(hir::Expr {
1250                 kind: hir::ExprKind::If(_, _, Some(else_expr)),
1251                 ..
1252             })) = self.tcx.hir().find(parent_id)
1253             {
1254                 return else_expr.hir_id == expr.hir_id;
1255             }
1256         }
1257         false
1258     }
1259 
1260     // Returns whether the given expression is a destruct assignment desugaring.
1261     // For example, `(a, b) = (1, &2);`
1262     // Here we try to find the pattern binding of the expression,
1263     // `default_binding_modes` is false only for destruct assignment desugaring.
is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool1264     pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
1265         if let hir::ExprKind::Path(hir::QPath::Resolved(
1266             _,
1267             hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
1268         )) = expr.kind
1269         {
1270             let bind = self.tcx.hir().find(*bind_hir_id);
1271             let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
1272             if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind &&
1273                 let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent {
1274                     return true;
1275                 }
1276         }
1277         return false;
1278     }
1279 
1280     /// This function is used to determine potential "simple" improvements or users' errors and
1281     /// provide them useful help. For example:
1282     ///
1283     /// ```compile_fail,E0308
1284     /// fn some_fn(s: &str) {}
1285     ///
1286     /// let x = "hey!".to_owned();
1287     /// some_fn(x); // error
1288     /// ```
1289     ///
1290     /// No need to find every potential function which could make a coercion to transform a
1291     /// `String` into a `&str` since a `&` would do the trick!
1292     ///
1293     /// In addition of this check, it also checks between references mutability state. If the
1294     /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
1295     /// `&mut`!".
suggest_deref_or_ref( &self, expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, ) -> Option<( Vec<(Span, String)>, String, Applicability, bool, bool, )>1296     pub fn suggest_deref_or_ref(
1297         &self,
1298         expr: &hir::Expr<'tcx>,
1299         checked_ty: Ty<'tcx>,
1300         expected: Ty<'tcx>,
1301     ) -> Option<(
1302         Vec<(Span, String)>,
1303         String,
1304         Applicability,
1305         bool, /* verbose */
1306         bool, /* suggest `&` or `&mut` type annotation */
1307     )> {
1308         let sess = self.sess();
1309         let sp = expr.span;
1310 
1311         // If the span is from an external macro, there's no suggestion we can make.
1312         if in_external_macro(sess, sp) {
1313             return None;
1314         }
1315 
1316         let sm = sess.source_map();
1317 
1318         let replace_prefix = |s: &str, old: &str, new: &str| {
1319             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
1320         };
1321 
1322         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
1323         let expr = expr.peel_drop_temps();
1324 
1325         match (&expr.kind, expected.kind(), checked_ty.kind()) {
1326             (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) {
1327                 (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
1328                     if let hir::ExprKind::Lit(_) = expr.kind
1329                         && let Ok(src) = sm.span_to_snippet(sp)
1330                         && replace_prefix(&src, "b\"", "\"").is_some()
1331                     {
1332                         let pos = sp.lo() + BytePos(1);
1333                         return Some((
1334                             vec![(sp.with_hi(pos), String::new())],
1335                             "consider removing the leading `b`".to_string(),
1336                             Applicability::MachineApplicable,
1337                             true,
1338                             false,
1339                         ));
1340                     }
1341                 }
1342                 (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
1343                     if let hir::ExprKind::Lit(_) = expr.kind
1344                         && let Ok(src) = sm.span_to_snippet(sp)
1345                         && replace_prefix(&src, "\"", "b\"").is_some()
1346                     {
1347                         return Some((
1348                             vec![(sp.shrink_to_lo(), "b".to_string())],
1349                             "consider adding a leading `b`".to_string(),
1350                             Applicability::MachineApplicable,
1351                             true,
1352                             false,
1353                         ));
1354                     }
1355                 }
1356                 _ => {}
1357             },
1358             (_, &ty::Ref(_, _, mutability), _) => {
1359                 // Check if it can work when put into a ref. For example:
1360                 //
1361                 // ```
1362                 // fn bar(x: &mut i32) {}
1363                 //
1364                 // let x = 0u32;
1365                 // bar(&x); // error, expected &mut
1366                 // ```
1367                 let ref_ty = match mutability {
1368                     hir::Mutability::Mut => {
1369                         Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
1370                     }
1371                     hir::Mutability::Not => {
1372                         Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
1373                     }
1374                 };
1375                 if self.can_coerce(ref_ty, expected) {
1376                     let mut sugg_sp = sp;
1377                     if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind {
1378                         let clone_trait =
1379                             self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
1380                         if args.is_empty()
1381                             && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
1382                                 |did| {
1383                                     let ai = self.tcx.associated_item(did);
1384                                     ai.trait_container(self.tcx) == Some(clone_trait)
1385                                 },
1386                             ) == Some(true)
1387                             && segment.ident.name == sym::clone
1388                         {
1389                             // If this expression had a clone call when suggesting borrowing
1390                             // we want to suggest removing it because it'd now be unnecessary.
1391                             sugg_sp = receiver.span;
1392                         }
1393                     }
1394 
1395                     if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind
1396                         && let Some(1) = self.deref_steps(expected, checked_ty)
1397                     {
1398                         // We have `*&T`, check if what was expected was `&T`.
1399                         // If so, we may want to suggest removing a `*`.
1400                         sugg_sp = sugg_sp.with_hi(inner.span.lo());
1401                         return Some((
1402                             vec![(sugg_sp, String::new())],
1403                             "consider removing deref here".to_string(),
1404                             Applicability::MachineApplicable,
1405                             true,
1406                             false,
1407                         ));
1408                     }
1409 
1410                     let needs_parens = match expr.kind {
1411                         // parenthesize if needed (Issue #46756)
1412                         hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
1413                         // parenthesize borrows of range literals (Issue #54505)
1414                         _ if is_range_literal(expr) => true,
1415                         _ => false,
1416                     };
1417 
1418                     if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
1419                         return Some((
1420                             sugg,
1421                             msg.to_string(),
1422                             Applicability::MachineApplicable,
1423                             true,
1424                             false,
1425                         ));
1426                     }
1427 
1428                     let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
1429                         Some(ident) => format!("{ident}: "),
1430                         None => String::new(),
1431                     };
1432 
1433                     if let Some(hir::Node::Expr(hir::Expr {
1434                         kind: hir::ExprKind::Assign(..),
1435                         ..
1436                     })) = self.tcx.hir().find_parent(expr.hir_id)
1437                     {
1438                         if mutability.is_mut() {
1439                             // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
1440                             return None;
1441                         }
1442                     }
1443 
1444                     let sugg = mutability.ref_prefix_str();
1445                     let (sugg, verbose) = if needs_parens {
1446                         (
1447                             vec![
1448                                 (sp.shrink_to_lo(), format!("{prefix}{sugg}(")),
1449                                 (sp.shrink_to_hi(), ")".to_string()),
1450                             ],
1451                             false,
1452                         )
1453                     } else {
1454                         (vec![(sp.shrink_to_lo(), format!("{prefix}{sugg}"))], true)
1455                     };
1456                     return Some((
1457                         sugg,
1458                         format!("consider {}borrowing here", mutability.mutably_str()),
1459                         Applicability::MachineApplicable,
1460                         verbose,
1461                         false,
1462                     ));
1463                 }
1464             }
1465             (
1466                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
1467                 _,
1468                 &ty::Ref(_, checked, _),
1469             ) if self.can_sub(self.param_env, checked, expected) => {
1470                 let make_sugg = |start: Span, end: BytePos| {
1471                     // skip `(` for tuples such as `(c) = (&123)`.
1472                     // make sure we won't suggest like `(c) = 123)` which is incorrect.
1473                     let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
1474                                 .map_or(start, |s| s.shrink_to_hi());
1475                     Some((
1476                         vec![(sp.with_hi(end), String::new())],
1477                         "consider removing the borrow".to_string(),
1478                         Applicability::MachineApplicable,
1479                         true,
1480                         true,
1481                     ))
1482                 };
1483 
1484                 // We have `&T`, check if what was expected was `T`. If so,
1485                 // we may want to suggest removing a `&`.
1486                 if sm.is_imported(expr.span) {
1487                     // Go through the spans from which this span was expanded,
1488                     // and find the one that's pointing inside `sp`.
1489                     //
1490                     // E.g. for `&format!("")`, where we want the span to the
1491                     // `format!()` invocation instead of its expansion.
1492                     if let Some(call_span) =
1493                         iter::successors(Some(expr.span), |s| s.parent_callsite())
1494                             .find(|&s| sp.contains(s))
1495                         && sm.is_span_accessible(call_span)
1496                     {
1497                         return make_sugg(sp, call_span.lo())
1498                     }
1499                     return None;
1500                 }
1501                 if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
1502                     return make_sugg(sp, expr.span.lo())
1503                 }
1504             }
1505             (
1506                 _,
1507                 &ty::RawPtr(TypeAndMut { ty: ty_b, mutbl: mutbl_b }),
1508                 &ty::Ref(_, ty_a, mutbl_a),
1509             ) => {
1510                 if let Some(steps) = self.deref_steps(ty_a, ty_b)
1511                     // Only suggest valid if dereferencing needed.
1512                     && steps > 0
1513                     // The pointer type implements `Copy` trait so the suggestion is always valid.
1514                     && let Ok(src) = sm.span_to_snippet(sp)
1515                 {
1516                     let derefs = "*".repeat(steps);
1517                     let old_prefix = mutbl_a.ref_prefix_str();
1518                     let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs;
1519 
1520                     let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| {
1521                         // skip `&` or `&mut ` if both mutabilities are mutable
1522                         let lo = sp.lo()
1523                             + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
1524                         // skip `&` or `&mut `
1525                         let hi = sp.lo() + BytePos(old_prefix.len() as _);
1526                         let sp = sp.with_lo(lo).with_hi(hi);
1527 
1528                         (
1529                             sp,
1530                             format!(
1531                                 "{}{derefs}",
1532                                 if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }
1533                             ),
1534                             if mutbl_b <= mutbl_a {
1535                                 Applicability::MachineApplicable
1536                             } else {
1537                                 Applicability::MaybeIncorrect
1538                             },
1539                         )
1540                     });
1541 
1542                     if let Some((span, src, applicability)) = suggestion {
1543                         return Some((
1544                             vec![(span, src)],
1545                             "consider dereferencing".to_string(),
1546                             applicability,
1547                             true,
1548                             false,
1549                         ));
1550                     }
1551                 }
1552             }
1553             _ if sp == expr.span => {
1554                 if let Some(mut steps) = self.deref_steps(checked_ty, expected) {
1555                     let mut expr = expr.peel_blocks();
1556                     let mut prefix_span = expr.span.shrink_to_lo();
1557                     let mut remove = String::new();
1558 
1559                     // Try peeling off any existing `&` and `&mut` to reach our target type
1560                     while steps > 0 {
1561                         if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind {
1562                             // If the expression has `&`, removing it would fix the error
1563                             prefix_span = prefix_span.with_hi(inner.span.lo());
1564                             expr = inner;
1565                             remove.push_str(mutbl.ref_prefix_str());
1566                             steps -= 1;
1567                         } else {
1568                             break;
1569                         }
1570                     }
1571                     // If we've reached our target type with just removing `&`, then just print now.
1572                     if steps == 0 && !remove.trim().is_empty() {
1573                         return Some((
1574                             vec![(prefix_span, String::new())],
1575                             format!("consider removing the `{}`", remove.trim()),
1576                             // Do not remove `&&` to get to bool, because it might be something like
1577                             // { a } && b, which we have a separate fixup suggestion that is more
1578                             // likely correct...
1579                             if remove.trim() == "&&" && expected == self.tcx.types.bool {
1580                                 Applicability::MaybeIncorrect
1581                             } else {
1582                                 Applicability::MachineApplicable
1583                             },
1584                             true,
1585                             false,
1586                         ));
1587                     }
1588 
1589                     // For this suggestion to make sense, the type would need to be `Copy`,
1590                     // or we have to be moving out of a `Box<T>`
1591                     if self.type_is_copy_modulo_regions(self.param_env, expected)
1592                         // FIXME(compiler-errors): We can actually do this if the checked_ty is
1593                         // `steps` layers of boxes, not just one, but this is easier and most likely.
1594                         || (checked_ty.is_box() && steps == 1)
1595                         // We can always deref a binop that takes its arguments by ref.
1596                         || matches!(
1597                             self.tcx.hir().get_parent(expr.hir_id),
1598                             hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. })
1599                                 if !op.node.is_by_value()
1600                         )
1601                     {
1602                         let deref_kind = if checked_ty.is_box() {
1603                             "unboxing the value"
1604                         } else if checked_ty.is_ref() {
1605                             "dereferencing the borrow"
1606                         } else {
1607                             "dereferencing the type"
1608                         };
1609 
1610                         // Suggest removing `&` if we have removed any, otherwise suggest just
1611                         // dereferencing the remaining number of steps.
1612                         let message = if remove.is_empty() {
1613                             format!("consider {deref_kind}")
1614                         } else {
1615                             format!(
1616                                 "consider removing the `{}` and {} instead",
1617                                 remove.trim(),
1618                                 deref_kind
1619                             )
1620                         };
1621 
1622                         let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
1623                             Some(ident) => format!("{ident}: "),
1624                             None => String::new(),
1625                         };
1626 
1627                         let (span, suggestion) = if self.is_else_if_block(expr) {
1628                             // Don't suggest nonsense like `else *if`
1629                             return None;
1630                         } else if let Some(expr) = self.maybe_get_block_expr(expr) {
1631                             // prefix should be empty here..
1632                             (expr.span.shrink_to_lo(), "*".to_string())
1633                         } else {
1634                             (prefix_span, format!("{}{}", prefix, "*".repeat(steps)))
1635                         };
1636                         if suggestion.trim().is_empty() {
1637                             return None;
1638                         }
1639 
1640                         return Some((
1641                             vec![(span, suggestion)],
1642                             message,
1643                             Applicability::MachineApplicable,
1644                             true,
1645                             false,
1646                         ));
1647                     }
1648                 }
1649             }
1650             _ => {}
1651         }
1652         None
1653     }
1654 
suggest_cast( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool1655     pub fn suggest_cast(
1656         &self,
1657         err: &mut Diagnostic,
1658         expr: &hir::Expr<'_>,
1659         checked_ty: Ty<'tcx>,
1660         expected_ty: Ty<'tcx>,
1661         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
1662     ) -> bool {
1663         if self.tcx.sess.source_map().is_imported(expr.span) {
1664             // Ignore if span is from within a macro.
1665             return false;
1666         }
1667 
1668         let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else {
1669             return false;
1670         };
1671 
1672         // If casting this expression to a given numeric type would be appropriate in case of a type
1673         // mismatch.
1674         //
1675         // We want to minimize the amount of casting operations that are suggested, as it can be a
1676         // lossy operation with potentially bad side effects, so we only suggest when encountering
1677         // an expression that indicates that the original type couldn't be directly changed.
1678         //
1679         // For now, don't suggest casting with `as`.
1680         let can_cast = false;
1681 
1682         let mut sugg = vec![];
1683 
1684         if let Some(hir::Node::ExprField(field)) = self.tcx.hir().find_parent(expr.hir_id) {
1685             // `expr` is a literal field for a struct, only suggest if appropriate
1686             if field.is_shorthand {
1687                 // This is a field literal
1688                 sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident)));
1689             } else {
1690                 // Likely a field was meant, but this field wasn't found. Do not suggest anything.
1691                 return false;
1692             }
1693         };
1694 
1695         if let hir::ExprKind::Call(path, args) = &expr.kind
1696             && let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
1697                 (&path.kind, args.len())
1698             // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697).
1699             && let (hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), sym::from) =
1700                 (&base_ty.kind, path_segment.ident.name)
1701         {
1702             if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() {
1703                 match ident.name {
1704                     sym::i128
1705                     | sym::i64
1706                     | sym::i32
1707                     | sym::i16
1708                     | sym::i8
1709                     | sym::u128
1710                     | sym::u64
1711                     | sym::u32
1712                     | sym::u16
1713                     | sym::u8
1714                     | sym::isize
1715                     | sym::usize
1716                         if base_ty_path.segments.len() == 1 =>
1717                     {
1718                         return false;
1719                     }
1720                     _ => {}
1721                 }
1722             }
1723         }
1724 
1725         let msg = format!(
1726             "you can convert {} `{}` to {} `{}`",
1727             checked_ty.kind().article(),
1728             checked_ty,
1729             expected_ty.kind().article(),
1730             expected_ty,
1731         );
1732         let cast_msg = format!(
1733             "you can cast {} `{}` to {} `{}`",
1734             checked_ty.kind().article(),
1735             checked_ty,
1736             expected_ty.kind().article(),
1737             expected_ty,
1738         );
1739         let lit_msg = format!(
1740             "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
1741         );
1742 
1743         let close_paren = if expr.precedence().order() < PREC_POSTFIX {
1744             sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
1745             ")"
1746         } else {
1747             ""
1748         };
1749 
1750         let mut cast_suggestion = sugg.clone();
1751         cast_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren} as {expected_ty}")));
1752         let mut into_suggestion = sugg.clone();
1753         into_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren}.into()")));
1754         let mut suffix_suggestion = sugg.clone();
1755         suffix_suggestion.push((
1756             if matches!(
1757                 (&expected_ty.kind(), &checked_ty.kind()),
1758                 (ty::Int(_) | ty::Uint(_), ty::Float(_))
1759             ) {
1760                 // Remove fractional part from literal, for example `42.0f32` into `42`
1761                 let src = src.trim_end_matches(&checked_ty.to_string());
1762                 let len = src.split('.').next().unwrap().len();
1763                 expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
1764             } else {
1765                 let len = src.trim_end_matches(&checked_ty.to_string()).len();
1766                 expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
1767             },
1768             if expr.precedence().order() < PREC_POSTFIX {
1769                 // Readd `)`
1770                 format!("{expected_ty})")
1771             } else {
1772                 expected_ty.to_string()
1773             },
1774         ));
1775         let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
1776             if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
1777         };
1778         let is_negative_int =
1779             |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Neg, ..));
1780         let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..));
1781 
1782         let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
1783 
1784         let suggest_fallible_into_or_lhs_from =
1785             |err: &mut Diagnostic, exp_to_found_is_fallible: bool| {
1786                 // If we know the expression the expected type is derived from, we might be able
1787                 // to suggest a widening conversion rather than a narrowing one (which may
1788                 // panic). For example, given x: u8 and y: u32, if we know the span of "x",
1789                 //   x > y
1790                 // can be given the suggestion "u32::from(x) > y" rather than
1791                 // "x > y.try_into().unwrap()".
1792                 let lhs_expr_and_src = expected_ty_expr.and_then(|expr| {
1793                     self.tcx
1794                         .sess
1795                         .source_map()
1796                         .span_to_snippet(expr.span)
1797                         .ok()
1798                         .map(|src| (expr, src))
1799                 });
1800                 let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
1801                     (lhs_expr_and_src, exp_to_found_is_fallible)
1802                 {
1803                     let msg = format!(
1804                         "you can convert `{lhs_src}` from `{expected_ty}` to `{checked_ty}`, matching the type of `{src}`",
1805                     );
1806                     let suggestion = vec![
1807                         (lhs_expr.span.shrink_to_lo(), format!("{checked_ty}::from(")),
1808                         (lhs_expr.span.shrink_to_hi(), ")".to_string()),
1809                     ];
1810                     (msg, suggestion)
1811                 } else {
1812                     let msg =
1813                         format!("{} and panic if the converted value doesn't fit", msg.clone());
1814                     let mut suggestion = sugg.clone();
1815                     suggestion.push((
1816                         expr.span.shrink_to_hi(),
1817                         format!("{close_paren}.try_into().unwrap()"),
1818                     ));
1819                     (msg, suggestion)
1820                 };
1821                 err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
1822             };
1823 
1824         let suggest_to_change_suffix_or_into =
1825             |err: &mut Diagnostic,
1826              found_to_exp_is_fallible: bool,
1827              exp_to_found_is_fallible: bool| {
1828                 let exp_is_lhs = expected_ty_expr.is_some_and(|e| self.tcx.hir().is_lhs(e.hir_id));
1829 
1830                 if exp_is_lhs {
1831                     return;
1832                 }
1833 
1834                 let always_fallible = found_to_exp_is_fallible
1835                     && (exp_to_found_is_fallible || expected_ty_expr.is_none());
1836                 let msg = if literal_is_ty_suffixed(expr) {
1837                     lit_msg.clone()
1838                 } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
1839                     // We now know that converting either the lhs or rhs is fallible. Before we
1840                     // suggest a fallible conversion, check if the value can never fit in the
1841                     // expected type.
1842                     let msg = format!("`{src}` cannot fit into type `{expected_ty}`");
1843                     err.note(msg);
1844                     return;
1845                 } else if in_const_context {
1846                     // Do not recommend `into` or `try_into` in const contexts.
1847                     return;
1848                 } else if found_to_exp_is_fallible {
1849                     return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible);
1850                 } else {
1851                     msg.clone()
1852                 };
1853                 let suggestion = if literal_is_ty_suffixed(expr) {
1854                     suffix_suggestion.clone()
1855                 } else {
1856                     into_suggestion.clone()
1857                 };
1858                 err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
1859             };
1860 
1861         match (&expected_ty.kind(), &checked_ty.kind()) {
1862             (ty::Int(exp), ty::Int(found)) => {
1863                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1864                 {
1865                     (Some(exp), Some(found)) if exp < found => (true, false),
1866                     (Some(exp), Some(found)) if exp > found => (false, true),
1867                     (None, Some(8 | 16)) => (false, true),
1868                     (Some(8 | 16), None) => (true, false),
1869                     (None, _) | (_, None) => (true, true),
1870                     _ => (false, false),
1871                 };
1872                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1873                 true
1874             }
1875             (ty::Uint(exp), ty::Uint(found)) => {
1876                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1877                 {
1878                     (Some(exp), Some(found)) if exp < found => (true, false),
1879                     (Some(exp), Some(found)) if exp > found => (false, true),
1880                     (None, Some(8 | 16)) => (false, true),
1881                     (Some(8 | 16), None) => (true, false),
1882                     (None, _) | (_, None) => (true, true),
1883                     _ => (false, false),
1884                 };
1885                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1886                 true
1887             }
1888             (&ty::Int(exp), &ty::Uint(found)) => {
1889                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1890                 {
1891                     (Some(exp), Some(found)) if found < exp => (false, true),
1892                     (None, Some(8)) => (false, true),
1893                     _ => (true, true),
1894                 };
1895                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1896                 true
1897             }
1898             (&ty::Uint(exp), &ty::Int(found)) => {
1899                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1900                 {
1901                     (Some(exp), Some(found)) if found > exp => (true, false),
1902                     (Some(8), None) => (true, false),
1903                     _ => (true, true),
1904                 };
1905                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1906                 true
1907             }
1908             (ty::Float(exp), ty::Float(found)) => {
1909                 if found.bit_width() < exp.bit_width() {
1910                     suggest_to_change_suffix_or_into(err, false, true);
1911                 } else if literal_is_ty_suffixed(expr) {
1912                     err.multipart_suggestion_verbose(
1913                         lit_msg,
1914                         suffix_suggestion,
1915                         Applicability::MachineApplicable,
1916                     );
1917                 } else if can_cast {
1918                     // Missing try_into implementation for `f64` to `f32`
1919                     err.multipart_suggestion_verbose(
1920                         format!("{cast_msg}, producing the closest possible value"),
1921                         cast_suggestion,
1922                         Applicability::MaybeIncorrect, // lossy conversion
1923                     );
1924                 }
1925                 true
1926             }
1927             (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
1928                 if literal_is_ty_suffixed(expr) {
1929                     err.multipart_suggestion_verbose(
1930                         lit_msg,
1931                         suffix_suggestion,
1932                         Applicability::MachineApplicable,
1933                     );
1934                 } else if can_cast {
1935                     // Missing try_into implementation for `{float}` to `{integer}`
1936                     err.multipart_suggestion_verbose(
1937                         format!("{msg}, rounding the float towards zero"),
1938                         cast_suggestion,
1939                         Applicability::MaybeIncorrect, // lossy conversion
1940                     );
1941                 }
1942                 true
1943             }
1944             (ty::Float(exp), ty::Uint(found)) => {
1945                 // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
1946                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
1947                     err.multipart_suggestion_verbose(
1948                         format!(
1949                             "{msg}, producing the floating point representation of the integer",
1950                         ),
1951                         into_suggestion,
1952                         Applicability::MachineApplicable,
1953                     );
1954                 } else if literal_is_ty_suffixed(expr) {
1955                     err.multipart_suggestion_verbose(
1956                         lit_msg,
1957                         suffix_suggestion,
1958                         Applicability::MachineApplicable,
1959                     );
1960                 } else {
1961                     // Missing try_into implementation for `{integer}` to `{float}`
1962                     err.multipart_suggestion_verbose(
1963                         format!(
1964                             "{cast_msg}, producing the floating point representation of the integer, \
1965                                  rounded if necessary",
1966                         ),
1967                         cast_suggestion,
1968                         Applicability::MaybeIncorrect, // lossy conversion
1969                     );
1970                 }
1971                 true
1972             }
1973             (ty::Float(exp), ty::Int(found)) => {
1974                 // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
1975                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
1976                     err.multipart_suggestion_verbose(
1977                         format!(
1978                             "{}, producing the floating point representation of the integer",
1979                             msg.clone(),
1980                         ),
1981                         into_suggestion,
1982                         Applicability::MachineApplicable,
1983                     );
1984                 } else if literal_is_ty_suffixed(expr) {
1985                     err.multipart_suggestion_verbose(
1986                         lit_msg,
1987                         suffix_suggestion,
1988                         Applicability::MachineApplicable,
1989                     );
1990                 } else {
1991                     // Missing try_into implementation for `{integer}` to `{float}`
1992                     err.multipart_suggestion_verbose(
1993                         format!(
1994                             "{}, producing the floating point representation of the integer, \
1995                                 rounded if necessary",
1996                             &msg,
1997                         ),
1998                         cast_suggestion,
1999                         Applicability::MaybeIncorrect, // lossy conversion
2000                     );
2001                 }
2002                 true
2003             }
2004             (
2005                 &ty::Uint(ty::UintTy::U32 | ty::UintTy::U64 | ty::UintTy::U128)
2006                 | &ty::Int(ty::IntTy::I32 | ty::IntTy::I64 | ty::IntTy::I128),
2007                 &ty::Char,
2008             ) => {
2009                 err.multipart_suggestion_verbose(
2010                     format!("{cast_msg}, since a `char` always occupies 4 bytes"),
2011                     cast_suggestion,
2012                     Applicability::MachineApplicable,
2013                 );
2014                 true
2015             }
2016             _ => false,
2017         }
2018     }
2019 
2020     /// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
suggest_method_call_on_range_literal( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, )2021     pub fn suggest_method_call_on_range_literal(
2022         &self,
2023         err: &mut Diagnostic,
2024         expr: &hir::Expr<'tcx>,
2025         checked_ty: Ty<'tcx>,
2026         expected_ty: Ty<'tcx>,
2027     ) {
2028         if !hir::is_range_literal(expr) {
2029             return;
2030         }
2031         let hir::ExprKind::Struct(
2032             hir::QPath::LangItem(LangItem::Range, ..),
2033             [start, end],
2034             _,
2035         ) = expr.kind else { return; };
2036         let parent = self.tcx.hir().parent_id(expr.hir_id);
2037         if let Some(hir::Node::ExprField(_)) = self.tcx.hir().find(parent) {
2038             // Ignore `Foo { field: a..Default::default() }`
2039             return;
2040         }
2041         let mut expr = end.expr;
2042         let mut expectation = Some(expected_ty);
2043         while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind {
2044             // Getting to the root receiver and asserting it is a fn call let's us ignore cases in
2045             // `tests/ui/methods/issues/issue-90315.stderr`.
2046             expr = rcvr;
2047             // If we have more than one layer of calls, then the expected ty
2048             // cannot guide the method probe.
2049             expectation = None;
2050         }
2051         let hir::ExprKind::Call(method_name, _) = expr.kind else { return; };
2052         let ty::Adt(adt, _) = checked_ty.kind() else { return; };
2053         if self.tcx.lang_items().range_struct() != Some(adt.did()) {
2054             return;
2055         }
2056         if let ty::Adt(adt, _) = expected_ty.kind()
2057             && self.tcx.lang_items().range_struct() == Some(adt.did())
2058         {
2059             return;
2060         }
2061         // Check if start has method named end.
2062         let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else { return; };
2063         let [hir::PathSegment { ident, .. }] = p.segments else { return; };
2064         let self_ty = self.typeck_results.borrow().expr_ty(start.expr);
2065         let Ok(_pick) = self.lookup_probe_for_diagnostic(
2066             *ident,
2067             self_ty,
2068             expr,
2069             probe::ProbeScope::AllTraits,
2070             expectation,
2071         ) else { return; };
2072         let mut sugg = ".";
2073         let mut span = start.expr.span.between(end.expr.span);
2074         if span.lo() + BytePos(2) == span.hi() {
2075             // There's no space between the start, the range op and the end, suggest removal which
2076             // will be more noticeable than the replacement of `..` with `.`.
2077             span = span.with_lo(span.lo() + BytePos(1));
2078             sugg = "";
2079         }
2080         err.span_suggestion_verbose(
2081             span,
2082             "you likely meant to write a method call instead of a range",
2083             sugg,
2084             Applicability::MachineApplicable,
2085         );
2086     }
2087 
2088     /// Identify when the type error is because `()` is found in a binding that was assigned a
2089     /// block without a tail expression.
suggest_return_binding_for_missing_tail_expr( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected_ty: Ty<'tcx>, )2090     fn suggest_return_binding_for_missing_tail_expr(
2091         &self,
2092         err: &mut Diagnostic,
2093         expr: &hir::Expr<'_>,
2094         checked_ty: Ty<'tcx>,
2095         expected_ty: Ty<'tcx>,
2096     ) {
2097         if !checked_ty.is_unit() {
2098             return;
2099         }
2100         let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; };
2101         let hir::def::Res::Local(hir_id) = path.res else { return; };
2102         let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else {
2103             return;
2104         };
2105         let Some(hir::Node::Local(hir::Local {
2106             ty: None,
2107             init: Some(init),
2108             ..
2109         })) = self.tcx.hir().find_parent(pat.hir_id) else { return; };
2110         let hir::ExprKind::Block(block, None) = init.kind else { return; };
2111         if block.expr.is_some() {
2112             return;
2113         }
2114         let [.., stmt] = block.stmts else {
2115             err.span_label(block.span, "this empty block is missing a tail expression");
2116             return;
2117         };
2118         let hir::StmtKind::Semi(tail_expr) = stmt.kind else { return; };
2119         let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else { return; };
2120         if self.can_eq(self.param_env, expected_ty, ty) {
2121             err.span_suggestion_short(
2122                 stmt.span.with_lo(tail_expr.span.hi()),
2123                 "remove this semicolon",
2124                 "",
2125                 Applicability::MachineApplicable,
2126             );
2127         } else {
2128             err.span_label(block.span, "this block is missing a tail expression");
2129         }
2130     }
2131 
note_wrong_return_ty_due_to_generic_arg( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, )2132     fn note_wrong_return_ty_due_to_generic_arg(
2133         &self,
2134         err: &mut Diagnostic,
2135         expr: &hir::Expr<'_>,
2136         checked_ty: Ty<'tcx>,
2137     ) {
2138         let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
2139         enum CallableKind {
2140             Function,
2141             Method,
2142             Constructor,
2143         }
2144         let mut maybe_emit_help = |def_id: hir::def_id::DefId,
2145                                    callable: rustc_span::symbol::Ident,
2146                                    args: &[hir::Expr<'_>],
2147                                    kind: CallableKind| {
2148             let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
2149             let fn_ty = self.tcx.type_of(def_id).skip_binder();
2150             if !fn_ty.is_fn() {
2151                 return;
2152             }
2153             let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
2154             let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
2155             if matches!(arg.kind(), ty::Param(_))
2156                 && fn_sig.output().contains(arg)
2157                 && self.node_ty(args[arg_idx].hir_id) == checked_ty
2158             {
2159                 let mut multi_span: MultiSpan = parent_expr.span.into();
2160                 multi_span.push_span_label(
2161                     args[arg_idx].span,
2162                     format!(
2163                         "this argument influences the {} of `{}`",
2164                         if matches!(kind, CallableKind::Constructor) {
2165                             "type"
2166                         } else {
2167                             "return type"
2168                         },
2169                         callable
2170                     ),
2171                 );
2172                 err.span_help(
2173                     multi_span,
2174                     format!(
2175                         "the {} `{}` due to the type of the argument passed",
2176                         match kind {
2177                             CallableKind::Function => "return type of this call is",
2178                             CallableKind::Method => "return type of this call is",
2179                             CallableKind::Constructor => "type constructed contains",
2180                         },
2181                         checked_ty
2182                     ),
2183                 );
2184             }
2185         };
2186         match parent_expr.kind {
2187             hir::ExprKind::Call(fun, args) => {
2188                 let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
2189                 let hir::def::Res::Def(kind, def_id) = path.res else { return; };
2190                 let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
2191                     CallableKind::Constructor
2192                 } else {
2193                     CallableKind::Function
2194                 };
2195                 maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
2196             }
2197             hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
2198                 let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
2199                 maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
2200             }
2201             _ => return,
2202         }
2203     }
2204 }
2205 
2206 pub enum TypeMismatchSource<'tcx> {
2207     /// Expected the binding to have the given type, but it was found to have
2208     /// a different type. Find out when that type first became incompatible.
2209     Ty(Ty<'tcx>),
2210     /// When we fail during method argument checking, try to find out if a previous
2211     /// expression has constrained the method's receiver in a way that makes the
2212     /// argument's type incompatible.
2213     Arg { call_expr: &'tcx hir::Expr<'tcx>, incompatible_arg: usize },
2214 }
2215