Enforce consistent drop order w/ async methods.

This commit extends the previous commit to apply to trait methods as
well as free functions.
This commit is contained in:
David Wood 2019-03-13 10:45:36 +01:00
parent 7c6dc7a254
commit 61346557ce
No known key found for this signature in database
GPG Key ID: 01760B4F9F53F154
2 changed files with 130 additions and 9 deletions

View File

@ -3611,15 +3611,33 @@ fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
)
}
ImplItemKind::Method(ref sig, ref body) => {
let body_id = self.lower_async_body(&sig.decl, &sig.header.asyncness.node, body);
let impl_trait_return_allow = !self.is_in_trait_impl;
let (generics, sig) = self.lower_method_sig(
&i.generics,
sig,
impl_item_def_id,
impl_trait_return_allow,
sig.header.asyncness.node.opt_return_id(),
);
let mut lower_method = |sig: &MethodSig| {
let body_id = self.lower_async_body(
&sig.decl, &sig.header.asyncness.node, body
);
let impl_trait_return_allow = !self.is_in_trait_impl;
let (generics, sig) = self.lower_method_sig(
&i.generics,
sig,
impl_item_def_id,
impl_trait_return_allow,
sig.header.asyncness.node.opt_return_id(),
);
(body_id, generics, sig)
};
let (body_id, generics, sig) = if let IsAsync::Async {
ref arguments, ..
} = sig.header.asyncness.node {
let mut sig = sig.clone();
// Replace the arguments of this async function with the generated
// arguments that will be moved into the closure.
sig.decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
lower_method(&sig)
} else {
lower_method(sig)
};
(generics, hir::ImplItemKind::Method(sig, body_id))
}
ImplItemKind::Type(ref ty) => (

View File

@ -10,6 +10,7 @@
use arc_wake::ArcWake;
use std::cell::RefCell;
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;
use std::task::Context;
@ -49,6 +50,46 @@ async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
struct Foo;
impl Foo {
async fn foo(x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
async fn bar(x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
async fn baz((x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
}
async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
}
struct Bar<'a>(PhantomData<&'a ()>);
impl<'a> Bar<'a> {
async fn foo(&'a self, x: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
async fn bar(&'a self, x: D, _: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
async fn baz(&'a self, (x, _): (D, D)) {
x.1.borrow_mut().push(DropOrder::Function);
}
async fn foobar(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
x.1.borrow_mut().push(DropOrder::Function);
}
}
fn main() {
let empty = Arc::new(EmptyWaker);
let waker = ArcWake::into_waker(empty);
@ -60,6 +101,8 @@ fn main() {
// non-async functions. This is because the drop order of captured variables doesn't match the
// drop order of arguments in a function.
// Free functions
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(foo(D("x", af.clone()), D("_y", af.clone())));
let _ = fut.as_mut().poll(&mut cx);
@ -86,4 +129,64 @@ fn main() {
assert_eq!(*af.borrow(), &[
Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_"),
]);
// Methods w/out self
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(Foo::foo(D("x", af.clone()), D("_y", af.clone())));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[Function, Val("_y"), Val("x")]);
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(Foo::bar(D("x", af.clone()), D("_", af.clone())));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(Foo::baz((D("x", af.clone()), D("_", af.clone()))));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(Foo::foobar(
D("x", af.clone()),
(D("a", af.clone()), D("_", af.clone()), D("_c", af.clone())),
D("_", af.clone()),
D("_y", af.clone()),
));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[
Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_"),
]);
// Methods
let b = Bar(Default::default());
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(b.foo(D("x", af.clone()), D("_y", af.clone())));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[Function, Val("_y"), Val("x")]);
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(b.bar(D("x", af.clone()), D("_", af.clone())));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(b.baz((D("x", af.clone()), D("_", af.clone()))));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[Function, Val("x"), Val("_")]);
let af = Arc::new(RefCell::new(Vec::new()));
let mut fut = Box::pin(b.foobar(
D("x", af.clone()),
(D("a", af.clone()), D("_", af.clone()), D("_c", af.clone())),
D("_", af.clone()),
D("_y", af.clone()),
));
let _ = fut.as_mut().poll(&mut cx);
assert_eq!(*af.borrow(), &[
Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_"),
]);
}