async/await: “the requirement `for<'r> 'r : 'static` is not satisfied” with `'static` across await point
Ekleog opened this issue · 5 comments
(continuation of rust-lang/futures-rs#1199 as it looks like a compiler bug after all, important points repeated here)
Problem
There appear to be an issue in handling traits that have a parent 'static bound boxed through an await point: the following example fails to compile with the requirement for<'r> 'r : 'static is not satisfied (note: I'm using generators for simplicity of reproduction, see below for a futures-only example)
trait Trait: 'static {}
async fn foo(b: Box<Trait + 'static>) -> () {
let bar = move || { b; () };
yield
}However, when removing the 'static bound on Trait, it appears to compile correctly, even though the Box itself still has the + 'static bound.
trait Trait {}
async fn foo(b: Box<Trait + 'static>) -> () {
let bar = move || { b; () };
yield
}Futures-only version
The error originated in code that looked like:
use futures::future;
use std::any::Any;
async fn foo(b: Box<Any + Send + 'static>) -> () {
await!(future::lazy(move |_| {
b;
()
}))
} The Any being here the trait that has the 'static bound. This was tested with futures-rs at commit rust-lang/futures-rs@c02ec75 and nightly 2018-08-14.
No generator-only version
I couldn't manage to get a generator-only version to fail: this compiles.
use std::any::Any;
use std::ops::Generator;
fn send(msg: Box<Any + 'static>) -> impl Generator + 'static {
|| {
let mut pinned = move || { msg; () };
yield
}
}Potentially related issue
This is potentially related to #53259, as the same for<'r> appears there?
Some work has started on #53736 ; the information there will likely be helpful to someone trying to fix this.
I think I've hit this with a generator-only code.
#![feature(generators)]
use std::cell::RefCell;
use std::rc::Rc;
trait Trait: 'static {}
struct Store<C> {
inner: Rc<RefCell<Option<C>>>,
}
#[test]
fn test_compose() {
Box::new(static move || {
let store = Store::<Box<dyn Trait>> {
inner: Default::default(),
};
yield ();
});
}I'm marking this issue as blocking the async-await stabilization -- if nothing else, we need to investigate it and figure out what is going on.
I did some more digging into this problem. This code will actually ICE if using a version of rustc built with debug assertions. Moreover, the follow example code -- which doesn't use generators at all -- will ICE in the same way:
use std::cell::RefCell;
use std::rc::Rc;
trait Trait: 'static {}
struct Store<C> {
inner: Rc<RefCell<Option<C>>>,
}
fn main() {
let store = Store::<Box<for<'a> fn(&(dyn Trait + 'a))>> {
inner: Default::default(),
};
}the problem here ultimately has to do with the way that the WF code works. I left some obscure notes on Zulip, but the bottom line is something like this:
- The WF code presently descends through binders but (generally speaking) opts not to prove WF conditions that involve higher-ranked regions.
- The strategy was described as "lazy" in the relevant RFC, but with the new universes code we can generally try to pursue something better, so I hope to get rid of it sooner or later.
- Anyway the idea is that whenever a higher-region is "expanded" with a particular value, we'll prove the WF at that point.
So in this particular case we wind up with a type for<'a> (dyn Trait + 'a) -- for this type to be WF, the region bound 'a: 'static must hold. We are producing this constraint. If debug assertions are enabled, we ICE out because the constraint isn't supposed to include higher-ranked regions (here, 'a). But without debug assertions, we fail to detect that, and then we just wind up failing to prove it.
It's kind of hard to stumble across this ICE normally, because dyn Trait defaults to dyn Trait + 'static since we see the 'static bound declared on Trait. However, with generators, it occurs more readily because when constructing the generator witness, we replace the 'static with a bound region (we replace all the internal regions in this way).
Pursuant with the existing lazy strategy, I think the right fix is just for the wf code to ignore the 'a: 'static constraint -- and that is a small patch to do. I will probably open a PR around this shortly.
Great, thank you! I can confirm that on latest nightly the issue is no longer there :D