Skip to content
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 impl Generator: self.has_escaping_regions #49537

Closed
Nemo157 opened this issue Mar 31, 2018 · 1 comment
Closed

ICE with impl Generator: self.has_escaping_regions #49537

Nemo157 opened this issue Mar 31, 2018 · 1 comment
Labels
A-coroutines Area: Coroutines C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Nemo157
Copy link
Member

Nemo157 commented Mar 31, 2018

#![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 Pins.

EDIT: Updated playground for breaking Pin changes: https://play.rust-lang.org/?gist=4c62d656bec128a07ea2df1d12385b66&version=nightly&mode=debug

@Nemo157 Nemo157 changed the title ICE with impl Generator using Pin ICE with impl Generator: self.has_escaping_regions Mar 31, 2018
@pietroalbini pietroalbini added I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ A-coroutines Area: Coroutines T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 11, 2018
@XAMPPRocky XAMPPRocky added the C-bug Category: This is a bug. label Jun 29, 2018
@Nemo157
Copy link
Member Author

Nemo157 commented Apr 4, 2019

Another updated playground for generator API changes. This now appears to compile and run fine.

@Nemo157 Nemo157 closed this as completed Apr 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-coroutines Area: Coroutines C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants