about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-10-15 13:47:43 -0400
committerMichael Goulet <michael@errs.io>2024-10-15 20:44:39 -0400
commit9070abab4b6862e42a8ce25eeb4a810301b76dd7 (patch)
tree7c953c118f9aeb9974e6e19df0f338ffed7ec1ae
parente3eba2d9204e9af2ac7a089f61996b25cfecf2d8 (diff)
downloadrust-9070abab4b6862e42a8ce25eeb4a810301b76dd7.tar.gz
rust-9070abab4b6862e42a8ce25eeb4a810301b76dd7.zip
Structurally resolve in may_coerce
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs23
-rw-r--r--tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs19
-rw-r--r--tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr21
3 files changed, 61 insertions, 2 deletions
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index bb2f1f0493a..fb9262a59b9 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1094,12 +1094,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
         // We don't ever need two-phase here since we throw out the result of the coercion.
         // We also just always set `coerce_never` to true, since this is a heuristic.
-        let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
+        let coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true);
         self.probe(|_| {
+            // Make sure to structurally resolve the types, since we use
+            // the `TyKind`s heavily in coercion.
+            let ocx = ObligationCtxt::new(self);
+            let structurally_resolve = |ty| {
+                let ty = self.shallow_resolve(ty);
+                if self.next_trait_solver()
+                    && let ty::Alias(..) = ty.kind()
+                {
+                    ocx.structurally_normalize(&cause, self.param_env, ty)
+                } else {
+                    Ok(ty)
+                }
+            };
+            let Ok(expr_ty) = structurally_resolve(expr_ty) else {
+                return false;
+            };
+            let Ok(target_ty) = structurally_resolve(target_ty) else {
+                return false;
+            };
+
             let Ok(ok) = coerce.coerce(expr_ty, target_ty) else {
                 return false;
             };
-            let ocx = ObligationCtxt::new(self);
             ocx.register_obligations(ok.obligations);
             ocx.select_where_possible().is_empty()
         })
diff --git a/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs
new file mode 100644
index 00000000000..bd3dccad152
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Znext-solver
+
+trait Mirror {
+    type Assoc;
+}
+impl<T> Mirror for T {
+    type Assoc = T;
+}
+
+fn arg() -> &'static [i32; 1] { todo!() }
+
+fn arg_error(x: <fn() as Mirror>::Assoc, y: ()) { todo!() }
+
+fn main() {
+    // Should suggest to reverse the args...
+    // but if we don't normalize the expected, then we don't.
+    arg_error((), || ());
+    //~^ ERROR arguments to this function are incorrect
+}
diff --git a/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr
new file mode 100644
index 00000000000..1938b3375a5
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/coerce-in-may-coerce.stderr
@@ -0,0 +1,21 @@
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/coerce-in-may-coerce.rs:17:5
+   |
+LL |     arg_error((), || ());
+   |     ^^^^^^^^^ --  ----- expected `()`, found `{closure@$DIR/coerce-in-may-coerce.rs:17:19: 17:21}`
+   |               |
+   |               expected `<fn() as Mirror>::Assoc`, found `()`
+   |
+note: function defined here
+  --> $DIR/coerce-in-may-coerce.rs:12:4
+   |
+LL | fn arg_error(x: <fn() as Mirror>::Assoc, y: ()) { todo!() }
+   |    ^^^^^^^^^ --------------------------  -----
+help: swap these arguments
+   |
+LL |     arg_error(|| (), ());
+   |              ~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.