rust-lang/rust · critical

Params should have been canonicalized to placeholders

Error message

Params should have been canonicalized to placeholders

What it means

In the solver's region-constraint destructor, a Component::Param(_) is treated as a hard error because canonicalization is supposed to have rewritten every early-bound region param into a Placeholder before region constraints are processed. Encountering a Param here means the canonicalization step that should have run before evaluating the goal was skipped or is incomplete.

Source

Thrown at compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs:185

        components: &[Component<I>],
        r: Region<I>,
    ) -> RegionConstraint<I> {
        RegionConstraint::And(
            components.into_iter().map(|c| self.destructure_component(c, r)).collect(),
        )
    }

    fn destructure_component(&mut self, c: &Component<I>, r: Region<I>) -> RegionConstraint<I> {
        use Component::*;
        match c {
            Region(c_r) => RegionConstraint::RegionOutlives(*c_r, r),
            Placeholder(p) => {
                RegionConstraint::PlaceholderTyOutlives(Ty::new_placeholder(self.cx(), *p), r)
            }
            // The alias is either rigid or ambiguous in which case we'll return with ambiguity.
            Alias(_, alias) => self.destructure_alias_outlives(*alias, r),
            UnresolvedInferenceVariable(_) => RegionConstraint::Ambiguity,
            Param(_) => panic!("Params should have been canonicalized to placeholders"),
            EscapingAlias(components) => self.destructure_components(components, r),
        }
    }

    /// Convert an alias outlives constraint into an OR constraint of any number of three
    /// separate classes of candidates:
    /// 1. component outlives. we turn `Alias<T, 'a>: 'b` into `T: 'b, 'a: 'b`.
    /// 2. item bounds. we turn `Alias<T, 'a>: 'b` into `'c: 'b` if `Alias` is
    ///     defined as `type Alias<T, 'a>: 'c`
    /// 3. env assumptions. we defer handling `Alias<T, 'a>: 'b` via where clauses until
    ///     when exiting the current binder. See [`RegionConstraint::AliasTyOutlivesViaEnv`].
    #[instrument(level = "debug", skip(self), ret)]
    fn destructure_alias_outlives(
        &mut self,
        alias: AliasTy<I>,
        r: Region<I>,
    ) -> RegionConstraint<I> {
        let item_bounds =

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Report the ICE to rustc with the offending crate and the backtrace.
  2. Verify the goal was canonicalized (params -> placeholders) before reaching region constraint collection; the bug is the missing canonicalization.
  3. Disable -Znext-solver to unblock.
  4. Bisect changes to canonicalization / placeholder instantiation in the new solver.
Defensive patterns

Strategy: validation

Validate before calling

// Region constraints must see placeholders, not Params. Ensure generic params are
// canonicalized before being passed into region solving (this is the compiler's job,
// but you can avoid triggering it by not hand-rolling region-parameterized generics).
fn uses_explicit_lifetime_params(src: &str) -> bool {
    src.contains("<'") && src.contains(">")
}
#[test]
fn flag_region_param_heavy_crates() {
    if uses_explicit_lifetime_params(include_str!("lib.rs")) {
        eprintln!("warning: explicit lifetime params may trigger solver canonicalization bug");
    }
}

Type guard

trait CanonicalLifetime: 'static {}
// force callers to bind lifetimes to 'static-or-equivalent placeholders, never raw Params
fn requires_canonical<'a, T: CanonicalLifetime>(_x: &'a T) {}

Try / catch

use std::panic::{catch_unwind, AssertUnwindSafe};
let ok = catch_unwind(AssertUnwindSafe(|| solve_region_constraints(&regions)));
if ok.is_err() { fall_back_to_legacy_solver_for_regions(); }

Prevention

When it happens

Trigger: Triggered when SolverRegionConstraints::destructure_component (compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs:175) matches Component::Param(_) — i.e. an outlives constraint over a still-parametric region reached the region-constraint collector without first being canonicalized to a placeholder.

Common situations: ICE during region-outlives / alias-outlives solving under -Znext-solver. Usually a regression in how the search graph or EvalCtxt canonicalizes goals before invoking the region constraint machinery.

Related errors


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