compiler/rustc_hir_analysis/src/check/compare_impl_item.rs RUST 2,796 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,796.
1use core::ops::ControlFlow;2use std::borrow::Cow;3use std::cmp::Ordering;4use std::iter;56use hir::def_id::{DefId, DefIdMap, LocalDefId};7use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};8use rustc_errors::codes::*;9use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err};10use rustc_hir::def::{DefKind, Res};11use rustc_hir::intravisit::VisitorExt;12use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit};13use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt};14use rustc_infer::traits::util;15use rustc_middle::ty::error::{ExpectedFound, TypeError};16use rustc_middle::ty::{17    self, BottomUpFolder, GenericArgs, GenericParamDefKind, Generics, Ty, TyCtxt, TypeFoldable,18    TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,19    Unnormalized, Upcast,20};21use rustc_middle::{bug, span_bug};22use rustc_span::{BytePos, DUMMY_SP, Span};23use rustc_trait_selection::error_reporting::InferCtxtErrorExt;24use rustc_trait_selection::infer::InferCtxtExt;25use rustc_trait_selection::regions::InferCtxtRegionExt;26use rustc_trait_selection::traits::{27    self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,28};29use tracing::{debug, instrument};3031use super::potentially_plural_count;32use crate::diagnostics::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};3334pub(super) mod refine;3536/// Call the query `tcx.compare_impl_item()` directly instead.37pub(super) fn compare_impl_item(38    tcx: TyCtxt<'_>,39    impl_item_def_id: LocalDefId,40) -> Result<(), ErrorGuaranteed> {41    let impl_item = tcx.associated_item(impl_item_def_id);42    let trait_item = tcx.associated_item(impl_item.expect_trait_impl()?);43    let impl_trait_ref =44        tcx.impl_trait_ref(impl_item.container_id(tcx)).instantiate_identity().skip_norm_wip();45    debug!(?impl_trait_ref);4647    match impl_item.kind {48        ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),49        ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),50        ty::AssocKind::Const { .. } => {51            compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref)52        }53    }54}5556/// Checks that a method from an impl conforms to the signature of57/// the same method as declared in the trait.58///59/// # Parameters60///61/// - `impl_m`: type of the method we are checking62/// - `trait_m`: the method in the trait63/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation64#[instrument(level = "debug", skip(tcx))]65fn compare_impl_method<'tcx>(66    tcx: TyCtxt<'tcx>,67    impl_m: ty::AssocItem,68    trait_m: ty::AssocItem,69    impl_trait_ref: ty::TraitRef<'tcx>,70) -> Result<(), ErrorGuaranteed> {71    check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;72    compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?;73    Ok(())74}7576/// Checks a bunch of different properties of the impl/trait methods for77/// compatibility, such as asyncness, number of argument, self receiver kind,78/// and number of early- and late-bound generics.79fn check_method_is_structurally_compatible<'tcx>(80    tcx: TyCtxt<'tcx>,81    impl_m: ty::AssocItem,82    trait_m: ty::AssocItem,83    impl_trait_ref: ty::TraitRef<'tcx>,84    delay: bool,85) -> Result<(), ErrorGuaranteed> {86    compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?;87    compare_number_of_generics(tcx, impl_m, trait_m, delay)?;88    compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?;89    compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?;90    compare_synthetic_generics(tcx, impl_m, trait_m, delay)?;91    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?;92    Ok(())93}9495/// This function is best explained by example. Consider a trait with its implementation:96///97/// ```rust98/// trait Trait<'t, T> {99///     // `trait_m`100///     fn method<'a, M>(t: &'t T, m: &'a M) -> Self;101/// }102///103/// struct Foo;104///105/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {106///     // `impl_m`107///     fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo { Foo }108/// }109/// ```110///111/// We wish to decide if those two method types are compatible.112/// For this we have to show that, assuming the bounds of the impl hold, the113/// bounds of `trait_m` imply the bounds of `impl_m`.114///115/// We start out with `trait_to_impl_args`, that maps the trait116/// type parameters to impl type parameters. This is taken from the117/// impl trait reference:118///119/// ```rust,ignore (pseudo-Rust)120/// trait_to_impl_args = {'t => 'j, T => &'i U, Self => Foo}121/// ```122///123/// We create a mapping `dummy_args` that maps from the impl type124/// parameters to fresh types and regions. For type parameters,125/// this is the identity transform, but we could as well use any126/// placeholder types. For regions, we convert from bound to free127/// regions (Note: but only early-bound regions, i.e., those128/// declared on the impl or used in type parameter bounds).129///130/// ```rust,ignore (pseudo-Rust)131/// impl_to_placeholder_args = {'i => 'i0, U => U0, N => N0 }132/// ```133///134/// Now we can apply `placeholder_args` to the type of the impl method135/// to yield a new function type in terms of our fresh, placeholder136/// types:137///138/// ```rust,ignore (pseudo-Rust)139/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo140/// ```141///142/// We now want to extract and instantiate the type of the *trait*143/// method and compare it. To do so, we must create a compound144/// instantiation by combining `trait_to_impl_args` and145/// `impl_to_placeholder_args`, and also adding a mapping for the method146/// type parameters. We extend the mapping to also include147/// the method parameters.148///149/// ```rust,ignore (pseudo-Rust)150/// trait_to_placeholder_args = { T => &'i0 U0, Self => Foo, M => N0 }151/// ```152///153/// Applying this to the trait method type yields:154///155/// ```rust,ignore (pseudo-Rust)156/// <'a> fn(t: &'i0 U0, m: &'a N0) -> Foo157/// ```158///159/// This type is also the same but the name of the bound region (`'a`160/// vs `'b`). However, the normal subtyping rules on fn types handle161/// this kind of equivalency just fine.162///163/// We now use these generic parameters to ensure that all declared bounds164/// are satisfied by the implementation's method.165///166/// We do this by creating a parameter environment which contains a167/// generic parameter corresponding to `impl_to_placeholder_args`. We then build168/// `trait_to_placeholder_args` and use it to convert the predicates contained169/// in the `trait_m` generics to the placeholder form.170///171/// Finally we register each of these predicates as an obligation and check that172/// they hold.173#[instrument(level = "debug", skip(tcx, impl_trait_ref))]174fn compare_method_predicate_entailment<'tcx>(175    tcx: TyCtxt<'tcx>,176    impl_m: ty::AssocItem,177    trait_m: ty::AssocItem,178    impl_trait_ref: ty::TraitRef<'tcx>,179) -> Result<(), ErrorGuaranteed> {180    // This node-id should be used for the `body_id` field on each181    // `ObligationCause` (and the `FnCtxt`).182    //183    // FIXME(@lcnr): remove that after removing `cause.body_id` from184    // obligations.185    let impl_m_def_id = impl_m.def_id.expect_local();186    let impl_m_span = tcx.def_span(impl_m_def_id);187    let cause = ObligationCause::new(188        impl_m_span,189        impl_m_def_id,190        ObligationCauseCode::CompareImplItem {191            impl_item_def_id: impl_m_def_id,192            trait_item_def_id: trait_m.def_id,193            kind: impl_m.kind,194        },195    );196197    // Create mapping from trait method to impl method.198    let impl_def_id = impl_m.container_id(tcx);199    let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(200        tcx,201        impl_m.container_id(tcx),202        impl_trait_ref.args,203    );204    debug!(?trait_to_impl_args);205206    let impl_m_predicates = tcx.predicates_of(impl_m.def_id);207    let trait_m_predicates = tcx.predicates_of(trait_m.def_id);208209    // This is the only tricky bit of the new way we check implementation methods210    // We need to build a set of predicates where only the method-level bounds211    // are from the trait and we assume all other bounds from the implementation212    // to be previously satisfied.213    //214    // We then register the obligations from the impl_m and check to see215    // if all constraints hold.216    let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());217    let mut hybrid_preds = impl_predicates.instantiate_identity(tcx).predicates;218    hybrid_preds.extend(219        trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate),220    );221222    let is_conditionally_const = tcx.is_conditionally_const(impl_m.def_id);223    if is_conditionally_const {224        // Augment the hybrid param-env with the const conditions225        // of the impl header and the trait method.226        hybrid_preds.extend(227            tcx.const_conditions(impl_def_id)228                .instantiate_identity(tcx)229                .into_iter()230                .chain(231                    tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args),232                )233                .map(|(trait_ref, _)| {234                    trait_ref.to_host_effect_clause(tcx, ty::BoundConstness::Maybe)235                }),236        );237    }238239    let hybrid_preds = hybrid_preds.into_iter().map(Unnormalized::skip_norm_wip);240    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);241    let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds));242    // FIXME(-Zhigher-ranked-assumptions): The `hybrid_preds`243    // should be well-formed. However, using them may result in244    // region errors as we currently don't track placeholder245    // assumptions.246    //247    // To avoid being backwards incompatible with the old solver,248    // we also eagerly normalize the where-bounds in the new solver249    // here while ignoring region constraints. This means we can then250    // use where-bounds whose normalization results in placeholder251    // errors further down without getting any errors.252    //253    // It should be sound to do so as the only region errors here254    // should be due to missing implied bounds.255    //256    // cc trait-system-refactor-initiative/issues/166.257    let param_env = if tcx.next_trait_solver_globally() {258        traits::deeply_normalize_param_env_ignoring_regions(tcx, param_env, normalize_cause)259    } else {260        traits::normalize_param_env_or_error(tcx, param_env, normalize_cause)261    };262    debug!(caller_bounds=?param_env.caller_bounds());263264    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());265    let ocx = ObligationCtxt::new_with_diagnostics(infcx);266267    // Create obligations for each predicate declared by the impl268    // definition in the context of the hybrid param-env. This makes269    // sure that the impl's method's where clauses are not more270    // restrictive than the trait's method (and the impl itself).271    let impl_m_own_bounds = impl_m_predicates.instantiate_own_identity();272    for (predicate, span) in impl_m_own_bounds {273        let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);274        let predicate = ocx.normalize(&normalize_cause, param_env, predicate);275276        let cause = ObligationCause::new(277            span,278            impl_m_def_id,279            ObligationCauseCode::CompareImplItem {280                impl_item_def_id: impl_m_def_id,281                trait_item_def_id: trait_m.def_id,282                kind: impl_m.kind,283            },284        );285        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));286    }287288    // If we're within a const implementation, we need to make sure that the method289    // does not assume stronger `[const]` bounds than the trait definition.290    //291    // This registers the `[const]` bounds of the impl method, which we will prove292    // using the hybrid param-env that we earlier augmented with the const conditions293    // from the impl header and trait method declaration.294    if is_conditionally_const {295        for (const_condition, span) in296            tcx.const_conditions(impl_m.def_id).instantiate_own_identity()297        {298            let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);299            let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);300301            let cause = ObligationCause::new(302                span,303                impl_m_def_id,304                ObligationCauseCode::CompareImplItem {305                    impl_item_def_id: impl_m_def_id,306                    trait_item_def_id: trait_m.def_id,307                    kind: impl_m.kind,308                },309            );310            ocx.register_obligation(traits::Obligation::new(311                tcx,312                cause,313                param_env,314                const_condition.to_host_effect_clause(tcx, ty::BoundConstness::Maybe),315            ));316        }317    }318319    // We now need to check that the signature of the impl method is320    // compatible with that of the trait method. We do this by321    // checking that `impl_fty <: trait_fty`.322    //323    // FIXME: We manually instantiate the trait method here as we need324    // to manually compute its implied bounds. Otherwise this could just325    // be `ocx.sub(impl_sig, trait_sig)`.326327    let mut wf_tys = FxIndexSet::default();328329    let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(330        impl_m_span,331        BoundRegionConversionTime::HigherRankedType,332        tcx.fn_sig(impl_m.def_id).instantiate_identity().skip_norm_wip(),333    );334335    let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id);336    let impl_sig =337        ocx.normalize(&norm_cause, param_env, Unnormalized::new_wip(unnormalized_impl_sig));338    debug!(?impl_sig);339340    let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args).skip_norm_wip();341    let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);342343    // Next, add all inputs and output as well-formed tys. Importantly,344    // we have to do this before normalization, since the normalized ty may345    // not contain the input parameters. See issue #87748.346    wf_tys.extend(trait_sig.inputs_and_output.iter());347    let trait_sig = ocx.normalize(&norm_cause, param_env, Unnormalized::new_wip(trait_sig));348    // We also have to add the normalized trait signature349    // as we don't normalize during implied bounds computation.350    wf_tys.extend(trait_sig.inputs_and_output.iter());351    debug!(?trait_sig);352353    // FIXME: We'd want to keep more accurate spans than "the method signature" when354    // processing the comparison between the trait and impl fn, but we sadly lose them355    // and point at the whole signature when a trait bound or specific input or output356    // type would be more appropriate. In other places we have a `Vec<Span>`357    // corresponding to their `Vec<Predicate>`, but we don't have that here.358    // Fixing this would improve the output of test `issue-83765.rs`.359    // There's the same issue in compare_eii code.360    let result = ocx.sup(&cause, param_env, trait_sig, impl_sig);361362    if let Err(terr) = result {363        debug!(?impl_sig, ?trait_sig, ?terr, "sub_types failed");364365        let emitted = report_trait_method_mismatch(366            infcx,367            cause,368            param_env,369            terr,370            (trait_m, trait_sig),371            (impl_m, impl_sig),372            impl_trait_ref,373        );374        return Err(emitted);375    }376377    if !(impl_sig, trait_sig).references_error() {378        for ty in unnormalized_impl_sig.inputs_and_output {379            ocx.register_obligation(traits::Obligation::new(380                infcx.tcx,381                cause.clone(),382                param_env,383                ty::ClauseKind::WellFormed(ty.into()),384            ));385        }386    }387388    // Check that all obligations are satisfied by the implementation's389    // version.390    let errors = ocx.evaluate_obligations_error_on_ambiguity();391    if !errors.is_empty() {392        let reported = infcx.err_ctxt().report_fulfillment_errors(errors);393        return Err(reported);394    }395396    // Finally, resolve all regions. This catches wily misuses of397    // lifetime parameters.398    let errors = infcx.resolve_regions(impl_m_def_id, param_env, wf_tys);399    if !errors.is_empty() {400        return Err(infcx401            .tainted_by_errors()402            .unwrap_or_else(|| infcx.err_ctxt().report_region_errors(impl_m_def_id, &errors)));403    }404405    Ok(())406}407408struct RemapLateParam<'tcx> {409    tcx: TyCtxt<'tcx>,410    mapping: FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>,411}412413impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'tcx> {414    fn cx(&self) -> TyCtxt<'tcx> {415        self.tcx416    }417418    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {419        if let ty::ReLateParam(fr) = r.kind() {420            ty::Region::new_late_param(421                self.tcx,422                fr.scope,423                self.mapping.get(&fr.kind).copied().unwrap_or(fr.kind),424            )425        } else {426            r427        }428    }429}430431/// Given a method def-id in an impl, compare the method signature of the impl432/// against the trait that it's implementing. In doing so, infer the hidden types433/// that this method's signature provides to satisfy each return-position `impl Trait`434/// in the trait signature.435///436/// The method is also responsible for making sure that the hidden types for each437/// RPITIT actually satisfy the bounds of the `impl Trait`, i.e. that if we infer438/// `impl Trait = Foo`, that `Foo: Trait` holds.439///440/// For example, given the sample code:441///442/// ```443/// use std::ops::Deref;444///445/// trait Foo {446///     fn bar() -> impl Deref<Target = impl Sized>;447///     //          ^- RPITIT #1        ^- RPITIT #2448/// }449///450/// impl Foo for () {451///     fn bar() -> Box<String> { Box::new(String::new()) }452/// }453/// ```454///455/// The hidden types for the RPITITs in `bar` would be inferred to:456///     * `impl Deref` (RPITIT #1) = `Box<String>`457///     * `impl Sized` (RPITIT #2) = `String`458///459/// The relationship between these two types is straightforward in this case, but460/// may be more tenuously connected via other `impl`s and normalization rules for461/// cases of more complicated nested RPITITs.462#[instrument(skip(tcx), level = "debug", ret)]463pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(464    tcx: TyCtxt<'tcx>,465    impl_m_def_id: LocalDefId,466) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> {467    let impl_m = tcx.associated_item(impl_m_def_id.to_def_id());468    let trait_m = tcx.associated_item(impl_m.expect_trait_impl()?);469    let impl_trait_ref = tcx470        .impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id()))471        .instantiate_identity()472        .skip_norm_wip();473    // First, check a few of the same things as `compare_impl_method`,474    // just so we don't ICE during instantiation later.475    check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;476477    let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id);478    let return_span = tcx.hir_fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();479    let cause = ObligationCause::new(480        return_span,481        impl_m_def_id,482        ObligationCauseCode::CompareImplItem {483            impl_item_def_id: impl_m_def_id,484            trait_item_def_id: trait_m.def_id,485            kind: impl_m.kind,486        },487    );488489    // Create mapping from trait to impl (i.e. impl trait header + impl method identity args).490    let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(491        tcx,492        impl_m.container_id(tcx),493        impl_trait_ref.args,494    );495496    let hybrid_preds = tcx497        .predicates_of(impl_m.container_id(tcx))498        .instantiate_identity(tcx)499        .into_iter()500        .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args))501        .map(|(clause, _)| clause.skip_norm_wip());502    let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds));503    let param_env = traits::normalize_param_env_or_error(504        tcx,505        param_env,506        ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id),507    );508509    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());510    let ocx = ObligationCtxt::new_with_diagnostics(infcx);511512    // Check that the where clauses of the impl are satisfied by the hybrid param env.513    // You might ask -- what does this have to do with RPITIT inference? Nothing.514    // We check these because if the where clauses of the signatures do not match515    // up, then we don't want to give spurious other errors that point at the RPITITs.516    // They're not necessary to check, though, because we already check them in517    // `compare_method_predicate_entailment`.518    let impl_m_own_bounds = tcx.predicates_of(impl_m_def_id).instantiate_own_identity();519    for (predicate, span) in impl_m_own_bounds {520        let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);521        let predicate = ocx.normalize(&normalize_cause, param_env, predicate);522523        let cause = ObligationCause::new(524            span,525            impl_m_def_id,526            ObligationCauseCode::CompareImplItem {527                impl_item_def_id: impl_m_def_id,528                trait_item_def_id: trait_m.def_id,529                kind: impl_m.kind,530            },531        );532        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));533    }534535    // Normalize the impl signature with fresh variables for lifetime inference.536    let misc_cause = ObligationCause::misc(return_span, impl_m_def_id);537    let impl_sig = ocx.normalize(538        &misc_cause,539        param_env,540        Unnormalized::new_wip(infcx.instantiate_binder_with_fresh_vars(541            return_span,542            BoundRegionConversionTime::HigherRankedType,543            tcx.fn_sig(impl_m.def_id).instantiate_identity().skip_norm_wip(),544        )),545    );546    impl_sig.error_reported()?;547    let impl_return_ty = impl_sig.output();548549    // Normalize the trait signature with liberated bound vars, passing it through550    // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces551    // them with inference variables.552    // We will use these inference variables to collect the hidden types of RPITITs.553    let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_def_id);554    let unnormalized_trait_sig = tcx555        .liberate_late_bound_regions(556            impl_m.def_id,557            tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args).skip_norm_wip(),558        )559        .fold_with(&mut collector);560561    let trait_sig =562        ocx.normalize(&misc_cause, param_env, Unnormalized::new_wip(unnormalized_trait_sig));563    trait_sig.error_reported()?;564    let trait_return_ty = trait_sig.output();565566    // RPITITs are allowed to use the implied predicates of the method that567    // defines them. This is because we want code like:568    // ```569    // trait Foo {570    //     fn test<'a, T>(_: &'a T) -> impl Sized;571    // }572    // impl Foo for () {573    //     fn test<'a, T>(x: &'a T) -> &'a T { x }574    // }575    // ```576    // .. to compile. However, since we use both the normalized and unnormalized577    // inputs and outputs from the instantiated trait signature, we will end up578    // seeing the hidden type of an RPIT in the signature itself. Naively, this579    // means that we will use the hidden type to imply the hidden type's own580    // well-formedness.581    //582    // To avoid this, we replace the infer vars used for hidden type inference583    // with placeholders, which imply nothing about outlives bounds, and then584    // prove below that the hidden types are well formed.585    let universe = infcx.create_next_universe();586    let mut idx = ty::BoundVar::ZERO;587    let mapping: FxIndexMap<_, _> = collector588        .types589        .iter()590        .map(|(_, &(ty, _))| {591            assert!(592                infcx.resolve_vars_if_possible(ty) == ty && ty.is_ty_var(),593                "{ty:?} should not have been constrained via normalization",594                ty = infcx.resolve_vars_if_possible(ty)595            );596            idx += 1;597            (598                ty,599                Ty::new_placeholder(600                    tcx,601                    ty::PlaceholderType::new(602                        universe,603                        ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon },604                    ),605                ),606            )607        })608        .collect();609    let mut type_mapper = BottomUpFolder {610        tcx,611        ty_op: |ty| *mapping.get(&ty).unwrap_or(&ty),612        lt_op: |lt| lt,613        ct_op: |ct| ct,614    };615    let wf_tys = FxIndexSet::from_iter(616        unnormalized_trait_sig617            .inputs_and_output618            .iter()619            .chain(trait_sig.inputs_and_output.iter())620            .map(|ty| ty.fold_with(&mut type_mapper)),621    );622623    match ocx.eq(&cause, param_env, trait_return_ty, impl_return_ty) {624        Ok(()) => {}625        Err(terr) => {626            let mut diag = struct_span_code_err!(627                tcx.dcx(),628                cause.span,629                E0053,630                "method `{}` has an incompatible return type for trait",631                trait_m.name()632            );633            infcx.err_ctxt().note_type_err(634                &mut diag,635                &cause,636                tcx.hir_get_if_local(impl_m.def_id)637                    .and_then(|node| node.fn_decl())638                    .map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)),639                Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {640                    expected: trait_return_ty.into(),641                    found: impl_return_ty.into(),642                }))),643                terr,644                false,645                None,646            );647            return Err(diag.emit());648        }649    }650651    debug!(?trait_sig, ?impl_sig, "equating function signatures");652653    // Unify the whole function signature. We need to do this to fully infer654    // the lifetimes of the return type, but do this after unifying just the655    // return types, since we want to avoid duplicating errors from656    // `compare_method_predicate_entailment`.657    match ocx.eq(&cause, param_env, trait_sig, impl_sig) {658        Ok(()) => {}659        Err(terr) => {660            // This function gets called during `compare_method_predicate_entailment` when normalizing a661            // signature that contains RPITIT. When the method signatures don't match, we have to662            // emit an error now because `compare_method_predicate_entailment` will not report the error663            // when normalization fails.664            let emitted = report_trait_method_mismatch(665                infcx,666                cause,667                param_env,668                terr,669                (trait_m, trait_sig),670                (impl_m, impl_sig),671                impl_trait_ref,672            );673            return Err(emitted);674        }675    }676677    if !unnormalized_trait_sig.output().references_error() && collector.types.is_empty() {678        tcx.dcx().delayed_bug(679            "expect >0 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`",680        );681    }682683    // FIXME: This has the same issue as #108544, but since this isn't breaking684    // existing code, I'm not particularly inclined to do the same hack as above685    // where we process wf obligations manually. This can be fixed in a forward-686    // compatible way later.687    let collected_types = collector.types;688    for (_, &(ty, _)) in &collected_types {689        ocx.register_obligation(traits::Obligation::new(690            tcx,691            misc_cause.clone(),692            param_env,693            ty::ClauseKind::WellFormed(ty.into()),694        ));695    }696697    // Check that all obligations are satisfied by the implementation's698    // RPITs.699    let errors = ocx.evaluate_obligations_error_on_ambiguity();700    if !errors.is_empty() {701        if let Err(guar) = try_report_async_mismatch(tcx, infcx, &errors, trait_m, impl_m, impl_sig)702        {703            return Err(guar);704        }705706        let guar = infcx.err_ctxt().report_fulfillment_errors(errors);707        return Err(guar);708    }709710    // Finally, resolve all regions. This catches wily misuses of711    // lifetime parameters.712    ocx.resolve_regions_and_report_errors(impl_m_def_id, param_env, wf_tys)?;713714    let mut remapped_types = DefIdMap::default();715    for (def_id, (ty, args)) in collected_types {716        match infcx.fully_resolve(ty) {717            Ok(ty) => {718                // `ty` contains free regions that we created earlier while liberating the719                // trait fn signature. However, projection normalization expects `ty` to720                // contains `def_id`'s early-bound regions.721                let id_args = GenericArgs::identity_for_item(tcx, def_id);722                debug!(?id_args, ?args);723                let map: FxIndexMap<_, _> = std::iter::zip(args, id_args)724                    .skip(tcx.generics_of(trait_m.def_id).count())725                    .filter_map(|(a, b)| Some((a.as_region()?, b.as_region()?)))726                    .collect();727                debug!(?map);728729                // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound730                // region args that are synthesized during AST lowering. These are args731                // that are appended to the parent args (trait and trait method). However,732                // we're trying to infer the uninstantiated type value of the RPITIT inside733                // the *impl*, so we can later use the impl's method args to normalize734                // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).735                //736                // Due to the design of RPITITs, during AST lowering, we have no idea that737                // an impl method corresponds to a trait method with RPITITs in it. Therefore,738                // we don't have a list of early-bound region args for the RPITIT in the impl.739                // Since early region parameters are index-based, we can't just rebase these740                // (trait method) early-bound region args onto the impl, and there's no741                // guarantee that the indices from the trait args and impl args line up.742                // So to fix this, we subtract the number of trait args and add the number of743                // impl args to *renumber* these early-bound regions to their corresponding744                // indices in the impl's generic parameters list.745                //746                // Also, we only need to account for a difference in trait and impl args,747                // since we previously enforce that the trait method and impl method have the748                // same generics.749                let num_trait_args = impl_trait_ref.args.len();750                let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).own_params.len();751                let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions {752                    tcx,753                    map,754                    num_trait_args,755                    num_impl_args,756                    def_id,757                    impl_m_def_id: impl_m.def_id,758                    ty,759                    return_span,760                }) {761                    Ok(ty) => ty,762                    Err(guar) => Ty::new_error(tcx, guar),763                };764                remapped_types.insert(def_id, ty::EarlyBinder::bind(ty));765            }766            Err(err) => {767                // This code path is not reached in any tests, but may be768                // reachable. If this is triggered, it should be converted to769                // `span_delayed_bug` and the triggering case turned into a770                // test.771                tcx.dcx()772                    .span_bug(return_span, format!("could not fully resolve: {ty} => {err:?}"));773            }774        }775    }776777    // We may not collect all RPITITs that we see in the HIR for a trait signature778    // because an RPITIT was located within a missing item. Like if we have a sig779    // returning `-> Missing<impl Sized>`, that gets converted to `-> {type error}`,780    // and when walking through the signature we end up never collecting the def id781    // of the `impl Sized`. Insert that here, so we don't ICE later.782    for assoc_item in tcx.associated_types_for_impl_traits_in_associated_fn(trait_m.def_id) {783        if !remapped_types.contains_key(assoc_item) {784            remapped_types.insert(785                *assoc_item,786                ty::EarlyBinder::bind(Ty::new_error_with_message(787                    tcx,788                    return_span,789                    "missing synthetic item for RPITIT",790                )),791            );792        }793    }794795    Ok(&*tcx.arena.alloc(remapped_types))796}797798struct ImplTraitInTraitCollector<'a, 'tcx, E> {799    ocx: &'a ObligationCtxt<'a, 'tcx, E>,800    types: FxIndexMap<DefId, (Ty<'tcx>, ty::GenericArgsRef<'tcx>)>,801    span: Span,802    param_env: ty::ParamEnv<'tcx>,803    body_id: LocalDefId,804}805806impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E>807where808    E: 'tcx,809{810    fn new(811        ocx: &'a ObligationCtxt<'a, 'tcx, E>,812        span: Span,813        param_env: ty::ParamEnv<'tcx>,814        body_id: LocalDefId,815    ) -> Self {816        ImplTraitInTraitCollector { ocx, types: FxIndexMap::default(), span, param_env, body_id }817    }818}819820impl<'tcx, E> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx, E>821where822    E: 'tcx,823{824    fn cx(&self) -> TyCtxt<'tcx> {825        self.ocx.infcx.tcx826    }827828    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {829        if let &ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args: proj_args, .. }) =830            ty.kind()831            && self.cx().is_impl_trait_in_trait(def_id)832        {833            if let Some((ty, _)) = self.types.get(&def_id) {834                return *ty;835            }836            //FIXME(RPITIT): Deny nested RPITIT in args too837            if proj_args.has_escaping_bound_vars() {838                bug!("FIXME(RPITIT): error here");839            }840            // Replace with infer var841            let infer_ty = self.ocx.infcx.next_ty_var(self.span);842            self.types.insert(def_id, (infer_ty, proj_args));843            // Recurse into bounds844            for (pred, pred_span) in self845                .cx()846                .explicit_item_bounds(def_id)847                .iter_instantiated_copied(self.cx(), proj_args)848                .map(Unnormalized::skip_norm_wip)849            {850                let pred = pred.fold_with(self);851                let pred = self.ocx.normalize(852                    &ObligationCause::misc(self.span, self.body_id),853                    self.param_env,854                    Unnormalized::new_wip(pred),855                );856857                self.ocx.register_obligation(traits::Obligation::new(858                    self.cx(),859                    ObligationCause::new(860                        self.span,861                        self.body_id,862                        ObligationCauseCode::WhereClause(def_id, pred_span),863                    ),864                    self.param_env,865                    pred,866                ));867            }868            infer_ty869        } else {870            ty.super_fold_with(self)871        }872    }873}874875struct RemapHiddenTyRegions<'tcx> {876    tcx: TyCtxt<'tcx>,877    /// Map from early/late params of the impl to identity regions of the RPITIT (GAT)878    /// in the trait.879    map: FxIndexMap<ty::Region<'tcx>, ty::Region<'tcx>>,880    num_trait_args: usize,881    num_impl_args: usize,882    /// Def id of the RPITIT (GAT) in the *trait*.883    def_id: DefId,884    /// Def id of the impl method which owns the opaque hidden type we're remapping.885    impl_m_def_id: DefId,886    /// The hidden type we're remapping. Useful for diagnostics.887    ty: Ty<'tcx>,888    /// Span of the return type. Useful for diagnostics.889    return_span: Span,890}891892impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {893    type Error = ErrorGuaranteed;894895    fn cx(&self) -> TyCtxt<'tcx> {896        self.tcx897    }898899    fn try_fold_region(900        &mut self,901        region: ty::Region<'tcx>,902    ) -> Result<ty::Region<'tcx>, Self::Error> {903        match region.kind() {904            // Never remap bound regions or `'static`905            ty::ReBound(..) | ty::ReStatic | ty::ReError(_) => return Ok(region),906            // We always remap liberated late-bound regions from the function.907            ty::ReLateParam(_) => {}908            // Remap early-bound regions as long as they don't come from the `impl` itself,909            // in which case we don't really need to renumber them.910            ty::ReEarlyParam(ebr) => {911                if ebr.index as usize >= self.num_impl_args {912                    // Remap913                } else {914                    return Ok(region);915                }916            }917            ty::ReVar(_) | ty::RePlaceholder(_) | ty::ReErased => unreachable!(918                "should not have leaked vars or placeholders into hidden type of RPITIT"919            ),920        }921922        let e = if let Some(id_region) = self.map.get(&region) {923            if let ty::ReEarlyParam(e) = id_region.kind() {924                e925            } else {926                bug!(927                    "expected to map region {region} to early-bound identity region, but got {id_region}"928                );929            }930        } else {931            let guar = match region.opt_param_def_id(self.tcx, self.impl_m_def_id) {932                Some(def_id) => {933                    let return_span = if let &ty::Alias(ty::AliasTy {934                        kind: ty::Opaque { def_id: opaque_ty_def_id },935                        ..936                    }) = self.ty.kind()937                    {938                        self.tcx.def_span(opaque_ty_def_id)939                    } else {940                        self.return_span941                    };942                    self.tcx943                        .dcx()944                        .struct_span_err(945                            return_span,946                            "return type captures more lifetimes than trait definition",947                        )948                        .with_span_label(self.tcx.def_span(def_id), "this lifetime was captured")949                        .with_span_note(950                            self.tcx.def_span(self.def_id),951                            "hidden type must only reference lifetimes captured by this impl trait",952                        )953                        .with_note(format!("hidden type inferred to be `{}`", self.ty))954                        .emit()955                }956                None => {957                    // This code path is not reached in any tests, but may be958                    // reachable. If this is triggered, it should be converted959                    // to `delayed_bug` and the triggering case turned into a960                    // test.961                    self.tcx.dcx().bug("should've been able to remap region");962                }963            };964            return Err(guar);965        };966967        Ok(ty::Region::new_early_param(968            self.tcx,969            ty::EarlyParamRegion {970                name: e.name,971                index: (e.index as usize - self.num_trait_args + self.num_impl_args) as u32,972            },973        ))974    }975}976977/// Gets the string for an explicit self declaration, e.g. "self", "&self",978/// etc.979fn get_self_string<'tcx, P>(self_arg_ty: Ty<'tcx>, is_self_ty: P) -> String980where981    P: Fn(Ty<'tcx>) -> bool,982{983    if is_self_ty(self_arg_ty) {984        "self".to_owned()985    } else if let ty::Ref(_, ty, mutbl) = self_arg_ty.kind()986        && is_self_ty(*ty)987    {988        match mutbl {989            hir::Mutability::Not => "&self".to_owned(),990            hir::Mutability::Mut => "&mut self".to_owned(),991        }992    } else {993        format!("self: {self_arg_ty}")994    }995}996997fn report_trait_method_mismatch<'tcx>(998    infcx: &InferCtxt<'tcx>,999    mut cause: ObligationCause<'tcx>,1000    param_env: ty::ParamEnv<'tcx>,1001    terr: TypeError<'tcx>,1002    (trait_m, trait_sig): (ty::AssocItem, ty::FnSig<'tcx>),1003    (impl_m, impl_sig): (ty::AssocItem, ty::FnSig<'tcx>),1004    impl_trait_ref: ty::TraitRef<'tcx>,1005) -> ErrorGuaranteed {1006    let tcx = infcx.tcx;1007    let (impl_err_span, trait_err_span) =1008        extract_spans_for_error_reporting(infcx, terr, &cause, impl_m, trait_m);10091010    let mut diag = struct_span_code_err!(1011        tcx.dcx(),1012        impl_err_span,1013        E0053,1014        "method `{}` has an incompatible type for trait",1015        trait_m.name()1016    );1017    match &terr {1018        TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)1019            if trait_m.is_method() =>1020        {1021            let ty = trait_sig.inputs()[0];1022            let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());10231024            // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the1025            // span points only at the type `Box<Self`>, but we want to cover the whole1026            // argument pattern and type.1027            let (sig, body) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();1028            let span = tcx1029                .hir_body_param_idents(body)1030                .zip(sig.decl.inputs.iter())1031                .map(|(param_ident, ty)| {1032                    if let Some(param_ident) = param_ident {1033                        param_ident.span.to(ty.span)1034                    } else {1035                        ty.span1036                    }1037                })1038                .next()1039                .unwrap_or(impl_err_span);10401041            diag.span_suggestion_verbose(1042                span,1043                "change the self-receiver type to match the trait",1044                sugg,1045                Applicability::MachineApplicable,1046            );1047        }1048        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {1049            if trait_sig.inputs().len() == *i {1050                // Suggestion to change output type. We do not suggest in `async` functions1051                // to avoid complex logic or incorrect output.1052                if let ImplItemKind::Fn(sig, _) =1053                    &tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).kind1054                    && !sig.header.asyncness.is_async()1055                {1056                    let msg = "change the output type to match the trait";1057                    let ap = Applicability::MachineApplicable;1058                    match sig.decl.output {1059                        hir::FnRetTy::DefaultReturn(sp) => {1060                            let sugg = format!(" -> {}", trait_sig.output());1061                            diag.span_suggestion_verbose(sp, msg, sugg, ap);1062                        }1063                        hir::FnRetTy::Return(hir_ty) => {1064                            let sugg = trait_sig.output();1065                            diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap);1066                        }1067                    };1068                };1069            } else if let Some(trait_ty) = trait_sig.inputs().get(*i) {1070                diag.span_suggestion_verbose(1071                    impl_err_span,1072                    "change the parameter type to match the trait",1073                    trait_ty,1074                    Applicability::MachineApplicable,1075                );1076            }1077        }1078        _ => {}1079    }10801081    cause.span = impl_err_span;1082    infcx.err_ctxt().note_type_err(1083        &mut diag,1084        &cause,1085        trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)),1086        Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {1087            expected: ty::Binder::dummy(trait_sig),1088            found: ty::Binder::dummy(impl_sig),1089        }))),1090        terr,1091        false,1092        None,1093    );10941095    diag.emit()1096}10971098fn check_region_bounds_on_impl_item<'tcx>(1099    tcx: TyCtxt<'tcx>,1100    impl_m: ty::AssocItem,1101    trait_m: ty::AssocItem,1102    delay: bool,1103) -> Result<(), ErrorGuaranteed> {1104    let impl_generics = tcx.generics_of(impl_m.def_id);1105    let impl_params = impl_generics.own_counts().lifetimes;11061107    let trait_generics = tcx.generics_of(trait_m.def_id);1108    let trait_params = trait_generics.own_counts().lifetimes;11091110    let Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span }) =1111        check_number_of_early_bound_regions(1112            tcx,1113            impl_m.def_id.expect_local(),1114            trait_m.def_id,1115            impl_generics,1116            impl_params,1117            trait_generics,1118            trait_params,1119        )1120    else {1121        return Ok(());1122    };11231124    if !delay && let Some(guar) = check_region_late_boundedness(tcx, impl_m, trait_m) {1125        return Err(guar);1126    }11271128    let reported = tcx1129        .dcx()1130        .create_err(LifetimesOrBoundsMismatchOnTrait {1131            span,1132            item_kind: impl_m.descr(),1133            ident: impl_m.ident(tcx),1134            generics_span,1135            bounds_span,1136            where_span,1137        })1138        .emit_unless_delay(delay);11391140    Err(reported)1141}11421143pub(super) struct CheckNumberOfEarlyBoundRegionsError {1144    pub(super) span: Span,1145    pub(super) generics_span: Span,1146    pub(super) bounds_span: Vec<Span>,1147    pub(super) where_span: Option<Span>,1148}11491150pub(super) fn check_number_of_early_bound_regions<'tcx>(1151    tcx: TyCtxt<'tcx>,1152    impl_def_id: LocalDefId,1153    trait_def_id: DefId,1154    impl_generics: &Generics,1155    impl_params: usize,1156    trait_generics: &Generics,1157    trait_params: usize,1158) -> Result<(), CheckNumberOfEarlyBoundRegionsError> {1159    debug!(?trait_generics, ?impl_generics);11601161    // Must have same number of early-bound lifetime parameters.1162    // Unfortunately, if the user screws up the bounds, then this1163    // will change classification between early and late. E.g.,1164    // if in trait we have `<'a,'b:'a>`, and in impl we just have1165    // `<'a,'b>`, then we have 2 early-bound lifetime parameters1166    // in trait but 0 in the impl. But if we report "expected 21167    // but found 0" it's confusing, because it looks like there1168    // are zero. Since I don't quite know how to phrase things at1169    // the moment, give a kind of vague error message.1170    if trait_params == impl_params {1171        return Ok(());1172    }11731174    let span = tcx1175        .hir_get_generics(impl_def_id)1176        .expect("expected impl item to have generics or else we can't compare them")1177        .span;11781179    let mut generics_span = tcx.def_span(trait_def_id);1180    let mut bounds_span = vec![];1181    let mut where_span = None;11821183    if let Some(trait_node) = tcx.hir_get_if_local(trait_def_id)1184        && let Some(trait_generics) = trait_node.generics()1185    {1186        generics_span = trait_generics.span;1187        // FIXME: we could potentially look at the impl's bounds to not point at bounds that1188        // *are* present in the impl.1189        for p in trait_generics.predicates {1190            match p.kind {1191                hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {1192                    bounds,1193                    ..1194                })1195                | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {1196                    bounds,1197                    ..1198                }) => {1199                    for b in *bounds {1200                        if let hir::GenericBound::Outlives(lt) = b {1201                            bounds_span.push(lt.ident.span);1202                        }1203                    }1204                }1205            }1206        }1207        if let Some(impl_node) = tcx.hir_get_if_local(impl_def_id.into())1208            && let Some(impl_generics) = impl_node.generics()1209        {1210            let mut impl_bounds = 0;1211            for p in impl_generics.predicates {1212                match p.kind {1213                    hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {1214                        bounds,1215                        ..1216                    })1217                    | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {1218                        bounds,1219                        ..1220                    }) => {1221                        for b in *bounds {1222                            if let hir::GenericBound::Outlives(_) = b {1223                                impl_bounds += 1;1224                            }1225                        }1226                    }1227                }1228            }1229            if impl_bounds == bounds_span.len() {1230                bounds_span = vec![];1231            } else if impl_generics.has_where_clause_predicates {1232                where_span = Some(impl_generics.where_clause_span);1233            }1234        }1235    }12361237    Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span })1238}12391240#[allow(unused)]1241enum LateEarlyMismatch<'tcx> {1242    EarlyInImpl(DefId, DefId, ty::Region<'tcx>),1243    LateInImpl(DefId, DefId, ty::Region<'tcx>),1244}12451246fn check_region_late_boundedness<'tcx>(1247    tcx: TyCtxt<'tcx>,1248    impl_m: ty::AssocItem,1249    trait_m: ty::AssocItem,1250) -> Option<ErrorGuaranteed> {1251    if !impl_m.is_fn() {1252        return None;1253    }12541255    let (infcx, param_env) = tcx1256        .infer_ctxt()1257        .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, impl_m.def_id));12581259    let impl_m_args = infcx.fresh_args_for_item(DUMMY_SP, impl_m.def_id);1260    let impl_m_sig = tcx.fn_sig(impl_m.def_id).instantiate(tcx, impl_m_args).skip_norm_wip();1261    let impl_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, impl_m_sig);12621263    let trait_m_args = infcx.fresh_args_for_item(DUMMY_SP, trait_m.def_id);1264    let trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_args).skip_norm_wip();1265    let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_m_sig);12661267    let ocx = ObligationCtxt::new(&infcx);12681269    // Equate the signatures so that we can infer whether a late-bound param was present where1270    // an early-bound param was expected, since we replace the late-bound lifetimes with1271    // `ReLateParam`, and early-bound lifetimes with infer vars, so the early-bound args will1272    // resolve to `ReLateParam` if there is a mismatch.1273    let Ok(()) = ocx.eq(1274        &ObligationCause::dummy(),1275        param_env,1276        ty::Binder::dummy(trait_m_sig),1277        ty::Binder::dummy(impl_m_sig),1278    ) else {1279        return None;1280    };12811282    let errors = ocx.try_evaluate_obligations();1283    if !errors.is_empty() {1284        return None;1285    }12861287    let mut mismatched = vec![];12881289    let impl_generics = tcx.generics_of(impl_m.def_id);1290    for (id_arg, arg) in1291        std::iter::zip(ty::GenericArgs::identity_for_item(tcx, impl_m.def_id), impl_m_args)1292    {1293        if let ty::GenericArgKind::Lifetime(r) = arg.kind()1294            && let ty::ReVar(vid) = r.kind()1295            && let r = infcx1296                .inner1297                .borrow_mut()1298                .unwrap_region_constraints()1299                .opportunistic_resolve_var(tcx, vid)1300            && let ty::ReLateParam(ty::LateParamRegion {1301                kind: ty::LateParamRegionKind::Named(trait_param_def_id),1302                ..1303            }) = r.kind()1304            && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind()1305        {1306            mismatched.push(LateEarlyMismatch::EarlyInImpl(1307                impl_generics.region_param(ebr, tcx).def_id,1308                trait_param_def_id,1309                id_arg.expect_region(),1310            ));1311        }1312    }13131314    let trait_generics = tcx.generics_of(trait_m.def_id);1315    for (id_arg, arg) in1316        std::iter::zip(ty::GenericArgs::identity_for_item(tcx, trait_m.def_id), trait_m_args)1317    {1318        if let ty::GenericArgKind::Lifetime(r) = arg.kind()1319            && let ty::ReVar(vid) = r.kind()1320            && let r = infcx1321                .inner1322                .borrow_mut()1323                .unwrap_region_constraints()1324                .opportunistic_resolve_var(tcx, vid)1325            && let ty::ReLateParam(ty::LateParamRegion {1326                kind: ty::LateParamRegionKind::Named(impl_param_def_id),1327                ..1328            }) = r.kind()1329            && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind()1330        {1331            mismatched.push(LateEarlyMismatch::LateInImpl(1332                impl_param_def_id,1333                trait_generics.region_param(ebr, tcx).def_id,1334                id_arg.expect_region(),1335            ));1336        }1337    }13381339    if mismatched.is_empty() {1340        return None;1341    }13421343    let spans: Vec<_> = mismatched1344        .iter()1345        .map(|param| {1346            let (LateEarlyMismatch::EarlyInImpl(impl_param_def_id, ..)1347            | LateEarlyMismatch::LateInImpl(impl_param_def_id, ..)) = *param;1348            tcx.def_span(impl_param_def_id)1349        })1350        .collect();13511352    let mut diag = tcx1353        .dcx()1354        .struct_span_err(spans, "lifetime parameters do not match the trait definition")1355        .with_note("lifetime parameters differ in whether they are early- or late-bound")1356        .with_code(E0195);1357    for mismatch in mismatched {1358        match mismatch {1359            LateEarlyMismatch::EarlyInImpl(1360                impl_param_def_id,1361                trait_param_def_id,1362                early_bound_region,1363            ) => {1364                let mut multispan = MultiSpan::from_spans(vec![1365                    tcx.def_span(impl_param_def_id),1366                    tcx.def_span(trait_param_def_id),1367                ]);1368                multispan1369                    .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl...");1370                multispan1371                    .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait...");1372                multispan.push_span_label(1373                    tcx.def_span(impl_param_def_id),1374                    format!("`{}` is early-bound", tcx.item_name(impl_param_def_id)),1375                );1376                multispan.push_span_label(1377                    tcx.def_span(trait_param_def_id),1378                    format!("`{}` is late-bound", tcx.item_name(trait_param_def_id)),1379                );1380                if let Some(span) =1381                    find_region_in_predicates(tcx, impl_m.def_id, early_bound_region)1382                {1383                    multispan.push_span_label(1384                        span,1385                        format!(1386                            "this lifetime bound makes `{}` early-bound",1387                            tcx.item_name(impl_param_def_id)1388                        ),1389                    );1390                }1391                diag.span_note(1392                    multispan,1393                    format!(1394                        "`{}` differs between the trait and impl",1395                        tcx.item_name(impl_param_def_id)1396                    ),1397                );1398            }1399            LateEarlyMismatch::LateInImpl(1400                impl_param_def_id,1401                trait_param_def_id,1402                early_bound_region,1403            ) => {1404                let mut multispan = MultiSpan::from_spans(vec![1405                    tcx.def_span(impl_param_def_id),1406                    tcx.def_span(trait_param_def_id),1407                ]);1408                multispan1409                    .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl...");1410                multispan1411                    .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait...");1412                multispan.push_span_label(1413                    tcx.def_span(impl_param_def_id),1414                    format!("`{}` is late-bound", tcx.item_name(impl_param_def_id)),1415                );1416                multispan.push_span_label(1417                    tcx.def_span(trait_param_def_id),1418                    format!("`{}` is early-bound", tcx.item_name(trait_param_def_id)),1419                );1420                if let Some(span) =1421                    find_region_in_predicates(tcx, trait_m.def_id, early_bound_region)1422                {1423                    multispan.push_span_label(1424                        span,1425                        format!(1426                            "this lifetime bound makes `{}` early-bound",1427                            tcx.item_name(trait_param_def_id)1428                        ),1429                    );1430                }1431                diag.span_note(1432                    multispan,1433                    format!(1434                        "`{}` differs between the trait and impl",1435                        tcx.item_name(impl_param_def_id)1436                    ),1437                );1438            }1439        }1440    }14411442    Some(diag.emit())1443}14441445fn find_region_in_predicates<'tcx>(1446    tcx: TyCtxt<'tcx>,1447    def_id: DefId,1448    early_bound_region: ty::Region<'tcx>,1449) -> Option<Span> {1450    for (pred, span) in tcx.explicit_predicates_of(def_id).instantiate_identity(tcx) {1451        if pred.skip_norm_wip().visit_with(&mut FindRegion(early_bound_region)).is_break() {1452            return Some(span);1453        }1454    }14551456    struct FindRegion<'tcx>(ty::Region<'tcx>);1457    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindRegion<'tcx> {1458        type Result = ControlFlow<()>;1459        fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {1460            if r == self.0 { ControlFlow::Break(()) } else { ControlFlow::Continue(()) }1461        }1462    }14631464    None1465}14661467#[instrument(level = "debug", skip(infcx))]1468fn extract_spans_for_error_reporting<'tcx>(1469    infcx: &infer::InferCtxt<'tcx>,1470    terr: TypeError<'_>,1471    cause: &ObligationCause<'tcx>,1472    impl_m: ty::AssocItem,1473    trait_m: ty::AssocItem,1474) -> (Span, Option<Span>) {1475    let tcx = infcx.tcx;1476    let mut impl_args = {1477        let (sig, _) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();1478        sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))1479    };14801481    let trait_args = trait_m.def_id.as_local().map(|def_id| {1482        let (sig, _) = tcx.hir_expect_trait_item(def_id).expect_fn();1483        sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))1484    });14851486    match terr {1487        TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {1488            (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))1489        }1490        _ => (cause.span, tcx.hir_span_if_local(trait_m.def_id)),1491    }1492}14931494fn compare_self_type<'tcx>(1495    tcx: TyCtxt<'tcx>,1496    impl_m: ty::AssocItem,1497    trait_m: ty::AssocItem,1498    impl_trait_ref: ty::TraitRef<'tcx>,1499    delay: bool,1500) -> Result<(), ErrorGuaranteed> {1501    // Try to give more informative error messages about self typing1502    // mismatches. Note that any mismatch will also be detected1503    // below, where we construct a canonical function type that1504    // includes the self parameter as a normal parameter. It's just1505    // that the error messages you get out of this code are a bit more1506    // inscrutable, particularly for cases where one method has no1507    // self.15081509    let self_string = |method: ty::AssocItem| {1510        let untransformed_self_ty = match method.container {1511            ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {1512                impl_trait_ref.self_ty()1513            }1514            ty::AssocContainer::Trait => tcx.types.self_param,1515        };1516        let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip().input(0);1517        let (infcx, param_env) = tcx1518            .infer_ctxt()1519            .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, method.def_id));1520        let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);1521        let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty);1522        get_self_string(self_arg_ty, can_eq_self)1523    };15241525    match (trait_m.is_method(), impl_m.is_method()) {1526        (false, false) | (true, true) => {}15271528        (false, true) => {1529            let self_descr = self_string(impl_m);1530            let impl_m_span = tcx.def_span(impl_m.def_id);1531            let mut err = struct_span_code_err!(1532                tcx.dcx(),1533                impl_m_span,1534                E0185,1535                "method `{}` has a `{}` declaration in the impl, but not in the trait",1536                trait_m.name(),1537                self_descr1538            );1539            err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));1540            if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {1541                err.span_label(span, format!("trait method declared without `{self_descr}`"));1542            } else {1543                err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));1544            }1545            return Err(err.emit_unless_delay(delay));1546        }15471548        (true, false) => {1549            let self_descr = self_string(trait_m);1550            let impl_m_span = tcx.def_span(impl_m.def_id);1551            let mut err = struct_span_code_err!(1552                tcx.dcx(),1553                impl_m_span,1554                E0186,1555                "method `{}` has a `{}` declaration in the trait, but not in the impl",1556                trait_m.name(),1557                self_descr1558            );1559            err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));1560            if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {1561                err.span_label(span, format!("`{self_descr}` used in trait"));1562            } else {1563                err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));1564            }15651566            return Err(err.emit_unless_delay(delay));1567        }1568    }15691570    Ok(())1571}15721573/// Checks that the number of generics on a given assoc item in a trait impl is the same1574/// as the number of generics on the respective assoc item in the trait definition.1575///1576/// For example this code emits the errors in the following code:1577/// ```rust,compile_fail1578/// trait Trait {1579///     fn foo();1580///     type Assoc<T>;1581/// }1582///1583/// impl Trait for () {1584///     fn foo<T>() {}1585///     //~^ error1586///     type Assoc = u32;1587///     //~^ error1588/// }1589/// ```1590///1591/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or1592/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in1593/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters1594fn compare_number_of_generics<'tcx>(1595    tcx: TyCtxt<'tcx>,1596    impl_: ty::AssocItem,1597    trait_: ty::AssocItem,1598    delay: bool,1599) -> Result<(), ErrorGuaranteed> {1600    let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();1601    let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();16021603    // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented1604    // in `compare_generic_param_kinds` which will give a nicer error message than something like:1605    // "expected 1 type parameter, found 0 type parameters"1606    if (trait_own_counts.types + trait_own_counts.consts)1607        == (impl_own_counts.types + impl_own_counts.consts)1608    {1609        return Ok(());1610    }16111612    // We never need to emit a separate error for RPITITs, since if an RPITIT1613    // has mismatched type or const generic arguments, then the method that it's1614    // inheriting the generics from will also have mismatched arguments, and1615    // we'll report an error for that instead. Delay a bug for safety, though.1616    if trait_.is_impl_trait_in_trait() {1617        // FIXME: no tests trigger this. If you find example code that does1618        // trigger this, please add it to the test suite.1619        tcx.dcx()1620            .bug("errors comparing numbers of generics of trait/impl functions were not emitted");1621    }16221623    let matchings = [1624        ("type", trait_own_counts.types, impl_own_counts.types),1625        ("const", trait_own_counts.consts, impl_own_counts.consts),1626    ];16271628    let item_kind = impl_.descr();16291630    let mut err_occurred = None;1631    for (kind, trait_count, impl_count) in matchings {1632        if impl_count != trait_count {1633            let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {1634                let mut spans = generics1635                    .params1636                    .iter()1637                    .filter(|p| match p.kind {1638                        hir::GenericParamKind::Lifetime {1639                            kind: hir::LifetimeParamKind::Elided(_),1640                        } => {1641                            // A fn can have an arbitrary number of extra elided lifetimes for the1642                            // same signature.1643                            !item.is_fn()1644                        }1645                        _ => true,1646                    })1647                    .map(|p| p.span)1648                    .collect::<Vec<Span>>();1649                if spans.is_empty() {1650                    spans = vec![generics.span]1651                }1652                spans1653            };1654            let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {1655                let trait_item = tcx.hir_expect_trait_item(def_id);1656                let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);1657                let impl_trait_spans: Vec<Span> = trait_item1658                    .generics1659                    .params1660                    .iter()1661                    .filter_map(|p| match p.kind {1662                        GenericParamKind::Type { synthetic: true, .. } => Some(p.span),1663                        _ => None,1664                    })1665                    .collect();1666                (Some(arg_spans), impl_trait_spans)1667            } else {1668                let trait_span = tcx.hir_span_if_local(trait_.def_id);1669                (trait_span.map(|s| vec![s]), vec![])1670            };16711672            let impl_item = tcx.hir_expect_impl_item(impl_.def_id.expect_local());1673            let impl_item_impl_trait_spans: Vec<Span> = impl_item1674                .generics1675                .params1676                .iter()1677                .filter_map(|p| match p.kind {1678                    GenericParamKind::Type { synthetic: true, .. } => Some(p.span),1679                    _ => None,1680                })1681                .collect();1682            let spans = arg_spans(&impl_, impl_item.generics);1683            let span = spans.first().copied();16841685            let mut err = tcx.dcx().struct_span_err(1686                spans,1687                format!(1688                    "{} `{}` has {} {kind} parameter{} but its trait \1689                     declaration has {} {kind} parameter{}",1690                    item_kind,1691                    trait_.name(),1692                    impl_count,1693                    pluralize!(impl_count),1694                    trait_count,1695                    pluralize!(trait_count),1696                    kind = kind,1697                ),1698            );1699            err.code(E0049);17001701            let msg =1702                format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),);1703            if let Some(spans) = trait_spans {1704                let mut spans = spans.iter();1705                if let Some(span) = spans.next() {1706                    err.span_label(*span, msg);1707                }1708                for span in spans {1709                    err.span_label(*span, "");1710                }1711            } else {1712                err.span_label(tcx.def_span(trait_.def_id), msg);1713            }17141715            if let Some(span) = span {1716                err.span_label(1717                    span,1718                    format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),),1719                );1720            }17211722            for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {1723                err.span_label(*span, "`impl Trait` introduces an implicit type parameter");1724            }17251726            let reported = err.emit_unless_delay(delay);1727            err_occurred = Some(reported);1728        }1729    }17301731    if let Some(reported) = err_occurred { Err(reported) } else { Ok(()) }1732}17331734fn compare_number_of_method_arguments<'tcx>(1735    tcx: TyCtxt<'tcx>,1736    impl_m: ty::AssocItem,1737    trait_m: ty::AssocItem,1738    delay: bool,1739) -> Result<(), ErrorGuaranteed> {1740    let impl_m_fty = tcx.fn_sig(impl_m.def_id);1741    let trait_m_fty = tcx.fn_sig(trait_m.def_id);1742    let trait_number_args = trait_m_fty.skip_binder().inputs().skip_binder().len();1743    let impl_number_args = impl_m_fty.skip_binder().inputs().skip_binder().len();17441745    if trait_number_args != impl_number_args {1746        let trait_span = trait_m1747            .def_id1748            .as_local()1749            .and_then(|def_id| {1750                let (trait_m_sig, _) = &tcx.hir_expect_trait_item(def_id).expect_fn();1751                let pos = trait_number_args.saturating_sub(1);1752                trait_m_sig.decl.inputs.get(pos).map(|arg| {1753                    if pos == 0 {1754                        arg.span1755                    } else {1756                        arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())1757                    }1758                })1759            })1760            .or_else(|| tcx.hir_span_if_local(trait_m.def_id));17611762        let (impl_m_sig, _) = &tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();1763        let pos = impl_number_args.saturating_sub(1);1764        let impl_span = impl_m_sig1765            .decl1766            .inputs1767            .get(pos)1768            .map(|arg| {1769                if pos == 0 {1770                    arg.span1771                } else {1772                    arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())1773                }1774            })1775            .unwrap_or_else(|| tcx.def_span(impl_m.def_id));17761777        let mut err = struct_span_code_err!(1778            tcx.dcx(),1779            impl_span,1780            E0050,1781            "method `{}` has {} but the declaration in trait `{}` has {}",1782            trait_m.name(),1783            potentially_plural_count(impl_number_args, "parameter"),1784            tcx.def_path_str(trait_m.def_id),1785            trait_number_args1786        );17871788        if let Some(trait_span) = trait_span {1789            err.span_label(1790                trait_span,1791                format!(1792                    "trait requires {}",1793                    potentially_plural_count(trait_number_args, "parameter")1794                ),1795            );1796        } else {1797            err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));1798        }17991800        err.span_label(1801            impl_span,1802            format!(1803                "expected {}, found {}",1804                potentially_plural_count(trait_number_args, "parameter"),1805                impl_number_args1806            ),1807        );18081809        // Only emit verbose suggestions when the trait span isn’t local (e.g., cross-crate).1810        if !trait_m.def_id.is_local() {1811            let trait_sig = tcx.fn_sig(trait_m.def_id);1812            let trait_arg_idents = tcx.fn_arg_idents(trait_m.def_id);1813            let sm = tcx.sess.source_map();1814            // Find the span of the space between the parentheses in a method.1815            // fn foo(...) {}1816            //        ^^^1817            let impl_inputs_span = if let (Some(first), Some(last)) =1818                (impl_m_sig.decl.inputs.first(), impl_m_sig.decl.inputs.last())1819            {1820                // We have inputs; construct the span from those.1821                // fn foo( a: i32, b: u32 ) {}1822                //        ^^^^^^^^^^^^^^^^1823                let arg_idents = tcx.fn_arg_idents(impl_m.def_id);1824                let first_lo = arg_idents1825                    .get(0)1826                    .and_then(|id| id.map(|id| id.span.lo()))1827                    .unwrap_or(first.span.lo());1828                Some(impl_m_sig.span.with_lo(first_lo).with_hi(last.span.hi()))1829            } else {1830                // We have no inputs; construct the span to the left of the last parenthesis1831                // fn foo( ) {}1832                //        ^1833                // FIXME: Keep spans for function parentheses around to make this more robust.1834                sm.span_to_snippet(impl_m_sig.span).ok().and_then(|s| {1835                    let right_paren = s.as_bytes().iter().rposition(|&b| b == b')')?;1836                    let pos = impl_m_sig.span.lo() + BytePos(right_paren as u32);1837                    Some(impl_m_sig.span.with_lo(pos).with_hi(pos))1838                })1839            };1840            let suggestion = match trait_number_args.cmp(&impl_number_args) {1841                Ordering::Greater => {1842                    // Span is right before the end parenthesis:1843                    // fn foo(a: i32 ) {}1844                    //              ^1845                    let trait_inputs = trait_sig.skip_binder().inputs().skip_binder();1846                    let missing = trait_inputs1847                        .iter()1848                        .enumerate()1849                        .skip(impl_number_args)1850                        .map(|(idx, ty)| {1851                            let name = trait_arg_idents1852                                .get(idx)1853                                .and_then(|ident| *ident)1854                                .map(|ident| ident.to_string())1855                                .unwrap_or_else(|| "_".to_string());1856                            format!("{name}: {ty}")1857                        })1858                        .collect::<Vec<_>>();18591860                    if missing.is_empty() {1861                        None1862                    } else {1863                        impl_inputs_span.map(|s| {1864                            let span = s.shrink_to_hi();1865                            let prefix = if impl_number_args == 0 { "" } else { ", " };1866                            let replacement = format!("{prefix}{}", missing.join(", "));1867                            (1868                                span,1869                                format!(1870                                    "add the missing parameter{} from the trait",1871                                    pluralize!(trait_number_args - impl_number_args)1872                                ),1873                                replacement,1874                            )1875                        })1876                    }1877                }1878                Ordering::Less => impl_inputs_span.and_then(|full| {1879                    // Span of the arguments that there are too many of:1880                    // fn foo(a: i32, b: u32) {}1881                    //              ^^^^^^^^1882                    let lo = if trait_number_args == 0 {1883                        full.lo()1884                    } else {1885                        impl_m_sig1886                            .decl1887                            .inputs1888                            .get(trait_number_args - 1)1889                            .map(|arg| arg.span.hi())?1890                    };1891                    let span = full.with_lo(lo);1892                    Some((1893                        span,1894                        format!(1895                            "remove the extra parameter{} to match the trait",1896                            pluralize!(impl_number_args - trait_number_args)1897                        ),1898                        String::new(),1899                    ))1900                }),1901                Ordering::Equal => unreachable!(),1902            };1903            if let Some((span, msg, replacement)) = suggestion {1904                err.span_suggestion_verbose(span, msg, replacement, Applicability::MaybeIncorrect);1905            }1906        }19071908        return Err(err.emit_unless_delay(delay));1909    }19101911    Ok(())1912}19131914fn compare_synthetic_generics<'tcx>(1915    tcx: TyCtxt<'tcx>,1916    impl_m: ty::AssocItem,1917    trait_m: ty::AssocItem,1918    delay: bool,1919) -> Result<(), ErrorGuaranteed> {1920    // FIXME(chrisvittal) Clean up this function, list of FIXME items:1921    //     1. Better messages for the span labels1922    //     2. Explanation as to what is going on1923    // If we get here, we already have the same number of generics, so the zip will1924    // be okay.1925    let mut error_found = None;1926    let impl_m_generics = tcx.generics_of(impl_m.def_id);1927    let trait_m_generics = tcx.generics_of(trait_m.def_id);1928    let impl_m_type_params =1929        impl_m_generics.own_params.iter().filter_map(|param| match param.kind {1930            GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),1931            GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,1932        });1933    let trait_m_type_params =1934        trait_m_generics.own_params.iter().filter_map(|param| match param.kind {1935            GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),1936            GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,1937        });1938    for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in1939        iter::zip(impl_m_type_params, trait_m_type_params)1940    {1941        if impl_synthetic != trait_synthetic {1942            let impl_def_id = impl_def_id.expect_local();1943            let impl_span = tcx.def_span(impl_def_id);1944            let trait_span = tcx.def_span(trait_def_id);1945            let mut err = struct_span_code_err!(1946                tcx.dcx(),1947                impl_span,1948                E0643,1949                "method `{}` has incompatible signature for trait",1950                trait_m.name()1951            );1952            err.span_label(trait_span, "declaration in trait here");1953            if impl_synthetic {1954                // The case where the impl method uses `impl Trait` but the trait method uses1955                // explicit generics1956                err.span_label(impl_span, "expected generic parameter, found `impl Trait`");1957                try {1958                    // try taking the name from the trait impl1959                    // FIXME: this is obviously suboptimal since the name can already be used1960                    // as another generic argument1961                    let new_name = tcx.opt_item_name(trait_def_id)?;1962                    let trait_m = trait_m.def_id.as_local()?;1963                    let trait_m = tcx.hir_expect_trait_item(trait_m);19641965                    let impl_m = impl_m.def_id.as_local()?;1966                    let impl_m = tcx.hir_expect_impl_item(impl_m);19671968                    // in case there are no generics, take the spot between the function name1969                    // and the opening paren of the argument list1970                    let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();1971                    // in case there are generics, just replace them1972                    let generics_span = impl_m.generics.span.substitute_dummy(new_generics_span);1973                    // replace with the generics from the trait1974                    let new_generics =1975                        tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;19761977                    err.multipart_suggestion(1978                        "try changing the `impl Trait` argument to a generic parameter",1979                        vec![1980                            // replace `impl Trait` with `T`1981                            (impl_span, new_name.to_string()),1982                            // replace impl method generics with trait method generics1983                            // This isn't quite right, as users might have changed the names1984                            // of the generics, but it works for the common case1985                            (generics_span, new_generics),1986                        ],1987                        Applicability::MaybeIncorrect,1988                    );1989                };1990            } else {1991                // The case where the trait method uses `impl Trait`, but the impl method uses1992                // explicit generics.1993                err.span_label(impl_span, "expected `impl Trait`, found generic parameter");1994                try {1995                    let impl_m = impl_m.def_id.as_local()?;1996                    let impl_m = tcx.hir_expect_impl_item(impl_m);1997                    let (sig, _) = impl_m.expect_fn();1998                    let input_tys = sig.decl.inputs;19992000                    struct Visitor(hir::def_id::LocalDefId);

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.