]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #103827 - compiler-errors:rpitit-substs-compat, r=wesleywiser
authorManish Goregaokar <manishsmail@gmail.com>
Wed, 9 Nov 2022 02:03:54 +0000 (21:03 -0500)
committerGitHub <noreply@github.com>
Wed, 9 Nov 2022 02:03:54 +0000 (21:03 -0500)
Properly remap and check for substs compatibility in `confirm_impl_trait_in_trait_candidate`

Fixes #103824

compiler/rustc_middle/src/ty/error.rs
compiler/rustc_trait_selection/src/traits/project.rs
src/test/ui/impl-trait/in-trait/generics-mismatch.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/generics-mismatch.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/specialization-broken.rs [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/specialization-broken.stderr [new file with mode: 0644]
src/test/ui/impl-trait/in-trait/specialization-substs-remap.rs [new file with mode: 0644]

index 4e6cdb786025e0bcd8f78e2d213e7b6758487476..dc13374f992eb7589f6eb919b50024314ab5d1ba 100644 (file)
@@ -430,7 +430,9 @@ pub fn note_and_explain_type_err(
                     (ty::Projection(_), ty::Projection(_)) => {
                         diag.note("an associated type was expected, but a different one was found");
                     }
-                    (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => {
+                    (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p))
+                        if self.def_kind(proj.item_def_id) != DefKind::ImplTraitPlaceholder =>
+                    {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
                         if !sp.contains(p_span) {
index 7f829e46bbb1bec2e88568fcb153cf8e4f953044..572f82117cc0e701440b9b0308f6848b539ed214 100644 (file)
@@ -2187,7 +2187,7 @@ 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,
+    assoc_item: &ty::AssocItem,
     substs: ty::SubstsRef<'tcx>,
 ) -> bool {
     fn check_substs_compatible_inner<'tcx>(
@@ -2219,7 +2219,10 @@ fn check_substs_compatible_inner<'tcx>(
         true
     }
 
-    check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
+    let generics = tcx.generics_of(assoc_item.def_id);
+    // Chop off any additional substs (RPITIT) substs
+    let substs = &substs[0..generics.count().min(substs.len())];
+    check_substs_compatible_inner(tcx, generics, substs)
 }
 
 fn confirm_impl_trait_in_trait_candidate<'tcx>(
@@ -2248,11 +2251,27 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         };
     }
 
-    let impl_fn_def_id = leaf_def.item.def_id;
     // Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
     // since `data.substs` are the impl substs.
     let impl_fn_substs =
         obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
+    let impl_fn_substs = translate_substs(
+        selcx.infcx(),
+        obligation.param_env,
+        data.impl_def_id,
+        impl_fn_substs,
+        leaf_def.defining_node,
+    );
+
+    if !check_substs_compatible(tcx, &leaf_def.item, impl_fn_substs) {
+        let err = tcx.ty_error_with_message(
+            obligation.cause.span,
+            "impl method and trait method have different parameters",
+        );
+        return Progress { term: err.into(), obligations };
+    }
+
+    let impl_fn_def_id = leaf_def.item.def_id;
 
     let cause = ObligationCause::new(
         obligation.cause.span,
diff --git a/src/test/ui/impl-trait/in-trait/generics-mismatch.rs b/src/test/ui/impl-trait/in-trait/generics-mismatch.rs
new file mode 100644 (file)
index 0000000..cc0fc72
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+struct U;
+
+trait Foo {
+    fn bar(&self) -> impl Sized;
+}
+
+impl Foo for U {
+    fn bar<T>(&self) {}
+    //~^ ERROR method `bar` has 1 type parameter but its trait declaration has 0 type parameters
+}
+
+fn main() {
+    U.bar();
+}
diff --git a/src/test/ui/impl-trait/in-trait/generics-mismatch.stderr b/src/test/ui/impl-trait/in-trait/generics-mismatch.stderr
new file mode 100644 (file)
index 0000000..cd42683
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
+  --> $DIR/generics-mismatch.rs:11:12
+   |
+LL |     fn bar(&self) -> impl Sized;
+   |           - expected 0 type parameters
+...
+LL |     fn bar<T>(&self) {}
+   |            ^ found 1 type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0049`.
diff --git a/src/test/ui/impl-trait/in-trait/specialization-broken.rs b/src/test/ui/impl-trait/in-trait/specialization-broken.rs
new file mode 100644 (file)
index 0000000..9d27d37
--- /dev/null
@@ -0,0 +1,26 @@
+// FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not.
+// But we fixed an ICE anyways.
+
+#![feature(specialization)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn bar(&self) -> impl Sized;
+}
+
+default impl<U> Foo for U
+where
+    U: Copy,
+{
+    fn bar(&self) -> U {
+        //~^ ERROR method `bar` has an incompatible type for trait
+        *self
+    }
+}
+
+impl Foo for i32 {}
+
+fn main() {
+    1i32.bar();
+}
diff --git a/src/test/ui/impl-trait/in-trait/specialization-broken.stderr b/src/test/ui/impl-trait/in-trait/specialization-broken.stderr
new file mode 100644 (file)
index 0000000..a30e634
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/specialization-broken.rs:16:22
+   |
+LL | default impl<U> Foo for U
+   |              - this type parameter
+...
+LL |     fn bar(&self) -> U {
+   |                      ^
+   |                      |
+   |                      expected associated type, found type parameter `U`
+   |                      help: change the output type to match the trait: `impl Sized`
+   |
+note: type in trait
+  --> $DIR/specialization-broken.rs:9:22
+   |
+LL |     fn bar(&self) -> impl Sized;
+   |                      ^^^^^^^^^^
+   = note: expected fn pointer `fn(&U) -> impl Sized`
+              found fn pointer `fn(&U) -> U`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/impl-trait/in-trait/specialization-substs-remap.rs b/src/test/ui/impl-trait/in-trait/specialization-substs-remap.rs
new file mode 100644 (file)
index 0000000..c9ee877
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(specialization)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn bar(&self) -> impl Sized;
+}
+
+impl<U> Foo for U
+where
+    U: Copy,
+{
+    fn bar(&self) -> U {
+        *self
+    }
+}
+
+impl Foo for i32 {}
+
+fn main() {
+    let _: i32 = 1i32.bar();
+}