-
Notifications
You must be signed in to change notification settings - Fork 13.3k
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
Comments
this is a regression happens in 1.72.0-nightly (5bd28f5 2023-06-28) |
Minimized using cargo-minimize and Perses, so I was able to remove dependency on #![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());
} |
I got the same ICE, but on rustc 1.72.0 stable, which persists on the latest nightly. CodeI apologize I can't shorten the code at the moment as I'm in a rush. The code is taken from a project using 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 {}
}
} Meta
Error output
Backtrace
|
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 {}
}
} |
WG-prioritization assigning priority (Zulip discussion). @rustbot label -I-prioritize +P-critical +E-needs-bisection |
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? |
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 {}
}
} |
Yeah, @ouz-a can you add the test above? |
We should keep this issue open even after #115215 is merged, since there seems to be something else going on see #115215 (comment) |
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
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:
(My work is unblocked though, thanks very much!) |
Hopefully that shouldn't affect your workflow, we will investigate this issue further in the future. |
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
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. |
Is there any update on this? @wesleywiser |
I tried this code:
I expected to see this happen: code compile.
Instead, this happened: internal compiler error: unexpected initial operand type
Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: