Rust: Rustc 1.33 stable panicked on a closure inside a closure

Created on 1 Mar 2019  ·  29Comments  ·  Source: rust-lang/rust

Rustc 1.33 panicked while compiling a code that was working well on 1.32.

I tried this code:

extern crate chrono;
extern crate dotenv;
extern crate futures;
extern crate hyper;
#[macro_use]
extern crate juniper;
extern crate juniper_hyper;
#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate uuid;

mod context;
mod schema;

use context::Context;
use dotenv::dotenv;
use futures::future;
use hyper::rt::Future;
use hyper::service::service_fn;
use hyper::{Body, Method, Response, Server, StatusCode};
use schema::{Mutation, Query, Schema};
use std::sync::Arc;

fn main() {
    // Load configuration
    dotenv().ok();

    // Prepare logger
    pretty_env_logger::init();

    info!("Starting Cardioid API");

    // Prepare HOST configuration
    let host = std::env::var("HOST").expect("Missing HOST definition in env variables");
    let address = host.parse().expect("Invalid HOST configuration");

    // Prepare context and schema
    let context = Arc::new(Context {});
    let root_node = Arc::new(Schema::new(Query {}, Mutation {}));

    // Define network service
    let new_service = move || {
        let root_node = root_node.clone();
        let ctx = context.clone();
        service_fn(move |req| -> Box<Future<Item = _, Error = _> + Send> {
            let root_node = root_node.clone();
            let ctx = ctx.clone();
            match (req.method(), req.uri().path()) {
                // GraphiQL
                (&Method::GET, "/") => Box::new(juniper_hyper::graphiql("/graphql")),

                // GraphQL
                (&Method::GET, "/graphql") => Box::new(juniper_hyper::graphql(root_node, ctx, req)),
                (&Method::POST, "/graphql") => {
                    Box::new(juniper_hyper::graphql(root_node, ctx, req))
                }

                // Default response
                _ => {
                    let mut response = Response::new(Body::empty());
                    *response.status_mut() = StatusCode::NOT_FOUND;
                    Box::new(future::ok(response))
                }
            }
        })
    };

    // Create server with service
    let server = Server::bind(&address)
        .serve(new_service)
        .map_err(|e| error!("Server error: {}", e));

    info!("Listening on http://{}", address);

    // Run server
    hyper::rt::run(server);
}

This happened: error: internal compiler error: src/librustc_mir/borrow_check/nll/universal_regions.rs:744: cannot convert `ReScope(Node(238))` to a region vid

Meta

rustc --version --verbose:

rustc 1.33.0 (2aa4c46cf 2019-02-28)
binary: rustc
commit-hash: 2aa4c46cfdd726e97360c2734835aa3515e8c858
commit-date: 2019-02-28
host: x86_64-apple-darwin
release: 1.33.0
LLVM version: 8.0

Backtrace:

error: internal compiler error: src/librustc_mir/borrow_check/nll/universal_regions.rs:744: cannot convert `ReScope(Node(238))` to a region vid

thread 'rustc' panicked at 'Box<Any>', src/librustc_errors/lib.rs:588:9
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
   1: std::sys_common::backtrace::_print
   2: std::panicking::default_hook::{{closure}}
   3: std::panicking::default_hook
   4: rustc::util::common::panic_hook
   5: std::panicking::rust_panic_with_hook
   6: std::panicking::begin_panic
   7: rustc_errors::Handler::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::bug_fmt
  14: rustc_mir::borrow_check::nll::universal_regions::UniversalRegionIndices::to_region_vid::{{closure}}
  15: rustc_mir::borrow_check::nll::universal_regions::UniversalRegionIndices::to_region_vid
  16: rustc_mir::borrow_check::nll::type_check::constraint_conversion::ConstraintConversion::convert_all
  17: rustc_mir::borrow_check::nll::type_check::TypeChecker::prove_predicate
  18: rustc_mir::borrow_check::nll::type_check::TypeChecker::check_stmt
  19: rustc_mir::borrow_check::nll::type_check::TypeChecker::typeck_mir
  20: rustc_mir::borrow_check::nll::type_check::type_check
  21: rustc_mir::borrow_check::nll::compute_regions
  22: rustc_mir::borrow_check::do_mir_borrowck
  23: rustc::ty::context::GlobalCtxt::enter_local
  24: rustc_mir::borrow_check::mir_borrowck
  25: rustc::ty::query::__query_compute::mir_borrowck
  26: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::mir_borrowck<'tcx>>::compute
  27: rustc::dep_graph::graph::DepGraph::with_task_impl
  28: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
  29: rustc_mir::borrow_check::nll::type_check::TypeChecker::check_stmt
  30: rustc_mir::borrow_check::nll::type_check::TypeChecker::typeck_mir
  31: rustc_mir::borrow_check::nll::type_check::type_check
  32: rustc_mir::borrow_check::nll::compute_regions
  33: rustc_mir::borrow_check::do_mir_borrowck
  34: rustc::ty::context::GlobalCtxt::enter_local
  35: rustc_mir::borrow_check::mir_borrowck
  36: rustc::ty::query::__query_compute::mir_borrowck
  37: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::mir_borrowck<'tcx>>::compute
  38: rustc::dep_graph::graph::DepGraph::with_task_impl
  39: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
  40: rustc_mir::borrow_check::nll::type_check::TypeChecker::check_stmt
  41: rustc_mir::borrow_check::nll::type_check::TypeChecker::typeck_mir
  42: rustc_mir::borrow_check::nll::type_check::type_check
  43: rustc_mir::borrow_check::nll::compute_regions
  44: rustc_mir::borrow_check::do_mir_borrowck
  45: rustc::ty::context::GlobalCtxt::enter_local
  46: rustc_mir::borrow_check::mir_borrowck
  47: rustc::ty::query::__query_compute::mir_borrowck
  48: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors<'tcx> for rustc::ty::query::queries::mir_borrowck<'tcx>>::compute
  49: rustc::dep_graph::graph::DepGraph::with_task_impl
  50: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::try_get_with
  51: rustc::ty::<impl rustc::ty::context::TyCtxt<'a, 'gcx, 'tcx>>::par_body_owners
  52: rustc::util::common::time
  53: <std::thread::local::LocalKey<T>>::with
  54: rustc::ty::context::TyCtxt::create_and_enter
  55: rustc_driver::driver::compile_input
  56: rustc_driver::run_compiler_with_pool
  57: <scoped_tls::ScopedKey<T>>::set
  58: rustc_driver::run_compiler
  59: <scoped_tls::ScopedKey<T>>::set
query stack during panic:
#0 [mir_borrowck] processing `main::{{closure}}::{{closure}}`
#1 [mir_borrowck] processing `main::{{closure}}`
#2 [mir_borrowck] processing `main`
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.33.0 (2aa4c46cf 2019-02-28) running on x86_64-apple-darwin

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 `api`.
C-bug I-ICE P-high T-compiler regression-from-stable-to-stable

Most helpful comment

I created a simple (but not minimal) project based on the initial comment, and checked it indeed ICEs on nightly with the expected "cannot convert ReScope(Node(...)) to a region vid" error.

I haven't tried minimizing or bisecting, however (but since very similar errors had been fixed by #60449, I thought this issue here would have been fixed at the same time — so maybe it won't be bisected to the Universes PR after all).


edit: I also ran a quick bisect on it, and it started ICEing (with a different error location) in nightly-2019-01-04 which is IIRC the one where Universes landed).

A minimization would be very helpful indeed.

All 29 comments

After some testing, this is the lines Box::new(juniper_hyper::graphql(root_node, ctx, req)) that cause the compiler to crash.

@julien1619 can you post a reduced test case or the full source including Cargo.toml and the module files?

Simple project that causes this:
https://github.com/zenlist/clincl

Bisected, the cause of the regression is https://github.com/rust-lang/rust/pull/55517. cc @nikomatsakis @scalexm

@jethrogb : @jatsrt just did a test case (thanks!).

triage: P-high.

assigning to self based on stack trace and related work on region-vid conversion issues, and removing nomination tag.

Is this likely to be in a 1.33.1 release?

If we do a release and the fix is not risky to land in a point release probably yes, but there aren't other point release worthy issues to fix so I'm not sure if we'll end up doing one.

This is currently blocking us from updating to 1.33.

Judging from our code and the code above, it might be related to Arc.

Simple project that causes this:
https://github.com/zenlist/clincl

This project has been deleted. Can someone either repost it, or share a copy with me?

Simple project that causes this:
https://github.com/zenlist/clincl

This project has been deleted. Can someone either repost it, or share a copy with me?

The comment below is now posted separately as #59494.


Not sure if it triggers the same bug, but I found this issue (in details below) while searching for a solution.

This code panics on 1.33 - 1.35, but does not panic on 1.32:

fn t7p<A,B,C>( f:impl Fn(B) -> C, g:impl Fn(A) -> B ) -> impl Fn(A) -> C
{
  move |a:A| -> C { f(g(a)) }
}

fn t8n<A,B,C>( f:impl Fn(A) -> B, g:impl Fn(A) -> C ) -> impl Fn(A) -> (B,C)
  where
    A: Copy
{
  move |a:A| -> (B,C) {
    let b = a;
    let fa = f(a);
    let ga = g(b);
    (fa, ga)
  }
}

fn main() {

  let f = |(_,_)| {  };
  let g = |(a,_)| { a };
  let t7 = |env| { |a| { |b| {  t7p(f, g)(((env,a),b))  }}};
  let t8 = t8n(t7, t7p(f, g));
}

On 1.32:

error[E0277]: expected a `std::ops::Fn<(_,)>` closure, found `impl std::ops::Fn<(((_, _), _),)>`
  --> src/main.rs:32:12
   |
32 |   let t8 = pair_panic(t7, o_panic(f, g));
   |            ^^^^^^^^^^ expected an `Fn<(_,)>` closure, found `impl std::ops::Fn<(((_, _), _),)>`
   |
   = help: the trait `std::ops::Fn<(_,)>` is not implemented for `impl std::ops::Fn<(((_, _), _),)>`
note: required by `pair_panic`
  --> src/main.rs:9:1
   |
9  | / fn pair_panic<A,B,C>( f:impl Fn(A) -> B, g:impl Fn(A) -> C ) -> impl Fn(A) -> (B,C)
10 | |   where
11 | |     A: Copy
12 | | {
...  |
18 | |   }
19 | | }
   | |_^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: Could not compile `panic`.

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

On 1.35 nightly (today):

thread 'rustc' panicked at 'assertion failed: result', src/librustc/traits/select.rs:2779:13
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
   1: std::sys_common::backtrace::_print
   2: std::panicking::default_hook::{{closure}}
   3: std::panicking::default_hook
   4: rustc::util::common::panic_hook
   5: std::panicking::rust_panic_with_hook
   6: std::panicking::begin_panic
   7: rustc::infer::InferCtxt::in_snapshot
   8: rustc::traits::select::SelectionContext::confirm_candidate
   9: rustc::traits::select::SelectionContext::select
  10: rustc_data_structures::obligation_forest::ObligationForest<O>::process_obligations
  11: <rustc::traits::fulfill::FulfillmentContext as rustc::traits::engine::TraitEngine>::select_where_possible
  12: rustc_typeck::check::FnCtxt::select_obligations_where_possible
  13: rustc_typeck::check::FnCtxt::check_argument_types
  14: rustc_typeck::check::callee::<impl rustc_typeck::check::FnCtxt>::confirm_builtin_call
  15: rustc_typeck::check::callee::<impl rustc_typeck::check::FnCtxt>::check_call
  16: rustc_typeck::check::FnCtxt::check_expr_kind
  17: rustc_typeck::check::FnCtxt::check_expr_with_expectation_and_needs
  18: rustc_typeck::check::FnCtxt::check_decl_initializer
  19: rustc_typeck::check::FnCtxt::check_decl_local
  20: rustc_typeck::check::FnCtxt::check_stmt
  21: rustc_typeck::check::FnCtxt::check_block_with_expected
  22: rustc_typeck::check::FnCtxt::check_expr_kind
  23: rustc_typeck::check::FnCtxt::check_expr_with_expectation_and_needs
  24: rustc_typeck::check::FnCtxt::check_return_expr
  25: rustc_typeck::check::check_fn
  26: rustc::ty::context::GlobalCtxt::enter_local
  27: rustc_typeck::check::typeck_tables_of
  28: rustc::ty::query::__query_compute::typeck_tables_of
  29: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::typeck_tables_of>::compute
  30: rustc::dep_graph::graph::DepGraph::with_task_impl
  31: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  32: rustc::ty::<impl rustc::ty::context::TyCtxt>::par_body_owners
  33: rustc_typeck::check::typeck_item_bodies
  34: rustc::ty::query::__query_compute::typeck_item_bodies
  35: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::typeck_item_bodies>::compute
  36: rustc::dep_graph::graph::DepGraph::with_task_impl
  37: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  38: rustc::util::common::time
  39: rustc_typeck::check_crate
  40: rustc_interface::passes::analysis
  41: rustc::ty::query::__query_compute::analysis
  42: rustc::ty::query::<impl rustc::ty::query::config::QueryAccessors for rustc::ty::query::queries::analysis>::compute
  43: rustc::dep_graph::graph::DepGraph::with_task_impl
  44: rustc::ty::query::plumbing::<impl rustc::ty::context::TyCtxt>::get_query
  45: rustc::ty::context::tls::enter_global
  46: rustc_interface::passes::BoxedGlobalCtxt::access::{{closure}}
  47: rustc_interface::passes::create_global_ctxt::{{closure}}
  48: rustc_interface::passes::BoxedGlobalCtxt::enter
  49: rustc_interface::interface::run_compiler_in_existing_thread_pool
  50: std::thread::local::LocalKey<T>::with
  51: scoped_tls::ScopedKey<T>::set
  52: syntax::with_globals
