rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.85k stars 12.66k forks source link

ICE: Type parameter W/#1 out of range when substituting #55872

Closed DutchGhost closed 5 years ago

DutchGhost commented 5 years ago

Playing with async/await, using

and some nightly features, I stumbled upon this ICE. (possibly related to https://github.com/rust-lang/rust/issues/55265)

#![feature(await_macro, async_await, futures_api, pin, existential_type)]

macro_rules! async_for {
    ($item:ident in $stream:ident $todo:block) => (
        while let Some($item) = await!($stream.next()) $todo
    )
}

use futures::{Stream, Future};
use std::marker::Unpin;

use futures::StreamExt as StreamExt;

use tokio::prelude::{AsyncWriteExt};

pub trait Sip
where
    Self: Stream
{
    type Future: Future;

    fn start_sip<W, F>(self, writer: W, convert: F) -> Self::Future
    where
        W: AsyncWriteExt + Unpin,
        F: Fn(&Self::Item) -> &[u8] + Unpin
    ;
}

impl <S> Sip for S
where
    S: Stream + Unpin,
{
    existential type Future: Future<Output = ()>;

    fn start_sip<W, F>(mut self, mut writer: W, mut convert: F) -> Self::Future
    where
        W: AsyncWriteExt + Unpin,
        F: Fn(&Self::Item) -> &[u8] + Unpin
    {
        async move {
            async_for!(item in self {
                let bytes = convert(&item);
                await!(writer.write_async(bytes));
            });

            await!(tokio::io::shutdown(writer).into_awaitable());
        }
    }
}
Backtrace: ``` error: internal compiler error: librustc\ty\subst.rs:462: Type parameter `W/#1` (W/1) out of range when substituting (root type=Some(impl futures::Future)) substs=[S] thread 'main' panicked at 'Box', librustc_errors\lib.rs:538:9 stack backtrace: 0: ::drop 1: std::panicking::take_hook 2: std::panicking::take_hook 3: > as rustc::ty::ToPredicate<'tcx>>::to_predicate 4: std::panicking::rust_panic_with_hook 5: ::hash 6: as rustc::ty::context::Lift<'tcx>>::lift_to_tcx 7: rustc::ty::context::tls::track_diagnostic 8: rustc::ty::context::tls::track_diagnostic 9: rustc::ty::context::tls::track_diagnostic 10: rustc::ty::context::tls::track_diagnostic 11: rustc::util::bug::bug_fmt 12: rustc::util::bug::bug_fmt 13: as rustc::ty::fold::TypeFolder<'gcx, 'tcx>>::fold_ty 14: rustc::ty::context::TyCtxt::generate_borrow_of_any_match_input 15: rustc::ty::error::>::sort_string 16: as rustc::ty::fold::TypeFolder<'gcx, 'tcx>>::fold_ty 17: rustc::ty::context::TyCtxt::generate_borrow_of_any_match_input 18: rustc::ty::error::>::sort_string 19: as rustc::ty::fold::TypeFolder<'gcx, 'tcx>>::fold_ty 20: as rustc::middle::expr_use_visitor::Delegate<'tcx>>::decl_without_init 21: rustc_mir::borrow_check::nll::facts:: for rustc_mir::dataflow::move_paths::indexes::BorrowIndex>::from 22: as rustc::mir::visit::Visitor<'tcx>>::visit_mir 23: as rustc::mir::visit::Visitor<'tcx>>::visit_local 24: as rustc::mir::visit::MutVisitor<'tcx>>::visit_statement 25: ::fmt 26: as rustc::middle::expr_use_visitor::Delegate<'tcx>>::decl_without_init 27: as rustc::mir::visit::MutVisitor<'tcx>>::visit_statement 28: rustc::ty::query::on_disk_cache::__ty_decoder_impl::>::read_str 29: rustc::ty::context::tls::track_diagnostic 30: rustc::ty::context::tls::track_diagnostic 31: rustc::dep_graph::graph::DepGraph::assert_ignored 32: rustc::ty::context::tls::track_diagnostic 33: rustc::ty::query::plumbing::>::try_print_query_stack 34: rustc::ty::query::plumbing::>::try_print_query_stack 35: rustc::ty::query::>::mir_borrowck 36: rustc_driver::set_sigpipe_handler 37: rustc_driver::set_sigpipe_handler 38: as rustc_driver::pretty::HirPrinterSupport<'hir>>::sess 39: rustc_driver::set_sigpipe_handler 40: rustc_driver::driver::compile_input 41: rustc_driver::run_compiler 42: ::fmt 43: rustc_driver::run_compiler 44: ::cause 45: _rust_maybe_catch_panic 46: ::fmt 47: rustc_driver::main 48: 49: std::panicking::update_panic_count 50: _rust_maybe_catch_panic 51: std::rt::lang_start_internal 52: 53: 54: BaseThreadInitThunk 55: RtlUserThreadStart query stack during panic: #0 [mir_borrowck] processing `::start_sip` 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.31.0-nightly (de9666f12 2018-10-31) 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 `webscraper_better`. ```

No ICE happens when writing the trait and implementation like this (notice the Generic parameters are now on the trait definition rather than on the function):

use futures::{Stream, Future};
use std::marker::Unpin;

use futures::StreamExt as StreamExt;

use tokio::prelude::{AsyncWriteExt};

pub trait Sip<W, F>
where
    Self: Stream
{
    type Future: Future;

    fn start_sip(self, writer: W, convert: F) -> Self::Future
    where
        W: AsyncWriteExt + Unpin,
        F: FnMut(&Self::Item) -> &[u8] + Unpin
    ;
}

impl <W, F, S> Sip<W, F> for S
where
    S: Stream + Unpin,
{
    existential type Future: Future<Output = ()>;

    fn start_sip(mut self, mut writer: W, mut convert: F) -> Self::Future
    where
        W: AsyncWriteExt + Unpin,
        F: FnMut(&Self::Item) -> &[u8] + Unpin
    {
        async move {
            async_for!(item in self {
                let bytes = convert(&item);
                await!(writer.write_async(bytes));
            });

            await!(tokio::io::shutdown(writer).into_awaitable());
        }
    }
}
gilescope commented 5 years ago

Confirmed this is still reproducible as of latest nightly (rustc 1.36.0-nightly (00859e3e6 2019-04-29))

gilescope commented 5 years ago

This is about as small as I can get it to repro:

#![feature(async_await, existential_type)]
pub trait Bar
{
    type E: Copy;

    fn foo<T>() -> Self::E;
}

impl <S> Bar for S
{
    existential type E: Copy;

    fn foo<T>() -> Self::E
    {
        async {}
    }
}

fn main() {}
nikomatsakis commented 5 years ago

Marking as blocking -- thanks for the minimal reproduction @gilescope, that's fantastic!

davidtwco commented 5 years ago

@rustbot claim

Going to investigate this with @nikomatsakis, see this message.

nikomatsakis commented 5 years ago
nikomatsakis commented 5 years ago

Not really related to async-await. This minimization does not involve async/await but gets a very similar ICE:

#![feature(existential_type)]
pub trait Bar
{
    type E: Copy;

    fn foo<T>() -> Self::E;
}

impl <S> Bar for S
{
    existential type E: Copy;

    fn foo<T>() -> Self::E
    {
        || ()
    }
}

fn main() {}
nikomatsakis commented 5 years ago

Preferred minimization (no annoying closures):

#![feature(existential_type)]
pub trait Bar
{
    type E: Copy;

    fn foo<T>() -> Self::E;
}

impl <S: Default> Bar for S
{
    existential type E: Copy;

    fn foo<T: Default>() -> Self::E
    {
        (S::default(), T::default())
    }
}

fn main() {}

The problem here is that the inferred type for E needs to be (S, T), but T is not in scope there. So we expect an error. (Not an ICE)

nikomatsakis commented 5 years ago

The Zulip thread diagnoses the problem and explains everything in a lot of detail.