New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICE: Existential type (w/ and w/o NLL) #53598

Open
andreytkachenko opened this Issue Aug 22, 2018 · 6 comments

Comments

Projects
None yet
7 participants
@andreytkachenko
Copy link

andreytkachenko commented Aug 22, 2018

here is the example:

#![feature(nll, existential_type)]

pub trait Engine {}
pub trait RenderImplementation<E, CE> 
    where E: Engine,
          CE: Engine,
{
    fn render_impl<C: Renderable<CE>>(&self, eng: &E, children: &C);
}
pub trait Renderable<E> 
    where E: Engine,
{
    fn render(&self, eng: &E);
}
pub trait View<E, CE>
    where E: Engine,
          CE: Engine,
{
    type Renderable: Renderable<E>;

    fn build<C: Renderable<CE> + 'static>(self, children: Option<C>) -> Self::Renderable;
}

pub struct Node <E, I, CHE, CH>
    where 
        E: Engine,
        CHE: Engine,
        I: RenderImplementation<E, CHE>,
        CH: Renderable<CHE>
{
    _m: std::marker::PhantomData<(I, CH, E, CHE)>
}

impl<E, I, CHE, CH> Node<E, I, CHE, CH>
    where 
        E: Engine,
        CHE: Engine,
        I: RenderImplementation<E, CHE>,
        CH: Renderable<CHE>
{
    pub fn new(_item: I, _children: CH) -> Self {
        Self {
            _m: Default::default()
        }
    }
}

impl<E, I, CHE, CH> Renderable<E> for Node<E, I, CHE, CH>
    where 
        E: Engine,
        CHE: Engine,
        I: RenderImplementation<E, CHE>,
        CH: Renderable<CHE>
{
    fn render(&self, _eng: &E) {}
}

impl <E: Engine, T: Renderable<E>> Renderable<E> for Option<T> {
    fn render(&self, _eng: &E) {}
}

pub struct HtmlEngine;
impl Engine for HtmlEngine {}

pub struct Div;

impl RenderImplementation<HtmlEngine, HtmlEngine> for Div {   
    fn render_impl<C>(&self, _eng: &HtmlEngine, _children: &C)
        where C: Renderable<HtmlEngine> 
    {}
}

impl View<HtmlEngine, HtmlEngine> for Div {
    existential type Renderable: Renderable<HtmlEngine>;

    fn build<C: Renderable<HtmlEngine> + 'static>(self, children: Option<C>) -> Self::Renderable {
        Node::new(self, children)
    }
}

fn main() {}

this example will compile well if you remove nll

@matthiaskrgr

This comment has been minimized.

Copy link
Contributor

matthiaskrgr commented Aug 22, 2018

