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::errors::{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(®ion) {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 }1208 if let Some(impl_node) = tcx.hir_get_if_local(impl_def_id.into())1209 && let Some(impl_generics) = impl_node.generics()1210 {1211 let mut impl_bounds = 0;1212 for p in impl_generics.predicates {1213 match p.kind {1214 hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {1215 bounds,1216 ..1217 })1218 | hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {1219 bounds,1220 ..1221 }) => {1222 for b in *bounds {1223 if let hir::GenericBound::Outlives(_) = b {1224 impl_bounds += 1;1225 }1226 }1227 }1228 _ => {}1229 }1230 }1231 if impl_bounds == bounds_span.len() {1232 bounds_span = vec![];1233 } else if impl_generics.has_where_clause_predicates {1234 where_span = Some(impl_generics.where_clause_span);1235 }1236 }1237 }12381239 Err(CheckNumberOfEarlyBoundRegionsError { span, generics_span, bounds_span, where_span })1240}12411242#[allow(unused)]1243enum LateEarlyMismatch<'tcx> {1244 EarlyInImpl(DefId, DefId, ty::Region<'tcx>),1245 LateInImpl(DefId, DefId, ty::Region<'tcx>),1246}12471248fn check_region_late_boundedness<'tcx>(1249 tcx: TyCtxt<'tcx>,1250 impl_m: ty::AssocItem,1251 trait_m: ty::AssocItem,1252) -> Option<ErrorGuaranteed> {1253 if !impl_m.is_fn() {1254 return None;1255 }12561257 let (infcx, param_env) = tcx1258 .infer_ctxt()1259 .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, impl_m.def_id));12601261 let impl_m_args = infcx.fresh_args_for_item(DUMMY_SP, impl_m.def_id);1262 let impl_m_sig = tcx.fn_sig(impl_m.def_id).instantiate(tcx, impl_m_args).skip_norm_wip();1263 let impl_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, impl_m_sig);12641265 let trait_m_args = infcx.fresh_args_for_item(DUMMY_SP, trait_m.def_id);1266 let trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_args).skip_norm_wip();1267 let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_m_sig);12681269 let ocx = ObligationCtxt::new(&infcx);12701271 // Equate the signatures so that we can infer whether a late-bound param was present where1272 // an early-bound param was expected, since we replace the late-bound lifetimes with1273 // `ReLateParam`, and early-bound lifetimes with infer vars, so the early-bound args will1274 // resolve to `ReLateParam` if there is a mismatch.1275 let Ok(()) = ocx.eq(1276 &ObligationCause::dummy(),1277 param_env,1278 ty::Binder::dummy(trait_m_sig),1279 ty::Binder::dummy(impl_m_sig),1280 ) else {1281 return None;1282 };12831284 let errors = ocx.try_evaluate_obligations();1285 if !errors.is_empty() {1286 return None;1287 }12881289 let mut mismatched = vec![];12901291 let impl_generics = tcx.generics_of(impl_m.def_id);1292 for (id_arg, arg) in1293 std::iter::zip(ty::GenericArgs::identity_for_item(tcx, impl_m.def_id), impl_m_args)1294 {1295 if let ty::GenericArgKind::Lifetime(r) = arg.kind()1296 && let ty::ReVar(vid) = r.kind()1297 && let r = infcx1298 .inner1299 .borrow_mut()1300 .unwrap_region_constraints()1301 .opportunistic_resolve_var(tcx, vid)1302 && let ty::ReLateParam(ty::LateParamRegion {1303 kind: ty::LateParamRegionKind::Named(trait_param_def_id),1304 ..1305 }) = r.kind()1306 && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind()1307 {1308 mismatched.push(LateEarlyMismatch::EarlyInImpl(1309 impl_generics.region_param(ebr, tcx).def_id,1310 trait_param_def_id,1311 id_arg.expect_region(),1312 ));1313 }1314 }13151316 let trait_generics = tcx.generics_of(trait_m.def_id);1317 for (id_arg, arg) in1318 std::iter::zip(ty::GenericArgs::identity_for_item(tcx, trait_m.def_id), trait_m_args)1319 {1320 if let ty::GenericArgKind::Lifetime(r) = arg.kind()1321 && let ty::ReVar(vid) = r.kind()1322 && let r = infcx1323 .inner1324 .borrow_mut()1325 .unwrap_region_constraints()1326 .opportunistic_resolve_var(tcx, vid)1327 && let ty::ReLateParam(ty::LateParamRegion {1328 kind: ty::LateParamRegionKind::Named(impl_param_def_id),1329 ..1330 }) = r.kind()1331 && let ty::ReEarlyParam(ebr) = id_arg.expect_region().kind()1332 {1333 mismatched.push(LateEarlyMismatch::LateInImpl(1334 impl_param_def_id,1335 trait_generics.region_param(ebr, tcx).def_id,1336 id_arg.expect_region(),1337 ));1338 }1339 }13401341 if mismatched.is_empty() {1342 return None;1343 }13441345 let spans: Vec<_> = mismatched1346 .iter()1347 .map(|param| {1348 let (LateEarlyMismatch::EarlyInImpl(impl_param_def_id, ..)1349 | LateEarlyMismatch::LateInImpl(impl_param_def_id, ..)) = *param;1350 tcx.def_span(impl_param_def_id)1351 })1352 .collect();13531354 let mut diag = tcx1355 .dcx()1356 .struct_span_err(spans, "lifetime parameters do not match the trait definition")1357 .with_note("lifetime parameters differ in whether they are early- or late-bound")1358 .with_code(E0195);1359 for mismatch in mismatched {1360 match mismatch {1361 LateEarlyMismatch::EarlyInImpl(1362 impl_param_def_id,1363 trait_param_def_id,1364 early_bound_region,1365 ) => {1366 let mut multispan = MultiSpan::from_spans(vec![1367 tcx.def_span(impl_param_def_id),1368 tcx.def_span(trait_param_def_id),1369 ]);1370 multispan1371 .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl...");1372 multispan1373 .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait...");1374 multispan.push_span_label(1375 tcx.def_span(impl_param_def_id),1376 format!("`{}` is early-bound", tcx.item_name(impl_param_def_id)),1377 );1378 multispan.push_span_label(1379 tcx.def_span(trait_param_def_id),1380 format!("`{}` is late-bound", tcx.item_name(trait_param_def_id)),1381 );1382 if let Some(span) =1383 find_region_in_predicates(tcx, impl_m.def_id, early_bound_region)1384 {1385 multispan.push_span_label(1386 span,1387 format!(1388 "this lifetime bound makes `{}` early-bound",1389 tcx.item_name(impl_param_def_id)1390 ),1391 );1392 }1393 diag.span_note(1394 multispan,1395 format!(1396 "`{}` differs between the trait and impl",1397 tcx.item_name(impl_param_def_id)1398 ),1399 );1400 }1401 LateEarlyMismatch::LateInImpl(1402 impl_param_def_id,1403 trait_param_def_id,1404 early_bound_region,1405 ) => {1406 let mut multispan = MultiSpan::from_spans(vec![1407 tcx.def_span(impl_param_def_id),1408 tcx.def_span(trait_param_def_id),1409 ]);1410 multispan1411 .push_span_label(tcx.def_span(tcx.parent(impl_m.def_id)), "in this impl...");1412 multispan1413 .push_span_label(tcx.def_span(tcx.parent(trait_m.def_id)), "in this trait...");1414 multispan.push_span_label(1415 tcx.def_span(impl_param_def_id),1416 format!("`{}` is late-bound", tcx.item_name(impl_param_def_id)),1417 );1418 multispan.push_span_label(1419 tcx.def_span(trait_param_def_id),1420 format!("`{}` is early-bound", tcx.item_name(trait_param_def_id)),1421 );1422 if let Some(span) =1423 find_region_in_predicates(tcx, trait_m.def_id, early_bound_region)1424 {1425 multispan.push_span_label(1426 span,1427 format!(1428 "this lifetime bound makes `{}` early-bound",1429 tcx.item_name(trait_param_def_id)1430 ),1431 );1432 }1433 diag.span_note(1434 multispan,1435 format!(1436 "`{}` differs between the trait and impl",1437 tcx.item_name(impl_param_def_id)1438 ),1439 );1440 }1441 }1442 }14431444 Some(diag.emit())1445}14461447fn find_region_in_predicates<'tcx>(1448 tcx: TyCtxt<'tcx>,1449 def_id: DefId,1450 early_bound_region: ty::Region<'tcx>,1451) -> Option<Span> {1452 for (pred, span) in tcx.explicit_predicates_of(def_id).instantiate_identity(tcx) {1453 if pred.skip_norm_wip().visit_with(&mut FindRegion(early_bound_region)).is_break() {1454 return Some(span);1455 }1456 }14571458 struct FindRegion<'tcx>(ty::Region<'tcx>);1459 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindRegion<'tcx> {1460 type Result = ControlFlow<()>;1461 fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {1462 if r == self.0 { ControlFlow::Break(()) } else { ControlFlow::Continue(()) }1463 }1464 }14651466 None1467}14681469#[instrument(level = "debug", skip(infcx))]1470fn extract_spans_for_error_reporting<'tcx>(1471 infcx: &infer::InferCtxt<'tcx>,1472 terr: TypeError<'_>,1473 cause: &ObligationCause<'tcx>,1474 impl_m: ty::AssocItem,1475 trait_m: ty::AssocItem,1476) -> (Span, Option<Span>) {1477 let tcx = infcx.tcx;1478 let mut impl_args = {1479 let (sig, _) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();1480 sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))1481 };14821483 let trait_args = trait_m.def_id.as_local().map(|def_id| {1484 let (sig, _) = tcx.hir_expect_trait_item(def_id).expect_fn();1485 sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))1486 });14871488 match terr {1489 TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {1490 (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))1491 }1492 _ => (cause.span, tcx.hir_span_if_local(trait_m.def_id)),1493 }1494}14951496fn compare_self_type<'tcx>(1497 tcx: TyCtxt<'tcx>,1498 impl_m: ty::AssocItem,1499 trait_m: ty::AssocItem,1500 impl_trait_ref: ty::TraitRef<'tcx>,1501 delay: bool,1502) -> Result<(), ErrorGuaranteed> {1503 // Try to give more informative error messages about self typing1504 // mismatches. Note that any mismatch will also be detected1505 // below, where we construct a canonical function type that1506 // includes the self parameter as a normal parameter. It's just1507 // that the error messages you get out of this code are a bit more1508 // inscrutable, particularly for cases where one method has no1509 // self.15101511 let self_string = |method: ty::AssocItem| {1512 let untransformed_self_ty = match method.container {1513 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {1514 impl_trait_ref.self_ty()1515 }1516 ty::AssocContainer::Trait => tcx.types.self_param,1517 };1518 let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip().input(0);1519 let (infcx, param_env) = tcx1520 .infer_ctxt()1521 .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, method.def_id));1522 let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);1523 let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty);1524 get_self_string(self_arg_ty, can_eq_self)1525 };15261527 match (trait_m.is_method(), impl_m.is_method()) {1528 (false, false) | (true, true) => {}15291530 (false, true) => {1531 let self_descr = self_string(impl_m);1532 let impl_m_span = tcx.def_span(impl_m.def_id);1533 let mut err = struct_span_code_err!(1534 tcx.dcx(),1535 impl_m_span,1536 E0185,1537 "method `{}` has a `{}` declaration in the impl, but not in the trait",1538 trait_m.name(),1539 self_descr1540 );1541 err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));1542 if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {1543 err.span_label(span, format!("trait method declared without `{self_descr}`"));1544 } else {1545 err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));1546 }1547 return Err(err.emit_unless_delay(delay));1548 }15491550 (true, false) => {1551 let self_descr = self_string(trait_m);1552 let impl_m_span = tcx.def_span(impl_m.def_id);1553 let mut err = struct_span_code_err!(1554 tcx.dcx(),1555 impl_m_span,1556 E0186,1557 "method `{}` has a `{}` declaration in the trait, but not in the impl",1558 trait_m.name(),1559 self_descr1560 );1561 err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));1562 if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {1563 err.span_label(span, format!("`{self_descr}` used in trait"));1564 } else {1565 err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));1566 }15671568 return Err(err.emit_unless_delay(delay));1569 }1570 }15711572 Ok(())1573}15741575/// Checks that the number of generics on a given assoc item in a trait impl is the same1576/// as the number of generics on the respective assoc item in the trait definition.1577///1578/// For example this code emits the errors in the following code:1579/// ```rust,compile_fail1580/// trait Trait {1581/// fn foo();1582/// type Assoc<T>;1583/// }1584///1585/// impl Trait for () {1586/// fn foo<T>() {}1587/// //~^ error1588/// type Assoc = u32;1589/// //~^ error1590/// }1591/// ```1592///1593/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or1594/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in1595/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters1596fn compare_number_of_generics<'tcx>(1597 tcx: TyCtxt<'tcx>,1598 impl_: ty::AssocItem,1599 trait_: ty::AssocItem,1600 delay: bool,1601) -> Result<(), ErrorGuaranteed> {1602 let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();1603 let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();16041605 // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented1606 // in `compare_generic_param_kinds` which will give a nicer error message than something like:1607 // "expected 1 type parameter, found 0 type parameters"1608 if (trait_own_counts.types + trait_own_counts.consts)1609 == (impl_own_counts.types + impl_own_counts.consts)1610 {1611 return Ok(());1612 }16131614 // We never need to emit a separate error for RPITITs, since if an RPITIT1615 // has mismatched type or const generic arguments, then the method that it's1616 // inheriting the generics from will also have mismatched arguments, and1617 // we'll report an error for that instead. Delay a bug for safety, though.1618 if trait_.is_impl_trait_in_trait() {1619 // FIXME: no tests trigger this. If you find example code that does1620 // trigger this, please add it to the test suite.1621 tcx.dcx()1622 .bug("errors comparing numbers of generics of trait/impl functions were not emitted");1623 }16241625 let matchings = [1626 ("type", trait_own_counts.types, impl_own_counts.types),1627 ("const", trait_own_counts.consts, impl_own_counts.consts),1628 ];16291630 let item_kind = impl_.descr();16311632 let mut err_occurred = None;1633 for (kind, trait_count, impl_count) in matchings {1634 if impl_count != trait_count {1635 let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {1636 let mut spans = generics1637 .params1638 .iter()1639 .filter(|p| match p.kind {1640 hir::GenericParamKind::Lifetime {1641 kind: hir::LifetimeParamKind::Elided(_),1642 } => {1643 // A fn can have an arbitrary number of extra elided lifetimes for the1644 // same signature.1645 !item.is_fn()1646 }1647 _ => true,1648 })1649 .map(|p| p.span)1650 .collect::<Vec<Span>>();1651 if spans.is_empty() {1652 spans = vec![generics.span]1653 }1654 spans1655 };1656 let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {1657 let trait_item = tcx.hir_expect_trait_item(def_id);1658 let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);1659 let impl_trait_spans: Vec<Span> = trait_item1660 .generics1661 .params1662 .iter()1663 .filter_map(|p| match p.kind {1664 GenericParamKind::Type { synthetic: true, .. } => Some(p.span),1665 _ => None,1666 })1667 .collect();1668 (Some(arg_spans), impl_trait_spans)1669 } else {1670 let trait_span = tcx.hir_span_if_local(trait_.def_id);1671 (trait_span.map(|s| vec![s]), vec![])1672 };16731674 let impl_item = tcx.hir_expect_impl_item(impl_.def_id.expect_local());1675 let impl_item_impl_trait_spans: Vec<Span> = impl_item1676 .generics1677 .params1678 .iter()1679 .filter_map(|p| match p.kind {1680 GenericParamKind::Type { synthetic: true, .. } => Some(p.span),1681 _ => None,1682 })1683 .collect();1684 let spans = arg_spans(&impl_, impl_item.generics);1685 let span = spans.first().copied();16861687 let mut err = tcx.dcx().struct_span_err(1688 spans,1689 format!(1690 "{} `{}` has {} {kind} parameter{} but its trait \1691 declaration has {} {kind} parameter{}",1692 item_kind,1693 trait_.name(),1694 impl_count,1695 pluralize!(impl_count),1696 trait_count,1697 pluralize!(trait_count),1698 kind = kind,1699 ),1700 );1701 err.code(E0049);17021703 let msg =1704 format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),);1705 if let Some(spans) = trait_spans {1706 let mut spans = spans.iter();1707 if let Some(span) = spans.next() {1708 err.span_label(*span, msg);1709 }1710 for span in spans {1711 err.span_label(*span, "");1712 }1713 } else {1714 err.span_label(tcx.def_span(trait_.def_id), msg);1715 }17161717 if let Some(span) = span {1718 err.span_label(1719 span,1720 format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),),1721 );1722 }17231724 for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {1725 err.span_label(*span, "`impl Trait` introduces an implicit type parameter");1726 }17271728 let reported = err.emit_unless_delay(delay);1729 err_occurred = Some(reported);1730 }1731 }17321733 if let Some(reported) = err_occurred { Err(reported) } else { Ok(()) }1734}17351736fn compare_number_of_method_arguments<'tcx>(1737 tcx: TyCtxt<'tcx>,1738 impl_m: ty::AssocItem,1739 trait_m: ty::AssocItem,1740 delay: bool,1741) -> Result<(), ErrorGuaranteed> {1742 let impl_m_fty = tcx.fn_sig(impl_m.def_id);1743 let trait_m_fty = tcx.fn_sig(trait_m.def_id);1744 let trait_number_args = trait_m_fty.skip_binder().inputs().skip_binder().len();1745 let impl_number_args = impl_m_fty.skip_binder().inputs().skip_binder().len();17461747 if trait_number_args != impl_number_args {1748 let trait_span = trait_m1749 .def_id1750 .as_local()1751 .and_then(|def_id| {1752 let (trait_m_sig, _) = &tcx.hir_expect_trait_item(def_id).expect_fn();1753 let pos = trait_number_args.saturating_sub(1);1754 trait_m_sig.decl.inputs.get(pos).map(|arg| {1755 if pos == 0 {1756 arg.span1757 } else {1758 arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())1759 }1760 })1761 })1762 .or_else(|| tcx.hir_span_if_local(trait_m.def_id));17631764 let (impl_m_sig, _) = &tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn();1765 let pos = impl_number_args.saturating_sub(1);1766 let impl_span = impl_m_sig1767 .decl1768 .inputs1769 .get(pos)1770 .map(|arg| {1771 if pos == 0 {1772 arg.span1773 } else {1774 arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())1775 }1776 })1777 .unwrap_or_else(|| tcx.def_span(impl_m.def_id));17781779 let mut err = struct_span_code_err!(1780 tcx.dcx(),1781 impl_span,1782 E0050,1783 "method `{}` has {} but the declaration in trait `{}` has {}",1784 trait_m.name(),1785 potentially_plural_count(impl_number_args, "parameter"),1786 tcx.def_path_str(trait_m.def_id),1787 trait_number_args1788 );17891790 if let Some(trait_span) = trait_span {1791 err.span_label(1792 trait_span,1793 format!(1794 "trait requires {}",1795 potentially_plural_count(trait_number_args, "parameter")1796 ),1797 );1798 } else {1799 err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));1800 }18011802 err.span_label(1803 impl_span,1804 format!(1805 "expected {}, found {}",1806 potentially_plural_count(trait_number_args, "parameter"),1807 impl_number_args1808 ),1809 );18101811 // Only emit verbose suggestions when the trait span isn’t local (e.g., cross-crate).1812 if !trait_m.def_id.is_local() {1813 let trait_sig = tcx.fn_sig(trait_m.def_id);1814 let trait_arg_idents = tcx.fn_arg_idents(trait_m.def_id);1815 let sm = tcx.sess.source_map();1816 // Find the span of the space between the parentheses in a method.1817 // fn foo(...) {}1818 // ^^^1819 let impl_inputs_span = if let (Some(first), Some(last)) =1820 (impl_m_sig.decl.inputs.first(), impl_m_sig.decl.inputs.last())1821 {1822 // We have inputs; construct the span from those.1823 // fn foo( a: i32, b: u32 ) {}1824 // ^^^^^^^^^^^^^^^^1825 let arg_idents = tcx.fn_arg_idents(impl_m.def_id);1826 let first_lo = arg_idents1827 .get(0)1828 .and_then(|id| id.map(|id| id.span.lo()))1829 .unwrap_or(first.span.lo());1830 Some(impl_m_sig.span.with_lo(first_lo).with_hi(last.span.hi()))1831 } else {1832 // We have no inputs; construct the span to the left of the last parenthesis1833 // fn foo( ) {}1834 // ^1835 // FIXME: Keep spans for function parentheses around to make this more robust.1836 sm.span_to_snippet(impl_m_sig.span).ok().and_then(|s| {1837 let right_paren = s.as_bytes().iter().rposition(|&b| b == b')')?;1838 let pos = impl_m_sig.span.lo() + BytePos(right_paren as u32);1839 Some(impl_m_sig.span.with_lo(pos).with_hi(pos))1840 })1841 };1842 let suggestion = match trait_number_args.cmp(&impl_number_args) {1843 Ordering::Greater => {1844 // Span is right before the end parenthesis:1845 // fn foo(a: i32 ) {}1846 // ^1847 let trait_inputs = trait_sig.skip_binder().inputs().skip_binder();1848 let missing = trait_inputs1849 .iter()1850 .enumerate()1851 .skip(impl_number_args)1852 .map(|(idx, ty)| {1853 let name = trait_arg_idents1854 .get(idx)1855 .and_then(|ident| *ident)1856 .map(|ident| ident.to_string())1857 .unwrap_or_else(|| "_".to_string());1858 format!("{name}: {ty}")1859 })1860 .collect::<Vec<_>>();18611862 if missing.is_empty() {1863 None1864 } else {1865 impl_inputs_span.map(|s| {1866 let span = s.shrink_to_hi();1867 let prefix = if impl_number_args == 0 { "" } else { ", " };1868 let replacement = format!("{prefix}{}", missing.join(", "));1869 (1870 span,1871 format!(1872 "add the missing parameter{} from the trait",1873 pluralize!(trait_number_args - impl_number_args)1874 ),1875 replacement,1876 )1877 })1878 }1879 }1880 Ordering::Less => impl_inputs_span.and_then(|full| {1881 // Span of the arguments that there are too many of:1882 // fn foo(a: i32, b: u32) {}1883 // ^^^^^^^^1884 let lo = if trait_number_args == 0 {1885 full.lo()1886 } else {1887 impl_m_sig1888 .decl1889 .inputs1890 .get(trait_number_args - 1)1891 .map(|arg| arg.span.hi())?1892 };1893 let span = full.with_lo(lo);1894 Some((1895 span,1896 format!(1897 "remove the extra parameter{} to match the trait",1898 pluralize!(impl_number_args - trait_number_args)1899 ),1900 String::new(),1901 ))1902 }),1903 Ordering::Equal => unreachable!(),1904 };1905 if let Some((span, msg, replacement)) = suggestion {1906 err.span_suggestion_verbose(span, msg, replacement, Applicability::MaybeIncorrect);1907 }1908 }19091910 return Err(err.emit_unless_delay(delay));1911 }19121913 Ok(())1914}19151916fn compare_synthetic_generics<'tcx>(1917 tcx: TyCtxt<'tcx>,1918 impl_m: ty::AssocItem,1919 trait_m: ty::AssocItem,1920 delay: bool,1921) -> Result<(), ErrorGuaranteed> {1922 // FIXME(chrisvittal) Clean up this function, list of FIXME items:1923 // 1. Better messages for the span labels1924 // 2. Explanation as to what is going on1925 // If we get here, we already have the same number of generics, so the zip will1926 // be okay.1927 let mut error_found = None;1928 let impl_m_generics = tcx.generics_of(impl_m.def_id);1929 let trait_m_generics = tcx.generics_of(trait_m.def_id);1930 let impl_m_type_params =1931 impl_m_generics.own_params.iter().filter_map(|param| match param.kind {1932 GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),1933 GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,1934 });1935 let trait_m_type_params =1936 trait_m_generics.own_params.iter().filter_map(|param| match param.kind {1937 GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),1938 GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,1939 });1940 for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in1941 iter::zip(impl_m_type_params, trait_m_type_params)1942 {1943 if impl_synthetic != trait_synthetic {1944 let impl_def_id = impl_def_id.expect_local();1945 let impl_span = tcx.def_span(impl_def_id);1946 let trait_span = tcx.def_span(trait_def_id);1947 let mut err = struct_span_code_err!(1948 tcx.dcx(),1949 impl_span,1950 E0643,1951 "method `{}` has incompatible signature for trait",1952 trait_m.name()1953 );1954 err.span_label(trait_span, "declaration in trait here");1955 if impl_synthetic {1956 // The case where the impl method uses `impl Trait` but the trait method uses1957 // explicit generics1958 err.span_label(impl_span, "expected generic parameter, found `impl Trait`");1959 try {1960 // try taking the name from the trait impl1961 // FIXME: this is obviously suboptimal since the name can already be used1962 // as another generic argument1963 let new_name = tcx.opt_item_name(trait_def_id)?;1964 let trait_m = trait_m.def_id.as_local()?;1965 let trait_m = tcx.hir_expect_trait_item(trait_m);19661967 let impl_m = impl_m.def_id.as_local()?;1968 let impl_m = tcx.hir_expect_impl_item(impl_m);19691970 // in case there are no generics, take the spot between the function name1971 // and the opening paren of the argument list1972 let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();1973 // in case there are generics, just replace them1974 let generics_span = impl_m.generics.span.substitute_dummy(new_generics_span);1975 // replace with the generics from the trait1976 let new_generics =1977 tcx.sess.source_map().span_to_snippet(trait_m.generics.span).ok()?;19781979 err.multipart_suggestion(1980 "try changing the `impl Trait` argument to a generic parameter",1981 vec![1982 // replace `impl Trait` with `T`1983 (impl_span, new_name.to_string()),1984 // replace impl method generics with trait method generics1985 // This isn't quite right, as users might have changed the names1986 // of the generics, but it works for the common case1987 (generics_span, new_generics),1988 ],1989 Applicability::MaybeIncorrect,1990 );1991 };1992 } else {1993 // The case where the trait method uses `impl Trait`, but the impl method uses1994 // explicit generics.1995 err.span_label(impl_span, "expected `impl Trait`, found generic parameter");1996 try {1997 let impl_m = impl_m.def_id.as_local()?;1998 let impl_m = tcx.hir_expect_impl_item(impl_m);1999 let (sig, _) = impl_m.expect_fn();2000 let input_tys = sig.decl.inputs;
Findings
✓ No findings reported for this file.