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 on stable and nightly: [codegen_fulfill_obligation] checking if std::ops::FnOnce fulfills its obligations #80351

Closed
codeflo opened this issue Dec 24, 2020 · 25 comments
Assignees
Labels
A-traits Area: Trait system C-bug Category: This is a bug. glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@codeflo
Copy link

codeflo commented Dec 24, 2020

I encountered the following ICE while working on a task queue where the tasks can query for different resources.

Below is a small example. The ICE doesn't seem to be triggered by dead code, which is why I included a main function.

Edit: The following output is from nightly, but I get the same error on stable (rustc 1.48.0 (7eac88a 2020-11-16) running on x86_64-pc-windows-msvc).

Edit 2: I was able to simplify the code quite a bit further. I hope it's close to minimal now.

Code

fn main() {
    enqueue::<(), _>(|_result| {});
}

trait Query<'a> {
    type Result: 'a;
    fn execute() -> Self::Result;
}

impl<'a> Query<'a> for () {
    type Result = ();
    fn execute() -> () {
        ()
    }
}

fn enqueue<Q: for<'q> Query<'q>, F: 'static + for<'r> FnOnce(<Q as Query<'r>>::Result)>(f: F) {
    let _: Box<dyn FnOnce()> = Box::new(move || f(Q::execute()));
}

Meta

rustc --version --verbose:

rustc 1.50.0-nightly (7f9c43cf9 2020-12-23)
binary: rustc
commit-hash: 7f9c43cf98cfe1c369045399929cb098155b8374
commit-date: 2020-12-23
host: x86_64-pc-windows-msvc
release: 1.50.0-nightly

Error output

cargo build:

   Compiling rustc-ice-repro v0.1.0 (C:\***\rustc-ice-repro)
error: internal compiler error: compiler\rustc_trait_selection\src\traits\codegen.rs:78:17: Encountered error `OutputTypeParameterMismatch(Binder(<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<(<() as Query<'_>>::Result,)>>), Binder(<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<((),)>>), Sorts(ExpectedFound { expected: (), found: <() as Query<'_>>::Result }))` selecting `Binder(<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<((),)>>)` during codegen

thread 'rustc' panicked at 'Box<Any>', compiler\rustc_errors\src\lib.rs:958:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.50.0-nightly (7f9c43cf9 2020-12-23) running on x86_64-pc-windows-msvc

note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
#0 [codegen_fulfill_obligation] checking if `std::ops::FnOnce` fulfills its obligations
#1 [resolve_instance] resolving instance `<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<((),)>>::call_once`
end of query stack
error: aborting due to previous error

error: could not compile `rustc-ice-repro`

To learn more, run the command again with --verbose.
Backtrace

Output with RUST_BACKTRACE=full:

   Compiling rustc-ice-repro v0.1.0 (C:\***\rustc-ice-repro)
error: internal compiler error: compiler\rustc_trait_selection\src\traits\codegen.rs:78:17: Encountered error `OutputTypeParameterMismatch(Binder(<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<(<() as Query<'_>>::Result,)>>), Binder(<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<((),)>>), Sorts(ExpectedFound { expected: (), found: <() as Query<'_>>::Result }))` selecting `Binder(<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<((),)>>)` during codegen

thread 'rustc' panicked at 'Box<Any>', compiler\rustc_errors\src\lib.rs:958:9
stack backtrace:
   0:     0x7ffb94b9bce5 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h17841712fc816a42
   1:     0x7ffb94bc871b - core::fmt::write::ha3ea633b18d2da75
   2:     0x7ffb94b8d4cd - <std::io::IoSlice as core::fmt::Debug>::fmt::h9df41d37d9186c48
   3:     0x7ffb94b9fecd - std::panicking::take_hook::h78f8a454f3a4df82
   4:     0x7ffb94b9f9da - std::panicking::take_hook::h78f8a454f3a4df82
   5:     0x7ffb780c9377 - rustc_driver::report_ice::h4f570b5a4fba1dc9
   6:     0x7ffb94ba09af - std::panicking::rust_panic_with_hook::h9fd6ff93f12148ea
   7:     0x7ffb7c9800f0 - <rustc_errors::diagnostic::StringPart as core::fmt::Debug>::fmt::h7af67de8d2c3b61b
   8:     0x7ffb7c980079 - <rustc_errors::diagnostic::StringPart as core::fmt::Debug>::fmt::h7af67de8d2c3b61b
   9:     0x7ffb7c980091 - <rustc_errors::diagnostic::StringPart as core::fmt::Debug>::fmt::h7af67de8d2c3b61b
  10:     0x7ffb7c9b71cb - rustc_errors::HandlerInner::err_count::h50c6ffc480963ac8
  11:     0x7ffb7c9b5312 - rustc_errors::Handler::bug::hb269e1fa812030f1
  12:     0x7ffb7c43696f - rustc_middle::util::bug::bug_fmt::ha0061901ad88904d
  13:     0x7ffb7c4324e0 - rustc_middle::ty::walk::<impl rustc_middle::ty::subst::GenericArg>::walk_shallow::hfcd570d087b90349
  14:     0x7ffb7c432483 - rustc_middle::ty::walk::<impl rustc_middle::ty::subst::GenericArg>::walk_shallow::hfcd570d087b90349
  15:     0x7ffb7c436899 - rustc_middle::util::bug::bug_fmt::ha0061901ad88904d
  16:     0x7ffb7c436807 - rustc_middle::util::bug::bug_fmt::ha0061901ad88904d
  17:     0x7ffb7bf4a884 - unicode_normalization::__test_api::stream_safe::h4a800097b98fe8b6
  18:     0x7ffb7c15ee9c - rustc_trait_selection::traits::codegen::codegen_fulfill_obligation::heb359a89dcda61be
  19:     0x7ffb7a3ad1d9 - regex_syntax::hir::ClassUnicodeRange::end::hbd23d559724b5da5
  20:     0x7ffb7a395725 - regex_syntax::hir::ClassUnicodeRange::end::hbd23d559724b5da5
  21:     0x7ffb7a3a7d02 - regex_syntax::hir::ClassUnicodeRange::end::hbd23d559724b5da5
  22:     0x7ffb7a3b4f4d - rustc_ty_utils::instance::provide::h4b164d63df4db7c9
  23:     0x7ffb7a368f39 - regex_syntax::hir::ClassUnicodeRange::end::hbd23d559724b5da5
  24:     0x7ffb7a3af815 - regex_syntax::hir::ClassUnicodeRange::end::hbd23d559724b5da5
  25:     0x7ffb7a3af3c1 - regex_syntax::hir::ClassUnicodeRange::end::hbd23d559724b5da5
  26:     0x7ffb7c36de8c - <rustc_middle::ty::adjustment::CustomCoerceUnsized as core::fmt::Debug>::fmt::hd5caefa151f67633
  27:     0x7ffb7c647466 - rustc_middle::dep_graph::<impl rustc_query_system::dep_graph::DepKind for rustc_middle::dep_graph::dep_node::DepKind>::debug_node::h067a466f347afbfa
  28:     0x7ffb7c8a3c90 - <rustc_middle::ty::layout::SizeSkeleton as core::fmt::Debug>::fmt::hdf39e1a062a831fa
  29:     0x7ffb7c4c6877 - rustc_middle::ty::context::TyCtxt::_intern_place_elems::h4e412a0a09631fd5
  30:     0x7ffb7c72080e - <rustc_middle::ty::layout::SizeSkeleton as core::fmt::Debug>::fmt::hdf39e1a062a831fa
  31:     0x7ffb7c35b5fd - rustc_middle::ty::instance::Instance::resolve_opt_const_arg::hd412f8d69c49b383
  32:     0x7ffb7c35b357 - rustc_middle::ty::instance::Instance::resolve::h792afa8d1a698994
  33:     0x7ffb7b2409c8 - <rustc_mir::monomorphize::collector::MirNeighborCollector as rustc_middle::mir::visit::Visitor>::visit_terminator::h9371f020c44c4369
  34:     0x7ffb7b243639 - <rustc_mir::monomorphize::collector::RootCollector as rustc_hir::itemlikevisit::ItemLikeVisitor>::visit_impl_item::h56d4e421d02eeb1b
  35:     0x7ffb7b23cd52 - rustc_mir::monomorphize::collector::collect_crate_mono_items::hdc49dd9b65a71123
  36:     0x7ffb7b23cfd0 - rustc_mir::monomorphize::collector::collect_crate_mono_items::hdc49dd9b65a71123
  37:     0x7ffb7b23cfd0 - rustc_mir::monomorphize::collector::collect_crate_mono_items::hdc49dd9b65a71123
  38:     0x7ffb7b23cfd0 - rustc_mir::monomorphize::collector::collect_crate_mono_items::hdc49dd9b65a71123
  39:     0x7ffb7b42d283 - <rustc_mir::util::storage::AlwaysLiveLocals as core::fmt::Debug>::fmt::h0c9fc37ba57fd7cd
  40:     0x7ffb7b23bf21 - rustc_mir::monomorphize::collector::collect_crate_mono_items::hdc49dd9b65a71123
  41:     0x7ffb7b2e2d31 - rustc_mir::monomorphize::partitioning::partition::h855dd72ec131e9de
  42:     0x7ffb7851f467 - <rustc_codegen_llvm::back::lto::ThinLTOKeysMap as core::fmt::Debug>::fmt::hbc55bf07d7d5ff94
  43:     0x7ffb7841533e - <rustc_codegen_llvm::llvm_::ffi::PassKind as core::fmt::Debug>::fmt::ha4490398b447c3e3
  44:     0x7ffb784625b7 - <rustc_ast::ast::FloatTy as rustc_codegen_llvm::debuginfo::metadata::MsvcBasicName>::msvc_basic_name::h13038d476c4525fe
  45:     0x7ffb78491351 - rustc_codegen_llvm::type_::<impl rustc_codegen_ssa::traits::type_::LayoutTypeMethods for rustc_codegen_llvm::context::CodegenCx>::reg_backend_type::h90e24b99f24a4f79
  46:     0x7ffb7838e914 - rustc_interface::util::commit_date_str::hd5efa7d3825e0a94
  47:     0x7ffb785382c4 - <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate::h822bcfb8449dad95
  48:     0x7ffb782e21ae - rustc_interface::interface::parse_cfgspecs::h699038d7e71e784d
  49:     0x7ffb7831542a - rustc_interface::passes::BoxedResolver::to_resolver_outputs::h62b13ab93254cba7
  50:     0x7ffb783600f6 - rustc_interface::queries::Queries::ongoing_codegen::ha4c64625b69244aa
  51:     0x7ffb7812fa7a - <rustc_mir::transform::generator::PinArgVisitor as rustc_middle::mir::visit::MutVisitor>::tcx::h7fe0c34315986731
  52:     0x7ffb780eff0c - <rustc_ast::ast::Variant as rustc_ast::attr::HasAttrs>::attrs::h9b5124b2e6e5fe34
  53:     0x7ffb7813118c - <rustc_mir::transform::generator::PinArgVisitor as rustc_middle::mir::visit::MutVisitor>::tcx::h7fe0c34315986731
  54:     0x7ffb78103b54 - <rustc_ast::ast::Variant as rustc_ast::attr::HasAttrs>::attrs::h9b5124b2e6e5fe34
  55:     0x7ffb7811599f - rustc_ast::util::parser::prec_let_scrutinee_needs_par::h0da38a96661182e5
  56:     0x7ffb7808c63d - <tracing_subscriber::util::TryInitError as core::fmt::Display>::fmt::h9f271cb85bcd455c
  57:     0x7ffb94bb00e3 - std::sys::windows::thread::Thread::new::h0de7ecb752bc4a62
  58:     0x7ffc0a247034 - BaseThreadInitThunk
  59:     0x7ffc0bc1d0d1 - RtlUserThreadStart

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.50.0-nightly (7f9c43cf9 2020-12-23) running on x86_64-pc-windows-msvc

note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
#0 [codegen_fulfill_obligation] checking if `std::ops::FnOnce` fulfills its obligations
#1 [resolve_instance] resolving instance `<[closure@src\main.rs:2:22: 2:34] as std::ops::FnOnce<((),)>>::call_once`
#2 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack
error: aborting due to previous error

error: could not compile `rustc-ice-repro`

To learn more, run the command again with --verbose.

@codeflo codeflo added C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 24, 2020
@codeflo codeflo changed the title ICE on nightly: [codegen_fulfill_obligation] checking if std::ops::FnOnce fulfills its obligations ICE on stable and nightly: [codegen_fulfill_obligation] checking if std::ops::FnOnce fulfills its obligations Dec 24, 2020
@camelid camelid added A-traits Area: Trait system I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Dec 25, 2020
@camelid
Copy link
Member

camelid commented Dec 25, 2020

Thanks for minimizing and checking on both stable and nightly! It's very helpful :)

@steffahn
Copy link
Member

steffahn commented Dec 25, 2020

Looks like this might be a duplicate of #80291.

@camelid
Copy link
Member

camelid commented Dec 25, 2020

Yeah, seems likely.

@codeflo
Copy link
Author

codeflo commented Dec 25, 2020

Interesting. Yeah, that looks surprisingly similar, although my usecase is maybe a bit different. I want to box and store the closure instead of executing it directly. For that reason, I don't think shifting around the lifetime bounds as mentioned in that discussion would work for me.

