Skip to content

Commit

Permalink
Check generic argument compatibility when projecting assoc ty
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Sep 29, 2022
1 parent 594134d commit ee713f3
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
42 changes: 40 additions & 2 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2146,10 +2146,10 @@ fn confirm_impl_candidate<'cx, 'tcx>(
} else {
ty.map_bound(|ty| ty.into())
};
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
if !check_substs_compatible(tcx, &assoc_ty.item, substs) {
let err = tcx.ty_error_with_message(
obligation.cause.span,
"impl item and trait item have different parameter counts",
"impl item and trait item have different parameters",
);
Progress { term: err.into(), obligations: nested }
} else {
Expand All @@ -2158,6 +2158,44 @@ fn confirm_impl_candidate<'cx, 'tcx>(
}
}

// Verify that the trait item and its implementation have compatible substs lists
fn check_substs_compatible<'tcx>(
tcx: TyCtxt<'tcx>,
assoc_ty: &ty::AssocItem,
substs: ty::SubstsRef<'tcx>,
) -> bool {
fn check_substs_compatible_inner<'tcx>(
tcx: TyCtxt<'tcx>,
generics: &'tcx ty::Generics,
args: &'tcx [ty::GenericArg<'tcx>],
) -> bool {
if generics.count() != args.len() {
return false;
}

let (parent_args, own_args) = args.split_at(generics.parent_count);

if let Some(parent) = generics.parent
&& let parent_generics = tcx.generics_of(parent)
&& !check_substs_compatible_inner(tcx, parent_generics, parent_args) {
return false;
}

for (param, arg) in std::iter::zip(&generics.params, own_args) {
match (&param.kind, arg.unpack()) {
(ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
| (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
| (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
_ => return false,
}
}

true
}

check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
}

fn confirm_impl_trait_in_trait_candidate<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/generic-associated-types/issue-102114.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
trait A {
type B<'b>;
fn a() -> Self::B<'static>;
}

struct C;

struct Wrapper<T>(T);

impl A for C {
type B<T> = Wrapper<T>;
//~^ ERROR type `B` has 1 type parameter but its trait declaration has 0 type parameters
fn a() -> Self::B<'static> {}
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/generic-associated-types/issue-102114.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
--> $DIR/issue-102114.rs:11:12
|
LL | type B<'b>;
| -- expected 0 type parameters
...
LL | type B<T> = Wrapper<T>;
| ^ found 1 type parameter

error: aborting due to previous error

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

0 comments on commit ee713f3

Please sign in to comment.