query stack during panic:
#0 [typeck_tables_of] processing `main`
#1 [typeck_item_bodies] type-checking all item bodies
#2 [analysis] running analysis passes on this crate
end of query stack

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.35.0-nightly (fbd34efb3 2019-03-26) running on x86_64-apple-darwin
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 `rust`.
To learn more, run the command again with --verbose.

--Bryan

@bryturner based on the stack trace, I do not think that is the exact same bug. Thanks for investigating; Lets make sure to file a separate issue for it!

@bryturner also, your code seems to be missing the definition for t7p? (I recommend posting reproduction in the playpen play.rust-lang.org and seeing if they reproduce there, for ease of sharing and also catching little cut-and-paste omissions along the way.)

Simple project that causes this:
https://github.com/zenlist/clincl

This project has been deleted. Can someone either repost it, or share a copy with me?

I probably should have pinged @jatsrt when I wrote that question. Let's seeing if pinging here helps.

Since the sample project that causes this was taken down, I guessed I will take an example from either #59606 or #59344 and use that as the basis for investigation going forward. #59344 in particular seems to have the best bet of having enough information (namely a Cargo.toml dependencies section) to allow easy reproduction.

@pnkfelix I've just checked on Rust 1.34.1 and I confirm the bug is still present. @darnuria and @GuillaumeGomez told me yesterday at the Paris meetup to bump this issue. I'll try to create a minimal testcase later today.

cc @rust-lang/compiler

Compiler triage: It seems like are still missing a case for reproduction?

@pietroalbini do you still have a local checkout of @jatsrt's repro?

@julien1619 by the way, were you able to create the minimal testcase you mentioned ?

@jethrogb nope :(

I created a simple (but not minimal) project based on the initial comment, and checked it indeed ICEs on nightly with the expected "cannot convert ReScope(Node(...)) to a region vid" error.

I haven't tried minimizing or bisecting, however (but since very similar errors had been fixed by #60449, I thought this issue here would have been fixed at the same time — so maybe it won't be bisected to the Universes PR after all).


edit: I also ran a quick bisect on it, and it started ICEing (with a different error location) in nightly-2019-01-04 which is IIRC the one where Universes landed).

A minimization would be very helpful indeed.

@lqd if I change main to no longer ICE (or if I inline mod deps), I get this error. Do you think you can have a repro that doesn't error when the ICE is gone?

error[E0507]: cannot move out of captured variable in an `FnMut` closure
  --> src/deps.rs:51:29
   |
42 |           root_node: Arc<RootNode<'a, QueryT, MutationT, S>>,
   |           --------- captured outer variable
...
51 |               future::poll_fn(move || {
   |  _____________________________^
52 | |                 let _res = request.execute(&root_node);
53 | |                 Ok(Async::Ready(()))
54 | |             })
   | |_____________^ cannot move out of captured variable in an `FnMut` closure

error: aborting due to previous error

a repro that doesn't error when the ICE is gone

Got it:

diff --git a/src/deps.rs b/src/deps.rs
index d5ad25a..a10b259 100644
--- a/src/deps.rs
+++ b/src/deps.rs
@@ -48,6 +48,7 @@ where
     {
         let requests: Vec<JuniperGraphQLRequest<S>> = vec![];
         future::join_all(requests.into_iter().map(move |request| {
+            let root_node = root_node.clone();
             future::poll_fn(move || {
                 let _res = request.execute(&root_node);
                 Ok(Async::Ready(()))

Reduced:

trait Future {
    type Item;
}

struct PollFn<F> {
    _i: F,
}
fn poll_fn<T, F>(_: F) -> PollFn<F>
where
    F: FnMut() -> T,
{
    unimplemented!()
}
impl<T, F> Future for PollFn<F>
where
    F: FnMut() -> T,
{
    type Item = T;
}

struct JoinAll<I>
where
    I: IntoIterator,
    I::Item: Future,
{
    _f: I::Item,
}
fn join_all<I>(_: I) -> JoinAll<I>
where
    I: IntoIterator,
    I::Item: Future,
{
    unimplemented!()
}
impl<I> Future for JoinAll<I>
where
    I: IntoIterator,
    I::Item: Future,
{
    type Item = I;
}

fn f<'a, T: 'a>(r: &'a T) -> impl Future + 'a {
    let requests = Vec::<()>::new();
    join_all(requests.into_iter().map(move |_| {
        poll_fn(move || {
            r;
        })
    }))
}

fn main() {
    || -> Box<Send> { Box::new(f(&())) };
}

Since this involves IntoIterator, it makes me think of another recent ICE involving universes, but I can't find the exact issue right now.

Maybe #58375?

I manually checked the latest nightly on the bigger repro project, and we have the expected error[E0507]: cannot move out of captured variable in anFnMutclosure error instead of the ICE 👍 . The minimized code above (thanks again @jethrogb) doesn't ICE either.

Was this page helpful?
0 / 5 - 0 ratings