-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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 with "failed to resolve instance for <... as IntoFuture>::into_future: Ok(None)" (regression between 1.73 and 1.74) #119095
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.
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: