Skip to main content

rustc_hir_typeck/fn_ctxt/
suggestions.rs

1// ignore-tidy-filelength
2use core::cmp::min;
3use core::iter;
4
5use hir::def_id::LocalDefId;
6use rustc_ast::util::parser::ExprPrecedence;
7use rustc_data_structures::packed::Pu128;
8use rustc_errors::{Applicability, Diag, MultiSpan, listify, msg};
9use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
10use rustc_hir::intravisit::Visitor;
11use rustc_hir::lang_items::LangItem;
12use rustc_hir::{
13    self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
14    GenericBound, HirId, LoopSource, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind,
15    TyKind, WherePredicateKind, expr_needs_parens, is_range_literal,
16};
17use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
18use rustc_hir_analysis::suggest_impl_trait;
19use rustc_middle::middle::stability::EvalResult;
20use rustc_middle::span_bug;
21use rustc_middle::ty::print::with_no_trimmed_paths;
22use rustc_middle::ty::{
23    self, Article, Binder, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Unnormalized, Upcast,
24    suggest_constraining_type_params,
25};
26use rustc_session::errors::ExprParenthesesNeeded;
27use rustc_span::{ExpnKind, Ident, MacroKind, Span, Spanned, Symbol, sym};
28use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
29use rustc_trait_selection::error_reporting::traits::DefIdOrName;
30use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
31use rustc_trait_selection::infer::InferCtxtExt;
32use rustc_trait_selection::traits;
33use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
34use tracing::{debug, instrument};
35
36use super::FnCtxt;
37use crate::errors::{self, SuggestBoxingForReturnImplTrait};
38use crate::fn_ctxt::rustc_span::BytePos;
39use crate::method::probe;
40use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
41
42impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
43    pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
44        self.typeck_results
45            .borrow()
46            .liberated_fn_sigs()
47            .get(self.tcx.local_def_id_to_hir_id(self.body_id))
48            .copied()
49    }
50
51    pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diag<'_>) {
52        // This suggestion is incorrect for
53        // fn foo() -> bool { match () { () => true } || match () { () => true } }
54        err.span_suggestion_short(
55            span.shrink_to_hi(),
56            "consider using a semicolon here",
57            ";",
58            Applicability::MaybeIncorrect,
59        );
60    }
61
62    /// On implicit return expressions with mismatched types, provides the following suggestions:
63    ///
64    /// - Points out the method's return type as the reason for the expected type.
65    /// - Possible missing semicolon.
66    /// - Possible missing return type if the return type is the default, and not `fn main()`.
67    pub(crate) fn suggest_mismatched_types_on_tail(
68        &self,
69        err: &mut Diag<'_>,
70        expr: &'tcx hir::Expr<'tcx>,
71        expected: Ty<'tcx>,
72        found: Ty<'tcx>,
73        blk_id: HirId,
74    ) -> bool {
75        let expr = expr.peel_drop_temps();
76        let mut pointing_at_return_type = false;
77        if let hir::ExprKind::Break(..) = expr.kind {
78            // `break` type mismatches provide better context for tail `loop` expressions.
79            return false;
80        }
81        if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) {
82            pointing_at_return_type =
83                self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id);
84            self.suggest_missing_break_or_return_expr(
85                err, expr, fn_decl, expected, found, blk_id, fn_id,
86            );
87        }
88        pointing_at_return_type
89    }
90
91    /// When encountering an fn-like type, try accessing the output of the type
92    /// and suggesting calling it if it satisfies a predicate (i.e. if the
93    /// output has a method or a field):
94    /// ```compile_fail,E0308
95    /// fn foo(x: usize) -> usize { x }
96    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
97    /// ```
98    pub(crate) fn suggest_fn_call(
99        &self,
100        err: &mut Diag<'_>,
101        expr: &hir::Expr<'_>,
102        found: Ty<'tcx>,
103        can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
104    ) -> bool {
105        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found) else {
106            return false;
107        };
108        if can_satisfy(output) {
109            let (sugg_call, mut applicability) = match inputs.len() {
110                0 => ("".to_string(), Applicability::MachineApplicable),
111                1..=4 => (
112                    inputs
113                        .iter()
114                        .map(|ty| {
115                            if ty.is_suggestable(self.tcx, false) {
116                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("/* {0} */", ty))
    })format!("/* {ty} */")
117                            } else {
118                                "/* value */".to_string()
119                            }
120                        })
121                        .collect::<Vec<_>>()
122                        .join(", "),
123                    Applicability::HasPlaceholders,
124                ),
125                _ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
126            };
127
128            let msg = match def_id_or_name {
129                DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
130                    DefKind::Ctor(CtorOf::Struct, _) => "construct this tuple struct".to_string(),
131                    DefKind::Ctor(CtorOf::Variant, _) => "construct this tuple variant".to_string(),
132                    kind => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("call this {0}",
                self.tcx.def_kind_descr(kind, def_id)))
    })format!("call this {}", self.tcx.def_kind_descr(kind, def_id)),
133                },
134                DefIdOrName::Name(name) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("call this {0}", name))
    })format!("call this {name}"),
135            };
136
137            let sugg = match expr.kind {
138                hir::ExprKind::Call(..)
139                | hir::ExprKind::Path(..)
140                | hir::ExprKind::Index(..)
141                | hir::ExprKind::Lit(..) => {
142                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_hi(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("({0})", sugg_call))
                        }))]))vec![(expr.span.shrink_to_hi(), format!("({sugg_call})"))]
143                }
144                hir::ExprKind::Closure { .. } => {
145                    // Might be `{ expr } || { bool }`
146                    applicability = Applicability::MaybeIncorrect;
147                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(), "(".to_string()),
                (expr.span.shrink_to_hi(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!(")({0})", sugg_call))
                        }))]))vec![
148                        (expr.span.shrink_to_lo(), "(".to_string()),
149                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
150                    ]
151                }
152                _ => {
153                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(), "(".to_string()),
                (expr.span.shrink_to_hi(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!(")({0})", sugg_call))
                        }))]))vec![
154                        (expr.span.shrink_to_lo(), "(".to_string()),
155                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
156                    ]
157                }
158            };
159
160            err.multipart_suggestion(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("use parentheses to {0}", msg))
    })format!("use parentheses to {msg}"), sugg, applicability);
161            return true;
162        }
163        false
164    }
165
166    /// Extracts information about a callable type for diagnostics. This is a
167    /// heuristic -- it doesn't necessarily mean that a type is always callable,
168    /// because the callable type must also be well-formed to be called.
169    pub(in super::super) fn extract_callable_info(
170        &self,
171        ty: Ty<'tcx>,
172    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
173        self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
174    }
175
176    pub(crate) fn suggest_two_fn_call(
177        &self,
178        err: &mut Diag<'_>,
179        lhs_expr: &'tcx hir::Expr<'tcx>,
180        lhs_ty: Ty<'tcx>,
181        rhs_expr: &'tcx hir::Expr<'tcx>,
182        rhs_ty: Ty<'tcx>,
183        can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
184    ) -> bool {
185        if lhs_expr.span.in_derive_expansion() || rhs_expr.span.in_derive_expansion() {
186            return false;
187        }
188        let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) else {
189            return false;
190        };
191        let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty) else {
192            return false;
193        };
194
195        if can_satisfy(lhs_output_ty, rhs_output_ty) {
196            let mut sugg = ::alloc::vec::Vec::new()vec![];
197            let mut applicability = Applicability::MachineApplicable;
198
199            for (expr, inputs) in [(lhs_expr, lhs_inputs), (rhs_expr, rhs_inputs)] {
200                let (sugg_call, this_applicability) = match inputs.len() {
201                    0 => ("".to_string(), Applicability::MachineApplicable),
202                    1..=4 => (
203                        inputs
204                            .iter()
205                            .map(|ty| {
206                                if ty.is_suggestable(self.tcx, false) {
207                                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("/* {0} */", ty))
    })format!("/* {ty} */")
208                                } else {
209                                    "/* value */".to_string()
210                                }
211                            })
212                            .collect::<Vec<_>>()
213                            .join(", "),
214                        Applicability::HasPlaceholders,
215                    ),
216                    _ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
217                };
218
219                applicability = applicability.max(this_applicability);
220
221                match expr.kind {
222                    hir::ExprKind::Call(..)
223                    | hir::ExprKind::Path(..)
224                    | hir::ExprKind::Index(..)
225                    | hir::ExprKind::Lit(..) => {
226                        sugg.extend([(expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("({0})", sugg_call))
    })format!("({sugg_call})"))]);
227                    }
228                    hir::ExprKind::Closure { .. } => {
229                        // Might be `{ expr } || { bool }`
230                        applicability = Applicability::MaybeIncorrect;
231                        sugg.extend([
232                            (expr.span.shrink_to_lo(), "(".to_string()),
233                            (expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(")({0})", sugg_call))
    })format!(")({sugg_call})")),
234                        ]);
235                    }
236                    _ => {
237                        sugg.extend([
238                            (expr.span.shrink_to_lo(), "(".to_string()),
239                            (expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(")({0})", sugg_call))
    })format!(")({sugg_call})")),
240                        ]);
241                    }
242                }
243            }
244
245            err.multipart_suggestion("use parentheses to call these", sugg, applicability);
246
247            true
248        } else {
249            false
250        }
251    }
252
253    pub(crate) fn suggest_remove_last_method_call(
254        &self,
255        err: &mut Diag<'_>,
256        expr: &hir::Expr<'tcx>,
257        expected: Ty<'tcx>,
258    ) -> bool {
259        if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) =
260            expr.kind
261            && let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
262            && self.may_coerce(recv_ty, expected)
263            && let name = method.name.as_str()
264            && (name.starts_with("to_") || name.starts_with("as_") || name == "into")
265        {
266            let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) {
267                expr.span.with_lo(recv_span.hi())
268            } else {
269                expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1))
270            };
271            err.span_suggestion_verbose(
272                span,
273                "try removing the method call",
274                "",
275                Applicability::MachineApplicable,
276            );
277            return true;
278        }
279        false
280    }
281
282    pub(crate) fn suggest_deref_ref_or_into(
283        &self,
284        err: &mut Diag<'_>,
285        expr: &hir::Expr<'tcx>,
286        expected: Ty<'tcx>,
287        found: Ty<'tcx>,
288        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
289    ) -> bool {
290        let expr = expr.peel_blocks();
291        let methods =
292            self.get_conversion_methods_for_diagnostic(expr.span, expected, found, expr.hir_id);
293
294        if let Some((suggestion, msg, applicability, verbose, annotation)) =
295            self.suggest_deref_or_ref(expr, found, expected)
296        {
297            if verbose {
298                err.multipart_suggestion(msg, suggestion, applicability);
299            } else {
300                err.multipart_suggestion(msg, suggestion, applicability);
301            }
302            if annotation {
303                let suggest_annotation = match expr.peel_drop_temps().kind {
304                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, _) => mutbl.ref_prefix_str(),
305                    _ => return true,
306                };
307                let mut tuple_indexes = Vec::new();
308                let mut expr_id = expr.hir_id;
309                for (parent_id, node) in self.tcx.hir_parent_iter(expr.hir_id) {
310                    match node {
311                        Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => {
312                            tuple_indexes.push(
313                                subs.iter()
314                                    .enumerate()
315                                    .find(|(_, sub_expr)| sub_expr.hir_id == expr_id)
316                                    .unwrap()
317                                    .0,
318                            );
319                            expr_id = parent_id;
320                        }
321                        Node::LetStmt(local) => {
322                            if let Some(mut ty) = local.ty {
323                                while let Some(index) = tuple_indexes.pop() {
324                                    match ty.kind {
325                                        TyKind::Tup(tys) => ty = &tys[index],
326                                        _ => return true,
327                                    }
328                                }
329                                let annotation_span = ty.span;
330                                err.span_suggestion(
331                                    annotation_span.with_hi(annotation_span.lo()),
332                                    "alternatively, consider changing the type annotation",
333                                    suggest_annotation,
334                                    Applicability::MaybeIncorrect,
335                                );
336                            }
337                            break;
338                        }
339                        _ => break,
340                    }
341                }
342            }
343            return true;
344        }
345
346        if self.suggest_else_fn_with_closure(err, expr, found, expected) {
347            return true;
348        }
349
350        if self.suggest_fn_call(err, expr, found, |output| self.may_coerce(output, expected))
351            && let ty::FnDef(def_id, ..) = *found.kind()
352            && let Some(sp) = self.tcx.hir_span_if_local(def_id)
353        {
354            let name = self.tcx.item_name(def_id);
355            let kind = self.tcx.def_kind(def_id);
356            if let DefKind::Ctor(of, CtorKind::Fn) = kind {
357                err.span_label(
358                    sp,
359                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{1}` defines {0} constructor here, which should be called",
                match of {
                    CtorOf::Struct => "a struct",
                    CtorOf::Variant => "an enum variant",
                }, name))
    })format!(
360                        "`{name}` defines {} constructor here, which should be called",
361                        match of {
362                            CtorOf::Struct => "a struct",
363                            CtorOf::Variant => "an enum variant",
364                        }
365                    ),
366                );
367            } else {
368                let descr = self.tcx.def_kind_descr(kind, def_id);
369                err.span_label(sp, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} `{1}` defined here", descr,
                name))
    })format!("{descr} `{name}` defined here"));
370            }
371            return true;
372        }
373
374        if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
375            return true;
376        }
377
378        if !methods.is_empty() {
379            let mut suggestions = methods
380                .iter()
381                .filter_map(|conversion_method| {
382                    let conversion_method_name = conversion_method.name();
383                    let receiver_method_ident = expr.method_ident();
384                    if let Some(method_ident) = receiver_method_ident
385                        && method_ident.name == conversion_method_name
386                    {
387                        return None; // do not suggest code that is already there (#53348)
388                    }
389
390                    let method_call_list = [sym::to_vec, sym::to_string];
391                    let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
392                        && receiver_method.ident.name == sym::clone
393                        && method_call_list.contains(&conversion_method_name)
394                    // If receiver is `.clone()` and found type has one of those methods,
395                    // we guess that the user wants to convert from a slice type (`&[]` or `&str`)
396                    // to an owned type (`Vec` or `String`). These conversions clone internally,
397                    // so we remove the user's `clone` call.
398                    {
399                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(receiver_method.ident.span, conversion_method_name.to_string())]))vec![(receiver_method.ident.span, conversion_method_name.to_string())]
400                    } else if self.precedence(expr) < ExprPrecedence::Unambiguous {
401                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(), "(".to_string()),
                (expr.span.shrink_to_hi(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!(").{0}()",
                                    conversion_method_name))
                        }))]))vec![
402                            (expr.span.shrink_to_lo(), "(".to_string()),
403                            (expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)),
404                        ]
405                    } else {
406                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_hi(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!(".{0}()",
                                    conversion_method_name))
                        }))]))vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method_name))]
407                    };
408                    let struct_pat_shorthand_field =
409                        self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr);
410                    if let Some(name) = struct_pat_shorthand_field {
411                        sugg.insert(0, (expr.span.shrink_to_lo(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", name))
    })format!("{name}: ")));
412                    }
413                    Some(sugg)
414                })
415                .peekable();
416            if suggestions.peek().is_some() {
417                err.multipart_suggestions(
418                    "try using a conversion method",
419                    suggestions,
420                    Applicability::MaybeIncorrect,
421                );
422                return true;
423            }
424        }
425
426        if let Some((found_ty_inner, expected_ty_inner, error_tys)) =
427            self.deconstruct_option_or_result(found, expected)
428            && let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind()
429        {
430            // Suggest removing any stray borrows (unless there's macro shenanigans involved).
431            let inner_expr = expr.peel_borrows();
432            if !inner_expr.span.eq_ctxt(expr.span) {
433                return false;
434            }
435            let borrow_removal_span = if inner_expr.hir_id == expr.hir_id {
436                None
437            } else {
438                Some(expr.span.shrink_to_lo().until(inner_expr.span))
439            };
440            // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
441            // `as_ref` and `as_deref` compatibility.
442            let error_tys_equate_as_ref = error_tys.is_none_or(|(found, expected)| {
443                self.can_eq(
444                    self.param_env,
445                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, found),
446                    expected,
447                )
448            });
449
450            let prefix_wrap = |sugg: &str| {
451                if let Some(name) = self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
452                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}{1}", name, sugg))
    })format!(": {}{}", name, sugg)
453                } else {
454                    sugg.to_string()
455                }
456            };
457
458            // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
459            // but those checks need to be a bit more delicate and the benefit is diminishing.
460            if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
461                let sugg = prefix_wrap(".as_ref()");
462                err.subdiagnostic(errors::SuggestConvertViaMethod {
463                    span: expr.span.shrink_to_hi(),
464                    sugg,
465                    expected,
466                    found,
467                    borrow_removal_span,
468                });
469                return true;
470            } else if let ty::Ref(_, peeled_found_ty, _) = found_ty_inner.kind()
471                && let ty::Adt(adt, _) = peeled_found_ty.peel_refs().kind()
472                && self.tcx.is_lang_item(adt.did(), LangItem::String)
473                && peeled.is_str()
474                // `Result::map`, conversely, does not take ref of the error type.
475                && error_tys.is_none_or(|(found, expected)| {
476                    self.can_eq(self.param_env, found, expected)
477                })
478            {
479                let sugg = prefix_wrap(".map(|x| x.as_str())");
480                err.span_suggestion_verbose(
481                    expr.span.shrink_to_hi(),
482                    rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("try converting the passed type into a `&str`"))msg!("try converting the passed type into a `&str`"),
483                    sugg,
484                    Applicability::MachineApplicable,
485                );
486                return true;
487            } else {
488                if !error_tys_equate_as_ref {
489                    return false;
490                }
491                let mut steps = self.autoderef(expr.span, found_ty_inner).silence_errors();
492                if let Some((deref_ty, _)) = steps.nth(1)
493                    && self.can_eq(self.param_env, deref_ty, peeled)
494                {
495                    let sugg = prefix_wrap(".as_deref()");
496                    err.subdiagnostic(errors::SuggestConvertViaMethod {
497                        span: expr.span.shrink_to_hi(),
498                        sugg,
499                        expected,
500                        found,
501                        borrow_removal_span,
502                    });
503                    return true;
504                }
505                for (deref_ty, n_step) in steps {
506                    if self.can_eq(self.param_env, deref_ty, peeled) {
507                        let explicit_deref = "*".repeat(n_step);
508                        let sugg = prefix_wrap(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".map(|v| &{0}v)", explicit_deref))
    })format!(".map(|v| &{explicit_deref}v)"));
509                        err.subdiagnostic(errors::SuggestConvertViaMethod {
510                            span: expr.span.shrink_to_hi(),
511                            sugg,
512                            expected,
513                            found,
514                            borrow_removal_span,
515                        });
516                        return true;
517                    }
518                }
519            }
520        }
521
522        false
523    }
524
525    /// If `ty` is `Option<T>`, returns `T, T, None`.
526    /// If `ty` is `Result<T, E>`, returns `T, T, Some(E, E)`.
527    /// Otherwise, returns `None`.
528    fn deconstruct_option_or_result(
529        &self,
530        found_ty: Ty<'tcx>,
531        expected_ty: Ty<'tcx>,
532    ) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)> {
533        let ty::Adt(found_adt, found_args) = found_ty.peel_refs().kind() else {
534            return None;
535        };
536        let ty::Adt(expected_adt, expected_args) = expected_ty.kind() else {
537            return None;
538        };
539        if self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
540            && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
541        {
542            Some((found_args.type_at(0), expected_args.type_at(0), None))
543        } else if self.tcx.is_diagnostic_item(sym::Result, found_adt.did())
544            && self.tcx.is_diagnostic_item(sym::Result, expected_adt.did())
545        {
546            Some((
547                found_args.type_at(0),
548                expected_args.type_at(0),
549                Some((found_args.type_at(1), expected_args.type_at(1))),
550            ))
551        } else {
552            None
553        }
554    }
555
556    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
557    /// in the heap by calling `Box::new()`.
558    pub(in super::super) fn suggest_boxing_when_appropriate(
559        &self,
560        err: &mut Diag<'_>,
561        span: Span,
562        hir_id: HirId,
563        expected: Ty<'tcx>,
564        found: Ty<'tcx>,
565    ) -> bool {
566        // Do not suggest `Box::new` in const context.
567        if self.tcx.hir_is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
568            return false;
569        }
570        if self.may_coerce(Ty::new_box(self.tcx, found), expected) {
571            let suggest_boxing = match *found.kind() {
572                ty::Tuple(tuple) if tuple.is_empty() => {
573                    errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
574                }
575                ty::Coroutine(def_id, ..)
576                    if #[allow(non_exhaustive_omitted_patterns)] match self.tcx.coroutine_kind(def_id)
    {
    Some(CoroutineKind::Desugared(CoroutineDesugaring::Async,
        CoroutineSource::Closure)) => true,
    _ => false,
}matches!(
577                        self.tcx.coroutine_kind(def_id),
578                        Some(CoroutineKind::Desugared(
579                            CoroutineDesugaring::Async,
580                            CoroutineSource::Closure
581                        ))
582                    ) =>
583                {
584                    errors::SuggestBoxing::AsyncBody
585                }
586                _ if let Node::ExprField(expr_field) = self.tcx.parent_hir_node(hir_id)
587                    && expr_field.is_shorthand =>
588                {
589                    errors::SuggestBoxing::ExprFieldShorthand {
590                        start: span.shrink_to_lo(),
591                        end: span.shrink_to_hi(),
592                        ident: expr_field.ident,
593                    }
594                }
595                _ => errors::SuggestBoxing::Other {
596                    start: span.shrink_to_lo(),
597                    end: span.shrink_to_hi(),
598                },
599            };
600            err.subdiagnostic(suggest_boxing);
601
602            true
603        } else {
604            false
605        }
606    }
607
608    /// When encountering a closure that captures variables, where a FnPtr is expected,
609    /// suggest a non-capturing closure
610    pub(in super::super) fn suggest_no_capture_closure(
611        &self,
612        err: &mut Diag<'_>,
613        expected: Ty<'tcx>,
614        found: Ty<'tcx>,
615    ) -> bool {
616        if let (ty::FnPtr(..), ty::Closure(def_id, _)) = (expected.kind(), found.kind())
617            && let Some(upvars) = self.tcx.upvars_mentioned(*def_id)
618        {
619            // Report upto four upvars being captured to reduce the amount error messages
620            // reported back to the user.
621            let spans_and_labels = upvars
622                .iter()
623                .take(4)
624                .map(|(var_hir_id, upvar)| {
625                    let var_name = self.tcx.hir_name(*var_hir_id).to_string();
626                    let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` captured here", var_name))
    })format!("`{var_name}` captured here");
627                    (upvar.span, msg)
628                })
629                .collect::<Vec<_>>();
630
631            let mut multi_span: MultiSpan =
632                spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
633            for (sp, label) in spans_and_labels {
634                multi_span.push_span_label(sp, label);
635            }
636            err.span_note(
637                multi_span,
638                "closures can only be coerced to `fn` types if they do not capture any variables",
639            );
640            return true;
641        }
642        false
643    }
644
645    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
646    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("suggest_calling_boxed_future_when_appropriate",
                                    "rustc_hir_typeck::fn_ctxt::suggestions",
                                    ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                    ::tracing_core::__macro_support::Option::Some(646u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                    ::tracing_core::field::FieldSet::new(&["expr", "expected",
                                                    "found"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expr)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&found)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: bool = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if self.tcx.hir_is_inside_const_context(expr.hir_id) {
                return false;
            }
            let pin_did = self.tcx.lang_items().pin_type();
            if pin_did.is_none() ||
                    self.tcx.lang_items().owned_box().is_none() {
                return false;
            }
            let box_found = Ty::new_box(self.tcx, found);
            let Some(pin_box_found) =
                Ty::new_lang_item(self.tcx, box_found,
                    LangItem::Pin) else { return false; };
            let Some(pin_found) =
                Ty::new_lang_item(self.tcx, found,
                    LangItem::Pin) else { return false; };
            match expected.kind() {
                ty::Adt(def, _) if Some(def.did()) == pin_did => {
                    if self.may_coerce(pin_box_found, expected) {
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs:675",
                                                "rustc_hir_typeck::fn_ctxt::suggestions",
                                                ::tracing::Level::DEBUG,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                                ::tracing_core::__macro_support::Option::Some(675u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                                ::tracing_core::field::FieldSet::new(&["message"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&format_args!("can coerce {0:?} to {1:?}, suggesting Box::pin",
                                                                            pin_box_found, expected) as &dyn Value))])
                                    });
                            } else { ; }
                        };
                        match found.kind() {
                            ty::Adt(def, _) if def.is_box() => {
                                err.help("use `Box::pin`");
                            }
                            _ => {
                                let prefix =
                                    if let Some(name) =
                                            self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr)
                                        {
                                        ::alloc::__export::must_use({
                                                ::alloc::fmt::format(format_args!("{0}: ", name))
                                            })
                                    } else { String::new() };
                                let suggestion =
                                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                                            [(expr.span.shrink_to_lo(),
                                                        ::alloc::__export::must_use({
                                                                ::alloc::fmt::format(format_args!("{0}Box::pin(", prefix))
                                                            })), (expr.span.shrink_to_hi(), ")".to_string())]));
                                err.multipart_suggestion("you need to pin and box this expression",
                                    suggestion, Applicability::MaybeIncorrect);
                            }
                        }
                        true
                    } else if self.may_coerce(pin_found, expected) {
                        match found.kind() {
                            ty::Adt(def, _) if def.is_box() => {
                                err.help("use `Box::pin`");
                                true
                            }
                            _ => false,
                        }
                    } else { false }
                }
                ty::Adt(def, _) if
                    def.is_box() && self.may_coerce(box_found, expected) => {
                    let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), ..
                            }) =
                        self.tcx.parent_hir_node(expr.hir_id) else {
                            return false;
                        };
                    match fn_name.kind {
                        ExprKind::Path(QPath::TypeRelative(hir::Ty {
                            kind: TyKind::Path(QPath::Resolved(_, Path { res: recv_ty,
                                .. })), .. }, method)) if
                            recv_ty.opt_def_id() == pin_did &&
                                method.ident.name == sym::new => {
                            err.span_suggestion(fn_name.span,
                                "use `Box::pin` to pin and box this expression", "Box::pin",
                                Applicability::MachineApplicable);
                            true
                        }
                        _ => false,
                    }
                }
                _ => false,
            }
        }
    }
}#[instrument(skip(self, err))]
647    pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
648        &self,
649        err: &mut Diag<'_>,
650        expr: &hir::Expr<'_>,
651        expected: Ty<'tcx>,
652        found: Ty<'tcx>,
653    ) -> bool {
654        // Handle #68197.
655
656        if self.tcx.hir_is_inside_const_context(expr.hir_id) {
657            // Do not suggest `Box::new` in const context.
658            return false;
659        }
660        let pin_did = self.tcx.lang_items().pin_type();
661        // This guards the `new_box` below.
662        if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() {
663            return false;
664        }
665        let box_found = Ty::new_box(self.tcx, found);
666        let Some(pin_box_found) = Ty::new_lang_item(self.tcx, box_found, LangItem::Pin) else {
667            return false;
668        };
669        let Some(pin_found) = Ty::new_lang_item(self.tcx, found, LangItem::Pin) else {
670            return false;
671        };
672        match expected.kind() {
673            ty::Adt(def, _) if Some(def.did()) == pin_did => {
674                if self.may_coerce(pin_box_found, expected) {
675                    debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
676                    match found.kind() {
677                        ty::Adt(def, _) if def.is_box() => {
678                            err.help("use `Box::pin`");
679                        }
680                        _ => {
681                            let prefix = if let Some(name) =
682                                self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr)
683                            {
684                                format!("{}: ", name)
685                            } else {
686                                String::new()
687                            };
688                            let suggestion = vec![
689                                (expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")),
690                                (expr.span.shrink_to_hi(), ")".to_string()),
691                            ];
692                            err.multipart_suggestion(
693                                "you need to pin and box this expression",
694                                suggestion,
695                                Applicability::MaybeIncorrect,
696                            );
697                        }
698                    }
699                    true
700                } else if self.may_coerce(pin_found, expected) {
701                    match found.kind() {
702                        ty::Adt(def, _) if def.is_box() => {
703                            err.help("use `Box::pin`");
704                            true
705                        }
706                        _ => false,
707                    }
708                } else {
709                    false
710                }
711            }
712            ty::Adt(def, _) if def.is_box() && self.may_coerce(box_found, expected) => {
713                // Check if the parent expression is a call to Pin::new. If it
714                // is and we were expecting a Box, ergo Pin<Box<expected>>, we
715                // can suggest Box::pin.
716                let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }) =
717                    self.tcx.parent_hir_node(expr.hir_id)
718                else {
719                    return false;
720                };
721                match fn_name.kind {
722                    ExprKind::Path(QPath::TypeRelative(
723                        hir::Ty {
724                            kind: TyKind::Path(QPath::Resolved(_, Path { res: recv_ty, .. })),
725                            ..
726                        },
727                        method,
728                    )) if recv_ty.opt_def_id() == pin_did && method.ident.name == sym::new => {
729                        err.span_suggestion(
730                            fn_name.span,
731                            "use `Box::pin` to pin and box this expression",
732                            "Box::pin",
733                            Applicability::MachineApplicable,
734                        );
735                        true
736                    }
737                    _ => false,
738                }
739            }
740            _ => false,
741        }
742    }
743
744    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
745    ///
746    /// ```compile_fail,E0308
747    /// # fn bar_that_returns_u32() -> u32 { 4 }
748    /// fn foo() {
749    ///     bar_that_returns_u32()
750    /// }
751    /// ```
752    ///
753    /// This routine checks if the return expression in a block would make sense on its own as a
754    /// statement and the return type has been left as default or has been specified as `()`. If so,
755    /// it suggests adding a semicolon.
756    ///
757    /// If the expression is the expression of a closure without block (`|| expr`), a
758    /// block is needed to be added too (`|| { expr; }`). This is denoted by `needs_block`.
759    pub(crate) fn suggest_missing_semicolon(
760        &self,
761        err: &mut Diag<'_>,
762        expression: &'tcx hir::Expr<'tcx>,
763        expected: Ty<'tcx>,
764        needs_block: bool,
765        parent_is_closure: bool,
766    ) {
767        if !expected.is_unit() {
768            return;
769        }
770        // `BlockTailExpression` only relevant if the tail expr would be
771        // useful on its own.
772        match expression.kind {
773            ExprKind::Call(..)
774            | ExprKind::MethodCall(..)
775            | ExprKind::Loop(..)
776            | ExprKind::If(..)
777            | ExprKind::Match(..)
778            | ExprKind::Block(..)
779                if expression.can_have_side_effects()
780                    // If the expression is from an external macro, then do not suggest
781                    // adding a semicolon, because there's nowhere to put it.
782                    // See issue #81943.
783                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
784            {
785                if needs_block {
786                    err.multipart_suggestion(
787                        "consider using a semicolon here",
788                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expression.span.shrink_to_lo(), "{ ".to_owned()),
                (expression.span.shrink_to_hi(), "; }".to_owned())]))vec![
789                            (expression.span.shrink_to_lo(), "{ ".to_owned()),
790                            (expression.span.shrink_to_hi(), "; }".to_owned()),
791                        ],
792                        Applicability::MachineApplicable,
793                    );
794                } else if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id)
795                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id)
796                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id)
797                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind
798                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id)
799                    && let hir::StmtKind::Expr(_) = stmt.kind
800                    && self.is_next_stmt_expr_continuation(stmt.hir_id)
801                {
802                    err.multipart_suggestion(
803                        "parentheses are required to parse this as an expression",
804                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(stmt.span.shrink_to_lo(), "(".to_string()),
                (stmt.span.shrink_to_hi(), ")".to_string())]))vec![
805                            (stmt.span.shrink_to_lo(), "(".to_string()),
806                            (stmt.span.shrink_to_hi(), ")".to_string()),
807                        ],
808                        Applicability::MachineApplicable,
809                    );
810                } else {
811                    err.span_suggestion(
812                        expression.span.shrink_to_hi(),
813                        "consider using a semicolon here",
814                        ";",
815                        Applicability::MachineApplicable,
816                    );
817                }
818            }
819            ExprKind::Path(..) | ExprKind::Lit(_)
820                if parent_is_closure
821                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
822            {
823                err.span_suggestion_verbose(
824                    expression.span.shrink_to_lo(),
825                    "consider ignoring the value",
826                    "_ = ",
827                    Applicability::MachineApplicable,
828                );
829            }
830            _ => {
831                if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id)
832                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id)
833                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id)
834                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind
835                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id)
836                    && let hir::StmtKind::Expr(_) = stmt.kind
837                    && self.is_next_stmt_expr_continuation(stmt.hir_id)
838                {
839                    // The error is pointing at an arm of an if-expression, and we want to get the
840                    // `Span` of the whole if-expression for the suggestion. This only works for a
841                    // single level of nesting, which is fine.
842                    // We have something like `if true { false } else { true } && true`. Suggest
843                    // wrapping in parentheses. We find the statement or expression following the
844                    // `if` (`&& true`) and see if it is something that can reasonably be
845                    // interpreted as a binop following an expression.
846                    err.multipart_suggestion(
847                        "parentheses are required to parse this as an expression",
848                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(stmt.span.shrink_to_lo(), "(".to_string()),
                (stmt.span.shrink_to_hi(), ")".to_string())]))vec![
849                            (stmt.span.shrink_to_lo(), "(".to_string()),
850                            (stmt.span.shrink_to_hi(), ")".to_string()),
851                        ],
852                        Applicability::MachineApplicable,
853                    );
854                }
855            }
856        }
857    }
858
859    pub(crate) fn is_next_stmt_expr_continuation(&self, hir_id: HirId) -> bool {
860        if let hir::Node::Block(b) = self.tcx.parent_hir_node(hir_id)
861            && let mut stmts = b.stmts.iter().skip_while(|s| s.hir_id != hir_id)
862            && let Some(_) = stmts.next() // The statement the statement that was passed in
863            && let Some(next) = match (stmts.next(), b.expr) { // The following statement
864                (Some(next), _) => match next.kind {
865                    hir::StmtKind::Expr(next) | hir::StmtKind::Semi(next) => Some(next),
866                    _ => None,
867                },
868                (None, Some(next)) => Some(next),
869                _ => None,
870            }
871            && let hir::ExprKind::AddrOf(..) // prev_stmt && next
872                | hir::ExprKind::Unary(..) // prev_stmt * next
873                | hir::ExprKind::Err(_) = next.kind
874        // prev_stmt + next
875        {
876            true
877        } else {
878            false
879        }
880    }
881
882    /// A possible error is to forget to add a return type that is needed:
883    ///
884    /// ```compile_fail,E0308
885    /// # fn bar_that_returns_u32() -> u32 { 4 }
886    /// fn foo() {
887    ///     bar_that_returns_u32()
888    /// }
889    /// ```
890    ///
891    /// This routine checks if the return type is left as default, the method is not part of an
892    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
893    /// type.
894    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("suggest_missing_return_type",
                                    "rustc_hir_typeck::fn_ctxt::suggestions",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                    ::tracing_core::__macro_support::Option::Some(894u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                    ::tracing_core::field::FieldSet::new(&["fn_decl",
                                                    "expected", "found", "fn_id"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&fn_decl)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&found)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&fn_id)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: bool = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if let Some(hir::CoroutineKind::Desugared(_,
                    hir::CoroutineSource::Block)) =
                    self.tcx.coroutine_kind(fn_id) {
                return false;
            }
            let found =
                self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
            match &fn_decl.output {
                &hir::FnRetTy::DefaultReturn(_) if
                    self.tcx.is_closure_like(fn_id.to_def_id()) => {}
                &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
                    if !self.can_add_return_type(fn_id) {
                        err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit {
                                span,
                            });
                    } else if let Some(found) =
                            found.make_suggestable(self.tcx, false, None) {
                        err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
                                span,
                                found: found.to_string(),
                            });
                    } else if let Some(sugg) =
                            suggest_impl_trait(self, self.param_env, found) {
                        err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
                                span,
                                found: sugg,
                            });
                    } else {
                        err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere {
                                span,
                            });
                    }
                    return true;
                }
                hir::FnRetTy::Return(hir_ty) => {
                    if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind &&
                                let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds &&
                            !trait_ref.trait_ref.path.segments.last().and_then(|seg|
                                            seg.args).map_or(false, |args| !args.constraints.is_empty())
                        {
                        let trait_name =
                            trait_ref.trait_ref.path.segments.iter().map(|seg|
                                            seg.ident.as_str()).collect::<Vec<_>>().join("::");
                        err.subdiagnostic(errors::ExpectedReturnTypeLabel::ImplTrait {
                                span: hir_ty.span,
                                trait_name,
                            });
                        if let Some(ret_coercion_span) =
                                self.ret_coercion_span.get() {
                            let expected_name = expected.to_string();
                            err.span_label(ret_coercion_span,
                                ::alloc::__export::must_use({
                                        ::alloc::fmt::format(format_args!("return type resolved to be `{0}`",
                                                expected_name))
                                    }));
                        }
                        let trait_def_id = trait_ref.trait_ref.path.res.def_id();
                        if self.tcx.is_dyn_compatible(trait_def_id) {
                            err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType {
                                    start_sp: hir_ty.span.with_hi(hir_ty.span.lo() +
                                            BytePos(4)),
                                    end_sp: hir_ty.span.shrink_to_hi(),
                                });
                            let body = self.tcx.hir_body_owned_by(fn_id);
                            let mut visitor = ReturnsVisitor::default();
                            visitor.visit_body(&body);
                            if !visitor.returns.is_empty() {
                                let starts: Vec<Span> =
                                    visitor.returns.iter().filter(|expr|
                                                    expr.span.can_be_used_for_suggestions()).map(|expr|
                                                expr.span.shrink_to_lo()).collect();
                                let ends: Vec<Span> =
                                    visitor.returns.iter().filter(|expr|
                                                    expr.span.can_be_used_for_suggestions()).map(|expr|
                                                expr.span.shrink_to_hi()).collect();
                                if !starts.is_empty() {
                                    err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr {
                                            starts,
                                            ends,
                                        });
                                }
                            }
                        }
                        self.try_suggest_return_impl_trait(err, expected, found,
                            fn_id);
                        self.try_note_caller_chooses_ty_for_ty_param(err, expected,
                            found);
                        return true;
                    } else if let hir::TyKind::OpaqueDef(op_ty, ..) =
                                            hir_ty.kind &&
                                        let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds &&
                                    let Some(hir::PathSegment { args: Some(generic_args), .. })
                                        = trait_ref.trait_ref.path.segments.last() &&
                                let [constraint] = generic_args.constraints &&
                            let Some(ty) = constraint.ty() {
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs:1015",
                                                "rustc_hir_typeck::fn_ctxt::suggestions",
                                                ::tracing::Level::DEBUG,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                                ::tracing_core::__macro_support::Option::Some(1015u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                                ::tracing_core::field::FieldSet::new(&["found"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&debug(&found) as
                                                                    &dyn Value))])
                                    });
                            } else { ; }
                        };
                        if found.is_suggestable(self.tcx, false) {
                            if ty.span.is_empty() {
                                err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
                                        span: ty.span,
                                        found: found.to_string(),
                                    });
                                return true;
                            } else {
                                err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
                                        span: ty.span,
                                        expected,
                                    });
                            }
                        }
                    } else {
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs:1033",
                                                "rustc_hir_typeck::fn_ctxt::suggestions",
                                                ::tracing::Level::DEBUG,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                                ::tracing_core::__macro_support::Option::Some(1033u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                                ::tracing_core::field::FieldSet::new(&["message", "hir_ty"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&format_args!("return type")
                                                                    as &dyn Value)),
                                                        (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&debug(&hir_ty) as
                                                                    &dyn Value))])
                                    });
                            } else { ; }
                        };
                        let ty = self.lowerer().lower_ty(hir_ty);
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs:1035",
                                                "rustc_hir_typeck::fn_ctxt::suggestions",
                                                ::tracing::Level::DEBUG,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                                ::tracing_core::__macro_support::Option::Some(1035u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                                ::tracing_core::field::FieldSet::new(&["message", "ty"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&format_args!("return type (lowered)")
                                                                    as &dyn Value)),
                                                        (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&debug(&ty) as
                                                                    &dyn Value))])
                                    });
                            } else { ; }
                        };
                        {
                            use ::tracing::__macro_support::Callsite as _;
                            static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                                {
                                    static META: ::tracing::Metadata<'static> =
                                        {
                                            ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs:1036",
                                                "rustc_hir_typeck::fn_ctxt::suggestions",
                                                ::tracing::Level::DEBUG,
                                                ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                                ::tracing_core::__macro_support::Option::Some(1036u32),
                                                ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                                ::tracing_core::field::FieldSet::new(&["message",
                                                                "expected"],
                                                    ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                                ::tracing::metadata::Kind::EVENT)
                                        };
                                    ::tracing::callsite::DefaultCallsite::new(&META)
                                };
                            let enabled =
                                ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                        ::tracing::Level::DEBUG <=
                                            ::tracing::level_filters::LevelFilter::current() &&
                                    {
                                        let interest = __CALLSITE.interest();
                                        !interest.is_never() &&
                                            ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                                interest)
                                    };
                            if enabled {
                                (|value_set: ::tracing::field::ValueSet|
                                            {
                                                let meta = __CALLSITE.metadata();
                                                ::tracing::Event::dispatch(meta, &value_set);
                                                ;
                                            })({
                                        #[allow(unused_imports)]
                                        use ::tracing::field::{debug, display, Value};
                                        let mut iter = __CALLSITE.metadata().fields().iter();
                                        __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&format_args!("expected type")
                                                                    as &dyn Value)),
                                                        (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                            ::tracing::__macro_support::Option::Some(&debug(&expected)
                                                                    as &dyn Value))])
                                    });
                            } else { ; }
                        };
                        let bound_vars =
                            self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id));
                        let ty = Binder::bind_with_vars(ty, bound_vars);
                        let ty =
                            self.normalize(hir_ty.span, Unnormalized::new_wip(ty));
                        let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
                        if self.may_coerce(expected, ty) {
                            err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
                                    span: hir_ty.span,
                                    expected,
                                });
                            self.try_suggest_return_impl_trait(err, expected, found,
                                fn_id);
                            self.try_note_caller_chooses_ty_for_ty_param(err, expected,
                                found);
                            return true;
                        }
                    }
                }
                _ => {}
            }
            false
        }
    }
}#[instrument(level = "trace", skip(self, err))]
895    pub(in super::super) fn suggest_missing_return_type(
896        &self,
897        err: &mut Diag<'_>,
898        fn_decl: &hir::FnDecl<'tcx>,
899        expected: Ty<'tcx>,
900        found: Ty<'tcx>,
901        fn_id: LocalDefId,
902    ) -> bool {
903        // Can't suggest `->` on a block-like coroutine
904        if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Block)) =
905            self.tcx.coroutine_kind(fn_id)
906        {
907            return false;
908        }
909
910        let found =
911            self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
912        // Only suggest changing the return type for methods that
913        // haven't set a return type at all (and aren't `fn main()`, impl or closure).
914        match &fn_decl.output {
915            // For closure with default returns, don't suggest adding return type
916            &hir::FnRetTy::DefaultReturn(_) if self.tcx.is_closure_like(fn_id.to_def_id()) => {}
917            &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
918                if !self.can_add_return_type(fn_id) {
919                    err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
920                } else if let Some(found) = found.make_suggestable(self.tcx, false, None) {
921                    err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
922                        span,
923                        found: found.to_string(),
924                    });
925                } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
926                    err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg });
927                } else {
928                    // FIXME: if `found` could be `impl Iterator` we should suggest that.
929                    err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
930                }
931
932                return true;
933            }
934            hir::FnRetTy::Return(hir_ty) => {
935                if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
936                    && let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds
937                    && !trait_ref
938                        .trait_ref
939                        .path
940                        .segments
941                        .last()
942                        .and_then(|seg| seg.args)
943                        .map_or(false, |args| !args.constraints.is_empty())
944                {
945                    // Use the path to get the trait name string
946                    let trait_name = trait_ref
947                        .trait_ref
948                        .path
949                        .segments
950                        .iter()
951                        .map(|seg| seg.ident.as_str())
952                        .collect::<Vec<_>>()
953                        .join("::");
954
955                    err.subdiagnostic(errors::ExpectedReturnTypeLabel::ImplTrait {
956                        span: hir_ty.span,
957                        trait_name,
958                    });
959
960                    if let Some(ret_coercion_span) = self.ret_coercion_span.get() {
961                        let expected_name = expected.to_string();
962                        err.span_label(
963                            ret_coercion_span,
964                            format!("return type resolved to be `{expected_name}`"),
965                        );
966                    }
967
968                    let trait_def_id = trait_ref.trait_ref.path.res.def_id();
969                    if self.tcx.is_dyn_compatible(trait_def_id) {
970                        err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType {
971                            start_sp: hir_ty.span.with_hi(hir_ty.span.lo() + BytePos(4)),
972                            end_sp: hir_ty.span.shrink_to_hi(),
973                        });
974
975                        let body = self.tcx.hir_body_owned_by(fn_id);
976                        let mut visitor = ReturnsVisitor::default();
977                        visitor.visit_body(&body);
978
979                        if !visitor.returns.is_empty() {
980                            let starts: Vec<Span> = visitor
981                                .returns
982                                .iter()
983                                .filter(|expr| expr.span.can_be_used_for_suggestions())
984                                .map(|expr| expr.span.shrink_to_lo())
985                                .collect();
986                            let ends: Vec<Span> = visitor
987                                .returns
988                                .iter()
989                                .filter(|expr| expr.span.can_be_used_for_suggestions())
990                                .map(|expr| expr.span.shrink_to_hi())
991                                .collect();
992
993                            if !starts.is_empty() {
994                                err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr {
995                                    starts,
996                                    ends,
997                                });
998                            }
999                        }
1000                    }
1001
1002                    self.try_suggest_return_impl_trait(err, expected, found, fn_id);
1003                    self.try_note_caller_chooses_ty_for_ty_param(err, expected, found);
1004                    return true;
1005                } else if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
1006                    // FIXME: account for RPITIT.
1007                    && let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds
1008                    && let Some(hir::PathSegment { args: Some(generic_args), .. }) =
1009                        trait_ref.trait_ref.path.segments.last()
1010                    && let [constraint] = generic_args.constraints
1011                    && let Some(ty) = constraint.ty()
1012                {
1013                    // Check if async function's return type was omitted.
1014                    // Don't emit suggestions if the found type is `impl Future<...>`.
1015                    debug!(?found);
1016                    if found.is_suggestable(self.tcx, false) {
1017                        if ty.span.is_empty() {
1018                            err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
1019                                span: ty.span,
1020                                found: found.to_string(),
1021                            });
1022                            return true;
1023                        } else {
1024                            err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
1025                                span: ty.span,
1026                                expected,
1027                            });
1028                        }
1029                    }
1030                } else {
1031                    // Only point to return type if the expected type is the return type, as if they
1032                    // are not, the expectation must have been caused by something else.
1033                    debug!(?hir_ty, "return type");
1034                    let ty = self.lowerer().lower_ty(hir_ty);
1035                    debug!(?ty, "return type (lowered)");
1036                    debug!(?expected, "expected type");
1037                    let bound_vars =
1038                        self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id));
1039                    let ty = Binder::bind_with_vars(ty, bound_vars);
1040                    let ty = self.normalize(hir_ty.span, Unnormalized::new_wip(ty));
1041                    let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
1042                    if self.may_coerce(expected, ty) {
1043                        err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
1044                            span: hir_ty.span,
1045                            expected,
1046                        });
1047                        self.try_suggest_return_impl_trait(err, expected, found, fn_id);
1048                        self.try_note_caller_chooses_ty_for_ty_param(err, expected, found);
1049                        return true;
1050                    }
1051                }
1052            }
1053            _ => {}
1054        }
1055        false
1056    }
1057
1058    /// Checks whether we can add a return type to a function.
1059    /// Assumes given function doesn't have a explicit return type.
1060    fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
1061        match self.tcx.hir_node_by_def_id(fn_id) {
1062            Node::Item(item) => {
1063                let (ident, _, _, _) = item.expect_fn();
1064                // This is less than ideal, it will not suggest a return type span on any
1065                // method called `main`, regardless of whether it is actually the entry point,
1066                // but it will still present it as the reason for the expected type.
1067                ident.name != sym::main
1068            }
1069            Node::ImplItem(item) => {
1070                // If it doesn't impl a trait, we can add a return type
1071                let Node::Item(&hir::Item {
1072                    kind: hir::ItemKind::Impl(hir::Impl { of_trait, .. }),
1073                    ..
1074                }) = self.tcx.parent_hir_node(item.hir_id())
1075                else {
1076                    ::core::panicking::panic("internal error: entered unreachable code");unreachable!();
1077                };
1078
1079                of_trait.is_none()
1080            }
1081            _ => true,
1082        }
1083    }
1084
1085    fn try_note_caller_chooses_ty_for_ty_param(
1086        &self,
1087        diag: &mut Diag<'_>,
1088        expected: Ty<'tcx>,
1089        found: Ty<'tcx>,
1090    ) {
1091        // Only show the note if:
1092        // 1. `expected` ty is a type parameter;
1093        // 2. The `expected` type parameter does *not* occur in the return expression type. This can
1094        //    happen for e.g. `fn foo<T>(t: &T) -> T { t }`, where `expected` is `T` but `found` is
1095        //    `&T`. Saying "the caller chooses a type for `T` which can be different from `&T`" is
1096        //    "well duh" and is only confusing and not helpful.
1097        let ty::Param(expected_ty_as_param) = expected.kind() else {
1098            return;
1099        };
1100
1101        if found.contains(expected) {
1102            return;
1103        }
1104
1105        diag.subdiagnostic(errors::NoteCallerChoosesTyForTyParam {
1106            ty_param_name: expected_ty_as_param.name,
1107            found_ty: found,
1108        });
1109    }
1110
1111    /// check whether the return type is a generic type with a trait bound
1112    /// only suggest this if the generic param is not present in the arguments
1113    /// if this is true, hint them towards changing the return type to `impl Trait`
1114    /// ```compile_fail,E0308
1115    /// fn cant_name_it<T: Fn() -> u32>() -> T {
1116    ///     || 3
1117    /// }
1118    /// ```
1119    fn try_suggest_return_impl_trait(
1120        &self,
1121        err: &mut Diag<'_>,
1122        expected: Ty<'tcx>,
1123        found: Ty<'tcx>,
1124        fn_id: LocalDefId,
1125    ) {
1126        // Only apply the suggestion if:
1127        //  - the return type is a generic parameter
1128        //  - the generic param is not used as a fn param
1129        //  - the generic param has at least one bound
1130        //  - the generic param doesn't appear in any other bounds where it's not the Self type
1131        // Suggest:
1132        //  - Changing the return type to be `impl <all bounds>`
1133
1134        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs:1134",
                        "rustc_hir_typeck::fn_ctxt::suggestions",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                        ::tracing_core::__macro_support::Option::Some(1134u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("try_suggest_return_impl_trait, expected = {0:?}, found = {1:?}",
                                                    expected, found) as &dyn Value))])
            });
    } else { ; }
};debug!("try_suggest_return_impl_trait, expected = {:?}, found = {:?}", expected, found);
1135
1136        let ty::Param(expected_ty_as_param) = expected.kind() else { return };
1137
1138        let fn_node = self.tcx.hir_node_by_def_id(fn_id);
1139
1140        let hir::Node::Item(hir::Item {
1141            kind:
1142                hir::ItemKind::Fn {
1143                    sig:
1144                        hir::FnSig {
1145                            decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. },
1146                            ..
1147                        },
1148                    generics: hir::Generics { params, predicates, .. },
1149                    ..
1150                },
1151            ..
1152        }) = fn_node
1153        else {
1154            return;
1155        };
1156
1157        if params.get(expected_ty_as_param.index as usize).is_none() {
1158            return;
1159        };
1160
1161        // get all where BoundPredicates here, because they are used in two cases below
1162        let where_predicates = predicates
1163            .iter()
1164            .filter_map(|p| match p.kind {
1165                WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
1166                    bounds,
1167                    bounded_ty,
1168                    ..
1169                }) => {
1170                    // FIXME: Maybe these calls to `lower_ty` can be removed (and the ones below)
1171                    let ty = self.lowerer().lower_ty(bounded_ty);
1172                    Some((ty, bounds))
1173                }
1174                _ => None,
1175            })
1176            .map(|(ty, bounds)| match ty.kind() {
1177                ty::Param(param_ty) if param_ty == expected_ty_as_param => Ok(Some(bounds)),
1178                // check whether there is any predicate that contains our `T`, like `Option<T>: Send`
1179                _ => match ty.contains(expected) {
1180                    true => Err(()),
1181                    false => Ok(None),
1182                },
1183            })
1184            .collect::<Result<Vec<_>, _>>();
1185
1186        let Ok(where_predicates) = where_predicates else { return };
1187
1188        // now get all predicates in the same types as the where bounds, so we can chain them
1189        let predicates_from_where =
1190            where_predicates.iter().flatten().flat_map(|bounds| bounds.iter());
1191
1192        // extract all bounds from the source code using their spans
1193        let all_matching_bounds_strs = predicates_from_where
1194            .filter_map(|bound| match bound {
1195                GenericBound::Trait(_) => {
1196                    self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
1197                }
1198                _ => None,
1199            })
1200            .collect::<Vec<String>>();
1201
1202        if all_matching_bounds_strs.is_empty() {
1203            return;
1204        }
1205
1206        let all_bounds_str = all_matching_bounds_strs.join(" + ");
1207
1208        let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| {
1209                let ty = self.lowerer().lower_ty( param);
1210                #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param
        => true,
    _ => false,
}matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param)
1211            });
1212
1213        if ty_param_used_in_fn_params {
1214            return;
1215        }
1216
1217        err.span_suggestion(
1218            fn_return.span(),
1219            "consider using an impl return type",
1220            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("impl {0}", all_bounds_str))
    })format!("impl {all_bounds_str}"),
