rust-lang/rust · error

unexpected root evaluation: {evaluation:?}

Error message

unexpected root evaluation: {evaluation:?}

What it means

Proof-tree builder invariant. WipEvaluationStep::finalize expects the finalized probe to be of kind inspect::ProbeKind::Root; any other ProbeKind is unreachable because an evaluation step always starts at a root probe. Hitting it means the proof-tree builder's probe bookkeeping (probe_depth / steps) got out of sync and finalized a non-root probe as if it were the root.

Source

Thrown at compiler/rustc_next_trait_solver/src/solve/inspect/build.rs:122

}

impl<I: Interner> WipEvaluationStep<I> {
    fn current_evaluation_scope(&mut self) -> &mut WipProbe<I> {
        let mut current = &mut self.evaluation;
        for _ in 0..self.probe_depth {
            match current.steps.last_mut() {
                Some(WipProbeStep::NestedProbe(p)) => current = p,
                _ => panic!(),
            }
        }
        current
    }

    fn finalize(self) -> inspect::Probe<I> {
        let evaluation = self.evaluation.finalize();
        match evaluation.kind {
            inspect::ProbeKind::Root { .. } => evaluation,
            _ => unreachable!("unexpected root evaluation: {evaluation:?}"),
        }
    }
}

#[derive_where(PartialEq, Debug; I: Interner)]
struct WipProbe<I: Interner> {
    initial_num_var_values: usize,
    steps: Vec<WipProbeStep<I>>,
    kind: Option<inspect::ProbeKind<I>>,
    final_state: Option<inspect::CanonicalState<I, ()>>,
}

impl<I: Interner> Eq for WipProbe<I> {}

impl<I: Interner> WipProbe<I> {
    fn finalize(self) -> inspect::Probe<I> {
        inspect::Probe {
            steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(),

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Report the ICE; it only occurs with inspection enabled, so include the flags used.
  2. Run without -Zverbose-internals / proof-tree inspection to avoid the buggy path.
  3. Audit new_evaluation_step / finalize_evaluation_step calls to ensure the root probe's kind is set before finalize().
  4. Bisect changes to the inspect/build.rs probe tracking.
Defensive patterns

Strategy: validation

Validate before calling

// The inspection/build path only expects certain root evaluations. If you drive
// rustc's `-Z self-profile` / `-Z dump-solver` from CI, gate the dump on known-good
// evaluation shapes.
fn dump_config_known_good(cfg: &DumpConfig) -> bool {
    matches!(cfg.root_evaluation, RootEval::Normal | RootEval::Transparent)
}
#[test]
fn assert_dump_safe() { assert!(dump_config_known_good(&dump_cfg())); }

Try / catch

use std::panic::{catch_unwind, AssertUnwindSafe};
let graph = catch_unwind(AssertUnwindSafe(|| inspect::build_root(evaluation)));
graph.ok().unwrap_or_else(inspect::empty_graph)

Prevention

When it happens

Trigger: Triggered only when proof-tree inspection is enabled (e.g. -Zverbose-internals, -Ztrait-solver=inspect, or debugger-driven evaluation) and EvaluationStepBuilder::finalize (compiler/rustc_next_trait_solver/src/solve/inspect/build.rs:118) is called on a WipEvaluationStep whose top-level probe was not assigned ProbeKind::Root.

Common situations: ICE seen while debugging the new solver or running tools that consume proof trees (rust-analyzer, -Ztimings, custom analyzers). Indicates a bug in the inspector's probe enter/leave logic rather than user code.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/597c7f13acf8f4a7.json. Report an issue: GitHub.