In case it helps, some additional context why this came up. My actual code is closer to this definition:

struct Source {
    // essentially AnyMap
}

trait Query<'a> {
    type Result: 'a;
    fn execute(source: &'a Source) -> Self::Result;
}

fn enqueue<Q: for<'q> Query<'q>, F: 'static + for<'r> FnOnce(<Q as Query<'r>>::Result)>(f: F) {
    let _box: Box<dyn FnOnce(&Source)> = Box::new(move |source| f(Q::execute(source)));
    // Store _box in queue
}

As you can see, the Query result is supposed to reference into the Source. At least intuitively, it seems like the higher ranked bounds are necessary to make this sound: Since the boxed Fn is only executed much later, neither Q nor F are allowed to care about the concrete lifetime of the Source parameter.

BTW, I didn't write the "Query" trait myself. It's actually this trait from the Legion crate, which is an entity-component system I use.

@apiraino
Copy link
Contributor

Assigning P-medium as discussed as part of the Prioritization Working Group procedure and removing I-prioritize.

@apiraino apiraino added P-medium Medium priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Dec 30, 2020
@apiraino
Copy link
Contributor

At a cursory look it seems to this ICE started after 1.26
https://rust.godbolt.org/z/6sjTY6

@camelid
Copy link
Member

camelid commented Dec 30, 2020

@apiraino If I use bare dyn Trait syntax (i.e. remove the dyn), I get an ICE as far back as 1.9. Not sure if it's the same ICE though:

thread 'rustc' panicked at 'Box<Any>', ../src/libsyntax/errors/mod.rs:536
note: Run with `RUST_BACKTRACE=1` for a backtrace.

error: internal compiler error: ../src/librustc_trans/common.rs:1102: Encountered error `OutputTypeParameterMismatch(Binder(<[closure@<source>:2:22: 2:34] as std::ops::FnOnce<(<() as Query<'_>>::Result,)>>), Binder(<[closure@<source>:2:22: 2:34] as std::ops::FnOnce<((),)>>), Sorts(ExpectedFound { expected: (), found: <() as Query<'_>>::Result }))` selecting `Binder(<[closure@<source>:2:22: 2:34] as std::ops::FnOnce<((),)>>)` during trans
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

fanninpm added a commit to fanninpm/glacier that referenced this issue Feb 11, 2021
@rust-lang-glacier-bot rust-lang-glacier-bot added the glacier ICE tracked in rust-lang/glacier. label Feb 12, 2021
@mouchtaris
Copy link

I seem to have run into the same issue.

Here is a another minification that should reproduce this error.

pub fn main() {
    f::<(), _>(|_| {});
}
fn f<S, P>(p: P)
where
    P: for<'r> FnOnce(<S as Trait<'r>>::Item),
    S: for<'r> Trait<'r>,
{
    p(None.unwrap())
}

pub trait Trait<'a> {
    type Item;
}
impl<'a, S> Trait<'a> for S {
    type Item = ();
}

mouchtaris pushed a commit to Good-Vibez/ct that referenced this issue Mar 28, 2021
mouchtaris pushed a commit to Good-Vibez/ct that referenced this issue Apr 5, 2021
@jorendorff
Copy link
Contributor

jorendorff commented Jun 23, 2021

I hit this in the wild too. Independently reduced to:

trait Viewable<'a> {
    type View;
}

impl<'a> Viewable<'a> for u64 {
    type View = u64;
}

fn main() {
    let _f: for <'a> fn(<u64 as Viewable<'a>>::View) = |_| {};
}

@jorendorff
Copy link
Contributor

Pretty error message:

error: internal compiler error: compiler/rustc_trait_selection/src/traits/codegen.rs:78:17:
Encountered error `OutputTypeParameterMismatch(
    Binder(
        <[closure@ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>,
        [Region(BrAnon(0))]
    ),
    Binder(
        <[closure@ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>,
        []
    ),
    Sorts(ExpectedFound {
        expected: u64,
        found: <u64 as Viewable<'_>>::View
    })
)` selecting `Binder(<[closure@ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>, [])` during codegen

I guess this checking code doesn't understand that <u64 as Viewable<'_>>::View is always u64, regardless of '_.

@jorendorff
Copy link
Contributor

Binder here is rustc_middle::ty::sty::Binder, which represents a type of the form for <PARAMS> TYPE, like for <'a> fn(<u64 as Viewable<'a>>::View) in my testcase.

Apparently, there are two separate times rustc has to look up trait impls:

  • At typeck time, if the code uses some method of a trait T on a value of type U, we have to check that U: T is satisfied. (Inside rustc, this requirement U: T is called an "obligation".) But we don't have to nail it down to a specific impl T for ..., and often can't; if we look at the context and see where U: T, typeck is happy.

  • At codegen time, rustc needs to figure out which method to call. Armed with the actual type parameters for the (monomorphized) code being compiled, we now need a specific impl T for the type U. Since typeck succeeded, we are guaranteed it exists somewhere. It's just a matter of finding it.

So, in this case, I guess, we correctly get through all the way to codegen, but then we fail to unify u64 with <u64 as Viewable<'a>>::View.

@jorendorff
Copy link
Contributor

See "Trait resolution" in the rustc-dev guide.

In SelectionContext::select, candidate assembly (docs, src) succeeds, but confirmation (docs, src) fails.

@jorendorff
Copy link
Contributor

Some debug output, but it's only what anyone who actually knows this code would already expect:

┐rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
├─0ms DEBUG rustc_trait_selection::traits::select::confirmation confirm_closure_candidate, obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0)
├─0ms DEBUG rustc_trait_selection::traits::select::confirmation confirm closure candidate obligations, closure_def_id=DefId(0:11 ~ ice[317d]::main::{closure#0}), trait_ref=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))]), obligations=[]
┘rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
error from SelectionContext::confirm_candidate: OutputTypeParameterMismatch(Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))]), Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>, []), Sorts(ExpectedFound { expected: u64, found: <u64 as Viewable<'_>>::View }))

@jorendorff
Copy link
Contributor

jorendorff commented Jun 23, 2021

This call to Trace::sub is failing (edited for readability):

│ ├─0ms DEBUG rustc_infer::infer::at sub(
    Binder(
        <[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62]
            as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>,
        [Region(BrAnon(0))]
    ) <: Binder(
        <[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62]
            as std::ops::FnMut<(u64,)>>,
        []
    )
)

And we do end up here:

│ │ │ │ │ ├─0ms DEBUG rustc_infer::infer::equate Equate.tys(<u64 as Viewable<'_>>::View, u64)
│ │ │ │ │ ├─0ms DEBUG rustc_infer::infer::equate Equate.tys: replacements (<u64 as Viewable<'_>>::View, u64)
│ │ │ │ │ ├─0ms DEBUG rustc_middle::ty::relate super_relate_tys: a=<u64 as Viewable<'_>>::View b=u64
│ │ │ │ │ ├─0ms DEBUG rustc_infer::infer commit_if_ok() -- r.is_ok() = false

@jorendorff
Copy link
Contributor

The reason typeck succeeds is that it calls normalize_associated_types_in here.

bound_sig is Binder((<u64 as Viewable<'_>>::View)->(), [Region(BrAnon(0))]).

Before that call, liberated_sig is (<u64 as Viewable<'_>>::View)->().

Afterwards, it is (u64)->().

@jorendorff
Copy link
Contributor

jorendorff commented Jun 24, 2021

OK, recap time. The Story So Far:

trait Viewable<'a> {
    type View;
}

impl<'a> Viewable<'a> for u64 {
    type View = u64;
}

fn main() {
    let _f: for<'a> fn(<u64 as Viewable<'a>>::View) = |_| {};
}

Type checking succeeds, but we hit an ICE during codegen, due to failure to select an impl for the obligation [closure type]: FnMut(u64).

This means there is a mismatch between how typeck solves traits and how codegen selects trait impls: typeck was satisfied the impl exists, but codegen can't find it.

More specifically: I think typeck realizes <u64 as Viewable<'a>>::View is u64, regardless of 'a, but codegen doesn't.

@jorendorff
Copy link
Contributor

jorendorff commented Jun 24, 2021

During typeck, the stack is (most recent call last):

  • FnCtxt::check_closure(expected=for<'a> Fn(<u64 as Viewable<'a>>::View)) in rustc_typeck/src/check/closure.rs
  • FnCtxt::sig_of_closure
  • FnCtxt::sig_of_closure_with_expectation -- Note: closure_sigs is called after expected_sig is "bound" to the closure type, which happens in this method.
  • FnCtxt::closure_sigs -- This normalizes the closure type, which by now contains <u64 as Viewable<'a>>::View, and normalization (below) simplifies this to u64.
  • normalize_associated_types_in in rustc_typeck/src/check/inherited.rs
  • partially_normalize_associated_types_in in rustc_trait_selection/src/infer.rs
  • normalize in rustc_trait_selection/src/traits/project.rs
  • normalize_to
  • normalize_with_depth_to
  • ⤷ ...

During codegen, the stack is:

  • confirm_candidate in rustc_trait_selection/src/traits/select/confirmation.rs
  • confirm_closure_candidate
  • normalize_with_depth in rustc_trait_selection/src/traits/project.rs
  • normalize_with_depth_to
  • ⤷ ...

So both phases try to normalize. The difference is:

  • During typeck, we have

    ├┐rustc_typeck::check::closure::closure_sigs ..., bound_sig=Binder(([<u64 as Viewable<'_>>::View]; c_variadic: false)->(), [Region(BrAnon(0))])
    │└┐rustc_trait_selection::traits::project::normalize_with_depth_to depth=0, value=([<u64 as Viewable<'_>>::View]; c_variadic: false)->()
    
  • During codegen, we have

    ├┐rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
    │└┐rustc_trait_selection::traits::project::normalize_with_depth_to depth=1, value=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))])
    

Note the difference in value. During codegen we have a Binder, so we intentionally do not normalize.

@jorendorff
Copy link
Contributor

jorendorff commented Jun 24, 2021

@wesleywiser pointed out that the snippet of log under "During codegen" above doesn't seem to correspond to the "During typeck" snippet. Here's the broader context during codegen:

$ RUSTC_LOG=rustc_typeck::check::closure=debug,rustc_trait_selection::traits::project=debug,rustc_trait_selection::traits::select::confirmation=debug rustc +stage1 ~/misc/rust/ice.rs
...
┐rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
├─0ms DEBUG rustc_trait_selection::traits::select::confirmation confirm_closure_candidate, obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0)
├─0ms DEBUG rustc_trait_selection::traits::select::confirmation confirm_closure_candidate before normalization, trait_ref=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))])
├┐rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
│└┐rustc_trait_selection::traits::project::normalize_with_depth_to depth=1, value=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))])
│ ├─0ms DEBUG rustc_trait_selection::traits::project result=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))]), obligations.len=0
│ ├─0ms DEBUG rustc_trait_selection::traits::project normalizer.obligations=[]
│┌┘rustc_trait_selection::traits::project::normalize_with_depth_to depth=1, value=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))])
├┘rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
├─0ms DEBUG rustc_trait_selection::traits::select::confirmation confirm closure candidate obligations, closure_def_id=DefId(0:11 ~ ice[317d]::main::{closure#0}), trait_ref=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))]), obligations=[]
├┐rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
│└┐rustc_trait_selection::traits::select::confirmation::confirm_poly_trait_refs obligation_cause=ObligationCauseData { span: no-location (#0), body_id: HirId { owner: DefId(0:0 ~ ice[317d]), local_id: 0 }, code: MiscObligation }, obligation_param_env=ParamEnv { caller_bounds: [], reveal: All }, obligation_trait_ref=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>, []), expected_trait_ref=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))])
│┌┘rustc_trait_selection::traits::select::confirmation::confirm_poly_trait_refs obligation_cause=ObligationCauseData { span: no-location (#0), body_id: HirId { owner: DefId(0:0 ~ ice[317d]), local_id: 0 }, code: MiscObligation }, obligation_param_env=ParamEnv { caller_bounds: [], reveal: All }, obligation_trait_ref=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>, []), expected_trait_ref=Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))])
├┘rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
┘rustc_trait_selection::traits::select::confirmation::confirm_candidate obligation=Obligation(predicate=Binder(TraitPredicate(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>), []), depth=0), candidate=ClosureCandidate
error: internal compiler error: compiler/rustc_trait_selection/src/traits/codegen.rs:78:17: Encountered error `OutputTypeParameterMismatch(Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(<u64 as Viewable<'_>>::View,)>>, [Region(BrAnon(0))]), Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>, []), Sorts(ExpectedFound { expected: u64, found: <u64 as Viewable<'_>>::View }))` selecting `Binder(<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>, [])` during codegen
thread 'rustc' panicked at 'Box<dyn Any>', compiler/rustc_errors/src/lib.rs:1007:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.55.0-dev running on x86_64-apple-darwin

query stack during panic:
#0 [codegen_fulfill_obligation] checking if `std::ops::FnMut` fulfills its obligations
#1 [resolve_instance] resolving instance `<[closure@/Users/jorendorff/misc/rust/ice.rs:10:56: 10:62] as std::ops::FnMut<(u64,)>>::call_mut`
end of query stack
error: aborting due to previous error

@jorendorff
Copy link
Contributor

#85499 will probably fix this.

@jackh726
Copy link
Member

@jorendorff excellent analysis here! You hit the nail on the head on the problem here. Indeed #85499 will fix this.

I'm going to close this issue as a duplicate of #62529. There are lots of examples and MCVEs of this.

@lqd
Copy link
Member

lqd commented Jun 28, 2021

Should we add all these minimal examples as tests on the PR then ?


The repro code above currently ICEs with #85499:

error: internal compiler error: broken MIR in DefId(0:11 ~ ice[317d]::main::{closure#0}) (bb0[0]): equate_normalized_input_or_output: `&[closure@ice.rs:10:55: 10:61]==&[closure@ice.rs:10:55: 10:61]` failed with `NoSolution`

@jackh726 jackh726 reopened this Jun 28, 2021
@jackh726
Copy link
Member

Thanks @lqd. There's over a dozen issues that are basically duplicates of #62529; I added several of the MCVEs in the PR itself, but ultimately they're generally testing the same thing.

Seems like this has an extra twist to it that will need further debugging (something I haven't seen for the other MCVEs).

I'm going to go ahead and assign this to myself to follow up on after #85499 lands.

@jackh726 jackh726 self-assigned this Jun 28, 2021
@jackh726
Copy link
Member

jackh726 commented Jun 28, 2021

@jorendorff if you still want to help out here, feel more than free to checkout #85499 and run the repro. I imagine we're probably just missing a normalize call somewhere.

If you have questions, I can answer questions or chat on zulip or here.

(If you aren't interested anymore or don't have time, no worries!)

@jackh726
Copy link
Member

Fixed by #85499, closing given that the PR adds a test with the same behavior

@steffahn
Copy link
Member

@jackh726 since #80291 was a potential duplicate, is that one fixed as-well?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-traits Area: Trait system C-bug Category: This is a bug. glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-medium Medium priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

9 participants