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