about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-09-29 21:22:34 +0000
committerMichael Goulet <michael@errs.io>2022-09-29 21:22:34 +0000
commitee713f3d4350c75bae85749619b0e1508f433e02 (patch)
treeafe80ad900d57ce9e39f4ae72aa7af0deb8e3f54
parent594134d873a1020947da9b73803dcce76b6f5cf1 (diff)
downloadrust-ee713f3d4350c75bae85749619b0e1508f433e02.tar.gz
rust-ee713f3d4350c75bae85749619b0e1508f433e02.zip
Check generic argument compatibility when projecting assoc ty
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs42
-rw-r--r--src/test/ui/generic-associated-types/issue-102114.rs16
-rw-r--r--src/test/ui/generic-associated-types/issue-102114.stderr12
3 files changed, 68 insertions, 2 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 07b65a9748d..29172d6caaf 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -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 {
@@ -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>,
diff --git a/src/test/ui/generic-associated-types/issue-102114.rs b/src/test/ui/generic-associated-types/issue-102114.rs
new file mode 100644
index 00000000000..de31737efef
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-102114.rs
@@ -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() {}
diff --git a/src/test/ui/generic-associated-types/issue-102114.stderr b/src/test/ui/generic-associated-types/issue-102114.stderr
new file mode 100644
index 00000000000..8e41dee54d7
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-102114.stderr
@@ -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`.