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::lang_items::LangItem;
11use rustc_hir::{
12    self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
13    GenericBound, HirId, LoopSource, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind,
14    TyKind, WherePredicateKind, expr_needs_parens, is_range_literal,
15};
16use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
17use rustc_hir_analysis::suggest_impl_trait;
18use rustc_middle::middle::stability::EvalResult;
19use rustc_middle::span_bug;
20use rustc_middle::ty::print::with_no_trimmed_paths;
21use rustc_middle::ty::{
22    self, Article, Binder, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, Upcast,
23    suggest_constraining_type_params,
24};
25use rustc_session::errors::ExprParenthesesNeeded;
26use rustc_span::{ExpnKind, Ident, MacroKind, Span, Spanned, Symbol, sym};
27use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
28use rustc_trait_selection::error_reporting::traits::DefIdOrName;
29use rustc_trait_selection::infer::InferCtxtExt;
30use rustc_trait_selection::traits;
31use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
32use tracing::{debug, instrument};
33
34use super::FnCtxt;
35use crate::errors;
36use crate::fn_ctxt::rustc_span::BytePos;
37use crate::method::probe;
38use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
39
40impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
41    pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
42        self.typeck_results
43            .borrow()
44            .liberated_fn_sigs()
45            .get(self.tcx.local_def_id_to_hir_id(self.body_id))
46            .copied()
47    }
48
49    pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diag<'_>) {
50        // This suggestion is incorrect for
51        // fn foo() -> bool { match () { () => true } || match () { () => true } }
52        err.span_suggestion_short(
53            span.shrink_to_hi(),
54            "consider using a semicolon here",
55            ";",
56            Applicability::MaybeIncorrect,
57        );
58    }
59
60    /// On implicit return expressions with mismatched types, provides the following suggestions:
61    ///
62    /// - Points out the method's return type as the reason for the expected type.
63    /// - Possible missing semicolon.
64    /// - Possible missing return type if the return type is the default, and not `fn main()`.
65    pub(crate) fn suggest_mismatched_types_on_tail(
66        &self,
67        err: &mut Diag<'_>,
68        expr: &'tcx hir::Expr<'tcx>,
69        expected: Ty<'tcx>,
70        found: Ty<'tcx>,
71        blk_id: HirId,
72    ) -> bool {
73        let expr = expr.peel_drop_temps();
74        let mut pointing_at_return_type = false;
75        if let hir::ExprKind::Break(..) = expr.kind {
76            // `break` type mismatches provide better context for tail `loop` expressions.
77            return false;
78        }
79        if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) {
80            pointing_at_return_type =
81                self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id);
82            self.suggest_missing_break_or_return_expr(
83                err, expr, fn_decl, expected, found, blk_id, fn_id,
84            );
85        }
86        pointing_at_return_type
87    }
88
89    /// When encountering an fn-like type, try accessing the output of the type
90    /// and suggesting calling it if it satisfies a predicate (i.e. if the
91    /// output has a method or a field):
92    /// ```compile_fail,E0308
93    /// fn foo(x: usize) -> usize { x }
94    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
95    /// ```
96    pub(crate) fn suggest_fn_call(
97        &self,
98        err: &mut Diag<'_>,
99        expr: &hir::Expr<'_>,
100        found: Ty<'tcx>,
101        can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
102    ) -> bool {
103        let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(found) else {
104            return false;
105        };
106        if can_satisfy(output) {
107            let (sugg_call, mut applicability) = match inputs.len() {
108                0 => ("".to_string(), Applicability::MachineApplicable),
109                1..=4 => (
110                    inputs
111                        .iter()
112                        .map(|ty| {
113                            if ty.is_suggestable(self.tcx, false) {
114                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("/* {0} */", ty))
    })format!("/* {ty} */")
115                            } else {
116                                "/* value */".to_string()
117                            }
118                        })
119                        .collect::<Vec<_>>()
120                        .join(", "),
121                    Applicability::HasPlaceholders,
122                ),
123                _ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
124            };
125
126            let msg = match def_id_or_name {
127                DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
128                    DefKind::Ctor(CtorOf::Struct, _) => "construct this tuple struct".to_string(),
129                    DefKind::Ctor(CtorOf::Variant, _) => "construct this tuple variant".to_string(),
130                    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)),
131                },
132                DefIdOrName::Name(name) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("call this {0}", name))
    })format!("call this {name}"),
133            };
134
135            let sugg = match expr.kind {
136                hir::ExprKind::Call(..)
137                | hir::ExprKind::Path(..)
138                | hir::ExprKind::Index(..)
139                | hir::ExprKind::Lit(..) => {
140                    ::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})"))]
141                }
142                hir::ExprKind::Closure { .. } => {
143                    // Might be `{ expr } || { bool }`
144                    applicability = Applicability::MaybeIncorrect;
145                    ::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![
146                        (expr.span.shrink_to_lo(), "(".to_string()),
147                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
148                    ]
149                }
150                _ => {
151                    ::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![
152                        (expr.span.shrink_to_lo(), "(".to_string()),
153                        (expr.span.shrink_to_hi(), format!(")({sugg_call})")),
154                    ]
155                }
156            };
157
158            err.multipart_suggestion(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("use parentheses to {0}", msg))
    })format!("use parentheses to {msg}"), sugg, applicability);
159            return true;
160        }
161        false
162    }
163
164    /// Extracts information about a callable type for diagnostics. This is a
165    /// heuristic -- it doesn't necessarily mean that a type is always callable,
166    /// because the callable type must also be well-formed to be called.
167    pub(in super::super) fn extract_callable_info(
168        &self,
169        ty: Ty<'tcx>,
170    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
171        self.err_ctxt().extract_callable_info(self.body_id, self.param_env, ty)
172    }
173
174    pub(crate) fn suggest_two_fn_call(
175        &self,
176        err: &mut Diag<'_>,
177        lhs_expr: &'tcx hir::Expr<'tcx>,
178        lhs_ty: Ty<'tcx>,
179        rhs_expr: &'tcx hir::Expr<'tcx>,
180        rhs_ty: Ty<'tcx>,
181        can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
182    ) -> bool {
183        if lhs_expr.span.in_derive_expansion() || rhs_expr.span.in_derive_expansion() {
184            return false;
185        }
186        let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) else {
187            return false;
188        };
189        let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_ty) else {
190            return false;
191        };
192
193        if can_satisfy(lhs_output_ty, rhs_output_ty) {
194            let mut sugg = ::alloc::vec::Vec::new()vec![];
195            let mut applicability = Applicability::MachineApplicable;
196
197            for (expr, inputs) in [(lhs_expr, lhs_inputs), (rhs_expr, rhs_inputs)] {
198                let (sugg_call, this_applicability) = match inputs.len() {
199                    0 => ("".to_string(), Applicability::MachineApplicable),
200                    1..=4 => (
201                        inputs
202                            .iter()
203                            .map(|ty| {
204                                if ty.is_suggestable(self.tcx, false) {
205                                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("/* {0} */", ty))
    })format!("/* {ty} */")
206                                } else {
207                                    "/* value */".to_string()
208                                }
209                            })
210                            .collect::<Vec<_>>()
211                            .join(", "),
212                        Applicability::HasPlaceholders,
213                    ),
214                    _ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
215                };
216
217                applicability = applicability.max(this_applicability);
218
219                match expr.kind {
220                    hir::ExprKind::Call(..)
221                    | hir::ExprKind::Path(..)
222                    | hir::ExprKind::Index(..)
223                    | hir::ExprKind::Lit(..) => {
224                        sugg.extend([(expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("({0})", sugg_call))
    })format!("({sugg_call})"))]);
225                    }
226                    hir::ExprKind::Closure { .. } => {
227                        // Might be `{ expr } || { bool }`
228                        applicability = Applicability::MaybeIncorrect;
229                        sugg.extend([
230                            (expr.span.shrink_to_lo(), "(".to_string()),
231                            (expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(")({0})", sugg_call))
    })format!(")({sugg_call})")),
232                        ]);
233                    }
234                    _ => {
235                        sugg.extend([
236                            (expr.span.shrink_to_lo(), "(".to_string()),
237                            (expr.span.shrink_to_hi(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(")({0})", sugg_call))
    })format!(")({sugg_call})")),
238                        ]);
239                    }
240                }
241            }
242
243            err.multipart_suggestion("use parentheses to call these", sugg, applicability);
244
245            true
246        } else {
247            false
248        }
249    }
250
251    pub(crate) fn suggest_remove_last_method_call(
252        &self,
253        err: &mut Diag<'_>,
254        expr: &hir::Expr<'tcx>,
255        expected: Ty<'tcx>,
256    ) -> bool {
257        if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) =
258            expr.kind
259            && let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
260            && self.may_coerce(recv_ty, expected)
261            && let name = method.name.as_str()
262            && (name.starts_with("to_") || name.starts_with("as_") || name == "into")
263        {
264            let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) {
265                expr.span.with_lo(recv_span.hi())
266            } else {
267                expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1))
268            };
269            err.span_suggestion_verbose(
270                span,
271                "try removing the method call",
272                "",
273                Applicability::MachineApplicable,
274            );
275            return true;
276        }
277        false
278    }
279
280    pub(crate) fn suggest_deref_ref_or_into(
281        &self,
282        err: &mut Diag<'_>,
283        expr: &hir::Expr<'tcx>,
284        expected: Ty<'tcx>,
285        found: Ty<'tcx>,
286        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
287    ) -> bool {
288        let expr = expr.peel_blocks();
289        let methods =
290            self.get_conversion_methods_for_diagnostic(expr.span, expected, found, expr.hir_id);
291
292        if let Some((suggestion, msg, applicability, verbose, annotation)) =
293            self.suggest_deref_or_ref(expr, found, expected)
294        {
295            if verbose {
296                err.multipart_suggestion(msg, suggestion, applicability);
297            } else {
298                err.multipart_suggestion(msg, suggestion, applicability);
299            }
300            if annotation {
301                let suggest_annotation = match expr.peel_drop_temps().kind {
302                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, _) => mutbl.ref_prefix_str(),
303                    _ => return true,
304                };
305                let mut tuple_indexes = Vec::new();
306                let mut expr_id = expr.hir_id;
307                for (parent_id, node) in self.tcx.hir_parent_iter(expr.hir_id) {
308                    match node {
309                        Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => {
310                            tuple_indexes.push(
311                                subs.iter()
312                                    .enumerate()
313                                    .find(|(_, sub_expr)| sub_expr.hir_id == expr_id)
314                                    .unwrap()
315                                    .0,
316                            );
317                            expr_id = parent_id;
318                        }
319                        Node::LetStmt(local) => {
320                            if let Some(mut ty) = local.ty {
321                                while let Some(index) = tuple_indexes.pop() {
322                                    match ty.kind {
323                                        TyKind::Tup(tys) => ty = &tys[index],
324                                        _ => return true,
325                                    }
326                                }
327                                let annotation_span = ty.span;
328                                err.span_suggestion(
329                                    annotation_span.with_hi(annotation_span.lo()),
330                                    "alternatively, consider changing the type annotation",
331                                    suggest_annotation,
332                                    Applicability::MaybeIncorrect,
333                                );
334                            }
335                            break;
336                        }
337                        _ => break,
338                    }
339                }
340            }
341            return true;
342        }
343
344        if self.suggest_else_fn_with_closure(err, expr, found, expected) {
345            return true;
346        }
347
348        if self.suggest_fn_call(err, expr, found, |output| self.may_coerce(output, expected))
349            && let ty::FnDef(def_id, ..) = *found.kind()
350            && let Some(sp) = self.tcx.hir_span_if_local(def_id)
351        {
352            let name = self.tcx.item_name(def_id);
353            let kind = self.tcx.def_kind(def_id);
354            if let DefKind::Ctor(of, CtorKind::Fn) = kind {
355                err.span_label(
356                    sp,
357                    ::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!(
358                        "`{name}` defines {} constructor here, which should be called",
359                        match of {
360                            CtorOf::Struct => "a struct",
361                            CtorOf::Variant => "an enum variant",
362                        }
363                    ),
364                );
365            } else {
366                let descr = self.tcx.def_kind_descr(kind, def_id);
367                err.span_label(sp, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} `{1}` defined here", descr,
                name))
    })format!("{descr} `{name}` defined here"));
368            }
369            return true;
370        }
371
372        if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
373            return true;
374        }
375
376        if !methods.is_empty() {
377            let mut suggestions = methods
378                .iter()
379                .filter_map(|conversion_method| {
380                    let conversion_method_name = conversion_method.name();
381                    let receiver_method_ident = expr.method_ident();
382                    if let Some(method_ident) = receiver_method_ident
383                        && method_ident.name == conversion_method_name
384                    {
385                        return None; // do not suggest code that is already there (#53348)
386                    }
387
388                    let method_call_list = [sym::to_vec, sym::to_string];
389                    let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
390                        && receiver_method.ident.name == sym::clone
391                        && method_call_list.contains(&conversion_method_name)
392                    // If receiver is `.clone()` and found type has one of those methods,
393                    // we guess that the user wants to convert from a slice type (`&[]` or `&str`)
394                    // to an owned type (`Vec` or `String`). These conversions clone internally,
395                    // so we remove the user's `clone` call.
396                    {
397                        ::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())]
398                    } else if self.precedence(expr) < ExprPrecedence::Unambiguous {
399                        ::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![
400                            (expr.span.shrink_to_lo(), "(".to_string()),
401                            (expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)),
402                        ]
403                    } else {
404                        ::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))]
405                    };
406                    let struct_pat_shorthand_field =
407                        self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr);
408                    if let Some(name) = struct_pat_shorthand_field {
409                        sugg.insert(0, (expr.span.shrink_to_lo(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", name))
    })format!("{name}: ")));
410                    }
411                    Some(sugg)
412                })
413                .peekable();
414            if suggestions.peek().is_some() {
415                err.multipart_suggestions(
416                    "try using a conversion method",
417                    suggestions,
418                    Applicability::MaybeIncorrect,
419                );
420                return true;
421            }
422        }
423
424        if let Some((found_ty_inner, expected_ty_inner, error_tys)) =
425            self.deconstruct_option_or_result(found, expected)
426            && let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind()
427        {
428            // Suggest removing any stray borrows (unless there's macro shenanigans involved).
429            let inner_expr = expr.peel_borrows();
430            if !inner_expr.span.eq_ctxt(expr.span) {
431                return false;
432            }
433            let borrow_removal_span = if inner_expr.hir_id == expr.hir_id {
434                None
435            } else {
436                Some(expr.span.shrink_to_lo().until(inner_expr.span))
437            };
438            // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
439            // `as_ref` and `as_deref` compatibility.
440            let error_tys_equate_as_ref = error_tys.is_none_or(|(found, expected)| {
441                self.can_eq(
442                    self.param_env,
443                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, found),
444                    expected,
445                )
446            });
447
448            let prefix_wrap = |sugg: &str| {
449                if let Some(name) = self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
450                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}{1}", name, sugg))
    })format!(": {}{}", name, sugg)
451                } else {
452                    sugg.to_string()
453                }
454            };
455
456            // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
457            // but those checks need to be a bit more delicate and the benefit is diminishing.
458            if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
459                let sugg = prefix_wrap(".as_ref()");
460                err.subdiagnostic(errors::SuggestConvertViaMethod {
461                    span: expr.span.shrink_to_hi(),
462                    sugg,
463                    expected,
464                    found,
465                    borrow_removal_span,
466                });
467                return true;
468            } else if let ty::Ref(_, peeled_found_ty, _) = found_ty_inner.kind()
469                && let ty::Adt(adt, _) = peeled_found_ty.peel_refs().kind()
470                && self.tcx.is_lang_item(adt.did(), LangItem::String)
471                && peeled.is_str()
472                // `Result::map`, conversely, does not take ref of the error type.
473                && error_tys.is_none_or(|(found, expected)| {
474                    self.can_eq(self.param_env, found, expected)
475                })
476            {
477                let sugg = prefix_wrap(".map(|x| x.as_str())");
478                err.span_suggestion_verbose(
479                    expr.span.shrink_to_hi(),
480                    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`"),
481                    sugg,
482                    Applicability::MachineApplicable,
483                );
484                return true;
485            } else {
486                if !error_tys_equate_as_ref {
487                    return false;
488                }
489                let mut steps = self.autoderef(expr.span, found_ty_inner).silence_errors();
490                if let Some((deref_ty, _)) = steps.nth(1)
491                    && self.can_eq(self.param_env, deref_ty, peeled)
492                {
493                    let sugg = prefix_wrap(".as_deref()");
494                    err.subdiagnostic(errors::SuggestConvertViaMethod {
495                        span: expr.span.shrink_to_hi(),
496                        sugg,
497                        expected,
498                        found,
499                        borrow_removal_span,
500                    });
501                    return true;
502                }
503                for (deref_ty, n_step) in steps {
504                    if self.can_eq(self.param_env, deref_ty, peeled) {
505                        let explicit_deref = "*".repeat(n_step);
506                        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)"));
507                        err.subdiagnostic(errors::SuggestConvertViaMethod {
508                            span: expr.span.shrink_to_hi(),
509                            sugg,
510                            expected,
511                            found,
512                            borrow_removal_span,
513                        });
514                        return true;
515                    }
516                }
517            }
518        }
519
520        false
521    }
522
523    /// If `ty` is `Option<T>`, returns `T, T, None`.
524    /// If `ty` is `Result<T, E>`, returns `T, T, Some(E, E)`.
525    /// Otherwise, returns `None`.
526    fn deconstruct_option_or_result(
527        &self,
528        found_ty: Ty<'tcx>,
529        expected_ty: Ty<'tcx>,
530    ) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)> {
531        let ty::Adt(found_adt, found_args) = found_ty.peel_refs().kind() else {
532            return None;
533        };
534        let ty::Adt(expected_adt, expected_args) = expected_ty.kind() else {
535            return None;
536        };
537        if self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
538            && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
539        {
540            Some((found_args.type_at(0), expected_args.type_at(0), None))
541        } else if self.tcx.is_diagnostic_item(sym::Result, found_adt.did())
542            && self.tcx.is_diagnostic_item(sym::Result, expected_adt.did())
543        {
544            Some((
545                found_args.type_at(0),
546                expected_args.type_at(0),
547                Some((found_args.type_at(1), expected_args.type_at(1))),
548            ))
549        } else {
550            None
551        }
552    }
553
554    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
555    /// in the heap by calling `Box::new()`.
556    pub(in super::super) fn suggest_boxing_when_appropriate(
557        &self,
558        err: &mut Diag<'_>,
559        span: Span,
560        hir_id: HirId,
561        expected: Ty<'tcx>,
562        found: Ty<'tcx>,
563    ) -> bool {
564        // Do not suggest `Box::new` in const context.
565        if self.tcx.hir_is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
566            return false;
567        }
568        if self.may_coerce(Ty::new_box(self.tcx, found), expected) {
569            let suggest_boxing = match *found.kind() {
570                ty::Tuple(tuple) if tuple.is_empty() => {
571                    errors::SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
572                }
573                ty::Coroutine(def_id, ..)
574                    if #[allow(non_exhaustive_omitted_patterns)] match self.tcx.coroutine_kind(def_id)
    {
    Some(CoroutineKind::Desugared(CoroutineDesugaring::Async,
        CoroutineSource::Closure)) => true,
    _ => false,
}matches!(
575                        self.tcx.coroutine_kind(def_id),
576                        Some(CoroutineKind::Desugared(
577                            CoroutineDesugaring::Async,
578                            CoroutineSource::Closure
579                        ))
580                    ) =>
581                {
582                    errors::SuggestBoxing::AsyncBody
583                }
584                _ if let Node::ExprField(expr_field) = self.tcx.parent_hir_node(hir_id)
585                    && expr_field.is_shorthand =>
586                {
587                    errors::SuggestBoxing::ExprFieldShorthand {
588                        start: span.shrink_to_lo(),
589                        end: span.shrink_to_hi(),
590                        ident: expr_field.ident,
591                    }
592                }
593                _ => errors::SuggestBoxing::Other {
594                    start: span.shrink_to_lo(),
595                    end: span.shrink_to_hi(),
596                },
597            };
598            err.subdiagnostic(suggest_boxing);
599
600            true
601        } else {
602            false
603        }
604    }
605
606    /// When encountering a closure that captures variables, where a FnPtr is expected,
607    /// suggest a non-capturing closure
608    pub(in super::super) fn suggest_no_capture_closure(
609        &self,
610        err: &mut Diag<'_>,
611        expected: Ty<'tcx>,
612        found: Ty<'tcx>,
613    ) -> bool {
614        if let (ty::FnPtr(..), ty::Closure(def_id, _)) = (expected.kind(), found.kind())
615            && let Some(upvars) = self.tcx.upvars_mentioned(*def_id)
616        {
617            // Report upto four upvars being captured to reduce the amount error messages
618            // reported back to the user.
619            let spans_and_labels = upvars
620                .iter()
621                .take(4)
622                .map(|(var_hir_id, upvar)| {
623                    let var_name = self.tcx.hir_name(*var_hir_id).to_string();
624                    let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` captured here", var_name))
    })format!("`{var_name}` captured here");
625                    (upvar.span, msg)
626                })
627                .collect::<Vec<_>>();
628
629            let mut multi_span: MultiSpan =
630                spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
631            for (sp, label) in spans_and_labels {
632                multi_span.push_span_label(sp, label);
633            }
634            err.span_note(
635                multi_span,
636                "closures can only be coerced to `fn` types if they do not capture any variables",
637            );
638            return true;
639        }
640        false
641    }
642
643    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
644    #[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(644u32),
                                    ::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:673",
                                                "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(673u32),
                                                ::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))]
645    pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
646        &self,
647        err: &mut Diag<'_>,
648        expr: &hir::Expr<'_>,
649        expected: Ty<'tcx>,
650        found: Ty<'tcx>,
651    ) -> bool {
652        // Handle #68197.
653
654        if self.tcx.hir_is_inside_const_context(expr.hir_id) {
655            // Do not suggest `Box::new` in const context.
656            return false;
657        }
658        let pin_did = self.tcx.lang_items().pin_type();
659        // This guards the `new_box` below.
660        if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() {
661            return false;
662        }
663        let box_found = Ty::new_box(self.tcx, found);
664        let Some(pin_box_found) = Ty::new_lang_item(self.tcx, box_found, LangItem::Pin) else {
665            return false;
666        };
667        let Some(pin_found) = Ty::new_lang_item(self.tcx, found, LangItem::Pin) else {
668            return false;
669        };
670        match expected.kind() {
671            ty::Adt(def, _) if Some(def.did()) == pin_did => {
672                if self.may_coerce(pin_box_found, expected) {
673                    debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
674                    match found.kind() {
675                        ty::Adt(def, _) if def.is_box() => {
676                            err.help("use `Box::pin`");
677                        }
678                        _ => {
679                            let prefix = if let Some(name) =
680                                self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr)
681                            {
682                                format!("{}: ", name)
683                            } else {
684                                String::new()
685                            };
686                            let suggestion = vec![
687                                (expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")),
688                                (expr.span.shrink_to_hi(), ")".to_string()),
689                            ];
690                            err.multipart_suggestion(
691                                "you need to pin and box this expression",
692                                suggestion,
693                                Applicability::MaybeIncorrect,
694                            );
695                        }
696                    }
697                    true
698                } else if self.may_coerce(pin_found, expected) {
699                    match found.kind() {
700                        ty::Adt(def, _) if def.is_box() => {
701                            err.help("use `Box::pin`");
702                            true
703                        }
704                        _ => false,
705                    }
706                } else {
707                    false
708                }
709            }
710            ty::Adt(def, _) if def.is_box() && self.may_coerce(box_found, expected) => {
711                // Check if the parent expression is a call to Pin::new. If it
712                // is and we were expecting a Box, ergo Pin<Box<expected>>, we
713                // can suggest Box::pin.
714                let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }) =
715                    self.tcx.parent_hir_node(expr.hir_id)
716                else {
717                    return false;
718                };
719                match fn_name.kind {
720                    ExprKind::Path(QPath::TypeRelative(
721                        hir::Ty {
722                            kind: TyKind::Path(QPath::Resolved(_, Path { res: recv_ty, .. })),
723                            ..
724                        },
725                        method,
726                    )) if recv_ty.opt_def_id() == pin_did && method.ident.name == sym::new => {
727                        err.span_suggestion(
728                            fn_name.span,
729                            "use `Box::pin` to pin and box this expression",
730                            "Box::pin",
731                            Applicability::MachineApplicable,
732                        );
733                        true
734                    }
735                    _ => false,
736                }
737            }
738            _ => false,
739        }
740    }
741
742    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
743    ///
744    /// ```compile_fail,E0308
745    /// # fn bar_that_returns_u32() -> u32 { 4 }
746    /// fn foo() {
747    ///     bar_that_returns_u32()
748    /// }
749    /// ```
750    ///
751    /// This routine checks if the return expression in a block would make sense on its own as a
752    /// statement and the return type has been left as default or has been specified as `()`. If so,
753    /// it suggests adding a semicolon.
754    ///
755    /// If the expression is the expression of a closure without block (`|| expr`), a
756    /// block is needed to be added too (`|| { expr; }`). This is denoted by `needs_block`.
757    pub(crate) fn suggest_missing_semicolon(
758        &self,
759        err: &mut Diag<'_>,
760        expression: &'tcx hir::Expr<'tcx>,
761        expected: Ty<'tcx>,
762        needs_block: bool,
763        parent_is_closure: bool,
764    ) {
765        if !expected.is_unit() {
766            return;
767        }
768        // `BlockTailExpression` only relevant if the tail expr would be
769        // useful on its own.
770        match expression.kind {
771            ExprKind::Call(..)
772            | ExprKind::MethodCall(..)
773            | ExprKind::Loop(..)
774            | ExprKind::If(..)
775            | ExprKind::Match(..)
776            | ExprKind::Block(..)
777                if expression.can_have_side_effects()
778                    // If the expression is from an external macro, then do not suggest
779                    // adding a semicolon, because there's nowhere to put it.
780                    // See issue #81943.
781                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
782            {
783                if needs_block {
784                    err.multipart_suggestion(
785                        "consider using a semicolon here",
786                        ::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![
787                            (expression.span.shrink_to_lo(), "{ ".to_owned()),
788                            (expression.span.shrink_to_hi(), "; }".to_owned()),
789                        ],
790                        Applicability::MachineApplicable,
791                    );
792                } else if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id)
793                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id)
794                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id)
795                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind
796                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id)
797                    && let hir::StmtKind::Expr(_) = stmt.kind
798                    && self.is_next_stmt_expr_continuation(stmt.hir_id)
799                {
800                    err.multipart_suggestion(
801                        "parentheses are required to parse this as an expression",
802                        ::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![
803                            (stmt.span.shrink_to_lo(), "(".to_string()),
804                            (stmt.span.shrink_to_hi(), ")".to_string()),
805                        ],
806                        Applicability::MachineApplicable,
807                    );
808                } else {
809                    err.span_suggestion(
810                        expression.span.shrink_to_hi(),
811                        "consider using a semicolon here",
812                        ";",
813                        Applicability::MachineApplicable,
814                    );
815                }
816            }
817            ExprKind::Path(..) | ExprKind::Lit(_)
818                if parent_is_closure
819                    && !expression.span.in_external_macro(self.tcx.sess.source_map()) =>
820            {
821                err.span_suggestion_verbose(
822                    expression.span.shrink_to_lo(),
823                    "consider ignoring the value",
824                    "_ = ",
825                    Applicability::MachineApplicable,
826                );
827            }
828            _ => {
829                if let hir::Node::Block(block) = self.tcx.parent_hir_node(expression.hir_id)
830                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(block.hir_id)
831                    && let hir::Node::Expr(if_expr) = self.tcx.parent_hir_node(expr.hir_id)
832                    && let hir::ExprKind::If(_cond, _then, Some(_else)) = if_expr.kind
833                    && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(if_expr.hir_id)
834                    && let hir::StmtKind::Expr(_) = stmt.kind
835                    && self.is_next_stmt_expr_continuation(stmt.hir_id)
836                {
837                    // The error is pointing at an arm of an if-expression, and we want to get the
838                    // `Span` of the whole if-expression for the suggestion. This only works for a
839                    // single level of nesting, which is fine.
840                    // We have something like `if true { false } else { true } && true`. Suggest
841                    // wrapping in parentheses. We find the statement or expression following the
842                    // `if` (`&& true`) and see if it is something that can reasonably be
843                    // interpreted as a binop following an expression.
844                    err.multipart_suggestion(
845                        "parentheses are required to parse this as an expression",
846                        ::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![
847                            (stmt.span.shrink_to_lo(), "(".to_string()),
848                            (stmt.span.shrink_to_hi(), ")".to_string()),
849                        ],
850                        Applicability::MachineApplicable,
851                    );
852                }
853            }
854        }
855    }
856
857    pub(crate) fn is_next_stmt_expr_continuation(&self, hir_id: HirId) -> bool {
858        if let hir::Node::Block(b) = self.tcx.parent_hir_node(hir_id)
859            && let mut stmts = b.stmts.iter().skip_while(|s| s.hir_id != hir_id)
860            && let Some(_) = stmts.next() // The statement the statement that was passed in
861            && let Some(next) = match (stmts.next(), b.expr) { // The following statement
862                (Some(next), _) => match next.kind {
863                    hir::StmtKind::Expr(next) | hir::StmtKind::Semi(next) => Some(next),
864                    _ => None,
865                },
866                (None, Some(next)) => Some(next),
867                _ => None,
868            }
869            && let hir::ExprKind::AddrOf(..) // prev_stmt && next
870                | hir::ExprKind::Unary(..) // prev_stmt * next
871                | hir::ExprKind::Err(_) = next.kind
872        // prev_stmt + next
873        {
874            true
875        } else {
876            false
877        }
878    }
879
880    /// A possible error is to forget to add a return type that is needed:
881    ///
882    /// ```compile_fail,E0308
883    /// # fn bar_that_returns_u32() -> u32 { 4 }
884    /// fn foo() {
885    ///     bar_that_returns_u32()
886    /// }
887    /// ```
888    ///
889    /// This routine checks if the return type is left as default, the method is not part of an
890    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
891    /// type.
892    #[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(892u32),
                                    ::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 &&
                                    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:943",
                                                "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(943u32),
                                                ::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:961",
                                                "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(961u32),
                                                ::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:963",
                                                "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(963u32),
                                                ::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:964",
                                                "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(964u32),
                                                ::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, 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))]
