about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-06-27 22:13:03 +0200
committerGitHub <noreply@github.com>2025-06-27 22:13:03 +0200
commit9108907a18d9b9ac46e361cced0fbfca6252f170 (patch)
tree284d896275a3b2ceb1a211546997924c7147d337
parent190a1a7f747408d1936a81065665c687013f6141 (diff)
parent87c8aa1ff6f320241e4161324946c1e23bc1617c (diff)
downloadrust-9108907a18d9b9ac46e361cced0fbfca6252f170.tar.gz
rust-9108907a18d9b9ac46e361cced0fbfca6252f170.zip
Rollup merge of #142806 - compiler-errors:norm-ct-has-ty, r=lcnr,BoxyUwU
Normalize before computing ConstArgHasType goal in new solver

This is a fix for rust-lang/rust#139905. See the description I left in the test.

I chose to fix this by normalizing the type before matching on its `.kind()` in `compute_const_arg_has_type_goal` (since it feels somewhat consistent with how we normalize types before assembling their candidates, for example); however, there are several other solutions that come to mind for fixing this ICE:
1. (this solution)
2. Giving `ConstKind::Error` a proper type, like `ConstKind::Value`, so that consts don't go from failing to passing `ConstArgHasType` goals after normalization (i.e. `UNEVALUATED` would normalize into a `ConstKind::Error(_, bool)` type rather than losing its type altogether).
3. Just suppressing the errors and accepting the fact that goals can go from fail->pass after normalization.

Thoughts? Happy to discuss this fix further.

r? `@BoxyUwU`
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs1
-rw-r--r--tests/ui/consts/normalize-before-const-arg-has-type-goal.rs19
-rw-r--r--tests/ui/consts/normalize-before-const-arg-has-type-goal.stderr9
3 files changed, 29 insertions, 0 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 4f845ef9cd9..e68ea22c7a2 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -191,6 +191,7 @@ where
         goal: Goal<I, (I::Const, I::Ty)>,
     ) -> QueryResult<I> {
         let (ct, ty) = goal.predicate;
+        let ct = self.structurally_normalize_const(goal.param_env, ct)?;
 
         let ct_ty = match ct.kind() {
             ty::ConstKind::Infer(_) => {
diff --git a/tests/ui/consts/normalize-before-const-arg-has-type-goal.rs b/tests/ui/consts/normalize-before-const-arg-has-type-goal.rs
new file mode 100644
index 00000000000..9caa3c9e214
--- /dev/null
+++ b/tests/ui/consts/normalize-before-const-arg-has-type-goal.rs
@@ -0,0 +1,19 @@
+trait A<const B: bool> {}
+
+//     vv- Let's call this const "UNEVALUATED" for the comment below.
+impl A<{}> for () {}
+//~^ ERROR mismatched types
+
+// During overlap check, we end up trying to prove `(): A<?0c>`. Inference guides
+// `?0c = UNEVALUATED` (which is the `{}` const in the erroneous impl). We then
+// fail to prove `ConstArgHasType<UNEVALUATED, u8>` since `UNEVALUATED` has the
+// type `bool` from the type_of query. We then deeply normalize the predicate for
+// error reporting, which ends up normalizing `UNEVALUATED` to a ConstKind::Error.
+// This ended up ICEing when trying to report an error for the `ConstArgHasType`
+// predicate, since we don't expect `ConstArgHasType(ERROR, Ty)` to ever fail.
+
+trait C<const D: u8> {}
+impl<const D: u8> C<D> for () where (): A<D> {}
+impl<const D: u8> C<D> for () {}
+
+fn main() {}
diff --git a/tests/ui/consts/normalize-before-const-arg-has-type-goal.stderr b/tests/ui/consts/normalize-before-const-arg-has-type-goal.stderr
new file mode 100644
index 00000000000..a53231846b7
--- /dev/null
+++ b/tests/ui/consts/normalize-before-const-arg-has-type-goal.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/normalize-before-const-arg-has-type-goal.rs:4:8
+   |
+LL | impl A<{}> for () {}
+   |        ^^ expected `bool`, found `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.