-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
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: