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