Skip to content

ICE: broken MIR: equate_inputs_and_outputs: NoSolution #112604

Closed
@K4rakara

Description

@K4rakara

All of this is yanked out of my work-in-progress bug-for-bug* Misskey Flavored markdown parser, which uses the Parser trait, as defined below, to hopefully allow the compiler to create well-optimized functions via inlining and such.

Where things get messy is in the introduction of the DynParser trait, which uses the same technique used by the lending_iterator and higher-kinded-types crates in order to remove the generic lifetime from its associated type, Output, since lifetime-only generic associated types aren't object-safe (yet?), despite lifetime-only generic parameters being object-safe.

Object-safety is required in this case, because the impl Trait syntax doesn't support cyclic types (for obvious reasons), so boxing and dynamic dispatch is necessary in order to break said cycle.

*as in, it behaves identically to mfm-js, regardless of if that behavior is really "correct" behavior for a markdown parser or not.

Code

Sorry for the rather large reproduction, this was as small as I was able to get it 😓
#![feature(decl_macro)]
#![feature(lazy_cell)]
#![feature(never_type)]

// Stand-in for the `higher-kinded-types` crate:
mod higher_kinded_types {
    use with_lifetime::WithLifetime;
    mod with_lifetime {
        pub trait WithLifetime<'lt> : Send + Sync + Unpin {
            type T;
        }

        impl<'lt, T : ?Sized + WithLifetime<'lt>>
            WithLifetime<'lt>
        for
            crate::higher_kinded_types::__private::HKT<T>
        {
            type T = T::T;
        }
    }

    pub trait HKT : Send + Sync + Unpin + seal::Sealed {
        type __<'lt>;
    }

    mod seal {
        pub trait Sealed {}
        impl<T : ?Sized> Sealed for super::__private::HKT<T> {}
    }

    impl<T : ?Sized> HKT for T
    where
        Self : for<'any> WithLifetime<'any> + seal::Sealed,
    {
        type __<'lt> = <Self as WithLifetime<'lt>>::T;
    }

    mod __private {
        pub use {::core, super::with_lifetime::WithLifetime};
        pub struct HKT<T : ?Sized>(::core::marker::PhantomData<T>, !);
    }

    pub macro HKT(<$lt:lifetime> = $T:ty $(,)?) {
        __private::HKT<dyn for<$lt> WithLifetime<$lt, T = $T>>
    }
}

// Stand-in for the `once-cell` crate.
mod once_cell {
    pub mod unsync {
        pub use std::cell::LazyCell as Lazy;
    }
}

use std::str::CharIndices;

use higher_kinded_types::HKT;

pub trait DynParser {
    type Output: HKT;

    fn dyn_parse<'a>(
        &self,
        input: &'a str,
        chars: CharIndices<'a>,
        state: &mut ParserState,
    ) -> Result<'a, <Self::Output as HKT>::__<'a>>;
}

impl<T> DynParser for T
where
    T: Parser,
{
    type Output = HKT!(<'a> = T::Output<'a>);

    fn dyn_parse<'a>(
        &self,
        input: &'a str,
        chars: CharIndices<'a>,
        state: &mut ParserState,
    ) -> Result<'a, <Self::Output as HKT>::__<'a>> {
        self.parse(input, chars, state)
    }
}

pub trait Parser {
    type Output<'a>;
    
    fn parse<'a>(
        &self,
        input: &'a str,
        chars: CharIndices<'a>,
        state: &mut ParserState,
    ) -> Result<'a, Self::Output<'a>>;
}

impl<Output: HKT> Parser for dyn '_ + DynParser<Output = Output> {
    type Output<'a> = Output::__<'a>;

    fn parse<'a>(
        &self,
        input: &'a str,
        chars: CharIndices<'a>,
        state: &mut ParserState,
    ) -> Result<'a, Self::Output<'a>> {
        self.dyn_parse(input, chars, state)
    }
}

impl<T> Parser for Box<T>
where
    T: ?Sized + Parser,
{
    type Output<'a> = T::Output<'a>;

    fn parse<'a>(
        &self,
        input: &'a str,
        chars: CharIndices<'a>,
        state: &mut ParserState,
    ) -> Result<'a, Self::Output<'a>> {
        <T as Parser>::parse(self, input, chars, state)
    }
}

#[derive(Clone, Debug, Default)]
pub struct ParserState { }

pub type Result<'a, T, E = ()> = ::std::result::Result<(CharIndices<'a>, T), E>;

pub const fn always<T>(value: T) -> impl for<'a> Parser<Output<'a> = T>
where
    T: Clone,
{
    #[derive(Clone)]
    struct Always<T> { value: T }

    impl<T> Parser for Always<T>
    where
        T: Clone,
    {
        type Output<'a> = T;

        fn parse<'a>(
            &self,
            _: &'a str,
            chars: CharIndices<'a>,
            _: &mut ParserState,
        ) -> Result<'a, Self::Output<'a>> {
            Ok((chars, self.value.clone()))
        }
    }

    Always { value }
}

pub const fn lazy<T, F>(init: F) -> impl for<'a> Parser<Output<'a> = T::Output<'a>>
where
    F: FnOnce() -> T,
    T: Parser,
{
    struct Lazy<F, T> { inner: once_cell::unsync::Lazy<T, F> }

    impl<F, T> Parser for Lazy<F, T>
    where
        F: FnOnce() -> T,
        T: Parser,
    {
        type Output<'a> = T::Output<'a>;

        fn parse<'a>(
            &self,
            input: &'a str,
            chars: CharIndices<'a>,
            state: &mut ParserState,
        ) -> Result<'a, Self::Output<'a>> {
            self.inner.parse(input, chars, state)
        }
    }

    Lazy { inner: once_cell::unsync::Lazy::new(init) }
}

pub fn uncycle<'a, T>(parser: T) -> Box<dyn 'a + DynParser<Output = HKT!(<'b> = T::Output<'b>)>>
where
    T: Parser + 'a,
{
    Box::new(parser)
}

/// vvv HERE vvv
pub fn foo() -> impl for<'a> Parser<Output<'a> = ()> {
    lazy(|| uncycle(always(())))
}

fn main() {
    println!("Hello, world!");
}

Meta

rustc --version --verbose:

rustc 1.72.0-nightly (df77afbca 2023-06-12)
binary: rustc
commit-hash: df77afbcaf3365a32066a8ca4a00ae6fc9a69647
commit-date: 2023-06-12
host: x86_64-unknown-linux-gnu
release: 1.72.0-nightly
LLVM version: 16.0.5

Error output

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

error: internal compiler error: broken MIR in DefId(0:99 ~ delay_span_bug_ice[dc5f]::foo::{closure#0}) (bb0[0]): equate_inputs_and_outputs: `std::boxed::Box<dyn DynParser<Output = higher_kinded_types::__private::HKT<dyn for<'b> higher_kinded_types::with_lifetime::WithLifetime<'b, for<'b> T = ()>>>>==std::boxed::Box<dyn DynParser<Output = higher_kinded_types::__private::HKT<dyn for<'b> higher_kinded_types::with_lifetime::WithLifetime<'b, for<'b> T = <impl Parser<Output = ()> as Parser>::Output<'b>>>>>` failed with `NoSolution`
   --> src/main.rs:193:10
    |
193 |     lazy(|| uncycle(always(())))
    |          ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: delayed at compiler/rustc_borrowck/src/type_check/input_output.rs:133:13
Backtrace

 0: <rustc_errors::HandlerInner>::emit_diagnostic
 1: <rustc_errors::Handler>::delay_span_bug::<rustc_span::span_encoding::Span, alloc::string::String>
 2: rustc_borrowck::type_check::type_check
 3: rustc_borrowck::nll::compute_regions
 4: rustc_borrowck::do_mir_borrowck
 5: rustc_borrowck::mir_borrowck
 6: 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]>>
 7: <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
 8: 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>
 9: rustc_query_impl::query_impl::mir_borrowck::get_query_incr::__rust_end_short_backtrace
10: <rustc_borrowck::type_check::TypeChecker>::prove_closure_bounds
11: <rustc_borrowck::type_check::TypeChecker>::typeck_mir
12: rustc_borrowck::type_check::type_check
13: rustc_borrowck::nll::compute_regions
14: rustc_borrowck::do_mir_borrowck
15: rustc_borrowck::mir_borrowck
16: 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]>>
17: <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
18: 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>
19: rustc_query_impl::query_impl::mir_borrowck::get_query_incr::__rust_end_short_backtrace
20: rustc_hir_analysis::collect::type_of::opaque::find_opaque_ty_constraints_for_rpit
21: rustc_hir_analysis::collect::type_of::type_of
22: rustc_query_impl::plumbing::__rust_begin_short_backtrace::<rustc_query_impl::query_impl::type_of::dynamic_query::{closure#2}::{closure#0}, rustc_middle::query::erase::Erased<[u8; 8]>>
23: <rustc_query_impl::query_impl::type_of::dynamic_query::{closure#2} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_span::def_id::DefId)>>::call_once
24: rustc_query_system::query::plumbing::try_execute_query::<rustc_query_impl::DynamicConfig<rustc_query_system::query::caches::DefaultCache<rustc_span::def_id::DefId, rustc_middle::query::erase::Erased<[u8; 8]>>, false, false, false>, rustc_query_impl::plumbing::QueryCtxt, true>
25: rustc_query_impl::query_impl::type_of::get_query_incr::__rust_end_short_backtrace
26: rustc_middle::query::plumbing::query_get_at::<rustc_query_system::query::caches::DefaultCache<rustc_span::def_id::DefId, rustc_middle::query::erase::Erased<[u8; 8]>>>
27: rustc_hir_analysis::check::check::check_mod_item_types
28: rustc_query_impl::plumbing::__rust_begin_short_backtrace::<rustc_query_impl::query_impl::check_mod_item_types::dynamic_query::{closure#2}::{closure#0}, rustc_middle::query::erase::Erased<[u8; 0]>>
29: <rustc_query_impl::query_impl::check_mod_item_types::dynamic_query::{closure#2} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, rustc_span::def_id::LocalDefId)>>::call_once
30: 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; 0]>>, false, false, false>, rustc_query_impl::plumbing::QueryCtxt, true>
31: rustc_query_impl::query_impl::check_mod_item_types::get_query_incr::__rust_end_short_backtrace
32: <rustc_middle::hir::map::Map>::for_each_module::<rustc_hir_analysis::check_crate::{closure#6}::{closure#0}>
33: <rustc_session::session::Session>::time::<(), rustc_hir_analysis::check_crate::{closure#6}>
34: rustc_hir_analysis::check_crate
35: rustc_interface::passes::analysis
36: 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]>>
37: <rustc_query_impl::query_impl::analysis::dynamic_query::{closure#2} as core::ops::function::FnOnce<(rustc_middle::ty::context::TyCtxt, ())>>::call_once
38: 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>
39: rustc_query_impl::query_impl::analysis::get_query_incr::__rust_end_short_backtrace
40: <rustc_middle::ty::context::GlobalCtxt>::enter::<rustc_driver_impl::run_compiler::{closure#1}::{closure#2}::{closure#4}, core::result::Result<(), rustc_span::ErrorGuaranteed>>
41: <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>>
42: <scoped_tls::ScopedKey<rustc_span::SessionGlobals>>::set::<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>>
43: 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>>
44: <<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}
45: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
           at /rustc/df77afbcaf3365a32066a8ca4a00ae6fc9a69647/library/alloc/src/boxed.rs:1985:9
46: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
           at /rustc/df77afbcaf3365a32066a8ca4a00ae6fc9a69647/library/alloc/src/boxed.rs:1985:9
47: std::sys::unix::thread::Thread::new::thread_start
           at /rustc/df77afbcaf3365a32066a8ca4a00ae6fc9a69647/library/std/src/sys/unix/thread.rs:108:17
48: start_thread
49: __clone3

Metadata

Metadata

Assignees

Labels

A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions