compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs RUST 7,388 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 7,388.
1// ignore-tidy-file-filelength23use std::borrow::Cow;4use std::path::PathBuf;5use std::{debug_assert_matches, iter};67use itertools::{EitherOrBoth, Itertools};8use rustc_abi::ExternAbi;9use rustc_attr_ir::lang_items::{self, LangItem};10use rustc_data_structures::fx::FxHashSet;11use rustc_errors::codes::*;12use rustc_errors::{13    Applicability, Diag, MultiSpan, Style, SuggestionStyle, pluralize, struct_span_code_err,14};15use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};16use rustc_hir::def_id::DefId;17use rustc_hir::intravisit::Visitor;18use rustc_hir::{19    self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node,20    expr_needs_parens,21};22use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk};23use rustc_infer::traits::ImplSource;24use rustc_middle::middle::privacy::Level;25use rustc_middle::traits::IsConstable;26use rustc_middle::ty::adjustment::{Adjust, DerefAdjustKind};27use rustc_middle::ty::error::TypeError;28use rustc_middle::ty::print::{29    PrintPolyTraitClauseExt as _, PrintPolyTraitRefExt, PrintTraitClauseExt as _,30    PrintTraitRefExt as _, with_forced_trimmed_paths, with_no_trimmed_paths,31    with_types_for_suggestion,32};33use rustc_middle::ty::{34    self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder,35    TypeSuperFoldable, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, TypeckResults,36    Unnormalized, Upcast, suggest_arbitrary_trait_bound, suggest_constraining_type_param,37};38use rustc_span::def_id::LocalDefId;39use rustc_span::{40    BytePos, DUMMY_SP, DesugaringKind, ExpnKind, Ident, MacroKind, Span, Symbol, bug, kw, span_bug,41    sym,42};43use tracing::{debug, instrument};4445use super::{46    DefIdOrName, FindExprBySpan, ImplCandidate, Obligation, ObligationCause, ObligationCauseCode,47    PredicateObligation,48};49use crate::diagnostics;50use crate::error_reporting::TypeErrCtxt;51use crate::infer::InferCtxtExt as _;52use crate::traits::query::evaluate_obligation::InferCtxtExt as _;53use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt, SelectionContext};5455#[derive(Debug)]56pub enum CoroutineInteriorOrUpvar {57    // span of interior type58    Interior(Span, Option<(Span, Option<Span>)>),59    // span of upvar60    Upvar(Span),61}6263// This type provides a uniform interface to retrieve data on coroutines, whether it originated from64// the local crate being compiled or from a foreign crate.65#[derive(Debug)]66struct CoroutineData<'a, 'tcx>(&'a TypeckResults<'tcx>);6768impl<'a, 'tcx> CoroutineData<'a, 'tcx> {69    /// Try to get information about variables captured by the coroutine that matches a type we are70    /// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to71    /// meet an obligation72    fn try_get_upvar_span<F>(73        &self,74        infer_context: &InferCtxt<'tcx>,75        coroutine_did: DefId,76        ty_matches: F,77    ) -> Option<CoroutineInteriorOrUpvar>78    where79        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,80    {81        infer_context.tcx.upvars_mentioned(coroutine_did).and_then(|upvars| {82            upvars.iter().find_map(|(upvar_id, upvar)| {83                let upvar_ty = self.0.node_type(*upvar_id);84                let upvar_ty = infer_context.deeply_resolve_ignoring_regions(upvar_ty);85                ty_matches(ty::Binder::dummy(upvar_ty))86                    .then(|| CoroutineInteriorOrUpvar::Upvar(upvar.span))87            })88        })89    }9091    /// Try to get the span of a type being awaited on that matches the type we are looking with the92    /// `ty_matches` function. We uses it to find awaited type which causes a failure to meet an93    /// obligation94    fn get_from_await_ty<F>(95        &self,96        visitor: AwaitsVisitor,97        tcx: TyCtxt<'tcx>,98        ty_matches: F,99    ) -> Option<Span>100    where101        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,102    {103        visitor104            .awaits105            .into_iter()106            .map(|id| tcx.hir_expect_expr(id))107            .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(await_expr))))108            .map(|expr| expr.span)109    }110}111112fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {113    (114        generics.tail_span_for_predicate_suggestion(),115        with_types_for_suggestion!(format!("{} {}", generics.add_where_or_trailing_comma(), pred)),116    )117}118119/// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but120/// it can also be an `impl Trait` param that needs to be decomposed to a type121/// param for cleaner code.122pub fn suggest_restriction<'tcx>(123    tcx: TyCtxt<'tcx>,124    item_id: LocalDefId,125    hir_generics: &hir::Generics<'tcx>,126    msg: &str,127    err: &mut Diag<'_>,128    fn_sig: Option<&hir::FnSig<'_>>,129    projection: Option<ty::ProjectionAliasTy<'_>>,130    trait_pred: ty::PolyTraitClause<'tcx>,131    // When we are dealing with a trait, `super_traits` will be `Some`:132    // Given `trait T: A + B + C {}`133    //              -  ^^^^^^^^^ GenericBounds134    //              |135    //              &Ident136    super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,137) {138    if hir_generics.where_clause_span.from_expansion()139        || hir_generics.where_clause_span.desugaring_kind().is_some()140        || projection.is_some_and(|projection| {141            (tcx.is_impl_trait_in_trait(projection.kind) && !tcx.features().return_type_notation())142                || tcx.lookup_stability(projection.kind).is_some_and(|stab| stab.is_unstable())143        })144    {145        return;146    }147    let generics = tcx.generics_of(item_id);148    // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...149    if let Some((param, bound_str, fn_sig)) =150        fn_sig.zip(projection).and_then(|(sig, p)| match *p.projection_self_ty().kind() {151            // Shenanigans to get the `Trait` from the `impl Trait`.152            ty::Param(param) => {153                let param_def = generics.type_param(param, tcx);154                if param_def.kind.is_synthetic() {155                    let bound_str =156                        param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string();157                    return Some((param_def, bound_str, sig));158                }159                None160            }161            _ => None,162        })163    {164        let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str));165        let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder {166            tcx,167            param,168            replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))169                .to_ty(tcx),170        });171        if !trait_pred.is_suggestable(tcx, false) {172            return;173        }174        // We know we have an `impl Trait` that doesn't satisfy a required projection.175176        // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'177        // types. There should be at least one, but there might be *more* than one. In that178        // case we could just ignore it and try to identify which one needs the restriction,179        // but instead we choose to suggest replacing all instances of `impl Trait` with `T`180        // where `T: Trait`.181        let mut ty_spans = vec![];182        for input in fn_sig.decl.inputs {183            ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }184                .visit_ty_unambig(input);185        }186        // The type param `T: Trait` we will suggest to introduce.187        let type_param = format!("{type_param_name}: {bound_str}");188189        let mut sugg = vec![190            if let Some(span) = hir_generics.span_for_param_suggestion() {191                (span, format!(", {type_param}"))192            } else {193                (hir_generics.span, format!("<{type_param}>"))194            },195            // `fn foo(t: impl Trait)`196            //                       ^ suggest `where <T as Trait>::A: Bound`197            predicate_constraint(hir_generics, trait_pred.upcast(tcx)),198        ];199        sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));200201        // Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.202        // FIXME: we should suggest `fn foo(t: impl Trait<A: Bound>)` instead.203        err.multipart_suggestion(204            "introduce a type parameter with a trait bound instead of using `impl Trait`",205            sugg,206            Applicability::MaybeIncorrect,207        );208    } else {209        if !trait_pred.is_suggestable(tcx, false) {210            return;211        }212        // Trivial case: `T` needs an extra bound: `T: Bound`.213        let (sp, suggestion) = match (214            hir_generics215                .params216                .iter()217                .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),218            super_traits,219        ) {220            (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),221            (None, Some((ident, []))) => (222                ident.span.shrink_to_hi(),223                format!(": {}", trait_pred.print_modifiers_and_trait_path()),224            ),225            (_, Some((_, [.., bounds]))) => (226                bounds.span().shrink_to_hi(),227                format!(" + {}", trait_pred.print_modifiers_and_trait_path()),228            ),229            (Some(_), Some((_, []))) => (230                hir_generics.span.shrink_to_hi(),231                format!(": {}", trait_pred.print_modifiers_and_trait_path()),232            ),233        };234235        err.span_suggestion_verbose(236            sp,237            format!("consider further restricting {msg}"),238            suggestion,239            Applicability::MachineApplicable,240        );241    }242}243244/// A single layer of `&` peeled from an expression, used by245/// [`TypeErrCtxt::peel_expr_refs`].246struct PeeledRef<'tcx> {247    /// The span covering the `&` (and any whitespace/mutability keyword) to remove.248    span: Span,249    /// The type after peeling this layer (and all prior layers).250    peeled_ty: Ty<'tcx>,251}252253impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {254    pub fn note_field_shadowed_by_private_candidate_in_cause(255        &self,256        err: &mut Diag<'_>,257        cause: &ObligationCause<'tcx>,258        param_env: ty::ParamEnv<'tcx>,259    ) {260        let mut hir_ids = FxHashSet::default();261        // Walk the parent chain so we can recover262        // the source expression from whichever layer carries them.263        let mut next_code = Some(cause.code());264        while let Some(cause_code) = next_code {265            match cause_code {266                ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. } => {267                    hir_ids.insert(*lhs_hir_id);268                    hir_ids.insert(*rhs_hir_id);269                }270                ObligationCauseCode::FunctionArg { arg_hir_id, .. }271                | ObligationCauseCode::ReturnValue(arg_hir_id)272                | ObligationCauseCode::AwaitableExpr(arg_hir_id)273                | ObligationCauseCode::BlockTailExpression(arg_hir_id, _)274                | ObligationCauseCode::UnOp { hir_id: arg_hir_id } => {275                    hir_ids.insert(*arg_hir_id);276                }277                ObligationCauseCode::OpaqueReturnType(Some((_, hir_id))) => {278                    hir_ids.insert(*hir_id);279                }280                _ => {}281            }282            next_code = cause_code.parent();283        }284285        if !cause.span.is_dummy()286            && let Some(body) = self.tcx.hir_maybe_body_owned_by(cause.body_def_id)287        {288            let mut expr_finder = FindExprBySpan::new(cause.span, self.tcx);289            expr_finder.visit_body(body);290            if let Some(expr) = expr_finder.result {291                hir_ids.insert(expr.hir_id);292            }293        }294295        // we will sort immediately by source order before emitting any diagnostics296        #[allow(rustc::potential_query_instability)]297        let mut hir_ids: Vec<_> = hir_ids.into_iter().collect();298        let source_map = self.tcx.sess.source_map();299        hir_ids.sort_by_cached_key(|hir_id| {300            let span = self.tcx.hir_span(*hir_id);301            let lo = source_map.lookup_byte_offset(span.lo());302            let hi = source_map.lookup_byte_offset(span.hi());303            (lo.sf.name.prefer_remapped_unconditionally().to_string(), lo.pos.0, hi.pos.0)304        });305306        for hir_id in hir_ids {307            self.note_field_shadowed_by_private_candidate(err, hir_id, param_env);308        }309    }310311    pub fn note_field_shadowed_by_private_candidate(312        &self,313        err: &mut Diag<'_>,314        hir_id: hir::HirId,315        param_env: ty::ParamEnv<'tcx>,316    ) {317        let Some(typeck_results) = &self.typeck_results else {318            return;319        };320        let Node::Expr(expr) = self.tcx.hir_node(hir_id) else {321            return;322        };323        let hir::ExprKind::Field(base_expr, field_ident) = expr.kind else {324            return;325        };326327        let Some(base_ty) = typeck_results.expr_ty_opt(base_expr) else {328            return;329        };330        let base_ty = self.deeply_resolve_ignoring_regions(base_ty);331        if base_ty.references_error() {332            return;333        }334335        let mut private_candidate: Option<(Ty<'tcx>, Ty<'tcx>, Span)> = None;336337        for (deref_base_ty, _) in (self.autoderef_steps)(base_ty) {338            let ty::Adt(base_def, args) = deref_base_ty.kind() else {339                continue;340            };341342            if base_def.is_enum() {343                continue;344            }345346            let (adjusted_ident, def_scope) = self.tcx.adjust_ident_and_get_scope(347                field_ident,348                base_def.did(),349                self.tcx.parent_module_from_def_id(typeck_results.hir_owner.def_id),350            );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::PolyTraitClause<'tcx>,467        associated_ty: Option<(&'static str, Ty<'tcx>)>,468        mut body_def_id: LocalDefId,469    ) {470        if trait_pred.skip_binder().polarity != ty::ClausePolarity::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_def_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_def_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,526                        body_def_id,527                        generics,528                        "`Self`",529                        err,530                        None,531                        projection,532                        trait_pred,533                        None,534                    );535                    return;536                }537538                hir::Node::TraitItem(hir::TraitItem {539                    generics,540                    kind: hir::TraitItemKind::Fn(fn_sig, ..),541                    ..542                })543                | hir::Node::ImplItem(hir::ImplItem {544                    generics,545                    kind: hir::ImplItemKind::Fn(fn_sig, ..),546                    ..547                })548                | hir::Node::Item(hir::Item {549                    kind: hir::ItemKind::Fn { sig: fn_sig, generics, .. },550                    ..551                }) if projection.is_some() => {552                    // Missing restriction on associated type of type parameter (unmet projection).553                    suggest_restriction(554                        self.tcx,555                        body_def_id,556                        generics,557                        "the associated type",558                        err,559                        Some(fn_sig),560                        projection,561                        trait_pred,562                        None,563                    );564                    return;565                }566                hir::Node::Item(hir::Item {567                    kind:568                        hir::ItemKind::Trait { generics, .. }569                        | hir::ItemKind::Impl(hir::Impl { generics, .. }),570                    ..571                }) if projection.is_some() => {572                    // Missing restriction on associated type of type parameter (unmet projection).573                    suggest_restriction(574                        self.tcx,575                        body_def_id,576                        generics,577                        "the associated type",578                        err,579                        None,580                        projection,581                        trait_pred,582                        None,583                    );584                    return;585                }586587                hir::Node::Item(hir::Item {588                    kind:589                        hir::ItemKind::Struct(_, generics, _)590                        | hir::ItemKind::Enum(_, generics, _)591                        | hir::ItemKind::Union(_, generics, _)592                        | hir::ItemKind::Trait { generics, .. }593                        | hir::ItemKind::Impl(hir::Impl { generics, .. })594                        | hir::ItemKind::Fn { generics, .. }595                        | hir::ItemKind::TyAlias(_, generics, _)596                        | hir::ItemKind::Const(_, generics, _, _)597                        | hir::ItemKind::TraitAlias(_, _, generics, _),598                    ..599                })600                | hir::Node::TraitItem(hir::TraitItem { generics, .. })601                | hir::Node::ImplItem(hir::ImplItem { generics, .. })602                    if param_ty =>603                {604                    // We skip the 0'th arg (self) because we do not want605                    // to consider the predicate as not suggestible if the606                    // self type is an arg position `impl Trait` -- instead,607                    // we handle that by adding ` + Bound` below.608                    // FIXME(compiler-errors): It would be nice to do the same609                    // this that we do in `suggest_restriction` and pull the610                    // `impl Trait` into a new generic if it shows up somewhere611                    // else in the predicate.612                    if !trait_pred.skip_binder().trait_ref.args[1..]613                        .iter()614                        .all(|g| g.is_suggestable(self.tcx, false))615                    {616                        return;617                    }618                    // Missing generic type parameter bound.619                    let param_name = self_ty.to_string();620                    let mut constraint = with_no_trimmed_paths!(621                        trait_pred.print_modifiers_and_trait_path().to_string()622                    );623624                    if let Some((name, term)) = associated_ty {625                        // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.626                        // That should be extracted into a helper function.627                        if let Some(stripped) = constraint.strip_suffix('>') {628                            constraint = format!("{stripped}, {name} = {term}>");629                        } else {630                            constraint.push_str(&format!("<{name} = {term}>"));631                        }632                    }633634                    if suggest_constraining_type_param(635                        self.tcx,636                        generics,637                        err,638                        &param_name,639                        &constraint,640                        Some(trait_pred.def_id()),641                        None,642                    ) {643                        return;644                    }645                }646647                hir::Node::TraitItem(hir::TraitItem {648                    generics,649                    kind: hir::TraitItemKind::Fn(..),650                    ..651                })652                | hir::Node::ImplItem(hir::ImplItem {653                    generics,654                    impl_kind: hir::ImplItemImplKind::Inherent { .. },655                    kind: hir::ImplItemKind::Fn(..),656                    ..657                }) if finder.can_suggest_bound(generics) => {658                    // Missing generic type parameter bound.659                    suggest_arbitrary_trait_bound(660                        self.tcx,661                        generics,662                        err,663                        trait_pred,664                        associated_ty,665                    );666                }667                hir::Node::Item(hir::Item {668                    kind:669                        hir::ItemKind::Struct(_, generics, _)670                        | hir::ItemKind::Enum(_, generics, _)671                        | hir::ItemKind::Union(_, generics, _)672                        | hir::ItemKind::Trait { generics, .. }673                        | hir::ItemKind::Impl(hir::Impl { generics, .. })674                        | hir::ItemKind::Fn { generics, .. }675                        | hir::ItemKind::TyAlias(_, generics, _)676                        | hir::ItemKind::Const(_, generics, _, _)677                        | hir::ItemKind::TraitAlias(_, _, generics, _),678                    ..679                }) if finder.can_suggest_bound(generics) => {680                    // Missing generic type parameter bound.681                    if suggest_arbitrary_trait_bound(682                        self.tcx,683                        generics,684                        err,685                        trait_pred,686                        associated_ty,687                    ) {688                        return;689                    }690                }691                hir::Node::Crate(..) => return,692693                _ => {}694            }695            body_def_id = self.tcx.local_parent(body_def_id);696        }697    }698699    /// Provide a suggestion to dereference arguments to functions and binary operators, if that700    /// would satisfy trait bounds.701    pub(super) fn suggest_dereferences(702        &self,703        obligation: &PredicateObligation<'tcx>,704        err: &mut Diag<'_>,705        trait_pred: ty::PolyTraitClause<'tcx>,706    ) -> bool {707        let mut code = obligation.cause.code();708        if let ObligationCauseCode::FunctionArg { arg_hir_id, call_hir_id, .. } = code709            && let Some(typeck_results) = &self.typeck_results710            && let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id)711            && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)712        {713            // Suggest dereferencing the argument to a function/method call if possible714715            // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)716            let mut real_trait_pred = trait_pred;717            while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {718                code = parent_code;719                if let Some(parent_trait_pred) = parent_trait_pred {720                    real_trait_pred = parent_trait_pred;721                }722            }723724            // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle725            // `ReBound`, and we don't particularly care about the regions.726            let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty());727            if !self.can_eq(obligation.param_env, real_ty, arg_ty) {728                return false;729            }730731            // Potentially, we'll want to place our dereferences under a `&`. We don't try this for732            // `&mut`, since we can't be sure users will get the side-effects they want from it.733            // If this doesn't work, we'll try removing the `&` in `suggest_remove_reference`.734            // FIXME(dianne): this misses the case where users need both to deref and remove `&`s.735            // This method could be combined with `TypeErrCtxt::suggest_remove_reference` to handle736            // that, similar to what `FnCtxt::suggest_deref_or_ref` does.737            let (is_under_ref, base_ty, span) = match expr.kind {738                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, subexpr)739                    if let &ty::Ref(region, base_ty, hir::Mutability::Not) = real_ty.kind() =>740                {741                    (Some(region), base_ty, subexpr.span)742                }743                // Don't suggest `*&mut`, etc.744                hir::ExprKind::AddrOf(..) => return false,745                _ => (None, real_ty, obligation.cause.span),746            };747748            let autoderef = (self.autoderef_steps)(base_ty);749            let mut is_boxed = base_ty.is_box();750            if let Some(steps) = autoderef.into_iter().position(|(mut ty, obligations)| {751                // Ensure one of the following for dereferencing to be valid: we're passing by752                // reference, `ty` is `Copy`, or we're moving out of a (potentially nested) `Box`.753                let can_deref = is_under_ref.is_some()754                    || self.type_is_copy_modulo_regions(obligation.param_env, ty)755                    || ty.is_numeric() // for inference vars (presumably but not provably `Copy`)756                    || is_boxed && self.type_is_sized_modulo_regions(obligation.param_env, ty);757                is_boxed &= ty.is_box();758759                // Re-add the `&` if necessary760                if let Some(region) = is_under_ref {761                    ty = Ty::new_ref(self.tcx, region, ty, hir::Mutability::Not);762                }763764                // Remapping bound vars here765                let real_trait_pred_and_ty =766                    real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));767                let obligation = self.mk_trait_obligation_with_new_self_ty(768                    obligation.param_env,769                    real_trait_pred_and_ty,770                );771772                can_deref773                    && obligations774                        .iter()775                        .chain([&obligation])776                        .all(|obligation| self.predicate_may_hold(obligation))777            }) && steps > 0778            {779                if span.in_external_macro(self.tcx.sess.source_map()) {780                    return false;781                }782783                // For a shared reference, prefer removing the outer `&` over suggesting784                // `&*reference`. Keep the reborrow for `&mut T` and smart pointers.785                if is_under_ref.is_some()786                    && steps == 1787                    && matches!(base_ty.kind(), ty::Ref(_, _, hir::Mutability::Not))788                    && !expr.span.from_expansion()789                    && self.suggest_remove_reference(obligation, err, real_trait_pred)790                {791                    return true;792                }793                let derefs = "*".repeat(steps);794                let msg = "consider dereferencing here";795796                let call_node = self.tcx.hir_node(*call_hir_id);797                let is_receiver = matches!(798                    call_node,799                    Node::Expr(hir::Expr {800                        kind: hir::ExprKind::MethodCall(_, receiver_expr, ..),801                        ..802                    })803                    if receiver_expr.hir_id == *arg_hir_id804                );805                if is_receiver {806                    err.multipart_suggestion(807                        msg,808                        vec![809                            (span.shrink_to_lo(), format!("({derefs}")),810                            (span.shrink_to_hi(), ")".to_string()),811                        ],812                        Applicability::MachineApplicable,813                    )814                } else {815                    err.span_suggestion_verbose(816                        span.shrink_to_lo(),817                        msg,818                        derefs,819                        Applicability::MachineApplicable,820                    )821                };822                return true;823            }824        } else if let (825            ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. },826            predicate,827        ) = code.peel_derives_with_predicate()828            && let Some(typeck_results) = &self.typeck_results829            && let hir::Node::Expr(lhs) = self.tcx.hir_node(*lhs_hir_id)830            && let hir::Node::Expr(rhs) = self.tcx.hir_node(*rhs_hir_id)831            && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs)832            && let trait_pred = predicate.unwrap_or(trait_pred)833            // Only run this code on binary operators834            && lang_items::BINARY_OPERATORS835                .iter()836                .filter_map(|&op| self.tcx.lang_items().get(op))837                .any(|op| {838                    op == trait_pred.skip_binder().trait_ref.def_id839                })840        {841            // Suggest dereferencing the LHS, RHS, or both terms of a binop if possible842            let trait_pred = predicate.unwrap_or(trait_pred);843            let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty());844            let lhs_autoderef = (self.autoderef_steps)(lhs_ty);845            let rhs_autoderef = (self.autoderef_steps)(rhs_ty);846            let first_lhs = lhs_autoderef.first().unwrap().clone();847            let first_rhs = rhs_autoderef.first().unwrap().clone();848            let mut autoderefs = lhs_autoderef849                .into_iter()850                .enumerate()851                .rev()852                .zip_longest(rhs_autoderef.into_iter().enumerate().rev())853                .map(|t| match t {854                    EitherOrBoth::Both(a, b) => (a, b),855                    EitherOrBoth::Left(a) => (a, (0, first_rhs.clone())),856                    EitherOrBoth::Right(b) => ((0, first_lhs.clone()), b),857                })858                .rev();859            if let Some((lsteps, rsteps)) =860                autoderefs.find_map(|((lsteps, (l_ty, _)), (rsteps, (r_ty, _)))| {861                    // Create a new predicate with the dereferenced LHS and RHS862                    // We simultaneously dereference both sides rather than doing them863                    // one at a time to account for cases such as &Box<T> == &&T864                    let trait_pred_and_ty = trait_pred.map_bound(|inner| {865                        (866                            ty::TraitClause {867                                trait_ref: ty::TraitRef::new_from_args(868                                    self.tcx,869                                    inner.trait_ref.def_id,870                                    self.tcx.mk_args(871                                        &[&[l_ty.into(), r_ty.into()], &inner.trait_ref.args[2..]]872                                            .concat(),873                                    ),874                                ),875                                ..inner876                            },877                            l_ty,878                        )879                    });880                    let obligation = self.mk_trait_obligation_with_new_self_ty(881                        obligation.param_env,882                        trait_pred_and_ty,883                    );884                    self.predicate_may_hold(&obligation).then_some(match (lsteps, rsteps) {885                        (_, 0) => (Some(lsteps), None),886                        (0, _) => (None, Some(rsteps)),887                        _ => (Some(lsteps), Some(rsteps)),888                    })889                })890            {891                let make_sugg = |mut expr: &Expr<'_>, mut steps| {892                    if expr.span.in_external_macro(self.tcx.sess.source_map()) {893                        return None;894                    }895                    let mut prefix_span = expr.span.shrink_to_lo();896                    let mut msg = "consider dereferencing here";897                    if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind {898                        msg = "consider removing the borrow and dereferencing instead";899                        if let hir::ExprKind::AddrOf(..) = inner.kind {900                            msg = "consider removing the borrows and dereferencing instead";901                        }902                    }903                    while let hir::ExprKind::AddrOf(_, _, inner) = expr.kind904                        && steps > 0905                    {906                        prefix_span = prefix_span.with_hi(inner.span.lo());907                        expr = inner;908                        steps -= 1;909                    }910                    // Empty suggestions with empty spans ICE with debug assertions911                    if steps == 0 {912                        return Some((913                            msg.trim_end_matches(" and dereferencing instead"),914                            vec![(prefix_span, String::new())],915                        ));916                    }917                    let derefs = "*".repeat(steps);918                    let needs_parens = steps > 0 && expr_needs_parens(expr);919                    let mut suggestion = if needs_parens {920                        vec![921                            (922                                expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),923                                format!("{derefs}("),924                            ),925                            (expr.span.shrink_to_hi(), ")".to_string()),926                        ]927                    } else {928                        vec![(929                            expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),930                            format!("{derefs}"),931                        )]932                    };933                    // Empty suggestions with empty spans ICE with debug assertions934                    if !prefix_span.is_empty() {935                        suggestion.push((prefix_span, String::new()));936                    }937                    Some((msg, suggestion))938                };939940                if let Some(lsteps) = lsteps941                    && let Some(rsteps) = rsteps942                    && lsteps > 0943                    && rsteps > 0944                {945                    let Some((_, mut suggestion)) = make_sugg(lhs, lsteps) else {946                        return false;947                    };948                    let Some((_, mut rhs_suggestion)) = make_sugg(rhs, rsteps) else {949                        return false;950                    };951                    suggestion.append(&mut rhs_suggestion);952                    err.multipart_suggestion(953                        "consider dereferencing both sides of the expression",954                        suggestion,955                        Applicability::MachineApplicable,956                    );957                    return true;958                } else if let Some(lsteps) = lsteps959                    && lsteps > 0960                {961                    let Some((msg, suggestion)) = make_sugg(lhs, lsteps) else {962                        return false;963                    };964                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);965                    return true;966                } else if let Some(rsteps) = rsteps967                    && rsteps > 0968                {969                    let Some((msg, suggestion)) = make_sugg(rhs, rsteps) else {970                        return false;971                    };972                    err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable);973                    return true;974                }975            }976        }977        false978    }979980    /// Given a closure's `DefId`, return the given name of the closure.981    ///982    /// This doesn't account for reassignments, but it's only used for suggestions.983    fn get_closure_name(984        &self,985        def_id: DefId,986        err: &mut Diag<'_>,987        msg: Cow<'static, str>,988    ) -> Option<Symbol> {989        let get_name = |err: &mut Diag<'_>, kind: &hir::PatKind<'_>| -> Option<Symbol> {990            // Get the local name of this closure. This can be inaccurate because991            // of the possibility of reassignment, but this should be good enough.992            match &kind {993                hir::PatKind::Binding(hir::BindingMode::NONE, _, ident, None) => Some(ident.name),994                _ => {995                    err.note(msg);996                    None997                }998            }999        };10001001        let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);1002        match self.tcx.parent_hir_node(hir_id) {1003            hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Let(local), .. }) => {1004                get_name(err, &local.pat.kind)1005            }1006            // Different to previous arm because one is `&hir::Local` and the other1007            // is `Box<hir::Local>`.1008            hir::Node::LetStmt(local) => get_name(err, &local.pat.kind),1009            _ => None,1010        }1011    }10121013    /// We tried to apply the bound to an `fn` or closure. Check whether calling it would1014    /// evaluate to a type that *would* satisfy the trait bound. If it would, suggest calling1015    /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.1016    pub(super) fn suggest_fn_call(1017        &self,1018        obligation: &PredicateObligation<'tcx>,1019        err: &mut Diag<'_>,1020        trait_pred: ty::PolyTraitClause<'tcx>,1021    ) -> bool {1022        // It doesn't make sense to make this suggestion outside of typeck...1023        // (also autoderef will ICE...)1024        if self.typeck_results.is_none() {1025            return false;1026        }10271028        if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =1029            obligation.predicate.kind().skip_binder()1030            && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized)1031        {1032            // Don't suggest calling to turn an unsized type into a sized type1033            return false;1034        }10351036        let self_ty = self.instantiate_binder_with_fresh_vars(1037            DUMMY_SP,1038            BoundRegionConversionTime::FnCall,1039            trait_pred.self_ty(),1040        );10411042        let Some((def_id_or_name, output, inputs)) =1043            self.extract_callable_info(obligation.cause.body_def_id, obligation.param_env, self_ty)1044        else {1045            return false;1046        };10471048        // Remapping bound vars here1049        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output));10501051        let new_obligation =1052            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);1053        if !self.predicate_must_hold_modulo_regions(&new_obligation) {1054            return false;1055        }10561057        // If this is a zero-argument async closure directly passed as an argument1058        // and the expected type is `Future`, suggest using `async {}` block instead1059        // of `async || {}`1060        if let ty::CoroutineClosure(def_id, args) = *self_ty.kind()1061            && let sig = args.as_coroutine_closure().coroutine_closure_sig().skip_binder()1062            && let ty::Tuple(inputs) = *sig.tupled_inputs_ty.kind()1063            && inputs.is_empty()1064            && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Future)1065            && let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1066            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) =1067                self.tcx.hir_node(*arg_hir_id)1068            && let Some(hir::Node::Expr(hir::Expr {1069                kind: hir::ExprKind::Closure(closure), ..1070            })) = self.tcx.hir_get_if_local(def_id)1071            && let hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async) = closure.kind1072            && let Some(arg_span) = closure.fn_arg_span1073            && obligation.cause.span.contains(arg_span)1074        {1075            let mut body = self.tcx.hir_body(closure.body).value;1076            let peeled = body.peel_blocks().peel_drop_temps();1077            if let hir::ExprKind::Closure(inner) = peeled.kind {1078                body = self.tcx.hir_body(inner.body).value;1079            }1080            if !matches!(body.peel_blocks().peel_drop_temps().kind, hir::ExprKind::Block(..)) {1081                return false;1082            }10831084            let sm = self.tcx.sess.source_map();1085            let removal_span = if let Ok(snippet) =1086                sm.span_to_snippet(arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1)))1087                && snippet.ends_with(' ')1088            {1089                // There's a space after `||`, include it in the removal1090                arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1))1091            } else {1092                arg_span1093            };1094            err.span_suggestion_verbose(1095                removal_span,1096                "use `async {}` instead of `async || {}` to introduce an async block",1097                "",1098                Applicability::MachineApplicable,1099            );1100            return true;1101        }11021103        // Get the name of the callable and the arguments to be used in the suggestion.1104        let msg = match def_id_or_name {1105            DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {1106                DefKind::Ctor(CtorOf::Struct, _) => {1107                    Cow::from("use parentheses to construct this tuple struct")1108                }1109                DefKind::Ctor(CtorOf::Variant, _) => {1110                    Cow::from("use parentheses to construct this tuple variant")1111                }1112                kind => Cow::from(format!(1113                    "use parentheses to call this {}",1114                    self.tcx.def_kind_descr(kind, def_id)1115                )),1116            },1117            DefIdOrName::Name(name) => Cow::from(format!("use parentheses to call this {name}")),1118        };11191120        let args = inputs1121            .into_iter()1122            .map(|ty| {1123                if ty.is_suggestable(self.tcx, false) {1124                    format!("/* {ty} */")1125                } else {1126                    "/* value */".to_string()1127                }1128            })1129            .collect::<Vec<_>>()1130            .join(", ");11311132        let callee_hir_id = match obligation.cause.code() {1133            ObligationCauseCode::FunctionArg { arg_hir_id, .. }1134                if obligation.cause.span.can_be_used_for_suggestions() =>1135            {1136                Some(*arg_hir_id)1137            }1138            // The iterator of a `for` loop is passed to `IntoIterator::into_iter`, so the failing1139            // `Iterator` goal is a derived obligation and `cause.span` carries the loop's1140            // desugaring context. The expression is still the user's, which its own span attests.1141            code => match code.peel_derives() {1142                ObligationCauseCode::ForLoopIterator(iter_hir_id)1143                    if self.tcx.hir_span(*iter_hir_id).can_be_used_for_suggestions() =>1144                {1145                    Some(*iter_hir_id)1146                }1147                _ => None,1148            },1149        };11501151        if let Some(callee_hir_id) = callee_hir_id {1152            let span = obligation.cause.span;11531154            let arg_expr = match self.tcx.hir_node(callee_hir_id) {1155                hir::Node::Expr(expr) => Some(expr),1156                _ => None,1157            };11581159            let is_closure_expr =1160                arg_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Closure(..)));11611162            // If the user wrote `|| {}()`, suggesting to call the closure would produce `(|| {}())()`,1163            // which doesn't help and is often outright wrong.1164            if args.is_empty()1165                && let Some(expr) = arg_expr1166                && let hir::ExprKind::Closure(closure) = expr.kind1167            {1168                let mut body = self.tcx.hir_body(closure.body).value;11691170                // Async closures desugar to a closure returning a coroutine1171                if let hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) =1172                    closure.kind1173                {1174                    let peeled = body.peel_blocks().peel_drop_temps();1175                    if let hir::ExprKind::Closure(inner) = peeled.kind {1176                        body = self.tcx.hir_body(inner.body).value;1177                    }1178                }11791180                let peeled_body = body.peel_blocks().peel_drop_temps();1181                if let hir::ExprKind::Call(callee, call_args) = peeled_body.kind1182                    && call_args.is_empty()1183                    && let hir::ExprKind::Block(..) = callee.peel_blocks().peel_drop_temps().kind1184                {1185                    return false;1186                }1187            }11881189            if is_closure_expr {1190                err.multipart_suggestions(1191                    msg,1192                    vec![vec![1193                        (span.shrink_to_lo(), "(".to_string()),1194                        (span.shrink_to_hi(), format!(")({args})")),1195                    ]],1196                    Applicability::HasPlaceholders,1197                );1198            } else {1199                err.span_suggestion_verbose(1200                    span.shrink_to_hi(),1201                    msg,1202                    format!("({args})"),1203                    Applicability::HasPlaceholders,1204                );1205            }1206        } else if let DefIdOrName::DefId(def_id) = def_id_or_name {1207            let name = match self.tcx.hir_get_if_local(def_id) {1208                Some(hir::Node::Expr(hir::Expr {1209                    kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),1210                    ..1211                })) => {1212                    err.span_label(*fn_decl_span, "consider calling this closure");1213                    let Some(name) = self.get_closure_name(def_id, err, msg.clone()) else {1214                        return false;1215                    };1216                    name.to_string()1217                }1218                Some(hir::Node::Item(hir::Item {1219                    kind: hir::ItemKind::Fn { ident, .. }, ..1220                })) => {1221                    err.span_label(ident.span, "consider calling this function");1222                    ident.to_string()1223                }1224                Some(hir::Node::Ctor(..)) => {1225                    let name = self.tcx.def_path_str(def_id);1226                    err.span_label(1227                        self.tcx.def_span(def_id),1228                        format!("consider calling the constructor for `{name}`"),1229                    );1230                    name1231                }1232                _ => return false,1233            };1234            err.help(format!("{msg}: `{name}({args})`"));1235        }1236        true1237    }12381239    pub(super) fn suggest_cast_to_fn_pointer(1240        &self,1241        obligation: &PredicateObligation<'tcx>,1242        err: &mut Diag<'_>,1243        leaf_trait_predicate: ty::PolyTraitClause<'tcx>,1244        main_trait_predicate: ty::PolyTraitClause<'tcx>,1245        span: Span,1246    ) -> bool {1247        let &[candidate] = &self.find_similar_impl_candidates(1248            leaf_trait_predicate.def_id(),1249            leaf_trait_predicate.self_ty().skip_binder(),1250        )[..] else {1251            return false;1252        };1253        let candidate = candidate.trait_ref;12541255        if !matches!(1256            (candidate.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind(),),1257            (ty::FnPtr(..), ty::FnDef(..))1258        ) {1259            return false;1260        }12611262        let parenthesized_cast = |span: Span| {1263            vec![1264                (span.shrink_to_lo(), "(".to_string()),1265                (span.shrink_to_hi(), format!(" as {})", candidate.self_ty())),1266            ]1267        };1268        // Wrap method receivers and `&`-references in parens.1269        let suggestion = if self.tcx.sess.source_map().span_followed_by(span, ".").is_some() {1270            parenthesized_cast(span)1271        } else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id) {1272            let mut expr_finder = FindExprBySpan::new(span, self.tcx);1273            expr_finder.visit_expr(&body.value);1274            if let Some(expr) = expr_finder.result1275                && let hir::ExprKind::AddrOf(_, _, expr) = expr.kind1276            {1277                parenthesized_cast(expr.span)1278            } else {1279                vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]1280            }1281        } else {1282            vec![(span.shrink_to_hi(), format!(" as {}", candidate.self_ty()))]1283        };12841285        let trait_ = self.tcx.short_string(candidate.print_trait_sugared(), err.long_ty_path());1286        let self_ty = self.tcx.short_string(candidate.self_ty(), err.long_ty_path());1287        err.multipart_suggestion(1288            format!(1289                "the trait `{trait_}` is implemented for fn pointer \1290                 `{self_ty}`, try casting using `as`",1291            ),1292            suggestion,1293            Applicability::MaybeIncorrect,1294        );1295        true1296    }12971298    pub(super) fn check_for_binding_assigned_block_without_tail_expression(1299        &self,1300        obligation: &PredicateObligation<'tcx>,1301        err: &mut Diag<'_>,1302        trait_pred: ty::PolyTraitClause<'tcx>,1303    ) {1304        let mut span = obligation.cause.span;1305        while span.from_expansion() {1306            // Remove all the desugaring and macro contexts.1307            span.remove_mark();1308        }1309        let mut expr_finder = FindExprBySpan::new(span, self.tcx);1310        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id) else {1311            return;1312        };1313        expr_finder.visit_expr(&body.value);1314        let Some(expr) = expr_finder.result else {1315            return;1316        };1317        let Some(typeck) = &self.typeck_results else {1318            return;1319        };1320        let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else {1321            return;1322        };1323        if !ty.is_unit() {1324            return;1325        };1326        let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else {1327            return;1328        };1329        let Res::Local(hir_id) = path.res else {1330            return;1331        };1332        let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {1333            return;1334        };1335        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =1336            self.tcx.parent_hir_node(pat.hir_id)1337        else {1338            return;1339        };1340        let hir::ExprKind::Block(block, None) = init.kind else {1341            return;1342        };1343        if block.expr.is_some() {1344            return;1345        }1346        let [.., stmt] = block.stmts else {1347            err.span_label(block.span, "this empty block is missing a tail expression");1348            return;1349        };1350        // FIXME expr and stmt have the same span if expr comes from expansion1351        // cc: https://github.com/rust-lang/rust/pull/147416#discussion_r24994075231352        if stmt.span.from_expansion() {1353            return;1354        }1355        let hir::StmtKind::Semi(tail_expr) = stmt.kind else {1356            return;1357        };1358        let Some(ty) = typeck.expr_ty_opt(tail_expr) else {1359            err.span_label(block.span, "this block is missing a tail expression");1360            return;1361        };1362        let ty =1363            self.resolve_numeric_literals_with_default(self.deeply_resolve_ignoring_regions(ty));1364        let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty));13651366        let new_obligation =1367            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);1368        if !matches!(tail_expr.kind, hir::ExprKind::Err(_))1369            && self.predicate_must_hold_modulo_regions(&new_obligation)1370        {1371            err.span_suggestion_short(1372                stmt.span.with_lo(tail_expr.span.hi()),1373                "remove this semicolon",1374                "",1375                Applicability::MachineApplicable,1376            );1377        } else {1378            err.span_label(block.span, "this block is missing a tail expression");1379        }1380    }13811382    pub(super) fn suggest_add_clone_to_arg(1383        &self,1384        obligation: &PredicateObligation<'tcx>,1385        err: &mut Diag<'_>,1386        trait_pred: ty::PolyTraitClause<'tcx>,1387    ) -> bool {1388        let self_ty = self.deeply_resolve_ignoring_regions(trait_pred.self_ty());1389        self.enter_forall(self_ty, |ty: Ty<'_>| {1390            let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_def_id) else {1391                return false;1392            };1393            let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };1394            let ty::Param(param) = inner_ty.kind() else { return false };1395            let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1396            else {1397                return false;1398            };13991400            let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span);1401            let has_clone = |ty| {1402                self.type_implements_trait(clone_trait, [ty], obligation.param_env)1403                    .must_apply_modulo_regions()1404            };14051406            let existing_clone_call = match self.tcx.hir_node(*arg_hir_id) {1407                // It's just a variable. Propose cloning it.1408                Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) => None,1409                // It's already a call to `clone()`. We might be able to suggest1410                // adding a `+ Clone` bound, though.1411                Node::Expr(Expr {1412                    kind:1413                        hir::ExprKind::MethodCall(1414                            hir::PathSegment { ident, .. },1415                            _receiver,1416                            [],1417                            call_span,1418                        ),1419                    hir_id,1420                    ..1421                }) if ident.name == sym::clone1422                    && !call_span.from_expansion()1423                    && !has_clone(*inner_ty) =>1424                {1425                    // We only care about method calls corresponding to the real `Clone` trait.1426                    let Some(typeck_results) = self.typeck_results.as_ref() else { return false };1427                    let Some((DefKind::AssocFn, did)) = typeck_results.type_dependent_def(*hir_id)1428                    else {1429                        return false;1430                    };1431                    if self.tcx.trait_of_assoc(did) != Some(clone_trait) {1432                        return false;1433                    }1434                    Some(ident.span)1435                }1436                _ => return false,1437            };14381439            let new_obligation = self.mk_trait_obligation_with_new_self_ty(1440                obligation.param_env,1441                trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),1442            );14431444            if self.predicate_may_hold(&new_obligation) && has_clone(ty) {1445                if !has_clone(param.to_ty(self.tcx)) {1446                    suggest_constraining_type_param(1447                        self.tcx,1448                        generics,1449                        err,1450                        param.name.as_str(),1451                        "Clone",1452                        Some(clone_trait),1453                        None,1454                    );1455                }1456                if let Some(existing_clone_call) = existing_clone_call {1457                    err.span_note(1458                        existing_clone_call,1459                        format!(1460                            "this `clone()` copies the reference, \1461                            which does not do anything, \1462                            because `{inner_ty}` does not implement `Clone`"1463                        ),1464                    );1465                } else {1466                    err.span_suggestion_verbose(1467                        obligation.cause.span.shrink_to_hi(),1468                        "consider using clone here",1469                        ".clone()".to_string(),1470                        Applicability::MaybeIncorrect,1471                    );1472                }1473                return true;1474            }1475            false1476        })1477    }14781479    /// Extracts information about a callable type for diagnostics. This is a1480    /// heuristic -- it doesn't necessarily mean that a type is always callable,1481    /// because the callable type must also be well-formed to be called.1482    pub fn extract_callable_info(1483        &self,1484        body_def_id: LocalDefId,1485        param_env: ty::ParamEnv<'tcx>,1486        found: Ty<'tcx>,1487    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {1488        // Autoderef is useful here because sometimes we box callables, etc.1489        let Some((def_id_or_name, output, inputs)) =1490            (self.autoderef_steps)(found).into_iter().find_map(|(found, _)| match *found.kind() {1491                ty::FnPtr(sig_tys, _) => Some((1492                    DefIdOrName::Name("function pointer"),1493                    sig_tys.output(),1494                    sig_tys.inputs(),1495                )),1496                ty::FnDef(def_id, _) => {1497                    let fn_sig = found.fn_sig(self.tcx);1498                    Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))1499                }1500                ty::Closure(def_id, args) => {1501                    let fn_sig = args.as_closure().sig();1502                    Some((1503                        DefIdOrName::DefId(def_id),1504                        fn_sig.output(),1505                        fn_sig.inputs().map_bound(|inputs| inputs[0].tuple_fields().as_slice()),1506                    ))1507                }1508                ty::CoroutineClosure(def_id, args) => {1509                    let sig_parts = args.as_coroutine_closure().coroutine_closure_sig();1510                    Some((1511                        DefIdOrName::DefId(def_id),1512                        sig_parts.map_bound(|sig| {1513                            sig.to_coroutine(1514                                self.tcx,1515                                args.as_coroutine_closure().parent_args(),1516                                // Just use infer vars here, since we  don't really care1517                                // what these types are, just that we're returning a coroutine.1518                                self.next_ty_var(DUMMY_SP),1519                                self.tcx.coroutine_for_closure(def_id),1520                                self.next_ty_var(DUMMY_SP),1521                            )1522                        }),1523                        sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),1524                    ))1525                }1526                ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {1527                    self.tcx1528                        .item_self_bounds(def_id)1529                        .instantiate(self.tcx, args)1530                        .skip_norm_wip()1531                        .iter()1532                        .find_map(|pred| {1533                            if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()1534                            && self1535                                .tcx1536                                .is_lang_item(proj.def_id(), LangItem::FnOnceOutput)1537                            // args tuple will always be args[1]1538                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()1539                            {1540                                Some((1541                                    DefIdOrName::DefId(def_id),1542                                    pred.kind().rebind(proj.term.expect_type()),1543                                    pred.kind().rebind(args.as_slice()),1544                                ))1545                            } else {1546                                None1547                            }1548                        })1549                }1550                ty::Dynamic(data, _) => data.iter().find_map(|pred| {1551                    if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()1552                        && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)1553                        // for existential projection, args are shifted over by 11554                        && let ty::Tuple(args) = proj.args.type_at(0).kind()1555                    {1556                        Some((1557                            DefIdOrName::Name("trait object"),1558                            pred.rebind(proj.term.expect_type()),1559                            pred.rebind(args.as_slice()),1560                        ))1561                    } else {1562                        None1563                    }1564                }),1565                ty::Param(param) => {1566                    let generics = self.tcx.generics_of(body_def_id);1567                    let name = if generics.count() > param.index as usize1568                        && let def = generics.param_at(param.index as usize, self.tcx)1569                        && matches!(def.kind, ty::GenericParamDefKind::Type { .. })1570                        && def.name == param.name1571                    {1572                        DefIdOrName::DefId(def.def_id)1573                    } else {1574                        DefIdOrName::Name("type parameter")1575                    };1576                    param_env.caller_bounds().find_map(|clause| {1577                        if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder()1578                            && self1579                                .tcx1580                                .is_lang_item(proj.def_id(), LangItem::FnOnceOutput)1581                            && proj.projection_term.self_ty() == found1582                            // args tuple will always be args[1]1583                            && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()1584                        {1585                            Some((1586                                name,1587                                clause.kind().rebind(proj.term.expect_type()),1588                                clause.kind().rebind(args.as_slice()),1589                            ))1590                        } else {1591                            None1592                        }1593                    })1594                }1595                _ => None,1596            })1597        else {1598            return None;1599        };16001601        let output = self.instantiate_binder_with_fresh_vars(1602            DUMMY_SP,1603            BoundRegionConversionTime::FnCall,1604            output,1605        );1606        let inputs = inputs1607            .skip_binder()1608            .iter()1609            .map(|ty| {1610                self.instantiate_binder_with_fresh_vars(1611                    DUMMY_SP,1612                    BoundRegionConversionTime::FnCall,1613                    inputs.rebind(*ty),1614                )1615            })1616            .collect();16171618        // We don't want to register any extra obligations, which should be1619        // implied by wf, but also because that would possibly result in1620        // erroneous errors later on.1621        let InferOk { value: output, obligations: _ } =1622            self.at(&ObligationCause::dummy(), param_env).normalize(Unnormalized::new_wip(output));16231624        if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }1625    }16261627    pub(super) fn where_clause_expr_matches_failed_self_ty(1628        &self,1629        obligation: &PredicateObligation<'tcx>,1630        old_self_ty: Ty<'tcx>,1631    ) -> bool {1632        let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() else {1633            return true;1634        };1635        let (Some(typeck_results), Some(body)) = (1636            self.typeck_results.as_ref(),1637            self.tcx.hir_maybe_body_owned_by(obligation.cause.body_def_id),1638        ) else {1639            return true;1640        };16411642        let mut expr_finder = FindExprBySpan::new(obligation.cause.span, self.tcx);1643        expr_finder.visit_expr(&body.value);1644        let Some(expr) = expr_finder.result else {1645            return true;1646        };16471648        let inner_old_self_ty = match old_self_ty.kind() {1649            ty::Ref(_, inner_ty, _) => Some(*inner_ty),1650            _ => None,1651        };16521653        typeck_results.expr_ty_adjusted_opt(expr).is_some_and(|expr_ty| {1654            self.can_eq(obligation.param_env, expr_ty, old_self_ty)1655                || inner_old_self_ty1656                    .is_some_and(|inner_ty| self.can_eq(obligation.param_env, expr_ty, inner_ty))1657        })1658    }16591660    pub(super) fn suggest_add_reference_to_arg(1661        &self,1662        obligation: &PredicateObligation<'tcx>,1663        err: &mut Diag<'_>,1664        poly_trait_pred: ty::PolyTraitClause<'tcx>,1665        has_custom_message: bool,1666    ) -> bool {1667        let span = obligation.cause.span;1668        let param_env = obligation.param_env;16691670        let mk_result = |trait_pred_and_new_ty| {1671            let obligation =1672                self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);1673            self.predicate_must_hold_modulo_regions(&obligation)1674        };16751676        let trait_pred_and_imm_ref = poly_trait_pred.map_bound(|p| {1677            (p, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))1678        });1679        let trait_pred_and_mut_ref = poly_trait_pred.map_bound(|p| {1680            (p, Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))1681        });16821683        let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);1684        let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);16851686        let mut point_at_relevant_args =1687            |pred_ty: Ty<'tcx>, args_and_inputs: Vec<(hir::Expr<'_>, Ty<'tcx>)>| {1688                let Some(typeck_results) = &self.typeck_results else { return false };16891690                let erased_self_ty =1691                    self.tcx.instantiate_bound_regions_with_erased(poly_trait_pred.self_ty());1692                let mut spans = vec![];1693                for (arg, input) in args_and_inputs {1694                    let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(&arg) else { continue };1695                    let pred_has_arg_type = self.infcx.can_eq(param_env, arg_ty, erased_self_ty);1696                    let arg_is_type_param = self.infcx.can_eq(param_env, pred_ty, input);1697                    if pred_has_arg_type && arg_is_type_param {1698                        err.span_label(1699                            arg.span,1700                            format!("`{arg_ty}` doesn't satisfy the trait bound"),1701                        );1702                        spans.push(arg.span);1703                    }1704                }1705                let this = pluralize!("this", spans.len());1706                if !spans.is_empty() {1707                    if imm_ref_self_ty_satisfies_pred {1708                        err.multipart_suggestion(1709                            format!("consider borrowing {this} argument"),1710                            spans.iter().map(|sp| (sp.shrink_to_lo(), "&".into())).collect(),1711                            Applicability::MaybeIncorrect,1712                        );1713                    }1714                    if mut_ref_self_ty_satisfies_pred {1715                        err.multipart_suggestion(1716                            format!("consider mutably borrowing {this} argument"),1717                            spans.iter().map(|sp| (sp.shrink_to_lo(), "&mut ".into())).collect(),1718                            Applicability::MaybeIncorrect,1719                        );1720                    }1721                }1722                !spans.is_empty()1723            };1724        let code = match obligation.cause.code() {1725            ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code,1726            // FIXME(compiler-errors): This is kind of a mess, but required for obligations1727            // that come from a path expr to affect the *call* expr.1728            c @ ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx)1729                if self.tcx.hir_span(*hir_id).lo() == span.lo() =>1730            {1731                // `hir_id` corresponds to the HIR node that introduced a `where`-clause obligation.1732                if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(*hir_id) {1733                    // If that obligation comes from a type in an associated method call, we need1734                    // special handling here.1735                    if let hir::ExprKind::Call(base, _) = expr.kind1736                        && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, segment)) =1737                            base.kind1738                        && let hir::Node::Expr(outer) = self.tcx.parent_hir_node(expr.hir_id)1739                        && let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mtbl, _) = outer.kind1740                        && ty.span == span1741                    {1742                        // We've encountered something like `&str::from("")`, where the intended code1743                        // was likely `<&str>::from("")`. The former is interpreted as "call method1744                        // `from` on `str` and borrow the result", while the latter means "call method1745                        // `from` on `&str`".17461747                        let sugg_msg = |pre: &str| {1748                            format!(1749                                "you likely meant to call the associated function `{FN}` for type \1750                                 `&{pre}{TY}`, but the code as written calls associated function `{FN}` on \1751                                 type `{TY}`",1752                                FN = segment.ident,1753                                TY = poly_trait_pred.self_ty(),1754                            )1755                        };1756                        match (imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl)1757                        {1758                            (true, _, hir::Mutability::Not) | (_, true, hir::Mutability::Mut) => {1759                                err.multipart_suggestion(1760                                    sugg_msg(mtbl.prefix_str()),1761                                    vec![1762                                        (outer.span.shrink_to_lo(), "<".to_string()),1763                                        (span.shrink_to_hi(), ">".to_string()),1764                                    ],1765                                    Applicability::MachineApplicable,1766                                );1767                            }1768                            (true, _, hir::Mutability::Mut) => {1769                                // There's an associated function found on the immutable borrow of the1770                                err.multipart_suggestion(1771                                    sugg_msg("mut "),1772                                    vec![1773                                        (outer.span.shrink_to_lo().until(span), "<&".to_string()),1774                                        (span.shrink_to_hi(), ">".to_string()),1775                                    ],1776                                    Applicability::MachineApplicable,1777                                );1778                            }1779                            (_, true, hir::Mutability::Not) => {1780                                err.multipart_suggestion(1781                                    sugg_msg(""),1782                                    vec![1783                                        (1784                                            outer.span.shrink_to_lo().until(span),1785                                            "<&mut ".to_string(),1786                                        ),1787                                        (span.shrink_to_hi(), ">".to_string()),1788                                    ],1789                                    Applicability::MachineApplicable,1790                                );1791                            }1792                            _ => {}1793                        }1794                        // If we didn't return early here, we would instead suggest `&&str::from("")`.1795                        return false;1796                    } else if let hir::ExprKind::Call(_, args) = expr.kind {1797                        // The `def_id` can point at a struct, which has no fn sig.1798                        if matches!(1799                            self.tcx.def_kind(*def_id),1800                            DefKind::AssocFn | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn)1801                        ) && let Some(pred) = self1802                                .tcx1803                                .clauses_of(*def_id)1804                                .instantiate_identity(self.tcx)1805                                .clauses1806                                .into_iter()1807                                .nth(*idx)1808                            && let Some(pred) = pred.as_trait_clause()1809                            // This feature allows for `for<T> T: Trait`, which fails1810                            // `instantiate_bound_regions_with_erased`. Avoid suggesting for now.1811                            && !self.tcx.features().non_lifetime_binders()1812                        {1813                            let pred_ty = self.tcx.instantiate_bound_regions_with_erased(1814                                pred.self_ty().skip_norm_wip(),1815                            );1816                            let fn_sig = self.tcx.instantiate_bound_regions_with_erased(1817                                self.tcx.fn_sig(*def_id).instantiate_identity().skip_norm_wip(),1818                            );1819                            if point_at_relevant_args(1820                                pred_ty,1821                                args.into_iter()1822                                    .zip(fn_sig.inputs())1823                                    .map(|(e, t)| (*e, *t))1824                                    .collect(),1825                            ) {1826                                return false;1827                            }1828                        }1829                    }1830                }1831                c1832            }1833            c @ ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx)1834                if let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id)1835                    && let hir::ExprKind::MethodCall(_segment, rcvr, args, ..) = expr.kind1836                    // The `def_id` can also point at the impl, which has no fn sig.1837                    && matches!(1838                        self.tcx.def_kind(*def_id),1839                        DefKind::AssocFn | DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn)1840                    )1841                    && let Some(pred) = self1842                        .tcx1843                        .clauses_of(*def_id)1844                        .instantiate_identity(self.tcx)1845                        .clauses1846                        .into_iter()1847                        .nth(*idx)1848                    && let Some(pred) = pred.as_trait_clause()1849                    // This feature allows for `for<T> T: Trait`, which fails1850                    // `instantiate_bound_regions_with_erased`. Avoid suggesting for now.1851                    && !self.tcx.features().non_lifetime_binders() =>1852            {1853                let fn_sig = self.tcx.instantiate_bound_regions_with_erased(1854                    self.tcx.fn_sig(*def_id).instantiate_identity().skip_norm_wip(),1855                );1856                // We've got a method call where likely one of the arguments didn't meet a bound.1857                let pred_ty =1858                    self.tcx.instantiate_bound_regions_with_erased(pred.self_ty().skip_norm_wip());1859                if point_at_relevant_args(1860                    pred_ty,1861                    [rcvr]1862                        .into_iter()1863                        .chain(args.into_iter())1864                        .zip(fn_sig.inputs())1865                        .map(|(e, t)| (*e, *t))1866                        .collect(),1867                ) {1868                    return false;1869                }1870                c1871            }1872            c if matches!(1873                span.ctxt().outer_expn_data().kind,1874                ExpnKind::Desugaring(DesugaringKind::ForLoop)1875            ) =>1876            {1877                c1878            }1879            _ => return false,1880        };18811882        // List of traits for which it would be nonsensical to suggest borrowing.1883        // For instance, immutable references are always Copy, so suggesting to1884        // borrow would always succeed, but it's probably not what the user wanted.1885        let mut never_suggest_borrow: Vec<_> =1886            [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized]1887                .iter()1888                .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item))1889                .collect();18901891        if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {1892            never_suggest_borrow.push(def_id);1893        }18941895        // Try to apply the original trait bound by borrowing.1896        let mut try_borrowing = |old_pred: ty::PolyTraitClause<'tcx>,1897                                 blacklist: &[DefId]|1898         -> bool {1899            if blacklist.contains(&old_pred.def_id()) {1900                return false;1901            }1902            // We map bounds to `&T` and `&mut T`1903            let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {1904                (1905                    trait_pred,1906                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),1907                )1908            });1909            let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {1910                (1911                    trait_pred,1912                    Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),1913                )1914            });19151916            let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);1917            let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);19181919            let (ref_inner_ty_satisfies_pred, ref_inner_ty_is_mut) =1920                if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code()1921                    && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()1922                {1923                    (1924                        mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),1925                        mutability.is_mut(),1926                    )1927                } else {1928                    (false, false)1929                };19301931            let is_immut = imm_ref_self_ty_satisfies_pred1932                || (ref_inner_ty_satisfies_pred && !ref_inner_ty_is_mut);1933            let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_is_mut;1934            if !is_immut && !is_mut {1935                return false;1936            }1937            let Ok(_snippet) = self.tcx.sess.source_map().span_to_snippet(span) else {1938                return false;1939            };1940            // We don't want a borrowing suggestion on the fields in structs1941            // ```1942            // #[derive(Clone)]1943            // struct Foo {1944            //     the_foos: Vec<Foo>1945            // }1946            // ```1947            if !matches!(1948                span.ctxt().outer_expn_data().kind,1949                ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)1950            ) {1951                return false;1952            }1953            // We have a very specific type of error, where just borrowing this argument1954            // might solve the problem. In cases like this, the important part is the1955            // original type obligation, not the last one that failed, which is arbitrary.1956            // Because of this, we modify the error to refer to the original obligation and1957            // return early in the caller.19581959            let mut label = || {1960                // Special case `Sized` as `old_pred` will be the trait itself instead of1961                // `Sized` when the trait bound is the source of the error.1962                let is_sized = match obligation.predicate.kind().skip_binder() {1963                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {1964                        self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized)1965                    }1966                    _ => false,1967                };19681969                let msg = format!(1970                    "the trait bound `{}` is not satisfied",1971                    self.tcx.short_string(old_pred, err.long_ty_path()),1972                );1973                let self_ty_str = self.tcx.short_string(old_pred.self_ty(), err.long_ty_path());1974                let trait_path = self1975                    .tcx1976                    .short_string(old_pred.print_modifiers_and_trait_path(), err.long_ty_path());19771978                if has_custom_message {1979                    let msg = if is_sized {1980                        "the trait bound `Sized` is not satisfied".into()1981                    } else {1982                        msg1983                    };1984                    err.note(msg);1985                } else {1986                    err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)];1987                }1988                if is_sized {1989                    err.span_label(1990                        span,1991                        format!("the trait `Sized` is not implemented for `{self_ty_str}`"),1992                    );1993                } else {1994                    err.span_label(1995                        span,1996                        format!("the trait `{trait_path}` is not implemented for `{self_ty_str}`"),1997                    );1998                }1999            };

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.

Generated by searchcode.com · powered by code_get_file + code_get_findings