Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check generics parity before collecting return-position impl Traits in trait #104295

Merged
merged 3 commits into from
Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 36 additions & 32 deletions compiler/rustc_hir_analysis/src/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -51,11 +49,11 @@ 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, 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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -352,11 +348,15 @@ 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), true)?;
compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;

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());
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 {
Expand All @@ -376,6 +376,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(),
Expand All @@ -388,6 +389,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(
Expand Down Expand Up @@ -448,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);
}
Expand Down Expand Up @@ -625,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
Expand Down Expand Up @@ -712,6 +714,7 @@ fn report_trait_method_mismatch<'tcx>(
_ => {}
}

cause.span = impl_err_span;
infcx.err_ctxt().note_type_err(
&mut diag,
&cause,
Expand Down Expand Up @@ -922,9 +925,9 @@ 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>,
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();
Expand Down Expand Up @@ -1054,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);
}
}
Expand Down Expand Up @@ -1306,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);

Expand Down Expand Up @@ -1363,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);
}
}
Expand Down Expand Up @@ -1489,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, impl_ty_span, 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)?;
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![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
}

fn main() {
S::bar();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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 previous error

For more information about this error, try `rustc --explain E0049`.