Closed
Description
#![feature(generators, generator_trait)]
use std::ops::Generator;
macro_rules! yield_from {
($e:expr) => {{
let mut gen = $e;
loop {
match unsafe { ::std::ops::Generator::resume(&mut gen) } {
::std::ops::GeneratorState::Yielded(e) => yield e,
::std::ops::GeneratorState::Complete(e) => break e,
}
}
}};
}
pub fn unpinned<'a, T: 'a, F, G>(
data: &'a mut T,
f: F,
) -> impl Generator<Yield = G::Yield, Return = G::Return> + 'a
where
F: FnOnce(&'a mut T) -> G + 'a,
G: Generator + 'a,
{
move || yield_from!(f(data))
}
#[derive(Debug)]
struct Foo;
impl Foo {
pub fn foo(&mut self) {
println!("{:?} at {:?}", *self, &*self as *const Self);
}
}
fn bar<'a>(foo: &'a mut Foo) -> impl Generator<Yield = (), Return = ()> + 'a {
move || {
let inner = unpinned(foo, |foo| {
move || {
foo.foo();
yield ();
foo.foo();
}
});
yield_from!(inner)
}
}
fn main() {
let mut foo = Foo;
let mut baz = bar(&mut foo);
println!("{:?}", unsafe { baz.resume() });
println!("{:?}", unsafe { baz.resume() });
}
(playground), errors:
thread 'rustc' panicked at 'assertion failed: !self.has_escaping_regions()', librustc/ty/mod.rs:1165:9
note: rustc 1.26.0-nightly (80785a547 2018-03-30) running on x86_64-unknown-linux-gnu
note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type bin
note: some of the compiler flags provided by cargo are hidden
click to see original with Pin
as well
Throwing all the new features together is always the best idea, right?
#![feature(pin, generators, generator_trait, arbitrary_self_types)]
use std::mem::Pin;
use std::ops::Generator;
macro_rules! yield_from {
($e:expr) => ({
let mut gen = $e;
loop {
let gen = &mut gen;
// The above is to force a borrow across yield point to ensure we're
// in an immovable generator, just in case $e is an immovable
// generator (hopefully we can detect this in the future somehow).
match unsafe { ::std::ops::Generator::resume(gen) } {
::std::ops::GeneratorState::Yielded(e) => yield e,
::std::ops::GeneratorState::Complete(e) => break e,
}
}
})
}
pub fn pinned<'a, T: 'a, F, G>(
data: T,
f: F,
) -> impl Generator<Yield = G::Yield, Return = G::Return> + 'a
where
F: FnOnce(Pin<'a, T>) -> G + 'a,
G: Generator + 'a,
{
static move || {
let data = data;
yield_from!(f(unsafe { Pin::new_unchecked(&mut data) }))
}
}
#[derive(Debug)]
struct Foo;
impl Foo {
pub fn foo(self: Pin<Self>) {
println!("{:?} at {:?}", *self, &*self as *const Self);
}
}
fn bar() -> impl Generator<Yield = (), Return = ()> {
static move || {
let inner = pinned(Foo, |foo| {
static move || {
foo.foo();
yield ();
foo.foo();
}
});
yield_from!(inner)
}
}
fn main() {
let mut baz = bar();
println!("{:?}", unsafe { baz.resume() });
println!("{:?}", unsafe { baz.resume() });
}
(playground), error:
thread 'rustc' panicked at 'assertion failed: !self.has_escaping_regions()', librustc/ty/mod.rs:1165:9
note: rustc 1.26.0-nightly (80785a547 2018-03-30) running on x86_64-unknown-linux-gnu
note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type bin
note: some of the compiler flags provided by cargo are hidden
I'll try and simplify this down, presumably it should be reproducible with normal references instead of Pin
s.
EDIT: Updated playground for breaking Pin
changes: https://play.rust-lang.org/?gist=4c62d656bec128a07ea2df1d12385b66&version=nightly&mode=debug