1221            Applicability::MaybeIncorrect,
1222        );
1223    }
1224
1225    pub(in super::super) fn suggest_missing_break_or_return_expr(
1226        &self,
1227        err: &mut Diag<'_>,
1228        expr: &'tcx hir::Expr<'tcx>,
1229        fn_decl: &hir::FnDecl<'tcx>,
1230        expected: Ty<'tcx>,
1231        found: Ty<'tcx>,
1232        id: HirId,
1233        fn_id: LocalDefId,
1234    ) {
1235        if !expected.is_unit() {
1236            return;
1237        }
1238        let found = self.resolve_vars_if_possible(found);
1239
1240        let innermost_loop = if self.is_loop(id) {
1241            Some(self.tcx.hir_node(id))
1242        } else {
1243            self.tcx
1244                .hir_parent_iter(id)
1245                .take_while(|(_, node)| {
1246                    // look at parents until we find the first body owner
1247                    node.body_id().is_none()
1248                })
1249                .find_map(|(parent_id, node)| self.is_loop(parent_id).then_some(node))
1250        };
1251        let can_break_with_value = innermost_loop.is_some_and(|node| {
1252            #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. })
        => true,
    _ => false,
}matches!(
1253                node,
1254                Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. })
1255            )
1256        });
1257
1258        let in_local_statement = self.is_local_statement(id)
1259            || self
1260                .tcx
1261                .hir_parent_iter(id)
1262                .any(|(parent_id, _)| self.is_local_statement(parent_id));
1263
1264        if can_break_with_value && in_local_statement {
1265            err.multipart_suggestion(
1266                "you might have meant to break the loop with this value",
1267                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(), "break ".to_string()),
                (expr.span.shrink_to_hi(), ";".to_string())]))vec![
1268                    (expr.span.shrink_to_lo(), "break ".to_string()),
1269                    (expr.span.shrink_to_hi(), ";".to_string()),
1270                ],
1271                Applicability::MaybeIncorrect,
1272            );
1273            return;
1274        }
1275
1276        let scope = self.tcx.hir_parent_iter(id).find(|(_, node)| {
1277            #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) | Node::Item(_) |
        Node::TraitItem(_) | Node::ImplItem(_) => true,
    _ => false,
}matches!(
1278                node,
1279                Node::Expr(Expr { kind: ExprKind::Closure(..), .. })
1280                    | Node::Item(_)
1281                    | Node::TraitItem(_)
1282                    | Node::ImplItem(_)
1283            )
1284        });
1285        let in_closure =
1286            #[allow(non_exhaustive_omitted_patterns)] match scope {
    Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. }))) => true,
    _ => false,
}matches!(scope, Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. }))));
1287
1288        let can_return = match fn_decl.output {
1289            hir::FnRetTy::Return(ty) => {
1290                let ty = self.lowerer().lower_ty(ty);
1291                let bound_vars = self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id));
1292                let ty = self
1293                    .tcx
1294                    .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars));
1295                let ty = match self.tcx.asyncness(fn_id) {
1296                    ty::Asyncness::Yes => {
1297                        self.err_ctxt().get_impl_future_output_ty(ty).unwrap_or_else(|| {
1298                            ::rustc_middle::util::bug::span_bug_fmt(fn_decl.output.span(),
    format_args!("failed to get output type of async function"))span_bug!(
1299                                fn_decl.output.span(),
1300                                "failed to get output type of async function"
1301                            )
1302                        })
1303                    }
1304                    ty::Asyncness::No => ty,
1305                };
1306                let ty = self.normalize(expr.span, Unnormalized::new_wip(ty));
1307                self.may_coerce(found, ty)
1308            }
1309            hir::FnRetTy::DefaultReturn(_) if in_closure => {
1310                self.ret_coercion.as_ref().is_some_and(|ret| {
1311                    let ret_ty = ret.borrow().expected_ty();
1312                    self.may_coerce(found, ret_ty)
1313                })
1314            }
1315            _ => false,
1316        };
1317        if can_return
1318            && let Some(span) = expr.span.find_ancestor_inside(
1319                self.tcx.hir_span_with_body(self.tcx.local_def_id_to_hir_id(fn_id)),
1320            )
1321        {
1322            // When the expr is in a match arm's body, we shouldn't add semicolon ';' at the end.
1323            // For example:
1324            // fn mismatch_types() -> i32 {
1325            //     match 1 {
1326            //         x => dbg!(x),
1327            //     }
1328            //     todo!()
1329            // }
1330            // -------------^^^^^^^-
1331            // Don't add semicolon `;` at the end of `dbg!(x)` expr
1332            fn is_in_arm<'tcx>(expr: &'tcx hir::Expr<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
1333                for (_, node) in tcx.hir_parent_iter(expr.hir_id) {
1334                    match node {
1335                        hir::Node::Block(block) => {
1336                            if let Some(ret) = block.expr
1337                                && ret.hir_id == expr.hir_id
1338                            {
1339                                continue;
1340                            }
1341                        }
1342                        hir::Node::Arm(arm) => {
1343                            if let hir::ExprKind::Block(block, _) = arm.body.kind
1344                                && let Some(ret) = block.expr
1345                                && ret.hir_id == expr.hir_id
1346                            {
1347                                return true;
1348                            }
1349                        }
1350                        hir::Node::Expr(e) if let hir::ExprKind::Block(block, _) = e.kind => {
1351                            if let Some(ret) = block.expr
1352                                && ret.hir_id == expr.hir_id
1353                            {
1354                                continue;
1355                            }
1356                        }
1357                        _ => {
1358                            return false;
1359                        }
1360                    }
1361                }
1362
1363                false
1364            }
1365            let mut suggs = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span.shrink_to_lo(), "return ".to_string())]))vec![(span.shrink_to_lo(), "return ".to_string())];
1366            if !is_in_arm(expr, self.tcx) {
1367                suggs.push((span.shrink_to_hi(), ";".to_string()));
1368            }
1369            err.multipart_suggestion(
1370                "you might have meant to return this value",
1371                suggs,
1372                Applicability::MaybeIncorrect,
1373            );
1374        }
1375    }
1376
1377    pub(in super::super) fn suggest_missing_parentheses(
1378        &self,
1379        err: &mut Diag<'_>,
1380        expr: &hir::Expr<'_>,
1381    ) -> bool {
1382        let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
1383        if let Some(sp) = self.tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) {
1384            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
1385            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
1386            true
1387        } else {
1388            false
1389        }
1390    }
1391
1392    /// Given an expression type mismatch, peel any `&` expressions until we get to
1393    /// a block expression, and then suggest replacing the braces with square braces
1394    /// if it was possibly mistaken array syntax.
1395    pub(crate) fn suggest_block_to_brackets_peeling_refs(
1396        &self,
1397        diag: &mut Diag<'_>,
1398        mut expr: &hir::Expr<'_>,
1399        mut expr_ty: Ty<'tcx>,
1400        mut expected_ty: Ty<'tcx>,
1401    ) -> bool {
1402        loop {
1403            match (&expr.kind, expr_ty.kind(), expected_ty.kind()) {
1404                (
1405                    hir::ExprKind::AddrOf(_, _, inner_expr),
1406                    ty::Ref(_, inner_expr_ty, _),
1407                    ty::Ref(_, inner_expected_ty, _),
1408                ) => {
1409                    expr = *inner_expr;
1410                    expr_ty = *inner_expr_ty;
1411                    expected_ty = *inner_expected_ty;
1412                }
1413                (hir::ExprKind::Block(blk, _), _, _) => {
1414                    self.suggest_block_to_brackets(diag, blk, expr_ty, expected_ty);
1415                    break true;
1416                }
1417                _ => break false,
1418            }
1419        }
1420    }
1421
1422    pub(crate) fn suggest_clone_for_ref(
1423        &self,
1424        diag: &mut Diag<'_>,
1425        expr: &hir::Expr<'_>,
1426        expr_ty: Ty<'tcx>,
1427        expected_ty: Ty<'tcx>,
1428    ) -> bool {
1429        if let ty::Ref(_, inner_ty, hir::Mutability::Not) = expr_ty.kind()
1430            && let Some(clone_trait_def) = self.tcx.lang_items().clone_trait()
1431            && expected_ty == *inner_ty
1432            && self
1433                .infcx
1434                .type_implements_trait(
1435                    clone_trait_def,
1436                    [self.tcx.erase_and_anonymize_regions(expected_ty)],
1437                    self.param_env,
1438                )
1439                .must_apply_modulo_regions()
1440        {
1441            let suggestion = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
1442                Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}.clone()", ident))
    })format!(": {ident}.clone()"),
1443                None => ".clone()".to_string(),
1444            };
1445
1446            let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span).shrink_to_hi();
1447
1448            diag.span_suggestion_verbose(
1449                span,
1450                "consider using clone here",
1451                suggestion,
1452                Applicability::MachineApplicable,
1453            );
1454            return true;
1455        }
1456        false
1457    }
1458
1459    pub(crate) fn suggest_copied_cloned_or_as_ref(
1460        &self,
1461        diag: &mut Diag<'_>,
1462        expr: &hir::Expr<'_>,
1463        expr_ty: Ty<'tcx>,
1464        expected_ty: Ty<'tcx>,
1465    ) -> bool {
1466        let ty::Adt(adt_def, args) = expr_ty.kind() else {
1467            return false;
1468        };
1469        let ty::Adt(expected_adt_def, expected_args) = expected_ty.kind() else {
1470            return false;
1471        };
1472        if adt_def != expected_adt_def {
1473            return false;
1474        }
1475
1476        if Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Result)
1477            && self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1))
1478            || Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Option)
1479        {
1480            let expr_inner_ty = args.type_at(0);
1481            let expected_inner_ty = expected_args.type_at(0);
1482            if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind()
1483                && self.can_eq(self.param_env, ty, expected_inner_ty)
1484            {
1485                let def_path = self.tcx.def_path_str(adt_def.did());
1486                let span = expr.span.shrink_to_hi();
1487                let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) {
1488                    errors::OptionResultRefMismatch::Copied { span, def_path }
1489                } else if self.type_is_clone_modulo_regions(self.param_env, ty) {
1490                    errors::OptionResultRefMismatch::Cloned { span, def_path }
1491                } else {
1492                    return false;
1493                };
1494                diag.subdiagnostic(subdiag);
1495                return true;
1496            }
1497        }
1498
1499        false
1500    }
1501
1502    pub(crate) fn suggest_into(
1503        &self,
1504        diag: &mut Diag<'_>,
1505        expr: &hir::Expr<'_>,
1506        expr_ty: Ty<'tcx>,
1507        expected_ty: Ty<'tcx>,
1508    ) -> bool {
1509        let expr = expr.peel_blocks();
1510
1511        // We have better suggestions for scalar interconversions...
1512        if expr_ty.is_scalar() && expected_ty.is_scalar() {
1513            return false;
1514        }
1515
1516        // Don't suggest turning a block into another type (e.g. `{}.into()`)
1517        if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    hir::ExprKind::Block(..) => true,
    _ => false,
}matches!(expr.kind, hir::ExprKind::Block(..)) {
1518            return false;
1519        }
1520
1521        // We'll later suggest `.as_ref` when noting the type error,
1522        // so skip if we will suggest that instead.
1523        if self.err_ctxt().should_suggest_as_ref(expected_ty, expr_ty).is_some() {
1524            return false;
1525        }
1526
1527        if let Some(into_def_id) = self.tcx.get_diagnostic_item(sym::Into)
1528            && self.predicate_must_hold_modulo_regions(&traits::Obligation::new(
1529                self.tcx,
1530                self.misc(expr.span),
1531                self.param_env,
1532                ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
1533            ))
1534            && !expr
1535                .span
1536                .macro_backtrace()
1537                .any(|x| #[allow(non_exhaustive_omitted_patterns)] match x.kind {
    ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..) => true,
    _ => false,
}matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..)))
1538        {
1539            let span = expr
1540                .span
1541                .find_ancestor_not_from_extern_macro(self.tcx.sess.source_map())
1542                .unwrap_or(expr.span);
1543
1544            let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous {
1545                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span.shrink_to_hi(), ".into()".to_owned())]))vec![(span.shrink_to_hi(), ".into()".to_owned())]
1546            } else {
1547                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span.shrink_to_lo(), "(".to_owned()),
                (span.shrink_to_hi(), ").into()".to_owned())]))vec![
1548                    (span.shrink_to_lo(), "(".to_owned()),
1549                    (span.shrink_to_hi(), ").into()".to_owned()),
1550                ]
1551            };
1552            if let Some(name) = self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
1553                sugg.insert(0, (expr.span.shrink_to_lo(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", name))
    })format!("{}: ", name)));
1554            }
1555            diag.multipart_suggestion(
1556                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("call `Into::into` on this expression to convert `{0}` into `{1}`",
                expr_ty, expected_ty))
    })format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
1557                    sugg,
1558                    Applicability::MaybeIncorrect
1559                );
1560            return true;
1561        }
1562
1563        false
1564    }
1565
1566    /// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
1567    pub(crate) fn suggest_option_to_bool(
1568        &self,
1569        diag: &mut Diag<'_>,
1570        expr: &hir::Expr<'_>,
1571        expr_ty: Ty<'tcx>,
1572        expected_ty: Ty<'tcx>,
1573    ) -> bool {
1574        if !expected_ty.is_bool() {
1575            return false;
1576        }
1577
1578        let ty::Adt(def, _) = expr_ty.peel_refs().kind() else {
1579            return false;
1580        };
1581        if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
1582            return false;
1583        }
1584
1585        let cond_parent = self.tcx.hir_parent_iter(expr.hir_id).find(|(_, node)| {
1586            !#[allow(non_exhaustive_omitted_patterns)] match node {
    hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. })
        if op.node == hir::BinOpKind::And => true,
    _ => false,
}matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
1587        });
1588        // Don't suggest:
1589        //     `let Some(_) = a.is_some() && b`
1590        //                     ++++++++++
1591        // since the user probably just misunderstood how `let else`
1592        // and `&&` work together.
1593        if let Some((_, hir::Node::LetStmt(local))) = cond_parent
1594            && let hir::PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
1595            | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
1596            && let hir::QPath::Resolved(None, path) = qpath
1597            && let Some(did) = path
1598                .res
1599                .opt_def_id()
1600                .and_then(|did| self.tcx.opt_parent(did))
1601                .and_then(|did| self.tcx.opt_parent(did))
1602            && self.tcx.is_diagnostic_item(sym::Option, did)
1603        {
1604            return false;
1605        }
1606
1607        let suggestion = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
1608            Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}.is_some()", ident))
    })format!(": {ident}.is_some()"),
1609            None => ".is_some()".to_string(),
1610        };
1611
1612        diag.span_suggestion_verbose(
1613            expr.span.shrink_to_hi(),
1614            "use `Option::is_some` to test if the `Option` has a value",
1615            suggestion,
1616            Applicability::MachineApplicable,
1617        );
1618        true
1619    }
1620
1621    // Suggest to change `Option<&Vec<T>>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`.
1622    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("suggest_deref_unwrap_or",
                                    "rustc_hir_typeck::fn_ctxt::suggestions",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                    ::tracing_core::__macro_support::Option::Some(1622u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                    ::tracing_core::field::FieldSet::new(&["callee_ty",
                                                    "call_ident", "expected_ty", "provided_ty", "is_method"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&callee_ty)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&call_ident)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected_ty)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&provided_ty)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&is_method as
                                                            &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !is_method { return; }
            let Some(callee_ty) = callee_ty else { return; };
            let ty::Adt(callee_adt, _) =
                callee_ty.peel_refs().kind() else { return; };
            let adt_name =
                if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did())
                    {
                    "Option"
                } else if self.tcx.is_diagnostic_item(sym::Result,
                        callee_adt.did()) {
                    "Result"
                } else { return; };
            let Some(call_ident) = call_ident else { return; };
            if call_ident.name != sym::unwrap_or { return; }
            let ty::Ref(_, peeled, _mutability) =
                provided_ty.kind() else { return; };
            let dummy_ty =
                if let ty::Array(elem_ty, size) = peeled.kind() &&
                            let ty::Infer(_) = elem_ty.kind() &&
                        self.try_structurally_resolve_const(provided_expr.span,
                                    *size).try_to_target_usize(self.tcx) == Some(0) {
                    let slice = Ty::new_slice(self.tcx, *elem_ty);
                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static,
                        slice)
                } else { provided_ty };
            if !self.may_coerce(expected_ty, dummy_ty) { return; }
            let msg =
                ::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("use `{0}::map_or` to deref inner value of `{0}`",
                                adt_name))
                    });
            err.multipart_suggestion(msg,
                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                        [(call_ident.span, "map_or".to_owned()),
                                (provided_expr.span.shrink_to_hi(),
                                    ", |v| v".to_owned())])), Applicability::MachineApplicable);
        }
    }
}#[instrument(level = "trace", skip(self, err, provided_expr))]
1623    pub(crate) fn suggest_deref_unwrap_or(
1624        &self,
1625        err: &mut Diag<'_>,
1626        callee_ty: Option<Ty<'tcx>>,
1627        call_ident: Option<Ident>,
1628        expected_ty: Ty<'tcx>,
1629        provided_ty: Ty<'tcx>,
1630        provided_expr: &Expr<'tcx>,
1631        is_method: bool,
1632    ) {
1633        if !is_method {
1634            return;
1635        }
1636        let Some(callee_ty) = callee_ty else {
1637            return;
1638        };
1639        let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else {
1640            return;
1641        };
1642        let adt_name = if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) {
1643            "Option"
1644        } else if self.tcx.is_diagnostic_item(sym::Result, callee_adt.did()) {
1645            "Result"
1646        } else {
1647            return;
1648        };
1649
1650        let Some(call_ident) = call_ident else {
1651            return;
1652        };
1653        if call_ident.name != sym::unwrap_or {
1654            return;
1655        }
1656
1657        let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else {
1658            return;
1659        };
1660
1661        // NOTE: Can we reuse `suggest_deref_or_ref`?
1662
1663        // Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
1664        let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind()
1665            && let ty::Infer(_) = elem_ty.kind()
1666            && self
1667                .try_structurally_resolve_const(provided_expr.span, *size)
1668                .try_to_target_usize(self.tcx)
1669                == Some(0)
1670        {
1671            let slice = Ty::new_slice(self.tcx, *elem_ty);
1672            Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice)
1673        } else {
1674            provided_ty
1675        };
1676
1677        if !self.may_coerce(expected_ty, dummy_ty) {
1678            return;
1679        }
1680        let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`");
1681        err.multipart_suggestion(
1682            msg,
1683            vec![
1684                (call_ident.span, "map_or".to_owned()),
1685                (provided_expr.span.shrink_to_hi(), ", |v| v".to_owned()),
1686            ],
1687            Applicability::MachineApplicable,
1688        );
1689    }
1690
1691    /// Suggest wrapping the block in square brackets instead of curly braces
1692    /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
1693    pub(crate) fn suggest_block_to_brackets(
1694        &self,
1695        diag: &mut Diag<'_>,
1696        blk: &hir::Block<'_>,
1697        blk_ty: Ty<'tcx>,
1698        expected_ty: Ty<'tcx>,
1699    ) {
1700        if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() {
1701            if self.may_coerce(blk_ty, *elem_ty)
1702                && blk.stmts.is_empty()
1703                && blk.rules == hir::BlockCheckMode::DefaultBlock
1704                && let source_map = self.tcx.sess.source_map()
1705                && let Ok(snippet) = source_map.span_to_snippet(blk.span)
1706                && snippet.starts_with('{')
1707                && snippet.ends_with('}')
1708            {
1709                diag.multipart_suggestion(
1710                    "to create an array, use square brackets instead of curly braces",
1711                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(blk.span.shrink_to_lo().with_hi(rustc_span::BytePos(blk.span.lo().0
                                + 1)), "[".to_string()),
                (blk.span.shrink_to_hi().with_lo(rustc_span::BytePos(blk.span.hi().0
                                - 1)), "]".to_string())]))vec![
1712                        (
1713                            blk.span
1714                                .shrink_to_lo()
1715                                .with_hi(rustc_span::BytePos(blk.span.lo().0 + 1)),
1716                            "[".to_string(),
1717                        ),
1718                        (
1719                            blk.span
1720                                .shrink_to_hi()
1721                                .with_lo(rustc_span::BytePos(blk.span.hi().0 - 1)),
1722                            "]".to_string(),
1723                        ),
1724                    ],
1725                    Applicability::MachineApplicable,
1726                );
1727            }
1728        }
1729    }
1730
1731    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("suggest_floating_point_literal",
                                    "rustc_hir_typeck::fn_ctxt::suggestions",
                                    ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                    ::tracing_core::__macro_support::Option::Some(1731u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                    ::tracing_core::field::FieldSet::new(&["expr",
                                                    "expected_ty"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expr)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected_ty)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: bool = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !expected_ty.is_floating_point() { return false; }
            match expr.kind {
                ExprKind::Struct(&qpath, [start, end], _) if
                    is_range_literal(expr) &&
                        self.tcx.qpath_is_lang_item(qpath, LangItem::Range) => {
                    err.span_suggestion_verbose(start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()),
                        "remove the unnecessary `.` operator for a floating point literal",
                        '.', Applicability::MaybeIncorrect);
                    true
                }
                ExprKind::Struct(&qpath, [arg], _) if
                    is_range_literal(expr) &&
                        let Some(qpath @ (LangItem::RangeFrom | LangItem::RangeTo))
                            = self.tcx.qpath_lang_item(qpath) => {
                    let range_span = expr.span.parent_callsite().unwrap();
                    match qpath {
                        LangItem::RangeFrom => {
                            err.span_suggestion_verbose(range_span.with_lo(arg.expr.span.hi()),
                                "remove the unnecessary `.` operator for a floating point literal",
                                '.', Applicability::MaybeIncorrect);
                        }
                        _ => {
                            err.span_suggestion_verbose(range_span.until(arg.expr.span),
                                "remove the unnecessary `.` operator and add an integer part for a floating point literal",
                                "0.", Applicability::MaybeIncorrect);
                        }
                    }
                    true
                }
                ExprKind::Lit(Spanned {
                    node: rustc_ast::LitKind::Int(lit,
                        rustc_ast::LitIntType::Unsuffixed),
                    span }) => {
                    let Ok(snippet) =
                        self.tcx.sess.source_map().span_to_snippet(span) else {
                            return false;
                        };
                    if !(snippet.starts_with("0x") || snippet.starts_with("0X"))
                        {
                        return false;
                    }
                    if snippet.len() <= 5 ||
                            !snippet.is_char_boundary(snippet.len() - 3) {
                        return false;
                    }
                    let (_, suffix) = snippet.split_at(snippet.len() - 3);
                    let value =
                        match suffix {
                            "f32" => (lit.get() - 0xf32) / (16 * 16 * 16),
                            "f64" => (lit.get() - 0xf64) / (16 * 16 * 16),
                            _ => return false,
                        };
                    err.span_suggestions(expr.span,
                        "rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float",
                        [::alloc::__export::must_use({
                                        ::alloc::fmt::format(format_args!("0x{0:X} as {1}", value,
                                                suffix))
                                    }),
                                ::alloc::__export::must_use({
                                        ::alloc::fmt::format(format_args!("{0}_{1}", value, suffix))
                                    })], Applicability::MaybeIncorrect);
                    true
                }
                _ => false,
            }
        }
    }
}#[instrument(skip(self, err))]
1732    pub(crate) fn suggest_floating_point_literal(
1733        &self,
1734        err: &mut Diag<'_>,
1735        expr: &hir::Expr<'_>,
1736        expected_ty: Ty<'tcx>,
1737    ) -> bool {
1738        if !expected_ty.is_floating_point() {
1739            return false;
1740        }
1741        match expr.kind {
1742            ExprKind::Struct(&qpath, [start, end], _)
1743                if is_range_literal(expr)
1744                    && self.tcx.qpath_is_lang_item(qpath, LangItem::Range) =>
1745            {
1746                err.span_suggestion_verbose(
1747                    start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()),
1748                    "remove the unnecessary `.` operator for a floating point literal",
1749                    '.',
1750                    Applicability::MaybeIncorrect,
1751                );
1752                true
1753            }
1754            ExprKind::Struct(&qpath, [arg], _)
1755                if is_range_literal(expr)
1756                    && let Some(qpath @ (LangItem::RangeFrom | LangItem::RangeTo)) =
1757                        self.tcx.qpath_lang_item(qpath) =>
1758            {
1759                let range_span = expr.span.parent_callsite().unwrap();
1760                match qpath {
1761                    LangItem::RangeFrom => {
1762                        err.span_suggestion_verbose(
1763                            range_span.with_lo(arg.expr.span.hi()),
1764                            "remove the unnecessary `.` operator for a floating point literal",
1765                            '.',
1766                            Applicability::MaybeIncorrect,
1767                        );
1768                    }
1769                    _ => {
1770                        err.span_suggestion_verbose(
1771                            range_span.until(arg.expr.span),
1772                            "remove the unnecessary `.` operator and add an integer part for a floating point literal",
1773                            "0.",
1774                            Applicability::MaybeIncorrect,
1775                        );
1776                    }
1777                }
1778                true
1779            }
1780            ExprKind::Lit(Spanned {
1781                node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
1782                span,
1783            }) => {
1784                let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {
1785                    return false;
1786                };
1787                if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
1788                    return false;
1789                }
1790                if snippet.len() <= 5 || !snippet.is_char_boundary(snippet.len() - 3) {
1791                    return false;
1792                }
1793                let (_, suffix) = snippet.split_at(snippet.len() - 3);
1794                let value = match suffix {
1795                    "f32" => (lit.get() - 0xf32) / (16 * 16 * 16),
1796                    "f64" => (lit.get() - 0xf64) / (16 * 16 * 16),
1797                    _ => return false,
1798                };
1799                err.span_suggestions(
1800                    expr.span,
1801                    "rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float",
1802                    [format!("0x{value:X} as {suffix}"), format!("{value}_{suffix}")],
1803                    Applicability::MaybeIncorrect,
1804                );
1805                true
1806            }
1807            _ => false,
1808        }
1809    }
1810
1811    /// Suggest providing `std::ptr::null()` or `std::ptr::null_mut()` if they
1812    /// pass in a literal 0 to an raw pointer.
1813    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
                ::tracing::Level::INFO <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("suggest_null_ptr_for_literal_zero_given_to_ptr_arg",
                                    "rustc_hir_typeck::fn_ctxt::suggestions",
                                    ::tracing::Level::INFO,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs"),
                                    ::tracing_core::__macro_support::Option::Some(1813u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fn_ctxt::suggestions"),
                                    ::tracing_core::field::FieldSet::new(&["expr",
                                                    "expected_ty"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::INFO <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::INFO <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expr)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expected_ty)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: bool = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let ty::RawPtr(_, mutbl) =
                expected_ty.kind() else { return false; };
            let ExprKind::Lit(Spanned {
                    node: rustc_ast::LitKind::Int(Pu128(0), _), span }) =
                expr.kind else { return false; };
            let null_sym =
                match mutbl {
                    hir::Mutability::Not => sym::ptr_null,
                    hir::Mutability::Mut => sym::ptr_null_mut,
                };
            let Some(null_did) =
                self.tcx.get_diagnostic_item(null_sym) else { return false; };
            let null_path_str =
                {
                    let _guard = NoTrimmedGuard::new();
                    self.tcx.def_path_str(null_did)
                };
            err.span_suggestion(span,
                ::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("if you meant to create a null pointer, use `{0}()`",
                                null_path_str))
                    }), null_path_str + "()", Applicability::MachineApplicable);
            true
        }
    }
}#[instrument(skip(self, err))]
1814    pub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg(
1815        &self,
1816        err: &mut Diag<'_>,
1817        expr: &hir::Expr<'_>,
1818        expected_ty: Ty<'tcx>,
1819    ) -> bool {
1820        // Expected type needs to be a raw pointer.
1821        let ty::RawPtr(_, mutbl) = expected_ty.kind() else {
1822            return false;
1823        };
1824
1825        // Provided expression needs to be a literal `0`.
1826        let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(Pu128(0), _), span }) = expr.kind
1827        else {
1828            return false;
1829        };
1830
1831        // We need to find a null pointer symbol to suggest
1832        let null_sym = match mutbl {
1833            hir::Mutability::Not => sym::ptr_null,
1834            hir::Mutability::Mut => sym::ptr_null_mut,
1835        };
1836        let Some(null_did) = self.tcx.get_diagnostic_item(null_sym) else {
1837            return false;
1838        };
1839        let null_path_str = with_no_trimmed_paths!(self.tcx.def_path_str(null_did));
1840
1841        // We have satisfied all requirements to provide a suggestion. Emit it.
1842        err.span_suggestion(
1843            span,
1844            format!("if you meant to create a null pointer, use `{null_path_str}()`"),
1845            null_path_str + "()",
1846            Applicability::MachineApplicable,
1847        );
1848
1849        true
1850    }
1851
1852    pub(crate) fn suggest_associated_const(
1853        &self,
1854        err: &mut Diag<'_>,
1855        expr: &hir::Expr<'tcx>,
1856        expected_ty: Ty<'tcx>,
1857    ) -> bool {
1858        let Some((DefKind::AssocFn, old_def_id)) =
1859            self.typeck_results.borrow().type_dependent_def(expr.hir_id)
1860        else {
1861            return false;
1862        };
1863        let old_item_name = self.tcx.item_name(old_def_id);
1864        let capitalized_name = Symbol::intern(&old_item_name.as_str().to_uppercase());
1865        if old_item_name == capitalized_name {
1866            return false;
1867        }
1868        let (item, segment) = match expr.kind {
1869            hir::ExprKind::Path(QPath::Resolved(
1870                Some(ty),
1871                hir::Path { segments: [segment], .. },
1872            ))
1873            | hir::ExprKind::Path(QPath::TypeRelative(ty, segment))
1874                if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
1875                    && let Ok(pick) = self.probe_for_name(
1876                        Mode::Path,
1877                        Ident::new(capitalized_name, segment.ident.span),
1878                        Some(expected_ty),
1879                        IsSuggestion(true),
1880                        self_ty,
1881                        expr.hir_id,
1882                        ProbeScope::TraitsInScope,
1883                    ) =>
1884            {
1885                (pick.item, segment)
1886            }
1887            hir::ExprKind::Path(QPath::Resolved(
1888                None,
1889                hir::Path { segments: [.., segment], .. },
1890            )) => {
1891                // we resolved through some path that doesn't end in the item name,
1892                // better not do a bad suggestion by accident.
1893                if old_item_name != segment.ident.name {
1894                    return false;
1895                }
1896                let Some(item) = self
1897                    .tcx
1898                    .associated_items(self.tcx.parent(old_def_id))
1899                    .filter_by_name_unhygienic(capitalized_name)
1900                    .next()
1901                else {
1902                    return false;
1903                };
1904                (*item, segment)
1905            }
1906            _ => return false,
1907        };
1908        if item.def_id == old_def_id
1909            || !#[allow(non_exhaustive_omitted_patterns)] match self.tcx.def_kind(item.def_id)
    {
    DefKind::AssocConst { .. } => true,
    _ => false,
}matches!(self.tcx.def_kind(item.def_id), DefKind::AssocConst { .. })
1910        {
1911            // Same item
1912            return false;
1913        }
1914        let item_ty = self.tcx.type_of(item.def_id).instantiate_identity().skip_norm_wip();
1915        // FIXME(compiler-errors): This check is *so* rudimentary
1916        if item_ty.has_param() {
1917            return false;
1918        }
1919        if self.may_coerce(item_ty, expected_ty) {
1920            err.span_suggestion_verbose(
1921                segment.ident.span,
1922                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("try referring to the associated const `{0}` instead",
                capitalized_name))
    })format!("try referring to the associated const `{capitalized_name}` instead",),
1923                capitalized_name,
1924                Applicability::MachineApplicable,
1925            );
1926            true
1927        } else {
1928            false
1929        }
1930    }
1931
1932    fn is_loop(&self, id: HirId) -> bool {
1933        let node = self.tcx.hir_node(id);
1934        #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Expr(Expr { kind: ExprKind::Loop(..), .. }) => true,
    _ => false,
}matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. }))
1935    }
1936
1937    fn is_local_statement(&self, id: HirId) -> bool {
1938        let node = self.tcx.hir_node(id);
1939        #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Stmt(Stmt { kind: StmtKind::Let(..), .. }) => true,
    _ => false,
}matches!(node, Node::Stmt(Stmt { kind: StmtKind::Let(..), .. }))
1940    }
1941
1942    /// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,
1943    /// which is a side-effect of autoref.
1944    pub(crate) fn note_type_is_not_clone(
1945        &self,
1946        diag: &mut Diag<'_>,
1947        expected_ty: Ty<'tcx>,
1948        found_ty: Ty<'tcx>,
1949        expr: &hir::Expr<'_>,
1950    ) {
1951        // When `expr` is `x` in something like `let x = foo.clone(); x`, need to recurse up to get
1952        // `foo` and `clone`.
1953        let expr = self.note_type_is_not_clone_inner_expr(expr);
1954
1955        // If we've recursed to an `expr` of `foo.clone()`, get `foo` and `clone`.
1956        let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else {
1957            return;
1958        };
1959
1960        let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else {
1961            return;
1962        };
1963        let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
1964        let results = self.typeck_results.borrow();
1965        // First, look for a `Clone::clone` call
1966        if segment.ident.name == sym::clone
1967            && results.type_dependent_def_id(expr.hir_id).is_some_and(|did| {
1968                    let assoc_item = self.tcx.associated_item(did);
1969                    assoc_item.container == ty::AssocContainer::Trait
1970                        && assoc_item.container_id(self.tcx) == clone_trait_did
1971                })
1972            // If that clone call hasn't already dereferenced the self type (i.e. don't give this
1973            // diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
1974            && !results.expr_adjustments(callee_expr).iter().any(|adj| #[allow(non_exhaustive_omitted_patterns)] match adj.kind {
    ty::adjustment::Adjust::Deref(..) => true,
    _ => false,
}matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
1975            // Check that we're in fact trying to clone into the expected type
1976            && self.may_coerce(*pointee_ty, expected_ty)
1977            && let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty])
1978            // And the expected type doesn't implement `Clone`
1979            && !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
1980                self.tcx,
1981                traits::ObligationCause::dummy(),
1982                self.param_env,
1983                trait_ref,
1984            ))
1985        {
1986            diag.span_note(
1987                callee_expr.span,
1988                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not implement `Clone`, so `{1}` was cloned instead",
                expected_ty, found_ty))
    })format!(
1989                    "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
1990                ),
1991            );
1992            let owner = self.tcx.hir_enclosing_body_owner(expr.hir_id);
1993            if let ty::Param(param) = expected_ty.kind()
1994                && let Some(generics) = self.tcx.hir_get_generics(owner)
1995            {
1996                suggest_constraining_type_params(
1997                    self.tcx,
1998                    generics,
1999                    diag,
2000                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(param.name.as_str(), "Clone", Some(clone_trait_did))]))vec![(param.name.as_str(), "Clone", Some(clone_trait_did))].into_iter(),
2001                    None,
2002                );
2003            } else {
2004                let mut suggest_derive = true;
2005                if let Some(errors) =
2006                    self.type_implements_trait_shallow(clone_trait_did, expected_ty, self.param_env)
2007                {
2008                    let manually_impl = "consider manually implementing `Clone` to avoid the \
2009                        implicit type parameter bounds";
2010                    match &errors[..] {
2011                        [] => {}
2012                        [error] => {
2013                            let msg = "`Clone` is not implemented because a trait bound is not \
2014                                satisfied";
2015                            if let traits::ObligationCauseCode::ImplDerived(data) =
2016                                error.obligation.cause.code()
2017                            {
2018                                let mut span: MultiSpan = data.span.into();
2019                                if self.tcx.is_automatically_derived(data.impl_or_alias_def_id) {
2020                                    span.push_span_label(
2021                                        data.span,
2022                                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("derive introduces an implicit `{0}` bound",
                error.obligation.predicate))
    })format!(
2023                                            "derive introduces an implicit `{}` bound",
2024                                            error.obligation.predicate
2025                                        ),
2026                                    );
2027                                }
2028                                diag.span_help(span, msg);
2029                                if self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
2030                                    && data.impl_or_alias_def_id.is_local()
2031                                {
2032                                    diag.help(manually_impl);
2033                                    suggest_derive = false;
2034                                }
2035                            } else {
2036                                diag.help(msg);
2037                            }
2038                        }
2039                        _ => {
2040                            let unsatisfied_bounds: Vec<_> = errors
2041                                .iter()
2042                                .filter_map(|error| match error.obligation.cause.code() {
2043                                    traits::ObligationCauseCode::ImplDerived(data) => {
2044                                        let pre = if self
2045                                            .tcx
2046                                            .is_automatically_derived(data.impl_or_alias_def_id)
2047                                        {
2048                                            "derive introduces an implicit "
2049                                        } else {
2050                                            ""
2051                                        };
2052                                        Some((
2053                                            data.span,
2054                                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}unsatisfied trait bound `{0}`",
                error.obligation.predicate, pre))
    })format!(
2055                                                "{pre}unsatisfied trait bound `{}`",
2056                                                error.obligation.predicate
2057                                            ),
2058                                        ))
2059                                    }
2060                                    _ => None,
2061                                })
2062                                .collect();
2063                            let msg = "`Clone` is not implemented because the some trait bounds \
2064                                could not be satisfied";
2065                            if errors.len() == unsatisfied_bounds.len() {
2066                                let mut unsatisfied_bounds_spans: MultiSpan = unsatisfied_bounds
2067                                    .iter()
2068                                    .map(|(span, _)| *span)
2069                                    .collect::<Vec<Span>>()
2070                                    .into();
2071                                for (span, label) in unsatisfied_bounds {
2072                                    unsatisfied_bounds_spans.push_span_label(span, label);
2073                                }
2074                                diag.span_help(unsatisfied_bounds_spans, msg);
2075                                if errors.iter().all(|error| match error.obligation.cause.code() {
2076                                    traits::ObligationCauseCode::ImplDerived(data) => {
2077                                        self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
2078                                            && data.impl_or_alias_def_id.is_local()
2079                                    }
2080                                    _ => false,
2081                                }) {
2082                                    diag.help(manually_impl);
2083                                    suggest_derive = false;
2084                                }
2085                            } else {
2086                                diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}: {0}",
                listify(&errors,
                        |e|
                            ::alloc::__export::must_use({
                                    ::alloc::fmt::format(format_args!("`{0}`",
                                            e.obligation.predicate))
                                })).unwrap(), msg))
    })format!(
2087                                    "{msg}: {}",
2088                                    listify(&errors, |e| format!("`{}`", e.obligation.predicate))
2089                                        .unwrap(),
2090                                ));
2091                            }
2092                        }
2093                    }
2094                    for error in errors {
2095                        if let traits::FulfillmentErrorCode::Select(
2096                            traits::SelectionError::Unimplemented,
2097                        ) = error.code
2098                            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
2099                                error.obligation.predicate.kind().skip_binder()
2100                        {
2101                            self.infcx.err_ctxt().suggest_derive(
2102                                &error.obligation,
2103                                diag,
2104                                error.obligation.predicate.kind().rebind(pred),
2105                            );
2106                        }
2107                    }
2108                }
2109                if suggest_derive {
2110                    self.suggest_derive(diag, &::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(trait_ref.upcast(self.tcx), None, None)]))vec![(trait_ref.upcast(self.tcx), None, None)]);
2111                }
2112            }
2113        }
2114    }
2115
2116    /// Given a type mismatch error caused by `&T` being cloned instead of `T`, and
2117    /// the `expr` as the source of this type mismatch, try to find the method call
2118    /// as the source of this error and return that instead. Otherwise, return the
2119    /// original expression.
2120    fn note_type_is_not_clone_inner_expr<'b>(
2121        &'b self,
2122        expr: &'b hir::Expr<'b>,
2123    ) -> &'b hir::Expr<'b> {
2124        match expr.peel_blocks().kind {
2125            hir::ExprKind::Path(hir::QPath::Resolved(
2126                None,
2127                hir::Path { segments: [_], res: crate::Res::Local(binding), .. },
2128            )) => {
2129                let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding) else {
2130                    return expr;
2131                };
2132
2133                match self.tcx.parent_hir_node(*hir_id) {
2134                    // foo.clone()
2135                    hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
2136                        self.note_type_is_not_clone_inner_expr(init)
2137                    }
2138                    // When `expr` is more complex like a tuple
2139                    hir::Node::Pat(hir::Pat {
2140                        hir_id: pat_hir_id,
2141                        kind: hir::PatKind::Tuple(pats, ..),
2142                        ..
2143                    }) => {
2144                        let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
2145                            self.tcx.parent_hir_node(*pat_hir_id)
2146                        else {
2147                            return expr;
2148                        };
2149
2150                        match init.peel_blocks().kind {
2151                            ExprKind::Tup(init_tup) => {
2152                                if let Some(init) = pats
2153                                    .iter()
2154                                    .enumerate()
2155                                    .filter(|x| x.1.hir_id == *hir_id)
2156                                    .find_map(|(i, _)| init_tup.get(i))
2157                                {
2158                                    self.note_type_is_not_clone_inner_expr(init)
2159                                } else {
2160                                    expr
2161                                }
2162                            }
2163                            _ => expr,
2164                        }
2165                    }
2166                    _ => expr,
2167                }
2168            }
2169            // If we're calling into a closure that may not be typed recurse into that call. no need
2170            // to worry if it's a call to a typed function or closure as this would ne handled
2171            // previously.
2172            hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => {
2173                if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) =
2174                    call_expr_kind
2175                    && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } =
2176                        call_expr_path
2177                    && let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding)
2178                    && let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
2179                        self.tcx.parent_hir_node(*hir_id)
2180                    && let Expr {
2181                        kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
2182                        ..
2183                    } = init
2184                {
2185                    let hir::Body { value: body_expr, .. } = self.tcx.hir_body(*body_id);
2186                    self.note_type_is_not_clone_inner_expr(body_expr)
2187                } else {
2188                    expr
2189                }
2190            }
2191            _ => expr,
2192        }
2193    }
2194
2195    pub(crate) fn is_field_suggestable(
2196        &self,
2197        field: &ty::FieldDef,
2198        hir_id: HirId,
2199        span: Span,
2200    ) -> bool {
2201        // The field must be visible in the containing module.
2202        field.vis.is_accessible_from(self.tcx.parent_module(hir_id), self.tcx)
2203            // The field must not be unstable.
2204            && !#[allow(non_exhaustive_omitted_patterns)] match self.tcx.eval_stability(field.did,
        None, rustc_span::DUMMY_SP, None) {
    rustc_middle::middle::stability::EvalResult::Deny { .. } => true,
    _ => false,
}matches!(
2205                self.tcx.eval_stability(field.did, None, rustc_span::DUMMY_SP, None),
2206                rustc_middle::middle::stability::EvalResult::Deny { .. }
2207            )
2208            // If the field is from an external crate it must not be `doc(hidden)`.
2209            && (field.did.is_local() || !self.tcx.is_doc_hidden(field.did))
2210            // If the field is hygienic it must come from the same syntax context.
2211            && self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span)
2212    }
2213
2214    pub(crate) fn suggest_missing_unwrap_expect(
2215        &self,
2216        err: &mut Diag<'_>,
2217        expr: &hir::Expr<'tcx>,
2218        expected: Ty<'tcx>,
2219        found: Ty<'tcx>,
2220    ) -> bool {
2221        let ty::Adt(adt, args) = found.kind() else {
2222            return false;
2223        };
2224        let ret_ty_matches = |diagnostic_item| {
2225            let Some(sig) = self.body_fn_sig() else {
2226                return false;
2227            };
2228            let ty::Adt(kind, _) = sig.output().kind() else {
2229                return false;
2230            };
2231            self.tcx.is_diagnostic_item(diagnostic_item, kind.did())
2232        };
2233
2234        // don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`,
2235        // `None.unwrap()` etc.
2236        let is_ctor = #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    hir::ExprKind::Call(hir::Expr {
        kind: hir::ExprKind::Path(hir::QPath::Resolved(None, hir::Path {
            res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. })), .. }, ..)
        |
        hir::ExprKind::Path(hir::QPath::Resolved(None, hir::Path {
        res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. })) => true,
    _ => false,
}matches!(
2237            expr.kind,
2238            hir::ExprKind::Call(
2239                hir::Expr {
2240                    kind: hir::ExprKind::Path(hir::QPath::Resolved(
2241                        None,
2242                        hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
2243                    )),
2244                    ..
2245                },
2246                ..,
2247            ) | hir::ExprKind::Path(hir::QPath::Resolved(
2248                None,
2249                hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
2250            )),
2251        );
2252
2253        let (article, kind, variant, sugg_operator) = if self.tcx.is_diagnostic_item(sym::Result, adt.did())
2254            // Do not suggest `.expect()` in const context where it's not available. rust-lang/rust#149316
2255            && !self.tcx.hir_is_inside_const_context(expr.hir_id)
2256        {
2257            ("a", "Result", "Err", ret_ty_matches(sym::Result))
2258        } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) {
2259            ("an", "Option", "None", ret_ty_matches(sym::Option))
2260        } else {
2261            return false;
2262        };
2263        if is_ctor || !self.may_coerce(args.type_at(0), expected) {
2264            return false;
2265        }
2266
2267        let (msg, sugg) = if sugg_operator {
2268            (
2269                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("use the `?` operator to extract the `{0}` value, propagating {1} `{2}::{3}` value to the caller",
                found, article, kind, variant))
    })format!(
2270                    "use the `?` operator to extract the `{found}` value, propagating \
2271                            {article} `{kind}::{variant}` value to the caller"
2272                ),
2273                "?",
2274            )
2275        } else {
2276            (
2277                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider using `{0}::expect` to unwrap the `{1}` value, panicking if the value is {2} `{0}::{3}`",
                kind, found, article, variant))
    })format!(
2278                    "consider using `{kind}::expect` to unwrap the `{found}` value, \
2279                                panicking if the value is {article} `{kind}::{variant}`"
2280                ),
2281                ".expect(\"REASON\")",
2282            )
2283        };
2284
2285        let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
2286            Some(_) if expr.span.from_expansion() => return false,
2287            Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}{1}", ident, sugg))
    })format!(": {ident}{sugg}"),
