-
Notifications
You must be signed in to change notification settings - Fork 13.3k
ICE with "failed to resolve instance for <... as IntoFuture>::into_future: Ok(None)" (regression between 1.73 and 1.74) #119095
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
I remembered that when I first saw this (and didn't have enough time to minimize it to the degree I have here), it had a different error message. use std::{net::SocketAddr, future::Future, sync::Arc};
use warp::{reply::Reply, Filter};
use sqlx::postgres::Postgres;
fn login<'a>(
db: impl sqlx::Acquire<'a, Database = sqlx::Postgres> + Send + 'a,
) -> impl Future<Output = ()> + Send + 'a {
async move {
sqlx::query_scalar::<Postgres, i64>("")
.fetch_one(&mut *db.acquire().await.unwrap())
.await
.unwrap();
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
let db = Arc::new(sqlx::postgres::PgPool::connect("").await.unwrap());
let app = warp::path!()
.then(move || {
let db = db.clone();
async move {
login(&mut *db.begin().await.unwrap()).await;
"".into_response()
}
})
.recover(move |_| async {
Ok::<String, warp::Rejection>(panic!("not yet implemented"))
})
.boxed();
warp::serve(app).run(SocketAddr::new([0, 0, 0, 0].into(), 8080)).await;
} Results in an ICE, which is likely related, with this error message ("unexpected unsized tail"):
Backtrace (with `RUST_BACKTRACE=full`, same stable version)
|
@rustbot label regression-from-stable-to-stable A-async-await |
It's easy to remove This is the The codeuse std::future::{self, Future};
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
trait Acquire<'c> {
type Connection;
fn acquire(self) -> Pin<Box<dyn Future<Output = Result<Self::Connection, ()>> + Send + 'c>>;
}
struct PgConnection;
impl<'c> Acquire<'c> for &'c mut PgConnection {
type Connection = ();
fn acquire(self) -> Pin<Box<dyn Future<Output = Result<Self::Connection, ()>> + Send + 'c>> {
unimplemented!()
}
}
fn login<'a>(db: impl Acquire<'a> + Send + 'a) -> impl Future<Output = ()> + Send + 'a {
async move {
let _ = db.acquire().await;
}
}
fn main() {
path()
.then(|| async {
let mut conn = PgConnection;
login(&mut conn).await;
})
.then(|_| async { unimplemented!() })
.boxed();
}
fn path() -> impl Filter<Extract = (), Error = ()> {
filter_fn(move || future::ready(Err(())))
}
struct Then<T, F> {
_marker: PhantomData<(T, F)>,
}
impl<T, F> FilterBase for Then<T, F>
where
T: Filter,
F: Func<T::Extract> + Clone + Send,
F::Output: Future + Send,
{
type Extract = (<F::Output as Future>::Output,);
type Error = T::Error;
type Future = ThenFuture<T, F>;
}
struct ThenFuture<T, F>
where
T: Filter,
F: Func<T::Extract>,
F::Output: Future + Send,
{
_state: State<T::Future, F>,
}
enum State<T, F>
where
T: TryFuture,
F: Func<T::Ok>,
F::Output: Future + Send,
{
Second(F::Output),
}
impl<T, F> Future for ThenFuture<T, F>
where
T: Filter,
F: Func<T::Extract>,
F::Output: Future + Send,
{
type Output = Result<(<F::Output as Future>::Output,), T::Error>;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
unimplemented!()
}
}
struct MapErr<T, F> {
_filter: T,
_callback: F,
}
impl<T, F, E> FilterBase for MapErr<T, F>
where
T: Filter,
F: Fn(T::Error) -> E + Clone + Send,
{
type Extract = T::Extract;
type Error = E;
type Future = MapErrFuture<T, F>;
}
struct MapErrFuture<T: Filter, F> {
_extract: T::Future,
_callback: F,
}
impl<T, F, E> Future for MapErrFuture<T, F>
where
T: Filter,
F: Fn(T::Error) -> E,
{
type Output = Result<T::Extract, E>;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
unimplemented!()
}
}
struct BoxedFilter<T> {
_filter: Arc<
dyn Filter<
Extract = T,
Error = (),
Future = Pin<Box<dyn Future<Output = Result<T, ()>> + Send>>,
> + Send
+ Sync,
>,
}
impl<T: Send> BoxedFilter<T> {
fn new<F>(filter: F) -> BoxedFilter<T>
where
F: Filter<Extract = T> + Send + Sync + 'static,
F::Error: Into<()>,
{
let filter = Arc::new(BoxingFilter {
filter: filter.map_err(Internal, Into::into),
});
BoxedFilter { _filter: filter }
}
}
struct BoxingFilter<F> {
filter: F,
}
impl<F> FilterBase for BoxingFilter<F>
where
F: Filter,
F::Future: Send + 'static,
{
type Extract = F::Extract;
type Error = F::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Extract, Self::Error>> + Send>>;
fn filter(&self, _: Internal) -> Self::Future {
Box::pin(self.filter.filter(Internal).into_future())
}
}
trait FilterBase {
type Extract;
type Error;
type Future: Future<Output = Result<Self::Extract, Self::Error>> + Send;
fn filter(&self, _internal: Internal) -> Self::Future {
unimplemented!()
}
fn map_err<F, E>(self, _internal: Internal, _fun: F) -> MapErr<Self, F>
where
Self: Sized,
F: Fn(Self::Error) -> E + Clone,
E: Send,
{
unimplemented!()
}
}
struct Internal;
trait Filter: FilterBase {
fn then<F>(self, _fun: F) -> Then<Self, F>
where
Self: Sized,
F: Func<Self::Extract> + Clone,
F::Output: Future + Send,
{
unimplemented!()
}
fn boxed(self) -> BoxedFilter<Self::Extract>
where
Self: Sized + Send + Sync + 'static,
Self::Extract: Send,
Self::Error: Into<()>,
{
BoxedFilter::new(self)
}
}
impl<T: FilterBase> Filter for T {}
fn filter_fn<F, U>(_func: F) -> FilterFn<F>
where
F: Fn() -> U,
U: TryFuture,
{
unimplemented!()
}
struct FilterFn<F> {
_func: F,
}
impl<F, U> FilterBase for FilterFn<F>
where
F: Fn() -> U,
U: TryFuture + Send + 'static,
{
type Extract = U::Ok;
type Error = U::Error;
type Future = IntoFuture<U>;
}
trait Func<Args> {
type Output;
}
impl<F, R> Func<()> for F
where
F: Fn() -> R,
{
type Output = R;
}
impl<F, R, T2> Func<(T2,)> for F
where
F: Fn(T2) -> R,
{
type Output = R;
}
trait TryFuture: Future {
type Ok;
type Error;
fn into_future(self) -> IntoFuture<Self>
where
Self: Sized,
{
unimplemented!()
}
}
impl<F, T, E> TryFuture for F
where
F: ?Sized + Future<Output = Result<T, E>>,
{
type Ok = T;
type Error = E;
}
struct IntoFuture<Fut> {
_future: Fut,
}
impl<Fut: TryFuture> Future for IntoFuture<Fut> {
type Output = Result<Fut::Ok, Fut::Error>;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
unimplemented!()
}
} |
@rustbot labels +AsyncAwait-Triaged +WG-async We reviewed this today in WG-async triage. It sounds like a bug. |
The reproduction by lqd above no longer ICEs now, but the original example still does, so here is a new reduced version that ICEs with use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
fn any<T>() -> T {
todo!()
}
#[allow(clippy::manual_async_fn)]
fn login<'a>(db: impl Acquire<'a> + Send + 'a) -> impl Future + Send + 'a {
async {
db.acquire().await;
}
}
type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
trait Acquire<'c> {
type Connection;
fn acquire(self) -> BoxFuture<Self::Connection>;
}
impl<'c> Acquire<'c> for &'c () {
type Connection = ();
fn acquire(self) -> BoxFuture<Self::Connection> {
todo!()
}
}
struct Then<F>(F);
impl<F> Future for Then<F>
where
F: Send,
{
type Output = ();
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> {
todo!()
}
}
fn main() {
let app = Then(async {
login(any::<&'static ()>()).await;
});
#[allow(clippy::async_yields_async)]
let mut future = Box::pin(Server(async { app }));
let _ = future.as_mut().poll(any::<&mut Context>());
}
trait ConnStreamExec<F> {}
impl<F> ConnStreamExec<F> for () where F: Future {}
struct Server<S>(S);
impl<S> Future for Server<S>
where
S: Future,
(): ConnStreamExec<S::Output>,
{
type Output = ();
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> {
todo!()
}
}
trait NeverImplemented {}
impl<E, F> ConnStreamExec<F> for E where E: NeverImplemented {} Error
|
Minimized further: use std::future::Future;
fn any<T>() -> T {
todo!()
}
trait Acquire {
type Connection;
}
impl Acquire for &'static () {
type Connection = ();
}
fn get_connection<T: Acquire>() -> impl Future + Send {
async { any::<T::Connection>() }
}
fn main() {
let future = async {
get_connection::<&'static ()>().await;
};
future.resolve_me();
}
pub trait ResolveMe {
fn resolve_me(self);
}
impl<S> ResolveMe for S
where
(): CheckSend<S>,
{
fn resolve_me(self) {}
}
trait CheckSend<F> {}
impl<F> CheckSend<F> for () where F: Send {}
trait NeverImplemented {}
impl<E, F> CheckSend<F> for E where E: NeverImplemented {} |
Another example, which doesn't mention any #![feature(auto_traits)]
auto trait Auto {}
fn any<T>() -> T {
loop {}
}
trait Acquire {
type Connection;
}
impl Acquire for &'static () {
type Connection = ();
}
trait Unit {}
impl Unit for () {}
fn get_connection<T>() -> impl Unit
where
T: Acquire,
T::Connection: Unit,
{
any::<T::Connection>()
}
fn main() {
let future = async { async { get_connection::<&'static ()>() }.await };
future.resolve_me();
}
trait ResolveMe {
fn resolve_me(self);
}
impl<S> ResolveMe for S
where
(): CheckAuto<S>,
{
fn resolve_me(self) {}
}
trait CheckAuto<F> {}
impl<F> CheckAuto<F> for () where F: Auto {}
trait NeverImplemented {}
impl<E, F> CheckAuto<F> for E where E: NeverImplemented {} I wasn't able to reproduce it with the following replacement although I thought it would have the same effect: // works
trait Auto {}
impl<T: ?Sized> Auto for T {} |
add crashtests for several old unfixed ICEs Adds several new crashtests for some older ICEs that did not yet have any. Tests were added for rust-lang#128097, rust-lang#119095, rust-lang#117460 and rust-lang#126443.
add crashtests for several old unfixed ICEs Adds several new crashtests for some older ICEs that did not yet have any. Tests were added for rust-lang#128097, rust-lang#119095, rust-lang#117460 and rust-lang#126443.
Rollup merge of rust-lang#129780 - cyrgani:master, r=compiler-errors add crashtests for several old unfixed ICEs Adds several new crashtests for some older ICEs that did not yet have any. Tests were added for rust-lang#128097, rust-lang#119095, rust-lang#117460 and rust-lang#126443.
@rustbot label: -E-needs-mcve +A-auto-traits +S-has-mcve |
WG-prioritization assigning priority (Zulip discussion). @rustbot label -I-prioritize +P-medium |
Code
with the dependencies
Meta
rustc --version --verbose
:It doesn't work on nightly, beta or stable (from 17.74 onward):
Beta, stable, 1.74
Notably, the code does compiles with 1.73:
Error output
1.74 & stable:
beta and nightly:
Backtrace (`RUST_BACKTRACE=1`)
Backtrace (`RUST_BACKTRACE=full`)
The text was updated successfully, but these errors were encountered: