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
- Read the `{:?}` goal in the ICE to identify the exact predicate, then drop its const/`~const TryAsDynCompat` bound.
- Move the dyn upcast out of the const context into runtime code.
- Report upstream with the ICE message (it already embeds the goal) and a minimal reproducer under `-Znext-solver`.
- 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
- `TryAsDynCompat` (trait-object upcast / dyn-compatibility check) has no const candidate (effect_goals.rs:458); never perform dyn upcasts inside `const fn`.
- Do trait-object upcasting only at runtime, where the vtable is available.
- In const code, dispatch via `match` on an enum-of-types or a concrete type rather than `dyn Trait` upcasting.
- If the ICE surfaces without an explicit upcast, the solver reached the const candidate unexpectedly — minimize and report.
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
- FusedIterator is not const
- AsyncIterator is not const
- Coroutine is not const
- DiscriminantKind is not const
- TransmuteFrom is not const
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/a6ca8443811d2345.json.
Report an issue: GitHub.