2288            None => sugg.to_string(),
2289        };
2290
2291        let span = expr
2292            .span
2293            .find_ancestor_not_from_extern_macro(self.tcx.sess.source_map())
2294            .unwrap_or(expr.span);
2295        err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
2296        true
2297    }
2298
2299    pub(crate) fn suggest_coercing_result_via_try_operator(
2300        &self,
2301        err: &mut Diag<'_>,
2302        expr: &hir::Expr<'tcx>,
2303        expected: Ty<'tcx>,
2304        found: Ty<'tcx>,
2305    ) -> bool {
2306        let returned = #[allow(non_exhaustive_omitted_patterns)] match self.tcx.parent_hir_node(expr.hir_id)
    {
    hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }) => true,
    _ => false,
}matches!(
2307            self.tcx.parent_hir_node(expr.hir_id),
2308            hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
2309        ) || self.tcx.hir_get_fn_id_for_return_block(expr.hir_id).is_some();
2310        if returned
2311            && let ty::Adt(e, args_e) = expected.kind()
2312            && let ty::Adt(f, args_f) = found.kind()
2313            && e.did() == f.did()
2314            && Some(e.did()) == self.tcx.get_diagnostic_item(sym::Result)
2315            && let e_ok = args_e.type_at(0)
2316            && let f_ok = args_f.type_at(0)
2317            && self.infcx.can_eq(self.param_env, f_ok, e_ok)
2318            && let e_err = args_e.type_at(1)
2319            && let f_err = args_f.type_at(1)
2320            && self
2321                .infcx
2322                .type_implements_trait(
2323                    self.tcx.get_diagnostic_item(sym::Into).unwrap(),
2324                    [f_err, e_err],
2325                    self.param_env,
2326                )
2327                .must_apply_modulo_regions()
2328        {
2329            err.multipart_suggestion(
2330                "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
2331                 in `Ok` so the expression remains of type `Result`",
2332                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(), "Ok(".to_string()),
                (expr.span.shrink_to_hi(), "?)".to_string())]))vec![
2333                    (expr.span.shrink_to_lo(), "Ok(".to_string()),
2334                    (expr.span.shrink_to_hi(), "?)".to_string()),
2335                ],
2336                Applicability::MaybeIncorrect,
2337            );
2338            return true;
2339        }
2340        false
2341    }
2342
2343    // If the expr is a while or for loop and is the tail expr of its
2344    // enclosing body suggest returning a value right after it
2345    pub(crate) fn suggest_returning_value_after_loop(
2346        &self,
2347        err: &mut Diag<'_>,
2348        expr: &hir::Expr<'tcx>,
2349        expected: Ty<'tcx>,
2350    ) -> bool {
2351        let tcx = self.tcx;
2352        let enclosing_scope =
2353            tcx.hir_get_enclosing_scope(expr.hir_id).map(|hir_id| tcx.hir_node(hir_id));
2354
2355        // Get tail expr of the enclosing block or body
2356        let tail_expr = if let Some(Node::Block(hir::Block { expr, .. })) = enclosing_scope
2357            && expr.is_some()
2358        {
2359            *expr
2360        } else {
2361            let body_def_id = tcx.hir_enclosing_body_owner(expr.hir_id);
2362            let body = tcx.hir_body_owned_by(body_def_id);
2363
2364            // Get tail expr of the body
2365            match body.value.kind {
2366                // Regular function body etc.
2367                hir::ExprKind::Block(block, _) => block.expr,
2368                // Anon const body (there's no block in this case)
2369                hir::ExprKind::DropTemps(expr) => Some(expr),
2370                _ => None,
2371            }
2372        };
2373
2374        let Some(tail_expr) = tail_expr else {
2375            return false; // Body doesn't have a tail expr we can compare with
2376        };
2377
2378        // Get the loop expr within the tail expr
2379        let loop_expr_in_tail = match expr.kind {
2380            hir::ExprKind::Loop(_, _, hir::LoopSource::While, _) => tail_expr,
2381            hir::ExprKind::Loop(_, _, hir::LoopSource::ForLoop, _) => {
2382                match tail_expr.peel_drop_temps() {
2383                    Expr { kind: ExprKind::Match(_, [Arm { body, .. }], _), .. } => body,
2384                    _ => return false, // Not really a for loop
2385                }
2386            }
2387            _ => return false, // Not a while or a for loop
2388        };
2389
2390        // If the expr is the loop expr in the tail
2391        // then make the suggestion
2392        if expr.hir_id == loop_expr_in_tail.hir_id {
2393            let span = expr.span;
2394
2395            let (msg, suggestion) = if expected.is_never() {
2396                (
2397                    "consider adding a diverging expression here",
2398                    "`loop {}` or `panic!(\"...\")`".to_string(),
2399                )
2400            } else {
2401                ("consider returning a value here", ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` value", expected))
    })format!("`{expected}` value"))
2402            };
2403
2404            let src_map = tcx.sess.source_map();
2405            let suggestion = if src_map.is_multiline(expr.span) {
2406                let indentation = src_map.indentation_before(span).unwrap_or_default();
2407                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\n{0}/* {1} */", indentation,
                suggestion))
    })format!("\n{indentation}/* {suggestion} */")
2408            } else {
2409                // If the entire expr is on a single line
2410                // put the suggestion also on the same line
2411                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" /* {0} */", suggestion))
    })format!(" /* {suggestion} */")
2412            };
2413
2414            err.span_suggestion_verbose(
2415                span.shrink_to_hi(),
2416                msg,
2417                suggestion,
2418                Applicability::MaybeIncorrect,
2419            );
2420
2421            true
2422        } else {
2423            false
2424        }
2425    }
2426
2427    /// Suggest replacing comma with semicolon in incorrect repeat expressions
2428    /// like `["_", 10]` or `vec![String::new(), 10]`.
2429    pub(crate) fn suggest_semicolon_in_repeat_expr(
2430        &self,
2431        err: &mut Diag<'_>,
2432        expr: &hir::Expr<'_>,
2433        expr_ty: Ty<'tcx>,
2434    ) -> bool {
2435        // Check if `expr` is contained in array of two elements
2436        if let hir::Node::Expr(array_expr) = self.tcx.parent_hir_node(expr.hir_id)
2437            && let hir::ExprKind::Array(elements) = array_expr.kind
2438            && let [first, second] = elements
2439            && second.hir_id == expr.hir_id
2440        {
2441            // Span between the two elements of the array
2442            let comma_span = first.span.between(second.span);
2443
2444            // Check if `expr` is a constant value of type `usize`.
2445            // This can only detect const variable declarations and
2446            // calls to const functions.
2447
2448            // Checking this here instead of rustc_hir::hir because
2449            // this check needs access to `self.tcx` but rustc_hir
2450            // has no access to `TyCtxt`.
2451            let expr_is_const_usize = expr_ty.is_usize()
2452                && match expr.kind {
2453                    ExprKind::Path(QPath::Resolved(
2454                        None,
2455                        Path { res: Res::Def(DefKind::Const { .. }, _), .. },
2456                    )) => true,
2457                    ExprKind::Call(
2458                        Expr {
2459                            kind:
2460                                ExprKind::Path(QPath::Resolved(
2461                                    None,
2462                                    Path { res: Res::Def(DefKind::Fn, fn_def_id), .. },
2463                                )),
2464                            ..
2465                        },
2466                        _,
2467                    ) => self.tcx.is_const_fn(*fn_def_id),
2468                    _ => false,
2469                };
2470
2471            // Type of the first element is guaranteed to be checked
2472            // when execution reaches here because `mismatched types`
2473            // error occurs only when type of second element of array
2474            // is not the same as type of first element.
2475            let first_ty = self.typeck_results.borrow().expr_ty(first);
2476
2477            // `array_expr` is from a macro `vec!["a", 10]` if
2478            // 1. array expression's span is imported from a macro
2479            // 2. first element of array implements `Clone` trait
2480            // 3. second element is an integer literal or is an expression of `usize` like type
2481            if self.tcx.sess.source_map().is_imported(array_expr.span)
2482                && self.type_is_clone_modulo_regions(self.param_env, first_ty)
2483                && (expr.is_size_lit() || expr_ty.is_usize_like())
2484            {
2485                err.subdiagnostic(errors::ReplaceCommaWithSemicolon {
2486                    comma_span,
2487                    descr: "a vector",
2488                });
2489                return true;
2490            }
2491
2492            // `array_expr` is from an array `["a", 10]` if
2493            // 1. first element of array implements `Copy` trait
2494            // 2. second element is an integer literal or is a const value of type `usize`
2495            if self.type_is_copy_modulo_regions(self.param_env, first_ty)
2496                && (expr.is_size_lit() || expr_is_const_usize)
2497            {
2498                err.subdiagnostic(errors::ReplaceCommaWithSemicolon {
2499                    comma_span,
2500                    descr: "an array",
2501                });
2502                return true;
2503            }
2504        }
2505        false
2506    }
2507
2508    /// If the expected type is an enum (Issue #55250) with any variants whose
2509    /// sole field is of the found type, suggest such variants. (Issue #42764)
2510    pub(crate) fn suggest_compatible_variants(
2511        &self,
2512        err: &mut Diag<'_>,
2513        expr: &hir::Expr<'_>,
2514        expected: Ty<'tcx>,
2515        expr_ty: Ty<'tcx>,
2516    ) -> bool {
2517        if expr.span.in_external_macro(self.tcx.sess.source_map()) {
2518            return false;
2519        }
2520        if let ty::Adt(expected_adt, args) = expected.kind() {
2521            if let hir::ExprKind::Field(base, ident) = expr.kind {
2522                let base_ty = self.typeck_results.borrow().expr_ty(base);
2523                if self.can_eq(self.param_env, base_ty, expected)
2524                    && let Some(base_span) = base.span.find_ancestor_inside(expr.span)
2525                {
2526                    err.span_suggestion_verbose(
2527                        expr.span.with_lo(base_span.hi()),
2528                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider removing the tuple struct field `{0}`",
                ident))
    })format!("consider removing the tuple struct field `{ident}`"),
2529                        "",
2530                        Applicability::MaybeIncorrect,
2531                    );
2532                    return true;
2533                }
2534            }
2535
2536            // If the expression is of type () and it's the return expression of a block,
2537            // we suggest adding a separate return expression instead.
2538            // (To avoid things like suggesting `Ok(while .. { .. })`.)
2539            if expr_ty.is_unit() {
2540                let mut id = expr.hir_id;
2541                let mut parent;
2542
2543                // Unroll desugaring, to make sure this works for `for` loops etc.
2544                loop {
2545                    parent = self.tcx.parent_hir_id(id);
2546                    let parent_span = self.tcx.hir_span(parent);
2547                    if parent_span.find_ancestor_inside(expr.span).is_some() {
2548                        // The parent node is part of the same span, so is the result of the
2549                        // same expansion/desugaring and not the 'real' parent node.
2550                        id = parent;
2551                        continue;
2552                    }
2553                    break;
2554                }
2555
2556                if let hir::Node::Block(&hir::Block { span: block_span, expr: Some(e), .. }) =
2557                    self.tcx.hir_node(parent)
2558                {
2559                    if e.hir_id == id {
2560                        if let Some(span) = expr.span.find_ancestor_inside(block_span) {
2561                            let return_suggestions = if self
2562                                .tcx
2563                                .is_diagnostic_item(sym::Result, expected_adt.did())
2564                            {
2565                                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["Ok(())"]))vec!["Ok(())"]
2566                            } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
2567                                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["None", "Some(())"]))vec!["None", "Some(())"]
2568                            } else {
2569                                return false;
2570                            };
2571                            if let Some(indent) =
2572                                self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
2573                            {
2574                                // Add a semicolon, except after `}`.
2575                                let semicolon =
2576                                    match self.tcx.sess.source_map().span_to_snippet(span) {
2577                                        Ok(s) if s.ends_with('}') => "",
2578                                        _ => ";",
2579                                    };
2580                                err.span_suggestions(
2581                                    span.shrink_to_hi(),
2582                                    "try adding an expression at the end of the block",
2583                                    return_suggestions
2584                                        .into_iter()
2585                                        .map(|r| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}\n{1}{2}", semicolon, indent,
                r))
    })format!("{semicolon}\n{indent}{r}")),
2586                                    Applicability::MaybeIncorrect,
2587                                );
2588                            }
2589                            return true;
2590                        }
2591                    }
2592                }
2593            }
2594
2595            let compatible_variants: Vec<(String, _, _, Option<String>)> = expected_adt
2596                .variants()
2597                .iter()
2598                .filter(|variant| {
2599                    variant.fields.len() == 1
2600                })
2601                .filter_map(|variant| {
2602                    let sole_field = &variant.single_field();
2603
2604                    // When expected_ty and expr_ty are the same ADT, we prefer to compare their internal generic params,
2605                    // When the current variant has a sole field whose type is still an unresolved inference variable,
2606                    // suggestions would be often wrong. So suppress the suggestion. See #145294.
2607                    if let (ty::Adt(exp_adt, _), ty::Adt(act_adt, _)) = (expected.kind(), expr_ty.kind())
2608                        && exp_adt.did() == act_adt.did()
2609                        && sole_field.ty(self.tcx, args).is_ty_var() {
2610                            return None;
2611                    }
2612
2613                    let field_is_local = sole_field.did.is_local();
2614                    let field_is_accessible =
2615                        sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
2616                        // Skip suggestions for unstable public fields (for example `Pin::__pointer`)
2617                        && #[allow(non_exhaustive_omitted_patterns)] match self.tcx.eval_stability(sole_field.did,
        None, expr.span, None) {
    EvalResult::Allow | EvalResult::Unmarked => true,
    _ => false,
}matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
2618
2619                    if !field_is_local && !field_is_accessible {
2620                        return None;
2621                    }
2622
2623                    let note_about_variant_field_privacy = (field_is_local && !field_is_accessible)
2624                        .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
2625
2626                    let sole_field_ty = sole_field.ty(self.tcx, args);
2627                    if self.may_coerce(expr_ty, sole_field_ty) {
2628                        let variant_path =
2629                            { let _guard = NoTrimmedGuard::new(); self.tcx.def_path_str(variant.def_id) }with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
2630                        // FIXME #56861: DRYer prelude filtering
2631                        if let Some(path) = variant_path.strip_prefix("std::prelude::")
2632                            && let Some((_, path)) = path.split_once("::")
2633                        {
2634                            return Some((path.to_string(), variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy));
2635                        }
2636                        Some((variant_path, variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy))
2637                    } else {
2638                        None
2639                    }
2640                })
2641                .collect();
2642
2643            let suggestions_for = |variant: &_, ctor_kind, field_name| {
2644                let prefix = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
2645                    Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: "),
2646                    None => String::new(),
2647                };
2648
2649                let (open, close) = match ctor_kind {
2650                    Some(CtorKind::Fn) => ("(".to_owned(), ")"),
2651                    None => (::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" {{ {0}: ", field_name))
    })format!(" {{ {field_name}: "), " }"),
2652
2653                    Some(CtorKind::Const) => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("unit variants don\'t have fields")));
}unreachable!("unit variants don't have fields"),
2654                };
2655
2656                // Suggest constructor as deep into the block tree as possible.
2657                // This fixes https://github.com/rust-lang/rust/issues/101065,
2658                // and also just helps make the most minimal suggestions.
2659                let mut expr = expr;
2660                while let hir::ExprKind::Block(block, _) = &expr.kind
2661                    && let Some(expr_) = &block.expr
2662                {
2663                    expr = expr_
2664                }
2665
2666                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("{0}{1}{2}", prefix,
                                    variant, open))
                        })), (expr.span.shrink_to_hi(), close.to_owned())]))vec![
2667                    (expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
2668                    (expr.span.shrink_to_hi(), close.to_owned()),
2669                ]
2670            };
2671
2672            match &compatible_variants[..] {
2673                [] => { /* No variants to format */ }
2674                [(variant, ctor_kind, field_name, note)] => {
2675                    // Just a single matching variant.
2676                    err.multipart_suggestion(
2677                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("try wrapping the expression in `{1}`{0}",
                note.as_deref().unwrap_or(""), variant))
    })format!(
2678                            "try wrapping the expression in `{variant}`{note}",
2679                            note = note.as_deref().unwrap_or("")
2680                        ),
2681                        suggestions_for(&**variant, *ctor_kind, *field_name),
2682                        Applicability::MaybeIncorrect,
2683                    );
2684                    return true;
2685                }
2686                _ => {
2687                    // More than one matching variant.
2688                    err.multipart_suggestions(
2689                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("try wrapping the expression in a variant of `{0}`",
                self.tcx.def_path_str(expected_adt.did())))
    })format!(
2690                            "try wrapping the expression in a variant of `{}`",
2691                            self.tcx.def_path_str(expected_adt.did())
2692                        ),
2693                        compatible_variants.into_iter().map(
2694                            |(variant, ctor_kind, field_name, _)| {
2695                                suggestions_for(&variant, ctor_kind, field_name)
2696                            },
2697                        ),
2698                        Applicability::MaybeIncorrect,
2699                    );
2700                    return true;
2701                }
2702            }
2703        }
2704
2705        false
2706    }
2707
2708    pub(crate) fn suggest_non_zero_new_unwrap(
2709        &self,
2710        err: &mut Diag<'_>,
2711        expr: &hir::Expr<'_>,
2712        expected: Ty<'tcx>,
2713        expr_ty: Ty<'tcx>,
2714    ) -> bool {
2715        let tcx = self.tcx;
2716        let (adt, args, unwrap) = match expected.kind() {
2717            // In case `Option<NonZero<T>>` is wanted, but `T` is provided, suggest calling `new`.
2718            ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
2719                let nonzero_type = args.type_at(0); // Unwrap option type.
2720                let ty::Adt(adt, args) = nonzero_type.kind() else {
2721                    return false;
2722                };
2723                (adt, args, "")
2724            }
2725            // In case `NonZero<T>` is wanted but `T` is provided, also add `.unwrap()` to satisfy types.
2726            ty::Adt(adt, args) => (adt, args, ".unwrap()"),
2727            _ => return false,
2728        };
2729
2730        if !self.tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
2731            return false;
2732        }
2733
2734        let int_type = args.type_at(0);
2735        if !self.may_coerce(expr_ty, int_type) {
2736            return false;
2737        }
2738
2739        err.multipart_suggestion(
2740            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider calling `{0}::new`",
                sym::NonZero))
    })format!("consider calling `{}::new`", sym::NonZero),
2741            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(expr.span.shrink_to_lo(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("{0}::new(",
                                    sym::NonZero))
                        })),
                (expr.span.shrink_to_hi(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("){0}", unwrap))
                        }))]))vec![
2742                (expr.span.shrink_to_lo(), format!("{}::new(", sym::NonZero)),
2743                (expr.span.shrink_to_hi(), format!("){unwrap}")),
2744            ],
2745            Applicability::MaybeIncorrect,
2746        );
2747
2748        true
2749    }
2750
2751    /// Identify some cases where `as_ref()` would be appropriate and suggest it.
2752    ///
2753    /// Given the following code:
2754    /// ```compile_fail,E0308
2755    /// struct Foo;
2756    /// fn takes_ref(_: &Foo) {}
2757    /// let ref opt = Some(Foo);
2758    ///
2759    /// opt.map(|param| takes_ref(param));
2760    /// ```
2761    /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead.
2762    ///
2763    /// It only checks for `Option` and `Result` and won't work with
2764    /// ```ignore (illustrative)
2765    /// opt.map(|param| { takes_ref(param) });
2766    /// ```
2767    fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> {
2768        let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind else {
2769            return None;
2770        };
2771
2772        let hir::def::Res::Local(local_id) = path.res else {
2773            return None;
2774        };
2775
2776        let Node::Param(hir::Param { hir_id: param_hir_id, .. }) =
2777            self.tcx.parent_hir_node(local_id)
2778        else {
2779            return None;
2780        };
2781
2782        let Node::Expr(hir::Expr {
2783            hir_id: expr_hir_id,
2784            kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
2785            ..
2786        }) = self.tcx.parent_hir_node(*param_hir_id)
2787        else {
2788            return None;
2789        };
2790
2791        let hir = self.tcx.parent_hir_node(*expr_hir_id);
2792        let closure_params_len = closure_fn_decl.inputs.len();
2793        let (
2794            Node::Expr(hir::Expr {
2795                kind: hir::ExprKind::MethodCall(method_path, receiver, ..),
2796                ..
2797            }),
2798            1,
2799        ) = (hir, closure_params_len)
2800        else {
2801            return None;
2802        };
2803
2804        let self_ty = self.typeck_results.borrow().expr_ty(receiver);
2805        let name = method_path.ident.name;
2806        let is_as_ref_able = match self_ty.peel_refs().kind() {
2807            ty::Adt(def, _) => {
2808                (self.tcx.is_diagnostic_item(sym::Option, def.did())
2809                    || self.tcx.is_diagnostic_item(sym::Result, def.did()))
2810                    && (name == sym::map || name == sym::and_then)
2811            }
2812            _ => false,
2813        };
2814        if is_as_ref_able {
2815            Some((
2816                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())]))vec![(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())],
2817                "consider using `as_ref` instead",
2818            ))
2819        } else {
2820            None
2821        }
2822    }
2823
2824    /// This function is used to determine potential "simple" improvements or users' errors and
2825    /// provide them useful help. For example:
2826    ///
2827    /// ```compile_fail,E0308
2828    /// fn some_fn(s: &str) {}
2829    ///
2830    /// let x = "hey!".to_owned();
2831    /// some_fn(x); // error
2832    /// ```
2833    ///
2834    /// No need to find every potential function which could make a coercion to transform a
2835    /// `String` into a `&str` since a `&` would do the trick!
2836    ///
2837    /// In addition of this check, it also checks between references mutability state. If the
2838    /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
2839    /// `&mut`!".
2840    pub(crate) fn suggest_deref_or_ref(
2841        &self,
2842        expr: &hir::Expr<'tcx>,
2843        checked_ty: Ty<'tcx>,
2844        expected: Ty<'tcx>,
2845    ) -> Option<(
2846        Vec<(Span, String)>,
2847        String,
2848        Applicability,
2849        bool, /* verbose */
2850        bool, /* suggest `&` or `&mut` type annotation */
2851    )> {
2852        let sess = self.sess();
2853        let sp = expr.range_span().unwrap_or(expr.span);
2854        let sm = sess.source_map();
2855
2856        // If the span is from an external macro, there's no suggestion we can make.
2857        if sp.in_external_macro(sm) {
2858            return None;
2859        }
2860
2861        let replace_prefix = |s: &str, old: &str, new: &str| {
2862            s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
2863        };
2864
2865        // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
2866        let expr = expr.peel_drop_temps();
2867
2868        match (&expr.kind, expected.kind(), checked_ty.kind()) {
2869            (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) {
2870                (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
2871                    if let hir::ExprKind::Lit(_) = expr.kind
2872                        && let Ok(src) = sm.span_to_snippet(sp)
2873                        && replace_prefix(&src, "b\"", "\"").is_some()
2874                    {
2875                        let pos = sp.lo() + BytePos(1);
2876                        return Some((
2877                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(sp.with_hi(pos), String::new())]))vec![(sp.with_hi(pos), String::new())],
2878                            "consider removing the leading `b`".to_string(),
2879                            Applicability::MachineApplicable,
2880                            true,
2881                            false,
2882                        ));
2883                    }
2884                }
2885                (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
2886                    if let hir::ExprKind::Lit(_) = expr.kind
2887                        && let Ok(src) = sm.span_to_snippet(sp)
2888                        && replace_prefix(&src, "\"", "b\"").is_some()
2889                    {
2890                        return Some((
2891                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(sp.shrink_to_lo(), "b".to_string())]))vec![(sp.shrink_to_lo(), "b".to_string())],
2892                            "consider adding a leading `b`".to_string(),
2893                            Applicability::MachineApplicable,
2894                            true,
2895                            false,
2896                        ));
2897                    }
2898                }
2899                _ => {}
2900            },
2901            (_, &ty::Ref(_, _, mutability), _) => {
2902                // Check if it can work when put into a ref. For example:
2903                //
2904                // ```
2905                // fn bar(x: &mut i32) {}
2906                //
2907                // let x = 0u32;
2908                // bar(&x); // error, expected &mut
2909                // ```
2910                let ref_ty = match mutability {
2911                    hir::Mutability::Mut => {
2912                        Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
2913                    }
2914                    hir::Mutability::Not => {
2915                        Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
2916                    }
2917                };
2918                if self.may_coerce(ref_ty, expected) {
2919                    let mut sugg_sp = sp;
2920                    if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind {
2921                        let clone_trait =
2922                            self.tcx.require_lang_item(LangItem::Clone, segment.ident.span);
2923                        if args.is_empty()
2924                            && self
2925                                .typeck_results
2926                                .borrow()
2927                                .type_dependent_def_id(expr.hir_id)
2928                                .is_some_and(|did| {
2929                                    let ai = self.tcx.associated_item(did);
2930                                    ai.trait_container(self.tcx) == Some(clone_trait)
2931                                })
2932                            && segment.ident.name == sym::clone
2933                        {
2934                            // If this expression had a clone call when suggesting borrowing
2935                            // we want to suggest removing it because it'd now be unnecessary.
2936                            sugg_sp = receiver.span;
2937                        }
2938                    }
2939
2940                    if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
2941                        && let Some(1) = self.deref_steps_for_suggestion(expected, checked_ty)
2942                        && self.typeck_results.borrow().expr_ty(inner).is_ref()
2943                    {
2944                        // We have `*&T`, check if what was expected was `&T`.
2945                        // If so, we may want to suggest removing a `*`.
2946                        sugg_sp = sugg_sp.with_hi(inner.span.lo());
2947                        return Some((
2948                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(sugg_sp, String::new())]))vec![(sugg_sp, String::new())],
2949                            "consider removing deref here".to_string(),
2950                            Applicability::MachineApplicable,
2951                            true,
2952                            false,
2953                        ));
2954                    }
2955
2956                    // Don't try to suggest ref/deref on an `if` expression, because:
2957                    // - The `if` could be part of a desugared `if else` statement,
2958                    //   which would create impossible suggestions such as `if ... { ... } else &if { ... } else { ... }`.
2959                    // - In general the suggestions it creates such as `&if ... { ... } else { ... }` are not very helpful.
2960                    // We try to generate a suggestion such as `if ... { &... } else { &... }` instead.
2961                    if let hir::ExprKind::If(_c, then, els) = expr.kind {
2962                        // The `then` of a `Expr::If` always contains a block, and that block may have a final expression that we can borrow
2963                        // If the block does not have a final expression, it will return () and we do not make a suggestion to borrow that.
2964                        let ExprKind::Block(then, _) = then.kind else { return None };
2965                        let Some(then) = then.expr else { return None };
2966                        let (mut suggs, help, app, verbose, mutref) =
2967                            self.suggest_deref_or_ref(then, checked_ty, expected)?;
2968
2969                        // If there is no `else`, the return type of this `if` will be (), so suggesting to change the `then` block is useless
2970                        let els_expr = match els?.kind {
2971                            ExprKind::Block(block, _) => block.expr?,
2972                            _ => els?,
2973                        };
2974                        let (else_suggs, ..) =
2975                            self.suggest_deref_or_ref(els_expr, checked_ty, expected)?;
2976                        suggs.extend(else_suggs);
2977
2978                        return Some((suggs, help, app, verbose, mutref));
2979                    }
2980
2981                    if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
2982                        return Some((
2983                            sugg,
2984                            msg.to_string(),
2985                            Applicability::MachineApplicable,
2986                            true,
2987                            false,
2988                        ));
2989                    }
2990
2991                    let prefix = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
2992                        Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: "),
2993                        None => String::new(),
2994                    };
2995
2996                    if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(..), .. }) =
2997                        self.tcx.parent_hir_node(expr.hir_id)
2998                    {
2999                        if mutability.is_mut() {
3000                            // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
3001                            return None;
3002                        }
3003                    }
3004
3005                    let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
3006                        if expr_needs_parens(expr) {
3007                            (
3008                                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span.shrink_to_lo(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("{0}{1}(", prefix, sugg))
                        })), (span.shrink_to_hi(), ")".to_string())]))vec![
3009                                    (span.shrink_to_lo(), format!("{prefix}{sugg}(")),
3010                                    (span.shrink_to_hi(), ")".to_string()),
3011                                ],
3012                                false,
3013                            )
3014                        } else {
3015                            (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span.shrink_to_lo(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("{0}{1}", prefix, sugg))
                        }))]))vec![(span.shrink_to_lo(), format!("{prefix}{sugg}"))], true)
3016                        }
3017                    };
3018
3019                    // Suggest dereferencing the lhs for expressions such as `&T <= T`
3020                    if let hir::Node::Expr(hir::Expr {
3021                        kind: hir::ExprKind::Binary(_, lhs, ..),
3022                        ..
3023                    }) = self.tcx.parent_hir_node(expr.hir_id)
3024                        && let &ty::Ref(..) = self.check_expr(lhs).kind()
3025                    {
3026                        let (sugg, verbose) = make_sugg(lhs, lhs.span, "*");
3027
3028                        return Some((
3029                            sugg,
3030                            "consider dereferencing the borrow".to_string(),
3031                            Applicability::MachineApplicable,
3032                            verbose,
3033                            false,
3034                        ));
3035                    }
3036
3037                    let sugg = mutability.ref_prefix_str();
3038                    let (sugg, verbose) = make_sugg(expr, sp, sugg);
3039                    return Some((
3040                        sugg,
3041                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider {0}borrowing here",
                mutability.mutably_str()))
    })format!("consider {}borrowing here", mutability.mutably_str()),
3042                        Applicability::MachineApplicable,
3043                        verbose,
3044                        false,
3045                    ));
3046                }
3047            }
3048            (hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr), _, &ty::Ref(_, checked, _))
3049                if self.can_eq(self.param_env, checked, expected) =>
3050            {
3051                let make_sugg = |start: Span, end: BytePos| {
3052                    // skip `(` for tuples such as `(c) = (&123)`.
3053                    // make sure we won't suggest like `(c) = 123)` which is incorrect.
3054                    let sp = sm
3055                        .span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
3056                        .map_or(start, |s| s.shrink_to_hi());
3057                    Some((
3058                        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(sp.with_hi(end), String::new())]))vec![(sp.with_hi(end), String::new())],
3059                        "consider removing the borrow".to_string(),
3060                        Applicability::MachineApplicable,
3061                        true,
3062                        true,
3063                    ))
3064                };
3065
3066                // We have `&T`, check if what was expected was `T`. If so,
3067                // we may want to suggest removing a `&`.
3068                if sm.is_imported(expr.span) {
3069                    // Go through the spans from which this span was expanded,
3070                    // and find the one that's pointing inside `sp`.
3071                    //
3072                    // E.g. for `&format!("")`, where we want the span to the
3073                    // `format!()` invocation instead of its expansion.
3074                    if let Some(call_span) =
3075                        iter::successors(Some(expr.span), |s| s.parent_callsite())
3076                            .find(|&s| sp.contains(s))
3077                        && sm.is_span_accessible(call_span)
3078                    {
3079                        return make_sugg(sp, call_span.lo());
3080                    }
3081                    return None;
3082                }
3083                if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
3084                    return make_sugg(sp, expr.span.lo());
3085                }
3086            }
3087            (_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => {
3088                if let Some(steps) = self.deref_steps_for_suggestion(ty_a, ty_b)
3089                    // Only suggest valid if dereferencing needed.
3090                    && steps > 0
3091                    // The pointer type implements `Copy` trait so the suggestion is always valid.
3092                    && let Ok(src) = sm.span_to_snippet(sp)
3093                {
3094                    let derefs = "*".repeat(steps);
3095                    let old_prefix = mutbl_a.ref_prefix_str();
3096                    let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs;
3097
3098                    let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| {
3099                        // skip `&` or `&mut ` if both mutabilities are mutable
3100                        let lo = sp.lo()
3101                            + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
3102                        // skip `&` or `&mut `
3103                        let hi = sp.lo() + BytePos(old_prefix.len() as _);
3104                        let sp = sp.with_lo(lo).with_hi(hi);
3105
3106                        (
3107                            sp,
3108                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}",
                if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" },
                derefs))
    })format!(
3109                                "{}{derefs}",
3110                                if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }
3111                            ),
3112                            if mutbl_b <= mutbl_a {
3113                                Applicability::MachineApplicable
3114                            } else {
3115                                Applicability::MaybeIncorrect
3116                            },
3117                        )
3118                    });
3119
3120                    if let Some((span, src, applicability)) = suggestion {
3121                        return Some((
3122                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span, src)]))vec![(span, src)],
3123                            "consider dereferencing".to_string(),
3124                            applicability,
3125                            true,
3126                            false,
3127                        ));
3128                    }
3129                }
3130            }
3131            _ if sp == expr.span => {
3132                if let Some(mut steps) = self.deref_steps_for_suggestion(checked_ty, expected) {
3133                    let mut expr = expr.peel_blocks();
3134                    let mut prefix_span = expr.span.shrink_to_lo();
3135                    let mut remove = String::new();
3136
3137                    // Try peeling off any existing `&` and `&mut` to reach our target type
3138                    while steps > 0 {
3139                        if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind {
3140                            // If the expression has `&`, removing it would fix the error
3141                            prefix_span = prefix_span.with_hi(inner.span.lo());
3142                            expr = inner;
3143                            remove.push_str(mutbl.ref_prefix_str());
3144                            steps -= 1;
3145                        } else {
3146                            break;
3147                        }
3148                    }
3149                    // If we've reached our target type with just removing `&`, then just print now.
3150                    if steps == 0 && !remove.trim().is_empty() {
3151                        return Some((
3152                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(prefix_span, String::new())]))vec![(prefix_span, String::new())],
3153                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider removing the `{0}`",
                remove.trim()))
    })format!("consider removing the `{}`", remove.trim()),
3154                            // Do not remove `&&` to get to bool, because it might be something like
3155                            // { a } && b, which we have a separate fixup suggestion that is more
3156                            // likely correct...
3157                            if remove.trim() == "&&" && expected == self.tcx.types.bool {
3158                                Applicability::MaybeIncorrect
3159                            } else {
3160                                Applicability::MachineApplicable
3161                            },
3162                            true,
3163                            false,
3164                        ));
3165                    }
3166
3167                    // For this suggestion to make sense, the type would need to be `Copy`,
3168                    // or we have to be moving out of a `Box<T>`
3169                    if self.type_is_copy_modulo_regions(self.param_env, expected)
3170                        // FIXME(compiler-errors): We can actually do this if the checked_ty is
3171                        // `steps` layers of boxes, not just one, but this is easier and most likely.
3172                        || (checked_ty.is_box() && steps == 1)
3173                        // We can always deref a binop that takes its arguments by ref.
3174                        || #[allow(non_exhaustive_omitted_patterns)] match self.tcx.parent_hir_node(expr.hir_id)
    {
    hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. }) if
        !op.node.is_by_value() => true,
    _ => false,
}matches!(
3175                            self.tcx.parent_hir_node(expr.hir_id),
3176                            hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. })
3177                                if !op.node.is_by_value()
3178                        )
3179                    {
3180                        let deref_kind = if checked_ty.is_box() {
3181                            // detect Box::new(..)
3182                            if let ExprKind::Call(box_new, [_]) = expr.kind
3183                                && let ExprKind::Path(qpath) = &box_new.kind
3184                                && let Res::Def(DefKind::AssocFn, fn_id) =
3185                                    self.typeck_results.borrow().qpath_res(qpath, box_new.hir_id)
3186                                && self.tcx.is_diagnostic_item(sym::box_new, fn_id)
3187                            {
3188                                let l_paren = self.tcx.sess.source_map().next_point(box_new.span);
3189                                let r_paren = self.tcx.sess.source_map().end_point(expr.span);
3190                                return Some((
3191                                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(box_new.span.to(l_paren), String::new()),
                (r_paren, String::new())]))vec![
3192                                        (box_new.span.to(l_paren), String::new()),
3193                                        (r_paren, String::new()),
3194                                    ],
3195                                    "consider removing the Box".to_string(),
3196                                    Applicability::MachineApplicable,
3197                                    false,
3198                                    false,
3199                                ));
3200                            }
3201                            "unboxing the value"
3202                        } else if checked_ty.is_ref() {
3203                            "dereferencing the borrow"
3204                        } else {
3205                            "dereferencing the type"
3206                        };
3207
3208                        // Suggest removing `&` if we have removed any, otherwise suggest just
3209                        // dereferencing the remaining number of steps.
3210                        let message = if remove.is_empty() {
3211                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider {0}", deref_kind))
    })format!("consider {deref_kind}")
3212                        } else {
3213                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider removing the `{0}` and {1} instead",
                remove.trim(), deref_kind))
    })format!(
3214                                "consider removing the `{}` and {} instead",
3215                                remove.trim(),
3216                                deref_kind
3217                            )
3218                        };
3219
3220                        let prefix =
3221                            match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
3222                                Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: "),
3223                                None => String::new(),
3224                            };
3225
3226                        let (span, suggestion) = if self.is_else_if_block(expr) {
3227                            // Don't suggest nonsense like `else *if`
3228                            return None;
3229                        } else if let Some(expr) = self.maybe_get_block_expr(expr) {
3230                            // prefix should be empty here..
3231                            (expr.span.shrink_to_lo(), "*".to_string())
3232                        } else {
3233                            (prefix_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", prefix,
                "*".repeat(steps)))
    })format!("{}{}", prefix, "*".repeat(steps)))
3234                        };
3235                        if suggestion.trim().is_empty() {
3236                            return None;
3237                        }
3238
3239                        if expr_needs_parens(expr) {
3240                            return Some((
3241                                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span,
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("{0}(", suggestion))
                        })), (expr.span.shrink_to_hi(), ")".to_string())]))vec![
3242                                    (span, format!("{suggestion}(")),
3243                                    (expr.span.shrink_to_hi(), ")".to_string()),
3244                                ],
3245                                message,
3246                                Applicability::MachineApplicable,
3247                                true,
3248                                false,
3249                            ));
3250                        }
3251
3252                        return Some((
3253                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span, suggestion)]))vec![(span, suggestion)],
3254                            message,
3255                            Applicability::MachineApplicable,
3256                            true,
3257                            false,
3258                        ));
3259                    }
3260                }
3261            }
3262            _ => {}
3263        }
3264        None
3265    }
3266
3267    /// Returns whether the given expression is an `else if`.
3268    fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
3269        if let hir::ExprKind::If(..) = expr.kind
3270            && let Node::Expr(hir::Expr { kind: hir::ExprKind::If(_, _, Some(else_expr)), .. }) =
3271                self.tcx.parent_hir_node(expr.hir_id)
3272        {
3273            return else_expr.hir_id == expr.hir_id;
3274        }
3275        false
3276    }
3277
3278    pub(crate) fn suggest_cast(
3279        &self,
3280        err: &mut Diag<'_>,
3281        expr: &hir::Expr<'_>,
3282        checked_ty: Ty<'tcx>,
3283        expected_ty: Ty<'tcx>,
3284        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
3285    ) -> bool {
3286        if self.tcx.sess.source_map().is_imported(expr.span) {
3287            // Ignore if span is from within a macro.
3288            return false;
3289        }
3290
3291        let span = if let hir::ExprKind::Lit(lit) = &expr.kind { lit.span } else { expr.span };
3292        let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) else {
3293            return false;
3294        };
3295
3296        // If casting this expression to a given numeric type would be appropriate in case of a type
3297        // mismatch.
3298        //
3299        // We want to minimize the amount of casting operations that are suggested, as it can be a
3300        // lossy operation with potentially bad side effects, so we only suggest when encountering
3301        // an expression that indicates that the original type couldn't be directly changed.
3302        //
3303        // For now, don't suggest casting with `as`.
3304        let can_cast = false;
3305
3306        let mut sugg = ::alloc::vec::Vec::new()vec![];
3307
3308        if let hir::Node::ExprField(field) = self.tcx.parent_hir_node(expr.hir_id) {
3309            // `expr` is a literal field for a struct, only suggest if appropriate
3310            if field.is_shorthand {
3311                // This is a field literal
3312                sugg.push((field.ident.span.shrink_to_lo(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", field.ident))
    })format!("{}: ", field.ident)));
3313            } else {
3314                // Likely a field was meant, but this field wasn't found. Do not suggest anything.
3315                return false;
3316            }
3317        };
3318
3319        if let hir::ExprKind::Call(path, args) = &expr.kind
3320            && let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
3321                (&path.kind, args.len())
3322            // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697).
3323            && let (hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), sym::from) =
3324                (&base_ty.kind, path_segment.ident.name)
3325        {
3326            if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() {
3327                match ident.name {
3328                    sym::i128
3329                    | sym::i64
3330                    | sym::i32
3331                    | sym::i16
3332                    | sym::i8
3333                    | sym::u128
3334                    | sym::u64
3335                    | sym::u32
3336                    | sym::u16
3337                    | sym::u8
3338                    | sym::isize
3339                    | sym::usize
3340                        if base_ty_path.segments.len() == 1 =>
3341                    {
3342                        return false;
3343                    }
3344                    _ => {}
3345                }
3346            }
3347        }
3348
3349        let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("you can convert {0} `{1}` to {2} `{3}`",
                checked_ty.kind().article(), checked_ty,
                expected_ty.kind().article(), expected_ty))
    })format!(
3350            "you can convert {} `{}` to {} `{}`",
3351            checked_ty.kind().article(),
3352            checked_ty,
3353            expected_ty.kind().article(),
3354            expected_ty,
3355        );
3356        let cast_msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("you can cast {0} `{1}` to {2} `{3}`",
                checked_ty.kind().article(), checked_ty,
                expected_ty.kind().article(), expected_ty))
    })format!(
3357            "you can cast {} `{}` to {} `{}`",
3358            checked_ty.kind().article(),
3359            checked_ty,
3360            expected_ty.kind().article(),
3361            expected_ty,
3362        );
3363        let lit_msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("change the type of the numeric literal from `{0}` to `{1}`",
                checked_ty, expected_ty))
    })format!(
3364            "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
3365        );
3366
3367        let close_paren = if self.precedence(expr) < ExprPrecedence::Unambiguous {
3368            sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
3369            ")"
3370        } else {
3371            ""
3372        };
3373
3374        let mut cast_suggestion = sugg.clone();
3375        cast_suggestion.push((expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} as {1}", close_paren,
                expected_ty))
    })format!("{close_paren} as {expected_ty}")));
3376        let mut into_suggestion = sugg.clone();
3377        into_suggestion.push((expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}.into()", close_paren))
    })format!("{close_paren}.into()")));
3378        let mut suffix_suggestion = sugg.clone();
3379        suffix_suggestion.push((
3380            if #[allow(non_exhaustive_omitted_patterns)] match (expected_ty.kind(),
        checked_ty.kind()) {
    (ty::Int(_) | ty::Uint(_), ty::Float(_)) => true,
    _ => false,
}matches!(
3381                (expected_ty.kind(), checked_ty.kind()),
3382                (ty::Int(_) | ty::Uint(_), ty::Float(_))
3383            ) {
3384                // Remove fractional part from literal, for example `42.0f32` into `42`
3385                let src = src.trim_end_matches(&checked_ty.to_string());
3386                let len = src.split('.').next().unwrap().len();
3387                span.with_lo(span.lo() + BytePos(len as u32))
3388            } else {
3389                let len = src.trim_end_matches(&checked_ty.to_string()).len();
3390                span.with_lo(span.lo() + BytePos(len as u32))
3391            },
3392            if self.precedence(expr) < ExprPrecedence::Unambiguous {
3393                // Readd `)`
3394                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0})", expected_ty))
    })format!("{expected_ty})")
3395            } else {
3396                expected_ty.to_string()
3397            },
3398        ));
3399        let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
3400            if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
3401        };
3402        let is_negative_int =
3403            |expr: &hir::Expr<'_>| #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    hir::ExprKind::Unary(hir::UnOp::Neg, ..) => true,
    _ => false,
}matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Neg, ..));
3404        let is_uint = |ty: Ty<'_>| #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Uint(..) => true,
    _ => false,
}matches!(ty.kind(), ty::Uint(..));
3405
3406        let in_const_context = self.tcx.hir_is_inside_const_context(expr.hir_id);
3407
3408        let suggest_fallible_into_or_lhs_from =
3409            |err: &mut Diag<'_>, exp_to_found_is_fallible: bool| {
3410                // If we know the expression the expected type is derived from, we might be able
3411                // to suggest a widening conversion rather than a narrowing one (which may
3412                // panic). For example, given x: u8 and y: u32, if we know the span of "x",
3413                //   x > y
3414                // can be given the suggestion "u32::from(x) > y" rather than
3415                // "x > y.try_into().unwrap()".
3416                let lhs_expr_and_src = expected_ty_expr.and_then(|expr| {
3417                    self.tcx
3418                        .sess
3419                        .source_map()
3420                        .span_to_snippet(expr.span)
3421                        .ok()
3422                        .map(|src| (expr, src))
3423                });
3424                let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
3425                    (lhs_expr_and_src, exp_to_found_is_fallible)
3426                {
3427                    let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("you can convert `{0}` from `{1}` to `{2}`, matching the type of `{3}`",
                lhs_src, expected_ty, checked_ty, src))
    })format!(
3428                        "you can convert `{lhs_src}` from `{expected_ty}` to `{checked_ty}`, matching the type of `{src}`",
3429                    );
3430                    let suggestion = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(lhs_expr.span.shrink_to_lo(),
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!("{0}::from(", checked_ty))
                        })), (lhs_expr.span.shrink_to_hi(), ")".to_string())]))vec![
3431                        (lhs_expr.span.shrink_to_lo(), format!("{checked_ty}::from(")),
3432                        (lhs_expr.span.shrink_to_hi(), ")".to_string()),
3433                    ];
3434                    (msg, suggestion)
3435                } else {
3436                    let msg =
3437                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} and panic if the converted value doesn\'t fit",
                msg.clone()))
    })format!("{} and panic if the converted value doesn't fit", msg.clone());
3438                    let mut suggestion = sugg.clone();
3439                    suggestion.push((
3440                        expr.span.shrink_to_hi(),
3441                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}.try_into().unwrap()",
                close_paren))
    })format!("{close_paren}.try_into().unwrap()"),
3442                    ));
3443                    (msg, suggestion)
3444                };
3445                err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);
3446            };
3447
3448        let suggest_to_change_suffix_or_into =
3449            |err: &mut Diag<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| {
3450                let exp_is_lhs = expected_ty_expr.is_some_and(|e| self.tcx.hir_is_lhs(e.hir_id));
3451
3452                if exp_is_lhs {
3453                    return;
3454                }
3455
3456                let always_fallible = found_to_exp_is_fallible
3457                    && (exp_to_found_is_fallible || expected_ty_expr.is_none());
3458                let msg = if literal_is_ty_suffixed(expr) {
3459                    lit_msg.clone()
3460                } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
3461                    // We now know that converting either the lhs or rhs is fallible. Before we
3462                    // suggest a fallible conversion, check if the value can never fit in the
3463                    // expected type.
3464                    let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` cannot fit into type `{1}`",
                src, expected_ty))
    })format!("`{src}` cannot fit into type `{expected_ty}`");
3465                    err.note(msg);
3466                    return;
3467                } else if in_const_context {
3468                    // Do not recommend `into` or `try_into` in const contexts.
3469                    return;
3470                } else if found_to_exp_is_fallible {
3471                    return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible);
3472                } else {
3473                    msg.clone()
3474                };
3475                let suggestion = if literal_is_ty_suffixed(expr) {
3476                    suffix_suggestion.clone()
3477                } else {
3478                    into_suggestion.clone()
3479                };
3480                err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);
3481            };
3482
3483        match (expected_ty.kind(), checked_ty.kind()) {
3484            (ty::Int(exp), ty::Int(found)) => {
3485                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3486                {
3487                    (Some(exp), Some(found)) if exp < found => (true, false),
3488                    (Some(exp), Some(found)) if exp > found => (false, true),
3489                    (None, Some(8 | 16)) => (false, true),
3490                    (Some(8 | 16), None) => (true, false),
3491                    (None, _) | (_, None) => (true, true),
3492                    _ => (false, false),
3493                };
3494                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3495                true
3496            }
3497            (ty::Uint(exp), ty::Uint(found)) => {
3498                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3499                {
3500                    (Some(exp), Some(found)) if exp < found => (true, false),
3501                    (Some(exp), Some(found)) if exp > found => (false, true),
3502                    (None, Some(8 | 16)) => (false, true),
3503                    (Some(8 | 16), None) => (true, false),
3504                    (None, _) | (_, None) => (true, true),
3505                    _ => (false, false),
3506                };
3507                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3508                true
3509            }
3510            (&ty::Int(exp), &ty::Uint(found)) => {
3511                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3512                {
3513                    (Some(exp), Some(found)) if found < exp => (false, true),
3514                    (None, Some(8)) => (false, true),
3515                    _ => (true, true),
3516                };
3517                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3518                true
3519            }
3520            (&ty::Uint(exp), &ty::Int(found)) => {
3521                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3522                {
3523                    (Some(exp), Some(found)) if found > exp => (true, false),
3524                    (Some(8), None) => (true, false),
3525                    _ => (true, true),
3526                };
3527                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3528                true
3529            }
3530            (ty::Float(exp), ty::Float(found)) => {
3531                if found.bit_width() < exp.bit_width() {
3532                    suggest_to_change_suffix_or_into(err, false, true);
3533                } else if literal_is_ty_suffixed(expr) {
3534                    err.multipart_suggestion(
3535                        lit_msg,
3536                        suffix_suggestion,
3537                        Applicability::MachineApplicable,
3538                    );
3539                } else if can_cast {
3540                    // Missing try_into implementation for `f64` to `f32`
3541                    err.multipart_suggestion(
3542                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the closest possible value",
                cast_msg))
    })format!("{cast_msg}, producing the closest possible value"),
3543                        cast_suggestion,
3544                        Applicability::MaybeIncorrect, // lossy conversion
3545                    );
3546                }
3547                true
3548            }
3549            (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
3550                if literal_is_ty_suffixed(expr) {
3551                    err.multipart_suggestion(
3552                        lit_msg,
3553                        suffix_suggestion,
3554                        Applicability::MachineApplicable,
3555                    );
3556                } else if can_cast {
3557                    // Missing try_into implementation for `{float}` to `{integer}`
3558                    err.multipart_suggestion(
3559                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, rounding the float towards zero",
                msg))
    })format!("{msg}, rounding the float towards zero"),
3560                        cast_suggestion,
3561                        Applicability::MaybeIncorrect, // lossy conversion
3562                    );
3563                }
3564                true
3565            }
3566            (ty::Float(exp), ty::Uint(found)) => {
3567                // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
3568                if exp.bit_width() > found.bit_width().unwrap_or(256) {
3569                    err.multipart_suggestion(
3570                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer",
                msg))
    })format!(
3571                            "{msg}, producing the floating point representation of the integer",
3572                        ),
3573                        into_suggestion,
3574                        Applicability::MachineApplicable,
3575                    );
3576                } else if literal_is_ty_suffixed(expr) {
3577                    err.multipart_suggestion(
3578                        lit_msg,
3579                        suffix_suggestion,
3580                        Applicability::MachineApplicable,
3581                    );
3582                } else {
3583                    // Missing try_into implementation for `{integer}` to `{float}`
3584                    err.multipart_suggestion(
3585                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer, rounded if necessary",
                cast_msg))
    })format!(
3586                            "{cast_msg}, producing the floating point representation of the integer, \
3587                                 rounded if necessary",
3588                        ),
3589                        cast_suggestion,
3590                        Applicability::MaybeIncorrect, // lossy conversion
3591                    );
3592                }
3593                true
3594            }
3595            (ty::Float(exp), ty::Int(found)) => {
3596                // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
3597                if exp.bit_width() > found.bit_width().unwrap_or(256) {
3598                    err.multipart_suggestion(
3599                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer",
                msg.clone()))
    })format!(
3600                            "{}, producing the floating point representation of the integer",
3601                            msg.clone(),
3602                        ),
3603                        into_suggestion,
3604                        Applicability::MachineApplicable,
3605                    );
3606                } else if literal_is_ty_suffixed(expr) {
3607                    err.multipart_suggestion(
3608                        lit_msg,
3609                        suffix_suggestion,
3610                        Applicability::MachineApplicable,
3611                    );
3612                } else {
3613                    // Missing try_into implementation for `{integer}` to `{float}`
3614                    err.multipart_suggestion(
3615                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer, rounded if necessary",
                &msg))
    })format!(
3616                            "{}, producing the floating point representation of the integer, \
3617                                rounded if necessary",
3618                            &msg,
3619                        ),
3620                        cast_suggestion,
3621                        Applicability::MaybeIncorrect, // lossy conversion
3622                    );
3623                }
3624                true
3625            }
3626            (
3627                &ty::Uint(ty::UintTy::U32 | ty::UintTy::U64 | ty::UintTy::U128)
3628                | &ty::Int(ty::IntTy::I32 | ty::IntTy::I64 | ty::IntTy::I128),
3629                &ty::Char,
3630            ) => {
3631                err.multipart_suggestion(
3632                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, since a `char` always occupies 4 bytes",
                cast_msg))
    })format!("{cast_msg}, since a `char` always occupies 4 bytes"),
3633                    cast_suggestion,
3634                    Applicability::MachineApplicable,
3635                );
3636                true
3637            }
3638            _ => false,
3639        }
3640    }
3641
3642    /// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
3643    pub(crate) fn suggest_method_call_on_range_literal(
3644        &self,
3645        err: &mut Diag<'_>,
3646        expr: &hir::Expr<'tcx>,
3647        checked_ty: Ty<'tcx>,
3648        expected_ty: Ty<'tcx>,
3649    ) {
3650        if !hir::is_range_literal(expr) {
3651            return;
3652        }
3653        let hir::ExprKind::Struct(&qpath, [start, end], _) = expr.kind else {
3654            return;
3655        };
3656        if !self.tcx.qpath_is_lang_item(qpath, LangItem::Range) {
3657            return;
3658        }
3659        if let hir::Node::ExprField(_) = self.tcx.parent_hir_node(expr.hir_id) {
3660            // Ignore `Foo { field: a..Default::default() }`
3661            return;
3662        }
3663        let mut expr = end.expr;
3664        let mut expectation = Some(expected_ty);
3665        while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind {
3666            // Getting to the root receiver and asserting it is a fn call let's us ignore cases in
3667            // `tests/ui/methods/issues/issue-90315.stderr`.
3668            expr = rcvr;
3669            // If we have more than one layer of calls, then the expected ty
3670            // cannot guide the method probe.
3671            expectation = None;
3672        }
3673        let hir::ExprKind::Call(method_name, _) = expr.kind else {
3674            return;
3675        };
3676        let ty::Adt(adt, _) = checked_ty.kind() else {
3677            return;
3678        };
3679        if self.tcx.lang_items().range_struct() != Some(adt.did()) {
3680            return;
3681        }
3682        if let ty::Adt(adt, _) = expected_ty.kind()
3683            && self.tcx.is_lang_item(adt.did(), LangItem::Range)
3684        {
3685            return;
3686        }
3687        // Check if start has method named end.
3688        let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else {
3689            return;
3690        };
3691        let [hir::PathSegment { ident, .. }] = p.segments else {
3692            return;
3693        };
3694        let self_ty = self.typeck_results.borrow().expr_ty(start.expr);
3695        let Ok(_pick) = self.lookup_probe_for_diagnostic(
3696            *ident,
3697            self_ty,
3698            expr,
3699            probe::ProbeScope::AllTraits,
3700            expectation,
3701        ) else {
3702            return;
3703        };
3704        let mut sugg = ".";
3705        let mut span = start.expr.span.between(end.expr.span);
3706        if span.lo() + BytePos(2) == span.hi() {
3707            // There's no space between the start, the range op and the end, suggest removal which
3708            // will be more noticeable than the replacement of `..` with `.`.
3709            span = span.with_lo(span.lo() + BytePos(1));
3710            sugg = "";
3711        }
3712        err.span_suggestion_verbose(
3713            span,
3714            "you likely meant to write a method call instead of a range",
3715            sugg,
3716            Applicability::MachineApplicable,
3717        );
3718    }
3719
3720    /// Identify when the type error is because `()` is found in a binding that was assigned a
3721    /// block without a tail expression.
3722    pub(crate) fn suggest_return_binding_for_missing_tail_expr(
3723        &self,
3724        err: &mut Diag<'_>,
3725        expr: &hir::Expr<'_>,
3726        checked_ty: Ty<'tcx>,
3727        expected_ty: Ty<'tcx>,
3728    ) {
3729        if !checked_ty.is_unit() {
3730            return;
3731        }
3732        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {
3733            return;
3734        };
3735        let hir::def::Res::Local(hir_id) = path.res else {
3736            return;
3737        };
3738        let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
3739            return;
3740        };
3741        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =
3742            self.tcx.parent_hir_node(pat.hir_id)
3743        else {
3744            return;
3745        };
3746        let hir::ExprKind::Block(block, None) = init.kind else {
3747            return;
3748        };
3749        if block.expr.is_some() {
3750            return;
3751        }
3752        let [.., stmt] = block.stmts else {
3753            err.span_label(block.span, "this empty block is missing a tail expression");
3754            return;
3755        };
3756        let hir::StmtKind::Semi(tail_expr) = stmt.kind else {
3757            return;
3758        };
3759        let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else {
3760            return;
3761        };
3762        if self.can_eq(self.param_env, expected_ty, ty)
3763            // FIXME: this happens with macro calls. Need to figure out why the stmt
3764            // `println!();` doesn't include the `;` in its `Span`. (#133845)
3765            // We filter these out to avoid ICEs with debug assertions on caused by
3766            // empty suggestions.
3767            && stmt.span.hi() != tail_expr.span.hi()
3768        {
3769            err.span_suggestion_short(
3770                stmt.span.with_lo(tail_expr.span.hi()),
3771                "remove this semicolon",
3772                "",
3773                Applicability::MachineApplicable,
3774            );
3775        } else {
3776            err.span_label(block.span, "this block is missing a tail expression");
3777        }
3778    }
3779
3780    pub(crate) fn suggest_swapping_lhs_and_rhs(
3781        &self,
3782        err: &mut Diag<'_>,
3783        rhs_ty: Ty<'tcx>,
3784        lhs_ty: Ty<'tcx>,
3785        rhs_expr: &'tcx hir::Expr<'tcx>,
3786        lhs_expr: &'tcx hir::Expr<'tcx>,
3787    ) {
3788        if let Some(partial_eq_def_id) = self.infcx.tcx.lang_items().eq_trait()
3789            && self
3790                .infcx
3791                .type_implements_trait(partial_eq_def_id, [rhs_ty, lhs_ty], self.param_env)
3792                .must_apply_modulo_regions()
3793        {
3794            let sm = self.tcx.sess.source_map();
3795            // If the span of rhs_expr or lhs_expr is in an external macro,
3796            // we just suppress the suggestion. See issue #139050
3797            if !rhs_expr.span.in_external_macro(sm)
3798                && !lhs_expr.span.in_external_macro(sm)
3799                && let Ok(rhs_snippet) = sm.span_to_snippet(rhs_expr.span)
3800                && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_expr.span)
3801            {
3802                err.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` implements `PartialEq<{1}>`",
                rhs_ty, lhs_ty))
    })format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`"));
3803                err.multipart_suggestion(
3804                    "consider swapping the equality",
3805                    ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(lhs_expr.span, rhs_snippet), (rhs_expr.span, lhs_snippet)]))vec![(lhs_expr.span, rhs_snippet), (rhs_expr.span, lhs_snippet)],
3806                    Applicability::MaybeIncorrect,
3807                );
3808            }
3809        }
3810    }
3811}