-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #106264 - Swatinem:higher-lifetime-regression, r=petroc…
…henkov Add regression test for #105501 The test was minified from the published crate `msf-ice:0.2.1` which failed in a crater run. A faulty compiler was triggering a `higher-ranked lifetime error`: > could not prove `[async block@...]: Send` The testcase has some complexity, as it has a simplified subset of `futures::StreamExt` in it, but the error is only being triggered by a few layers of nesting. For example removing the noop `then` call would have been enough to make the error go away.
- Loading branch information
Showing
1 changed file
with
165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// check-pass | ||
// edition:2018 | ||
|
||
// This is a regression test for https://github.com/rust-lang/rust/issues/105501. | ||
// It was minified from the published `msf-ice:0.2.1` crate which failed in a crater run. | ||
// A faulty compiler was triggering a `higher-ranked lifetime error`: | ||
// | ||
// > could not prove `[async block@...]: Send` | ||
|
||
use mini_futures::Stream; | ||
|
||
fn is_send(_: impl Send) {} | ||
|
||
pub fn main() { | ||
let fut = async { | ||
let mut stream = mini_futures::iter([()]) | ||
.then(|_| async {}) | ||
.map(|_| async { None }) | ||
.buffered() | ||
.filter_map(std::future::ready); | ||
|
||
stream.next().await | ||
}; | ||
|
||
is_send(async move { | ||
let _: Option<()> = fut.await; | ||
}); | ||
} | ||
|
||
// this is a simplified subset of `futures::StreamExt` and related types | ||
mod mini_futures { | ||
use std::future::Future; | ||
use std::pin::Pin; | ||
use std::task::{Context, Poll}; | ||
|
||
pub fn iter<I>(_: I) -> Iter<I::IntoIter> | ||
where | ||
I: IntoIterator, | ||
{ | ||
todo!() | ||
} | ||
|
||
pub trait Stream { | ||
type Item; | ||
|
||
fn then<Fut, F>(self, _: F) -> Then<Self, Fut, F> | ||
where | ||
F: FnMut(Self::Item) -> Fut, | ||
Fut: Future, | ||
Self: Sized, | ||
{ | ||
todo!() | ||
} | ||
|
||
fn map<T, F>(self, _: F) -> Map<Self, F> | ||
where | ||
F: FnMut(Self::Item) -> T, | ||
Self: Sized, | ||
{ | ||
todo!() | ||
} | ||
|
||
fn buffered(self) -> Buffered<Self> | ||
where | ||
Self::Item: Future, | ||
Self: Sized, | ||
{ | ||
todo!() | ||
} | ||
|
||
fn filter_map<Fut, T, F>(self, _: F) -> FilterMap<Self, Fut, F> | ||
where | ||
F: FnMut(Self::Item) -> Fut, | ||
Fut: Future<Output = Option<T>>, | ||
Self: Sized, | ||
{ | ||
todo!() | ||
} | ||
|
||
fn next(&mut self) -> Next<'_, Self> { | ||
todo!() | ||
} | ||
} | ||
|
||
pub struct Iter<I> { | ||
__: I, | ||
} | ||
impl<I> Stream for Iter<I> | ||
where | ||
I: Iterator, | ||
{ | ||
type Item = I::Item; | ||
} | ||
|
||
pub struct Then<St, Fut, F> { | ||
__: (St, Fut, F), | ||
} | ||
impl<St, Fut, F> Stream for Then<St, Fut, F> | ||
where | ||
St: Stream, | ||
F: FnMut(St::Item) -> Fut, | ||
Fut: Future, | ||
{ | ||
type Item = Fut::Output; | ||
} | ||
|
||
pub struct Map<St, F> { | ||
__: (St, F), | ||
} | ||
impl<St, F> Stream for Map<St, F> | ||
where | ||
St: Stream, | ||
F: FnMut1<St::Item>, | ||
{ | ||
type Item = F::Output; | ||
} | ||
|
||
pub trait FnMut1<A> { | ||
type Output; | ||
} | ||
impl<T, A, R> FnMut1<A> for T | ||
where | ||
T: FnMut(A) -> R, | ||
{ | ||
type Output = R; | ||
} | ||
|
||
pub struct Buffered<St> | ||
where | ||
St: Stream, | ||
St::Item: Future, | ||
{ | ||
__: (St, St::Item), | ||
} | ||
impl<St> Stream for Buffered<St> | ||
where | ||
St: Stream, | ||
St::Item: Future, | ||
{ | ||
type Item = <St::Item as Future>::Output; | ||
} | ||
|
||
pub struct FilterMap<St, Fut, F> { | ||
__: (St, Fut, F), | ||
} | ||
impl<St, Fut, F, T> Stream for FilterMap<St, Fut, F> | ||
where | ||
St: Stream, | ||
F: FnMut1<St::Item, Output = Fut>, | ||
Fut: Future<Output = Option<T>>, | ||
{ | ||
type Item = T; | ||
} | ||
|
||
pub struct Next<'a, St: ?Sized> { | ||
__: &'a mut St, | ||
} | ||
impl<St: ?Sized + Stream> Future for Next<'_, St> { | ||
type Output = Option<St::Item>; | ||
|
||
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> { | ||
todo!() | ||
} | ||
} | ||
} |