diff options
Diffstat (limited to 'src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs')
-rw-r--r-- | src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs b/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs new file mode 100644 index 000000000..10f6bd740 --- /dev/null +++ b/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs @@ -0,0 +1,46 @@ +// check-pass + +#![feature(gen_future, generator_trait, negative_impls)] + +use std::ops::{Generator, GeneratorState}; +use std::task::{Poll, Context}; +use std::future::{Future}; +use std::ptr::NonNull; +use std::pin::Pin; + +fn main() {} + +#[derive(Debug, Copy, Clone)] +pub struct ResumeTy(NonNull<Context<'static>>); + +unsafe impl Send for ResumeTy {} + +unsafe impl Sync for ResumeTy {} + +pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return> +where + T: Generator<ResumeTy, Yield = ()>, +{ + struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T); + + // We rely on the fact that async/await futures are immovable in order to create + // self-referential borrows in the underlying generator. + impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {} + + impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> { + type Output = T::Return; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection. + let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; + + // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The + // `.await` lowering will safely cast that back to a `&mut Context`. + match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) { + GeneratorState::Yielded(()) => Poll::Pending, + GeneratorState::Complete(x) => Poll::Ready(x), + } + } + } + + GenFuture(gen) +} |