rust-lang/rust · error
ConstEquate should not be emitted when `-Znext-solver` is ac
Error message
ConstEquate should not be emitted when `-Znext-solver` is active
What it means
The next trait solver intentionally does not implement ConstEquate (a predicate the old solver emits when unifying two unevaluated consts). evaluate_added_goals_and_make_canonical_response's goal dispatch hits PredicateKind::ConstEquate and panics, because under -Znext-solver const equality is handled via ConstEvaluatable/normalization instead. Reaching this panic means old-solver code constructed a ConstEquate predicate and routed it into the new solver.
Source
Thrown at compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs:935
ecx.compute_unstable_feature_goal(param_env, symbol)?
}
ty::PredicateKind::Subtype(predicate) => {
ecx.compute_subtype_goal(Goal { param_env, predicate })?
}
ty::PredicateKind::Coerce(predicate) => {
ecx.compute_coerce_goal(Goal { param_env, predicate })?
}
ty::PredicateKind::DynCompatible(trait_def_id) => {
ecx.compute_dyn_compatible_goal(trait_def_id)?
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
ecx.compute_well_formed_goal(Goal { param_env, predicate: term })?
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
ecx.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })?
}
ty::PredicateKind::ConstEquate(_, _) => {
panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
}
ty::PredicateKind::NormalizesTo(predicate) => {
ecx.compute_normalizes_to_goal(Goal { param_env, predicate })?
}
ty::PredicateKind::Ambiguous => {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)?
}
})
})
}
// Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning
// the certainty of all the goals.
#[instrument(level = "trace", skip(self))]
pub(super) fn try_evaluate_added_goals(
&mut self,
) -> Result<Certainty, NoSolutionOrRerunNonErased> {
for _ in 0..FIXPOINT_STEP_LIMIT {View on GitHub (pinned to 22057b88b0)
Solutions
- Report the ICE; include the source location that constructed the ConstEquate predicate (visible in the backtrace).
- Migrate the offending type-checking call site to emit ConstEvaluatable/normalization goals instead of ConstEquate.
- As an end-user workaround, turn off -Znext-solver until the emitter path is fixed.
- Gate the triggering crate off the new solver with -Znext-solver=coherence or the crate-level solver selector.
Example fix
// before (old-solver emission leaking into next-solver) self.tcx().predicate_must_hold(modulo_regions, ObligationCause::new(span, ConstEquate(a, b))); // after (route through ConstEvaluatable / normalization) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)?;
Defensive patterns
Strategy: validation
Validate before calling
// Block builds that combine `ConstEquate`-emitting patterns with the next solver.
fn next_solver_active() -> bool {
std::env::var("RUSTFLAGS").unwrap_or_default().contains("next-solver")
|| std::env::var("CARGO_ENCODED_RUSTFLAGS").unwrap_or_default().contains("next-solver")
}
fn const_equate_pattern_used(src: &str) -> bool {
// crude: a where-clause of the form `N = M` on const params emits ConstEquate
src.contains("<const N: usize>") && src.contains("where")
&& src.split('=').count() > 1
}
#[test]
fn no_const_equate_with_next_solver() {
assert!(!(next_solver_active() && const_equate_pattern_used(include_str!("lib.rs"))));
} Try / catch
use std::panic::{catch_unwind, AssertUnwindSafe};
let out = catch_unwind(AssertUnwindSafe(|| run_typeck(crate_ast)));
if out.is_err() { eprintln!("ConstEquate + next-solver conflict; rebuild without -Znext-solver"); std::process::exit(101); } Prevention
- Never combine `const N: usize = M` equality bounds with `-Znext-solver` — pick one solver and stay there.
- Set `RUSTFLAGS=""` explicitly in CI for crates that use const-equality, so a global nightly profile can't sneak `-Znext-solver` in.
- Document in your crate's README which solver it assumes; this is a global, implicit dependency.
When it happens
Trigger: Triggered when the new solver's compute_goal dispatch (compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs:934) receives a ty::PredicateKind::ConstEquate(_, _) predicate. This happens when type-checking code that still emits ConstEquate (e.g. certain array-pattern / const-equality unifications) runs while -Znext-solver is active.
Common situations: ICE seen on code that equates generic consts (array sizes, const generics in patterns) when the compiler is built/run with -Znext-solver but a code path wasn't migrated off ConstEquate. Common during rustc development when toggling the solver on for more crates.
Related errors
- unexpected orig_value: {ct:?}
- unexpected const kind: {:?}
- non-rigid unevaluated constant for compute_const_arg_has_typ
- this never happens at the root, we're never in erased mode h
- unexpected orig_value: {ty:?}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/132f6434a31f620e.json.
Report an issue: GitHub.