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(®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 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.