From 94e047ba3bff6a789f51f89b2e6fd880102744ad Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Fri, 11 Nov 2022 17:36:16 +0000 Subject: [PATCH 1/3] Check generics parity between impl and trait before collecting RPITITs --- .../src/check/compare_method.rs | 14 ++++++++++--- .../in-trait/trait-more-generics-than-impl.rs | 18 ++++++++++++++++ .../trait-more-generics-than-impl.stderr | 21 +++++++++++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs create mode 100644 src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index e68df228c6b..110ecd2f56b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -51,7 +51,7 @@ pub(crate) fn compare_impl_method<'tcx>( return; } - if let Err(_) = compare_number_of_generics(tcx, impl_m, impl_m_span, trait_m, trait_item_span) { + if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span) { return; } @@ -352,6 +352,10 @@ pub fn collect_trait_impl_trait_tys<'tcx>( let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap(); let param_env = tcx.param_env(def_id); + // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later. + compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id))?; + compare_generic_param_kinds(tcx, impl_m, trait_m)?; + let trait_to_impl_substs = impl_trait_ref.substs; let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); @@ -376,6 +380,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( let infcx = &tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(infcx); + // Normalize the impl signature with fresh variables for lifetime inference. let norm_cause = ObligationCause::misc(return_span, impl_m_hir_id); let impl_sig = ocx.normalize( norm_cause.clone(), @@ -388,6 +393,10 @@ pub fn collect_trait_impl_trait_tys<'tcx>( ); let impl_return_ty = impl_sig.output(); + // Normalize the trait signature with liberated bound vars, passing it through + // the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces + // them with inference variables. + // We will use these inference variables to collect the hidden types of RPITITs. let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id); let unnormalized_trait_sig = tcx .liberate_late_bound_regions( @@ -922,7 +931,6 @@ fn compare_self_type<'tcx>( fn compare_number_of_generics<'tcx>( tcx: TyCtxt<'tcx>, impl_: &ty::AssocItem, - _impl_span: Span, trait_: &ty::AssocItem, trait_span: Option<Span>, ) -> Result<(), ErrorGuaranteed> { @@ -1489,7 +1497,7 @@ pub(crate) fn compare_ty_impl<'tcx>( debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref); let _: Result<(), ErrorGuaranteed> = (|| { - compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?; + compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span)?; compare_generic_param_kinds(tcx, impl_ty, trait_ty)?; diff --git a/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs new file mode 100644 index 00000000000..608006203d9 --- /dev/null +++ b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs @@ -0,0 +1,18 @@ +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +struct S; + +trait Foo { + fn bar<T>() -> impl Sized; +} + +impl Foo for S { + fn bar() -> impl Sized {} + //~^ ERROR method `bar` has 0 type parameters but its trait declaration has 1 type parameter + //~| ERROR method `bar` has 0 type parameters but its trait declaration has 1 type parameter +} + +fn main() { + S::bar(); +} diff --git a/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr new file mode 100644 index 00000000000..acde1f7654b --- /dev/null +++ b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr @@ -0,0 +1,21 @@ +error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/trait-more-generics-than-impl.rs:11:11 + | +LL | fn bar<T>() -> impl Sized; + | - expected 1 type parameter +... +LL | fn bar() -> impl Sized {} + | ^ found 0 type parameters + +error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/trait-more-generics-than-impl.rs:11:11 + | +LL | fn bar<T>() -> impl Sized; + | - expected 1 type parameter +... +LL | fn bar() -> impl Sized {} + | ^ found 0 type parameters + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0049`. From 0a95878972f35923e837fcce3eabc6e9c5c917ce Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Tue, 15 Nov 2022 04:06:40 +0000 Subject: [PATCH 2/3] drive-by: style nits --- .../src/check/compare_method.rs | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 110ecd2f56b..10089453ed6 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -14,10 +14,8 @@ use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::util::ExplicitSelf; use rustc_middle::ty::{ - self, AssocItem, DefIdTree, TraitRef, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitable, + self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, }; -use rustc_middle::ty::{FnSig, InternalSubsts}; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; @@ -144,9 +142,9 @@ pub(crate) fn compare_impl_method<'tcx>( #[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))] fn compare_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, - impl_m: &AssocItem, + impl_m: &ty::AssocItem, impl_m_span: Span, - trait_m: &AssocItem, + trait_m: &ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let trait_to_impl_substs = impl_trait_ref.substs; @@ -157,8 +155,7 @@ fn compare_predicate_entailment<'tcx>( // FIXME(@lcnr): remove that after removing `cause.body_id` from // obligations. let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); - // We sometimes modify the span further down. - let mut cause = ObligationCause::new( + let cause = ObligationCause::new( impl_m_span, impl_m_hir_id, ObligationCauseCode::CompareImplItemObligation { @@ -307,14 +304,13 @@ fn compare_predicate_entailment<'tcx>( debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); let emitted = report_trait_method_mismatch( - tcx, - &mut cause, &infcx, + cause, terr, (trait_m, trait_fty), (impl_m, impl_fty), - &trait_sig, - &impl_trait_ref, + trait_sig, + impl_trait_ref, ); return Err(emitted); } @@ -360,7 +356,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); - let mut cause = ObligationCause::new( + let cause = ObligationCause::new( return_span, impl_m_hir_id, ObligationCauseCode::CompareImplItemObligation { @@ -457,14 +453,13 @@ pub fn collect_trait_impl_trait_tys<'tcx>( // emit an error now because `compare_predicate_entailment` will not report the error // when normalization fails. let emitted = report_trait_method_mismatch( - tcx, - &mut cause, infcx, + cause, terr, (trait_m, trait_fty), (impl_m, impl_fty), - &trait_sig, - &impl_trait_ref, + trait_sig, + impl_trait_ref, ); return Err(emitted); } @@ -634,23 +629,21 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> { } fn report_trait_method_mismatch<'tcx>( - tcx: TyCtxt<'tcx>, - cause: &mut ObligationCause<'tcx>, infcx: &InferCtxt<'tcx>, + mut cause: ObligationCause<'tcx>, terr: TypeError<'tcx>, - (trait_m, trait_fty): (&AssocItem, Ty<'tcx>), - (impl_m, impl_fty): (&AssocItem, Ty<'tcx>), - trait_sig: &FnSig<'tcx>, - impl_trait_ref: &TraitRef<'tcx>, + (trait_m, trait_fty): (&ty::AssocItem, Ty<'tcx>), + (impl_m, impl_fty): (&ty::AssocItem, Ty<'tcx>), + trait_sig: ty::FnSig<'tcx>, + impl_trait_ref: ty::TraitRef<'tcx>, ) -> ErrorGuaranteed { + let tcx = infcx.tcx; let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m); - cause.span = impl_err_span; - let mut diag = struct_span_err!( tcx.sess, - cause.span(), + impl_err_span, E0053, "method `{}` has an incompatible type for trait", trait_m.name @@ -721,6 +714,7 @@ fn report_trait_method_mismatch<'tcx>( _ => {} } + cause.span = impl_err_span; infcx.err_ctxt().note_type_err( &mut diag, &cause, From df5f247a5c5432fc85a84cafb8461fafd01cf6ae Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Tue, 22 Nov 2022 01:36:35 +0000 Subject: [PATCH 3/3] Delay bug to deduplicate diagnostics --- .../src/check/compare_method.rs | 18 ++++++++++-------- .../in-trait/trait-more-generics-than-impl.rs | 1 - .../trait-more-generics-than-impl.stderr | 11 +---------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 10089453ed6..6a178478758 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -49,11 +49,11 @@ pub(crate) fn compare_impl_method<'tcx>( return; } - if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span) { + if let Err(_) = compare_number_of_generics(tcx, impl_m, trait_m, trait_item_span, false) { return; } - if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) { + if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m, false) { return; } @@ -349,8 +349,8 @@ pub fn collect_trait_impl_trait_tys<'tcx>( let param_env = tcx.param_env(def_id); // First, check a few of the same thing as `compare_impl_method`, just so we don't ICE during substitutions later. - compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id))?; - compare_generic_param_kinds(tcx, impl_m, trait_m)?; + compare_number_of_generics(tcx, impl_m, trait_m, tcx.hir().span_if_local(impl_m.def_id), true)?; + compare_generic_param_kinds(tcx, impl_m, trait_m, true)?; let trait_to_impl_substs = impl_trait_ref.substs; @@ -927,6 +927,7 @@ fn compare_number_of_generics<'tcx>( impl_: &ty::AssocItem, trait_: &ty::AssocItem, trait_span: Option<Span>, + delay: bool, ) -> Result<(), ErrorGuaranteed> { let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts(); let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts(); @@ -1056,7 +1057,7 @@ fn compare_number_of_generics<'tcx>( err.span_label(*span, "`impl Trait` introduces an implicit type parameter"); } - let reported = err.emit(); + let reported = err.emit_unless(delay); err_occurred = Some(reported); } } @@ -1308,6 +1309,7 @@ fn compare_generic_param_kinds<'tcx>( tcx: TyCtxt<'tcx>, impl_item: &ty::AssocItem, trait_item: &ty::AssocItem, + delay: bool, ) -> Result<(), ErrorGuaranteed> { assert_eq!(impl_item.kind, trait_item.kind); @@ -1365,7 +1367,7 @@ fn compare_generic_param_kinds<'tcx>( err.span_label(impl_header_span, ""); err.span_label(param_impl_span, make_param_message("found", param_impl)); - let reported = err.emit(); + let reported = err.emit_unless(delay); return Err(reported); } } @@ -1491,9 +1493,9 @@ pub(crate) fn compare_ty_impl<'tcx>( debug!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref); let _: Result<(), ErrorGuaranteed> = (|| { - compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span)?; + compare_number_of_generics(tcx, impl_ty, trait_ty, trait_item_span, false)?; - compare_generic_param_kinds(tcx, impl_ty, trait_ty)?; + compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; let sp = tcx.def_span(impl_ty.def_id); compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?; diff --git a/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs index 608006203d9..0bbe50ea6fd 100644 --- a/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs +++ b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs @@ -10,7 +10,6 @@ trait Foo { impl Foo for S { fn bar() -> impl Sized {} //~^ ERROR method `bar` has 0 type parameters but its trait declaration has 1 type parameter - //~| ERROR method `bar` has 0 type parameters but its trait declaration has 1 type parameter } fn main() { diff --git a/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr index acde1f7654b..8ff54cad951 100644 --- a/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr +++ b/src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr @@ -7,15 +7,6 @@ LL | fn bar<T>() -> impl Sized; LL | fn bar() -> impl Sized {} | ^ found 0 type parameters -error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/trait-more-generics-than-impl.rs:11:11 - | -LL | fn bar<T>() -> impl Sized; - | - expected 1 type parameter -... -LL | fn bar() -> impl Sized {} - | ^ found 0 type parameters - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0049`.