893    pub(in super::super) fn suggest_missing_return_type(
894        &self,
895        err: &mut Diag<'_>,
896        fn_decl: &hir::FnDecl<'tcx>,
897        expected: Ty<'tcx>,
898        found: Ty<'tcx>,
899        fn_id: LocalDefId,
900    ) -> bool {
901        // Can't suggest `->` on a block-like coroutine
902        if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Block)) =
903            self.tcx.coroutine_kind(fn_id)
904        {
905            return false;
906        }
907
908        let found =
909            self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
910        // Only suggest changing the return type for methods that
911        // haven't set a return type at all (and aren't `fn main()`, impl or closure).
912        match &fn_decl.output {
913            // For closure with default returns, don't suggest adding return type
914            &hir::FnRetTy::DefaultReturn(_) if self.tcx.is_closure_like(fn_id.to_def_id()) => {}
915            &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
916                if !self.can_add_return_type(fn_id) {
917                    err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
918                } else if let Some(found) = found.make_suggestable(self.tcx, false, None) {
919                    err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
920                        span,
921                        found: found.to_string(),
922                    });
923                } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
924                    err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg });
925                } else {
926                    // FIXME: if `found` could be `impl Iterator` we should suggest that.
927                    err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
928                }
929
930                return true;
931            }
932            hir::FnRetTy::Return(hir_ty) => {
933                if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
934                    // FIXME: account for RPITIT.
935                    && let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds
936                    && let Some(hir::PathSegment { args: Some(generic_args), .. }) =
937                        trait_ref.trait_ref.path.segments.last()
938                    && let [constraint] = generic_args.constraints
939                    && let Some(ty) = constraint.ty()
940                {
941                    // Check if async function's return type was omitted.
942                    // Don't emit suggestions if the found type is `impl Future<...>`.
943                    debug!(?found);
944                    if found.is_suggestable(self.tcx, false) {
945                        if ty.span.is_empty() {
946                            err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
947                                span: ty.span,
948                                found: found.to_string(),
949                            });
950                            return true;
951                        } else {
952                            err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
953                                span: ty.span,
954                                expected,
955                            });
956                        }
957                    }
958                } else {
959                    // Only point to return type if the expected type is the return type, as if they
960                    // are not, the expectation must have been caused by something else.
961                    debug!(?hir_ty, "return type");
962                    let ty = self.lowerer().lower_ty(hir_ty);
963                    debug!(?ty, "return type (lowered)");
964                    debug!(?expected, "expected type");
965                    let bound_vars =
966                        self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id));
967                    let ty = Binder::bind_with_vars(ty, bound_vars);
968                    let ty = self.normalize(hir_ty.span, ty);
969                    let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
970                    if self.may_coerce(expected, ty) {
971                        err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
972                            span: hir_ty.span,
973                            expected,
974                        });
975                        self.try_suggest_return_impl_trait(err, expected, found, fn_id);
976                        self.try_note_caller_chooses_ty_for_ty_param(err, expected, found);
977                        return true;
978                    }
979                }
980            }
981            _ => {}
982        }
983        false
984    }
985
986    /// Checks whether we can add a return type to a function.
987    /// Assumes given function doesn't have a explicit return type.
988    fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
989        match self.tcx.hir_node_by_def_id(fn_id) {
990            Node::Item(item) => {
991                let (ident, _, _, _) = item.expect_fn();
992                // This is less than ideal, it will not suggest a return type span on any
993                // method called `main`, regardless of whether it is actually the entry point,
994                // but it will still present it as the reason for the expected type.
995                ident.name != sym::main
996            }
997            Node::ImplItem(item) => {
998                // If it doesn't impl a trait, we can add a return type
999                let Node::Item(&hir::Item {
1000                    kind: hir::ItemKind::Impl(hir::Impl { of_trait, .. }),
1001                    ..
1002                }) = self.tcx.parent_hir_node(item.hir_id())
1003                else {
1004                    ::core::panicking::panic("internal error: entered unreachable code");unreachable!();
1005                };
1006
1007                of_trait.is_none()
1008            }
1009            _ => true,
1010        }
1011    }
1012
1013    fn try_note_caller_chooses_ty_for_ty_param(
1014        &self,
1015        diag: &mut Diag<'_>,
1016        expected: Ty<'tcx>,
1017        found: Ty<'tcx>,
1018    ) {
1019        // Only show the note if:
1020        // 1. `expected` ty is a type parameter;
1021        // 2. The `expected` type parameter does *not* occur in the return expression type. This can
1022        //    happen for e.g. `fn foo<T>(t: &T) -> T { t }`, where `expected` is `T` but `found` is
1023        //    `&T`. Saying "the caller chooses a type for `T` which can be different from `&T`" is
1024        //    "well duh" and is only confusing and not helpful.
1025        let ty::Param(expected_ty_as_param) = expected.kind() else {
1026            return;
1027        };
1028
1029        if found.contains(expected) {
1030            return;
1031        }
1032
1033        diag.subdiagnostic(errors::NoteCallerChoosesTyForTyParam {
1034            ty_param_name: expected_ty_as_param.name,
1035            found_ty: found,
1036        });
1037    }
1038
1039    /// check whether the return type is a generic type with a trait bound
1040    /// only suggest this if the generic param is not present in the arguments
1041    /// if this is true, hint them towards changing the return type to `impl Trait`
1042    /// ```compile_fail,E0308
1043    /// fn cant_name_it<T: Fn() -> u32>() -> T {
1044    ///     || 3
1045    /// }
1046    /// ```
1047    fn try_suggest_return_impl_trait(
1048        &self,
1049        err: &mut Diag<'_>,
1050        expected: Ty<'tcx>,
1051        found: Ty<'tcx>,
1052        fn_id: LocalDefId,
1053    ) {
1054        // Only apply the suggestion if:
1055        //  - the return type is a generic parameter
1056        //  - the generic param is not used as a fn param
1057        //  - the generic param has at least one bound
1058        //  - the generic param doesn't appear in any other bounds where it's not the Self type
1059        // Suggest:
1060        //  - Changing the return type to be `impl <all bounds>`
1061
1062        {
    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:1062",
                        "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(1062u32),
                        ::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);
1063
1064        let ty::Param(expected_ty_as_param) = expected.kind() else { return };
1065
1066        let fn_node = self.tcx.hir_node_by_def_id(fn_id);
1067
1068        let hir::Node::Item(hir::Item {
1069            kind:
1070                hir::ItemKind::Fn {
1071                    sig:
1072                        hir::FnSig {
1073                            decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. },
1074                            ..
1075                        },
1076                    generics: hir::Generics { params, predicates, .. },
1077                    ..
1078                },
1079            ..
1080        }) = fn_node
1081        else {
1082            return;
1083        };
1084
1085        if params.get(expected_ty_as_param.index as usize).is_none() {
1086            return;
1087        };
1088
1089        // get all where BoundPredicates here, because they are used in two cases below
1090        let where_predicates = predicates
1091            .iter()
1092            .filter_map(|p| match p.kind {
1093                WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
1094                    bounds,
1095                    bounded_ty,
1096                    ..
1097                }) => {
1098                    // FIXME: Maybe these calls to `lower_ty` can be removed (and the ones below)
1099                    let ty = self.lowerer().lower_ty(bounded_ty);
1100                    Some((ty, bounds))
1101                }
1102                _ => None,
1103            })
1104            .map(|(ty, bounds)| match ty.kind() {
1105                ty::Param(param_ty) if param_ty == expected_ty_as_param => Ok(Some(bounds)),
1106                // check whether there is any predicate that contains our `T`, like `Option<T>: Send`
1107                _ => match ty.contains(expected) {
1108                    true => Err(()),
1109                    false => Ok(None),
1110                },
1111            })
1112            .collect::<Result<Vec<_>, _>>();
1113
1114        let Ok(where_predicates) = where_predicates else { return };
1115
1116        // now get all predicates in the same types as the where bounds, so we can chain them
1117        let predicates_from_where =
1118            where_predicates.iter().flatten().flat_map(|bounds| bounds.iter());
1119
1120        // extract all bounds from the source code using their spans
1121        let all_matching_bounds_strs = predicates_from_where
1122            .filter_map(|bound| match bound {
1123                GenericBound::Trait(_) => {
1124                    self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
1125                }
1126                _ => None,
1127            })
1128            .collect::<Vec<String>>();
1129
1130        if all_matching_bounds_strs.is_empty() {
1131            return;
1132        }
1133
1134        let all_bounds_str = all_matching_bounds_strs.join(" + ");
1135
1136        let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| {
1137                let ty = self.lowerer().lower_ty( param);
1138                #[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)
1139            });
1140
1141        if ty_param_used_in_fn_params {
1142            return;
1143        }
1144
1145        err.span_suggestion(
1146            fn_return.span(),
1147            "consider using an impl return type",
1148            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("impl {0}", all_bounds_str))
    })format!("impl {all_bounds_str}"),
1149            Applicability::MaybeIncorrect,
1150        );
1151    }
1152
1153    pub(in super::super) fn suggest_missing_break_or_return_expr(
1154        &self,
1155        err: &mut Diag<'_>,
1156        expr: &'tcx hir::Expr<'tcx>,
1157        fn_decl: &hir::FnDecl<'tcx>,
1158        expected: Ty<'tcx>,
1159        found: Ty<'tcx>,
1160        id: HirId,
1161        fn_id: LocalDefId,
1162    ) {
1163        if !expected.is_unit() {
1164            return;
1165        }
1166        let found = self.resolve_vars_if_possible(found);
1167
1168        let innermost_loop = if self.is_loop(id) {
1169            Some(self.tcx.hir_node(id))
1170        } else {
1171            self.tcx
1172                .hir_parent_iter(id)
1173                .take_while(|(_, node)| {
1174                    // look at parents until we find the first body owner
1175                    node.body_id().is_none()
1176                })
1177                .find_map(|(parent_id, node)| self.is_loop(parent_id).then_some(node))
1178        };
1179        let can_break_with_value = innermost_loop.is_some_and(|node| {
1180            #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. })
        => true,
    _ => false,
}matches!(
1181                node,
1182                Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. })
1183            )
1184        });
1185
1186        let in_local_statement = self.is_local_statement(id)
1187            || self
1188                .tcx
1189                .hir_parent_iter(id)
1190                .any(|(parent_id, _)| self.is_local_statement(parent_id));
1191
1192        if can_break_with_value && in_local_statement {
1193            err.multipart_suggestion(
1194                "you might have meant to break the loop with this value",
1195                ::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![
1196                    (expr.span.shrink_to_lo(), "break ".to_string()),
1197                    (expr.span.shrink_to_hi(), ";".to_string()),
1198                ],
1199                Applicability::MaybeIncorrect,
1200            );
1201            return;
1202        }
1203
1204        let scope = self.tcx.hir_parent_iter(id).find(|(_, node)| {
1205            #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) | Node::Item(_) |
        Node::TraitItem(_) | Node::ImplItem(_) => true,
    _ => false,
}matches!(
1206                node,
1207                Node::Expr(Expr { kind: ExprKind::Closure(..), .. })
1208                    | Node::Item(_)
1209                    | Node::TraitItem(_)
1210                    | Node::ImplItem(_)
1211            )
1212        });
1213        let in_closure =
1214            #[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(..), .. }))));
1215
1216        let can_return = match fn_decl.output {
1217            hir::FnRetTy::Return(ty) => {
1218                let ty = self.lowerer().lower_ty(ty);
1219                let bound_vars = self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id));
1220                let ty = self
1221                    .tcx
1222                    .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars));
1223                let ty = match self.tcx.asyncness(fn_id) {
1224                    ty::Asyncness::Yes => {
1225                        self.err_ctxt().get_impl_future_output_ty(ty).unwrap_or_else(|| {
1226                            ::rustc_middle::util::bug::span_bug_fmt(fn_decl.output.span(),
    format_args!("failed to get output type of async function"))span_bug!(
1227                                fn_decl.output.span(),
1228                                "failed to get output type of async function"
1229                            )
1230                        })
1231                    }
1232                    ty::Asyncness::No => ty,
1233                };
1234                let ty = self.normalize(expr.span, ty);
1235                self.may_coerce(found, ty)
1236            }
1237            hir::FnRetTy::DefaultReturn(_) if in_closure => {
1238                self.ret_coercion.as_ref().is_some_and(|ret| {
1239                    let ret_ty = ret.borrow().expected_ty();
1240                    self.may_coerce(found, ret_ty)
1241                })
1242            }
1243            _ => false,
1244        };
1245        if can_return
1246            && let Some(span) = expr.span.find_ancestor_inside(
1247                self.tcx.hir_span_with_body(self.tcx.local_def_id_to_hir_id(fn_id)),
1248            )
1249        {
1250            // When the expr is in a match arm's body, we shouldn't add semicolon ';' at the end.
1251            // For example:
1252            // fn mismatch_types() -> i32 {
1253            //     match 1 {
1254            //         x => dbg!(x),
1255            //     }
1256            //     todo!()
1257            // }
1258            // -------------^^^^^^^-
1259            // Don't add semicolon `;` at the end of `dbg!(x)` expr
1260            fn is_in_arm<'tcx>(expr: &'tcx hir::Expr<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
1261                for (_, node) in tcx.hir_parent_iter(expr.hir_id) {
1262                    match node {
1263                        hir::Node::Block(block) => {
1264                            if let Some(ret) = block.expr
1265                                && ret.hir_id == expr.hir_id
1266                            {
1267                                continue;
1268                            }
1269                        }
1270                        hir::Node::Arm(arm) => {
1271                            if let hir::ExprKind::Block(block, _) = arm.body.kind
1272                                && let Some(ret) = block.expr
1273                                && ret.hir_id == expr.hir_id
1274                            {
1275                                return true;
1276                            }
1277                        }
1278                        hir::Node::Expr(e) if let hir::ExprKind::Block(block, _) = e.kind => {
1279                            if let Some(ret) = block.expr
1280                                && ret.hir_id == expr.hir_id
1281                            {
1282                                continue;
1283                            }
1284                        }
1285                        _ => {
1286                            return false;
1287                        }
1288                    }
1289                }
1290
1291                false
1292            }
1293            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())];
1294            if !is_in_arm(expr, self.tcx) {
1295                suggs.push((span.shrink_to_hi(), ";".to_string()));
1296            }
1297            err.multipart_suggestion(
1298                "you might have meant to return this value",
1299                suggs,
1300                Applicability::MaybeIncorrect,
1301            );
1302        }
1303    }
1304
1305    pub(in super::super) fn suggest_missing_parentheses(
1306        &self,
1307        err: &mut Diag<'_>,
1308        expr: &hir::Expr<'_>,
1309    ) -> bool {
1310        let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
1311        if let Some(sp) = self.tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) {
1312            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
1313            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
1314            true
1315        } else {
1316            false
1317        }
1318    }
1319
1320    /// Given an expression type mismatch, peel any `&` expressions until we get to
1321    /// a block expression, and then suggest replacing the braces with square braces
1322    /// if it was possibly mistaken array syntax.
1323    pub(crate) fn suggest_block_to_brackets_peeling_refs(
1324        &self,
1325        diag: &mut Diag<'_>,
1326        mut expr: &hir::Expr<'_>,
1327        mut expr_ty: Ty<'tcx>,
1328        mut expected_ty: Ty<'tcx>,
1329    ) -> bool {
1330        loop {
1331            match (&expr.kind, expr_ty.kind(), expected_ty.kind()) {
1332                (
1333                    hir::ExprKind::AddrOf(_, _, inner_expr),
1334                    ty::Ref(_, inner_expr_ty, _),
1335                    ty::Ref(_, inner_expected_ty, _),
1336                ) => {
1337                    expr = *inner_expr;
1338                    expr_ty = *inner_expr_ty;
1339                    expected_ty = *inner_expected_ty;
1340                }
1341                (hir::ExprKind::Block(blk, _), _, _) => {
1342                    self.suggest_block_to_brackets(diag, blk, expr_ty, expected_ty);
1343                    break true;
1344                }
1345                _ => break false,
1346            }
1347        }
1348    }
1349
1350    pub(crate) fn suggest_clone_for_ref(
1351        &self,
1352        diag: &mut Diag<'_>,
1353        expr: &hir::Expr<'_>,
1354        expr_ty: Ty<'tcx>,
1355        expected_ty: Ty<'tcx>,
1356    ) -> bool {
1357        if let ty::Ref(_, inner_ty, hir::Mutability::Not) = expr_ty.kind()
1358            && let Some(clone_trait_def) = self.tcx.lang_items().clone_trait()
1359            && expected_ty == *inner_ty
1360            && self
1361                .infcx
1362                .type_implements_trait(
1363                    clone_trait_def,
1364                    [self.tcx.erase_and_anonymize_regions(expected_ty)],
1365                    self.param_env,
1366                )
1367                .must_apply_modulo_regions()
1368        {
1369            let suggestion = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
1370                Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}.clone()", ident))
    })format!(": {ident}.clone()"),
1371                None => ".clone()".to_string(),
1372            };
1373
1374            let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span).shrink_to_hi();
1375
1376            diag.span_suggestion_verbose(
1377                span,
1378                "consider using clone here",
1379                suggestion,
1380                Applicability::MachineApplicable,
1381            );
1382            return true;
1383        }
1384        false
1385    }
1386
1387    pub(crate) fn suggest_copied_cloned_or_as_ref(
1388        &self,
1389        diag: &mut Diag<'_>,
1390        expr: &hir::Expr<'_>,
1391        expr_ty: Ty<'tcx>,
1392        expected_ty: Ty<'tcx>,
1393    ) -> bool {
1394        let ty::Adt(adt_def, args) = expr_ty.kind() else {
1395            return false;
1396        };
1397        let ty::Adt(expected_adt_def, expected_args) = expected_ty.kind() else {
1398            return false;
1399        };
1400        if adt_def != expected_adt_def {
1401            return false;
1402        }
1403
1404        if Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Result)
1405            && self.can_eq(self.param_env, args.type_at(1), expected_args.type_at(1))
1406            || Some(adt_def.did()) == self.tcx.get_diagnostic_item(sym::Option)
1407        {
1408            let expr_inner_ty = args.type_at(0);
1409            let expected_inner_ty = expected_args.type_at(0);
1410            if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind()
1411                && self.can_eq(self.param_env, ty, expected_inner_ty)
1412            {
1413                let def_path = self.tcx.def_path_str(adt_def.did());
1414                let span = expr.span.shrink_to_hi();
1415                let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) {
1416                    errors::OptionResultRefMismatch::Copied { span, def_path }
1417                } else if self.type_is_clone_modulo_regions(self.param_env, ty) {
1418                    errors::OptionResultRefMismatch::Cloned { span, def_path }
1419                } else {
1420                    return false;
1421                };
1422                diag.subdiagnostic(subdiag);
1423                return true;
1424            }
1425        }
1426
1427        false
1428    }
1429
1430    pub(crate) fn suggest_into(
1431        &self,
1432        diag: &mut Diag<'_>,
1433        expr: &hir::Expr<'_>,
1434        expr_ty: Ty<'tcx>,
1435        expected_ty: Ty<'tcx>,
1436    ) -> bool {
1437        let expr = expr.peel_blocks();
1438
1439        // We have better suggestions for scalar interconversions...
1440        if expr_ty.is_scalar() && expected_ty.is_scalar() {
1441            return false;
1442        }
1443
1444        // Don't suggest turning a block into another type (e.g. `{}.into()`)
1445        if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    hir::ExprKind::Block(..) => true,
    _ => false,
}matches!(expr.kind, hir::ExprKind::Block(..)) {
1446            return false;
1447        }
1448
1449        // We'll later suggest `.as_ref` when noting the type error,
1450        // so skip if we will suggest that instead.
1451        if self.err_ctxt().should_suggest_as_ref(expected_ty, expr_ty).is_some() {
1452            return false;
1453        }
1454
1455        if let Some(into_def_id) = self.tcx.get_diagnostic_item(sym::Into)
1456            && self.predicate_must_hold_modulo_regions(&traits::Obligation::new(
1457                self.tcx,
1458                self.misc(expr.span),
1459                self.param_env,
1460                ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
1461            ))
1462            && !expr
1463                .span
1464                .macro_backtrace()
1465                .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, ..)))
1466        {
1467            let span = expr
1468                .span
1469                .find_ancestor_not_from_extern_macro(self.tcx.sess.source_map())
1470                .unwrap_or(expr.span);
1471
1472            let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous {
1473                ::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())]
1474            } else {
1475                ::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![
1476                    (span.shrink_to_lo(), "(".to_owned()),
1477                    (span.shrink_to_hi(), ").into()".to_owned()),
1478                ]
1479            };
1480            if let Some(name) = self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
1481                sugg.insert(0, (expr.span.shrink_to_lo(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", name))
    })format!("{}: ", name)));
