Description
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`.