Backtrace:


   Compiling issue_53598 v0.1.0 (file:///tmp/issue_53598)
error: internal compiler error: librustc/ty/subst.rs:479: Type parameter `C/#0` (C/0) out of range when substituting (root type=Some(Node<HtmlEngine, Div, HtmlEngine, std::option::Option<C>>)) substs=[]
thread 'main' panicked at 'Box<Any>', librustc_errors/lib.rs:517:9
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:211
   3: std::panicking::default_hook
             at libstd/panicking.rs:227
   4: rustc::util::common::panic_hook
   5: std::panicking::rust_panic_with_hook
             at libstd/panicking.rs:479
   6: std::panicking::begin_panic
   7: rustc_errors::Handler::span_bug
   8: rustc::util::bug::opt_span_bug_fmt::{{closure}}
   9: rustc::ty::context::tls::with_opt::{{closure}}
  10: rustc::ty::context::tls::with_context_opt
  11: rustc::ty::context::tls::with_opt
  12: rustc::util::bug::opt_span_bug_fmt
  13: rustc::util::bug::span_bug_fmt
  14: <rustc::ty::subst::SubstFolder<'a, 'gcx, 'tcx> as rustc::ty::fold::TypeFolder<'gcx, 'tcx>>::fold_ty
  15: rustc::ty::fold::TypeFoldable::fold_with
  16: rustc::ty::structural_impls::<impl rustc::ty::fold::TypeFoldable<'tcx> for &'tcx rustc::ty::TyS<'tcx>>::super_fold_with
  17: <rustc::ty::subst::SubstFolder<'a, 'gcx, 'tcx> as rustc::ty::fold::TypeFolder<'gcx, 'tcx>>::fold_ty
  18: rustc::ty::fold::TypeFoldable::fold_with
  19: rustc::ty::structural_impls::<impl rustc::ty::fold::TypeFoldable<'tcx> for &'tcx rustc::ty::TyS<'tcx>>::super_fold_with
  20: <rustc::ty::subst::SubstFolder<'a, 'gcx, 'tcx> as rustc::ty::fold::TypeFolder<'gcx, 'tcx>>::fold_ty
  21: rustc::infer::InferCtxt::commit_if_ok
  22: <rustc::traits::query::type_op::custom::CustomTypeOp<F, G> as rustc::traits::query::type_op::TypeOp<'gcx, 'tcx>>::fully_perform
  23: rustc_mir::borrow_check::nll::type_check::type_check
  24: rustc_mir::borrow_check::nll::compute_regions
  25: rustc_mir::borrow_check::do_mir_borrowck
  26: rustc::ty::context::GlobalCtxt::enter_local
  27: rustc_mir::borrow_check::mir_borrowck
  28: rustc::ty::query::__query_compute::mir_borrowck
  29: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::mir_borrowck<'tcx>>::compute
  30: rustc::ty::context::tls::with_context
  31: rustc::dep_graph::graph::DepGraph::with_task_impl
  32: <rustc::ty::query::plumbing::JobOwner<'a, 'tcx, Q>>::start
  33: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::force_query_with_job
  34: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::get_query
  35: rustc::ty::query::<impl rustc::ty::context::TyCtxt<'a, 'tcx, 'lcx>>::mir_borrowck
  36: rustc::ty::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::par_body_owners
  37: rustc::util::common::time
  38: rustc::ty::context::tls::enter_context
  39: <std::thread::local::LocalKey<T>>::with
  40: rustc::ty::context::TyCtxt::create_and_enter
  41: rustc_driver::driver::compile_input
  42: rustc_driver::run_compiler_with_pool
  43: syntax::with_globals
  44: <std::panic::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
  45: __rust_maybe_catch_panic
             at libpanic_unwind/lib.rs:102
  46: rustc_driver::run
  47: rustc_driver::main
  48: std::rt::lang_start::{{closure}}
  49: std::panicking::try::do_call
             at libstd/rt.rs:59
             at libstd/panicking.rs:310
  50: __rust_maybe_catch_panic
             at libpanic_unwind/lib.rs:102
  51: std::rt::lang_start_internal
             at libstd/panicking.rs:289
             at libstd/panic.rs:392
             at libstd/rt.rs:58
  52: main
  53: __libc_start_main
  54: <unknown>
query stack during panic:
#0 [mir_borrowck] processing `<Div as View<HtmlEngine, HtmlEngine>>::build`
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-nightly (33b923fd4 2018-08-18) running on x86_64-unknown-linux-gnu
note: compiler flags: -C debuginfo=2 -C incremental -C target-cpu=native --crate-type bin
note: some of the compiler flags provided by cargo are hidden
error: Could not compile `issue_53598`.
To learn more, run the command again with --verbose.
@andreytkachenko

This comment has been minimized.

Copy link
Author

andreytkachenko commented Aug 22, 2018

Hmm I reproduced same ICE with next snippet without nll:

#![feature(existential_type)]

pub trait Engine {}
pub trait RenderImplementation<E, CE> 
    where E: Engine,
          CE: Engine,
{
    fn render_impl<C: Renderable<CE>>(&self, eng: &E, children: &C);
}
pub trait Renderable<E> 
    where E: Engine,
{
    fn render(&self, eng: &E);
}
pub trait View<E, CE>
    where E: Engine,
          CE: Engine,
{
    type Renderable: Renderable<E>;

    fn build<C: Renderable<CE> + 'static>(self, children: Option<C>) -> Self::Renderable;
}

pub struct Node <E, I, CHE, CH>
    where 
        E: Engine,
        CHE: Engine,
        I: RenderImplementation<E, CHE>,
        CH: Renderable<CHE>
{
    _m: std::marker::PhantomData<(I, CH, E, CHE)>
}

impl<E, I, CHE, CH> Node<E, I, CHE, CH>
    where 
        E: Engine,
        CHE: Engine,
        I: RenderImplementation<E, CHE>,
        CH: Renderable<CHE>
{
    pub fn new(_item: I, _children: CH) -> Self {
        Self {
            _m: Default::default()
        }
    }
}

impl<E, I, CHE, CH> Renderable<E> for Node<E, I, CHE, CH>
    where 
        E: Engine,
        CHE: Engine,
        I: RenderImplementation<E, CHE>,
        CH: Renderable<CHE>
{
    fn render(&self, _eng: &E) {}
}

impl <E: Engine, T: Renderable<E>> Renderable<E> for Option<T> {
    fn render(&self, _eng: &E) {}
}

pub struct HtmlEngine;
impl Engine for HtmlEngine {}

pub struct Div;

impl RenderImplementation<HtmlEngine, HtmlEngine> for Div {   
    fn render_impl<C>(&self, _eng: &HtmlEngine, _children: &C)
        where C: Renderable<HtmlEngine> 
    {}
}

impl View<HtmlEngine, HtmlEngine> for Div {
    existential type Renderable: Renderable<HtmlEngine>;

    fn build<C: Renderable<HtmlEngine> + 'static>(self, children: Option<C>) -> Self::Renderable {
        Node::new(self, children)
    }
}