1482            }
1483            diag.multipart_suggestion(
1484                    ::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}`"),
1485                    sugg,
1486                    Applicability::MaybeIncorrect
1487                );
1488            return true;
1489        }
1490
1491        false
1492    }
1493
1494    /// When expecting a `bool` and finding an `Option`, suggests using `let Some(..)` or `.is_some()`
1495    pub(crate) fn suggest_option_to_bool(
1496        &self,
1497        diag: &mut Diag<'_>,
1498        expr: &hir::Expr<'_>,
1499        expr_ty: Ty<'tcx>,
1500        expected_ty: Ty<'tcx>,
1501    ) -> bool {
1502        if !expected_ty.is_bool() {
1503            return false;
1504        }
1505
1506        let ty::Adt(def, _) = expr_ty.peel_refs().kind() else {
1507            return false;
1508        };
1509        if !self.tcx.is_diagnostic_item(sym::Option, def.did()) {
1510            return false;
1511        }
1512
1513        let cond_parent = self.tcx.hir_parent_iter(expr.hir_id).find(|(_, node)| {
1514            !#[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)
1515        });
1516        // Don't suggest:
1517        //     `let Some(_) = a.is_some() && b`
1518        //                     ++++++++++
1519        // since the user probably just misunderstood how `let else`
1520        // and `&&` work together.
1521        if let Some((_, hir::Node::LetStmt(local))) = cond_parent
1522            && let hir::PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
1523            | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
1524            && let hir::QPath::Resolved(None, path) = qpath
1525            && let Some(did) = path
1526                .res
1527                .opt_def_id()
1528                .and_then(|did| self.tcx.opt_parent(did))
1529                .and_then(|did| self.tcx.opt_parent(did))
1530            && self.tcx.is_diagnostic_item(sym::Option, did)
1531        {
1532            return false;
1533        }
1534
1535        let suggestion = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
1536            Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}.is_some()", ident))
    })format!(": {ident}.is_some()"),
1537            None => ".is_some()".to_string(),
1538        };
1539
1540        diag.span_suggestion_verbose(
1541            expr.span.shrink_to_hi(),
1542            "use `Option::is_some` to test if the `Option` has a value",
1543            suggestion,
1544            Applicability::MachineApplicable,
1545        );
1546        true
1547    }
1548
1549    // Suggest to change `Option<&Vec<T>>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`.
1550    #[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(1550u32),
                                    ::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))]
1551    pub(crate) fn suggest_deref_unwrap_or(
1552        &self,
1553        err: &mut Diag<'_>,
1554        callee_ty: Option<Ty<'tcx>>,
1555        call_ident: Option<Ident>,
1556        expected_ty: Ty<'tcx>,
1557        provided_ty: Ty<'tcx>,
1558        provided_expr: &Expr<'tcx>,
1559        is_method: bool,
1560    ) {
1561        if !is_method {
1562            return;
1563        }
1564        let Some(callee_ty) = callee_ty else {
1565            return;
1566        };
1567        let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else {
1568            return;
1569        };
1570        let adt_name = if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) {
1571            "Option"
1572        } else if self.tcx.is_diagnostic_item(sym::Result, callee_adt.did()) {
1573            "Result"
1574        } else {
1575            return;
1576        };
1577
1578        let Some(call_ident) = call_ident else {
1579            return;
1580        };
1581        if call_ident.name != sym::unwrap_or {
1582            return;
1583        }
1584
1585        let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else {
1586            return;
1587        };
1588
1589        // NOTE: Can we reuse `suggest_deref_or_ref`?
1590
1591        // Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
1592        let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind()
1593            && let ty::Infer(_) = elem_ty.kind()
1594            && self
1595                .try_structurally_resolve_const(provided_expr.span, *size)
1596                .try_to_target_usize(self.tcx)
1597                == Some(0)
1598        {
1599            let slice = Ty::new_slice(self.tcx, *elem_ty);
1600            Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice)
1601        } else {
1602            provided_ty
1603        };
1604
1605        if !self.may_coerce(expected_ty, dummy_ty) {
1606            return;
1607        }
1608        let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`");
1609        err.multipart_suggestion(
1610            msg,
1611            vec![
1612                (call_ident.span, "map_or".to_owned()),
1613                (provided_expr.span.shrink_to_hi(), ", |v| v".to_owned()),
1614            ],
1615            Applicability::MachineApplicable,
1616        );
1617    }
1618
1619    /// Suggest wrapping the block in square brackets instead of curly braces
1620    /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`.
1621    pub(crate) fn suggest_block_to_brackets(
1622        &self,
1623        diag: &mut Diag<'_>,
1624        blk: &hir::Block<'_>,
1625        blk_ty: Ty<'tcx>,
1626        expected_ty: Ty<'tcx>,
1627    ) {
1628        if let ty::Slice(elem_ty) | ty::Array(elem_ty, _) = expected_ty.kind() {
1629            if self.may_coerce(blk_ty, *elem_ty)
1630                && blk.stmts.is_empty()
1631                && blk.rules == hir::BlockCheckMode::DefaultBlock
1632                && let source_map = self.tcx.sess.source_map()
1633                && let Ok(snippet) = source_map.span_to_snippet(blk.span)
1634                && snippet.starts_with('{')
1635                && snippet.ends_with('}')
1636            {
1637                diag.multipart_suggestion(
1638                    "to create an array, use square brackets instead of curly braces",
1639                    ::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![
1640                        (
1641                            blk.span
1642                                .shrink_to_lo()
1643                                .with_hi(rustc_span::BytePos(blk.span.lo().0 + 1)),
1644                            "[".to_string(),
1645                        ),
1646                        (
1647                            blk.span
1648                                .shrink_to_hi()
1649                                .with_lo(rustc_span::BytePos(blk.span.hi().0 - 1)),
1650                            "]".to_string(),
1651                        ),
1652                    ],
1653                    Applicability::MachineApplicable,
1654                );
1655            }
1656        }
1657    }
1658
1659    #[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(1659u32),
                                    ::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))]
1660    pub(crate) fn suggest_floating_point_literal(
1661        &self,
1662        err: &mut Diag<'_>,
1663        expr: &hir::Expr<'_>,
1664        expected_ty: Ty<'tcx>,
1665    ) -> bool {
1666        if !expected_ty.is_floating_point() {
1667            return false;
1668        }
1669        match expr.kind {
1670            ExprKind::Struct(&qpath, [start, end], _)
1671                if is_range_literal(expr)
1672                    && self.tcx.qpath_is_lang_item(qpath, LangItem::Range) =>
1673            {
1674                err.span_suggestion_verbose(
1675                    start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()),
1676                    "remove the unnecessary `.` operator for a floating point literal",
1677                    '.',
1678                    Applicability::MaybeIncorrect,
1679                );
1680                true
1681            }
1682            ExprKind::Struct(&qpath, [arg], _)
1683                if is_range_literal(expr)
1684                    && let Some(qpath @ (LangItem::RangeFrom | LangItem::RangeTo)) =
1685                        self.tcx.qpath_lang_item(qpath) =>
1686            {
1687                let range_span = expr.span.parent_callsite().unwrap();
1688                match qpath {
1689                    LangItem::RangeFrom => {
1690                        err.span_suggestion_verbose(
1691                            range_span.with_lo(arg.expr.span.hi()),
1692                            "remove the unnecessary `.` operator for a floating point literal",
1693                            '.',
1694                            Applicability::MaybeIncorrect,
1695                        );
1696                    }
1697                    _ => {
1698                        err.span_suggestion_verbose(
1699                            range_span.until(arg.expr.span),
1700                            "remove the unnecessary `.` operator and add an integer part for a floating point literal",
1701                            "0.",
1702                            Applicability::MaybeIncorrect,
1703                        );
1704                    }
1705                }
1706                true
1707            }
1708            ExprKind::Lit(Spanned {
1709                node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
1710                span,
1711            }) => {
1712                let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {
1713                    return false;
1714                };
1715                if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
1716                    return false;
1717                }
1718                if snippet.len() <= 5 || !snippet.is_char_boundary(snippet.len() - 3) {
1719                    return false;
1720                }
1721                let (_, suffix) = snippet.split_at(snippet.len() - 3);
1722                let value = match suffix {
1723                    "f32" => (lit.get() - 0xf32) / (16 * 16 * 16),
1724                    "f64" => (lit.get() - 0xf64) / (16 * 16 * 16),
1725                    _ => return false,
1726                };
1727                err.span_suggestions(
1728                    expr.span,
1729                    "rewrite this as a decimal floating point literal, or use `as` to turn a hex literal into a float",
1730                    [format!("0x{value:X} as {suffix}"), format!("{value}_{suffix}")],
1731                    Applicability::MaybeIncorrect,
1732                );
1733                true
1734            }
1735            _ => false,
1736        }
1737    }
1738
1739    /// Suggest providing `std::ptr::null()` or `std::ptr::null_mut()` if they
1740    /// pass in a literal 0 to an raw pointer.
1741    #[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(1741u32),
                                    ::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))]
1742    pub(crate) fn suggest_null_ptr_for_literal_zero_given_to_ptr_arg(
1743        &self,
1744        err: &mut Diag<'_>,
1745        expr: &hir::Expr<'_>,
1746        expected_ty: Ty<'tcx>,
1747    ) -> bool {
1748        // Expected type needs to be a raw pointer.
1749        let ty::RawPtr(_, mutbl) = expected_ty.kind() else {
1750            return false;
1751        };
1752
1753        // Provided expression needs to be a literal `0`.
1754        let ExprKind::Lit(Spanned { node: rustc_ast::LitKind::Int(Pu128(0), _), span }) = expr.kind
1755        else {
1756            return false;
1757        };
1758
1759        // We need to find a null pointer symbol to suggest
1760        let null_sym = match mutbl {
1761            hir::Mutability::Not => sym::ptr_null,
1762            hir::Mutability::Mut => sym::ptr_null_mut,
1763        };
1764        let Some(null_did) = self.tcx.get_diagnostic_item(null_sym) else {
1765            return false;
1766        };
1767        let null_path_str = with_no_trimmed_paths!(self.tcx.def_path_str(null_did));
1768
1769        // We have satisfied all requirements to provide a suggestion. Emit it.
1770        err.span_suggestion(
1771            span,
1772            format!("if you meant to create a null pointer, use `{null_path_str}()`"),
1773            null_path_str + "()",
1774            Applicability::MachineApplicable,
1775        );
1776
1777        true
1778    }
1779
1780    pub(crate) fn suggest_associated_const(
1781        &self,
1782        err: &mut Diag<'_>,
1783        expr: &hir::Expr<'tcx>,
1784        expected_ty: Ty<'tcx>,
1785    ) -> bool {
1786        let Some((DefKind::AssocFn, old_def_id)) =
1787            self.typeck_results.borrow().type_dependent_def(expr.hir_id)
1788        else {
1789            return false;
1790        };
1791        let old_item_name = self.tcx.item_name(old_def_id);
1792        let capitalized_name = Symbol::intern(&old_item_name.as_str().to_uppercase());
1793        if old_item_name == capitalized_name {
1794            return false;
1795        }
1796        let (item, segment) = match expr.kind {
1797            hir::ExprKind::Path(QPath::Resolved(
1798                Some(ty),
1799                hir::Path { segments: [segment], .. },
1800            ))
1801            | hir::ExprKind::Path(QPath::TypeRelative(ty, segment))
1802                if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
1803                    && let Ok(pick) = self.probe_for_name(
1804                        Mode::Path,
1805                        Ident::new(capitalized_name, segment.ident.span),
1806                        Some(expected_ty),
1807                        IsSuggestion(true),
1808                        self_ty,
1809                        expr.hir_id,
1810                        ProbeScope::TraitsInScope,
1811                    ) =>
1812            {
1813                (pick.item, segment)
1814            }
1815            hir::ExprKind::Path(QPath::Resolved(
1816                None,
1817                hir::Path { segments: [.., segment], .. },
1818            )) => {
1819                // we resolved through some path that doesn't end in the item name,
1820                // better not do a bad suggestion by accident.
1821                if old_item_name != segment.ident.name {
1822                    return false;
1823                }
1824                let Some(item) = self
1825                    .tcx
1826                    .associated_items(self.tcx.parent(old_def_id))
1827                    .filter_by_name_unhygienic(capitalized_name)
1828                    .next()
1829                else {
1830                    return false;
1831                };
1832                (*item, segment)
1833            }
1834            _ => return false,
1835        };
1836        if item.def_id == old_def_id
1837            || !#[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 { .. })
1838        {
1839            // Same item
1840            return false;
1841        }
1842        let item_ty = self.tcx.type_of(item.def_id).instantiate_identity();
1843        // FIXME(compiler-errors): This check is *so* rudimentary
1844        if item_ty.has_param() {
1845            return false;
1846        }
1847        if self.may_coerce(item_ty, expected_ty) {
1848            err.span_suggestion_verbose(
1849                segment.ident.span,
1850                ::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",),
1851                capitalized_name,
1852                Applicability::MachineApplicable,
1853            );
1854            true
1855        } else {
1856            false
1857        }
1858    }
1859
1860    fn is_loop(&self, id: HirId) -> bool {
1861        let node = self.tcx.hir_node(id);
1862        #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Expr(Expr { kind: ExprKind::Loop(..), .. }) => true,
    _ => false,
}matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. }))
1863    }
1864
1865    fn is_local_statement(&self, id: HirId) -> bool {
1866        let node = self.tcx.hir_node(id);
1867        #[allow(non_exhaustive_omitted_patterns)] match node {
    Node::Stmt(Stmt { kind: StmtKind::Let(..), .. }) => true,
    _ => false,
}matches!(node, Node::Stmt(Stmt { kind: StmtKind::Let(..), .. }))
1868    }
1869
1870    /// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,
1871    /// which is a side-effect of autoref.
1872    pub(crate) fn note_type_is_not_clone(
1873        &self,
1874        diag: &mut Diag<'_>,
1875        expected_ty: Ty<'tcx>,
1876        found_ty: Ty<'tcx>,
1877        expr: &hir::Expr<'_>,
1878    ) {
1879        // When `expr` is `x` in something like `let x = foo.clone(); x`, need to recurse up to get
1880        // `foo` and `clone`.
1881        let expr = self.note_type_is_not_clone_inner_expr(expr);
1882
1883        // If we've recursed to an `expr` of `foo.clone()`, get `foo` and `clone`.
1884        let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else {
1885            return;
1886        };
1887
1888        let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else {
1889            return;
1890        };
1891        let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
1892        let results = self.typeck_results.borrow();
1893        // First, look for a `Clone::clone` call
1894        if segment.ident.name == sym::clone
1895            && results.type_dependent_def_id(expr.hir_id).is_some_and(|did| {
1896                    let assoc_item = self.tcx.associated_item(did);
1897                    assoc_item.container == ty::AssocContainer::Trait
1898                        && assoc_item.container_id(self.tcx) == clone_trait_did
1899                })
1900            // If that clone call hasn't already dereferenced the self type (i.e. don't give this
1901            // diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
1902            && !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(..)))
1903            // Check that we're in fact trying to clone into the expected type
1904            && self.may_coerce(*pointee_ty, expected_ty)
1905            && let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty])
1906            // And the expected type doesn't implement `Clone`
1907            && !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
1908                self.tcx,
1909                traits::ObligationCause::dummy(),
1910                self.param_env,
1911                trait_ref,
1912            ))
1913        {
1914            diag.span_note(
1915                callee_expr.span,
1916                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` does not implement `Clone`, so `{1}` was cloned instead",
                expected_ty, found_ty))
    })format!(
1917                    "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
1918                ),
1919            );
1920            let owner = self.tcx.hir_enclosing_body_owner(expr.hir_id);
1921            if let ty::Param(param) = expected_ty.kind()
1922                && let Some(generics) = self.tcx.hir_get_generics(owner)
1923            {
1924                suggest_constraining_type_params(
1925                    self.tcx,
1926                    generics,
1927                    diag,
1928                    ::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(),
1929                    None,
1930                );
1931            } else {
1932                let mut suggest_derive = true;
1933                if let Some(errors) =
1934                    self.type_implements_trait_shallow(clone_trait_did, expected_ty, self.param_env)
1935                {
1936                    let manually_impl = "consider manually implementing `Clone` to avoid the \
1937                        implicit type parameter bounds";
1938                    match &errors[..] {
1939                        [] => {}
1940                        [error] => {
1941                            let msg = "`Clone` is not implemented because a trait bound is not \
1942                                satisfied";
1943                            if let traits::ObligationCauseCode::ImplDerived(data) =
1944                                error.obligation.cause.code()
1945                            {
1946                                let mut span: MultiSpan = data.span.into();
1947                                if self.tcx.is_automatically_derived(data.impl_or_alias_def_id) {
1948                                    span.push_span_label(
1949                                        data.span,
1950                                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("derive introduces an implicit `{0}` bound",
                error.obligation.predicate))
    })format!(
1951                                            "derive introduces an implicit `{}` bound",
1952                                            error.obligation.predicate
1953                                        ),
1954                                    );
1955                                }
1956                                diag.span_help(span, msg);
1957                                if self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
1958                                    && data.impl_or_alias_def_id.is_local()
1959                                {
1960                                    diag.help(manually_impl);
1961                                    suggest_derive = false;
1962                                }
1963                            } else {
1964                                diag.help(msg);
1965                            }
1966                        }
1967                        _ => {
1968                            let unsatisfied_bounds: Vec<_> = errors
1969                                .iter()
1970                                .filter_map(|error| match error.obligation.cause.code() {
1971                                    traits::ObligationCauseCode::ImplDerived(data) => {
1972                                        let pre = if self
1973                                            .tcx
1974                                            .is_automatically_derived(data.impl_or_alias_def_id)
1975                                        {
1976                                            "derive introduces an implicit "
1977                                        } else {
1978                                            ""
1979                                        };
1980                                        Some((
1981                                            data.span,
1982                                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}unsatisfied trait bound `{0}`",
                error.obligation.predicate, pre))
    })format!(
1983                                                "{pre}unsatisfied trait bound `{}`",
1984                                                error.obligation.predicate
1985                                            ),
1986                                        ))
1987                                    }
1988                                    _ => None,
1989                                })
1990                                .collect();
1991                            let msg = "`Clone` is not implemented because the some trait bounds \
1992                                could not be satisfied";
1993                            if errors.len() == unsatisfied_bounds.len() {
1994                                let mut unsatisfied_bounds_spans: MultiSpan = unsatisfied_bounds
1995                                    .iter()
1996                                    .map(|(span, _)| *span)
1997                                    .collect::<Vec<Span>>()
1998                                    .into();
1999                                for (span, label) in unsatisfied_bounds {
2000                                    unsatisfied_bounds_spans.push_span_label(span, label);
2001                                }
2002                                diag.span_help(unsatisfied_bounds_spans, msg);
2003                                if errors.iter().all(|error| match error.obligation.cause.code() {
2004                                    traits::ObligationCauseCode::ImplDerived(data) => {
2005                                        self.tcx.is_automatically_derived(data.impl_or_alias_def_id)
2006                                            && data.impl_or_alias_def_id.is_local()
2007                                    }
2008                                    _ => false,
2009                                }) {
2010                                    diag.help(manually_impl);
2011                                    suggest_derive = false;
2012                                }
2013                            } else {
2014                                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!(
2015                                    "{msg}: {}",
2016                                    listify(&errors, |e| format!("`{}`", e.obligation.predicate))
2017                                        .unwrap(),
2018                                ));
2019                            }
2020                        }
2021                    }
2022                    for error in errors {
2023                        if let traits::FulfillmentErrorCode::Select(
2024                            traits::SelectionError::Unimplemented,
2025                        ) = error.code
2026                            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
2027                                error.obligation.predicate.kind().skip_binder()
2028                        {
2029                            self.infcx.err_ctxt().suggest_derive(
2030                                &error.obligation,
2031                                diag,
2032                                error.obligation.predicate.kind().rebind(pred),
2033                            );
2034                        }
2035                    }
2036                }
2037                if suggest_derive {
2038                    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)]);
2039                }
2040            }
2041        }
2042    }
2043
2044    /// Given a type mismatch error caused by `&T` being cloned instead of `T`, and
2045    /// the `expr` as the source of this type mismatch, try to find the method call
2046    /// as the source of this error and return that instead. Otherwise, return the
2047    /// original expression.
2048    fn note_type_is_not_clone_inner_expr<'b>(
2049        &'b self,
2050        expr: &'b hir::Expr<'b>,
2051    ) -> &'b hir::Expr<'b> {
2052        match expr.peel_blocks().kind {
2053            hir::ExprKind::Path(hir::QPath::Resolved(
2054                None,
2055                hir::Path { segments: [_], res: crate::Res::Local(binding), .. },
2056            )) => {
2057                let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding) else {
2058                    return expr;
2059                };
2060
2061                match self.tcx.parent_hir_node(*hir_id) {
2062                    // foo.clone()
2063                    hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
2064                        self.note_type_is_not_clone_inner_expr(init)
2065                    }
2066                    // When `expr` is more complex like a tuple
2067                    hir::Node::Pat(hir::Pat {
2068                        hir_id: pat_hir_id,
2069                        kind: hir::PatKind::Tuple(pats, ..),
2070                        ..
2071                    }) => {
2072                        let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
2073                            self.tcx.parent_hir_node(*pat_hir_id)
2074                        else {
2075                            return expr;
2076                        };
2077
2078                        match init.peel_blocks().kind {
2079                            ExprKind::Tup(init_tup) => {
2080                                if let Some(init) = pats
2081                                    .iter()
2082                                    .enumerate()
2083                                    .filter(|x| x.1.hir_id == *hir_id)
2084                                    .find_map(|(i, _)| init_tup.get(i))
2085                                {
2086                                    self.note_type_is_not_clone_inner_expr(init)
2087                                } else {
2088                                    expr
2089                                }
2090                            }
2091                            _ => expr,
2092                        }
2093                    }
2094                    _ => expr,
2095                }
2096            }
2097            // If we're calling into a closure that may not be typed recurse into that call. no need
2098            // to worry if it's a call to a typed function or closure as this would ne handled
2099            // previously.
2100            hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => {
2101                if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) =
2102                    call_expr_kind
2103                    && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } =
2104                        call_expr_path
2105                    && let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding)
2106                    && let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
2107                        self.tcx.parent_hir_node(*hir_id)
2108                    && let Expr {
2109                        kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
2110                        ..
2111                    } = init
2112                {
2113                    let hir::Body { value: body_expr, .. } = self.tcx.hir_body(*body_id);
2114                    self.note_type_is_not_clone_inner_expr(body_expr)
2115                } else {
2116                    expr
2117                }
2118            }
2119            _ => expr,
2120        }
2121    }
2122
2123    pub(crate) fn is_field_suggestable(
2124        &self,
2125        field: &ty::FieldDef,
2126        hir_id: HirId,
2127        span: Span,
2128    ) -> bool {
2129        // The field must be visible in the containing module.
2130        field.vis.is_accessible_from(self.tcx.parent_module(hir_id), self.tcx)
2131            // The field must not be unstable.
2132            && !#[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!(
2133                self.tcx.eval_stability(field.did, None, rustc_span::DUMMY_SP, None),
2134                rustc_middle::middle::stability::EvalResult::Deny { .. }
2135            )
2136            // If the field is from an external crate it must not be `doc(hidden)`.
2137            && (field.did.is_local() || !self.tcx.is_doc_hidden(field.did))
2138            // If the field is hygienic it must come from the same syntax context.
2139            && self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span)
2140    }
2141
2142    pub(crate) fn suggest_missing_unwrap_expect(
2143        &self,
2144        err: &mut Diag<'_>,
2145        expr: &hir::Expr<'tcx>,
2146        expected: Ty<'tcx>,
2147        found: Ty<'tcx>,
2148    ) -> bool {
2149        let ty::Adt(adt, args) = found.kind() else {
2150            return false;
2151        };
2152        let ret_ty_matches = |diagnostic_item| {
2153            let Some(sig) = self.body_fn_sig() else {
2154                return false;
2155            };
2156            let ty::Adt(kind, _) = sig.output().kind() else {
2157                return false;
2158            };
2159            self.tcx.is_diagnostic_item(diagnostic_item, kind.did())
2160        };
2161
2162        // don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`,
2163        // `None.unwrap()` etc.
2164        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!(
2165            expr.kind,
2166            hir::ExprKind::Call(
2167                hir::Expr {
2168                    kind: hir::ExprKind::Path(hir::QPath::Resolved(
2169                        None,
2170                        hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
2171                    )),
2172                    ..
2173                },
2174                ..,
2175            ) | hir::ExprKind::Path(hir::QPath::Resolved(
2176                None,
2177                hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
2178            )),
2179        );
2180
2181        let (article, kind, variant, sugg_operator) = if self.tcx.is_diagnostic_item(sym::Result, adt.did())
2182            // Do not suggest `.expect()` in const context where it's not available. rust-lang/rust#149316
2183            && !self.tcx.hir_is_inside_const_context(expr.hir_id)
2184        {
2185            ("a", "Result", "Err", ret_ty_matches(sym::Result))
2186        } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) {
2187            ("an", "Option", "None", ret_ty_matches(sym::Option))
2188        } else {
2189            return false;
2190        };
2191        if is_ctor || !self.may_coerce(args.type_at(0), expected) {
2192            return false;
2193        }
2194
2195        let (msg, sugg) = if sugg_operator {
2196            (
2197                ::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!(
2198                    "use the `?` operator to extract the `{found}` value, propagating \
2199                            {article} `{kind}::{variant}` value to the caller"
2200                ),
2201                "?",
2202            )
2203        } else {
2204            (
2205                ::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!(
2206                    "consider using `{kind}::expect` to unwrap the `{found}` value, \
2207                                panicking if the value is {article} `{kind}::{variant}`"
2208                ),
2209                ".expect(\"REASON\")",
2210            )
2211        };
2212
2213        let sugg = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
2214            Some(_) if expr.span.from_expansion() => return false,
2215            Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(": {0}{1}", ident, sugg))
    })format!(": {ident}{sugg}"),
2216            None => sugg.to_string(),
2217        };
2218
2219        let span = expr
2220            .span
2221            .find_ancestor_not_from_extern_macro(self.tcx.sess.source_map())
2222            .unwrap_or(expr.span);
2223        err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
2224        true
2225    }
2226
2227    pub(crate) fn suggest_coercing_result_via_try_operator(
2228        &self,
2229        err: &mut Diag<'_>,
2230        expr: &hir::Expr<'tcx>,
2231        expected: Ty<'tcx>,
2232        found: Ty<'tcx>,
2233    ) -> bool {
2234        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!(
2235            self.tcx.parent_hir_node(expr.hir_id),
2236            hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
2237        ) || self.tcx.hir_get_fn_id_for_return_block(expr.hir_id).is_some();
2238        if returned
2239            && let ty::Adt(e, args_e) = expected.kind()
2240            && let ty::Adt(f, args_f) = found.kind()
2241            && e.did() == f.did()
2242            && Some(e.did()) == self.tcx.get_diagnostic_item(sym::Result)
2243            && let e_ok = args_e.type_at(0)
2244            && let f_ok = args_f.type_at(0)
2245            && self.infcx.can_eq(self.param_env, f_ok, e_ok)
2246            && let e_err = args_e.type_at(1)
2247            && let f_err = args_f.type_at(1)
2248            && self
2249                .infcx
2250                .type_implements_trait(
2251                    self.tcx.get_diagnostic_item(sym::Into).unwrap(),
2252                    [f_err, e_err],
2253                    self.param_env,
2254                )
2255                .must_apply_modulo_regions()
2256        {
2257            err.multipart_suggestion(
2258                "use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
2259                 in `Ok` so the expression remains of type `Result`",
2260                ::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![
2261                    (expr.span.shrink_to_lo(), "Ok(".to_string()),
2262                    (expr.span.shrink_to_hi(), "?)".to_string()),
2263                ],
2264                Applicability::MaybeIncorrect,
2265            );
2266            return true;
2267        }
2268        false
2269    }
2270
2271    // If the expr is a while or for loop and is the tail expr of its
2272    // enclosing body suggest returning a value right after it
2273    pub(crate) fn suggest_returning_value_after_loop(
2274        &self,
2275        err: &mut Diag<'_>,
2276        expr: &hir::Expr<'tcx>,
2277        expected: Ty<'tcx>,
2278    ) -> bool {
2279        let tcx = self.tcx;
2280        let enclosing_scope =
2281            tcx.hir_get_enclosing_scope(expr.hir_id).map(|hir_id| tcx.hir_node(hir_id));
2282
2283        // Get tail expr of the enclosing block or body
2284        let tail_expr = if let Some(Node::Block(hir::Block { expr, .. })) = enclosing_scope
2285            && expr.is_some()
2286        {
2287            *expr
2288        } else {
2289            let body_def_id = tcx.hir_enclosing_body_owner(expr.hir_id);
2290            let body = tcx.hir_body_owned_by(body_def_id);
2291
2292            // Get tail expr of the body
2293            match body.value.kind {
2294                // Regular function body etc.
2295                hir::ExprKind::Block(block, _) => block.expr,
2296                // Anon const body (there's no block in this case)
2297                hir::ExprKind::DropTemps(expr) => Some(expr),
2298                _ => None,
2299            }
2300        };
2301
2302        let Some(tail_expr) = tail_expr else {
2303            return false; // Body doesn't have a tail expr we can compare with
2304        };
2305
2306        // Get the loop expr within the tail expr
2307        let loop_expr_in_tail = match expr.kind {
2308            hir::ExprKind::Loop(_, _, hir::LoopSource::While, _) => tail_expr,
2309            hir::ExprKind::Loop(_, _, hir::LoopSource::ForLoop, _) => {
2310                match tail_expr.peel_drop_temps() {
2311                    Expr { kind: ExprKind::Match(_, [Arm { body, .. }], _), .. } => body,
2312                    _ => return false, // Not really a for loop
2313                }
2314            }
2315            _ => return false, // Not a while or a for loop
2316        };
2317
2318        // If the expr is the loop expr in the tail
2319        // then make the suggestion
2320        if expr.hir_id == loop_expr_in_tail.hir_id {
2321            let span = expr.span;
2322
2323            let (msg, suggestion) = if expected.is_never() {
2324                (
2325                    "consider adding a diverging expression here",
2326                    "`loop {}` or `panic!(\"...\")`".to_string(),
2327                )
2328            } else {
2329                ("consider returning a value here", ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` value", expected))
    })format!("`{expected}` value"))
2330            };
2331
2332            let src_map = tcx.sess.source_map();
2333            let suggestion = if src_map.is_multiline(expr.span) {
2334                let indentation = src_map.indentation_before(span).unwrap_or_default();
2335                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\n{0}/* {1} */", indentation,
                suggestion))
    })format!("\n{indentation}/* {suggestion} */")
2336            } else {
2337                // If the entire expr is on a single line
2338                // put the suggestion also on the same line
2339                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" /* {0} */", suggestion))
    })format!(" /* {suggestion} */")
2340            };
2341
2342            err.span_suggestion_verbose(
2343                span.shrink_to_hi(),
2344                msg,
2345                suggestion,
2346                Applicability::MaybeIncorrect,
2347            );
2348
2349            true
2350        } else {
2351            false
2352        }
2353    }
2354
2355    /// Suggest replacing comma with semicolon in incorrect repeat expressions
2356    /// like `["_", 10]` or `vec![String::new(), 10]`.
2357    pub(crate) fn suggest_semicolon_in_repeat_expr(
2358        &self,
2359        err: &mut Diag<'_>,
2360        expr: &hir::Expr<'_>,
2361        expr_ty: Ty<'tcx>,
2362    ) -> bool {
2363        // Check if `expr` is contained in array of two elements
2364        if let hir::Node::Expr(array_expr) = self.tcx.parent_hir_node(expr.hir_id)
2365            && let hir::ExprKind::Array(elements) = array_expr.kind
2366            && let [first, second] = elements
2367            && second.hir_id == expr.hir_id
2368        {
2369            // Span between the two elements of the array
2370            let comma_span = first.span.between(second.span);
2371
2372            // Check if `expr` is a constant value of type `usize`.
2373            // This can only detect const variable declarations and
2374            // calls to const functions.
2375
2376            // Checking this here instead of rustc_hir::hir because
2377            // this check needs access to `self.tcx` but rustc_hir
2378            // has no access to `TyCtxt`.
2379            let expr_is_const_usize = expr_ty.is_usize()
2380                && match expr.kind {
2381                    ExprKind::Path(QPath::Resolved(
2382                        None,
2383                        Path { res: Res::Def(DefKind::Const { .. }, _), .. },
2384                    )) => true,
2385                    ExprKind::Call(
2386                        Expr {
2387                            kind:
2388                                ExprKind::Path(QPath::Resolved(
2389                                    None,
2390                                    Path { res: Res::Def(DefKind::Fn, fn_def_id), .. },
2391                                )),
2392                            ..
2393                        },
2394                        _,
2395                    ) => self.tcx.is_const_fn(*fn_def_id),
2396                    _ => false,
2397                };
2398
2399            // Type of the first element is guaranteed to be checked
2400            // when execution reaches here because `mismatched types`
2401            // error occurs only when type of second element of array
2402            // is not the same as type of first element.
2403            let first_ty = self.typeck_results.borrow().expr_ty(first);
2404
2405            // `array_expr` is from a macro `vec!["a", 10]` if
2406            // 1. array expression's span is imported from a macro
2407            // 2. first element of array implements `Clone` trait
2408            // 3. second element is an integer literal or is an expression of `usize` like type
2409            if self.tcx.sess.source_map().is_imported(array_expr.span)
2410                && self.type_is_clone_modulo_regions(self.param_env, first_ty)
2411                && (expr.is_size_lit() || expr_ty.is_usize_like())
2412            {
2413                err.subdiagnostic(errors::ReplaceCommaWithSemicolon {
2414                    comma_span,
2415                    descr: "a vector",
2416                });
2417                return true;
2418            }
2419
2420            // `array_expr` is from an array `["a", 10]` if
2421            // 1. first element of array implements `Copy` trait
2422            // 2. second element is an integer literal or is a const value of type `usize`
2423            if self.type_is_copy_modulo_regions(self.param_env, first_ty)
2424                && (expr.is_size_lit() || expr_is_const_usize)
2425            {
2426                err.subdiagnostic(errors::ReplaceCommaWithSemicolon {
2427                    comma_span,
2428                    descr: "an array",
2429                });
2430                return true;
2431            }
2432        }
2433        false
2434    }
2435
2436    /// If the expected type is an enum (Issue #55250) with any variants whose
2437    /// sole field is of the found type, suggest such variants. (Issue #42764)
2438    pub(crate) fn suggest_compatible_variants(
2439        &self,
2440        err: &mut Diag<'_>,
2441        expr: &hir::Expr<'_>,
2442        expected: Ty<'tcx>,
2443        expr_ty: Ty<'tcx>,
2444    ) -> bool {
2445        if expr.span.in_external_macro(self.tcx.sess.source_map()) {
2446            return false;
2447        }
2448        if let ty::Adt(expected_adt, args) = expected.kind() {
2449            if let hir::ExprKind::Field(base, ident) = expr.kind {
2450                let base_ty = self.typeck_results.borrow().expr_ty(base);
2451                if self.can_eq(self.param_env, base_ty, expected)
2452                    && let Some(base_span) = base.span.find_ancestor_inside(expr.span)
2453                {
2454                    err.span_suggestion_verbose(
2455                        expr.span.with_lo(base_span.hi()),
2456                        ::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}`"),
2457                        "",
2458                        Applicability::MaybeIncorrect,
2459                    );
2460                    return true;
2461                }
2462            }
2463
2464            // If the expression is of type () and it's the return expression of a block,
2465            // we suggest adding a separate return expression instead.
2466            // (To avoid things like suggesting `Ok(while .. { .. })`.)
2467            if expr_ty.is_unit() {
2468                let mut id = expr.hir_id;
2469                let mut parent;
2470
2471                // Unroll desugaring, to make sure this works for `for` loops etc.
2472                loop {
2473                    parent = self.tcx.parent_hir_id(id);
2474                    let parent_span = self.tcx.hir_span(parent);
2475                    if parent_span.find_ancestor_inside(expr.span).is_some() {
2476                        // The parent node is part of the same span, so is the result of the
2477                        // same expansion/desugaring and not the 'real' parent node.
2478                        id = parent;
2479                        continue;
2480                    }
2481                    break;
2482                }
2483
2484                if let hir::Node::Block(&hir::Block { span: block_span, expr: Some(e), .. }) =
2485                    self.tcx.hir_node(parent)
2486                {
2487                    if e.hir_id == id {
2488                        if let Some(span) = expr.span.find_ancestor_inside(block_span) {
2489                            let return_suggestions = if self
2490                                .tcx
2491                                .is_diagnostic_item(sym::Result, expected_adt.did())
2492                            {
2493                                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["Ok(())"]))vec!["Ok(())"]
2494                            } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
2495                                ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        ["None", "Some(())"]))vec!["None", "Some(())"]
2496                            } else {
2497                                return false;
2498                            };
2499                            if let Some(indent) =
2500                                self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
2501                            {
2502                                // Add a semicolon, except after `}`.
2503                                let semicolon =
2504                                    match self.tcx.sess.source_map().span_to_snippet(span) {
2505                                        Ok(s) if s.ends_with('}') => "",
2506                                        _ => ";",
2507                                    };
2508                                err.span_suggestions(
2509                                    span.shrink_to_hi(),
2510                                    "try adding an expression at the end of the block",
2511                                    return_suggestions
2512                                        .into_iter()
2513                                        .map(|r| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}\n{1}{2}", semicolon, indent,
                r))
    })format!("{semicolon}\n{indent}{r}")),
2514                                    Applicability::MaybeIncorrect,
2515                                );
2516                            }
2517                            return true;
2518                        }
2519                    }
2520                }
2521            }
2522
2523            let compatible_variants: Vec<(String, _, _, Option<String>)> = expected_adt
2524                .variants()
2525                .iter()
2526                .filter(|variant| {
2527                    variant.fields.len() == 1
2528                })
2529                .filter_map(|variant| {
2530                    let sole_field = &variant.single_field();
2531
2532                    // When expected_ty and expr_ty are the same ADT, we prefer to compare their internal generic params,
2533                    // When the current variant has a sole field whose type is still an unresolved inference variable,
2534                    // suggestions would be often wrong. So suppress the suggestion. See #145294.
2535                    if let (ty::Adt(exp_adt, _), ty::Adt(act_adt, _)) = (expected.kind(), expr_ty.kind())
2536                        && exp_adt.did() == act_adt.did()
2537                        && sole_field.ty(self.tcx, args).is_ty_var() {
2538                            return None;
2539                    }
2540
2541                    let field_is_local = sole_field.did.is_local();
2542                    let field_is_accessible =
2543                        sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx)
2544                        // Skip suggestions for unstable public fields (for example `Pin::__pointer`)
2545                        && #[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);
2546
2547                    if !field_is_local && !field_is_accessible {
2548                        return None;
2549                    }
2550
2551                    let note_about_variant_field_privacy = (field_is_local && !field_is_accessible)
2552                        .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
2553
2554                    let sole_field_ty = sole_field.ty(self.tcx, args);
2555                    if self.may_coerce(expr_ty, sole_field_ty) {
2556                        let variant_path =
2557                            { let _guard = NoTrimmedGuard::new(); self.tcx.def_path_str(variant.def_id) }with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
2558                        // FIXME #56861: DRYer prelude filtering
2559                        if let Some(path) = variant_path.strip_prefix("std::prelude::")
2560                            && let Some((_, path)) = path.split_once("::")
2561                        {
2562                            return Some((path.to_string(), variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy));
2563                        }
2564                        Some((variant_path, variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy))
2565                    } else {
2566                        None
2567                    }
2568                })
2569                .collect();
2570
2571            let suggestions_for = |variant: &_, ctor_kind, field_name| {
2572                let prefix = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
2573                    Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: "),
2574                    None => String::new(),
2575                };
2576
2577                let (open, close) = match ctor_kind {
2578                    Some(CtorKind::Fn) => ("(".to_owned(), ")"),
2579                    None => (::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" {{ {0}: ", field_name))
    })format!(" {{ {field_name}: "), " }"),
2580
2581                    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"),
2582                };
2583
2584                // Suggest constructor as deep into the block tree as possible.
2585                // This fixes https://github.com/rust-lang/rust/issues/101065,
2586                // and also just helps make the most minimal suggestions.
2587                let mut expr = expr;
2588                while let hir::ExprKind::Block(block, _) = &expr.kind
2589                    && let Some(expr_) = &block.expr
2590                {
2591                    expr = expr_
2592                }
2593
2594                ::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![
2595                    (expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
2596                    (expr.span.shrink_to_hi(), close.to_owned()),
2597                ]
2598            };
2599
2600            match &compatible_variants[..] {
2601                [] => { /* No variants to format */ }
2602                [(variant, ctor_kind, field_name, note)] => {
2603                    // Just a single matching variant.
2604                    err.multipart_suggestion(
2605                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("try wrapping the expression in `{1}`{0}",
                note.as_deref().unwrap_or(""), variant))
    })format!(
2606                            "try wrapping the expression in `{variant}`{note}",
2607                            note = note.as_deref().unwrap_or("")
2608                        ),
2609                        suggestions_for(&**variant, *ctor_kind, *field_name),
2610                        Applicability::MaybeIncorrect,
2611                    );
2612                    return true;
2613                }
2614                _ => {
2615                    // More than one matching variant.
2616                    err.multipart_suggestions(
2617                        ::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!(
2618                            "try wrapping the expression in a variant of `{}`",
2619                            self.tcx.def_path_str(expected_adt.did())
2620                        ),
2621                        compatible_variants.into_iter().map(
2622                            |(variant, ctor_kind, field_name, _)| {
2623                                suggestions_for(&variant, ctor_kind, field_name)
2624                            },
2625                        ),
2626                        Applicability::MaybeIncorrect,
2627                    );
2628                    return true;
2629                }
2630            }
2631        }
2632
2633        false
2634    }
2635
2636    pub(crate) fn suggest_non_zero_new_unwrap(
2637        &self,
2638        err: &mut Diag<'_>,
2639        expr: &hir::Expr<'_>,
2640        expected: Ty<'tcx>,
2641        expr_ty: Ty<'tcx>,
2642    ) -> bool {
2643        let tcx = self.tcx;
2644        let (adt, args, unwrap) = match expected.kind() {
2645            // In case `Option<NonZero<T>>` is wanted, but `T` is provided, suggest calling `new`.
2646            ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
2647                let nonzero_type = args.type_at(0); // Unwrap option type.
2648                let ty::Adt(adt, args) = nonzero_type.kind() else {
2649                    return false;
2650                };
2651                (adt, args, "")
2652            }
2653            // In case `NonZero<T>` is wanted but `T` is provided, also add `.unwrap()` to satisfy types.
2654            ty::Adt(adt, args) => (adt, args, ".unwrap()"),
2655            _ => return false,
2656        };
2657
2658        if !self.tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
2659            return false;
2660        }
2661
2662        let int_type = args.type_at(0);
2663        if !self.may_coerce(expr_ty, int_type) {
2664            return false;
2665        }
2666
2667        err.multipart_suggestion(
2668            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider calling `{0}::new`",
                sym::NonZero))
    })format!("consider calling `{}::new`", sym::NonZero),
2669            ::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![
2670                (expr.span.shrink_to_lo(), format!("{}::new(", sym::NonZero)),
2671                (expr.span.shrink_to_hi(), format!("){unwrap}")),
2672            ],
2673            Applicability::MaybeIncorrect,
2674        );
2675
2676        true
2677    }
2678
2679    /// Identify some cases where `as_ref()` would be appropriate and suggest it.
2680    ///
2681    /// Given the following code:
2682    /// ```compile_fail,E0308
2683    /// struct Foo;
2684    /// fn takes_ref(_: &Foo) {}
2685    /// let ref opt = Some(Foo);
2686    ///
2687    /// opt.map(|param| takes_ref(param));
2688    /// ```
2689    /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead.
2690    ///
2691    /// It only checks for `Option` and `Result` and won't work with
2692    /// ```ignore (illustrative)
2693    /// opt.map(|param| { takes_ref(param) });
2694    /// ```
2695    fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> {
2696        let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind else {
2697            return None;
2698        };
2699
2700        let hir::def::Res::Local(local_id) = path.res else {
2701            return None;
2702        };
2703
2704        let Node::Param(hir::Param { hir_id: param_hir_id, .. }) =
2705            self.tcx.parent_hir_node(local_id)
2706        else {
2707            return None;
2708        };
2709
2710        let Node::Expr(hir::Expr {
2711            hir_id: expr_hir_id,
2712            kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
2713            ..
2714        }) = self.tcx.parent_hir_node(*param_hir_id)
2715        else {
2716            return None;
2717        };
2718
2719        let hir = self.tcx.parent_hir_node(*expr_hir_id);
2720        let closure_params_len = closure_fn_decl.inputs.len();
2721        let (
2722            Node::Expr(hir::Expr {
2723                kind: hir::ExprKind::MethodCall(method_path, receiver, ..),
2724                ..
2725            }),
2726            1,
2727        ) = (hir, closure_params_len)
2728        else {
2729            return None;
2730        };
2731
2732        let self_ty = self.typeck_results.borrow().expr_ty(receiver);
2733        let name = method_path.ident.name;
2734        let is_as_ref_able = match self_ty.peel_refs().kind() {
2735            ty::Adt(def, _) => {
2736                (self.tcx.is_diagnostic_item(sym::Option, def.did())
2737                    || self.tcx.is_diagnostic_item(sym::Result, def.did()))
2738                    && (name == sym::map || name == sym::and_then)
2739            }
2740            _ => false,
2741        };
2742        if is_as_ref_able {
2743            Some((
2744                ::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())],
2745                "consider using `as_ref` instead",
2746            ))
2747        } else {
2748            None
2749        }
2750    }
2751
2752    /// This function is used to determine potential "simple" improvements or users' errors and
2753    /// provide them useful help. For example:
2754    ///
2755    /// ```compile_fail,E0308
2756    /// fn some_fn(s: &str) {}
2757    ///
2758    /// let x = "hey!".to_owned();
2759    /// some_fn(x); // error
2760    /// ```
2761    ///
2762    /// No need to find every potential function which could make a coercion to transform a
2763    /// `String` into a `&str` since a `&` would do the trick!
2764    ///
2765    /// In addition of this check, it also checks between references mutability state. If the
2766    /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
2767    /// `&mut`!".
2768    pub(crate) fn suggest_deref_or_ref(
2769        &self,
2770        expr: &hir::Expr<'tcx>,
2771        checked_ty: Ty<'tcx>,
2772        expected: Ty<'tcx>,
2773    ) -> Option<(
2774        Vec<(Span, String)>,
2775        String,
2776        Applicability,
2777        bool, /* verbose */
2778        bool, /* suggest `&` or `&mut` type annotation */
2779    )> {
2780        let sess = self.sess();
2781        let sp = expr.range_span().unwrap_or(expr.span);
2782        let sm = sess.source_map();
2783
2784        // If the span is from an external macro, there's no suggestion we can make.
2785        if sp.in_external_macro(sm) {
2786            return None;
2787        }
2788
2789        let replace_prefix = |s: &str, old: &str, new: &str| {
2790            s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
2791        };
2792
2793        // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
2794        let expr = expr.peel_drop_temps();
2795
2796        match (&expr.kind, expected.kind(), checked_ty.kind()) {
2797            (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) {
2798                (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
2799                    if let hir::ExprKind::Lit(_) = expr.kind
2800                        && let Ok(src) = sm.span_to_snippet(sp)
2801                        && replace_prefix(&src, "b\"", "\"").is_some()
2802                    {
2803                        let pos = sp.lo() + BytePos(1);
2804                        return Some((
2805                            ::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())],
2806                            "consider removing the leading `b`".to_string(),
2807                            Applicability::MachineApplicable,
2808                            true,
2809                            false,
2810                        ));
2811                    }
2812                }
2813                (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
2814                    if let hir::ExprKind::Lit(_) = expr.kind
2815                        && let Ok(src) = sm.span_to_snippet(sp)
2816                        && replace_prefix(&src, "\"", "b\"").is_some()
2817                    {
2818                        return Some((
2819                            ::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())],
2820                            "consider adding a leading `b`".to_string(),
2821                            Applicability::MachineApplicable,
2822                            true,
2823                            false,
2824                        ));
2825                    }
2826                }
2827                _ => {}
2828            },
2829            (_, &ty::Ref(_, _, mutability), _) => {
2830                // Check if it can work when put into a ref. For example:
2831                //
2832                // ```
2833                // fn bar(x: &mut i32) {}
2834                //
2835                // let x = 0u32;
2836                // bar(&x); // error, expected &mut
2837                // ```
2838                let ref_ty = match mutability {
2839                    hir::Mutability::Mut => {
2840                        Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
2841                    }
2842                    hir::Mutability::Not => {
2843                        Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty)
2844                    }
2845                };
2846                if self.may_coerce(ref_ty, expected) {
2847                    let mut sugg_sp = sp;
2848                    if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind {
2849                        let clone_trait =
2850                            self.tcx.require_lang_item(LangItem::Clone, segment.ident.span);
2851                        if args.is_empty()
2852                            && self
2853                                .typeck_results
2854                                .borrow()
2855                                .type_dependent_def_id(expr.hir_id)
2856                                .is_some_and(|did| {
2857                                    let ai = self.tcx.associated_item(did);
2858                                    ai.trait_container(self.tcx) == Some(clone_trait)
2859                                })
2860                            && segment.ident.name == sym::clone
2861                        {
2862                            // If this expression had a clone call when suggesting borrowing
2863                            // we want to suggest removing it because it'd now be unnecessary.
2864                            sugg_sp = receiver.span;
2865                        }
2866                    }
2867
2868                    if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
2869                        && let Some(1) = self.deref_steps_for_suggestion(expected, checked_ty)
2870                        && self.typeck_results.borrow().expr_ty(inner).is_ref()
2871                    {
2872                        // We have `*&T`, check if what was expected was `&T`.
2873                        // If so, we may want to suggest removing a `*`.
2874                        sugg_sp = sugg_sp.with_hi(inner.span.lo());
2875                        return Some((
2876                            ::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())],
2877                            "consider removing deref here".to_string(),
2878                            Applicability::MachineApplicable,
2879                            true,
2880                            false,
2881                        ));
2882                    }
2883
2884                    // Don't try to suggest ref/deref on an `if` expression, because:
2885                    // - The `if` could be part of a desugared `if else` statement,
2886                    //   which would create impossible suggestions such as `if ... { ... } else &if { ... } else { ... }`.
2887                    // - In general the suggestions it creates such as `&if ... { ... } else { ... }` are not very helpful.
2888                    // We try to generate a suggestion such as `if ... { &... } else { &... }` instead.
2889                    if let hir::ExprKind::If(_c, then, els) = expr.kind {
2890                        // The `then` of a `Expr::If` always contains a block, and that block may have a final expression that we can borrow
2891                        // If the block does not have a final expression, it will return () and we do not make a suggestion to borrow that.
2892                        let ExprKind::Block(then, _) = then.kind else { return None };
2893                        let Some(then) = then.expr else { return None };
2894                        let (mut suggs, help, app, verbose, mutref) =
2895                            self.suggest_deref_or_ref(then, checked_ty, expected)?;
2896
2897                        // If there is no `else`, the return type of this `if` will be (), so suggesting to change the `then` block is useless
2898                        let els_expr = match els?.kind {
2899                            ExprKind::Block(block, _) => block.expr?,
2900                            _ => els?,
2901                        };
2902                        let (else_suggs, ..) =
2903                            self.suggest_deref_or_ref(els_expr, checked_ty, expected)?;
2904                        suggs.extend(else_suggs);
2905
2906                        return Some((suggs, help, app, verbose, mutref));
2907                    }
2908
2909                    if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
2910                        return Some((
2911                            sugg,
2912                            msg.to_string(),
2913                            Applicability::MachineApplicable,
2914                            true,
2915                            false,
2916                        ));
2917                    }
2918
2919                    let prefix = match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
2920                        Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: "),
2921                        None => String::new(),
2922                    };
2923
2924                    if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(..), .. }) =
2925                        self.tcx.parent_hir_node(expr.hir_id)
2926                    {
2927                        if mutability.is_mut() {
2928                            // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
2929                            return None;
2930                        }
2931                    }
2932
2933                    let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
2934                        if expr_needs_parens(expr) {
2935                            (
2936                                ::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![
2937                                    (span.shrink_to_lo(), format!("{prefix}{sugg}(")),
2938                                    (span.shrink_to_hi(), ")".to_string()),
2939                                ],
2940                                false,
2941                            )
2942                        } else {
2943                            (::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)
2944                        }
2945                    };
2946
2947                    // Suggest dereferencing the lhs for expressions such as `&T <= T`
2948                    if let hir::Node::Expr(hir::Expr {
2949                        kind: hir::ExprKind::Binary(_, lhs, ..),
2950                        ..
2951                    }) = self.tcx.parent_hir_node(expr.hir_id)
2952                        && let &ty::Ref(..) = self.check_expr(lhs).kind()
2953                    {
2954                        let (sugg, verbose) = make_sugg(lhs, lhs.span, "*");
2955
2956                        return Some((
2957                            sugg,
2958                            "consider dereferencing the borrow".to_string(),
2959                            Applicability::MachineApplicable,
2960                            verbose,
2961                            false,
2962                        ));
2963                    }
2964
2965                    let sugg = mutability.ref_prefix_str();
2966                    let (sugg, verbose) = make_sugg(expr, sp, sugg);
2967                    return Some((
2968                        sugg,
2969                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider {0}borrowing here",
                mutability.mutably_str()))
    })format!("consider {}borrowing here", mutability.mutably_str()),
2970                        Applicability::MachineApplicable,
2971                        verbose,
2972                        false,
2973                    ));
2974                }
2975            }
2976            (hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr), _, &ty::Ref(_, checked, _))
2977                if self.can_eq(self.param_env, checked, expected) =>
2978            {
2979                let make_sugg = |start: Span, end: BytePos| {
2980                    // skip `(` for tuples such as `(c) = (&123)`.
2981                    // make sure we won't suggest like `(c) = 123)` which is incorrect.
2982                    let sp = sm
2983                        .span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
2984                        .map_or(start, |s| s.shrink_to_hi());
2985                    Some((
2986                        ::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())],
2987                        "consider removing the borrow".to_string(),
2988                        Applicability::MachineApplicable,
2989                        true,
2990                        true,
2991                    ))
2992                };
2993
2994                // We have `&T`, check if what was expected was `T`. If so,
2995                // we may want to suggest removing a `&`.
2996                if sm.is_imported(expr.span) {
2997                    // Go through the spans from which this span was expanded,
2998                    // and find the one that's pointing inside `sp`.
2999                    //
3000                    // E.g. for `&format!("")`, where we want the span to the
3001                    // `format!()` invocation instead of its expansion.
3002                    if let Some(call_span) =
3003                        iter::successors(Some(expr.span), |s| s.parent_callsite())
3004                            .find(|&s| sp.contains(s))
3005                        && sm.is_span_accessible(call_span)
3006                    {
3007                        return make_sugg(sp, call_span.lo());
3008                    }
3009                    return None;
3010                }
3011                if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
3012                    return make_sugg(sp, expr.span.lo());
3013                }
3014            }
3015            (_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => {
3016                if let Some(steps) = self.deref_steps_for_suggestion(ty_a, ty_b)
3017                    // Only suggest valid if dereferencing needed.
3018                    && steps > 0
3019                    // The pointer type implements `Copy` trait so the suggestion is always valid.
3020                    && let Ok(src) = sm.span_to_snippet(sp)
3021                {
3022                    let derefs = "*".repeat(steps);
3023                    let old_prefix = mutbl_a.ref_prefix_str();
3024                    let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs;
3025
3026                    let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| {
3027                        // skip `&` or `&mut ` if both mutabilities are mutable
3028                        let lo = sp.lo()
3029                            + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
3030                        // skip `&` or `&mut `
3031                        let hi = sp.lo() + BytePos(old_prefix.len() as _);
3032                        let sp = sp.with_lo(lo).with_hi(hi);
3033
3034                        (
3035                            sp,
3036                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}",
                if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" },
                derefs))
    })format!(
3037                                "{}{derefs}",
3038                                if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }
3039                            ),
3040                            if mutbl_b <= mutbl_a {
3041                                Applicability::MachineApplicable
3042                            } else {
3043                                Applicability::MaybeIncorrect
3044                            },
3045                        )
3046                    });
3047
3048                    if let Some((span, src, applicability)) = suggestion {
3049                        return Some((
3050                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span, src)]))vec![(span, src)],
3051                            "consider dereferencing".to_string(),
3052                            applicability,
3053                            true,
3054                            false,
3055                        ));
3056                    }
3057                }
3058            }
3059            _ if sp == expr.span => {
3060                if let Some(mut steps) = self.deref_steps_for_suggestion(checked_ty, expected) {
3061                    let mut expr = expr.peel_blocks();
3062                    let mut prefix_span = expr.span.shrink_to_lo();
3063                    let mut remove = String::new();
3064
3065                    // Try peeling off any existing `&` and `&mut` to reach our target type
3066                    while steps > 0 {
3067                        if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind {
3068                            // If the expression has `&`, removing it would fix the error
3069                            prefix_span = prefix_span.with_hi(inner.span.lo());
3070                            expr = inner;
3071                            remove.push_str(mutbl.ref_prefix_str());
3072                            steps -= 1;
3073                        } else {
3074                            break;
3075                        }
3076                    }
3077                    // If we've reached our target type with just removing `&`, then just print now.
3078                    if steps == 0 && !remove.trim().is_empty() {
3079                        return Some((
3080                            ::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())],
3081                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider removing the `{0}`",
                remove.trim()))
    })format!("consider removing the `{}`", remove.trim()),
3082                            // Do not remove `&&` to get to bool, because it might be something like
3083                            // { a } && b, which we have a separate fixup suggestion that is more
3084                            // likely correct...
3085                            if remove.trim() == "&&" && expected == self.tcx.types.bool {
3086                                Applicability::MaybeIncorrect
3087                            } else {
3088                                Applicability::MachineApplicable
3089                            },
3090                            true,
3091                            false,
3092                        ));
3093                    }
3094
3095                    // For this suggestion to make sense, the type would need to be `Copy`,
3096                    // or we have to be moving out of a `Box<T>`
3097                    if self.type_is_copy_modulo_regions(self.param_env, expected)
3098                        // FIXME(compiler-errors): We can actually do this if the checked_ty is
3099                        // `steps` layers of boxes, not just one, but this is easier and most likely.
3100                        || (checked_ty.is_box() && steps == 1)
3101                        // We can always deref a binop that takes its arguments by ref.
3102                        || #[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!(
3103                            self.tcx.parent_hir_node(expr.hir_id),
3104                            hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. })
3105                                if !op.node.is_by_value()
3106                        )
3107                    {
3108                        let deref_kind = if checked_ty.is_box() {
3109                            // detect Box::new(..)
3110                            // FIXME: use `box_new` diagnostic item instead?
3111                            if let ExprKind::Call(box_new, [_]) = expr.kind
3112                                && let ExprKind::Path(qpath) = &box_new.kind
3113                                && let Res::Def(DefKind::AssocFn, fn_id) =
3114                                    self.typeck_results.borrow().qpath_res(qpath, box_new.hir_id)
3115                                && let Some(impl_id) = self.tcx.inherent_impl_of_assoc(fn_id)
3116                                && self.tcx.type_of(impl_id).skip_binder().is_box()
3117                                && self.tcx.item_name(fn_id) == sym::new
3118                            {
3119                                let l_paren = self.tcx.sess.source_map().next_point(box_new.span);
3120                                let r_paren = self.tcx.sess.source_map().end_point(expr.span);
3121                                return Some((
3122                                    ::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![
3123                                        (box_new.span.to(l_paren), String::new()),
3124                                        (r_paren, String::new()),
3125                                    ],
3126                                    "consider removing the Box".to_string(),
3127                                    Applicability::MachineApplicable,
3128                                    false,
3129                                    false,
3130                                ));
3131                            }
3132                            "unboxing the value"
3133                        } else if checked_ty.is_ref() {
3134                            "dereferencing the borrow"
3135                        } else {
3136                            "dereferencing the type"
3137                        };
3138
3139                        // Suggest removing `&` if we have removed any, otherwise suggest just
3140                        // dereferencing the remaining number of steps.
3141                        let message = if remove.is_empty() {
3142                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider {0}", deref_kind))
    })format!("consider {deref_kind}")
3143                        } else {
3144                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider removing the `{0}` and {1} instead",
                remove.trim(), deref_kind))
    })format!(
3145                                "consider removing the `{}` and {} instead",
3146                                remove.trim(),
3147                                deref_kind
3148                            )
3149                        };
3150
3151                        let prefix =
3152                            match self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr) {
3153                                Some(ident) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", ident))
    })format!("{ident}: "),
3154                                None => String::new(),
3155                            };
3156
3157                        let (span, suggestion) = if self.is_else_if_block(expr) {
3158                            // Don't suggest nonsense like `else *if`
3159                            return None;
3160                        } else if let Some(expr) = self.maybe_get_block_expr(expr) {
3161                            // prefix should be empty here..
3162                            (expr.span.shrink_to_lo(), "*".to_string())
3163                        } else {
3164                            (prefix_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", prefix,
                "*".repeat(steps)))
    })format!("{}{}", prefix, "*".repeat(steps)))
3165                        };
3166                        if suggestion.trim().is_empty() {
3167                            return None;
3168                        }
3169
3170                        if expr_needs_parens(expr) {
3171                            return Some((
3172                                ::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![
3173                                    (span, format!("{suggestion}(")),
3174                                    (expr.span.shrink_to_hi(), ")".to_string()),
3175                                ],
3176                                message,
3177                                Applicability::MachineApplicable,
3178                                true,
3179                                false,
3180                            ));
3181                        }
3182
3183                        return Some((
3184                            ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(span, suggestion)]))vec![(span, suggestion)],
3185                            message,
3186                            Applicability::MachineApplicable,
3187                            true,
3188                            false,
3189                        ));
3190                    }
3191                }
3192            }
3193            _ => {}
3194        }
3195        None
3196    }
3197
3198    /// Returns whether the given expression is an `else if`.
3199    fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
3200        if let hir::ExprKind::If(..) = expr.kind
3201            && let Node::Expr(hir::Expr { kind: hir::ExprKind::If(_, _, Some(else_expr)), .. }) =
3202                self.tcx.parent_hir_node(expr.hir_id)
3203        {
3204            return else_expr.hir_id == expr.hir_id;
3205        }
3206        false
3207    }
3208
3209    pub(crate) fn suggest_cast(
3210        &self,
3211        err: &mut Diag<'_>,
3212        expr: &hir::Expr<'_>,
3213        checked_ty: Ty<'tcx>,
3214        expected_ty: Ty<'tcx>,
3215        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
3216    ) -> bool {
3217        if self.tcx.sess.source_map().is_imported(expr.span) {
3218            // Ignore if span is from within a macro.
3219            return false;
3220        }
3221
3222        let span = if let hir::ExprKind::Lit(lit) = &expr.kind { lit.span } else { expr.span };
3223        let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) else {
3224            return false;
3225        };
3226
3227        // If casting this expression to a given numeric type would be appropriate in case of a type
3228        // mismatch.
3229        //
3230        // We want to minimize the amount of casting operations that are suggested, as it can be a
3231        // lossy operation with potentially bad side effects, so we only suggest when encountering
3232        // an expression that indicates that the original type couldn't be directly changed.
3233        //
3234        // For now, don't suggest casting with `as`.
3235        let can_cast = false;
3236
3237        let mut sugg = ::alloc::vec::Vec::new()vec![];
3238
3239        if let hir::Node::ExprField(field) = self.tcx.parent_hir_node(expr.hir_id) {
3240            // `expr` is a literal field for a struct, only suggest if appropriate
3241            if field.is_shorthand {
3242                // This is a field literal
3243                sugg.push((field.ident.span.shrink_to_lo(), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: ", field.ident))
    })format!("{}: ", field.ident)));
