I was working on yet another implementation of the builder pattern, and pushing the type system to hold info about whether a type has been initialized. I used a proc macro to handle the boiler plate code. When I was testing it I ran into this ICE.
The code I wrote should fail to compile, but it shouldn't cause an ICE.
I tried creating a minimal example, but when I inline the macro call, the ICE disappears.
#[macro_use]
extern crate partial_init_derive;
extern crate partial_init_core;
#[derive(PartialInit)]
struct Foo<T> {
thing: (T,),
}
fn main() {
let foo = <Foo<_> as partial_init_core::PartialInit>::uninit().build();
}
note removing type inference by changing main to the code below, also gets rid of hte ICE.
fn main() {
let foo = <Foo<()> as partial_init_core::PartialInit>::uninit().build();
}
The PartialInit derive macro creates this code (comments have been stripped for brevity):
#[allow(non_camel_case_types)]
mod __Foo__ {
pub enum thing {}
impl ::partial_init_core::FieldName for thing {}
pub mod uninit {
use super::super::*;
pub type thing<T> = ::partial_init_core::Uninit<super::thing, T>;
}
}
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
struct PartialFoo<T, thing: ::partial_init_core::MaybeInit<__Foo__::thing, T>> {
thing: thing,
__phantom_data__partial_init_: ::partial_init_core::PhantomData<(T)>,
}
#[allow(non_camel_case_types)]
impl<T> ::partial_init_core::PartialInit for Foo<T> {
type Uninitialized = PartialFoo<T, ::partial_init_core::Uninit<__Foo__::thing, T>>;
#[inline(always)]
fn uninit() -> Self::Uninitialized {
Default::default()
}
}
impl<T> Default for PartialFoo<T, ::partial_init_core::Uninit<__Foo__::thing, T>> {
#[inline(always)]
fn default() -> Self {
PartialFoo {
__phantom_data__partial_init_: Default::default(),
thing: Default::default(),
}
}
}
#[allow(non_camel_case_types)]
impl<T, thing: ::partial_init_core::Init<__Foo__::thing, T>> PartialFoo<T, thing> {
#[inline(always)]
fn build(self) -> Foo<T> {
Foo {
thing: ::partial_init_core::Init::get(self.thing),
}
}
}
#[allow(non_camel_case_types)]
impl<T> PartialFoo<T, ::partial_init_core::Uninit<__Foo__::thing, T>> {
#[inline(always)]
fn thing<thing: ::partial_init_core::Init<__Foo__::thing, T>>(
self,
thing: thing,
) -> PartialFoo<T, thing> {
PartialFoo {
__phantom_data__partial_init_: Default::default(),
thing,
}
}
}
And the relevant code can be seen here.
the run crate contains the test code
the partial-init-core contains necessary traits and structs for partial-init-derive
the partial-init-derive crate contains the proc-macro
stack trace
error: internal compiler error: librustc\traits\select.rs:3189: Impl DefId(10/0:33 ~ partial_init_core[903a]::init_impl[0]::{{impl}}[4]) was matchable against Obligation(predicate=Binder(TraitPredicate(<partial_init_core::Uninit<__Foo__::thing, (_,)> as partial_init_core::Init<__Foo__::thing, (_,)>>)),depth=0) but now is not
thread 'main' panicked at 'Box<Any>', librustc_errors\lib.rs:587:9
stack backtrace:
0: <std::sys::windows::args::Args as core::ops::drop::Drop>::drop
1: <std::path::PathBuf as core::convert::From<std::ffi::os_str::OsString>>::from
2: std::panicking::take_hook
3: std::panicking::take_hook
4: <rustc::ty::sty::Binder<rustc::ty::ProjectionPredicate<'tcx>> as rustc::ty::ToPredicate<'tcx>>::to_predicate
5: std::panicking::rust_panic_with_hook
6: <rustc_errors::diagnostic::SubDiagnostic as core::fmt::Debug>::fmt
7: rustc_errors::Handler::bug
8: rustc::ty::context::tls::track_diagnostic
9: rustc::ty::context::tls::track_diagnostic
10: rustc::ty::context::tls::track_diagnostic
11: rustc::ty::context::tls::track_diagnostic
12: rustc::util::bug::bug_fmt
13: rustc::util::bug::bug_fmt
14: rustc::infer::InferCtxt::commit_from
15: rustc::traits::select::SelectionContext::coinductive_predicate
16: rustc::traits::select::SelectionContext::select
17: rustc::ty::context::TypeckTables::expr_ty
18: <rustc::traits::fulfill::FulfillmentContext<'tcx> as rustc::traits::engine::TraitEngine<'tcx>>::select_where_possible
19: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
20: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
21: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
22: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
23: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
24: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
25: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
26: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
27: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
28: <rustc_typeck::check::FnCtxt<'a, 'gcx, 'tcx> as rustc_typeck::astconv::AstConv<'gcx, 'tcx>>::record_ty
29: <rustc_typeck::check::GatherLocalsVisitor<'a, 'gcx, 'tcx> as rustc::hir::intravisit::Visitor<'gcx>>::visit_pat
30: <rustc_typeck::check::method::suggest::TraitInfo as core::cmp::PartialOrd>::partial_cmp
31: <rustc_typeck::astconv::Bounds<'tcx> as core::fmt::Debug>::fmt
32: <rustc_typeck::check::CheckItemTypesVisitor<'a, 'tcx> as rustc::hir::itemlikevisit::ItemLikeVisitor<'tcx>>::visit_item
33: <rustc::traits::query::dropck_outlives::DropckOutlivesResult<'a> as rustc::ty::context::Lift<'tcx>>::lift_to_tcx
34: rustc::ty::query::on_disk_cache::__ty_decoder_impl::<impl serialize::serialize::Decoder for rustc::ty::query::on_disk_cache::CacheDecoder<'a, 'tcx, 'x>>::read_str
35: rustc::ty::context::tls::track_diagnostic
36: rustc::dep_graph::graph::DepGraph::assert_ignored
37: rustc::ty::context::tls::track_diagnostic
38: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
39: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
40: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
41: <rustc_typeck::check::CheckItemTypesVisitor<'a, 'tcx> as rustc::hir::itemlikevisit::ItemLikeVisitor<'tcx>>::visit_item
42: rustc::ty::query::on_disk_cache::__ty_decoder_impl::<impl serialize::serialize::Decoder for rustc::ty::query::on_disk_cache::CacheDecoder<'a, 'tcx, 'x>>::read_str
43: rustc::ty::context::tls::track_diagnostic
44: rustc::dep_graph::graph::DepGraph::assert_ignored
45: rustc::ty::context::tls::track_diagnostic
46: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
47: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_print_query_stack
48: rustc_typeck::check_crate
49: <unknown>
50: <rustc_driver::pretty::NoAnn<'hir> as rustc_driver::pretty::HirPrinterSupport<'hir>>::sess
51: <rustc_driver::CompilationFailure as core::fmt::Debug>::fmt
52: rustc_driver::driver::compile_input
53: rustc_driver::run_compiler
54: rustc_driver::target_features::add_configuration
55: rustc_driver::run_compiler
56: rustc_driver::target_features::add_configuration
57: _rust_maybe_catch_panic
58: rustc_driver::profile::dump
59: rustc_driver::main
60: <unknown>
61: std::panicking::update_panic_count
62: _rust_maybe_catch_panic
63: std::rt::lang_start_internal
64: <unknown>
65: <unknown>
66: BaseThreadInitThunk
67: RtlUserThreadStart
query stack during panic:
#0 [typeck_tables_of] processing `main`
#1 [typeck_item_bodies] type-checking all item bodies
end of query stack
error: aborting due to previous error
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: rustc 1.30.0 (da5f414c2 2018-10-24) running on x86_64-pc-windows-msvc
note: compiler flags: -C debuginfo=2 -C incremental --crate-type bin
note: some of the compiler flags provided by cargo are hidden
error: Could not compile `run`.
I was working on yet another implementation of the builder pattern, and pushing the type system to hold info about whether a type has been initialized. I used a proc macro to handle the boiler plate code. When I was testing it I ran into this ICE.
The code I wrote should fail to compile, but it shouldn't cause an ICE.
I tried creating a minimal example, but when I inline the macro call, the ICE disappears.
note removing type inference by changing
mainto the code below, also gets rid of hte ICE.The
PartialInitderive macro creates this code (comments have been stripped for brevity):And the relevant code can be seen here.
the
runcrate contains the test codethe
partial-init-corecontains necessary traits and structs for partial-init-derivethe
partial-init-derivecrate contains the proc-macrostack trace