about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-06-06 17:00:06 +0000
committerMichael Goulet <michael@errs.io>2025-06-06 17:13:53 +0000
commit7efd90a1a56f5f4cf5a73f40b1b84032407873a1 (patch)
tree8aa22c1e1ef708b90df62fead5d6a2f23f60a9d7
parent0b20963d6b892651937fb3600e15ca285bdcfefd (diff)
Treat normalizing consts like normalizing types in deeply normalize
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs47
-rw-r--r--tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs (renamed from tests/crashes/140571.rs)11
-rw-r--r--tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr21
3 files changed, 54 insertions, 25 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index d903f94b489..a8d32221204 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -16,7 +16,6 @@ use tracing::instrument;
 use super::{FulfillmentCtxt, NextSolverError};
 use crate::error_reporting::InferCtxtErrorExt;
 use crate::error_reporting::traits::OverflowCause;
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
 
 /// Deeply normalize all aliases in `value`. This does not handle inference and expects
@@ -143,12 +142,18 @@ where
 
     fn normalize_unevaluated_const(
         &mut self,
-        uv: ty::UnevaluatedConst<'tcx>,
+        alias_ct: ty::Const<'tcx>,
     ) -> Result<ty::Const<'tcx>, Vec<E>> {
+        assert_matches!(alias_ct.kind(), ty::ConstKind::Unevaluated(..));
+
         let infcx = self.at.infcx;
         let tcx = infcx.tcx;
         let recursion_limit = tcx.recursion_limit();
         if !recursion_limit.value_within_limit(self.depth) {
+            let ty::ConstKind::Unevaluated(uv) = alias_ct.kind() else {
+                unreachable!();
+            };
+
             self.at.infcx.err_ctxt().report_overflow_error(
                 OverflowCause::DeeplyNormalize(uv.into()),
                 self.at.cause.span,
@@ -164,21 +169,20 @@ where
             tcx,
             self.at.cause.clone(),
             self.at.param_env,
-            ty::NormalizesTo { alias: uv.into(), term: new_infer_ct.into() },
+            ty::PredicateKind::AliasRelate(
+                alias_ct.into(),
+                new_infer_ct.into(),
+                ty::AliasRelationDirection::Equate,
+            ),
         );
 
-        let result = if infcx.predicate_may_hold(&obligation) {
-            self.fulfill_cx.register_predicate_obligation(infcx, obligation);
-            let errors = self.fulfill_cx.select_where_possible(infcx);
-            if !errors.is_empty() {
-                return Err(errors);
-            }
-            let ct = infcx.resolve_vars_if_possible(new_infer_ct);
-            ct.try_fold_with(self)?
-        } else {
-            ty::Const::new_unevaluated(tcx, uv).try_super_fold_with(self)?
-        };
+        self.fulfill_cx.register_predicate_obligation(infcx, obligation);
+        self.select_all_and_stall_coroutine_predicates()?;
 
+        // Alias is guaranteed to be fully structurally resolved,
+        // so we can super fold here.
+        let ct = infcx.resolve_vars_if_possible(new_infer_ct);
+        let result = ct.try_super_fold_with(self)?;
         self.depth -= 1;
         Ok(result)
     }
@@ -260,15 +264,12 @@ where
             return Ok(ct);
         }
 
-        let uv = match ct.kind() {
-            ty::ConstKind::Unevaluated(ct) => ct,
-            _ => return ct.try_super_fold_with(self),
-        };
+        let ty::ConstKind::Unevaluated(..) = ct.kind() else { return ct.try_super_fold_with(self) };
 
-        if uv.has_escaping_bound_vars() {
-            let (uv, mapped_regions, mapped_types, mapped_consts) =
-                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv);
-            let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))?;
+        if ct.has_escaping_bound_vars() {
+            let (ct, mapped_regions, mapped_types, mapped_consts) =
+                BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct);
+            let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct))?;
             Ok(PlaceholderReplacer::replace_placeholders(
                 infcx,
                 mapped_regions,
@@ -278,7 +279,7 @@ where
                 result,
             ))
         } else {
-            ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))
+            ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct))
         }
     }
 }
diff --git a/tests/crashes/140571.rs b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs
index 97fa1d8432d..f4cde1d62b2 100644
--- a/tests/crashes/140571.rs
+++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs
@@ -1,14 +1,21 @@
-//@ known-bug: #140571
+// Regression test for #140571. The compiler used to ICE
+
+#![feature(associated_const_equality, specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
 pub trait IsVoid {
     const IS_VOID: bool;
 }
 impl<T> IsVoid for T {
     default const IS_VOID: bool = false;
 }
-impl<T> Maybe<T> for () where T: NotVoid + ?Sized {}
 
 pub trait NotVoid {}
 impl<T> NotVoid for T where T: IsVoid<IS_VOID = false> + ?Sized {}
 
 pub trait Maybe<T> {}
 impl<T> Maybe<T> for T {}
+impl<T> Maybe<T> for () where T: NotVoid + ?Sized {}
+//~^ ERROR conflicting implementations of trait `Maybe<()>` for type `()`
+
+fn main() {}
diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr
new file mode 100644
index 00000000000..a26b30fbb63
--- /dev/null
+++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr
@@ -0,0 +1,21 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:39
+   |
+LL | #![feature(associated_const_equality, specialization)]
+   |                                       ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0119]: conflicting implementations of trait `Maybe<()>` for type `()`
+  --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:18:1
+   |
+LL | impl<T> Maybe<T> for T {}
+   | ---------------------- first implementation here
+LL | impl<T> Maybe<T> for () where T: NotVoid + ?Sized {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0119`.