Skip to content

ICE: unexpected initial operand type. #114858

New issue

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

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

Already on GitHub? # to your account

Open
fakeshadow opened this issue Aug 15, 2023 · 13 comments
Open

ICE: unexpected initial operand type. #114858

fakeshadow opened this issue Aug 15, 2023 · 13 comments
Labels
C-bug Category: This is a bug. F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@fakeshadow
Copy link

fakeshadow commented Aug 15, 2023

I tried this code:

#![feature(impl_trait_in_assoc_type)]

use std::{future::Future, convert::Infallible};

trait AsyncFn<Arg> {
    type Output;
    type Future<'f>: Future<Output = Self::Output>
    where
        Arg: 'f,
        Self: 'f;

    fn call<'s>(&'s self, arg: Arg) -> Self::Future<'s>
    where
        Arg: 's;
}

trait AsyncFn2<Arg> {
    type Output;
    type Future: Future<Output = Self::Output>;

    fn call(&self, arg: Arg) -> Self::Future;
}

impl<F, A, B, Fut> AsyncFn2<(A, B)> for F
where
    F: Fn(A, B) -> Fut,
    Fut: Future,
{
    type Output = Fut::Output;
    type Future = Fut;

    fn call(&self, (a, b): (A, B)) -> Self::Future {
        self(a, b)
    }
}

struct Func<F>(F);

impl<Arg, F, Fut> AsyncFn<Arg> for Func<F>
where
    F: Fn(Arg) -> Fut,
    Fut: Future,
{
    type Output = Fut::Output;
    type Future<'f> = impl Future<Output = Self::Output> + 'f where Arg: 'f, Self: 'f;

    fn call<'s>(&'s self, arg: Arg) -> Self::Future<'s>
    where
        Arg: 's,
    {
        async move { (self.0)(arg).await }
    }
}

struct EnclosedFn<T1, T2> {
    this: T1,
    other: T2,
}

impl<Arg, T1, T2, O> AsyncFn<Arg> for EnclosedFn<T1, T2>
where
    T1: AsyncFn<Arg>,
    T2: for<'s> AsyncFn2<(&'s T1, Arg), Output = O>,
{
    type Output = O;
    type Future<'f> = impl Future<Output = Self::Output> + 'f where Arg: 'f, Self: 'f;

    fn call<'s>(&'s self, arg: Arg) -> Self::Future<'s>
    where
        Arg: 's,
    {
        self.other.call((&self.this, arg))
    }
}

trait Enclosed<Arg>: AsyncFn<Arg> {
    fn enclosed<T>(self, other: T) -> EnclosedFn<Self, T>
    where
        T: for<'s> AsyncFn2<(&'s Self, Arg)>,
        Self: Sized,
    {
        EnclosedFn { this: self, other }
    }
}

impl<Arg, F> Enclosed<Arg> for F where F: AsyncFn<Arg> {}

fn main() {
    async fn middelware<S, Arg>(s: &S, arg: Arg) -> S::Output
    where
        S: AsyncFn<Arg>,
    {
        s.call(arg).await
    }

    let f = Func(|arg: String| async move { Ok::<_, Infallible>(arg) })
        .enclosed(middelware)
        .enclosed(middelware);

    futures::executor::block_on(f.call(String::new())).unwrap();
}

I expected to see this happen: code compile.

Instead, this happened: internal compiler error: unexpected initial operand type

Meta

rustc --version --verbose:

rustc 1.73.0-nightly (1b198b3a1 2023-08-13)
binary: rustc
commit-hash: 1b198b3a196442e14fb06978166ab46a4618d131
commit-date: 2023-08-13
host: x86_64-unknown-linux-gnu
release: 1.73.0-nightly
LLVM version: 17.0.0
Backtrace

thread 'rustc' panicked at /rustc/1b198b3a196442e14fb06978166ab46a4618d131/compiler/rustc_codegen_ssa/src/mir/locals.rs:46:21:
assertion failed: `(left == right)`
  left: `*mut [async fn body@src/main.rs:333:5: 335:6]`,
 right: `*mut [async fn body@src/main.rs:333:5: 335:6]`: unexpected initial operand type
stack backtrace:
   0: rust_begin_unwind
             at /rustc/1b198b3a196442e14fb06978166ab46a4618d131/library/std/src/panicking.rs:617:5
   1: core::panicking::panic_fmt
             at /rustc/1b198b3a196442e14fb06978166ab46a4618d131/library/core/src/panicking.rs:67:14
   2: core::panicking::assert_failed_inner
   3: core::panicking::assert_failed::<rustc_middle::ty::Ty, rustc_middle::ty::Ty>
   4: rustc_codegen_ssa::mir::codegen_mir::<rustc_codegen_llvm::builder::Builder>
   5: rustc_codegen_llvm::base::compile_codegen_unit::module_codegen
   6: <rustc_middle::dep_graph::dep_node::DepKind as rustc_query_system::dep_graph::DepKind>::with_deps::<<rustc_query_system::dep_graph::graph::DepGraphData<rustc_middle::dep_graph::dep_node::DepKind>>::with_task<rustc_middle::ty::context::TyCtxt, rustc_span::symbol::Symbol, rustc_codegen_ssa::ModuleCodegen<rustc_codegen_llvm::ModuleLlvm>>::{closure#0}::{closure#0}, rustc_codegen_ssa::ModuleCodegen<rustc_codegen_llvm::ModuleLlvm>>
   7: rustc_codegen_llvm::base::compile_codegen_unit
   8: rustc_codegen_ssa::base::codegen_crate::<rustc_codegen_llvm::LlvmCodegenBackend>
   9: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
  10: <rustc_session::session::Session>::time::<alloc::boxed::Box<dyn core::any::Any>, rustc_interface::passes::start_codegen::{closure#0}>
  11: rustc_interface::passes::start_codegen
  12: <rustc_middle::ty::context::GlobalCtxt>::enter::<<rustc_interface::queries::Queries>::ongoing_codegen::{closure#0}, core::result::Result<alloc::boxed::Box<dyn core::any::Any>, rustc_span::ErrorGuaranteed>>
  13: rustc_span::set_source_map::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}::{closure#0}>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

@fakeshadow fakeshadow added the C-bug Category: This is a bug. label Aug 15, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 15, 2023
@saethlin saethlin added 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. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Aug 15, 2023
@fakeshadow
Copy link
Author

this is a regression happens in 1.72.0-nightly (5bd28f5 2023-06-28)

@albertlarsan68 albertlarsan68 added the requires-nightly This issue requires a nightly compiler in some way. label Aug 21, 2023
@albertlarsan68
Copy link
Member

Minimized using cargo-minimize and Perses, so I was able to remove dependency on futures:

#![feature(impl_trait_in_assoc_type)]
use std::future::Future;
trait AsyncFn<Arg> {
    type Output;
    type Future<'f>: Future<Output = Self::Output>
    where
        Arg: 'f,
        Self: 'f;
    fn call<'s>(&'s self, arg: Arg) -> Self::Future<'s>
    where
        Arg: 's;
}
trait AsyncFn2<Arg> {
    type Output;
    type Future: Future<Output = Self::Output>;
    fn call(&self, arg: Arg) -> Self::Future;
}
impl<F, A, B, Fut> AsyncFn2<(A, B)> for F
where
    F: Fn(A, B) -> Fut,
    Fut: Future
{
    type Output = Fut::Output;
    type Future = Fut;
    fn call(&self, _a: (A, B)) -> Self::Future {
        loop {}
    }
}
struct Func<F>(F);
impl<Arg, F, Fut> AsyncFn<Arg> for Func<F>
where
    F: Fn(Arg) -> Fut,
    Fut: Future
{
    type Output = Fut::Output;
    type Future<'f>
     = impl Future<Output = Self::Output> + 'f where Arg: 'f, Self: 'f;
    fn call<'s>(&'s self, arg: Arg) -> Self::Future<'s>
    where
        Arg: 's
    {
        async move { (self.0)(arg).await }
    }
}
struct EnclosedFn<T1, T2> {
    this: T1,
    other: T2
}
impl<Arg, T1, T2, O> AsyncFn<Arg> for EnclosedFn<T1, T2>
where
    T2: for<'s> AsyncFn2<(&'s T1, Arg), Output = O>
{
    type Output = O;
    type Future<'f>
     = impl Future<Output = Self::Output> + 'f where Arg: 'f, Self: 'f;
    fn call<'s>(&'s self, arg: Arg) -> Self::Future<'s>
    where
        Arg: 's
    {
        self.other.call((&self.this, arg))
    }
}
trait Enclosed<Arg> {
    fn enclosed<T>(self, _other: T) -> EnclosedFn<Self, T>
    where
        Self: Sized
    {
        loop {}
    }
}
impl<Arg, F> Enclosed<Arg> for F where F: AsyncFn<Arg> {}
fn main() {
    async fn middelware<S, Arg>(s: &S, arg: Arg) -> S::Output
    where
        S: AsyncFn<Arg>
    {
        s.call(arg).await
    }
    let f = Func(|arg| async move {})
        .enclosed(middelware)
        .enclosed(middelware);
    f.call(String::new());
}

@PhotonQuantum
Copy link

PhotonQuantum commented Aug 24, 2023

I got the same ICE, but on rustc 1.72.0 stable, which persists on the latest nightly.

Code

I apologize I can't shorten the code at the moment as I'm in a rush. The code is taken from a project using actix-web and sqlx, and I have extracted all the relevant traits and types. It only requires futures and tokio to build, and works in the playground.

use std::future::Future;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;

use futures::future::BoxFuture;

#[tokio::main(flavor = "current_thread")]
async fn main() {
    wrapper_call(handler, ()).await; // must call through `wrapper_call`, or no ICE
}

pub async fn wrapper_call<F, Args>(handler: F, args: Args) -> F::Output
where
    F: Handler<Args>,
    Args: FromRequest + 'static,
    F::Output: Responder + 'static,
{
    std::hint::black_box(handler.call(args).await)
}

async fn handler() -> impl Responder {
    let mut conn: PoolConnection<Postgres> = loop {};
    let _a = f(&mut *conn).await; // must pass to a function accepting `impl Acquire`, and must await
}

async fn f<'a>(db: impl Acquire<'a, Database = Postgres>) {
    let _a = db.acquire().await; // must await
}

// === Taken from actix-web ===

pub trait Responder {}

impl Responder for () {}

pub trait Handler<Args>: Clone + 'static {
    type Output;
    type Future: Future<Output = Self::Output>;

    fn call(&self, args: Args) -> Self::Future;
}

impl<Func, Fut> Handler<()> for Func
where
    Func: Fn() -> Fut + Clone + 'static,
    Fut: Future,
{
    type Output = Fut::Output;
    type Future = Fut;

    #[inline]
    fn call(&self, _: ()) -> Self::Future {
        loop {}
    }
}

pub trait FromRequest: Sized {}

impl FromRequest for () {}

pub struct Data<T: ?Sized>(Arc<T>);

impl<T: ?Sized> Deref for Data<T> {
    type Target = Arc<T>;

    fn deref(&self) -> &Arc<T> {
        loop {}
    }
}

impl<T: ?Sized + 'static> FromRequest for Data<T> {}

// === Taken from sqlx ===

pub trait Acquire<'c> {
    type Database: Database;

    type Connection: Deref<Target = <Self::Database as Database>::Connection> + DerefMut + Send;

    fn acquire(self) -> BoxFuture<'c, Self::Connection>;
}

pub trait Database: 'static + Sized + Send {
    type Connection: Connection<Database = Self>;
}

pub trait Connection: Send {
    type Database: Database;
}

pub struct PoolConnection<DB: Database>(PhantomData<DB>);

impl<DB: Database> Deref for PoolConnection<DB> {
    type Target = DB::Connection;

    fn deref(&self) -> &Self::Target {
        loop {}
    }
}

impl<DB: Database> DerefMut for PoolConnection<DB> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        loop {}
    }
}

impl<'c, DB: Database> Acquire<'c> for &'c mut PoolConnection<DB> {
    type Database = DB;

    type Connection = &'c mut <DB as Database>::Connection;

    #[inline]
    fn acquire(self) -> BoxFuture<'c, Self::Connection> {
        loop {}
    }
}

pub struct Postgres;

impl Database for Postgres {
    type Connection = PgConnection;
}

pub struct PgConnection;

impl Connection for PgConnection {
    type Database = Postgres;
}

impl<'c> Acquire<'c> for &'c mut PgConnection {
    type Database = Postgres;

    type Connection = &'c mut <Postgres as Database>::Connection;

    #[inline]
    fn acquire(self) -> BoxFuture<'c, Self::Connection> {
        loop {}
    }
}

https://play.rust-lang.org/?version=nightly&mode=release&edition=2021&gist=f78b9542bf0a24ece742bba90a2b8247

Meta

rustc 1.72.0 (5680fa18f 2023-08-23)
binary: rustc
commit-hash: 5680fa18feaa87f3ff04063800aec256c3d4b4be
commit-date: 2023-08-23
host: aarch64-apple-darwin
release: 1.72.0
LLVM version: 16.0.5

Error output

