Needs help in debugging a rustc ICE

When I am working on a faily large repository, I was hit by a rustc ICE. However, the message and the project itself is way too messy (By the way the project uses a considerable amount of generics upon generics and GATs, and I'm sure the repo is very broken to begin with) and I cannot even draft a meaningful issue report let alone locating the bug.

The ICE message is attached at the end.

The help I need is:

  1. Tools to pretty print the humongous single line ParamEnvAnd. I can't find a formatter that turns the single line print into multiline pretty print
  2. Even better, possibly some explanation on the meaning of some fields in the message.
  3. Insight of the nature of the bug
  4. Anything that can help me pinpoint the bug.
/// About hundreds of warnings ...............

error: internal compiler error: no errors encountered even though `delay_span_bug` issued

error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [Binder { value: ProjectionPredicate(AliasTy { args: [L], def_id: DefId(0:3074 ~ epgi_core[11b1]::tree::layer::Layer::ChildCanvas) }, Term::Ty(<<E as tree::element::Element>::ChildProtocol as foundation::protocol::Protocol>::Canvas)), bound_vars: [] }, Binder { value: ProjectionPredicate(AliasTy { args: [L], def_id: DefId(0:3073 ~ epgi_core[11b1]::tree::layer::Layer::ParentCanvas) }, Term::Ty(<<E as tree::element::Element>::ParentProtocol as foundation::protocol::Protocol>::Canvas)), bound_vars: [] }, Binder { value: TraitPredicate(<L as tree::layer::Layer>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<L as std::marker::Sync>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<L as std::marker::Send>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as foundation::protocol::LayerProtocol>, polarity:Positive), bound_vars: [] }, Binder { value: ProjectionPredicate(AliasTy { args: [<E as tree::element::Element>::ParentProtocol], def_id: DefId(0:629 ~ epgi_core[11b1]::foundation::protocol::Protocol::Transform) }, Term::Ty(<<<E as tree::element::Element>::ParentProtocol as foundation::protocol::Protocol>::Canvas as foundation::protocol::Canvas>::Transform)), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as foundation::protocol::Protocol>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as std::marker::Sync>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as std::marker::Send>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as std::clone::Clone>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as std::marker::Sized>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as std::marker::Copy>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ParentProtocol as std::fmt::Debug>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as foundation::protocol::LayerProtocol>, polarity:Positive), bound_vars: [] }, Binder { value: ProjectionPredicate(AliasTy { args: [<E as tree::element::Element>::ChildProtocol], def_id: DefId(0:629 ~ epgi_core[11b1]::foundation::protocol::Protocol::Transform) }, Term::Ty(<<<E as tree::element::Element>::ChildProtocol as foundation::protocol::Protocol>::Canvas as foundation::protocol::Canvas>::Transform)), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as foundation::protocol::Protocol>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as std::marker::Sync>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as std::marker::Send>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as std::clone::Clone>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as std::marker::Sized>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as std::marker::Copy>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<<E as tree::element::Element>::ChildProtocol as std::fmt::Debug>, polarity:Positive), bound_vars: [] }, Binder { value: ProjectionPredicate(AliasTy { args: [R], def_id: DefId(0:3435 ~ epgi_core[11b1]::tree::render::Render::ChildProtocol) }, Term::Ty(<E as tree::element::Element>::ChildProtocol)), bound_vars: [] }, Binder { value: ProjectionPredicate(AliasTy { args: [R], def_id: DefId(0:3434 ~ epgi_core[11b1]::tree::render::Render::ParentProtocol) }, Term::Ty(<E as tree::element::Element>::ParentProtocol)), bound_vars: [] }, Binder { value: TraitPredicate(<R as tree::render::LayerRender<L>>, polarity:Positive), bound_vars: [] }, Binder { value: ProjectionPredicate(AliasTy { args: [R], def_id: DefId(0:3444 ~ epgi_core[11b1]::tree::render::Render::LayerOrUnit) }, Term::Ty(L)), bound_vars: [] }, Binder { value: TraitPredicate(<R as tree::render::Render>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<R as std::marker::Sync>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<R as std::marker::Send>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<E as tree::element::RenderElement<R>>, polarity:Positive), bound_vars: [] }, Binder { value: ProjectionPredicate(AliasTy { args: [E], def_id: DefId(0:2911 ~ epgi_core[11b1]::tree::element::Element::RenderOrUnit) }, Term::Ty(R)), bound_vars: [] }, Binder { value: TraitPredicate(<E as tree::element::Element>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<E as std::clone::Clone>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<E as std::marker::Sync>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<E as std::marker::Send>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<L as std::marker::Sized>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<R as std::marker::Sized>, polarity:Positive), bound_vars: [] }, Binder { value: TraitPredicate(<E as std::marker::Sized>, polarity:Positive), bound_vars: [] }, Binder { value: OutlivesPredicate(L, ReStatic), bound_vars: [] }, Binder { value: OutlivesPredicate(<E as tree::element::Element>::ParentProtocol, ReStatic), bound_vars: [] }, Binder { value: OutlivesPredicate(<E as tree::element::Element>::ChildProtocol, ReStatic), bound_vars: [] }, Binder { value: OutlivesPredicate(R, ReStatic), bound_vars: [] }, Binder { value: OutlivesPredicate(E, ReStatic), bound_vars: [] }], reveal: UserFacing }, value: DropckOutlives { dropped_ty: std::sync::Arc<tree::element::ElementNode<E>> } }
  |
  = note: delayed at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs:162:32
             0: std::backtrace::Backtrace::create
             1: <rustc_errors::HandlerInner>::emit_diagnostic
             2: <rustc_errors::Handler>::delay_span_bug::<rustc_span::span_encoding::Span, alloc::string::String>
             3: <rustc_borrowck::type_check::liveness::trace::LivenessContext>::compute_drop_data
             4: rustc_borrowck::type_check::liveness::trace::trace
             5: rustc_borrowck::type_check::liveness::generate
             6: rustc_borrowck::type_check::type_check
             7: rustc_borrowck::nll::compute_regions
             8: rustc_borrowck::do_mir_borrowck
             9: rustc_borrowck::mir_borrowck
            10: rustc_query_impl::plumbing::__rust_begin_short_backtrace::<rustc_query_impl::query_impl::mir_borrowck::dynamic_query::{closure#2}::{closure#0}, rustc_middle::query::erase::Erased<[u8; 8]>>
            11: <rustc_query_impl::query_impl::mir_borrowck::dynamic_query::{closure#2} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId)>>::call_once
            12: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::DynamicConfig<rustc_query_system::query::caches::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::Erased<[u8; 8]>>, false, false, false>, rustc_query_impl::plumbing::QueryCtxt, true>
            13: rustc_query_impl::query_impl::mir_borrowck::get_query_incr::__rust_end_short_backtrace
            14: <core::panic::unwind_safe::AssertUnwindSafe<rustc_data_structures::sync::par_for_each_in<&[rustc_span::def_id::LocalDefId], <rustc_middle::hir::map::Map>::par_body_owners<rustc_interface::passes::analysis::{closure#1}::{closure#0}>::{closure#0}>::{closure#0}::{closure#0}> as core::ops::function::FnOnce<()>>::call_once
            15: rustc_data_structures::sync::par_for_each_in::<&[rustc_span::def_id::LocalDefId], <rustc_middle::hir::map::Map>::par_body_owners<rustc_interface::passes::analysis::{closure#1}::{closure#0}>::{closure#0}>
            16: <rustc_session::session::Session>::time::<(), rustc_interface::passes::analysis::{closure#1}>
            17: rustc_interface::passes::analysis
            18: rustc_query_impl::plumbing::__rust_begin_short_backtrace::<rustc_query_impl::query_impl::analysis::dynamic_query::{closure#2}::{closure#0}, rustc_middle::query::erase::Erased<[u8; 1]>>
            19: <rustc_query_impl::query_impl::analysis::dynamic_query::{closure#2} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, ())>>::call_once
            20: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::DynamicConfig<rustc_query_system::query::caches::SingleCache<rustc_middle::query::erase::Erased<[u8; 1]>>, false, false, false>, rustc_query_impl::plumbing::QueryCtxt, true>
            21: rustc_query_impl::query_impl::analysis::get_query_incr::__rust_end_short_backtrace
            22: <rustc_middle::ty::context::GlobalCtxt>::enter::<rustc_driver_impl::run_compiler::{closure#1}::{closure#2}::{closure#6}, core::result::Result<(), rustc_span::ErrorGuaranteed>>
            23: <rustc_interface::interface::Compiler>::enter::<rustc_driver_impl::run_compiler::{closure#1}::{closure#2}, core::result::Result<core::option::Option<rustc_interface::queries::Linker>, rustc_span::ErrorGuaranteed>>
            24: std::sys_common::backtrace::__rust_begin_short_backtrace::<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>
            25: <<std::thread::Builder>::spawn_unchecked_<rustc_interface::util::run_in_thread_pool_with_globals<rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#0}::{closure#0}, core::result::Result<(), rustc_span::ErrorGuaranteed>>::{closure#1} as core::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
            26: std::sys::unix::thread::Thread::new::thread_start
            27: __pthread_joiner_wake
          

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: rustc 1.73.0 (cc66ad468 2023-10-03) running on aarch64-apple-darwin

note: compiler flags: --crate-type lib -C embed-bitcode=no -C debuginfo=2 -C split-debuginfo=unpacked -C incremental=[REDACTED]

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
end of query stack

An update: By enumerating all occurrance of a type in the error message, and commenting them out. I was able to pinpoint the specific few lines of code that introduces this problem. It seems the signature of a complex generic function alone (i.e. with its entire body commented out) is enough to produce this problem.

Though, this is still far from a worthwhile issue report (due to the trait gymnastics involved in the repo, which itself alone would probably not fit in here). Any additional insight is still appreciated

Final update:
Pinpointed the exact trait gymnastic pattern that cause this ICE. It turns out supplying a stricter but quite reasonable type bound inside the generic signature fixes this problem. Working on a reproducible example.

For anyone later with this problem:
The problem seems to be linked to cyclic associated type, with a cyclic type bound in super trait, with an impl trait on trait. Then it gets triggered when your generic function misses some (seemingly implicit) cyclic bound.

I will probably never understand what you have there but now I'm curious to see that complex generic function signature. Any chance of you posting it here?

Sure. Here is basically what was happening. I'm marked out the specific type bound that needs tighten up to avoid ICE

I'll work on a minimal example someday later

// There are two cycles to watch out:
// 1. Between Element and RenderOrUnit (impl-ed for Render)
// 2. Between HktContainer and Parallel

// Function signature in question
pub fn create_root_element<E, R, L>(
    widget: E::ArcWidget,
    element: E,
    element_children: ContainerOf<E, ArcChildElementNode<E::ChildProtocol>>,
    render: R,
    layer: L,
    hooks: Hooks,
    constraints: <E::ParentProtocol as Protocol>::Constraints,
) -> Arc<ElementNode<E>>
where
    E: RenderElement<R>,
    R: LayerRender<
        L,
        ChildContainer = E::ChildContainer, // ----This is the type bounds that needs tighten up--------- 
        ParentProtocol = E::ParentProtocol,
        ChildProtocol = E::ChildProtocol,
    >,
    R::ChildProtocol: LayerProtocol,
    R::ParentProtocol: LayerProtocol,
    L: Layer<
        ParentCanvas = <R::ParentProtocol as Protocol>::Canvas,
        ChildCanvas = <R::ChildProtocol as Protocol>::Canvas,
    >,
{
}

// About <E as Element>::ChildContainer
pub trait Element: Send + Sync + Clone + 'static {
    // ................ 
    type ChildContainer: HktContainer;
    type RenderOrUnit: RenderOrUnit<Self>;
}

// About <R as Render>::ChildContainer
pub trait Render: Send + Sync + Clone + 'static {
    // ................ 
    type ChildContainer: HktContainer;
}

// About HktContainer
pub trait HktContainer {
    type Container<T>: Parallel<Item = T, HktContainer = Self> + Send + Sync
    where
        T: Send + Sync;
}

// About Parallel
pub trait Parallel
{
    // ........................
    type HktContainer: HktContainer<Container<<Self as Parallel>::Item> = Self>;
}

// About RenderElement
pub trait RenderElement<
    R: Render<ParentProtocol = Self::ParentProtocol, ChildProtocol = Self::ChildProtocol>,
>: Element<RenderOrUnit = R>
{
}

// About RenderOrUnit's impl trait on trait
impl<E, R> RenderOrUnit<E> for R
where
    E: RenderElement<Self>,
    R: Render<
        ParentProtocol = E::ParentProtocol,
        ChildProtocol = E::ChildProtocol,
        ChildContainer = E::ChildContainer,
    >,
{
}
// Also RenderOrUnit is impl-ed on the unit type ()

I feel like this is your code trying to say that you've over-complicated things and maybe it's time to introduce some type erasure (e.g. Box<dyn Widget>)... Just because the language allows you to be generic over everything and use HKTs, doesn't mean you need to use it.

Going overboard with generics tends to lead to a poor developer experience due to unreadable error messages and long compile times.

That is my gut reaction. If I found myself having to write code that looked like that I'd start to think I was using the wrong approach. Or go back to Javascript :slight_smile:

While I agree with the sentiment that reducing code complexity makes code easier to reason about (for humans and compilers alike), this is revealing a bug in the compiler.

I had trouble finding the link (hopefully this is the original) but here is a guide on minimizing the reproduction case:

5 Likes

This is a fun project intending with half the purpose being to interrogate Rustc type checker and to see how much ZGC can choke the compiler. So far I'm amazed.

And while you may not believe it, this over-complicated mess actually makes API designing easier as it provides a very good specialization workaround in stable rust.

Fair enough. What is "ZGC"?

One day I might understand it. Then I might believe it :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.