Skip to content
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 whilst experimenting with opaque/existential types. #70877

Closed
mental32 opened this issue Apr 7, 2020 · 4 comments · Fixed by #77956
Closed

ICE whilst experimenting with opaque/existential types. #70877

mental32 opened this issue Apr 7, 2020 · 4 comments · Fixed by #77956
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. F-impl_trait_in_bindings `#![feature(impl_trait_in_bindings)]` F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@mental32
Copy link
Contributor

mental32 commented Apr 7, 2020

ICE whilst experimenting with opaque/existential types.

I tried this code:

#![feature(type_alias_impl_trait)]
#![feature(impl_trait_in_bindings)]

type FooArg<'a> = &'a dyn ToString;
type FooRet = impl std::fmt::Debug;

type FooItem = Box<dyn Fn(FooArg) -> FooRet>;
type Foo = impl Iterator<Item = FooItem>;

#[repr(C)]
struct Bar(u8);

impl Iterator for Bar {
    type Item = FooItem;

    fn next(&mut self) -> Option<Self::Item> {
        Some(Box::new(quux))
    }
}

fn quux(st: FooArg) -> FooRet {
    Some(st.to_string())
}

fn ham() -> Foo {
    Bar(1)
}

fn oof() -> impl std::fmt::Debug {
    let mut bar = ham();
    let func = bar.next().unwrap();
    return func(&"oof");
}

fn main() {
    println!("{:?}", oof());
}

I expected to see this happen: "oof" in stdout

Instead, this happened: ICE!

warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
 --> oops.rs:2:12
  |
2 | #![feature(impl_trait_in_bindings)]
  |            ^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(incomplete_features)]` on by default

error: internal compiler error: Non-defining use of DefId(0:5 ~ oops[317d]::FooRet[0]) with revealed type
  --> oops.rs:25:1
   |
25 | / fn ham() -> Foo {
26 | |     Bar(1)
27 | | }
   | |_^

thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:355:17
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

error: internal compiler error: unexpected panic

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.43.0-nightly (564758c4c 2020-03-08) running on x86_64-unknown-linux-gnu

Meta

rustc --version --verbose:

rustc 1.43.0-nightly (564758c4c 2020-03-08)
binary: rustc
commit-hash: 564758c4c329e89722454dd2fbb35f1ac0b8b47c
commit-date: 2020-03-08
host: x86_64-unknown-linux-gnu
release: 1.43.0-nightly
LLVM version: 9.0

Backtrace:

(The above backtrace but with RUST_BACKTRACE="full")

RUST_BACKTRACE="full" rustc oops.rs                                                                                                                                                                                                                                                                      08:58:45
warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
 --> oops.rs:2:12
  |
2 | #![feature(impl_trait_in_bindings)]
  |            ^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(incomplete_features)]` on by default

error: internal compiler error: Non-defining use of DefId(0:5 ~ oops[317d]::FooRet[0]) with revealed type
  --> oops.rs:25:1
   |
25 | / fn ham() -> Foo {
26 | |     Bar(1)
27 | | }
   | |_^

thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:355:17
stack backtrace:
   0:     0x7f1023ca0784 - backtrace::backtrace::libunwind::trace::h6c956c3ba1fc7bb8
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
   1:     0x7f1023ca0784 - backtrace::backtrace::trace_unsynchronized::ha74600fd7051fbcc
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
   2:     0x7f1023ca0784 - std::sys_common::backtrace::_print_fmt::h136191e12f9131d1
                               at src/libstd/sys_common/backtrace.rs:78
   3:     0x7f1023ca0784 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::he1b6d1e88d44f14b
                               at src/libstd/sys_common/backtrace.rs:59
   4:     0x7f1023cda05c - core::fmt::write::h2da0f6fb1c5744aa
                               at src/libcore/fmt/mod.rs:1063
   5:     0x7f1023c92397 - std::io::Write::write_fmt::h565a38f626356c9a
                               at src/libstd/io/mod.rs:1428
   6:     0x7f1023ca5495 - std::sys_common::backtrace::_print::hb8c44fcba2bbae0d
                               at src/libstd/sys_common/backtrace.rs:62
   7:     0x7f1023ca5495 - std::sys_common::backtrace::print::h450b65b78884d83c
                               at src/libstd/sys_common/backtrace.rs:49
   8:     0x7f1023ca5495 - std::panicking::default_hook::{{closure}}::hf2107f0d1e85e58b
                               at src/libstd/panicking.rs:204
   9:     0x7f1023ca51e2 - std::panicking::default_hook::hed6039e35bf0a02a
                               at src/libstd/panicking.rs:224
  10:     0x7f10242f3899 - rustc_driver::report_ice::h79c3287ca6d2e7bd
  11:     0x7f1023ca5bc5 - std::panicking::rust_panic_with_hook::hfa422439ae633a29
                               at src/libstd/panicking.rs:474
  12:     0x7f1026a6f8ce - std::panicking::begin_panic::h4ebe9e0d0c9344b8
  13:     0x7f1026aa5f2f - <rustc_errors::HandlerInner as core::ops::drop::Drop>::drop::h9b8649ccf972c411
  14:     0x7f102430dc36 - core::ptr::drop_in_place::ha73c7e95b0d52445
  15:     0x7f102431256d - <alloc::rc::Rc<T> as core::ops::drop::Drop>::drop::hb9da4511e93091f7
  16:     0x7f10243606fd - core::ptr::drop_in_place::hdcab46d2516c088e
  17:     0x7f10243478f2 - rustc_interface::interface::run_compiler_in_existing_thread_pool::h6fcbd3ddf26127ee
  18:     0x7f10242fb34c - std::sys_common::backtrace::__rust_begin_short_backtrace::hbc599e437c563f62
  19:     0x7f1023cb7dd7 - __rust_maybe_catch_panic
                               at src/libpanic_unwind/lib.rs:86
  20:     0x7f102434a056 - core::ops::function::FnOnce::call_once{{vtable.shim}}::h29932a57129906c8
  21:     0x7f1023c8211f - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::h17bc559ade1f3898
                               at /rustc/564758c4c329e89722454dd2fbb35f1ac0b8b47c/src/liballoc/boxed.rs:1017
  22:     0x7f1023cb66e0 - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::h5f4de8825e11517b
                               at /rustc/564758c4c329e89722454dd2fbb35f1ac0b8b47c/src/liballoc/boxed.rs:1017
  23:     0x7f1023cb66e0 - std::sys_common::thread::start_thread::h9d05d51d7326efdc
                               at src/libstd/sys_common/thread.rs:13
  24:     0x7f1023cb66e0 - std::sys::unix::thread::Thread::new::thread_start::hc91805f14c4a4cf3
                               at src/libstd/sys/unix/thread.rs:80
  25:     0x7f1023bc346f - start_thread
  26:     0x7f1023ae33d3 - clone
  27:                0x0 - <unknown>