3244            } else {
3245                // Likely a field was meant, but this field wasn't found. Do not suggest anything.
3246                return false;
3247            }
3248        };
3249
3250        if let hir::ExprKind::Call(path, args) = &expr.kind
3251            && let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
3252                (&path.kind, args.len())
3253            // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697).
3254            && let (hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), sym::from) =
3255                (&base_ty.kind, path_segment.ident.name)
3256        {
3257            if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() {
3258                match ident.name {
3259                    sym::i128
3260                    | sym::i64
3261                    | sym::i32
3262                    | sym::i16
3263                    | sym::i8
3264                    | sym::u128
3265                    | sym::u64
3266                    | sym::u32
3267                    | sym::u16
3268                    | sym::u8
3269                    | sym::isize
3270                    | sym::usize
3271                        if base_ty_path.segments.len() == 1 =>
3272                    {
3273                        return false;
3274                    }
3275                    _ => {}
3276                }
3277            }
3278        }
3279
3280        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!(
3281            "you can convert {} `{}` to {} `{}`",
3282            checked_ty.kind().article(),
3283            checked_ty,
3284            expected_ty.kind().article(),
3285            expected_ty,
3286        );
3287        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!(
3288            "you can cast {} `{}` to {} `{}`",
3289            checked_ty.kind().article(),
3290            checked_ty,
3291            expected_ty.kind().article(),
3292            expected_ty,
3293        );
3294        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!(
3295            "change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
3296        );
3297
3298        let close_paren = if self.precedence(expr) < ExprPrecedence::Unambiguous {
3299            sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
3300            ")"
3301        } else {
3302            ""
3303        };
3304
3305        let mut cast_suggestion = sugg.clone();
3306        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}")));
3307        let mut into_suggestion = sugg.clone();
3308        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()")));
3309        let mut suffix_suggestion = sugg.clone();
3310        suffix_suggestion.push((
3311            if #[allow(non_exhaustive_omitted_patterns)] match (expected_ty.kind(),
        checked_ty.kind()) {
    (ty::Int(_) | ty::Uint(_), ty::Float(_)) => true,
    _ => false,
}matches!(
3312                (expected_ty.kind(), checked_ty.kind()),
3313                (ty::Int(_) | ty::Uint(_), ty::Float(_))
3314            ) {
3315                // Remove fractional part from literal, for example `42.0f32` into `42`
3316                let src = src.trim_end_matches(&checked_ty.to_string());
3317                let len = src.split('.').next().unwrap().len();
3318                span.with_lo(span.lo() + BytePos(len as u32))
3319            } else {
3320                let len = src.trim_end_matches(&checked_ty.to_string()).len();
3321                span.with_lo(span.lo() + BytePos(len as u32))
3322            },
3323            if self.precedence(expr) < ExprPrecedence::Unambiguous {
3324                // Readd `)`
3325                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0})", expected_ty))
    })format!("{expected_ty})")
3326            } else {
3327                expected_ty.to_string()
3328            },
3329        ));
3330        let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
3331            if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
3332        };
3333        let is_negative_int =
3334            |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, ..));
3335        let is_uint = |ty: Ty<'_>| #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Uint(..) => true,
    _ => false,
}matches!(ty.kind(), ty::Uint(..));
3336
3337        let in_const_context = self.tcx.hir_is_inside_const_context(expr.hir_id);
3338
3339        let suggest_fallible_into_or_lhs_from =
3340            |err: &mut Diag<'_>, exp_to_found_is_fallible: bool| {
3341                // If we know the expression the expected type is derived from, we might be able
3342                // to suggest a widening conversion rather than a narrowing one (which may
3343                // panic). For example, given x: u8 and y: u32, if we know the span of "x",
3344                //   x > y
3345                // can be given the suggestion "u32::from(x) > y" rather than
3346                // "x > y.try_into().unwrap()".
3347                let lhs_expr_and_src = expected_ty_expr.and_then(|expr| {
3348                    self.tcx
3349                        .sess
3350                        .source_map()
3351                        .span_to_snippet(expr.span)
3352                        .ok()
3353                        .map(|src| (expr, src))
3354                });
3355                let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
3356                    (lhs_expr_and_src, exp_to_found_is_fallible)
3357                {
3358                    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!(
3359                        "you can convert `{lhs_src}` from `{expected_ty}` to `{checked_ty}`, matching the type of `{src}`",
3360                    );
3361                    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![
3362                        (lhs_expr.span.shrink_to_lo(), format!("{checked_ty}::from(")),
3363                        (lhs_expr.span.shrink_to_hi(), ")".to_string()),
3364                    ];
3365                    (msg, suggestion)
3366                } else {
3367                    let msg =
3368                        ::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());
3369                    let mut suggestion = sugg.clone();
3370                    suggestion.push((
3371                        expr.span.shrink_to_hi(),
3372                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}.try_into().unwrap()",
                close_paren))
    })format!("{close_paren}.try_into().unwrap()"),
3373                    ));
3374                    (msg, suggestion)
3375                };
3376                err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);
3377            };
3378
3379        let suggest_to_change_suffix_or_into =
3380            |err: &mut Diag<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| {
3381                let exp_is_lhs = expected_ty_expr.is_some_and(|e| self.tcx.hir_is_lhs(e.hir_id));
3382
3383                if exp_is_lhs {
3384                    return;
3385                }
3386
3387                let always_fallible = found_to_exp_is_fallible
3388                    && (exp_to_found_is_fallible || expected_ty_expr.is_none());
3389                let msg = if literal_is_ty_suffixed(expr) {
3390                    lit_msg.clone()
3391                } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
3392                    // We now know that converting either the lhs or rhs is fallible. Before we
3393                    // suggest a fallible conversion, check if the value can never fit in the
3394                    // expected type.
3395                    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}`");
3396                    err.note(msg);
3397                    return;
3398                } else if in_const_context {
3399                    // Do not recommend `into` or `try_into` in const contexts.
3400                    return;
3401                } else if found_to_exp_is_fallible {
3402                    return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible);
3403                } else {
3404                    msg.clone()
3405                };
3406                let suggestion = if literal_is_ty_suffixed(expr) {
3407                    suffix_suggestion.clone()
3408                } else {
3409                    into_suggestion.clone()
3410                };
3411                err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);
3412            };
3413
3414        match (expected_ty.kind(), checked_ty.kind()) {
3415            (ty::Int(exp), ty::Int(found)) => {
3416                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3417                {
3418                    (Some(exp), Some(found)) if exp < found => (true, false),
3419                    (Some(exp), Some(found)) if exp > found => (false, true),
3420                    (None, Some(8 | 16)) => (false, true),
3421                    (Some(8 | 16), None) => (true, false),
3422                    (None, _) | (_, None) => (true, true),
3423                    _ => (false, false),
3424                };
3425                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3426                true
3427            }
3428            (ty::Uint(exp), ty::Uint(found)) => {
3429                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3430                {
3431                    (Some(exp), Some(found)) if exp < found => (true, false),
3432                    (Some(exp), Some(found)) if exp > found => (false, true),
3433                    (None, Some(8 | 16)) => (false, true),
3434                    (Some(8 | 16), None) => (true, false),
3435                    (None, _) | (_, None) => (true, true),
3436                    _ => (false, false),
3437                };
3438                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3439                true
3440            }
3441            (&ty::Int(exp), &ty::Uint(found)) => {
3442                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3443                {
3444                    (Some(exp), Some(found)) if found < exp => (false, true),
3445                    (None, Some(8)) => (false, true),
3446                    _ => (true, true),
3447                };
3448                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3449                true
3450            }
3451            (&ty::Uint(exp), &ty::Int(found)) => {
3452                let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
3453                {
3454                    (Some(exp), Some(found)) if found > exp => (true, false),
3455                    (Some(8), None) => (true, false),
3456                    _ => (true, true),
3457                };
3458                suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
3459                true
3460            }
3461            (ty::Float(exp), ty::Float(found)) => {
3462                if found.bit_width() < exp.bit_width() {
3463                    suggest_to_change_suffix_or_into(err, false, true);
3464                } else if literal_is_ty_suffixed(expr) {
3465                    err.multipart_suggestion(
3466                        lit_msg,
3467                        suffix_suggestion,
3468                        Applicability::MachineApplicable,
3469                    );
3470                } else if can_cast {
3471                    // Missing try_into implementation for `f64` to `f32`
3472                    err.multipart_suggestion(
3473                        ::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"),
3474                        cast_suggestion,
3475                        Applicability::MaybeIncorrect, // lossy conversion
3476                    );
3477                }
3478                true
3479            }
3480            (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
3481                if literal_is_ty_suffixed(expr) {
3482                    err.multipart_suggestion(
3483                        lit_msg,
3484                        suffix_suggestion,
3485                        Applicability::MachineApplicable,
3486                    );
3487                } else if can_cast {
3488                    // Missing try_into implementation for `{float}` to `{integer}`
3489                    err.multipart_suggestion(
3490                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, rounding the float towards zero",
                msg))
    })format!("{msg}, rounding the float towards zero"),
3491                        cast_suggestion,
3492                        Applicability::MaybeIncorrect, // lossy conversion
3493                    );
3494                }
3495                true
3496            }
3497            (ty::Float(exp), ty::Uint(found)) => {
3498                // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
3499                if exp.bit_width() > found.bit_width().unwrap_or(256) {
3500                    err.multipart_suggestion(
3501                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer",
                msg))
    })format!(
3502                            "{msg}, producing the floating point representation of the integer",
3503                        ),
3504                        into_suggestion,
3505                        Applicability::MachineApplicable,
3506                    );
3507                } else if literal_is_ty_suffixed(expr) {
3508                    err.multipart_suggestion(
3509                        lit_msg,
3510                        suffix_suggestion,
3511                        Applicability::MachineApplicable,
3512                    );
3513                } else {
3514                    // Missing try_into implementation for `{integer}` to `{float}`
3515                    err.multipart_suggestion(
3516                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer, rounded if necessary",
                cast_msg))
    })format!(
3517                            "{cast_msg}, producing the floating point representation of the integer, \
3518                                 rounded if necessary",
3519                        ),
3520                        cast_suggestion,
3521                        Applicability::MaybeIncorrect, // lossy conversion
3522                    );
3523                }
3524                true
3525            }
3526            (ty::Float(exp), ty::Int(found)) => {
3527                // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
3528                if exp.bit_width() > found.bit_width().unwrap_or(256) {
3529                    err.multipart_suggestion(
3530                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer",
                msg.clone()))
    })format!(
3531                            "{}, producing the floating point representation of the integer",
3532                            msg.clone(),
3533                        ),
3534                        into_suggestion,
3535                        Applicability::MachineApplicable,
3536                    );
3537                } else if literal_is_ty_suffixed(expr) {
3538                    err.multipart_suggestion(
3539                        lit_msg,
3540                        suffix_suggestion,
3541                        Applicability::MachineApplicable,
3542                    );
3543                } else {
3544                    // Missing try_into implementation for `{integer}` to `{float}`
3545                    err.multipart_suggestion(
3546                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}, producing the floating point representation of the integer, rounded if necessary",
                &msg))
    })format!(
3547                            "{}, producing the floating point representation of the integer, \
3548                                rounded if necessary",
3549                            &msg,
3550                        ),
3551                        cast_suggestion,
3552                        Applicability::MaybeIncorrect, // lossy conversion
3553                    );
3554                }
3555                true
3556            }
3557            (
3558                &ty::Uint(ty::UintTy::U32 | ty::UintTy::U64 | ty::UintTy::U128)
3559                | &ty::Int(ty::IntTy::I32 | ty::IntTy::I64 | ty::IntTy::I128),
3560                &ty::Char,
3561            ) => {
3562                err.multipart_suggestion(
3563                    ::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"),
3564                    cast_suggestion,
3565                    Applicability::MachineApplicable,
3566                );
3567                true
3568            }
3569            _ => false,
3570        }
3571    }
3572
3573    /// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
3574    pub(crate) fn suggest_method_call_on_range_literal(
3575        &self,
3576        err: &mut Diag<'_>,
3577        expr: &hir::Expr<'tcx>,
3578        checked_ty: Ty<'tcx>,
3579        expected_ty: Ty<'tcx>,
3580    ) {
3581        if !hir::is_range_literal(expr) {
3582            return;
3583        }
3584        let hir::ExprKind::Struct(&qpath, [start, end], _) = expr.kind else {
3585            return;
3586        };
3587        if !self.tcx.qpath_is_lang_item(qpath, LangItem::Range) {
3588            return;
3589        }
3590        if let hir::Node::ExprField(_) = self.tcx.parent_hir_node(expr.hir_id) {
3591            // Ignore `Foo { field: a..Default::default() }`
3592            return;
3593        }
3594        let mut expr = end.expr;
3595        let mut expectation = Some(expected_ty);
3596        while let hir::ExprKind::MethodCall(_, rcvr, ..) = expr.kind {
3597            // Getting to the root receiver and asserting it is a fn call let's us ignore cases in
3598            // `tests/ui/methods/issues/issue-90315.stderr`.
3599            expr = rcvr;
3600            // If we have more than one layer of calls, then the expected ty
3601            // cannot guide the method probe.
3602            expectation = None;
3603        }
3604        let hir::ExprKind::Call(method_name, _) = expr.kind else {
3605            return;
3606        };
3607        let ty::Adt(adt, _) = checked_ty.kind() else {
3608            return;
3609        };
3610        if self.tcx.lang_items().range_struct() != Some(adt.did()) {
3611            return;
3612        }
3613        if let ty::Adt(adt, _) = expected_ty.kind()
3614            && self.tcx.is_lang_item(adt.did(), LangItem::Range)
3615        {
3616            return;
3617        }
3618        // Check if start has method named end.
3619        let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = method_name.kind else {
3620            return;
3621        };
3622        let [hir::PathSegment { ident, .. }] = p.segments else {
3623            return;
3624        };
3625        let self_ty = self.typeck_results.borrow().expr_ty(start.expr);
3626        let Ok(_pick) = self.lookup_probe_for_diagnostic(
3627            *ident,
3628            self_ty,
3629            expr,
3630            probe::ProbeScope::AllTraits,
3631            expectation,
3632        ) else {
3633            return;
3634        };
3635        let mut sugg = ".";
3636        let mut span = start.expr.span.between(end.expr.span);
3637        if span.lo() + BytePos(2) == span.hi() {
3638            // There's no space between the start, the range op and the end, suggest removal which
3639            // will be more noticeable than the replacement of `..` with `.`.
3640            span = span.with_lo(span.lo() + BytePos(1));
3641            sugg = "";
3642        }
3643        err.span_suggestion_verbose(
3644            span,
3645            "you likely meant to write a method call instead of a range",
3646            sugg,
3647            Applicability::MachineApplicable,
3648        );
3649    }
3650
3651    /// Identify when the type error is because `()` is found in a binding that was assigned a
3652    /// block without a tail expression.
3653    pub(crate) fn suggest_return_binding_for_missing_tail_expr(
3654        &self,
3655        err: &mut Diag<'_>,
3656        expr: &hir::Expr<'_>,
3657        checked_ty: Ty<'tcx>,
3658        expected_ty: Ty<'tcx>,
3659    ) {
3660        if !checked_ty.is_unit() {
3661            return;
3662        }
3663        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {
3664            return;
3665        };
3666        let hir::def::Res::Local(hir_id) = path.res else {
3667            return;
3668        };
3669        let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
3670            return;
3671        };
3672        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =
3673            self.tcx.parent_hir_node(pat.hir_id)
3674        else {
3675            return;
3676        };
3677        let hir::ExprKind::Block(block, None) = init.kind else {
3678            return;
3679        };
3680        if block.expr.is_some() {
3681            return;
3682        }
3683        let [.., stmt] = block.stmts else {
3684            err.span_label(block.span, "this empty block is missing a tail expression");
3685            return;
3686        };
3687        let hir::StmtKind::Semi(tail_expr) = stmt.kind else {
3688            return;
3689        };
3690        let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else {
3691            return;
3692        };
3693        if self.can_eq(self.param_env, expected_ty, ty)
3694            // FIXME: this happens with macro calls. Need to figure out why the stmt
3695            // `println!();` doesn't include the `;` in its `Span`. (#133845)
3696            // We filter these out to avoid ICEs with debug assertions on caused by
3697            // empty suggestions.
3698            && stmt.span.hi() != tail_expr.span.hi()
3699        {
3700            err.span_suggestion_short(
3701                stmt.span.with_lo(tail_expr.span.hi()),
3702                "remove this semicolon",
3703                "",
3704                Applicability::MachineApplicable,
3705            );
3706        } else {
3707            err.span_label(block.span, "this block is missing a tail expression");
3708        }
3709    }
3710
3711    pub(crate) fn suggest_swapping_lhs_and_rhs(
3712        &self,
3713        err: &mut Diag<'_>,
3714        rhs_ty: Ty<'tcx>,
3715        lhs_ty: Ty<'tcx>,
3716        rhs_expr: &'tcx hir::Expr<'tcx>,
3717        lhs_expr: &'tcx hir::Expr<'tcx>,
3718    ) {
3719        if let Some(partial_eq_def_id) = self.infcx.tcx.lang_items().eq_trait()
3720            && self
3721                .infcx
3722                .type_implements_trait(partial_eq_def_id, [rhs_ty, lhs_ty], self.param_env)
3723                .must_apply_modulo_regions()
3724        {
3725            let sm = self.tcx.sess.source_map();
3726            // If the span of rhs_expr or lhs_expr is in an external macro,
3727            // we just suppress the suggestion. See issue #139050
3728            if !rhs_expr.span.in_external_macro(sm)
3729                && !lhs_expr.span.in_external_macro(sm)
3730                && let Ok(rhs_snippet) = sm.span_to_snippet(rhs_expr.span)
3731                && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_expr.span)
3732            {
3733                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}>`"));
3734                err.multipart_suggestion(
3735                    "consider swapping the equality",
3736                    ::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)],
3737                    Applicability::MaybeIncorrect,
3738                );
3739            }
3740        }
3741    }
3742}