Skip to main content

rustc_hir_typeck/fn_ctxt/
suggestions.rs

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