error: internal compiler error: unexpected panic

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.43.0-nightly (564758c4c 2020-03-08) running on x86_64-unknown-linux-gnu

query stack during panic:
end of query stack
@mental32 mental32 changed the title ICE whilst experimenting with opaque types. ICE whilst experimenting with opaque/existential types. Apr 7, 2020
@mental32
Copy link
Contributor Author

mental32 commented Apr 7, 2020

I can still reproduce the issue after a rustup update, new output of rustc --version --verbose:

rustc 1.44.0-nightly (6dee5f112 2020-04-06)
binary: rustc
commit-hash: 6dee5f1126dfd5c9314ee5ae9d9eb010e35ef257
commit-date: 2020-04-06
host: x86_64-unknown-linux-gnu
release: 1.44.0-nightly
LLVM version: 9.0

@jonas-schievink jonas-schievink added A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. F-impl_trait_in_bindings `#![feature(impl_trait_in_bindings)]` F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 7, 2020
@rust-lang-glacier-bot rust-lang-glacier-bot added the glacier ICE tracked in rust-lang/glacier. label Apr 11, 2020
@davidtwco
Copy link
Member

Not completely sure, but I think this might be another example of this ICE (playground):

#![feature(type_alias_impl_trait)]

pub trait Baz { }

impl Baz for () { }

type Qux = impl Baz;

pub trait Foo {
    type Assoc;
}

impl Foo for () {
    type Assoc = Qux;
}

type Bar = impl Foo<Assoc = Qux>;

fn assign() -> Bar {}

fn assign2() -> Qux {}

extern "C" {
    pub fn lint_me() -> <Bar as Foo>::Assoc;
}

fn main() {}

@davidtwco
Copy link
Member

I've looked into this a little bit - I don't know what the correct behavior is, but hopefully this saves someone some time when they go to fix this (or someone can tell me what the correct behavior is and I can fix it). The following assumes the test case from my previous comment.

This error is emitted during MIR type-check here:

tcx.sess.delay_span_bug(
body.span,
&format!(
"Non-defining use of {:?} with revealed type",
opaque_def_id,
),
);

It happens when the DefId isn't in concrete_opaque_types in TypeckTables. concrete_opaque_types is added to during typeck writeback, here:

let old = self.tables.concrete_opaque_types.insert(def_id, new);

In particular, this case is when we're considering the TypeckTables for assign, where fcx.opaque_types has two values - Bar and Qux. For Qux, we end up infering the concrete type to be Qux and fall into this branch:

if def_id == defin_ty_def_id {
debug!(
"skipping adding concrete definition for opaque type {:?} {:?}",
opaque_defn, defin_ty_def_id
);
skip_add = true;
}

This code exists to avoid considering foo1 a defining use in this example:

#![feature(type_alias_impl_trait)]
trait TA {}
impl TA for () {} 
type A = impl TA;
fn foo() -> A { } // defining use
fn foo1() -> A { foo() } // not a defining use

fcx.opaque_types gets those values here from opaque_type_map, which is returned from instantiate_opaque_types:

for (ty, decl) in opaque_type_map {
let _ = opaque_types.insert(ty, decl);
let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
}

That ends up at instantiate_opaque_types_in_map here:

fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {

This looks over the type (in this case, the return type, Bar, of assign, whose definition is impl Foo<Assoc = Qux>) and looks for the opaque types, and creates inference variables for their concrete types.

As a result of this, assign is effectively considered a defining use for both Bar and Qux. Bar is inferred to be () - trivially, because of the return value of assign.

Because Qux is used in the type of Bar, whatever type that ends up being will be considered a defining use of Qux too - and the impl of Foo for () (what Bar is) says that <Bar as Foo>::Assoc should be Qux - so Qux's concrete type is considered to be Qux. That triggers the logic in writeback where we skip adding the concrete type to concrete_opaque_types - and hence the ICE in MIR type check.

As I see it, there are two possible options here:

  1. Don't consider Qux a defining use in this case (when the use in the return type is in a bound), so the concrete type will come from the other defining uses.

  2. Determine that the inference variable that ends up being Qux doesn't come from a defining use (but from the trait implementation) and so should be ignored or an error emitted.

@JohnTitor JohnTitor added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Oct 7, 2020
@JohnTitor
Copy link
Member

Triage: This is no longer ICE with the latest nightly, marking as E-needs-test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. F-impl_trait_in_bindings `#![feature(impl_trait_in_bindings)]` F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ requires-nightly This issue requires a nightly compiler in some way. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Development

Successfully merging a pull request may close this issue.

5 participants