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