thread 'rustc' panicked at 'assertion failed: `(left == right)`
  left: `*mut [async fn body@src/main.rs:22:38: 25:2]`,
 right: `*mut [async fn body@src/main.rs:22:38: 25:2]`: unexpected initial operand type', /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/compiler/rustc_codegen_ssa/src/mir/locals.rs:46:21
Backtrace

   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::assert_failed_inner
   3: core::panicking::assert_failed::<rustc_middle::ty::Ty, rustc_middle::ty::Ty>
   4: rustc_codegen_ssa::mir::codegen_mir::<rustc_codegen_llvm::builder::Builder>
   5: rustc_codegen_ssa::base::codegen_instance::<rustc_codegen_llvm::builder::Builder>
   6: rustc_codegen_llvm::base::compile_codegen_unit::module_codegen
   7: <rustc_middle::dep_graph::dep_node::DepKind as rustc_query_system::dep_graph::DepKind>::with_deps::<<rustc_query_system::dep_graph::graph::DepGraphData<rustc_middle::dep_graph::dep_node::DepKind>>::with_task<rustc_middle::ty::context::TyCtxt, rustc_span::symbol::Symbol, rustc_codegen_ssa::ModuleCodegen<rustc_codegen_llvm::ModuleLlvm>>::{closure#0}::{closure#0}, rustc_codegen_ssa::ModuleCodegen<rustc_codegen_llvm::ModuleLlvm>>
   8: rustc_codegen_llvm::base::compile_codegen_unit
   9: rustc_codegen_ssa::base::codegen_crate::<rustc_codegen_llvm::LlvmCodegenBackend>
  10: <rustc_codegen_llvm::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate
  11: <rustc_session::session::Session>::time::<alloc::boxed::Box<dyn core::any::Any>, rustc_interface::passes::start_codegen::{closure#0}>
  12: rustc_interface::passes::start_codegen
  13: <rustc_middle::ty::context::GlobalCtxt>::enter::<<rustc_interface::queries::Queries>::ongoing_codegen::{closure#0}, core::result::Result<alloc::boxed::Box<dyn core::any::Any>, rustc_span::ErrorGuaranteed>>
  14: <rustc_interface::queries::Queries>::ongoing_codegen
  15: <rustc_interface::interface::Compiler>::enter::<rustc_driver_impl::run_compiler::{closure#1}::{closure#2}, core::result::Result<core::option::Option<rustc_interface::queries::Linker>, rustc_span::ErrorGuaranteed>>
  16: rustc_span::set_source_map::<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_interface::interface::run_compiler<core::result::Result<(), rustc_span::ErrorGuaranteed>, rustc_driver_impl::run_compiler::{closure#1}>::{closure#0}::{closure#0}>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

@saethlin saethlin removed the requires-nightly This issue requires a nightly compiler in some way. label Aug 25, 2023
@saethlin saethlin added the regression-from-stable-to-stable Performance or correctness regression from one stable version to another. label Aug 25, 2023
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Aug 25, 2023
@albertlarsan68
Copy link
Member

albertlarsan68 commented Aug 26, 2023

Minimized using cargo-minimize and Perses, and removed all the dependencies:

use std::future::Future;
use std::ops::Deref;
use std::pin::Pin;
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T>>>;
fn main() {
    wrapper_call(handler, ());
}
async fn wrapper_call<F, Args>(handler: F, args: Args) -> F::Output
where
    F: Handler<Args>,
{
    handler.call(args).await
}
async fn handler() {
    let conn: PoolConnection<Postgres> = loop {};
    f(&mut *conn).await;
}
async fn f<'a>(db: impl Acquire<'a>) {
    db.acquire().await;
}
trait Handler<Args> {
    type Output;
    type Future: Future<Output = Self::Output>;
    fn call(&self, args: Args) -> Self::Future;
}
impl<Func, Fut> Handler<()> for Func
where
    Func: Fn() -> Fut,
    Fut: Future,
{
    type Output = Fut::Output;
    type Future = Fut;
    fn call(&self, _: ()) -> Self::Future {
        loop {}
    }
}
trait Acquire<'c> {
    type Database;
    type Connection;
    fn acquire(self) -> BoxFuture<'c, Self::Connection>;
}
trait Database {
    type Connection;
}
struct PoolConnection<DB>(DB);
impl<DB: Database> Deref for PoolConnection<DB> {
    type Target = DB::Connection;
    fn deref(&self) -> &Self::Target {
        loop {}
    }
}
struct Postgres;
impl Database for Postgres {
    type Connection = PgConnection;
}
struct PgConnection;
impl<'c> Acquire<'c> for &'c mut PgConnection {
    type Database = Postgres;
    type Connection = &'c Postgres;
    fn acquire(self) -> BoxFuture<'c, Self::Connection> {
        loop {}
    }
}

@apiraino
Copy link
Contributor

WG-prioritization assigning priority (Zulip discussion).

@rustbot label -I-prioritize +P-critical +E-needs-bisection

@rustbot rustbot added E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc P-critical Critical priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Aug 29, 2023
@lqd
Copy link
Member

lqd commented Aug 29, 2023

Bisected to #113108.

#114858 (comment) could likely be reduced even more, but it seems small enough to get a test in #115215 to fix the issue, wdyt @compiler-errors?

@lqd lqd removed the E-needs-bisection Call for participation: This issue needs bisection: https://github.com/rust-lang/cargo-bisect-rustc label Aug 29, 2023
@Luk-ESC
Copy link
Contributor

Luk-ESC commented Aug 29, 2023

Reduced #114858 (comment) some more:

use std::future::Future;
use std::pin::Pin;

type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;

fn main() {
    _ = wrapper_call(handler);
}

async fn wrapper_call(handler: impl Handler) {
    handler.call().await;
}
async fn handler() {
    f(&()).await;
}
async fn f<'a>(db: impl Acquire<'a>) {
    db.acquire().await;
}

trait Handler {
    type Future: Future;
    fn call(self) -> Self::Future;
}

impl<Fut, F> Handler for F
where
    F: Fn() -> Fut,
    Fut: Future,
{
    type Future = Fut;
    fn call(self) -> Self::Future {
        loop {}
    }
}

trait Acquire<'a> {
    type Connection;
    fn acquire(self) -> BoxFuture<Self::Connection>;
}
impl<'a> Acquire<'a> for &'a () {
    type Connection = Self;
    fn acquire(self) -> BoxFuture<Self> {
        loop {}
    }
}

@compiler-errors
Copy link
Member

Yeah, @ouz-a can you add the test above?

@ouz-a
Copy link
Contributor

ouz-a commented Sep 7, 2023

We should keep this issue open even after #115215 is merged, since there seems to be something else going on see #115215 (comment)

bors added a commit to rust-lang-ci/rust that referenced this issue Sep 12, 2023
Remove assert that checks type equality

rust-lang#112307 although this prevented `unsound` issues it also seems to introduce regressions rust-lang#114858 is example of this regression. I locally tested this rust-lang#114858 (comment) issue and failing assert is [this](https://www.diffchecker.com/cjb7jSQm/).

This is also related to rust-lang#115025
@fasterthanlime
Copy link
Contributor

fasterthanlime commented Sep 13, 2023

As of nightly-2023-09-13 (which includes #115215), my test suite passes.

That warning does appear thrice during compilation, I believe that's work left for later:

WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type. See the issues/114858

(My work is unblocked though, thanks very much!)

@ouz-a
Copy link
Contributor

ouz-a commented Sep 13, 2023

As of nightly-2023-09-13 (which includes #115215), my test suite passes.

The same warning does appear thrice during compilation, I believe that's work left for later:

WARN rustc_codegen_ssa::mir::locals Unexpected initial operand type. See the issues/114858

Hopefully that shouldn't affect your workflow, we will investigate this issue further in the future.

github-actions bot pushed a commit to rust-lang/miri that referenced this issue Sep 15, 2023
Remove assert that checks type equality

rust-lang/rust#112307 although this prevented `unsound` issues it also seems to introduce regressions rust-lang/rust#114858 is example of this regression. I locally tested this rust-lang/rust#114858 (comment) issue and failing assert is [this](https://www.diffchecker.com/cjb7jSQm/).

This is also related to rust-lang/rust#115025
@wesleywiser wesleywiser removed the P-critical Critical priority label Sep 28, 2023
@wesleywiser wesleywiser added the P-high High priority label Sep 28, 2023
@wesleywiser
Copy link
Member

Visited during the weekly compiler triage meeting. We think the severity of this issue can now be downgraded to P-high as the compiler no longer ICEs and work is continuing to remove the root cause of the current warning which is in place.

@tsatke
Copy link

tsatke commented May 25, 2024

Is there any update on this? @wesleywiser

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
C-bug Category: This is a bug. F-impl_trait_in_assoc_type `#![feature(impl_trait_in_assoc_type)]` I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. 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