rust-lang/rust · critical

`TryAsDynCompat` is not const: {:?}

Error message

`TryAsDynCompat` is not const: {:?}

What it means

Internal `unreachable!` in the next-gen trait solver's const-effect candidate assembly for `TryAsDynCompat` (the `core::ops::TryAsDynCompat` trait behind dyn-compat trait upcasting). Unlike the sibling stubs, this panic also formats the offending `goal` via `{:?}`, so the ICE message includes the exact predicate that was routed. `TryAsDynCompat` has no const implementation, so reaching this candidate is a solver bug.

Source

Thrown at compiler/rustc_next_trait_solver/src/solve/effect_goals.rs:458

    fn consider_builtin_transmute_candidate(
        _ecx: &mut EvalCtxt<'_, D>,
        _goal: Goal<I, Self>,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        unreachable!("TransmuteFrom is not const")
    }

    fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
        _ecx: &mut EvalCtxt<'_, D>,
        _goal: Goal<I, Self>,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        unreachable!("BikeshedGuaranteedNoDrop is not const");
    }

    fn consider_builtin_try_as_dyn_candidate(
        _ecx: &mut EvalCtxt<'_, D>,
        goal: Goal<I, Self>,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        unreachable!("`TryAsDynCompat` is not const: {:?}", goal)
    }

    fn consider_structural_builtin_unsize_candidates(
        _ecx: &mut EvalCtxt<'_, D>,
        _goal: Goal<I, Self>,
    ) -> Result<Vec<Candidate<I>>, RerunNonErased> {
        unreachable!("Unsize is not const")
    }

    fn consider_builtin_field_candidate(
        _ecx: &mut EvalCtxt<'_, D>,
        _goal: Goal<<D as SolverDelegate>::Interner, Self>,
    ) -> Result<Candidate<<D as SolverDelegate>::Interner>, NoSolutionOrRerunNonErased> {
        unreachable!("Field is not const")
    }
}

impl<D, I> EvalCtxt<'_, D>

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Read the `{:?}` goal in the ICE to identify the exact predicate, then drop its const/`~const TryAsDynCompat` bound.
  2. Move the dyn upcast out of the const context into runtime code.
  3. Report upstream with the ICE message (it already embeds the goal) and a minimal reproducer under `-Znext-solver`.
  4. Bisect nightlies — dyn-compat const routing is new and unstable.

Example fix

// before
const fn upcast<T: ?Sized + const TryAsDynCompat<dyn Debug>>(t: &T) -> &dyn Debug { t }

// after
fn upcast<T: ?Sized + TryAsDynCompat<dyn Debug>>(t: &T) -> &dyn Debug { t }
Defensive patterns

Strategy: validation

Validate before calling

// build.rs: reject const TryAsDynCompat (dyn upcast) usage
fn main() {
    let src = std::fs::read_to_string("src/lib.rs").unwrap_or_default();
    for banned in ["~const TryAsDynCompat", "const TryAsDynCompat", "TryAsDynCompat"] {
        assert!(!src.contains(banned), "rejected: {banned} — dyn-compat upcast is not const");
    }
    println!("cargo:rerun-if-changed=src/lib.rs");
}

Prevention

When it happens

Trigger: The host-effect solver is asked to prove `T: const TryAsDynCompat<U>` / `~const TryAsDynCompat<U>`, typically via dyn-trait upcasting (`dyn Trait` → `dyn Supertrait`) performed inside a `const fn` or under `#[const_trait]` propagation, with `-Znext-solver` enabled.

Common situations: Nightly code using trait upcasting coercion (`dyn Sub` → `dyn Super`) inside const context; `#[const_trait]` hierarchies that imply `TryAsDynCompat`; `-Znext-solver` regression after dyn-compat routing was added to effect-goal assembly.

Related errors


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