[ICE]: "unexpected ambiguity" due to recursive RPIT
Open
Nobody has claimed this yet.
A-impl-trait
A-type-system
C-bug
fixed-by-next-solver
I-ICE
T-compiler
T-types
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.2k
- PR merge metrics
- PR metrics pending
Description
Code
trait Trait {
type Output;
}
impl<O, F: Fn() -> O> Trait for F {
type Output = O;
}
struct Wrap<P>(P);
impl<P: Trait> Trait for Wrap<P> {
type Output = P::Output;
}
fn wrap<P: Trait>(x: P) -> impl Trait {
Wrap(x)
}
fn consume<P: Trait>(_: P) -> P::Output {
unimplemented!()
}
pub fn recurse<T>() -> impl Sized {
consume(wrap(recurse::<T>))
}
The code here is identical to #139658 except that recurse is now a generic function.
cc @lcnr
Meta
Reproducible on the playground with version 1.95.0-nightly (2026-02-16 3c9faa0d037b9eecda4a)
Error output
note: no errors encountered even though delayed bugs were created
note: those delayed bugs will now be shown as internal compiler errors
error: internal compiler error: unexpected ambiguity: CanonicalQueryInput { canonical: Canonical { value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [Binder { value: TraitPredicate(<T as std::marker::Sized>, polarity:Positive), bound_vars: [] }] }, value: AliasTerm { args: [Wrap<FnDef(DefId(0:21 ~ playground[9e4e]::recurse), [T/#0])>], def_id: DefId(0:4 ~ playground[9e4e]::Trait::Output), .. } }, max_universe: U0, var_kinds: [] }, typing_mode: PostAnalysis } Canonical { value: QueryResponse { var_values: CanonicalVarValues { var_values: [] }, region_constraints: QueryRegionConstraints { outlives: [], assumptions: [] }, certainty: Ambiguous, opaque_types: [], value: NormalizationResult { normalized_term: Term::Ty(^c_0) } }, max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }
Backtrace
|
= note: delayed at /rustc-dev/3c9faa0d037b9eecda4a440cc482ff7f960fb8a5/compiler/rustc_trait_selection/src/traits/query/normalize.rs:350:27
0: <rustc_errors::DiagCtxtInner>::emit_diagnostic
1: <rustc_errors::DiagCtxtHandle>::emit_diagnostic
2: <rustc_span::ErrorGuaranteed as rustc_errors::diagnostic::EmissionGuarantee>::emit_producing_guarantee
3: <rustc_errors::DiagCtxtHandle>::delayed_bug::<alloc::string::String>
4: <rustc_trait_selection::traits::query::normalize::QueryNormalizer>::try_fold_free_or_assoc
5: <rustc_trait_selection::traits::query::normalize::QueryNormalizer as rustc_type_ir::fold::FallibleTypeFolder<rustc_middle::ty::context::TyCtxt>>::try_fold_ty
6: <rustc_trait_selection::traits::query::normalize::QueryNormalizer as rustc_type_ir::fold::FallibleTypeFolder<rustc_middle::ty::context::TyCtxt>>::try_fold_ty
7: <rustc_traits::normalize_erasing_regions::provide::{closure#0} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_middle::ty::PseudoCanonicalInput<rustc_middle::ty::generic_args::GenericArg>)>>::call_once
8: rustc_query_impl::execution::try_execute_query::<rustc_middle::query::caches::DefaultCache<rustc_middle::ty::PseudoCanonicalInput<rustc_middle::ty::generic_args::GenericArg>, rustc_middle::query::erase::ErasedData<[u8; 8]>>, {rustc_query_impl::QueryFlags { is_anon: false, is_depth_limit: false, is_feedable: false }}, false>
9: rustc_query_impl::query_impl::try_normalize_generic_arg_after_erasing_regions::get_query_non_incr::__rust_end_short_backtrace
10: <rustc_middle::ty::normalize_erasing_regions::TryNormalizeAfterErasingRegionsFolder as rustc_type_ir::fold::FallibleTypeFolder<rustc_middle::ty::context::TyCtxt>>::try_fold_ty
11: <rustc_mir_transform::post_analysis_normalize::PostAnalysisNormalize as rustc_mir_transform::pass_manager::MirPass>::run_pass
12: rustc_mir_transform::run_analysis_to_runtime_passes
13: rustc_mir_transform::mir_drops_elaborated_and_const_checked
14: rustc_query_impl::query_impl::mir_drops_elaborated_and_const_checked::invoke_provider_fn::__rust_begin_short_backtrace
15: rustc_query_impl::execution::try_execute_query::<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>, {rustc_query_impl::QueryFlags { is_anon: false, is_depth_limit: false, is_feedable: false }}, false>
16: rustc_query_impl::query_impl::mir_drops_elaborated_and_const_checked::get_query_non_incr::__rust_end_short_backtrace
17: <rustc_middle::ty::context::TyCtxt>::par_hir_body_owners::<rustc_interface::passes::run_required_analyses::{closure#1}::{closure#0}>::{closure#0}
18: rustc_interface::passes::analysis
19: rustc_query_impl::execution::try_execute_query::<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>, {rustc_query_impl::QueryFlags { is_anon: false, is_depth_limit: false, is_feedable: false }}, false>
20: rustc_query_impl::query_impl::analysis::get_query_non_incr::__rust_end_short_backtrace
21: <rustc_interface::passes::create_and_enter_global_ctxt<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2}>::{closure#2} as core::ops::function::FnOnce<(&rustc_session::session::Session, rustc_middle::ty::context::CurrentGcx, alloc::sync::Arc<rustc_data_structures::jobserver::Proxy>, &std::sync::once_lock::OnceLock<rustc_middle::ty::context::GlobalCtxt>, &rustc_data_structures::sync::worker_local::WorkerLocal<rustc_middle::arena::Arena>, &rustc_data_structures::sync::worker_local::WorkerLocal<rustc_hir::Arena>, rustc_driver_impl::run_compiler::{closure#0}::{closure#2})>>::call_once::{shim:vtable#0}
22: rustc_interface::interface::run_compiler::<(), rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}
23: std::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface::util::run_in_thread_with_globals<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<(), rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
24: <std::thread::lifecycle::spawn_unchecked<rustc_interface::util::run_in_thread_with_globals<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<(), rustc_driver_impl::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
25: <std::sys::thread::unix::Thread>::new::thread_start
26: <unknown>
27: clone
note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
note: please make sure that you have updated to the latest nightly
note: please attach the file at `/playground/rustc-ice-2026-02-17T04_45_48-26.txt` to your bug report
note: rustc 1.95.0-nightly (3c9faa0d0 2026-02-16) running on x86_64-unknown-linux-gnu
note: compiler flags: --crate-type lib -C embed-bitcode=no -C codegen-units=1 -C debuginfo=2
note: some of the compiler flags provided by cargo are hidden
query stack during panic:
end of query stack
error: could not compile `playground` (lib)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the minimized example with the reported Rust nightly, then compare it with issue #139658. Start at compiler/rustc_trait_selection/src/traits/query/normalize.rs:350 and follow the delayed-bug path shown in the backtrace. Done means this recursive generic RPIT case no longer produces an internal compiler error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100