-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
yield has a problem with lifetimes #45259
Comments
Well, this is a bit awkward: After looking at issue 44197 I tried to replace -match foo.i() {
+let i = foo.i();
+match i { in the code above, and the compilation suddenly worked fine. #![feature(conservative_impl_trait, generators, generator_trait)]
extern crate futures;
use std::ops::{ Generator, GeneratorState };
use futures::{ Async, future, Future };
struct Foo {
i: u8,
}
impl Foo {
fn i<'a>(&'a mut self) -> impl Future<Item = u8, Error = ()> + 'a {
future::ok(self.i)
}
}
fn run<'a>(foo: &'a mut Foo) -> impl Generator<Yield = (), Return = Result<u8, ()>> + 'a {
move || {
if false {
yield
}
let _ = {
let mut f = foo.i();
loop {
let poll = f.poll();
match poll {
Ok(Async::Ready(i)) => break i,
Ok(Async::NotReady) => yield,
_ => unreachable!(),
}
}
};
{
let mut f = foo.i();
let poll = f.poll();
match poll {
Ok(Async::Ready(i)) => Ok(i),
_ => unreachable!(),
}
}
}
}
fn main() {
let mut foo = Foo { i: 0 };
let mut g = run(&mut foo);
match g.resume() {
GeneratorState::Complete(Ok(i)) => println!("{}", i),
_ => unreachable!(),
}
} |
Reduced test case: #![feature(conservative_impl_trait, generators, generator_trait)]
use std::ops::Generator;
trait Tr { }
struct Foo;
impl Tr for Foo { }
struct Bar;
impl Bar {
fn baz<'a>(&'a mut self) -> impl Tr + 'a {
Foo
}
}
fn run<'a>(bar: &'a mut Bar) -> impl Generator<Yield = (), Return = ()> + 'a {
move || {
if false {
yield;
}
{
let _baz = bar.baz();
if false { yield; }
}
{
bar.baz();
}
}
}
fn main() {
} |
These are all due to borrows being considered live at a suspension point. @nikomatsakis You wrote the code that should detect these cases. @arielb1 also had some comments about it you should look at. |
@Zoxc, Are you saying that this is just the wrong error message or do you agree that this is a 'real' bug? |
It is just a wrong error message. |
I do not see why this code should not work. The mutual reference of |
There actually seem to be something interesting going on here. Here is a reduced test case: #![feature(generators)]
fn _run(bar: &mut i32) {
|| {
{
let _baz = &*bar;
yield;
}
*bar = 2;
};
}
fn main() {}
This program is not fundamentally unsafe and would compile if region inference had found a better lifetime for the reborrow. So I guess this is more unfortunate semantics than a bug, but the error message should still be improved. |
Thanks, @Zoxc for your explanation. I see now why this code won't compile. I don't know if it's possible to make the compiler inject some code after the |
@manuels I'm working on a way to make this work. |
This is basically non-lexical lifetimes. The borrow is inferred to be potentially live over a yield point, and therefore it's potentially live while the generator is used. |
Or you could attack the "both fn foo(x: &mut u32) {
// both `s` and `t` are live for the generator's lifetime, but within
// the generator they have distinct lifetimes.
move || {
{
let s = &mut *x;
yield;
*s += 1;
}
let t = &mut *x;
yield;
*t += 1;
};
} |
@Zoxc, thanks for taking care of this issue! Are there any updates (e.g. about blocking issues) on this bug? |
Apparently @arielb1 did something on the issue blocking immovable types. |
Great, thanks for the update! |
So with
|
@manuels That is a separate bug so a new issue should be created for it. |
Ok, I was wondering, but the backtrace looked too complex to me to analyze it. Thanks, @Zoxc! |
…ws across suspension points to borrowck. Fixes rust-lang#44197, rust-lang#45259 and rust-lang#45093.
This bug is fixed by #47353 and using |
Immovable generators This adds support for immovable generators which allow you to borrow local values inside generator across suspension points. These are declared using a `static` keyword: ```rust let mut generator = static || { let local = &Vec::new(); yield; local.push(0i8); }; generator.resume(); // ERROR moving the generator after it has resumed would invalidate the interior reference // drop(generator); ``` Region inference is no longer affected by the types stored in generators so the regions inside should be similar to other code (and unaffected by the presence of `yield` expressions). The borrow checker is extended to pick up the slack so interior references still result in errors for movable generators. This fixes #44197, #45259 and #45093. This PR depends on [PR #44917 (immovable types)](#44917), I suggest potential reviewers ignore the first commit as it adds immovable types.
When working with
futures-await
I ran into a problem with lifetimes. @Arnavion was able to pin it down to the implementation of generators.I simplified the code and got rid of
futures
completely. My current minimal example to reproduce this bug reads:For some reason the compiler complains:
@Arnavion's diagnosis is
I tried to have a look at the rust compiler's implementation of
std::ops::Generator
by I don't know enough to debug this problem.The fact that the compiler complains about the lifetime, however, is strange.
The text was updated successfully, but these errors were encountered: