compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs RUST 6,647 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 6,647.
1// ignore-tidy-filelength23use std::borrow::Cow;4use std::path::PathBuf;5use std::{debug_assert_matches, iter};67use itertools::{EitherOrBoth, Itertools};8use rustc_abi::ExternAbi;9use rustc_data_structures::fx::FxHashSet;10use rustc_data_structures::stack::ensure_sufficient_stack;11use rustc_errors::codes::*;12use rustc_errors::{13    Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize,14    struct_span_code_err,15};16use rustc_hir::def::{CtorOf, DefKind, Res};17use rustc_hir::def_id::DefId;18use rustc_hir::intravisit::{Visitor, VisitorExt};19use rustc_hir::lang_items::LangItem;20use rustc_hir::{21    self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,22    expr_needs_parens,23};24use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};25use rustc_infer::traits::ImplSource;26use rustc_middle::middle::privacy::Level;27use rustc_middle::traits::IsConstable;28use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind};29use rustc_middle::ty::error::TypeError;30use rustc_middle::ty::print::{31    PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _,32    PrintTraitRefExt as _, with_forced_trimmed_paths, with_no_trimmed_paths,33    with_types_for_suggestion,34};35use rustc_middle::ty::{36    self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,37    TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, TypeckResults,38    Unnormalized, Upcast, suggest_arbitrary_trait_bound, suggest_constraining_type_param,39};40use rustc_middle::{bug, span_bug};41use rustc_span::def_id::LocalDefId;42use rustc_span::{43    BytePos, DUMMY_SP, DesugaringKind, ExpnKind, Ident, MacroKind, Span, Symbol, kw, sym,44};45use tracing::{debug, instrument};4647use super::{48    DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode,49    PredicateObligation,50};51use crate::error_reporting::TypeErrCtxt;52use crate::errors;53use crate::infer::InferCtxtExt as _;54use crate::traits::query::evaluate_obligation::InferCtxtExt as _;55use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt, SelectionContext};5657#[derive(Debug)]58pub enum CoroutineInteriorOrUpvar {59    // span of interior type60    Interior(Span, Option<(Span, Option<Span>)>),61    // span of upvar62    Upvar(Span),63}6465// This type provides a uniform interface to retrieve data on coroutines, whether it originated from66// the local crate being compiled or from a foreign crate.67#[derive(Debug)]68struct CoroutineData<'a, 'tcx>(&'a TypeckResults<'tcx>);6970impl<'a, 'tcx> CoroutineData<'a, 'tcx> {71    /// Try to get information about variables captured by the coroutine that matches a type we are72    /// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to73    /// meet an obligation74    fn try_get_upvar_span<F>(75        &self,76        infer_context: &InferCtxt<'tcx>,77        coroutine_did: DefId,78        ty_matches: F,79    ) -> Option<CoroutineInteriorOrUpvar>80    where81        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,82    {83        infer_context.tcx.upvars_mentioned(coroutine_did).and_then(|upvars| {84            upvars.iter().find_map(|(upvar_id, upvar)| {85                let upvar_ty = self.0.node_type(*upvar_id);86                let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);87                ty_matches(ty::Binder::dummy(upvar_ty))88                    .then(|| CoroutineInteriorOrUpvar::Upvar(upvar.span))89            })90        })91    }9293    /// Try to get the span of a type being awaited on that matches the type we are looking with the94    /// `ty_matches` function. We uses it to find awaited type which causes a failure to meet an95    /// obligation96    fn get_from_await_ty<F>(97        &self,98        visitor: AwaitsVisitor,99        tcx: TyCtxt<'tcx>,100        ty_matches: F,101    ) -> Option<Span>102    where103        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,104    {105        visitor106            .awaits107            .into_iter()108            .map(|id| tcx.hir_expect_expr(id))109            .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(await_expr))))110            .map(|expr| expr.span)111    }112}113114fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {115    (116        generics.tail_span_for_predicate_suggestion(),117        with_types_for_suggestion!(format!("{} {}", generics.add_where_or_trailing_comma(), pred)),118    )119}120121/// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but122/// it can also be an `impl Trait` param that needs to be decomposed to a type123/// param for cleaner code.124pub fn suggest_restriction<'tcx, G: EmissionGuarantee>(125    tcx: TyCtxt<'tcx>,126    item_id: LocalDefId,127    hir_generics: &hir::Generics<'tcx>,128    msg: &str,129    err: &mut Diag<'_, G>,130    fn_sig: Option<&hir::FnSig<'_>>,131    projection: Option<ty::AliasTy<'_>>,132    trait_pred: ty::PolyTraitPredicate<'tcx>,133    // When we are dealing with a trait, `super_traits` will be `Some`:134    // Given `trait T: A + B + C {}`135    //              -  ^^^^^^^^^ GenericBounds136    //              |137    //              &Ident138    super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,139) {140    if hir_generics.where_clause_span.from_expansion()141        || hir_generics.where_clause_span.desugaring_kind().is_some()142        || projection.is_some_and(|projection| {143            (tcx.is_impl_trait_in_trait(projection.kind.def_id())144                && !tcx.features().return_type_notation())145                || tcx146                    .lookup_stability(projection.kind.def_id())147                    .is_some_and(|stab| stab.is_unstable())148        })149    {150        return;151    }152    let generics = tcx.generics_of(item_id);153    // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...154    if let Some((param, bound_str, fn_sig)) =155        fn_sig.zip(projection).and_then(|(sig, p)| match *p.self_ty().kind() {156            // Shenanigans to get the `Trait` from the `impl Trait`.157            ty::Param(param) => {158                let param_def = generics.type_param(param, tcx);159                if param_def.kind.is_synthetic() {160                    let bound_str =161                        param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string();162                    return Some((param_def, bound_str, sig));163                }164                None165            }166            _ => None,167        })168    {169        let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str));170        let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder {171            tcx,172            param,173            replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))174                .to_ty(tcx),175        });176        if !trait_pred.is_suggestable(tcx, false) {177            return;178        }179        // We know we have an `impl Trait` that doesn't satisfy a required projection.180181        // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'182        // types. There should be at least one, but there might be *more* than one. In that183        // case we could just ignore it and try to identify which one needs the restriction,184        // but instead we choose to suggest replacing all instances of `impl Trait` with `T`185        // where `T: Trait`.186        let mut ty_spans = vec![];187        for input in fn_sig.decl.inputs {188            ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }189                .visit_ty_unambig(input);190        }191        // The type param `T: Trait` we will suggest to introduce.192        let type_param = format!("{type_param_name}: {bound_str}");193194        let mut sugg = vec![195            if let Some(span) = hir_generics.span_for_param_suggestion() {196                (span, format!(", {type_param}"))197            } else {198                (hir_generics.span, format!("<{type_param}>"))199            },200            // `fn foo(t: impl Trait)`201            //                       ^ suggest `where <T as Trait>::A: Bound`202            predicate_constraint(hir_generics, trait_pred.upcast(tcx)),203        ];204        sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));205206        // Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.207        // FIXME: we should suggest `fn foo(t: impl Trait<A: Bound>)` instead.208        err.multipart_suggestion(209            "introduce a type parameter with a trait bound instead of using `impl Trait`",210            sugg,211            Applicability::MaybeIncorrect,212        );213    } else {214        if !trait_pred.is_suggestable(tcx, false) {215            return;216        }217        // Trivial case: `T` needs an extra bound: `T: Bound`.218        let (sp, suggestion) = match (219            hir_generics220                .params221                .iter()222                .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),223            super_traits,224        ) {225            (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),226            (None, Some((ident, []))) => (227                ident.span.shrink_to_hi(),228                format!(": {}", trait_pred.print_modifiers_and_trait_path()),229            ),230            (_, Some((_, [.., bounds]))) => (231                bounds.span().shrink_to_hi(),232                format!(" + {}", trait_pred.print_modifiers_and_trait_path()),233            ),234            (Some(_), Some((_, []))) => (235                hir_generics.span.shrink_to_hi(),236                format!(": {}", trait_pred.print_modifiers_and_trait_path()),237            ),238        };239240        err.span_suggestion_verbose(241            sp,242            format!("consider further restricting {msg}"),243            suggestion,244            Applicability::MachineApplicable,245        );246    }247}248249/// A single layer of `&` peeled from an expression, used by250/// [`TypeErrCtxt::peel_expr_refs`].251struct PeeledRef<'tcx> {252    /// The span covering the `&` (and any whitespace/mutability keyword) to remove.253    span: Span,254    /// The type after peeling this layer (and all prior layers).255    peeled_ty: Ty<'tcx>,256}257258impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {259    pub fn note_field_shadowed_by_private_candidate_in_cause(260        &self,261        err: &mut Diag<'_>,262        cause: &ObligationCause<'tcx>,263        param_env: ty::ParamEnv<'tcx>,264    ) {265        let mut hir_ids = FxHashSet::default();266        // Walk the parent chain so we can recover267        // the source expression from whichever layer carries them.268        let mut next_code = Some(cause.code());269        while let Some(cause_code) = next_code {270            match cause_code {271                ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => {272                    hir_ids.insert(*lhs_hir_id);273                    hir_ids.insert(*rhs_hir_id);274                }275                ObligationCauseCode::FunctionArg { arg_hir_id, .. }276                | ObligationCauseCode::ReturnValue(arg_hir_id)277                | ObligationCauseCode::AwaitableExpr(arg_hir_id)278                | ObligationCauseCode::BlockTailExpression(arg_hir_id, _)279                | ObligationCauseCode::UnOp { hir_id: arg_hir_id } => {280                    hir_ids.insert(*arg_hir_id);281                }282                ObligationCauseCode::OpaqueReturnType(Some((_, hir_id))) => {283                    hir_ids.insert(*hir_id);284                }285                _ => {}286            }287            next_code = cause_code.parent();288        }289290        if !cause.span.is_dummy()291            && let Some(body) = self.tcx.hir_maybe_body_owned_by(cause.body_id)292        {293            let mut expr_finder = FindExprBySpan::new(cause.span, self.tcx);294            expr_finder.visit_body(body);295            if let Some(expr) = expr_finder.result {296                hir_ids.insert(expr.hir_id);297            }298        }299300        // we will sort immediately by source order before emitting any diagnostics301        #[allow(rustc::potential_query_instability)]302        let mut hir_ids: Vec<_> = hir_ids.into_iter().collect();303        let source_map = self.tcx.sess.source_map();304        hir_ids.sort_by_cached_key(|hir_id| {305            let span = self.tcx.hir_span(*hir_id);306            let lo = source_map.lookup_byte_offset(span.lo());307            let hi = source_map.lookup_byte_offset(span.hi());308            (lo.sf.name.prefer_remapped_unconditionally().to_string(), lo.pos.0, hi.pos.0)309        });310311        for hir_id in hir_ids {312            self.note_field_shadowed_by_private_candidate(err, hir_id, param_env);313        }314    }315316    pub fn note_field_shadowed_by_private_candidate(317        &self,318        err: &mut Diag<'_>,319        hir_id: hir::HirId,320        param_env: ty::ParamEnv<'tcx>,321    ) {322        let Some(typeck_results) = &self.typeck_results else {323            return;324        };325        let Node::Expr(expr) = self.tcx.hir_node(hir_id) else {326            return;327        };328        let hir::ExprKind::Field(base_expr, field_ident) = expr.kind else {329            return;330        };331332        let Some(base_ty) = typeck_results.expr_ty_opt(base_expr) else {333            return;334        };335        let base_ty = self.resolve_vars_if_possible(base_ty);336        if base_ty.references_error() {337            return;338        }339340        let fn_body_hir_id = self.tcx.local_def_id_to_hir_id(typeck_results.hir_owner.def_id);341        let mut private_candidate: Option<(Ty<'tcx>, Ty<'tcx>, Span)> = None;342343        for (deref_base_ty, _) in (self.autoderef_steps)(base_ty) {344            let ty::Adt(base_def, args) = deref_base_ty.kind() else {345                continue;346            };347348            if base_def.is_enum() {349                continue;350            }351352            let (adjusted_ident, def_scope) =353                self.tcx.adjust_ident_and_get_scope(field_ident, base_def.did(), fn_body_hir_id);354355            let Some((_, field_def)) =356                base_def.non_enum_variant().fields.iter_enumerated().find(|(_, field)| {357                    field.ident(self.tcx).normalize_to_macros_2_0() == adjusted_ident358                })359            else {360                continue;361            };362            let field_span = self363                .tcx364                .def_ident_span(field_def.did)365                .unwrap_or_else(|| self.tcx.def_span(field_def.did));366367            if field_def.vis.is_accessible_from(def_scope, self.tcx) {368                let accessible_field_ty = field_def.ty(self.tcx, args);369                if let Some((private_base_ty, private_field_ty, private_field_span)) =370                    private_candidate371                    && !self.can_eq(param_env, private_field_ty, accessible_field_ty)372                {373                    let private_struct_span = match private_base_ty.kind() {374                        ty::Adt(private_base_def, _) => self375                            .tcx376                            .def_ident_span(private_base_def.did())377                            .unwrap_or_else(|| self.tcx.def_span(private_base_def.did())),378                        _ => DUMMY_SP,379                    };380                    let accessible_struct_span = self381                        .tcx382                        .def_ident_span(base_def.did())383                        .unwrap_or_else(|| self.tcx.def_span(base_def.did()));384                    let deref_impl_span = (typeck_results385                        .expr_adjustments(base_expr)386                        .iter()387                        .filter(|adj| {388                            matches!(adj.kind, Adjust::Deref(DerefAdjustKind::Overloaded(_)))389                        })390                        .count()391                        == 1)392                        .then(|| {393                            self.probe(|_| {394                                let deref_trait_did =395                                    self.tcx.require_lang_item(LangItem::Deref, DUMMY_SP);396                                let trait_ref =397                                    ty::TraitRef::new(self.tcx, deref_trait_did, [private_base_ty]);398                                let obligation: Obligation<'tcx, ty::Predicate<'tcx>> =399                                    Obligation::new(400                                        self.tcx,401                                        ObligationCause::dummy(),402                                        param_env,403                                        trait_ref,404                                    );405                                let Ok(Some(ImplSource::UserDefined(impl_data))) =406                                    SelectionContext::new(self)407                                        .select(&obligation.with(self.tcx, trait_ref))408                                else {409                                    return None;410                                };411                                Some(self.tcx.def_span(impl_data.impl_def_id))412                            })413                        })414                        .flatten();415416                    let mut note_spans: MultiSpan = private_struct_span.into();417                    if private_struct_span != DUMMY_SP {418                        note_spans.push_span_label(private_struct_span, "in this struct");419                    }420                    if private_field_span != DUMMY_SP {421                        note_spans.push_span_label(422                            private_field_span,423                            "if this field wasn't private, it would be accessible",424                        );425                    }426                    if accessible_struct_span != DUMMY_SP {427                        note_spans.push_span_label(428                            accessible_struct_span,429                            "this struct is accessible through auto-deref",430                        );431                    }432                    if field_span != DUMMY_SP {433                        note_spans434                            .push_span_label(field_span, "this is the field that was accessed");435                    }436                    if let Some(deref_impl_span) = deref_impl_span437                        && deref_impl_span != DUMMY_SP438                    {439                        note_spans.push_span_label(440                            deref_impl_span,441                            "the field was accessed through this `Deref`",442                        );443                    }444445                    err.span_note(446                        note_spans,447                        format!(448                            "there is a field `{field_ident}` on `{private_base_ty}` with type `{private_field_ty}` but it is private; `{field_ident}` from `{deref_base_ty}` was accessed through auto-deref instead"449                        ),450                    );451                }452453                // we finally get to the accessible field,454                // so we can return early without checking the rest of the autoderef candidates455                return;456            }457458            private_candidate.get_or_insert((459                deref_base_ty,460                field_def.ty(self.tcx, args),461                field_span,462            ));463        }464    }465466    pub fn suggest_restricting_param_bound(467        &self,468        err: &mut Diag<'_>,469        trait_pred: ty::PolyTraitPredicate<'tcx>,470        associated_ty: Option<(&'static str, Ty<'tcx>)>,471        mut body_id: LocalDefId,472    ) {473        if trait_pred.skip_binder().polarity != ty::PredicatePolarity::Positive {474            return;475        }476477        let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);478479        let self_ty = trait_pred.skip_binder().self_ty();480        let (param_ty, projection) = match *self_ty.kind() {481            ty::Param(_) => (true, None),482            ty::Alias(projection @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {483                (false, Some(projection))484            }485            _ => (false, None),486        };487488        let mut finder = ParamFinder { .. };489        finder.visit_binder(&trait_pred);490491        // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we492        //        don't suggest `T: Sized + ?Sized`.493        loop {494            let node = self.tcx.hir_node_by_def_id(body_id);495            match node {496                hir::Node::Item(hir::Item {497                    kind: hir::ItemKind::Trait { ident, generics, bounds, .. },498                    ..499                }) if self_ty == self.tcx.types.self_param => {500                    assert!(param_ty);501                    // Restricting `Self` for a single method.502                    suggest_restriction(503                        self.tcx,504                        body_id,505                        generics,506                        "`Self`",507                        err,508                        None,509                        projection,510                        trait_pred,511                        Some((&ident, bounds)),512                    );513                    return;514                }515516                hir::Node::TraitItem(hir::TraitItem {517                    generics,518                    kind: hir::TraitItemKind::Fn(..),519                    ..520                }) if self_ty == self.tcx.types.self_param => {521                    assert!(param_ty);522                    // Restricting `Self` for a single method.523                    suggest_restriction(524                        self.tcx, body_id, generics, "`Self`", err, None, projection, trait_pred,525                        None,526                    );527                    return;528                }529530                hir::Node::TraitItem(hir::TraitItem {531                    generics,532                    kind: hir::TraitItemKind::Fn(fn_sig, ..),533                    ..534                })535                | hir::Node::ImplItem(hir::ImplItem {536                    generics,537                    kind: hir::ImplItemKind::Fn(fn_sig, ..),538                    ..539                })540                | hir::Node::Item(hir::Item {541                    kind: hir::ItemKind::Fn { sig: fn_sig, generics, .. },542                    ..543                }) if projection.is_some() => {544                    // Missing restriction on associated type of type parameter (unmet projection).545                    suggest_restriction(546                        self.tcx,547                        body_id,548                        generics,549                        "the associated type",550                        err,551                        Some(fn_sig),552                        projection,553                        trait_pred,554                        None,555                    );556                    return;557                }558                hir::Node::Item(hir::Item {559                    kind:560                        hir::ItemKind::Trait { generics, .. }561                        | hir::ItemKind::Impl(hir::Impl { generics, .. }),562                    ..563                }) if projection.is_some() => {564                    // Missing restriction on associated type of type parameter (unmet projection).565                    suggest_restriction(566                        self.tcx,567                        body_id,568                        generics,569                        "the associated type",570                        err,571                        None,572                        projection,573                        trait_pred,574                        None,575                    );576                    return;577                }578579                hir::Node::Item(hir::Item {580                    kind:581                        hir::ItemKind::Struct(_, generics, _)582                        | hir::ItemKind::Enum(_, generics, _)583                        | hir::ItemKind::Union(_, generics, _)584                        | hir::ItemKind::Trait { generics, .. }585                        | hir::ItemKind::Impl(hir::Impl { generics, .. })586                        | hir::ItemKind::Fn { generics, .. }587                        | hir::ItemKind::TyAlias(_, generics, _)588                        | hir::ItemKind::Const(_, generics, _, _)589                        | hir::ItemKind::TraitAlias(_, _, generics, _),590                    ..591                })592                | hir::Node::TraitItem(hir::TraitItem { generics, .. })593                | hir::Node::ImplItem(hir::ImplItem { generics, .. })594                    if param_ty =>595                {596                    // We skip the 0'th arg (self) because we do not want597                    // to consider the predicate as not suggestible if the598                    // self type is an arg position `impl Trait` -- instead,599                    // we handle that by adding ` + Bound` below.600                    // FIXME(compiler-errors): It would be nice to do the same601                    // this that we do in `suggest_restriction` and pull the602                    // `impl Trait` into a new generic if it shows up somewhere603                    // else in the predicate.604                    if !trait_pred.skip_binder().trait_ref.args[1..]605                        .iter()606                        .all(|g| g.is_suggestable(self.tcx, false))607                    {608                        return;609                    }610                    // Missing generic type parameter bound.611                    let param_name = self_ty.to_string();612                    let mut constraint = with_no_trimmed_paths!(613                        trait_pred.print_modifiers_and_trait_path().to_string()614                    );615616                    if let Some((name, term)) = associated_ty {617                        // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.618                        // That should be extracted into a helper function.619                        if let Some(stripped) = constraint.strip_suffix('>') {620                            constraint = format!("{stripped}, {name} = {term}>");621                        } else {622                            constraint.push_str(&format!("<{name} = {term}>"));623                        }624                    }625626                    if suggest_constraining_type_param(627                        self.tcx,628                        generics,629                        err,630                        &param_name,631                        &constraint,632                        Some(trait_pred.def_id()),633                        None,634                    ) {635                        return;636                    }637                }638639                hir::Node::TraitItem(hir::TraitItem {640                    generics,641                    kind: hir::TraitItemKind::Fn(..),642                    ..643                })644                | hir::Node::ImplItem(hir::ImplItem {645                    generics,646                    impl_kind: hir::ImplItemImplKind::Inherent { .. },647                    kind: hir::ImplItemKind::Fn(..),648                    ..649                }) if finder.can_suggest_bound(generics) => {650                    // Missing generic type parameter bound.651                    suggest_arbitrary_trait_bound(652                        self.tcx,653                        generics,654                        err,655                        trait_pred,656                        associated_ty,657                    );658                }659                hir::Node::Item(hir::Item {660                    kind:661                        hir::ItemKind::Struct(_, generics, _)662                        | hir::ItemKind::Enum(_, generics, _)663                        | hir::ItemKind::Union(_, generics, _)664                        | hir::ItemKind::Trait { generics, .. }665                        | hir::ItemKind::Impl(hir::Impl { generics, .. })666                        | hir::ItemKind::Fn { generics, .. }667                        | hir::ItemKind::TyAlias(_, generics, _)668                        | hir::ItemKind::Const(_, generics, _, _)669                        | hir::ItemKind::TraitAlias(_, _, generics, _),670                    ..671                }) if finder.can_suggest_bound(generics) => {672                    // Missing generic type parameter bound.673                    if suggest_arbitrary_trait_bound(674                        self.tcx,675                        generics,676                        err,677                        trait_pred,678                        associated_ty,679                    ) {680                        return;681                    }682                }683                hir::Node::Crate(..) => return,684685                _ => {}686            }687            body_id = self.tcx.local_parent(body_id);688        }689    }690691    /// Provide a suggestion to dereference arguments to functions and binary operators, if that692    /// would satisfy trait bounds.693    pub(super) fn suggest_dereferences(694        &self,695        obligation: &PredicateObligation<'tcx>,696        err: &mut Diag<'_>,697        trait_pred: ty::PolyTraitPredicate<'tcx>,698    ) -> bool {699        let mut code = obligation.cause.code();700        if let ObligationCauseCode::FunctionArg { arg_hir_id, call_hir_id, .. } = code701            && let Some(typeck_results) = &self.typeck_results702            && let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id)703            && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)704        {705            // Suggest dereferencing the argument to a function/method call if possible706707            // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)708            let mut real_trait_pred = trait_pred;709            while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {710                code = parent_code;711                if let Some(parent_trait_pred) = parent_trait_pred {712                    real_trait_pred = parent_trait_pred;713                }714            }715716            // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle717            // `ReBound`, and we don't particularly care about the regions.718            let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty());719            if !self.can_eq(obligation.param_env, real_ty, arg_ty) {720                return false;721            }722723            // Potentially, we'll want to place our dereferences under a `&`. We don't try this for724            // `&mut`, since we can't be sure users will get the side-effects they want from it.725            // If this doesn't work, we'll try removing the `&` in `suggest_remove_reference`.726            // FIXME(dianne): this misses the case where users need both to deref and remove `&`s.727            // This method could be combined with `TypeErrCtxt::suggest_remove_reference` to handle728            // that, similar to what `FnCtxt::suggest_deref_or_ref` does.729            let (is_under_ref, base_ty, span) = match expr.kind {730                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, subexpr)731                    if let &ty::Ref(region, base_ty, hir::Mutability::Not) = real_ty.kind() =>732                {733                    (Some(region), base_ty, subexpr.span)734                }735                // Don't suggest `*&mut`, etc.736                hir::ExprKind::AddrOf(..) => return false,737                _ => (None, real_ty, obligation.cause.span),738            };739740            let autoderef = (self.autoderef_steps)(base_ty);741            let mut is_boxed = base_ty.is_box();742            if let Some(steps) = autoderef.into_iter().position(|(mut ty, obligations)| {743                // Ensure one of the following for dereferencing to be valid: we're passing by744                // reference, `ty` is `Copy`, or we're moving out of a (potentially nested) `Box`.745                let can_deref = is_under_ref.is_some()746                    || self.type_is_copy_modulo_regions(obligation.param_env, ty)747                    || ty.is_numeric() // for inference vars (presumably but not provably `Copy`)748                    || is_boxed && self.type_is_sized_modulo_regions(obligation.param_env, ty);749                is_boxed &= ty.is_box();750751                // Re-add the `&` if necessary752                if let Some(region) = is_under_ref {753                    ty = Ty::new_ref(self.tcx, region, ty, hir::Mutability::Not);754                }755756                // Remapping bound vars here757                let real_trait_pred_and_ty =758                    real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));759                let obligation = self.mk_trait_obligation_with_new_self_ty(760                    obligation.param_env,761                    real_trait_pred_and_ty,762                );763764                can_deref765                    && obligations766                        .iter()767                        .chain([&obligation])768                        .all(|obligation| self.predicate_may_hold(obligation))769            }) && steps > 0770            {771                if span.in_external_macro(self.tcx.sess.source_map()) {772                    return false;773                }774                let derefs = "*".repeat(steps);775                let msg = "consider dereferencing here";776777                let call_node = self.tcx.hir_node(*call_hir_id);778                let is_receiver = matches!(779                    call_node,780                    Node::Expr(hir::Expr {781                        kind: hir::ExprKind::MethodCall(_, receiver_expr, ..),782                        ..783                    })784                    if receiver_expr.hir_id == *arg_hir_id785                );786                if is_receiver {787                    err.multipart_suggestion(788                        msg,789                        vec![790                            (span.shrink_to_lo(), format!("({derefs}")),791                            (span.shrink_to_hi(), ")".to_string()),792                        ],793                        Applicability::MachineApplicable,794                    )795                } else {796                    err.span_suggestion_verbose(797                        span.shrink_to_lo(),798                        msg,799                        derefs,800                        Applicability::MachineApplicable,801                    )802                };803                return true;804            }805        } else if let (806            ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. },807            predicate,808        ) = code.peel_derives_with_predicate()809            && let Some(typeck_results) = &self.typeck_results810            && let hir::Node::Expr(lhs) = self.tcx.hir_node(*lhs_hir_id)811            && let hir::Node::Expr(rhs) = self.tcx.hir_node(*rhs_hir_id)812            && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs)813            && let trait_pred = predicate.unwrap_or(trait_pred)814            // Only run this code on binary operators815            && hir::lang_items::BINARY_OPERATORS816                .iter()817                .filter_map(|&op| self.tcx.lang_items().get(op))818                .any(|op| {819                    op == trait_pred.skip_binder().trait_ref.def_id820                })821        {822            // Suggest dereferencing the LHS, RHS, or both terms of a binop if possible823            let trait_pred = predicate.unwrap_or(trait_pred);824            let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty());825            let lhs_autoderef = (self.autoderef_steps)(lhs_ty);826            let rhs_autoderef = (self.autoderef_steps)(rhs_ty);827            let first_lhs = lhs_autoderef.first().unwrap().clone();828            let first_rhs = rhs_autoderef.first().unwrap().clone();829            let mut autoderefs = lhs_autoderef830                .into_iter()831                .enumerate()832                .rev()833                .zip_longest(rhs_autoderef.into_iter().enumerate().rev())834                .map(|t| match t {835                    EitherOrBoth::Both(a, b) => (a, b),836                    EitherOrBoth::Left(a) => (a, (0, first_rhs.clone())),837                    EitherOrBoth::Right(b) => ((0, first_lhs.clone()), b),838                })839                .rev();840            if let Some((lsteps, rsteps)) =841                autoderefs.find_map(|((lsteps, (l_ty, _)), (rsteps, (r_ty, _)))| {842                    // Create a new predicate with the dereferenced LHS and RHS843                    // We simultaneously dereference both sides rather than doing them844                    // one at a time to account for cases such as &Box<T> == &&T845                    let trait_pred_and_ty = trait_pred.map_bound(|inner| {846                        (847                            ty::TraitPredicate {848                                trait_ref: ty::TraitRef::new_from_args(849                                    self.tcx,850                                    inner.trait_ref.def_id,851                                    self.tcx.mk_args(852                                        &[&[l_ty.into(), r_ty.into()], &inner.trait_ref.args[2..]]853                                            .concat(),854                                    ),855                                ),856                                ..inner857                            },858                            l_ty,859                        )860                    });861                    let obligation = self.mk_trait_obligation_with_new_self_ty(862                        obligation.param_env,863                        trait_pred_and_ty,864                    );865                    self.predicate_may_hold(&obligation).then_some(match (lsteps, rsteps) {866                        (_, 0) => (Some(lsteps), None),867                        (0, _) => (None, Some(rsteps)),868                        _ => (Some(lsteps), Some(rsteps)),869                    })870                })871            {872                let make_sugg = |mut expr: &Expr<'_>, mut steps| {873                    if expr.span.in_external_macro(self.tcx.sess.source_map()) {874                        return None;875                    }876                    let mut prefix_span = expr.span.shrink_to_lo();877                    let mut msg = "consider dereferencing here";878                    if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind {879                        msg = "consider removing the borrow and dereferencing instead";880                        if let hir::ExprKind::AddrOf(..) = inner.kind {881                            msg = "consider removing the borrows and dereferencing instead";882                        }883                    }884                    while let hir::ExprKind::AddrOf(_, _, inner) = expr.kind885                        && steps > 0886                    {887                        prefix_span = prefix_span.with_hi(inner.span.lo());888                        expr = inner;889                        steps -= 1;890                    }891                    // Empty suggestions with empty spans ICE with debug assertions892                    if steps == 0 {893                        return Some((894                            msg.trim_end_matches(" and dereferencing instead"),895                            vec![(prefix_span, String::new())],896                        ));897                    }898                    let derefs = "*".repeat(steps);899                    let needs_parens = steps > 0 && expr_needs_parens(expr);900                    let mut suggestion = if needs_parens {901                        vec![902                            (903                                expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),904                                format!("{derefs}("),905                            ),906                            (expr.span.shrink_to_hi(), ")".to_string()),907                        ]908                    } else {909                        vec![(910                            expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),911                            format!("{derefs}"),912                        )]913                    };914                    // Empty suggestions with empty spans ICE with debug assertions915                    if !prefix_span.is_empty() {916                        suggestion.push((prefix_span, String::new()));917                    }918                    Some((msg, suggestion))919                };920921                if let Some(lsteps) = lsteps922                    && let Some(rsteps) = rsteps923                    && lsteps > 0924                    && rsteps > 0925                {926                    let Some((_, mut suggestion)) = make_sugg(lhs, lsteps) else {927                        return false;928                    };929                    let Some((_, mut rhs_suggestion)) = make_sugg(rhs, rsteps) else {930                        return false;931                    };932                    suggestion.append(&mut rhs_suggestion);933                    err.multipart_suggestion(934                        "consider dereferencing both sides of the expression",935                        suggestion,936                        Applicability::MachineApplicable,937                    );938                    return true;939                } else if let Some(lsteps) = lsteps940                    && lsteps > 0941                {942                    let Some((msg, suggestion)) = make_sugg(lhs, lsteps) else {943                        return false;944                    };945                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);946                    return true;947                } else if let Some(rsteps) = rsteps948                    && rsteps > 0949                {950                    let Some((msg, suggestion)) = make_sugg(rhs, rsteps) else {951                        return false;952                    };953                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);954                    return true;955                }956            }957        }958        false959    }960961    /// Given a closure's `DefId`, return the given name of the closure.962    ///963    /// This doesn't account for reassignments, but it's only used for suggestions.964    fn get_closure_name(965        &self,966        def_id: DefId,967        err: &mut Diag<'_>,968        msg: Cow<'static, str>,969    ) -> Option<Symbol> {970        let get_name = |err: &mut Diag<'_>, kind: &hir::PatKind<'_>| -> Option<Symbol> {971            // Get the local name of this closure. This can be inaccurate because972            // of the possibility of reassignment, but this should be good enough.973            match &kind {974                hir::PatKind::Binding(hir::BindingMode::NONE, _, ident, None) => Some(ident.name),975                _ => {976                    err.note(msg);977                    None978                }979            }980        };981982        let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);983        match self.tcx.parent_hir_node(hir_id) {984            hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(local), .. }) => {985                get_name(err, &local.pat.kind)986            }987            // Different to previous arm because one is `&hir::Local` and the other988            // is `Box<hir::Local>`.989            hir::Node::LetStmt(local) => get_name(err, &local.pat.kind),990            _ => None,991        }992    }993994    /// We tried to apply the bound to an `fn` or closure. Check whether calling it would995    /// evaluate to a type that *would* satisfy the trait bound. If it would, suggest calling996    /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.997    pub(super) fn suggest_fn_call(998        &self,999        obligation: &PredicateObligation<'tcx>,1000        err: &mut Diag<'_>,1001        trait_pred: ty::PolyTraitPredicate<'tcx>,1002    ) -> bool {1003        // It doesn't make sense to make this suggestion outside of typeck...1004        // (also autoderef will ICE...)1005        if self.typeck_results.is_none() {1006            return false;1007        }10081009        if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =1010            obligation.predicate.kind().skip_binder()1011            && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized)1012        {1013            // Don't suggest calling to turn an unsized type into a sized type1014            return false;1015        }10161017        let self_ty = self.instantiate_binder_with_fresh_vars(1018            DUMMY_SP,1019            BoundRegionConversionTime::FnCall,1020            trait_pred.self_ty(),1021        );10221023        let Some((def_id_or_name, output, inputs)) =1024            self.extract_callable_info(obligation.cause.body_id, obligation.param_env, self_ty)1025        else {1026            return false;1027        };10281029        // Remapping bound vars here1030        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));10311032        let new_obligation =1033            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);1034        if !self.predicate_must_hold_modulo_regions(&new_obligation) {1035            return false;1036        }10371038        // If this is a zero-argument async closure directly passed as an argument1039        // and the expected type is `Future`, suggest using `async {}` block instead1040        // of `async || {}`1041        if let ty::CoroutineClosure(def_id, args) = *self_ty.kind()1042            && let sig = args.as_coroutine_closure().coroutine_closure_sig().skip_binder()1043            && let ty::Tuple(inputs) = *sig.tupled_inputs_ty.kind()1044            && inputs.is_empty()1045            && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Future)1046            && let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1047            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) =1048                self.tcx.hir_node(*arg_hir_id)1049            && let Some(hir::Node::Expr(hir::Expr {1050                kind: hir::ExprKind::Closure(closure), ..1051            })) = self.tcx.hir_get_if_local(def_id)1052            && let hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async) = closure.kind1053            && let Some(arg_span) = closure.fn_arg_span1054            && obligation.cause.span.contains(arg_span)1055        {1056            let mut body = self.tcx.hir_body(closure.body).value;1057            let peeled = body.peel_blocks().peel_drop_temps();1058            if let hir::ExprKind::Closure(inner) = peeled.kind {1059                body = self.tcx.hir_body(inner.body).value;1060            }1061            if !matches!(body.peel_blocks().peel_drop_temps().kind, hir::ExprKind::Block(..)) {1062                return false;1063            }10641065            let sm = self.tcx.sess.source_map();1066            let removal_span = if let Ok(snippet) =1067                sm.span_to_snippet(arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1)))1068                && snippet.ends_with(' ')1069            {1070                // There's a space after `||`, include it in the removal1071                arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1))1072            } else {1073                arg_span1074            };1075            err.span_suggestion_verbose(1076                removal_span,1077                "use `async {}` instead of `async || {}` to introduce an async block",1078                "",1079                Applicability::MachineApplicable,1080            );1081            return true;1082        }10831084        // Get the name of the callable and the arguments to be used in the suggestion.1085        let msg = match def_id_or_name {1086            DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {1087                DefKind::Ctor(CtorOf::Struct, _) => {1088                    Cow::from("use parentheses to construct this tuple struct")1089                }1090                DefKind::Ctor(CtorOf::Variant, _) => {1091                    Cow::from("use parentheses to construct this tuple variant")1092                }1093                kind => Cow::from(format!(1094                    "use parentheses to call this {}",1095                    self.tcx.def_kind_descr(kind, def_id)1096                )),1097            },1098            DefIdOrName::Name(name) => Cow::from(format!("use parentheses to call this {name}")),1099        };11001101        let args = inputs1102            .into_iter()1103            .map(|ty| {1104                if ty.is_suggestable(self.tcx, false) {1105                    format!("/* {ty} */")1106                } else {1107                    "/* value */".to_string()1108                }1109            })1110            .collect::<Vec<_>>()1111            .join(", ");11121113        if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1114            && obligation.cause.span.can_be_used_for_suggestions()1115        {1116            let span = obligation.cause.span;11171118            let arg_expr = match self.tcx.hir_node(*arg_hir_id) {1119                hir::Node::Expr(expr) => Some(expr),1120                _ => None,1121            };11221123            let is_closure_expr =1124                arg_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Closure(..)));11251126            // If the user wrote `|| {}()`, suggesting to call the closure would produce `(|| {}())()`,1127            // which doesn't help and is often outright wrong.1128            if args.is_empty()1129                && let Some(expr) = arg_expr1130                && let hir::ExprKind::Closure(closure) = expr.kind1131            {1132                let mut body = self.tcx.hir_body(closure.body).value;11331134                // Async closures desugar to a closure returning a coroutine1135                if let hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) =1136                    closure.kind1137                {1138                    let peeled = body.peel_blocks().peel_drop_temps();1139                    if let hir::ExprKind::Closure(inner) = peeled.kind {1140                        body = self.tcx.hir_body(inner.body).value;1141                    }1142                }11431144                let peeled_body = body.peel_blocks().peel_drop_temps();1145                if let hir::ExprKind::Call(callee, call_args) = peeled_body.kind1146                    && call_args.is_empty()1147                    && let hir::ExprKind::Block(..) = callee.peel_blocks().peel_drop_temps().kind1148                {1149                    return false;1150                }1151            }11521153            if is_closure_expr {1154                err.multipart_suggestions(1155                    msg,1156                    vec![vec![1157                        (span.shrink_to_lo(), "(".to_string()),1158                        (span.shrink_to_hi(), format!(")({args})")),1159                    ]],1160                    Applicability::HasPlaceholders,1161                );1162            } else {1163                err.span_suggestion_verbose(1164                    span.shrink_to_hi(),1165                    msg,1166                    format!("({args})"),1167                    Applicability::HasPlaceholders,1168                );1169            }1170        } else if let DefIdOrName::DefId(def_id) = def_id_or_name {1171            let name = match self.tcx.hir_get_if_local(def_id) {1172                Some(hir::Node::Expr(hir::Expr {1173                    kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),1174                    ..1175                })) => {1176                    err.span_label(*fn_decl_span, "consider calling this closure");1177                    let Some(name) = self.get_closure_name(def_id, err, msg.clone()) else {1178                        return false;1179                    };1180                    name.to_string()1181                }1182                Some(hir::Node::Item(hir::Item {1183                    kind: hir::ItemKind::Fn { ident, .. }, ..1184                })) => {1185                    err.span_label(ident.span, "consider calling this function");1186                    ident.to_string()1187                }1188                Some(hir::Node::Ctor(..)) => {1189                    let name = self.tcx.def_path_str(def_id);1190                    err.span_label(1191                        self.tcx.def_span(def_id),1192                        format!("consider calling the constructor for `{name}`"),1193                    );1194                    name1195                }1196                _ => return false,1197            };1198            err.help(format!("{msg}: `{name}({args})`"));1199        }1200        true1201    }12021203    pub(super) fn suggest_cast_to_fn_pointer(1204        &self,1205        obligation: &PredicateObligation<'tcx>,1206        err: &mut Diag<'_>,1207        leaf_trait_predicate: ty::PolyTraitPredicate<'tcx>,1208        main_trait_predicate: ty::PolyTraitPredicate<'tcx>,1209        span: Span,1210    ) -> bool {1211        let &[candidate] = &self.find_similar_impl_candidates(leaf_trait_predicate)[..] else {1212            return false;1213        };1214        let candidate = candidate.trait_ref;12151216        if !matches!(1217            (candidate.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind(),),1218            (ty::FnPtr(..), ty::FnDef(..))1219        ) {1220            return false;1221        }12221223        let parenthesized_cast = |span: Span| {1224            vec![1225                (span.shrink_to_lo(), "(".to_string()),1226                (span.shrink_to_hi(), format!(" as {})", candidate.self_ty())),1227            ]1228        };1229        // Wrap method receivers and `&`-references in parens.1230        let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() {1231            parenthesized_cast(span)1232        } else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) {1233            let mut expr_finder = FindExprBySpan::new(span, self.tcx);1234            expr_finder.visit_expr(body.value);1235            if let Some(expr) = expr_finder.result1236                && let hir::ExprKind::AddrOf(_, _, expr) = expr.kind1237            {1238                parenthesized_cast(expr.span)1239            } else {1240                vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]1241            }1242        } else {1243            vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]1244        };12451246        let trait_ = self.tcx.short_string(candidate.print_trait_sugared(), err.long_ty_path());1247        let self_ty = self.tcx.short_string(candidate.self_ty(), err.long_ty_path());1248        err.multipart_suggestion(1249            format!(1250                "the trait `{trait_}` is implemented for fn pointer \1251                 `{self_ty}`, try casting using `as`",1252            ),1253            suggestion,1254            Applicability::MaybeIncorrect,1255        );1256        true1257    }12581259    pub(super) fn check_for_binding_assigned_block_without_tail_expression(1260        &self,1261        obligation: &PredicateObligation<'tcx>,1262        err: &mut Diag<'_>,1263        trait_pred: ty::PolyTraitPredicate<'tcx>,1264    ) {1265        let mut span = obligation.cause.span;1266        while span.from_expansion() {1267            // Remove all the desugaring and macro contexts.1268            span.remove_mark();1269        }1270        let mut expr_finder = FindExprBySpan::new(span, self.tcx);1271        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {1272            return;1273        };1274        expr_finder.visit_expr(body.value);1275        let Some(expr) = expr_finder.result else {1276            return;1277        };1278        let Some(typeck) = &self.typeck_results else {1279            return;1280        };1281        let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else {1282            return;1283        };1284        if !ty.is_unit() {1285            return;1286        };1287        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {1288            return;1289        };1290        let Res::Local(hir_id) = path.res else {1291            return;1292        };1293        let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {1294            return;1295        };1296        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =1297            self.tcx.parent_hir_node(pat.hir_id)1298        else {1299            return;1300        };1301        let hir::ExprKind::Block(block, None) = init.kind else {1302            return;1303        };1304        if block.expr.is_some() {1305            return;1306        }1307        let [.., stmt] = block.stmts else {1308            err.span_label(block.span, "this empty block is missing a tail expression");1309            return;1310        };1311        // FIXME expr and stmt have the same span if expr comes from expansion1312        // cc: https://github.com/rust-lang/rust/pull/147416#discussion_r24994075231313        if stmt.span.from_expansion() {1314            return;1315        }1316        let hir::StmtKind::Semi(tail_expr) = stmt.kind else {1317            return;1318        };1319        let Some(ty) = typeck.expr_ty_opt(tail_expr) else {1320            err.span_label(block.span, "this block is missing a tail expression");1321            return;1322        };1323        let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty));1324        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty));13251326        let new_obligation =1327            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);1328        if !matches!(tail_expr.kind, hir::ExprKind::Err(_))1329            && self.predicate_must_hold_modulo_regions(&new_obligation)1330        {1331            err.span_suggestion_short(1332                stmt.span.with_lo(tail_expr.span.hi()),1333                "remove this semicolon",1334                "",1335                Applicability::MachineApplicable,1336            );1337        } else {1338            err.span_label(block.span, "this block is missing a tail expression");1339        }1340    }13411342    pub(super) fn suggest_add_clone_to_arg(1343        &self,1344        obligation: &PredicateObligation<'tcx>,1345        err: &mut Diag<'_>,1346        trait_pred: ty::PolyTraitPredicate<'tcx>,1347    ) -> bool {1348        let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());1349        self.enter_forall(self_ty, |ty: Ty<'_>| {1350            let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else {1351                return false;1352            };1353            let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };1354            let ty::Param(param) = inner_ty.kind() else { return false };1355            let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1356            else {1357                return false;1358            };13591360            let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span);1361            let has_clone = |ty| {1362                self.type_implements_trait(clone_trait, [ty], obligation.param_env)1363                    .must_apply_modulo_regions()1364            };13651366            let existing_clone_call = match self.tcx.hir_node(*arg_hir_id) {1367                // It's just a variable. Propose cloning it.1368                Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) => None,1369                // It's already a call to `clone()`. We might be able to suggest1370                // adding a `+ Clone` bound, though.1371                Node::Expr(Expr {1372                    kind:1373                        hir::ExprKind::MethodCall(1374                            hir::PathSegment { ident, .. },1375                            _receiver,1376                            [],1377                            call_span,1378                        ),1379                    hir_id,1380                    ..1381                }) if ident.name == sym::clone1382                    && !call_span.from_expansion()1383                    && !has_clone(*inner_ty) =>1384                {1385                    // We only care about method calls corresponding to the real `Clone` trait.1386                    let Some(typeck_results) = self.typeck_results.as_ref() else { return false };1387                    let Some((DefKind::AssocFn, did)) = typeck_results.type_dependent_def(*hir_id)1388                    else {1389                        return false;1390                    };1391                    if self.tcx.trait_of_assoc(did) != Some(clone_trait) {1392                        return false;1393                    }1394                    Some(ident.span)1395                }1396                _ => return false,1397            };13981399            let new_obligation = self.mk_trait_obligation_with_new_self_ty(1400                obligation.param_env,1401                trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),1402            );14031404            if self.predicate_may_hold(&new_obligation) && has_clone(ty) {1405                if !has_clone(param.to_ty(self.tcx)) {1406                    suggest_constraining_type_param(1407                        self.tcx,1408                        generics,1409                        err,1410                        param.name.as_str(),1411                        "Clone",1412                        Some(clone_trait),1413                        None,1414                    );1415                }1416                if let Some(existing_clone_call) = existing_clone_call {1417                    err.span_note(1418                        existing_clone_call,1419                        format!(1420                            "this `clone()` copies the reference, \1421                            which does not do anything, \1422                            because `{inner_ty}` does not implement `Clone`"1423                        ),1424                    );1425                } else {1426                    err.span_suggestion_verbose(1427                        obligation.cause.span.shrink_to_hi(),1428                        "consider using clone here",1429                        ".clone()".to_string(),1430                        Applicability::MaybeIncorrect,1431                    );1432                }1433                return true;1434            }1435            false1436        })1437    }14381439    /// Extracts information about a callable type for diagnostics. This is a1440    /// heuristic -- it doesn't necessarily mean that a type is always callable,1441    /// because the callable type must also be well-formed to be called.1442    pub fn extract_callable_info(1443        &self,1444        body_id: LocalDefId,1445        param_env: ty::ParamEnv<'tcx>,1446        found: Ty<'tcx>,1447    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {1448        // Autoderef is useful here because sometimes we box callables, etc.1449        let Some((def_id_or_name, output, inputs)) =1450            (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| match *found.kind() {1451                ty::FnPtr(sig_tys, _) => Some((1452                    DefIdOrName::Name("function pointer"),1453                    sig_tys.output(),1454                    sig_tys.inputs(),1455                )),1456                ty::FnDef(def_id, _) => {1457                    let fn_sig = found.fn_sig(self.tcx);1458                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))1459                }1460                ty::Closure(def_id, args) => {1461                    let fn_sig = args.as_closure().sig();1462                    Some((1463                        DefIdOrName::DefId(def_id),1464                        fn_sig.output(),1465                        fn_sig.inputs().map_bound(|inputs| inputs[0].tuple_fields().as_slice()),1466                    ))1467                }1468                ty::CoroutineClosure(def_id, args) => {1469                    let sig_parts = args.as_coroutine_closure().coroutine_closure_sig();1470                    Some((1471                        DefIdOrName::DefId(def_id),1472                        sig_parts.map_bound(|sig| {1473                            sig.to_coroutine(1474                                self.tcx,1475                                args.as_coroutine_closure().parent_args(),1476                                // Just use infer vars here, since we  don't really care1477                                // what these types are, just that we're returning a coroutine.1478                                self.next_ty_var(DUMMY_SP),1479                                self.tcx.coroutine_for_closure(def_id),1480                                self.next_ty_var(DUMMY_SP),1481                            )1482                        }),1483                        sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),1484                    ))1485                }1486                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {1487                    self.tcx1488                        .item_self_bounds(def_id)1489                        .instantiate(self.tcx, args)1490                        .skip_norm_wip()1491                        .iter()1492                        .find_map(|pred| {1493                            if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()1494                            && self1495                                .tcx1496                                .is_lang_item(proj.projection_term.def_id(), LangItem::FnOnceOutput)1497                            // args tuple will always be args[1]1498                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()1499                            {1500                                Some((1501                                    DefIdOrName::DefId(def_id),1502                                    pred.kind().rebind(proj.term.expect_type()),1503                                    pred.kind().rebind(args.as_slice()),1504                                ))1505                            } else {1506                                None1507                            }1508                        })1509                }1510                ty::Dynamic(data, _) => data.iter().find_map(|pred| {1511                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()1512                        && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)1513                        // for existential projection, args are shifted over by 11514                        && let ty::Tuple(args) = proj.args.type_at(0).kind()1515                    {1516                        Some((1517                            DefIdOrName::Name("trait object"),1518                            pred.rebind(proj.term.expect_type()),1519                            pred.rebind(args.as_slice()),1520                        ))1521                    } else {1522                        None1523                    }1524                }),1525                ty::Param(param) => {1526                    let generics = self.tcx.generics_of(body_id);1527                    let name = if generics.count() > param.index as usize1528                        && let def = generics.param_at(param.index as usize, self.tcx)1529                        && matches!(def.kind, ty::GenericParamDefKind::Type { .. })1530                        && def.name == param.name1531                    {1532                        DefIdOrName::DefId(def.def_id)1533                    } else {1534                        DefIdOrName::Name("type parameter")1535                    };1536                    param_env.caller_bounds().iter().find_map(|pred| {1537                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()1538                            && self1539                                .tcx1540                                .is_lang_item(proj.projection_term.def_id(), LangItem::FnOnceOutput)1541                            && proj.projection_term.self_ty() == found1542                            // args tuple will always be args[1]1543                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()1544                        {1545                            Some((1546                                name,1547                                pred.kind().rebind(proj.term.expect_type()),1548                                pred.kind().rebind(args.as_slice()),1549                            ))1550                        } else {1551                            None1552                        }1553                    })1554                }1555                _ => None,1556            })1557        else {1558            return None;1559        };15601561        let output = self.instantiate_binder_with_fresh_vars(1562            DUMMY_SP,1563            BoundRegionConversionTime::FnCall,1564            output,1565        );1566        let inputs = inputs1567            .skip_binder()1568            .iter()1569            .map(|ty| {1570                self.instantiate_binder_with_fresh_vars(1571                    DUMMY_SP,1572                    BoundRegionConversionTime::FnCall,1573                    inputs.rebind(*ty),1574                )1575            })1576            .collect();15771578        // We don't want to register any extra obligations, which should be1579        // implied by wf, but also because that would possibly result in1580        // erroneous errors later on.1581        let InferOk { value: output, obligations: _ } =1582            self.at(&ObligationCause::dummy(), param_env).normalize(Unnormalized::new_wip(output));15831584        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }1585    }15861587    pub(super) fn where_clause_expr_matches_failed_self_ty(1588        &self,1589        obligation: &PredicateObligation<'tcx>,1590        old_self_ty: Ty<'tcx>,1591    ) -> bool {1592        let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() else {1593            return true;1594        };1595        let (Some(typeck_results), Some(body)) = (1596            self.typeck_results.as_ref(),1597            self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id),1598        ) else {1599            return true;1600        };16011602        let mut expr_finder = FindExprBySpan::new(obligation.cause.span, self.tcx);1603        expr_finder.visit_expr(body.value);1604        let Some(expr) = expr_finder.result else {1605            return true;1606        };16071608        let inner_old_self_ty = match old_self_ty.kind() {1609            ty::Ref(_, inner_ty, _) => Some(*inner_ty),1610            _ => None,1611        };16121613        [typeck_results.expr_ty_adjusted_opt(expr)].into_iter().flatten().any(|expr_ty| {1614            self.can_eq(obligation.param_env, expr_ty, old_self_ty)1615                || inner_old_self_ty1616                    .is_some_and(|inner_ty| self.can_eq(obligation.param_env, expr_ty, inner_ty))1617        })1618    }16191620    pub(super) fn suggest_add_reference_to_arg(1621        &self,1622        obligation: &PredicateObligation<'tcx>,1623        err: &mut Diag<'_>,1624        poly_trait_pred: ty::PolyTraitPredicate<'tcx>,1625        has_custom_message: bool,1626    ) -> bool {1627        let span = obligation.cause.span;1628        let param_env = obligation.param_env;16291630        let mk_result = |trait_pred_and_new_ty| {1631            let obligation =1632                self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);1633            self.predicate_must_hold_modulo_regions(&obligation)1634        };16351636        let code = match obligation.cause.code() {1637            ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code,1638            // FIXME(compiler-errors): This is kind of a mess, but required for obligations1639            // that come from a path expr to affect the *call* expr.1640            c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _)1641                if self.tcx.hir_span(*hir_id).lo() == span.lo() =>1642            {1643                // `hir_id` corresponds to the HIR node that introduced a `where`-clause obligation.1644                // If that obligation comes from a type in an associated method call, we need1645                // special handling here.1646                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(*hir_id)1647                    && let hir::ExprKind::Call(base, _) = expr.kind1648                    && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, segment)) = base.kind1649                    && let hir::Node::Expr(outer) = self.tcx.parent_hir_node(expr.hir_id)1650                    && let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mtbl, _) = outer.kind1651                    && ty.span == span1652                {1653                    // We've encountered something like `&str::from("")`, where the intended code1654                    // was likely `<&str>::from("")`. The former is interpreted as "call method1655                    // `from` on `str` and borrow the result", while the latter means "call method1656                    // `from` on `&str`".16571658                    let trait_pred_and_imm_ref = poly_trait_pred.map_bound(|p| {1659                        (p, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))1660                    });1661                    let trait_pred_and_mut_ref = poly_trait_pred.map_bound(|p| {1662                        (p, Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))1663                    });16641665                    let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);1666                    let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);1667                    let sugg_msg = |pre: &str| {1668                        format!(1669                            "you likely meant to call the associated function `{FN}` for type \1670                             `&{pre}{TY}`, but the code as written calls associated function `{FN}` on \1671                             type `{TY}`",1672                            FN = segment.ident,1673                            TY = poly_trait_pred.self_ty(),1674                        )1675                    };1676                    match (imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl) {1677                        (true, _, hir::Mutability::Not) | (_, true, hir::Mutability::Mut) => {1678                            err.multipart_suggestion(1679                                sugg_msg(mtbl.prefix_str()),1680                                vec![1681                                    (outer.span.shrink_to_lo(), "<".to_string()),1682                                    (span.shrink_to_hi(), ">".to_string()),1683                                ],1684                                Applicability::MachineApplicable,1685                            );1686                        }1687                        (true, _, hir::Mutability::Mut) => {1688                            // There's an associated function found on the immutable borrow of the1689                            err.multipart_suggestion(1690                                sugg_msg("mut "),1691                                vec![1692                                    (outer.span.shrink_to_lo().until(span), "<&".to_string()),1693                                    (span.shrink_to_hi(), ">".to_string()),1694                                ],1695                                Applicability::MachineApplicable,1696                            );1697                        }1698                        (_, true, hir::Mutability::Not) => {1699                            err.multipart_suggestion(1700                                sugg_msg(""),1701                                vec![1702                                    (outer.span.shrink_to_lo().until(span), "<&mut ".to_string()),1703                                    (span.shrink_to_hi(), ">".to_string()),1704                                ],1705                                Applicability::MachineApplicable,1706                            );1707                        }1708                        _ => {}1709                    }1710                    // If we didn't return early here, we would instead suggest `&&str::from("")`.1711                    return false;1712                }1713                c1714            }1715            c if matches!(1716                span.ctxt().outer_expn_data().kind,1717                ExpnKind::Desugaring(DesugaringKind::ForLoop)1718            ) =>1719            {1720                c1721            }1722            _ => return false,1723        };17241725        // List of traits for which it would be nonsensical to suggest borrowing.1726        // For instance, immutable references are always Copy, so suggesting to1727        // borrow would always succeed, but it's probably not what the user wanted.1728        let mut never_suggest_borrow: Vec<_> =1729            [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized]1730                .iter()1731                .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item))1732                .collect();17331734        if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {1735            never_suggest_borrow.push(def_id);1736        }17371738        // Try to apply the original trait bound by borrowing.1739        let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,1740                                 blacklist: &[DefId]|1741         -> bool {1742            if blacklist.contains(&old_pred.def_id()) {1743                return false;1744            }1745            // We map bounds to `&T` and `&mut T`1746            let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {1747                (1748                    trait_pred,1749                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),1750                )1751            });1752            let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {1753                (1754                    trait_pred,1755                    Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),1756                )1757            });17581759            let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);1760            let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);17611762            let (ref_inner_ty_satisfies_pred, ref_inner_ty_is_mut) =1763                if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code()1764                    && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()1765                {1766                    (1767                        mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),1768                        mutability.is_mut(),1769                    )1770                } else {1771                    (false, false)1772                };17731774            let is_immut = imm_ref_self_ty_satisfies_pred1775                || (ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut);1776            let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut;1777            if !is_immut && !is_mut {1778                return false;1779            }1780            let Ok(_snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {1781                return false;1782            };1783            // We don't want a borrowing suggestion on the fields in structs1784            // ```1785            // #[derive(Clone)]1786            // struct Foo {1787            //     the_foos: Vec<Foo>1788            // }1789            // ```1790            if !matches!(1791                span.ctxt().outer_expn_data().kind,1792                ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)1793            ) {1794                return false;1795            }1796            // We have a very specific type of error, where just borrowing this argument1797            // might solve the problem. In cases like this, the important part is the1798            // original type obligation, not the last one that failed, which is arbitrary.1799            // Because of this, we modify the error to refer to the original obligation and1800            // return early in the caller.18011802            let mut label = || {1803                // Special case `Sized` as `old_pred` will be the trait itself instead of1804                // `Sized` when the trait bound is the source of the error.1805                let is_sized = match obligation.predicate.kind().skip_binder() {1806                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {1807                        self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized)1808                    }1809                    _ => false,1810                };18111812                let msg = format!(1813                    "the trait bound `{}` is not satisfied",1814                    self.tcx.short_string(old_pred, err.long_ty_path()),1815                );1816                let self_ty_str = self.tcx.short_string(old_pred.self_ty(), err.long_ty_path());1817                let trait_path = self1818                    .tcx1819                    .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path());18201821                if has_custom_message {1822                    let msg = if is_sized {1823                        "the trait bound `Sized` is not satisfied".into()1824                    } else {1825                        msg1826                    };1827                    err.note(msg);1828                } else {1829                    err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];1830                }1831                if is_sized {1832                    err.span_label(1833                        span,1834                        format!("the trait `Sized` is not implemented for `{self_ty_str}`"),1835                    );1836                } else {1837                    err.span_label(1838                        span,1839                        format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"),1840                    );1841                }1842            };18431844            let mut sugg_prefixes = vec![];1845            if is_immut {1846                sugg_prefixes.push("&");1847            }1848            if is_mut {1849                sugg_prefixes.push("&mut ");1850            }1851            let sugg_msg = format!(1852                "consider{} borrowing here",1853                if is_mut && !is_immut { " mutably" } else { "" },1854            );18551856            // Issue #104961, we need to add parentheses properly for compound expressions1857            // for example, `x.starts_with("hi".to_string() + "you")`1858            // should be `x.starts_with(&("hi".to_string() + "you"))`1859            let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {1860                return false;1861            };1862            let mut expr_finder = FindExprBySpan::new(span, self.tcx);1863            expr_finder.visit_expr(body.value);18641865            if let Some(ty) = expr_finder.ty_result {1866                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(ty.hir_id)1867                    && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, _)) = expr.kind1868                    && ty.span == span1869                {1870                    // We've encountered something like `str::from("")`, where the intended code1871                    // was likely `<&str>::from("")`. #143393.1872                    label();1873                    err.multipart_suggestions(1874                        sugg_msg,1875                        sugg_prefixes.into_iter().map(|sugg_prefix| {1876                            vec![1877                                (span.shrink_to_lo(), format!("<{sugg_prefix}")),1878                                (span.shrink_to_hi(), ">".to_string()),1879                            ]1880                        }),1881                        Applicability::MaybeIncorrect,1882                    );1883                    return true;1884                }1885                return false;1886            }1887            let Some(expr) = expr_finder.result else {1888                return false;1889            };1890            if let hir::ExprKind::AddrOf(_, _, _) = expr.kind {1891                return false;1892            }1893            let old_self_ty = old_pred.skip_binder().self_ty();1894            if !old_self_ty.has_escaping_bound_vars()1895                && !self.where_clause_expr_matches_failed_self_ty(1896                    obligation,1897                    self.tcx.instantiate_bound_regions_with_erased(old_pred.self_ty()),1898                )1899            {1900                return false;1901            }1902            let needs_parens_post = expr_needs_parens(expr);1903            let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) {1904                Node::Expr(e)1905                    if let hir::ExprKind::MethodCall(_, base, _, _) = e.kind1906                        && base.hir_id == expr.hir_id =>1907                {1908                    true1909                }1910                _ => false,1911            };19121913            label();1914            let suggestions = sugg_prefixes.into_iter().map(|sugg_prefix| {1915                match (needs_parens_pre, needs_parens_post) {1916                    (false, false) => vec![(span.shrink_to_lo(), sugg_prefix.to_string())],1917                    // We have something like `foo.bar()`, where we want to bororw foo, so we need1918                    // to suggest `(&mut foo).bar()`.1919                    (false, true) => vec![1920                        (span.shrink_to_lo(), format!("{sugg_prefix}(")),1921                        (span.shrink_to_hi(), ")".to_string()),1922                    ],1923                    // Issue #109436, we need to add parentheses properly for method calls1924                    // for example, `foo.into()` should be `(&foo).into()`1925                    (true, false) => vec![1926                        (span.shrink_to_lo(), format!("({sugg_prefix}")),1927                        (span.shrink_to_hi(), ")".to_string()),1928                    ],1929                    (true, true) => vec![1930                        (span.shrink_to_lo(), format!("({sugg_prefix}(")),1931                        (span.shrink_to_hi(), "))".to_string()),1932                    ],1933                }1934            });1935            err.multipart_suggestions(sugg_msg, suggestions, Applicability::MaybeIncorrect);1936            return true;1937        };19381939        if let ObligationCauseCode::ImplDerived(cause) = &*code {1940            try_borrowing(cause.derived.parent_trait_pred, &[])1941        } else if let ObligationCauseCode::WhereClause(..)1942        | ObligationCauseCode::WhereClauseInExpr(..) = code1943        {1944            try_borrowing(poly_trait_pred, &never_suggest_borrow)1945        } else {1946            false1947        }1948    }19491950    // Suggest borrowing the type1951    pub(super) fn suggest_borrowing_for_object_cast(1952        &self,1953        err: &mut Diag<'_>,1954        obligation: &PredicateObligation<'tcx>,1955        self_ty: Ty<'tcx>,1956        target_ty: Ty<'tcx>,1957    ) {1958        let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else {1959            return;1960        };1961        let ty::Dynamic(predicates, _) = object_ty.kind() else {1962            return;1963        };1964        let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty);19651966        for predicate in predicates.iter() {1967            if !self.predicate_must_hold_modulo_regions(1968                &obligation.with(self.tcx, predicate.with_self_ty(self.tcx, self_ref_ty)),1969            ) {1970                return;1971            }1972        }19731974        err.span_suggestion_verbose(1975            obligation.cause.span.shrink_to_lo(),1976            format!(1977                "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`"1978            ),1979            "&",1980            Applicability::MaybeIncorrect,1981        );1982    }19831984    /// Peel `&`-borrows from an expression, following through untyped let-bindings.1985    /// Returns a list of removable `&` layers (each with the span to remove and the1986    /// resulting type), plus an optional terminal [`hir::Param`] when the chain ends1987    /// at a function parameter (including async-fn desugared parameters).1988    fn peel_expr_refs(1989        &self,1990        mut expr: &'tcx hir::Expr<'tcx>,1991        mut ty: Ty<'tcx>,1992    ) -> (Vec<PeeledRef<'tcx>>, Option<&'tcx hir::Param<'tcx>>) {1993        let mut refs = Vec::new();1994        'outer: loop {1995            while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {1996                let span =1997                    if let Some(borrowed_span) = borrowed.span.find_ancestor_inside(expr.span) {1998                        expr.span.until(borrowed_span)1999                    } else {2000                        break 'outer;

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.