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: unexpected initial operand type. #114858

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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