]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/demand.rs
Apply suggestions from the review
[rust.git] / compiler / rustc_typeck / src / check / demand.rs
1 use crate::check::FnCtxt;
2 use rustc_infer::infer::InferOk;
3 use rustc_trait_selection::infer::InferCtxtExt as _;
4 use rustc_trait_selection::traits::ObligationCause;
5
6 use rustc_ast::util::parser::PREC_POSTFIX;
7 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
8 use rustc_hir as hir;
9 use rustc_hir::lang_items::LangItem;
10 use rustc_hir::{is_range_literal, Node};
11 use rustc_middle::lint::in_external_macro;
12 use rustc_middle::ty::adjustment::AllowTwoPhase;
13 use rustc_middle::ty::error::{ExpectedFound, TypeError};
14 use rustc_middle::ty::print::with_no_trimmed_paths;
15 use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut};
16 use rustc_span::symbol::{sym, Symbol};
17 use rustc_span::{BytePos, Span};
18
19 use super::method::probe;
20
21 use std::iter;
22
23 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24     pub fn emit_coerce_suggestions(
25         &self,
26         err: &mut Diagnostic,
27         expr: &hir::Expr<'tcx>,
28         expr_ty: Ty<'tcx>,
29         expected: Ty<'tcx>,
30         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
31         error: Option<TypeError<'tcx>>,
32     ) {
33         self.annotate_expected_due_to_let_ty(err, expr, error);
34         self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
35         self.suggest_compatible_variants(err, expr, expected, expr_ty);
36         self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
37         if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
38             return;
39         }
40         self.suggest_no_capture_closure(err, expected, expr_ty);
41         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
42         self.suggest_missing_parentheses(err, expr);
43         self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
44         self.note_type_is_not_clone(err, expected, expr_ty, expr);
45         self.note_need_for_fn_pointer(err, expected, expr_ty);
46         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
47         self.report_closure_inferred_return_type(err, expected);
48     }
49
50     // Requires that the two types unify, and prints an error message if
51     // they don't.
52     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
53         if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
54             e.emit();
55         }
56     }
57
58     pub fn demand_suptype_diag(
59         &self,
60         sp: Span,
61         expected: Ty<'tcx>,
62         actual: Ty<'tcx>,
63     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
64         self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
65     }
66
67     #[instrument(skip(self), level = "debug")]
68     pub fn demand_suptype_with_origin(
69         &self,
70         cause: &ObligationCause<'tcx>,
71         expected: Ty<'tcx>,
72         actual: Ty<'tcx>,
73     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
74         match self.at(cause, self.param_env).sup(expected, actual) {
75             Ok(InferOk { obligations, value: () }) => {
76                 self.register_predicates(obligations);
77                 None
78             }
79             Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
80         }
81     }
82
83     pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
84         if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) {
85             err.emit();
86         }
87     }
88
89     pub fn demand_eqtype_diag(
90         &self,
91         sp: Span,
92         expected: Ty<'tcx>,
93         actual: Ty<'tcx>,
94     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
95         self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
96     }
97
98     pub fn demand_eqtype_with_origin(
99         &self,
100         cause: &ObligationCause<'tcx>,
101         expected: Ty<'tcx>,
102         actual: Ty<'tcx>,
103     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
104         match self.at(cause, self.param_env).eq(expected, actual) {
105             Ok(InferOk { obligations, value: () }) => {
106                 self.register_predicates(obligations);
107                 None
108             }
109             Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
110         }
111     }
112
113     pub fn demand_coerce(
114         &self,
115         expr: &hir::Expr<'tcx>,
116         checked_ty: Ty<'tcx>,
117         expected: Ty<'tcx>,
118         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
119         allow_two_phase: AllowTwoPhase,
120     ) -> Ty<'tcx> {
121         let (ty, err) =
122             self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase);
123         if let Some(mut err) = err {
124             err.emit();
125         }
126         ty
127     }
128
129     /// Checks that the type of `expr` can be coerced to `expected`.
130     ///
131     /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
132     /// will be permitted if the diverges flag is currently "always".
133     #[tracing::instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
134     pub fn demand_coerce_diag(
135         &self,
136         expr: &hir::Expr<'tcx>,
137         checked_ty: Ty<'tcx>,
138         expected: Ty<'tcx>,
139         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
140         allow_two_phase: AllowTwoPhase,
141     ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
142         let expected = self.resolve_vars_with_obligations(expected);
143
144         let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
145             Ok(ty) => return (ty, None),
146             Err(e) => e,
147         };
148
149         self.set_tainted_by_errors();
150         let expr = expr.peel_drop_temps();
151         let cause = self.misc(expr.span);
152         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
153         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
154
155         let is_insufficiently_polymorphic =
156             matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
157
158         // FIXME(#73154): For now, we do leak check when coercing function
159         // pointers in typeck, instead of only during borrowck. This can lead
160         // to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful.
161         if !is_insufficiently_polymorphic {
162             self.emit_coerce_suggestions(
163                 &mut err,
164                 expr,
165                 expr_ty,
166                 expected,
167                 expected_ty_expr,
168                 Some(e),
169             );
170         }
171
172         (expected, Some(err))
173     }
174
175     fn annotate_expected_due_to_let_ty(
176         &self,
177         err: &mut Diagnostic,
178         expr: &hir::Expr<'_>,
179         error: Option<TypeError<'_>>,
180     ) {
181         let parent = self.tcx.hir().get_parent_node(expr.hir_id);
182         match (self.tcx.hir().find(parent), error) {
183             (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
184                 if init.hir_id == expr.hir_id =>
185             {
186                 // Point at `let` assignment type.
187                 err.span_label(ty.span, "expected due to this");
188             }
189             (
190                 Some(hir::Node::Expr(hir::Expr {
191                     kind: hir::ExprKind::Assign(lhs, rhs, _), ..
192                 })),
193                 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
194             ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
195                 // We ignore closures explicitly because we already point at them elsewhere.
196                 // Point at the assigned-to binding.
197                 let mut primary_span = lhs.span;
198                 let mut secondary_span = lhs.span;
199                 let mut post_message = "";
200                 match lhs.kind {
201                     hir::ExprKind::Path(hir::QPath::Resolved(
202                         None,
203                         hir::Path {
204                             res:
205                                 hir::def::Res::Def(
206                                     hir::def::DefKind::Static(_) | hir::def::DefKind::Const,
207                                     def_id,
208                                 ),
209                             ..
210                         },
211                     )) => {
212                         if let Some(hir::Node::Item(hir::Item {
213                             ident,
214                             kind: hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..),
215                             ..
216                         })) = self.tcx.hir().get_if_local(*def_id)
217                         {
218                             primary_span = ty.span;
219                             secondary_span = ident.span;
220                             post_message = " type";
221                         }
222                     }
223                     hir::ExprKind::Path(hir::QPath::Resolved(
224                         None,
225                         hir::Path { res: hir::def::Res::Local(hir_id), .. },
226                     )) => {
227                         if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) {
228                             let parent = self.tcx.hir().get_parent_node(pat.hir_id);
229                             primary_span = pat.span;
230                             secondary_span = pat.span;
231                             match self.tcx.hir().find(parent) {
232                                 Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
233                                     primary_span = ty.span;
234                                     post_message = " type";
235                                 }
236                                 Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
237                                     primary_span = init.span;
238                                     post_message = " value";
239                                 }
240                                 Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
241                                     primary_span = *ty_span;
242                                     post_message = " parameter type";
243                                 }
244                                 _ => {}
245                             }
246                         }
247                     }
248                     _ => {}
249                 }
250
251                 if primary_span != secondary_span
252                     && self
253                         .tcx
254                         .sess
255                         .source_map()
256                         .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
257                 {
258                     // We are pointing at the binding's type or initializer value, but it's pattern
259                     // is in a different line, so we point at both.
260                     err.span_label(secondary_span, "expected due to the type of this binding");
261                     err.span_label(primary_span, &format!("expected due to this{post_message}"));
262                 } else if post_message == "" {
263                     // We are pointing at either the assignment lhs or the binding def pattern.
264                     err.span_label(primary_span, "expected due to the type of this binding");
265                 } else {
266                     // We are pointing at the binding's type or initializer value.
267                     err.span_label(primary_span, &format!("expected due to this{post_message}"));
268                 }
269
270                 if !lhs.is_syntactic_place_expr() {
271                     // We already emitted E0070 "invalid left-hand side of assignment", so we
272                     // silence this.
273                     err.downgrade_to_delayed_bug();
274                 }
275             }
276             _ => {}
277         }
278     }
279
280     /// If the expected type is an enum (Issue #55250) with any variants whose
281     /// sole field is of the found type, suggest such variants. (Issue #42764)
282     fn suggest_compatible_variants(
283         &self,
284         err: &mut Diagnostic,
285         expr: &hir::Expr<'_>,
286         expected: Ty<'tcx>,
287         expr_ty: Ty<'tcx>,
288     ) {
289         if let ty::Adt(expected_adt, substs) = expected.kind() {
290             // If the expression is of type () and it's the return expression of a block,
291             // we suggest adding a separate return expression instead.
292             // (To avoid things like suggesting `Ok(while .. { .. })`.)
293             if expr_ty.is_unit() {
294                 let mut id = expr.hir_id;
295                 let mut parent;
296
297                 // Unroll desugaring, to make sure this works for `for` loops etc.
298                 loop {
299                     parent = self.tcx.hir().get_parent_node(id);
300                     if let Some(parent_span) = self.tcx.hir().opt_span(parent) {
301                         if parent_span.find_ancestor_inside(expr.span).is_some() {
302                             // The parent node is part of the same span, so is the result of the
303                             // same expansion/desugaring and not the 'real' parent node.
304                             id = parent;
305                             continue;
306                         }
307                     }
308                     break;
309                 }
310
311                 if let Some(hir::Node::Block(&hir::Block {
312                     span: block_span, expr: Some(e), ..
313                 })) = self.tcx.hir().find(parent)
314                 {
315                     if e.hir_id == id {
316                         if let Some(span) = expr.span.find_ancestor_inside(block_span) {
317                             let return_suggestions = if self
318                                 .tcx
319                                 .is_diagnostic_item(sym::Result, expected_adt.did())
320                             {
321                                 vec!["Ok(())"]
322                             } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
323                                 vec!["None", "Some(())"]
324                             } else {
325                                 return;
326                             };
327                             if let Some(indent) =
328                                 self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
329                             {
330                                 // Add a semicolon, except after `}`.
331                                 let semicolon =
332                                     match self.tcx.sess.source_map().span_to_snippet(span) {
333                                         Ok(s) if s.ends_with('}') => "",
334                                         _ => ";",
335                                     };
336                                 err.span_suggestions(
337                                     span.shrink_to_hi(),
338                                     "try adding an expression at the end of the block",
339                                     return_suggestions
340                                         .into_iter()
341                                         .map(|r| format!("{semicolon}\n{indent}{r}")),
342                                     Applicability::MaybeIncorrect,
343                                 );
344                             }
345                             return;
346                         }
347                     }
348                 }
349             }
350
351             let compatible_variants: Vec<String> = expected_adt
352                 .variants()
353                 .iter()
354                 .filter(|variant| {
355                     variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
356                 })
357                 .filter_map(|variant| {
358                     let sole_field = &variant.fields[0];
359
360                     if !sole_field.did.is_local()
361                         && !sole_field
362                             .vis
363                             .is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
364                     {
365                         return None;
366                     }
367
368                     let sole_field_ty = sole_field.ty(self.tcx, substs);
369                     if self.can_coerce(expr_ty, sole_field_ty) {
370                         let variant_path =
371                             with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
372                         // FIXME #56861: DRYer prelude filtering
373                         if let Some(path) = variant_path.strip_prefix("std::prelude::")
374                             && let Some((_, path)) = path.split_once("::")
375                         {
376                             return Some(path.to_string());
377                         }
378                         Some(variant_path)
379                     } else {
380                         None
381                     }
382                 })
383                 .collect();
384
385             let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
386                 Some(ident) => format!("{ident}: "),
387                 None => String::new(),
388             };
389
390             match &compatible_variants[..] {
391                 [] => { /* No variants to format */ }
392                 [variant] => {
393                     // Just a single matching variant.
394                     err.multipart_suggestion_verbose(
395                         &format!("try wrapping the expression in `{variant}`"),
396                         vec![
397                             (expr.span.shrink_to_lo(), format!("{prefix}{variant}(")),
398                             (expr.span.shrink_to_hi(), ")".to_string()),
399                         ],
400                         Applicability::MaybeIncorrect,
401                     );
402                 }
403                 _ => {
404                     // More than one matching variant.
405                     err.multipart_suggestions(
406                         &format!(
407                             "try wrapping the expression in a variant of `{}`",
408                             self.tcx.def_path_str(expected_adt.did())
409                         ),
410                         compatible_variants.into_iter().map(|variant| {
411                             vec![
412                                 (expr.span.shrink_to_lo(), format!("{prefix}{variant}(")),
413                                 (expr.span.shrink_to_hi(), ")".to_string()),
414                             ]
415                         }),
416                         Applicability::MaybeIncorrect,
417                     );
418                 }
419             }
420         }
421     }
422
423     fn suggest_non_zero_new_unwrap(
424         &self,
425         err: &mut Diagnostic,
426         expr: &hir::Expr<'_>,
427         expected: Ty<'tcx>,
428         expr_ty: Ty<'tcx>,
429     ) {
430         let tcx = self.tcx;
431         let (adt, unwrap) = match expected.kind() {
432             // In case Option<NonZero*> is wanted, but * is provided, suggest calling new
433             ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
434                 // Unwrap option
435                 let ty::Adt(adt, _) = substs.type_at(0).kind() else { return };
436
437                 (adt, "")
438             }
439             // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
440             ty::Adt(adt, _) => (adt, ".unwrap()"),
441             _ => return,
442         };
443
444         let map = [
445             (sym::NonZeroU8, tcx.types.u8),
446             (sym::NonZeroU16, tcx.types.u16),
447             (sym::NonZeroU32, tcx.types.u32),
448             (sym::NonZeroU64, tcx.types.u64),
449             (sym::NonZeroU128, tcx.types.u128),
450             (sym::NonZeroI8, tcx.types.i8),
451             (sym::NonZeroI16, tcx.types.i16),
452             (sym::NonZeroI32, tcx.types.i32),
453             (sym::NonZeroI64, tcx.types.i64),
454             (sym::NonZeroI128, tcx.types.i128),
455         ];
456
457         let Some((s, _)) = map
458             .iter()
459             .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
460             else { return };
461
462         let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
463
464         err.multipart_suggestion(
465             format!("consider calling `{s}::new`"),
466             vec![
467                 (expr.span.shrink_to_lo(), format!("{path}::new(")),
468                 (expr.span.shrink_to_hi(), format!("){unwrap}")),
469             ],
470             Applicability::MaybeIncorrect,
471         );
472     }
473
474     pub fn get_conversion_methods(
475         &self,
476         span: Span,
477         expected: Ty<'tcx>,
478         checked_ty: Ty<'tcx>,
479         hir_id: hir::HirId,
480     ) -> Vec<AssocItem> {
481         let mut methods =
482             self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id);
483         methods.retain(|m| {
484             self.has_only_self_parameter(m)
485                 && self
486                     .tcx
487                     // This special internal attribute is used to permit
488                     // "identity-like" conversion methods to be suggested here.
489                     //
490                     // FIXME (#46459 and #46460): ideally
491                     // `std::convert::Into::into` and `std::borrow:ToOwned` would
492                     // also be `#[rustc_conversion_suggestion]`, if not for
493                     // method-probing false-positives and -negatives (respectively).
494                     //
495                     // FIXME? Other potential candidate methods: `as_ref` and
496                     // `as_mut`?
497                     .has_attr(m.def_id, sym::rustc_conversion_suggestion)
498         });
499
500         methods
501     }
502
503     /// This function checks whether the method is not static and does not accept other parameters than `self`.
504     fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
505         match method.kind {
506             ty::AssocKind::Fn => {
507                 method.fn_has_self_parameter
508                     && self.tcx.fn_sig(method.def_id).inputs().skip_binder().len() == 1
509             }
510             _ => false,
511         }
512     }
513
514     /// Identify some cases where `as_ref()` would be appropriate and suggest it.
515     ///
516     /// Given the following code:
517     /// ```compile_fail,E0308
518     /// struct Foo;
519     /// fn takes_ref(_: &Foo) {}
520     /// let ref opt = Some(Foo);
521     ///
522     /// opt.map(|param| takes_ref(param));
523     /// ```
524     /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead.
525     ///
526     /// It only checks for `Option` and `Result` and won't work with
527     /// ```ignore (illustrative)
528     /// opt.map(|param| { takes_ref(param) });
529     /// ```
530     fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, String)> {
531         let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else {
532             return None;
533         };
534
535         let hir::def::Res::Local(local_id) = path.res else {
536             return None;
537         };
538
539         let local_parent = self.tcx.hir().get_parent_node(local_id);
540         let Some(Node::Param(hir::Param { hir_id: param_hir_id, .. })) = self.tcx.hir().find(local_parent) else {
541             return None;
542         };
543
544         let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
545         let Some(Node::Expr(hir::Expr {
546             hir_id: expr_hir_id,
547             kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
548             ..
549         })) = self.tcx.hir().find(param_parent) else {
550             return None;
551         };
552
553         let expr_parent = self.tcx.hir().get_parent_node(*expr_hir_id);
554         let hir = self.tcx.hir().find(expr_parent);
555         let closure_params_len = closure_fn_decl.inputs.len();
556         let (
557             Some(Node::Expr(hir::Expr {
558                 kind: hir::ExprKind::MethodCall(method_path, method_expr, _),
559                 ..
560             })),
561             1,
562         ) = (hir, closure_params_len) else {
563             return None;
564         };
565
566         let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
567         let self_ty = format!("{:?}", self_ty);
568         let name = method_path.ident.name;
569         let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
570             || self_ty.starts_with("&std::result::Result")
571             || self_ty.starts_with("std::option::Option")
572             || self_ty.starts_with("std::result::Result"))
573             && (name == sym::map || name == sym::and_then);
574         match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
575             (true, Ok(src)) => {
576                 let suggestion = format!("as_ref().{}", src);
577                 Some((method_path.ident.span, "consider using `as_ref` instead", suggestion))
578             }
579             _ => None,
580         }
581     }
582
583     pub(crate) fn maybe_get_struct_pattern_shorthand_field(
584         &self,
585         expr: &hir::Expr<'_>,
586     ) -> Option<Symbol> {
587         let hir = self.tcx.hir();
588         let local = match expr {
589             hir::Expr {
590                 kind:
591                     hir::ExprKind::Path(hir::QPath::Resolved(
592                         None,
593                         hir::Path {
594                             res: hir::def::Res::Local(_),
595                             segments: [hir::PathSegment { ident, .. }],
596                             ..
597                         },
598                     )),
599                 ..
600             } => Some(ident),
601             _ => None,
602         }?;
603
604         match hir.find(hir.get_parent_node(expr.hir_id))? {
605             Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) => {
606                 for field in *fields {
607                     if field.ident.name == local.name && field.is_shorthand {
608                         return Some(local.name);
609                     }
610                 }
611             }
612             _ => {}
613         }
614
615         None
616     }
617
618     /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
619     pub(crate) fn maybe_get_block_expr(
620         &self,
621         expr: &hir::Expr<'tcx>,
622     ) -> Option<&'tcx hir::Expr<'tcx>> {
623         match expr {
624             hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
625             _ => None,
626         }
627     }
628
629     /// Returns whether the given expression is an `else if`.
630     pub(crate) fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
631         if let hir::ExprKind::If(..) = expr.kind {
632             let parent_id = self.tcx.hir().get_parent_node(expr.hir_id);
633             if let Some(Node::Expr(hir::Expr {
634                 kind: hir::ExprKind::If(_, _, Some(else_expr)),
635                 ..
636             })) = self.tcx.hir().find(parent_id)
637             {
638                 return else_expr.hir_id == expr.hir_id;
639             }
640         }
641         false
642     }
643
644     /// This function is used to determine potential "simple" improvements or users' errors and
645     /// provide them useful help. For example:
646     ///
647     /// ```compile_fail,E0308
648     /// fn some_fn(s: &str) {}
649     ///
650     /// let x = "hey!".to_owned();
651     /// some_fn(x); // error
652     /// ```
653     ///
654     /// No need to find every potential function which could make a coercion to transform a
655     /// `String` into a `&str` since a `&` would do the trick!
656     ///
657     /// In addition of this check, it also checks between references mutability state. If the
658     /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
659     /// `&mut`!".
660     pub fn check_ref(
661         &self,
662         expr: &hir::Expr<'tcx>,
663         checked_ty: Ty<'tcx>,
664         expected: Ty<'tcx>,
665     ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> {
666         let sess = self.sess();
667         let sp = expr.span;
668
669         // If the span is from an external macro, there's no suggestion we can make.
670         if in_external_macro(sess, sp) {
671             return None;
672         }
673
674         let sm = sess.source_map();
675
676         let replace_prefix = |s: &str, old: &str, new: &str| {
677             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
678         };
679
680         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
681         let expr = expr.peel_drop_temps();
682
683         match (&expr.kind, expected.kind(), checked_ty.kind()) {
684             (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) {
685                 (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
686                     if let hir::ExprKind::Lit(_) = expr.kind
687                         && let Ok(src) = sm.span_to_snippet(sp)
688                         && replace_prefix(&src, "b\"", "\"").is_some()
689                     {
690                                 let pos = sp.lo() + BytePos(1);
691                                 return Some((
692                                     sp.with_hi(pos),
693                                     "consider removing the leading `b`".to_string(),
694                                     String::new(),
695                                     Applicability::MachineApplicable,
696                                     true,
697                                 ));
698                             }
699                         }
700                 (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
701                     if let hir::ExprKind::Lit(_) = expr.kind
702                         && let Ok(src) = sm.span_to_snippet(sp)
703                         && replace_prefix(&src, "\"", "b\"").is_some()
704                     {
705                                 return Some((
706                                     sp.shrink_to_lo(),
707                                     "consider adding a leading `b`".to_string(),
708                                     "b".to_string(),
709                                     Applicability::MachineApplicable,
710                                     true,
711                                 ));
712                     }
713                 }
714                 _ => {}
715             },
716             (_, &ty::Ref(_, _, mutability), _) => {
717                 // Check if it can work when put into a ref. For example:
718                 //
719                 // ```
720                 // fn bar(x: &mut i32) {}
721                 //
722                 // let x = 0u32;
723                 // bar(&x); // error, expected &mut
724                 // ```
725                 let ref_ty = match mutability {
726                     hir::Mutability::Mut => {
727                         self.tcx.mk_mut_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
728                     }
729                     hir::Mutability::Not => {
730                         self.tcx.mk_imm_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
731                     }
732                 };
733                 if self.can_coerce(ref_ty, expected) {
734                     let mut sugg_sp = sp;
735                     if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind {
736                         let clone_trait =
737                             self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
738                         if let ([arg], Some(true), sym::clone) = (
739                             &args[..],
740                             self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
741                                 |did| {
742                                     let ai = self.tcx.associated_item(did);
743                                     ai.container == ty::TraitContainer(clone_trait)
744                                 },
745                             ),
746                             segment.ident.name,
747                         ) {
748                             // If this expression had a clone call when suggesting borrowing
749                             // we want to suggest removing it because it'd now be unnecessary.
750                             sugg_sp = arg.span;
751                         }
752                     }
753                     if let Ok(src) = sm.span_to_snippet(sugg_sp) {
754                         let needs_parens = match expr.kind {
755                             // parenthesize if needed (Issue #46756)
756                             hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
757                             // parenthesize borrows of range literals (Issue #54505)
758                             _ if is_range_literal(expr) => true,
759                             _ => false,
760                         };
761                         let sugg_expr = if needs_parens { format!("({src})") } else { src };
762
763                         if let Some(sugg) = self.can_use_as_ref(expr) {
764                             return Some((
765                                 sugg.0,
766                                 sugg.1.to_string(),
767                                 sugg.2,
768                                 Applicability::MachineApplicable,
769                                 false,
770                             ));
771                         }
772
773                         let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
774                             Some(ident) => format!("{ident}: "),
775                             None => String::new(),
776                         };
777
778                         if let Some(hir::Node::Expr(hir::Expr {
779                             kind: hir::ExprKind::Assign(..),
780                             ..
781                         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
782                         {
783                             if mutability == hir::Mutability::Mut {
784                                 // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
785                                 return None;
786                             }
787                         }
788
789                         return Some(match mutability {
790                             hir::Mutability::Mut => (
791                                 sp,
792                                 "consider mutably borrowing here".to_string(),
793                                 format!("{prefix}&mut {sugg_expr}"),
794                                 Applicability::MachineApplicable,
795                                 false,
796                             ),
797                             hir::Mutability::Not => (
798                                 sp,
799                                 "consider borrowing here".to_string(),
800                                 format!("{prefix}&{sugg_expr}"),
801                                 Applicability::MachineApplicable,
802                                 false,
803                             ),
804                         });
805                     }
806                 }
807             }
808             (
809                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
810                 _,
811                 &ty::Ref(_, checked, _),
812             ) if self.infcx.can_sub(self.param_env, checked, expected).is_ok() => {
813                 // We have `&T`, check if what was expected was `T`. If so,
814                 // we may want to suggest removing a `&`.
815                 if sm.is_imported(expr.span) {
816                     // Go through the spans from which this span was expanded,
817                     // and find the one that's pointing inside `sp`.
818                     //
819                     // E.g. for `&format!("")`, where we want the span to the
820                     // `format!()` invocation instead of its expansion.
821                     if let Some(call_span) =
822                         iter::successors(Some(expr.span), |s| s.parent_callsite())
823                             .find(|&s| sp.contains(s))
824                         && sm.is_span_accessible(call_span)
825                     {
826                         return Some((
827                             sp.with_hi(call_span.lo()),
828                             "consider removing the borrow".to_string(),
829                             String::new(),
830                             Applicability::MachineApplicable,
831                             true,
832                         ));
833                     }
834                     return None;
835                 }
836                 if sp.contains(expr.span)
837                     && sm.is_span_accessible(expr.span)
838                 {
839                     return Some((
840                         sp.with_hi(expr.span.lo()),
841                         "consider removing the borrow".to_string(),
842                         String::new(),
843                         Applicability::MachineApplicable,
844                         true,
845                     ));
846                 }
847             }
848             (
849                 _,
850                 &ty::RawPtr(TypeAndMut { ty: ty_b, mutbl: mutbl_b }),
851                 &ty::Ref(_, ty_a, mutbl_a),
852             ) => {
853                 if let Some(steps) = self.deref_steps(ty_a, ty_b)
854                     // Only suggest valid if dereferencing needed.
855                     && steps > 0
856                     // The pointer type implements `Copy` trait so the suggestion is always valid.
857                     && let Ok(src) = sm.span_to_snippet(sp)
858                 {
859                     let derefs = "*".repeat(steps);
860                     if let Some((span, src, applicability)) = match mutbl_b {
861                         hir::Mutability::Mut => {
862                             let new_prefix = "&mut ".to_owned() + &derefs;
863                             match mutbl_a {
864                                 hir::Mutability::Mut => {
865                                     replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
866                                         let pos = sp.lo() + BytePos(5);
867                                         let sp = sp.with_lo(pos).with_hi(pos);
868                                         (sp, derefs, Applicability::MachineApplicable)
869                                     })
870                                 }
871                                 hir::Mutability::Not => {
872                                     replace_prefix(&src, "&", &new_prefix).map(|_| {
873                                         let pos = sp.lo() + BytePos(1);
874                                         let sp = sp.with_lo(pos).with_hi(pos);
875                                         (
876                                             sp,
877                                             format!("mut {derefs}"),
878                                             Applicability::Unspecified,
879                                         )
880                                     })
881                                 }
882                             }
883                         }
884                         hir::Mutability::Not => {
885                             let new_prefix = "&".to_owned() + &derefs;
886                             match mutbl_a {
887                                 hir::Mutability::Mut => {
888                                     replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
889                                         let lo = sp.lo() + BytePos(1);
890                                         let hi = sp.lo() + BytePos(5);
891                                         let sp = sp.with_lo(lo).with_hi(hi);
892                                         (sp, derefs, Applicability::MachineApplicable)
893                                     })
894                                 }
895                                 hir::Mutability::Not => {
896                                     replace_prefix(&src, "&", &new_prefix).map(|_| {
897                                         let pos = sp.lo() + BytePos(1);
898                                         let sp = sp.with_lo(pos).with_hi(pos);
899                                         (sp, derefs, Applicability::MachineApplicable)
900                                     })
901                                 }
902                             }
903                         }
904                     } {
905                         return Some((
906                             span,
907                             "consider dereferencing".to_string(),
908                             src,
909                             applicability,
910                             true,
911                         ));
912                     }
913                 }
914             }
915             _ if sp == expr.span => {
916                 if let Some(mut steps) = self.deref_steps(checked_ty, expected) {
917                     let mut expr = expr.peel_blocks();
918                     let mut prefix_span = expr.span.shrink_to_lo();
919                     let mut remove = String::new();
920
921                     // Try peeling off any existing `&` and `&mut` to reach our target type
922                     while steps > 0 {
923                         if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind {
924                             // If the expression has `&`, removing it would fix the error
925                             prefix_span = prefix_span.with_hi(inner.span.lo());
926                             expr = inner;
927                             remove += match mutbl {
928                                 hir::Mutability::Not => "&",
929                                 hir::Mutability::Mut => "&mut ",
930                             };
931                             steps -= 1;
932                         } else {
933                             break;
934                         }
935                     }
936                     // If we've reached our target type with just removing `&`, then just print now.
937                     if steps == 0 {
938                         return Some((
939                             prefix_span,
940                             format!("consider removing the `{}`", remove.trim()),
941                             String::new(),
942                             // Do not remove `&&` to get to bool, because it might be something like
943                             // { a } && b, which we have a separate fixup suggestion that is more
944                             // likely correct...
945                             if remove.trim() == "&&" && expected == self.tcx.types.bool {
946                                 Applicability::MaybeIncorrect
947                             } else {
948                                 Applicability::MachineApplicable
949                             },
950                             true,
951                         ));
952                     }
953
954                     // For this suggestion to make sense, the type would need to be `Copy`,
955                     // or we have to be moving out of a `Box<T>`
956                     if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
957                         // FIXME(compiler-errors): We can actually do this if the checked_ty is
958                         // `steps` layers of boxes, not just one, but this is easier and most likely.
959                         || (checked_ty.is_box() && steps == 1)
960                     {
961                         let deref_kind = if checked_ty.is_box() {
962                             "unboxing the value"
963                         } else if checked_ty.is_region_ptr() {
964                             "dereferencing the borrow"
965                         } else {
966                             "dereferencing the type"
967                         };
968
969                         // Suggest removing `&` if we have removed any, otherwise suggest just
970                         // dereferencing the remaining number of steps.
971                         let message = if remove.is_empty() {
972                             format!("consider {deref_kind}")
973                         } else {
974                             format!(
975                                 "consider removing the `{}` and {} instead",
976                                 remove.trim(),
977                                 deref_kind
978                             )
979                         };
980
981                         let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
982                             Some(ident) => format!("{ident}: "),
983                             None => String::new(),
984                         };
985
986                         let (span, suggestion) = if self.is_else_if_block(expr) {
987                             // Don't suggest nonsense like `else *if`
988                             return None;
989                         } else if let Some(expr) = self.maybe_get_block_expr(expr) {
990                             // prefix should be empty here..
991                             (expr.span.shrink_to_lo(), "*".to_string())
992                         } else {
993                             (prefix_span, format!("{}{}", prefix, "*".repeat(steps)))
994                         };
995
996                         return Some((
997                             span,
998                             message,
999                             suggestion,
1000                             Applicability::MachineApplicable,
1001                             true,
1002                         ));
1003                     }
1004                 }
1005             }
1006             _ => {}
1007         }
1008         None
1009     }
1010
1011     pub fn check_for_cast(
1012         &self,
1013         err: &mut Diagnostic,
1014         expr: &hir::Expr<'_>,
1015         checked_ty: Ty<'tcx>,
1016         expected_ty: Ty<'tcx>,
1017         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
1018     ) -> bool {
1019         if self.tcx.sess.source_map().is_imported(expr.span) {
1020             // Ignore if span is from within a macro.
1021             return false;
1022         }
1023
1024         let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else {
1025             return false;
1026         };
1027
1028         // If casting this expression to a given numeric type would be appropriate in case of a type
1029         // mismatch.
1030         //
1031         // We want to minimize the amount of casting operations that are suggested, as it can be a
1032         // lossy operation with potentially bad side effects, so we only suggest when encountering
1033         // an expression that indicates that the original type couldn't be directly changed.
1034         //
1035         // For now, don't suggest casting with `as`.
1036         let can_cast = false;
1037
1038         let mut sugg = vec![];
1039
1040         if let Some(hir::Node::Expr(hir::Expr {
1041             kind: hir::ExprKind::Struct(_, fields, _), ..
1042         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
1043         {
1044             // `expr` is a literal field for a struct, only suggest if appropriate
1045             match (*fields)
1046                 .iter()
1047                 .find(|field| field.expr.hir_id == expr.hir_id && field.is_shorthand)
1048             {
1049                 // This is a field literal
1050                 Some(field) => {
1051                     sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident)));
1052                 }
1053                 // Likely a field was meant, but this field wasn't found. Do not suggest anything.
1054                 None => return false,
1055             }
1056         };
1057
1058         if let hir::ExprKind::Call(path, args) = &expr.kind
1059             && let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
1060                 (&path.kind, args.len())
1061             // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697).
1062             && let (hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), sym::from) =
1063                 (&base_ty.kind, path_segment.ident.name)
1064         {
1065             if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() {
1066                 match ident.name {
1067                     sym::i128
1068                     | sym::i64
1069                     | sym::i32
1070                     | sym::i16
1071                     | sym::i8
1072                     | sym::u128
1073                     | sym::u64
1074                     | sym::u32
1075                     | sym::u16
1076                     | sym::u8
1077                     | sym::isize
1078                     | sym::usize
1079                         if base_ty_path.segments.len() == 1 =>
1080                     {
1081                         return false;
1082                     }
1083                     _ => {}
1084                 }
1085             }
1086         }
1087
1088         let msg = format!(
1089             "you can convert {} `{}` to {} `{}`",
1090             checked_ty.kind().article(),
1091             checked_ty,
1092             expected_ty.kind().article(),
1093             expected_ty,
1094         );
1095         let cast_msg = format!(
1096             "you can cast {} `{}` to {} `{}`",
1097             checked_ty.kind().article(),
1098             checked_ty,
1099             expected_ty.kind().article(),
1100             expected_ty,
1101         );
1102         let lit_msg = format!(
1103             "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
1104         );
1105
1106         let close_paren = if expr.precedence().order() < PREC_POSTFIX {
1107             sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
1108             ")"
1109         } else {
1110             ""
1111         };
1112
1113         let mut cast_suggestion = sugg.clone();
1114         cast_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren} as {expected_ty}")));
1115         let mut into_suggestion = sugg.clone();
1116         into_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren}.into()")));
1117         let mut suffix_suggestion = sugg.clone();
1118         suffix_suggestion.push((
1119             if matches!(
1120                 (&expected_ty.kind(), &checked_ty.kind()),
1121                 (ty::Int(_) | ty::Uint(_), ty::Float(_))
1122             ) {
1123                 // Remove fractional part from literal, for example `42.0f32` into `42`
1124                 let src = src.trim_end_matches(&checked_ty.to_string());
1125                 let len = src.split('.').next().unwrap().len();
1126                 expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
1127             } else {
1128                 let len = src.trim_end_matches(&checked_ty.to_string()).len();
1129                 expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
1130             },
1131             if expr.precedence().order() < PREC_POSTFIX {
1132                 // Readd `)`
1133                 format!("{expected_ty})")
1134             } else {
1135                 expected_ty.to_string()
1136             },
1137         ));
1138         let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
1139             if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
1140         };
1141         let is_negative_int =
1142             |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Neg, ..));
1143         let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..));
1144
1145         let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
1146
1147         let suggest_fallible_into_or_lhs_from =
1148             |err: &mut Diagnostic, exp_to_found_is_fallible: bool| {
1149                 // If we know the expression the expected type is derived from, we might be able
1150                 // to suggest a widening conversion rather than a narrowing one (which may
1151                 // panic). For example, given x: u8 and y: u32, if we know the span of "x",
1152                 //   x > y
1153                 // can be given the suggestion "u32::from(x) > y" rather than
1154                 // "x > y.try_into().unwrap()".
1155                 let lhs_expr_and_src = expected_ty_expr.and_then(|expr| {
1156                     self.tcx
1157                         .sess
1158                         .source_map()
1159                         .span_to_snippet(expr.span)
1160                         .ok()
1161                         .map(|src| (expr, src))
1162                 });
1163                 let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
1164                     (lhs_expr_and_src, exp_to_found_is_fallible)
1165                 {
1166                     let msg = format!(
1167                         "you can convert `{lhs_src}` from `{expected_ty}` to `{checked_ty}`, matching the type of `{src}`",
1168                     );
1169                     let suggestion = vec![
1170                         (lhs_expr.span.shrink_to_lo(), format!("{checked_ty}::from(")),
1171                         (lhs_expr.span.shrink_to_hi(), ")".to_string()),
1172                     ];
1173                     (msg, suggestion)
1174                 } else {
1175                     let msg = format!("{msg} and panic if the converted value doesn't fit");
1176                     let mut suggestion = sugg.clone();
1177                     suggestion.push((
1178                         expr.span.shrink_to_hi(),
1179                         format!("{close_paren}.try_into().unwrap()"),
1180                     ));
1181                     (msg, suggestion)
1182                 };
1183                 err.multipart_suggestion_verbose(
1184                     &msg,
1185                     suggestion,
1186                     Applicability::MachineApplicable,
1187                 );
1188             };
1189
1190         let suggest_to_change_suffix_or_into =
1191             |err: &mut Diagnostic,
1192              found_to_exp_is_fallible: bool,
1193              exp_to_found_is_fallible: bool| {
1194                 let exp_is_lhs =
1195                     expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false);
1196
1197                 if exp_is_lhs {
1198                     return;
1199                 }
1200
1201                 let always_fallible = found_to_exp_is_fallible
1202                     && (exp_to_found_is_fallible || expected_ty_expr.is_none());
1203                 let msg = if literal_is_ty_suffixed(expr) {
1204                     &lit_msg
1205                 } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
1206                     // We now know that converting either the lhs or rhs is fallible. Before we
1207                     // suggest a fallible conversion, check if the value can never fit in the
1208                     // expected type.
1209                     let msg = format!("`{src}` cannot fit into type `{expected_ty}`");
1210                     err.note(&msg);
1211                     return;
1212                 } else if in_const_context {
1213                     // Do not recommend `into` or `try_into` in const contexts.
1214                     return;
1215                 } else if found_to_exp_is_fallible {
1216                     return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible);
1217                 } else {
1218                     &msg
1219                 };
1220                 let suggestion = if literal_is_ty_suffixed(expr) {
1221                     suffix_suggestion.clone()
1222                 } else {
1223                     into_suggestion.clone()
1224                 };
1225                 err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
1226             };
1227
1228         match (&expected_ty.kind(), &checked_ty.kind()) {
1229             (&ty::Int(ref exp), &ty::Int(ref found)) => {
1230                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1231                 {
1232                     (Some(exp), Some(found)) if exp < found => (true, false),
1233                     (Some(exp), Some(found)) if exp > found => (false, true),
1234                     (None, Some(8 | 16)) => (false, true),
1235                     (Some(8 | 16), None) => (true, false),
1236                     (None, _) | (_, None) => (true, true),
1237                     _ => (false, false),
1238                 };
1239                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1240                 true
1241             }
1242             (&ty::Uint(ref exp), &ty::Uint(ref found)) => {
1243                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1244                 {
1245                     (Some(exp), Some(found)) if exp < found => (true, false),
1246                     (Some(exp), Some(found)) if exp > found => (false, true),
1247                     (None, Some(8 | 16)) => (false, true),
1248                     (Some(8 | 16), None) => (true, false),
1249                     (None, _) | (_, None) => (true, true),
1250                     _ => (false, false),
1251                 };
1252                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1253                 true
1254             }
1255             (&ty::Int(exp), &ty::Uint(found)) => {
1256                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1257                 {
1258                     (Some(exp), Some(found)) if found < exp => (false, true),
1259                     (None, Some(8)) => (false, true),
1260                     _ => (true, true),
1261                 };
1262                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1263                 true
1264             }
1265             (&ty::Uint(exp), &ty::Int(found)) => {
1266                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1267                 {
1268                     (Some(exp), Some(found)) if found > exp => (true, false),
1269                     (Some(8), None) => (true, false),
1270                     _ => (true, true),
1271                 };
1272                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1273                 true
1274             }
1275             (&ty::Float(ref exp), &ty::Float(ref found)) => {
1276                 if found.bit_width() < exp.bit_width() {
1277                     suggest_to_change_suffix_or_into(err, false, true);
1278                 } else if literal_is_ty_suffixed(expr) {
1279                     err.multipart_suggestion_verbose(
1280                         &lit_msg,
1281                         suffix_suggestion,
1282                         Applicability::MachineApplicable,
1283                     );
1284                 } else if can_cast {
1285                     // Missing try_into implementation for `f64` to `f32`
1286                     err.multipart_suggestion_verbose(
1287                         &format!("{cast_msg}, producing the closest possible value"),
1288                         cast_suggestion,
1289                         Applicability::MaybeIncorrect, // lossy conversion
1290                     );
1291                 }
1292                 true
1293             }
1294             (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
1295                 if literal_is_ty_suffixed(expr) {
1296                     err.multipart_suggestion_verbose(
1297                         &lit_msg,
1298                         suffix_suggestion,
1299                         Applicability::MachineApplicable,
1300                     );
1301                 } else if can_cast {
1302                     // Missing try_into implementation for `{float}` to `{integer}`
1303                     err.multipart_suggestion_verbose(
1304                         &format!("{msg}, rounding the float towards zero"),
1305                         cast_suggestion,
1306                         Applicability::MaybeIncorrect, // lossy conversion
1307                     );
1308                 }
1309                 true
1310             }
1311             (&ty::Float(ref exp), &ty::Uint(ref found)) => {
1312                 // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
1313                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
1314                     err.multipart_suggestion_verbose(
1315                         &format!(
1316                             "{msg}, producing the floating point representation of the integer",
1317                         ),
1318                         into_suggestion,
1319                         Applicability::MachineApplicable,
1320                     );
1321                 } else if literal_is_ty_suffixed(expr) {
1322                     err.multipart_suggestion_verbose(
1323                         &lit_msg,
1324                         suffix_suggestion,
1325                         Applicability::MachineApplicable,
1326                     );
1327                 } else {
1328                     // Missing try_into implementation for `{integer}` to `{float}`
1329                     err.multipart_suggestion_verbose(
1330                         &format!(
1331                             "{cast_msg}, producing the floating point representation of the integer, \
1332                                  rounded if necessary",
1333                         ),
1334                         cast_suggestion,
1335                         Applicability::MaybeIncorrect, // lossy conversion
1336                     );
1337                 }
1338                 true
1339             }
1340             (&ty::Float(ref exp), &ty::Int(ref found)) => {
1341                 // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
1342                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
1343                     err.multipart_suggestion_verbose(
1344                         &format!(
1345                             "{}, producing the floating point representation of the integer",
1346                             &msg,
1347                         ),
1348                         into_suggestion,
1349                         Applicability::MachineApplicable,
1350                     );
1351                 } else if literal_is_ty_suffixed(expr) {
1352                     err.multipart_suggestion_verbose(
1353                         &lit_msg,
1354                         suffix_suggestion,
1355                         Applicability::MachineApplicable,
1356                     );
1357                 } else {
1358                     // Missing try_into implementation for `{integer}` to `{float}`
1359                     err.multipart_suggestion_verbose(
1360                         &format!(
1361                             "{}, producing the floating point representation of the integer, \
1362                                 rounded if necessary",
1363                             &msg,
1364                         ),
1365                         cast_suggestion,
1366                         Applicability::MaybeIncorrect, // lossy conversion
1367                     );
1368                 }
1369                 true
1370             }
1371             (
1372                 &ty::Uint(ty::UintTy::U32 | ty::UintTy::U64 | ty::UintTy::U128)
1373                 | &ty::Int(ty::IntTy::I32 | ty::IntTy::I64 | ty::IntTy::I128),
1374                 &ty::Char,
1375             ) => {
1376                 err.multipart_suggestion_verbose(
1377                     &format!("{cast_msg}, since a `char` always occupies 4 bytes"),
1378                     cast_suggestion,
1379                     Applicability::MachineApplicable,
1380                 );
1381                 true
1382             }
1383             _ => false,
1384         }
1385     }
1386
1387     // Report the type inferred by the return statement.
1388     fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) {
1389         if let Some(sp) = self.ret_coercion_span.get()
1390             // If the closure has an explicit return type annotation, or if
1391             // the closure's return type has been inferred from outside
1392             // requirements (such as an Fn* trait bound), then a type error
1393             // may occur at the first return expression we see in the closure
1394             // (if it conflicts with the declared return type). Skip adding a
1395             // note in this case, since it would be incorrect.
1396             && !self.return_type_pre_known
1397         {
1398             err.span_note(
1399                 sp,
1400                 &format!(
1401                     "return type inferred to be `{}` here",
1402                     self.resolve_vars_if_possible(expected)
1403                 ),
1404             );
1405         }
1406     }
1407 }