#[derive(Default)]
pub struct Stub<E: Engine> {
    _e: std::marker::PhantomData<E>
}

impl<E: Engine> Renderable<E> for Stub<E>  {
    fn render(&self, _eng: &E) {}
}

fn main() {
    Div.build::<Stub<_>>(None);
}

@andreytkachenko andreytkachenko changed the title ICE: Existential type + NLL ICE: Existential type [+ NLL] Aug 22, 2018

@estebank estebank added the I-ICE label Aug 22, 2018

@nikomatsakis nikomatsakis added T-compiler and removed A-NLL labels Aug 27, 2018

@pnkfelix pnkfelix changed the title ICE: Existential type [+ NLL] ICE: Existential type (w/ and w/o NLL) Aug 28, 2018

@Arnavion

This comment has been minimized.

Copy link

Arnavion commented Jan 29, 2019

Smaller repro:

#![feature(existential_type)]

pub trait Foo {
    type Item: std::fmt::Debug;

    fn foo<T: std::fmt::Debug>(_: T) -> Self::Item;
}

#[derive(Debug)]
pub struct S<T>(std::marker::PhantomData<T>);

pub struct S2;

impl Foo for S2 {
    existential type Item: std::fmt::Debug;

    fn foo<T: std::fmt::Debug>(_: T) -> Self::Item {
        S::<T>(Default::default())
    }
}

Edit: AFAICT the problem is the existential assoc type is being made dependent on the type parameter of the trait method (<S2 as Foo>::foo's T in this repro, <Div as View<HtmlEngine, HtmlEngine>>::build's C in the OP). So it would be a compile error if it weren't for the ICE.

@andreytkachenko

This comment has been minimized.

Copy link
Author

andreytkachenko commented Jan 29, 2019

@Arnavion you example compiles without ICE.

@andreytkachenko

This comment has been minimized.

Copy link
Author

andreytkachenko commented Jan 29, 2019

@Arnavion, sorry it needs to be added nll feature or used 2018 edition.

Here is complete one which fails to compile regardless nll feature:

#![feature(existential_type)]

pub trait Foo {
    type Item: std::fmt::Debug;

    fn foo<T: std::fmt::Debug>(_: T) -> Self::Item;
}

#[derive(Debug)]
pub struct S<T>(std::marker::PhantomData<T>);

pub struct S2;

impl Foo for S2 {
    existential type Item: std::fmt::Debug;

    fn foo<T: std::fmt::Debug>(_: T) -> Self::Item {
        S::<T>(Default::default())
    }
}

fn main() {
    S2::foo(123);
}

@oli-obk oli-obk self-assigned this Jan 29, 2019

@Arnavion

This comment has been minimized.

Copy link

Arnavion commented Jan 29, 2019

@andreytkachenko Right, 2015 doesn't hit the error until you actually try to use the type.

Regardless, as I said in my previous comment, this code should be a compile error anyway regardless of edition, since it's trying to declare an associated type that depends on the type parameters of the trait method rather than the trait.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment