compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs RUST 6,639 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 6,639.
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::diagnostics;52use crate::error_reporting::TypeErrCtxt;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::ProjectionAliasTy<'_>>,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) && !tcx.features().return_type_notation())144                || tcx.lookup_stability(projection.kind).is_some_and(|stab| stab.is_unstable())145        })146    {147        return;148    }149    let generics = tcx.generics_of(item_id);150    // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...151    if let Some((param, bound_str, fn_sig)) =152        fn_sig.zip(projection).and_then(|(sig, p)| match *p.projection_self_ty().kind() {153            // Shenanigans to get the `Trait` from the `impl Trait`.154            ty::Param(param) => {155                let param_def = generics.type_param(param, tcx);156                if param_def.kind.is_synthetic() {157                    let bound_str =158                        param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string();159                    return Some((param_def, bound_str, sig));160                }161                None162            }163            _ => None,164        })165    {166        let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str));167        let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder {168            tcx,169            param,170            replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))171                .to_ty(tcx),172        });173        if !trait_pred.is_suggestable(tcx, false) {174            return;175        }176        // We know we have an `impl Trait` that doesn't satisfy a required projection.177178        // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'179        // types. There should be at least one, but there might be *more* than one. In that180        // case we could just ignore it and try to identify which one needs the restriction,181        // but instead we choose to suggest replacing all instances of `impl Trait` with `T`182        // where `T: Trait`.183        let mut ty_spans = vec![];184        for input in fn_sig.decl.inputs {185            ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }186                .visit_ty_unambig(input);187        }188        // The type param `T: Trait` we will suggest to introduce.189        let type_param = format!("{type_param_name}: {bound_str}");190191        let mut sugg = vec![192            if let Some(span) = hir_generics.span_for_param_suggestion() {193                (span, format!(", {type_param}"))194            } else {195                (hir_generics.span, format!("<{type_param}>"))196            },197            // `fn foo(t: impl Trait)`198            //                       ^ suggest `where <T as Trait>::A: Bound`199            predicate_constraint(hir_generics, trait_pred.upcast(tcx)),200        ];201        sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));202203        // Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.204        // FIXME: we should suggest `fn foo(t: impl Trait<A: Bound>)` instead.205        err.multipart_suggestion(206            "introduce a type parameter with a trait bound instead of using `impl Trait`",207            sugg,208            Applicability::MaybeIncorrect,209        );210    } else {211        if !trait_pred.is_suggestable(tcx, false) {212            return;213        }214        // Trivial case: `T` needs an extra bound: `T: Bound`.215        let (sp, suggestion) = match (216            hir_generics217                .params218                .iter()219                .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),220            super_traits,221        ) {222            (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),223            (None, Some((ident, []))) => (224                ident.span.shrink_to_hi(),225                format!(": {}", trait_pred.print_modifiers_and_trait_path()),226            ),227            (_, Some((_, [.., bounds]))) => (228                bounds.span().shrink_to_hi(),229                format!(" + {}", trait_pred.print_modifiers_and_trait_path()),230            ),231            (Some(_), Some((_, []))) => (232                hir_generics.span.shrink_to_hi(),233                format!(": {}", trait_pred.print_modifiers_and_trait_path()),234            ),235        };236237        err.span_suggestion_verbose(238            sp,239            format!("consider further restricting {msg}"),240            suggestion,241            Applicability::MachineApplicable,242        );243    }244}245246/// A single layer of `&` peeled from an expression, used by247/// [`TypeErrCtxt::peel_expr_refs`].248struct PeeledRef<'tcx> {249    /// The span covering the `&` (and any whitespace/mutability keyword) to remove.250    span: Span,251    /// The type after peeling this layer (and all prior layers).252    peeled_ty: Ty<'tcx>,253}254255impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {256    pub fn note_field_shadowed_by_private_candidate_in_cause(257        &self,258        err: &mut Diag<'_>,259        cause: &ObligationCause<'tcx>,260        param_env: ty::ParamEnv<'tcx>,261    ) {262        let mut hir_ids = FxHashSet::default();263        // Walk the parent chain so we can recover264        // the source expression from whichever layer carries them.265        let mut next_code = Some(cause.code());266        while let Some(cause_code) = next_code {267            match cause_code {268                ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => {269                    hir_ids.insert(*lhs_hir_id);270                    hir_ids.insert(*rhs_hir_id);271                }272                ObligationCauseCode::FunctionArg { arg_hir_id, .. }273                | ObligationCauseCode::ReturnValue(arg_hir_id)274                | ObligationCauseCode::AwaitableExpr(arg_hir_id)275                | ObligationCauseCode::BlockTailExpression(arg_hir_id, _)276                | ObligationCauseCode::UnOp { hir_id: arg_hir_id } => {277                    hir_ids.insert(*arg_hir_id);278                }279                ObligationCauseCode::OpaqueReturnType(Some((_, hir_id))) => {280                    hir_ids.insert(*hir_id);281                }282                _ => {}283            }284            next_code = cause_code.parent();285        }286287        if !cause.span.is_dummy()288            && let Some(body) = self.tcx.hir_maybe_body_owned_by(cause.body_id)289        {290            let mut expr_finder = FindExprBySpan::new(cause.span, self.tcx);291            expr_finder.visit_body(body);292            if let Some(expr) = expr_finder.result {293                hir_ids.insert(expr.hir_id);294            }295        }296297        // we will sort immediately by source order before emitting any diagnostics298        #[allow(rustc::potential_query_instability)]299        let mut hir_ids: Vec<_> = hir_ids.into_iter().collect();300        let source_map = self.tcx.sess.source_map();301        hir_ids.sort_by_cached_key(|hir_id| {302            let span = self.tcx.hir_span(*hir_id);303            let lo = source_map.lookup_byte_offset(span.lo());304            let hi = source_map.lookup_byte_offset(span.hi());305            (lo.sf.name.prefer_remapped_unconditionally().to_string(), lo.pos.0, hi.pos.0)306        });307308        for hir_id in hir_ids {309            self.note_field_shadowed_by_private_candidate(err, hir_id, param_env);310        }311    }312313    pub fn note_field_shadowed_by_private_candidate(314        &self,315        err: &mut Diag<'_>,316        hir_id: hir::HirId,317        param_env: ty::ParamEnv<'tcx>,318    ) {319        let Some(typeck_results) = &self.typeck_results else {320            return;321        };322        let Node::Expr(expr) = self.tcx.hir_node(hir_id) else {323            return;324        };325        let hir::ExprKind::Field(base_expr, field_ident) = expr.kind else {326            return;327        };328329        let Some(base_ty) = typeck_results.expr_ty_opt(base_expr) else {330            return;331        };332        let base_ty = self.resolve_vars_if_possible(base_ty);333        if base_ty.references_error() {334            return;335        }336337        let fn_body_hir_id = self.tcx.local_def_id_to_hir_id(typeck_results.hir_owner.def_id);338        let mut private_candidate: Option<(Ty<'tcx>, Ty<'tcx>, Span)> = None;339340        for (deref_base_ty, _) in (self.autoderef_steps)(base_ty) {341            let ty::Adt(base_def, args) = deref_base_ty.kind() else {342                continue;343            };344345            if base_def.is_enum() {346                continue;347            }348349            let (adjusted_ident, def_scope) =350                self.tcx.adjust_ident_and_get_scope(field_ident, base_def.did(), fn_body_hir_id);351352            let Some((_, field_def)) =353                base_def.non_enum_variant().fields.iter_enumerated().find(|(_, field)| {354                    field.ident(self.tcx).normalize_to_macros_2_0() == adjusted_ident355                })356            else {357                continue;358            };359            let field_span = self360                .tcx361                .def_ident_span(field_def.did)362                .unwrap_or_else(|| self.tcx.def_span(field_def.did));363364            if field_def.vis.is_accessible_from(def_scope, self.tcx) {365                let accessible_field_ty = field_def.ty(self.tcx, args).skip_norm_wip();366                if let Some((private_base_ty, private_field_ty, private_field_span)) =367                    private_candidate368                    && !self.can_eq(param_env, private_field_ty, accessible_field_ty)369                {370                    let private_struct_span = match private_base_ty.kind() {371                        ty::Adt(private_base_def, _) => self372                            .tcx373                            .def_ident_span(private_base_def.did())374                            .unwrap_or_else(|| self.tcx.def_span(private_base_def.did())),375                        _ => DUMMY_SP,376                    };377                    let accessible_struct_span = self378                        .tcx379                        .def_ident_span(base_def.did())380                        .unwrap_or_else(|| self.tcx.def_span(base_def.did()));381                    let deref_impl_span = (typeck_results382                        .expr_adjustments(base_expr)383                        .iter()384                        .filter(|adj| {385                            matches!(adj.kind, Adjust::Deref(DerefAdjustKind::Overloaded(_)))386                        })387                        .count()388                        == 1)389                        .then(|| {390                            self.probe(|_| {391                                let deref_trait_did =392                                    self.tcx.require_lang_item(LangItem::Deref, DUMMY_SP);393                                let trait_ref =394                                    ty::TraitRef::new(self.tcx, deref_trait_did, [private_base_ty]);395                                let obligation: Obligation<'tcx, ty::Predicate<'tcx>> =396                                    Obligation::new(397                                        self.tcx,398                                        ObligationCause::dummy(),399                                        param_env,400                                        trait_ref,401                                    );402                                let Ok(Some(ImplSource::UserDefined(impl_data))) =403                                    SelectionContext::new(self)404                                        .select(&obligation.with(self.tcx, trait_ref))405                                else {406                                    return None;407                                };408                                Some(self.tcx.def_span(impl_data.impl_def_id))409                            })410                        })411                        .flatten();412413                    let mut note_spans: MultiSpan = private_struct_span.into();414                    if private_struct_span != DUMMY_SP {415                        note_spans.push_span_label(private_struct_span, "in this struct");416                    }417                    if private_field_span != DUMMY_SP {418                        note_spans.push_span_label(419                            private_field_span,420                            "if this field wasn't private, it would be accessible",421                        );422                    }423                    if accessible_struct_span != DUMMY_SP {424                        note_spans.push_span_label(425                            accessible_struct_span,426                            "this struct is accessible through auto-deref",427                        );428                    }429                    if field_span != DUMMY_SP {430                        note_spans431                            .push_span_label(field_span, "this is the field that was accessed");432                    }433                    if let Some(deref_impl_span) = deref_impl_span434                        && deref_impl_span != DUMMY_SP435                    {436                        note_spans.push_span_label(437                            deref_impl_span,438                            "the field was accessed through this `Deref`",439                        );440                    }441442                    err.span_note(443                        note_spans,444                        format!(445                            "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"446                        ),447                    );448                }449450                // we finally get to the accessible field,451                // so we can return early without checking the rest of the autoderef candidates452                return;453            }454455            private_candidate.get_or_insert((456                deref_base_ty,457                field_def.ty(self.tcx, args).skip_norm_wip(),458                field_span,459            ));460        }461    }462463    pub fn suggest_restricting_param_bound(464        &self,465        err: &mut Diag<'_>,466        trait_pred: ty::PolyTraitPredicate<'tcx>,467        associated_ty: Option<(&'static str, Ty<'tcx>)>,468        mut body_id: LocalDefId,469    ) {470        if trait_pred.skip_binder().polarity != ty::PredicatePolarity::Positive {471            return;472        }473474        let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);475476        let self_ty = trait_pred.skip_binder().self_ty();477        let (param_ty, projection) = match *self_ty.kind() {478            ty::Param(_) => (true, None),479            ty::Alias(alias) => {480                if let Some(projection) = alias.try_to_projection() {481                    (false, Some(projection))482                } else {483                    (false, None)484                }485            }486            _ => (false, None),487        };488489        let mut finder = ParamFinder { .. };490        finder.visit_binder(&trait_pred);491492        // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we493        //        don't suggest `T: Sized + ?Sized`.494        loop {495            let node = self.tcx.hir_node_by_def_id(body_id);496            match node {497                hir::Node::Item(hir::Item {498                    kind: hir::ItemKind::Trait { ident, generics, bounds, .. },499                    ..500                }) if self_ty == self.tcx.types.self_param => {501                    assert!(param_ty);502                    // Restricting `Self` for a single method.503                    suggest_restriction(504                        self.tcx,505                        body_id,506                        generics,507                        "`Self`",508                        err,509                        None,510                        projection,511                        trait_pred,512                        Some((&ident, bounds)),513                    );514                    return;515                }516517                hir::Node::TraitItem(hir::TraitItem {518                    generics,519                    kind: hir::TraitItemKind::Fn(..),520                    ..521                }) if self_ty == self.tcx.types.self_param => {522                    assert!(param_ty);523                    // Restricting `Self` for a single method.524                    suggest_restriction(525                        self.tcx, body_id, generics, "`Self`", err, None, projection, trait_pred,526                        None,527                    );528                    return;529                }530531                hir::Node::TraitItem(hir::TraitItem {532                    generics,533                    kind: hir::TraitItemKind::Fn(fn_sig, ..),534                    ..535                })536                | hir::Node::ImplItem(hir::ImplItem {537                    generics,538                    kind: hir::ImplItemKind::Fn(fn_sig, ..),539                    ..540                })541                | hir::Node::Item(hir::Item {542                    kind: hir::ItemKind::Fn { sig: fn_sig, generics, .. },543                    ..544                }) if projection.is_some() => {545                    // Missing restriction on associated type of type parameter (unmet projection).546                    suggest_restriction(547                        self.tcx,548                        body_id,549                        generics,550                        "the associated type",551                        err,552                        Some(fn_sig),553                        projection,554                        trait_pred,555                        None,556                    );557                    return;558                }559                hir::Node::Item(hir::Item {560                    kind:561                        hir::ItemKind::Trait { generics, .. }562                        | hir::ItemKind::Impl(hir::Impl { generics, .. }),563                    ..564                }) if projection.is_some() => {565                    // Missing restriction on associated type of type parameter (unmet projection).566                    suggest_restriction(567                        self.tcx,568                        body_id,569                        generics,570                        "the associated type",571                        err,572                        None,573                        projection,574                        trait_pred,575                        None,576                    );577                    return;578                }579580                hir::Node::Item(hir::Item {581                    kind:582                        hir::ItemKind::Struct(_, generics, _)583                        | hir::ItemKind::Enum(_, generics, _)584                        | hir::ItemKind::Union(_, generics, _)585                        | hir::ItemKind::Trait { generics, .. }586                        | hir::ItemKind::Impl(hir::Impl { generics, .. })587                        | hir::ItemKind::Fn { generics, .. }588                        | hir::ItemKind::TyAlias(_, generics, _)589                        | hir::ItemKind::Const(_, generics, _, _)590                        | hir::ItemKind::TraitAlias(_, _, generics, _),591                    ..592                })593                | hir::Node::TraitItem(hir::TraitItem { generics, .. })594                | hir::Node::ImplItem(hir::ImplItem { generics, .. })595                    if param_ty =>596                {597                    // We skip the 0'th arg (self) because we do not want598                    // to consider the predicate as not suggestible if the599                    // self type is an arg position `impl Trait` -- instead,600                    // we handle that by adding ` + Bound` below.601                    // FIXME(compiler-errors): It would be nice to do the same602                    // this that we do in `suggest_restriction` and pull the603                    // `impl Trait` into a new generic if it shows up somewhere604                    // else in the predicate.605                    if !trait_pred.skip_binder().trait_ref.args[1..]606                        .iter()607                        .all(|g| g.is_suggestable(self.tcx, false))608                    {609                        return;610                    }611                    // Missing generic type parameter bound.612                    let param_name = self_ty.to_string();613                    let mut constraint = with_no_trimmed_paths!(614                        trait_pred.print_modifiers_and_trait_path().to_string()615                    );616617                    if let Some((name, term)) = associated_ty {618                        // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.619                        // That should be extracted into a helper function.620                        if let Some(stripped) = constraint.strip_suffix('>') {621                            constraint = format!("{stripped}, {name} = {term}>");622                        } else {623                            constraint.push_str(&format!("<{name} = {term}>"));624                        }625                    }626627                    if suggest_constraining_type_param(628                        self.tcx,629                        generics,630                        err,631                        &param_name,632                        &constraint,633                        Some(trait_pred.def_id()),634                        None,635                    ) {636                        return;637                    }638                }639640                hir::Node::TraitItem(hir::TraitItem {641                    generics,642                    kind: hir::TraitItemKind::Fn(..),643                    ..644                })645                | hir::Node::ImplItem(hir::ImplItem {646                    generics,647                    impl_kind: hir::ImplItemImplKind::Inherent { .. },648                    kind: hir::ImplItemKind::Fn(..),649                    ..650                }) if finder.can_suggest_bound(generics) => {651                    // Missing generic type parameter bound.652                    suggest_arbitrary_trait_bound(653                        self.tcx,654                        generics,655                        err,656                        trait_pred,657                        associated_ty,658                    );659                }660                hir::Node::Item(hir::Item {661                    kind:662                        hir::ItemKind::Struct(_, generics, _)663                        | hir::ItemKind::Enum(_, generics, _)664                        | hir::ItemKind::Union(_, generics, _)665                        | hir::ItemKind::Trait { generics, .. }666                        | hir::ItemKind::Impl(hir::Impl { generics, .. })667                        | hir::ItemKind::Fn { generics, .. }668                        | hir::ItemKind::TyAlias(_, generics, _)669                        | hir::ItemKind::Const(_, generics, _, _)670                        | hir::ItemKind::TraitAlias(_, _, generics, _),671                    ..672                }) if finder.can_suggest_bound(generics) => {673                    // Missing generic type parameter bound.674                    if suggest_arbitrary_trait_bound(675                        self.tcx,676                        generics,677                        err,678                        trait_pred,679                        associated_ty,680                    ) {681                        return;682                    }683                }684                hir::Node::Crate(..) => return,685686                _ => {}687            }688            body_id = self.tcx.local_parent(body_id);689        }690    }691692    /// Provide a suggestion to dereference arguments to functions and binary operators, if that693    /// would satisfy trait bounds.694    pub(super) fn suggest_dereferences(695        &self,696        obligation: &PredicateObligation<'tcx>,697        err: &mut Diag<'_>,698        trait_pred: ty::PolyTraitPredicate<'tcx>,699    ) -> bool {700        let mut code = obligation.cause.code();701        if let ObligationCauseCode::FunctionArg { arg_hir_id, call_hir_id, .. } = code702            && let Some(typeck_results) = &self.typeck_results703            && let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id)704            && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)705        {706            // Suggest dereferencing the argument to a function/method call if possible707708            // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)709            let mut real_trait_pred = trait_pred;710            while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {711                code = parent_code;712                if let Some(parent_trait_pred) = parent_trait_pred {713                    real_trait_pred = parent_trait_pred;714                }715            }716717            // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle718            // `ReBound`, and we don't particularly care about the regions.719            let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty());720            if !self.can_eq(obligation.param_env, real_ty, arg_ty) {721                return false;722            }723724            // Potentially, we'll want to place our dereferences under a `&`. We don't try this for725            // `&mut`, since we can't be sure users will get the side-effects they want from it.726            // If this doesn't work, we'll try removing the `&` in `suggest_remove_reference`.727            // FIXME(dianne): this misses the case where users need both to deref and remove `&`s.728            // This method could be combined with `TypeErrCtxt::suggest_remove_reference` to handle729            // that, similar to what `FnCtxt::suggest_deref_or_ref` does.730            let (is_under_ref, base_ty, span) = match expr.kind {731                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, subexpr)732                    if let &ty::Ref(region, base_ty, hir::Mutability::Not) = real_ty.kind() =>733                {734                    (Some(region), base_ty, subexpr.span)735                }736                // Don't suggest `*&mut`, etc.737                hir::ExprKind::AddrOf(..) => return false,738                _ => (None, real_ty, obligation.cause.span),739            };740741            let autoderef = (self.autoderef_steps)(base_ty);742            let mut is_boxed = base_ty.is_box();743            if let Some(steps) = autoderef.into_iter().position(|(mut ty, obligations)| {744                // Ensure one of the following for dereferencing to be valid: we're passing by745                // reference, `ty` is `Copy`, or we're moving out of a (potentially nested) `Box`.746                let can_deref = is_under_ref.is_some()747                    || self.type_is_copy_modulo_regions(obligation.param_env, ty)748                    || ty.is_numeric() // for inference vars (presumably but not provably `Copy`)749                    || is_boxed && self.type_is_sized_modulo_regions(obligation.param_env, ty);750                is_boxed &= ty.is_box();751752                // Re-add the `&` if necessary753                if let Some(region) = is_under_ref {754                    ty = Ty::new_ref(self.tcx, region, ty, hir::Mutability::Not);755                }756757                // Remapping bound vars here758                let real_trait_pred_and_ty =759                    real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));760                let obligation = self.mk_trait_obligation_with_new_self_ty(761                    obligation.param_env,762                    real_trait_pred_and_ty,763                );764765                can_deref766                    && obligations767                        .iter()768                        .chain([&obligation])769                        .all(|obligation| self.predicate_may_hold(obligation))770            }) && steps > 0771            {772                if span.in_external_macro(self.tcx.sess.source_map()) {773                    return false;774                }775                let derefs = "*".repeat(steps);776                let msg = "consider dereferencing here";777778                let call_node = self.tcx.hir_node(*call_hir_id);779                let is_receiver = matches!(780                    call_node,781                    Node::Expr(hir::Expr {782                        kind: hir::ExprKind::MethodCall(_, receiver_expr, ..),783                        ..784                    })785                    if receiver_expr.hir_id == *arg_hir_id786                );787                if is_receiver {788                    err.multipart_suggestion(789                        msg,790                        vec![791                            (span.shrink_to_lo(), format!("({derefs}")),792                            (span.shrink_to_hi(), ")".to_string()),793                        ],794                        Applicability::MachineApplicable,795                    )796                } else {797                    err.span_suggestion_verbose(798                        span.shrink_to_lo(),799                        msg,800                        derefs,801                        Applicability::MachineApplicable,802                    )803                };804                return true;805            }806        } else if let (807            ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. },808            predicate,809        ) = code.peel_derives_with_predicate()810            && let Some(typeck_results) = &self.typeck_results811            && let hir::Node::Expr(lhs) = self.tcx.hir_node(*lhs_hir_id)812            && let hir::Node::Expr(rhs) = self.tcx.hir_node(*rhs_hir_id)813            && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs)814            && let trait_pred = predicate.unwrap_or(trait_pred)815            // Only run this code on binary operators816            && hir::lang_items::BINARY_OPERATORS817                .iter()818                .filter_map(|&op| self.tcx.lang_items().get(op))819                .any(|op| {820                    op == trait_pred.skip_binder().trait_ref.def_id821                })822        {823            // Suggest dereferencing the LHS, RHS, or both terms of a binop if possible824            let trait_pred = predicate.unwrap_or(trait_pred);825            let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty());826            let lhs_autoderef = (self.autoderef_steps)(lhs_ty);827            let rhs_autoderef = (self.autoderef_steps)(rhs_ty);828            let first_lhs = lhs_autoderef.first().unwrap().clone();829            let first_rhs = rhs_autoderef.first().unwrap().clone();830            let mut autoderefs = lhs_autoderef831                .into_iter()832                .enumerate()833                .rev()834                .zip_longest(rhs_autoderef.into_iter().enumerate().rev())835                .map(|t| match t {836                    EitherOrBoth::Both(a, b) => (a, b),837                    EitherOrBoth::Left(a) => (a, (0, first_rhs.clone())),838                    EitherOrBoth::Right(b) => ((0, first_lhs.clone()), b),839                })840                .rev();841            if let Some((lsteps, rsteps)) =842                autoderefs.find_map(|((lsteps, (l_ty, _)), (rsteps, (r_ty, _)))| {843                    // Create a new predicate with the dereferenced LHS and RHS844                    // We simultaneously dereference both sides rather than doing them845                    // one at a time to account for cases such as &Box<T> == &&T846                    let trait_pred_and_ty = trait_pred.map_bound(|inner| {847                        (848                            ty::TraitPredicate {849                                trait_ref: ty::TraitRef::new_from_args(850                                    self.tcx,851                                    inner.trait_ref.def_id,852                                    self.tcx.mk_args(853                                        &[&[l_ty.into(), r_ty.into()], &inner.trait_ref.args[2..]]854                                            .concat(),855                                    ),856                                ),857                                ..inner858                            },859                            l_ty,860                        )861                    });862                    let obligation = self.mk_trait_obligation_with_new_self_ty(863                        obligation.param_env,864                        trait_pred_and_ty,865                    );866                    self.predicate_may_hold(&obligation).then_some(match (lsteps, rsteps) {867                        (_, 0) => (Some(lsteps), None),868                        (0, _) => (None, Some(rsteps)),869                        _ => (Some(lsteps), Some(rsteps)),870                    })871                })872            {873                let make_sugg = |mut expr: &Expr<'_>, mut steps| {874                    if expr.span.in_external_macro(self.tcx.sess.source_map()) {875                        return None;876                    }877                    let mut prefix_span = expr.span.shrink_to_lo();878                    let mut msg = "consider dereferencing here";879                    if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind {880                        msg = "consider removing the borrow and dereferencing instead";881                        if let hir::ExprKind::AddrOf(..) = inner.kind {882                            msg = "consider removing the borrows and dereferencing instead";883                        }884                    }885                    while let hir::ExprKind::AddrOf(_, _, inner) = expr.kind886                        && steps > 0887                    {888                        prefix_span = prefix_span.with_hi(inner.span.lo());889                        expr = inner;890                        steps -= 1;891                    }892                    // Empty suggestions with empty spans ICE with debug assertions893                    if steps == 0 {894                        return Some((895                            msg.trim_end_matches(" and dereferencing instead"),896                            vec![(prefix_span, String::new())],897                        ));898                    }899                    let derefs = "*".repeat(steps);900                    let needs_parens = steps > 0 && expr_needs_parens(expr);901                    let mut suggestion = if needs_parens {902                        vec![903                            (904                                expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),905                                format!("{derefs}("),906                            ),907                            (expr.span.shrink_to_hi(), ")".to_string()),908                        ]909                    } else {910                        vec![(911                            expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),912                            format!("{derefs}"),913                        )]914                    };915                    // Empty suggestions with empty spans ICE with debug assertions916                    if !prefix_span.is_empty() {917                        suggestion.push((prefix_span, String::new()));918                    }919                    Some((msg, suggestion))920                };921922                if let Some(lsteps) = lsteps923                    && let Some(rsteps) = rsteps924                    && lsteps > 0925                    && rsteps > 0926                {927                    let Some((_, mut suggestion)) = make_sugg(lhs, lsteps) else {928                        return false;929                    };930                    let Some((_, mut rhs_suggestion)) = make_sugg(rhs, rsteps) else {931                        return false;932                    };933                    suggestion.append(&mut rhs_suggestion);934                    err.multipart_suggestion(935                        "consider dereferencing both sides of the expression",936                        suggestion,937                        Applicability::MachineApplicable,938                    );939                    return true;940                } else if let Some(lsteps) = lsteps941                    && lsteps > 0942                {943                    let Some((msg, suggestion)) = make_sugg(lhs, lsteps) else {944                        return false;945                    };946                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);947                    return true;948                } else if let Some(rsteps) = rsteps949                    && rsteps > 0950                {951                    let Some((msg, suggestion)) = make_sugg(rhs, rsteps) else {952                        return false;953                    };954                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);955                    return true;956                }957            }958        }959        false960    }961962    /// Given a closure's `DefId`, return the given name of the closure.963    ///964    /// This doesn't account for reassignments, but it's only used for suggestions.965    fn get_closure_name(966        &self,967        def_id: DefId,968        err: &mut Diag<'_>,969        msg: Cow<'static, str>,970    ) -> Option<Symbol> {971        let get_name = |err: &mut Diag<'_>, kind: &hir::PatKind<'_>| -> Option<Symbol> {972            // Get the local name of this closure. This can be inaccurate because973            // of the possibility of reassignment, but this should be good enough.974            match &kind {975                hir::PatKind::Binding(hir::BindingMode::NONE, _, ident, None) => Some(ident.name),976                _ => {977                    err.note(msg);978                    None979                }980            }981        };982983        let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);984        match self.tcx.parent_hir_node(hir_id) {985            hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(local), .. }) => {986                get_name(err, &local.pat.kind)987            }988            // Different to previous arm because one is `&hir::Local` and the other989            // is `Box<hir::Local>`.990            hir::Node::LetStmt(local) => get_name(err, &local.pat.kind),991            _ => None,992        }993    }994995    /// We tried to apply the bound to an `fn` or closure. Check whether calling it would996    /// evaluate to a type that *would* satisfy the trait bound. If it would, suggest calling997    /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.998    pub(super) fn suggest_fn_call(999        &self,1000        obligation: &PredicateObligation<'tcx>,1001        err: &mut Diag<'_>,1002        trait_pred: ty::PolyTraitPredicate<'tcx>,1003    ) -> bool {1004        // It doesn't make sense to make this suggestion outside of typeck...1005        // (also autoderef will ICE...)1006        if self.typeck_results.is_none() {1007            return false;1008        }10091010        if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =1011            obligation.predicate.kind().skip_binder()1012            && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized)1013        {1014            // Don't suggest calling to turn an unsized type into a sized type1015            return false;1016        }10171018        let self_ty = self.instantiate_binder_with_fresh_vars(1019            DUMMY_SP,1020            BoundRegionConversionTime::FnCall,1021            trait_pred.self_ty(),1022        );10231024        let Some((def_id_or_name, output, inputs)) =1025            self.extract_callable_info(obligation.cause.body_id, obligation.param_env, self_ty)1026        else {1027            return false;1028        };10291030        // Remapping bound vars here1031        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));10321033        let new_obligation =1034            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);1035        if !self.predicate_must_hold_modulo_regions(&new_obligation) {1036            return false;1037        }10381039        // If this is a zero-argument async closure directly passed as an argument1040        // and the expected type is `Future`, suggest using `async {}` block instead1041        // of `async || {}`1042        if let ty::CoroutineClosure(def_id, args) = *self_ty.kind()1043            && let sig = args.as_coroutine_closure().coroutine_closure_sig().skip_binder()1044            && let ty::Tuple(inputs) = *sig.tupled_inputs_ty.kind()1045            && inputs.is_empty()1046            && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Future)1047            && let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1048            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) =1049                self.tcx.hir_node(*arg_hir_id)1050            && let Some(hir::Node::Expr(hir::Expr {1051                kind: hir::ExprKind::Closure(closure), ..1052            })) = self.tcx.hir_get_if_local(def_id)1053            && let hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async) = closure.kind1054            && let Some(arg_span) = closure.fn_arg_span1055            && obligation.cause.span.contains(arg_span)1056        {1057            let mut body = self.tcx.hir_body(closure.body).value;1058            let peeled = body.peel_blocks().peel_drop_temps();1059            if let hir::ExprKind::Closure(inner) = peeled.kind {1060                body = self.tcx.hir_body(inner.body).value;1061            }1062            if !matches!(body.peel_blocks().peel_drop_temps().kind, hir::ExprKind::Block(..)) {1063                return false;1064            }10651066            let sm = self.tcx.sess.source_map();1067            let removal_span = if let Ok(snippet) =1068                sm.span_to_snippet(arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1)))1069                && snippet.ends_with(' ')1070            {1071                // There's a space after `||`, include it in the removal1072                arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1))1073            } else {1074                arg_span1075            };1076            err.span_suggestion_verbose(1077                removal_span,1078                "use `async {}` instead of `async || {}` to introduce an async block",1079                "",1080                Applicability::MachineApplicable,1081            );1082            return true;1083        }10841085        // Get the name of the callable and the arguments to be used in the suggestion.1086        let msg = match def_id_or_name {1087            DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {1088                DefKind::Ctor(CtorOf::Struct, _) => {1089                    Cow::from("use parentheses to construct this tuple struct")1090                }1091                DefKind::Ctor(CtorOf::Variant, _) => {1092                    Cow::from("use parentheses to construct this tuple variant")1093                }1094                kind => Cow::from(format!(1095                    "use parentheses to call this {}",1096                    self.tcx.def_kind_descr(kind, def_id)1097                )),1098            },1099            DefIdOrName::Name(name) => Cow::from(format!("use parentheses to call this {name}")),1100        };11011102        let args = inputs1103            .into_iter()1104            .map(|ty| {1105                if ty.is_suggestable(self.tcx, false) {1106                    format!("/* {ty} */")1107                } else {1108                    "/* value */".to_string()1109                }1110            })1111            .collect::<Vec<_>>()1112            .join(", ");11131114        if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1115            && obligation.cause.span.can_be_used_for_suggestions()1116        {1117            let span = obligation.cause.span;11181119            let arg_expr = match self.tcx.hir_node(*arg_hir_id) {1120                hir::Node::Expr(expr) => Some(expr),1121                _ => None,1122            };11231124            let is_closure_expr =1125                arg_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Closure(..)));11261127            // If the user wrote `|| {}()`, suggesting to call the closure would produce `(|| {}())()`,1128            // which doesn't help and is often outright wrong.1129            if args.is_empty()1130                && let Some(expr) = arg_expr1131                && let hir::ExprKind::Closure(closure) = expr.kind1132            {1133                let mut body = self.tcx.hir_body(closure.body).value;11341135                // Async closures desugar to a closure returning a coroutine1136                if let hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) =1137                    closure.kind1138                {1139                    let peeled = body.peel_blocks().peel_drop_temps();1140                    if let hir::ExprKind::Closure(inner) = peeled.kind {1141                        body = self.tcx.hir_body(inner.body).value;1142                    }1143                }11441145                let peeled_body = body.peel_blocks().peel_drop_temps();1146                if let hir::ExprKind::Call(callee, call_args) = peeled_body.kind1147                    && call_args.is_empty()1148                    && let hir::ExprKind::Block(..) = callee.peel_blocks().peel_drop_temps().kind1149                {1150                    return false;1151                }1152            }11531154            if is_closure_expr {1155                err.multipart_suggestions(1156                    msg,1157                    vec![vec![1158                        (span.shrink_to_lo(), "(".to_string()),1159                        (span.shrink_to_hi(), format!(")({args})")),1160                    ]],1161                    Applicability::HasPlaceholders,1162                );1163            } else {1164                err.span_suggestion_verbose(1165                    span.shrink_to_hi(),1166                    msg,1167                    format!("({args})"),1168                    Applicability::HasPlaceholders,1169                );1170            }1171        } else if let DefIdOrName::DefId(def_id) = def_id_or_name {1172            let name = match self.tcx.hir_get_if_local(def_id) {1173                Some(hir::Node::Expr(hir::Expr {1174                    kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),1175                    ..1176                })) => {1177                    err.span_label(*fn_decl_span, "consider calling this closure");1178                    let Some(name) = self.get_closure_name(def_id, err, msg.clone()) else {1179                        return false;1180                    };1181                    name.to_string()1182                }1183                Some(hir::Node::Item(hir::Item {1184                    kind: hir::ItemKind::Fn { ident, .. }, ..1185                })) => {1186                    err.span_label(ident.span, "consider calling this function");1187                    ident.to_string()1188                }1189                Some(hir::Node::Ctor(..)) => {1190                    let name = self.tcx.def_path_str(def_id);1191                    err.span_label(1192                        self.tcx.def_span(def_id),1193                        format!("consider calling the constructor for `{name}`"),1194                    );1195                    name1196                }1197                _ => return false,1198            };1199            err.help(format!("{msg}: `{name}({args})`"));1200        }1201        true1202    }12031204    pub(super) fn suggest_cast_to_fn_pointer(1205        &self,1206        obligation: &PredicateObligation<'tcx>,1207        err: &mut Diag<'_>,1208        leaf_trait_predicate: ty::PolyTraitPredicate<'tcx>,1209        main_trait_predicate: ty::PolyTraitPredicate<'tcx>,1210        span: Span,1211    ) -> bool {1212        let &[candidate] = &self.find_similar_impl_candidates(leaf_trait_predicate)[..] else {1213            return false;1214        };1215        let candidate = candidate.trait_ref;12161217        if !matches!(1218            (candidate.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind(),),1219            (ty::FnPtr(..), ty::FnDef(..))1220        ) {1221            return false;1222        }12231224        let parenthesized_cast = |span: Span| {1225            vec![1226                (span.shrink_to_lo(), "(".to_string()),1227                (span.shrink_to_hi(), format!(" as {})", candidate.self_ty())),1228            ]1229        };1230        // Wrap method receivers and `&`-references in parens.1231        let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() {1232            parenthesized_cast(span)1233        } else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) {1234            let mut expr_finder = FindExprBySpan::new(span, self.tcx);1235            expr_finder.visit_expr(body.value);1236            if let Some(expr) = expr_finder.result1237                && let hir::ExprKind::AddrOf(_, _, expr) = expr.kind1238            {1239                parenthesized_cast(expr.span)1240            } else {1241                vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]1242            }1243        } else {1244            vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]1245        };12461247        let trait_ = self.tcx.short_string(candidate.print_trait_sugared(), err.long_ty_path());1248        let self_ty = self.tcx.short_string(candidate.self_ty(), err.long_ty_path());1249        err.multipart_suggestion(1250            format!(1251                "the trait `{trait_}` is implemented for fn pointer \1252                 `{self_ty}`, try casting using `as`",1253            ),1254            suggestion,1255            Applicability::MaybeIncorrect,1256        );1257        true1258    }12591260    pub(super) fn check_for_binding_assigned_block_without_tail_expression(1261        &self,1262        obligation: &PredicateObligation<'tcx>,1263        err: &mut Diag<'_>,1264        trait_pred: ty::PolyTraitPredicate<'tcx>,1265    ) {1266        let mut span = obligation.cause.span;1267        while span.from_expansion() {1268            // Remove all the desugaring and macro contexts.1269            span.remove_mark();1270        }1271        let mut expr_finder = FindExprBySpan::new(span, self.tcx);1272        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {1273            return;1274        };1275        expr_finder.visit_expr(body.value);1276        let Some(expr) = expr_finder.result else {1277            return;1278        };1279        let Some(typeck) = &self.typeck_results else {1280            return;1281        };1282        let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else {1283            return;1284        };1285        if !ty.is_unit() {1286            return;1287        };1288        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {1289            return;1290        };1291        let Res::Local(hir_id) = path.res else {1292            return;1293        };1294        let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {1295            return;1296        };1297        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =1298            self.tcx.parent_hir_node(pat.hir_id)1299        else {1300            return;1301        };1302        let hir::ExprKind::Block(block, None) = init.kind else {1303            return;1304        };1305        if block.expr.is_some() {1306            return;1307        }1308        let [.., stmt] = block.stmts else {1309            err.span_label(block.span, "this empty block is missing a tail expression");1310            return;1311        };1312        // FIXME expr and stmt have the same span if expr comes from expansion1313        // cc: https://github.com/rust-lang/rust/pull/147416#discussion_r24994075231314        if stmt.span.from_expansion() {1315            return;1316        }1317        let hir::StmtKind::Semi(tail_expr) = stmt.kind else {1318            return;1319        };1320        let Some(ty) = typeck.expr_ty_opt(tail_expr) else {1321            err.span_label(block.span, "this block is missing a tail expression");1322            return;1323        };1324        let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty));1325        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty));13261327        let new_obligation =1328            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);1329        if !matches!(tail_expr.kind, hir::ExprKind::Err(_))1330            && self.predicate_must_hold_modulo_regions(&new_obligation)1331        {1332            err.span_suggestion_short(1333                stmt.span.with_lo(tail_expr.span.hi()),1334                "remove this semicolon",1335                "",1336                Applicability::MachineApplicable,1337            );1338        } else {1339            err.span_label(block.span, "this block is missing a tail expression");1340        }1341    }13421343    pub(super) fn suggest_add_clone_to_arg(1344        &self,1345        obligation: &PredicateObligation<'tcx>,1346        err: &mut Diag<'_>,1347        trait_pred: ty::PolyTraitPredicate<'tcx>,1348    ) -> bool {1349        let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());1350        self.enter_forall(self_ty, |ty: Ty<'_>| {1351            let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else {1352                return false;1353            };1354            let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };1355            let ty::Param(param) = inner_ty.kind() else { return false };1356            let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1357            else {1358                return false;1359            };13601361            let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span);1362            let has_clone = |ty| {1363                self.type_implements_trait(clone_trait, [ty], obligation.param_env)1364                    .must_apply_modulo_regions()1365            };13661367            let existing_clone_call = match self.tcx.hir_node(*arg_hir_id) {1368                // It's just a variable. Propose cloning it.1369                Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) => None,1370                // It's already a call to `clone()`. We might be able to suggest1371                // adding a `+ Clone` bound, though.1372                Node::Expr(Expr {1373                    kind:1374                        hir::ExprKind::MethodCall(1375                            hir::PathSegment { ident, .. },1376                            _receiver,1377                            [],1378                            call_span,1379                        ),1380                    hir_id,1381                    ..1382                }) if ident.name == sym::clone1383                    && !call_span.from_expansion()1384                    && !has_clone(*inner_ty) =>1385                {1386                    // We only care about method calls corresponding to the real `Clone` trait.1387                    let Some(typeck_results) = self.typeck_results.as_ref() else { return false };1388                    let Some((DefKind::AssocFn, did)) = typeck_results.type_dependent_def(*hir_id)1389                    else {1390                        return false;1391                    };1392                    if self.tcx.trait_of_assoc(did) != Some(clone_trait) {1393                        return false;1394                    }1395                    Some(ident.span)1396                }1397                _ => return false,1398            };13991400            let new_obligation = self.mk_trait_obligation_with_new_self_ty(1401                obligation.param_env,1402                trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),1403            );14041405            if self.predicate_may_hold(&new_obligation) && has_clone(ty) {1406                if !has_clone(param.to_ty(self.tcx)) {1407                    suggest_constraining_type_param(1408                        self.tcx,1409                        generics,1410                        err,1411                        param.name.as_str(),1412                        "Clone",1413                        Some(clone_trait),1414                        None,1415                    );1416                }1417                if let Some(existing_clone_call) = existing_clone_call {1418                    err.span_note(1419                        existing_clone_call,1420                        format!(1421                            "this `clone()` copies the reference, \1422                            which does not do anything, \1423                            because `{inner_ty}` does not implement `Clone`"1424                        ),1425                    );1426                } else {1427                    err.span_suggestion_verbose(1428                        obligation.cause.span.shrink_to_hi(),1429                        "consider using clone here",1430                        ".clone()".to_string(),1431                        Applicability::MaybeIncorrect,1432                    );1433                }1434                return true;1435            }1436            false1437        })1438    }14391440    /// Extracts information about a callable type for diagnostics. This is a1441    /// heuristic -- it doesn't necessarily mean that a type is always callable,1442    /// because the callable type must also be well-formed to be called.1443    pub fn extract_callable_info(1444        &self,1445        body_id: LocalDefId,1446        param_env: ty::ParamEnv<'tcx>,1447        found: Ty<'tcx>,1448    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {1449        // Autoderef is useful here because sometimes we box callables, etc.1450        let Some((def_id_or_name, output, inputs)) =1451            (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| match *found.kind() {1452                ty::FnPtr(sig_tys, _) => Some((1453                    DefIdOrName::Name("function pointer"),1454                    sig_tys.output(),1455                    sig_tys.inputs(),1456                )),1457                ty::FnDef(def_id, _) => {1458                    let fn_sig = found.fn_sig(self.tcx);1459                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))1460                }1461                ty::Closure(def_id, args) => {1462                    let fn_sig = args.as_closure().sig();1463                    Some((1464                        DefIdOrName::DefId(def_id),1465                        fn_sig.output(),1466                        fn_sig.inputs().map_bound(|inputs| inputs[0].tuple_fields().as_slice()),1467                    ))1468                }1469                ty::CoroutineClosure(def_id, args) => {1470                    let sig_parts = args.as_coroutine_closure().coroutine_closure_sig();1471                    Some((1472                        DefIdOrName::DefId(def_id),1473                        sig_parts.map_bound(|sig| {1474                            sig.to_coroutine(1475                                self.tcx,1476                                args.as_coroutine_closure().parent_args(),1477                                // Just use infer vars here, since we  don't really care1478                                // what these types are, just that we're returning a coroutine.1479                                self.next_ty_var(DUMMY_SP),1480                                self.tcx.coroutine_for_closure(def_id),1481                                self.next_ty_var(DUMMY_SP),1482                            )1483                        }),1484                        sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),1485                    ))1486                }1487                ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {1488                    self.tcx1489                        .item_self_bounds(def_id)1490                        .instantiate(self.tcx, args)1491                        .skip_norm_wip()1492                        .iter()1493                        .find_map(|pred| {1494                            if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()1495                            && self1496                                .tcx1497                                .is_lang_item(proj.def_id(), LangItem::FnOnceOutput)1498                            // args tuple will always be args[1]1499                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()1500                            {1501                                Some((1502                                    DefIdOrName::DefId(def_id),1503                                    pred.kind().rebind(proj.term.expect_type()),1504                                    pred.kind().rebind(args.as_slice()),1505                                ))1506                            } else {1507                                None1508                            }1509                        })1510                }1511                ty::Dynamic(data, _) => data.iter().find_map(|pred| {1512                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()1513                        && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)1514                        // for existential projection, args are shifted over by 11515                        && let ty::Tuple(args) = proj.args.type_at(0).kind()1516                    {1517                        Some((1518                            DefIdOrName::Name("trait object"),1519                            pred.rebind(proj.term.expect_type()),1520                            pred.rebind(args.as_slice()),1521                        ))1522                    } else {1523                        None1524                    }1525                }),1526                ty::Param(param) => {1527                    let generics = self.tcx.generics_of(body_id);1528                    let name = if generics.count() > param.index as usize1529                        && let def = generics.param_at(param.index as usize, self.tcx)1530                        && matches!(def.kind, ty::GenericParamDefKind::Type { .. })1531                        && def.name == param.name1532                    {1533                        DefIdOrName::DefId(def.def_id)1534                    } else {1535                        DefIdOrName::Name("type parameter")1536                    };1537                    param_env.caller_bounds().iter().find_map(|pred| {1538                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()1539                            && self1540                                .tcx1541                                .is_lang_item(proj.def_id(), LangItem::FnOnceOutput)1542                            && proj.projection_term.self_ty() == found1543                            // args tuple will always be args[1]1544                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()1545                        {1546                            Some((1547                                name,1548                                pred.kind().rebind(proj.term.expect_type()),1549                                pred.kind().rebind(args.as_slice()),1550                            ))1551                        } else {1552                            None1553                        }1554                    })1555                }1556                _ => None,1557            })1558        else {1559            return None;1560        };15611562        let output = self.instantiate_binder_with_fresh_vars(1563            DUMMY_SP,1564            BoundRegionConversionTime::FnCall,1565            output,1566        );1567        let inputs = inputs1568            .skip_binder()1569            .iter()1570            .map(|ty| {1571                self.instantiate_binder_with_fresh_vars(1572                    DUMMY_SP,1573                    BoundRegionConversionTime::FnCall,1574                    inputs.rebind(*ty),1575                )1576            })1577            .collect();15781579        // We don't want to register any extra obligations, which should be1580        // implied by wf, but also because that would possibly result in1581        // erroneous errors later on.1582        let InferOk { value: output, obligations: _ } =1583            self.at(&ObligationCause::dummy(), param_env).normalize(Unnormalized::new_wip(output));15841585        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }1586    }15871588    pub(super) fn where_clause_expr_matches_failed_self_ty(1589        &self,1590        obligation: &PredicateObligation<'tcx>,1591        old_self_ty: Ty<'tcx>,1592    ) -> bool {1593        let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() else {1594            return true;1595        };1596        let (Some(typeck_results), Some(body)) = (1597            self.typeck_results.as_ref(),1598            self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id),1599        ) else {1600            return true;1601        };16021603        let mut expr_finder = FindExprBySpan::new(obligation.cause.span, self.tcx);1604        expr_finder.visit_expr(body.value);1605        let Some(expr) = expr_finder.result else {1606            return true;1607        };16081609        let inner_old_self_ty = match old_self_ty.kind() {1610            ty::Ref(_, inner_ty, _) => Some(*inner_ty),1611            _ => None,1612        };16131614        [typeck_results.expr_ty_adjusted_opt(expr)].into_iter().flatten().any(|expr_ty| {1615            self.can_eq(obligation.param_env, expr_ty, old_self_ty)1616                || inner_old_self_ty1617                    .is_some_and(|inner_ty| self.can_eq(obligation.param_env, expr_ty, inner_ty))1618        })1619    }16201621    pub(super) fn suggest_add_reference_to_arg(1622        &self,1623        obligation: &PredicateObligation<'tcx>,1624        err: &mut Diag<'_>,1625        poly_trait_pred: ty::PolyTraitPredicate<'tcx>,1626        has_custom_message: bool,1627    ) -> bool {1628        let span = obligation.cause.span;1629        let param_env = obligation.param_env;16301631        let mk_result = |trait_pred_and_new_ty| {1632            let obligation =1633                self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);1634            self.predicate_must_hold_modulo_regions(&obligation)1635        };16361637        let code = match obligation.cause.code() {1638            ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code,1639            // FIXME(compiler-errors): This is kind of a mess, but required for obligations1640            // that come from a path expr to affect the *call* expr.1641            c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _)1642                if self.tcx.hir_span(*hir_id).lo() == span.lo() =>1643            {1644                // `hir_id` corresponds to the HIR node that introduced a `where`-clause obligation.1645                // If that obligation comes from a type in an associated method call, we need1646                // special handling here.1647                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(*hir_id)1648                    && let hir::ExprKind::Call(base, _) = expr.kind1649                    && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, segment)) = base.kind1650                    && let hir::Node::Expr(outer) = self.tcx.parent_hir_node(expr.hir_id)1651                    && let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mtbl, _) = outer.kind1652                    && ty.span == span1653                {1654                    // We've encountered something like `&str::from("")`, where the intended code1655                    // was likely `<&str>::from("")`. The former is interpreted as "call method1656                    // `from` on `str` and borrow the result", while the latter means "call method1657                    // `from` on `&str`".16581659                    let trait_pred_and_imm_ref = poly_trait_pred.map_bound(|p| {1660                        (p, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))1661                    });1662                    let trait_pred_and_mut_ref = poly_trait_pred.map_bound(|p| {1663                        (p, Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))1664                    });16651666                    let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);1667                    let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);1668                    let sugg_msg = |pre: &str| {1669                        format!(1670                            "you likely meant to call the associated function `{FN}` for type \1671                             `&{pre}{TY}`, but the code as written calls associated function `{FN}` on \1672                             type `{TY}`",1673                            FN = segment.ident,1674                            TY = poly_trait_pred.self_ty(),1675                        )1676                    };1677                    match (imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl) {1678                        (true, _, hir::Mutability::Not) | (_, true, hir::Mutability::Mut) => {1679                            err.multipart_suggestion(1680                                sugg_msg(mtbl.prefix_str()),1681                                vec![1682                                    (outer.span.shrink_to_lo(), "<".to_string()),1683                                    (span.shrink_to_hi(), ">".to_string()),1684                                ],1685                                Applicability::MachineApplicable,1686                            );1687                        }1688                        (true, _, hir::Mutability::Mut) => {1689                            // There's an associated function found on the immutable borrow of the1690                            err.multipart_suggestion(1691                                sugg_msg("mut "),1692                                vec![1693                                    (outer.span.shrink_to_lo().until(span), "<&".to_string()),1694                                    (span.shrink_to_hi(), ">".to_string()),1695                                ],1696                                Applicability::MachineApplicable,1697                            );1698                        }1699                        (_, true, hir::Mutability::Not) => {1700                            err.multipart_suggestion(1701                                sugg_msg(""),1702                                vec![1703                                    (outer.span.shrink_to_lo().until(span), "<&mut ".to_string()),1704                                    (span.shrink_to_hi(), ">".to_string()),1705                                ],1706                                Applicability::MachineApplicable,1707                            );1708                        }1709                        _ => {}1710                    }1711                    // If we didn't return early here, we would instead suggest `&&str::from("")`.1712                    return false;1713                }1714                c1715            }1716            c if matches!(1717                span.ctxt().outer_expn_data().kind,1718                ExpnKind::Desugaring(DesugaringKind::ForLoop)1719            ) =>1720            {1721                c1722            }1723            _ => return false,1724        };17251726        // List of traits for which it would be nonsensical to suggest borrowing.1727        // For instance, immutable references are always Copy, so suggesting to1728        // borrow would always succeed, but it's probably not what the user wanted.1729        let mut never_suggest_borrow: Vec<_> =1730            [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized]1731                .iter()1732                .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item))1733                .collect();17341735        if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {1736            never_suggest_borrow.push(def_id);1737        }17381739        // Try to apply the original trait bound by borrowing.1740        let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,1741                                 blacklist: &[DefId]|1742         -> bool {1743            if blacklist.contains(&old_pred.def_id()) {1744                return false;1745            }1746            // We map bounds to `&T` and `&mut T`1747            let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {1748                (1749                    trait_pred,1750                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),1751                )1752            });1753            let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {1754                (1755                    trait_pred,1756                    Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),1757                )1758            });17591760            let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);1761            let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);17621763            let (ref_inner_ty_satisfies_pred, ref_inner_ty_is_mut) =1764                if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code()1765                    && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()1766                {1767                    (1768                        mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),1769                        mutability.is_mut(),1770                    )1771                } else {1772                    (false, false)1773                };17741775            let is_immut = imm_ref_self_ty_satisfies_pred1776                || (ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut);1777            let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut;1778            if !is_immut && !is_mut {1779                return false;1780            }1781            let Ok(_snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {1782                return false;1783            };1784            // We don't want a borrowing suggestion on the fields in structs1785            // ```1786            // #[derive(Clone)]1787            // struct Foo {1788            //     the_foos: Vec<Foo>1789            // }1790            // ```1791            if !matches!(1792                span.ctxt().outer_expn_data().kind,1793                ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)1794            ) {1795                return false;1796            }1797            // We have a very specific type of error, where just borrowing this argument1798            // might solve the problem. In cases like this, the important part is the1799            // original type obligation, not the last one that failed, which is arbitrary.1800            // Because of this, we modify the error to refer to the original obligation and1801            // return early in the caller.18021803            let mut label = || {1804                // Special case `Sized` as `old_pred` will be the trait itself instead of1805                // `Sized` when the trait bound is the source of the error.1806                let is_sized = match obligation.predicate.kind().skip_binder() {1807                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {1808                        self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized)1809                    }1810                    _ => false,1811                };18121813                let msg = format!(1814                    "the trait bound `{}` is not satisfied",1815                    self.tcx.short_string(old_pred, err.long_ty_path()),1816                );1817                let self_ty_str = self.tcx.short_string(old_pred.self_ty(), err.long_ty_path());1818                let trait_path = self1819                    .tcx1820                    .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path());18211822                if has_custom_message {1823                    let msg = if is_sized {1824                        "the trait bound `Sized` is not satisfied".into()1825                    } else {1826                        msg1827                    };1828                    err.note(msg);1829                } else {1830                    err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];1831                }1832                if is_sized {1833                    err.span_label(1834                        span,1835                        format!("the trait `Sized` is not implemented for `{self_ty_str}`"),1836                    );1837                } else {1838                    err.span_label(1839                        span,1840                        format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"),1841                    );1842                }1843            };18441845            let mut sugg_prefixes = vec![];1846            if is_immut {1847                sugg_prefixes.push("&");1848            }1849            if is_mut {1850                sugg_prefixes.push("&mut ");1851            }1852            let sugg_msg = format!(1853                "consider{} borrowing here",1854                if is_mut && !is_immut { " mutably" } else { "" },1855            );18561857            // Issue #104961, we need to add parentheses properly for compound expressions1858            // for example, `x.starts_with("hi".to_string() + "you")`1859            // should be `x.starts_with(&("hi".to_string() + "you"))`1860            let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {1861                return false;1862            };1863            let mut expr_finder = FindExprBySpan::new(span, self.tcx);1864            expr_finder.visit_expr(body.value);18651866            if let Some(ty) = expr_finder.ty_result {1867                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(ty.hir_id)1868                    && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, _)) = expr.kind1869                    && ty.span == span1870                {1871                    // We've encountered something like `str::from("")`, where the intended code1872                    // was likely `<&str>::from("")`. #143393.1873                    label();1874                    err.multipart_suggestions(1875                        sugg_msg,1876                        sugg_prefixes.into_iter().map(|sugg_prefix| {1877                            vec![1878                                (span.shrink_to_lo(), format!("<{sugg_prefix}")),1879                                (span.shrink_to_hi(), ">".to_string()),1880                            ]1881                        }),1882                        Applicability::MaybeIncorrect,1883                    );1884                    return true;1885                }1886                return false;1887            }1888            let Some(expr) = expr_finder.result else {1889                return false;1890            };1891            if let hir::ExprKind::AddrOf(_, _, _) = expr.kind {1892                return false;1893            }1894            let old_self_ty = old_pred.skip_binder().self_ty();1895            if !old_self_ty.has_escaping_bound_vars()1896                && !self.where_clause_expr_matches_failed_self_ty(1897                    obligation,1898                    self.tcx.instantiate_bound_regions_with_erased(old_pred.self_ty()),1899                )1900            {1901                return false;1902            }1903            let needs_parens_post = expr_needs_parens(expr);1904            let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) {1905                Node::Expr(e)1906                    if let hir::ExprKind::MethodCall(_, base, _, _) = e.kind1907                        && base.hir_id == expr.hir_id =>1908                {1909                    true1910                }1911                _ => false,1912            };19131914            label();1915            let suggestions = sugg_prefixes.into_iter().map(|sugg_prefix| {1916                match (needs_parens_pre, needs_parens_post) {1917                    (false, false) => vec![(span.shrink_to_lo(), sugg_prefix.to_string())],1918                    // We have something like `foo.bar()`, where we want to bororw foo, so we need1919                    // to suggest `(&mut foo).bar()`.1920                    (false, true) => vec![1921                        (span.shrink_to_lo(), format!("{sugg_prefix}(")),1922                        (span.shrink_to_hi(), ")".to_string()),1923                    ],1924                    // Issue #109436, we need to add parentheses properly for method calls1925                    // for example, `foo.into()` should be `(&foo).into()`1926                    (true, false) => vec![1927                        (span.shrink_to_lo(), format!("({sugg_prefix}")),1928                        (span.shrink_to_hi(), ")".to_string()),1929                    ],1930                    (true, true) => vec![1931                        (span.shrink_to_lo(), format!("({sugg_prefix}(")),1932                        (span.shrink_to_hi(), "))".to_string()),1933                    ],1934                }1935            });1936            err.multipart_suggestions(sugg_msg, suggestions, Applicability::MaybeIncorrect);1937            return true;1938        };19391940        if let ObligationCauseCode::ImplDerived(cause) = &*code {1941            try_borrowing(cause.derived.parent_trait_pred, &[])1942        } else if let ObligationCauseCode::WhereClause(..)1943        | ObligationCauseCode::WhereClauseInExpr(..) = code1944        {1945            try_borrowing(poly_trait_pred, &never_suggest_borrow)1946        } else {1947            false1948        }1949    }19501951    // Suggest borrowing the type1952    pub(super) fn suggest_borrowing_for_object_cast(1953        &self,1954        err: &mut Diag<'_>,1955        obligation: &PredicateObligation<'tcx>,1956        self_ty: Ty<'tcx>,1957        target_ty: Ty<'tcx>,1958    ) {1959        let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else {1960            return;1961        };1962        let ty::Dynamic(predicates, _) = object_ty.kind() else {1963            return;1964        };1965        let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty);19661967        for predicate in predicates.iter() {1968            if !self.predicate_must_hold_modulo_regions(1969                &obligation.with(self.tcx, predicate.with_self_ty(self.tcx, self_ref_ty)),1970            ) {1971                return;1972            }1973        }19741975        err.span_suggestion_verbose(1976            obligation.cause.span.shrink_to_lo(),1977            format!(1978                "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`"1979            ),1980            "&",1981            Applicability::MaybeIncorrect,1982        );1983    }19841985    /// Peel `&`-borrows from an expression, following through untyped let-bindings.1986    /// Returns a list of removable `&` layers (each with the span to remove and the1987    /// resulting type), plus an optional terminal [`hir::Param`] when the chain ends1988    /// at a function parameter (including async-fn desugared parameters).1989    fn peel_expr_refs(1990        &self,1991        mut expr: &'tcx hir::Expr<'tcx>,1992        mut ty: Ty<'tcx>,1993    ) -> (Vec<PeeledRef<'tcx>>, Option<&'tcx hir::Param<'tcx>>) {1994        let mut refs = Vec::new();1995        'outer: loop {1996            while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {1997                let span =1998                    if let Some(borrowed_span) = borrowed.span.find_ancestor_inside(expr.span) {1999                        expr.span.until(borrowed_span)2000                    } else {

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.