diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index df455a725c5b..e7fe9bf40ba7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2996,8 +2996,33 @@ impl<'a> LoweringContext<'a> { if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness { let mut body = body.clone(); + // Async function arguments are lowered into the closure body so that they are + // captured and so that the drop order matches the equivalent non-async functions. + // + // async fn foo(: , : , : ) { + // async move { + // } + // } + // + // // ...becomes... + // fn foo(__arg0: , __arg1: , __arg2: ) { + // async move { + // let __arg2 = __arg2; + // let = __arg2; + // let __arg1 = __arg1; + // let = __arg1; + // let __arg0 = __arg0; + // let = __arg0; + // } + // } + // + // If `` is a simple ident, then it is lowered to a single + // `let = ;` statement as an optimization. for a in arguments.iter().rev() { - body.stmts.insert(0, a.stmt.clone()); + if let Some(pat_stmt) = a.pat_stmt.clone() { + body.stmts.insert(0, pat_stmt); + } + body.stmts.insert(0, a.move_stmt.clone()); } let async_expr = this.make_async_expr( @@ -3093,7 +3118,11 @@ impl<'a> LoweringContext<'a> { let mut decl = decl.clone(); // Replace the arguments of this async function with the generated // arguments that will be moved into the closure. - decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect(); + for (i, a) in arguments.clone().drain(..).enumerate() { + if let Some(arg) = a.arg { + decl.inputs[i] = arg; + } + } lower_fn(&decl) } else { lower_fn(decl) @@ -3590,7 +3619,11 @@ impl<'a> LoweringContext<'a> { 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(); + for (i, a) in arguments.clone().drain(..).enumerate() { + if let Some(arg) = a.arg { + sig.decl.inputs[i] = arg; + } + } lower_method(&sig) } else { lower_method(sig) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 0fa973853221..78de85398594 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -94,7 +94,9 @@ impl<'a> DefCollector<'a> { // Walk the generated arguments for the `async fn`. for a in arguments { use visit::Visitor; - this.visit_ty(&a.arg.ty); + if let Some(arg) = &a.arg { + this.visit_ty(&arg.ty); + } } // We do not invoke `walk_fn_decl` as this will walk the arguments that are being @@ -105,10 +107,13 @@ impl<'a> DefCollector<'a> { *closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span, ); this.with_parent(closure_def, |this| { + use visit::Visitor; + // Walk each of the generated statements before the regular block body. for a in arguments { - use visit::Visitor; - // Walk each of the generated statements before the regular block body. - this.visit_stmt(&a.stmt); + this.visit_stmt(&a.move_stmt); + if let Some(pat_stmt) = &a.pat_stmt { + this.visit_stmt(&pat_stmt); + } } visit::walk_block(this, &body); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index f5cb4cfa29f5..8d5c1798e0fa 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1334,14 +1334,19 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node { for a in arguments { // Visit the argument.. - self.visit_pat(&a.arg.pat); - if let ast::ArgSource::AsyncFn(pat) = &a.arg.source { - self.visit_pat(pat); + if let Some(arg) = &a.arg { + self.visit_pat(&arg.pat); + if let ast::ArgSource::AsyncFn(pat) = &arg.source { + self.visit_pat(pat); + } + self.visit_ty(&arg.ty); } - self.visit_ty(&a.arg.ty); // ..and the statement. - self.visit_stmt(&a.stmt); + self.visit_stmt(&a.move_stmt); + if let Some(pat_stmt) = &a.pat_stmt { + self.visit_stmt(&pat_stmt); + } } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index be68f3035371..281be201a66c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -862,7 +862,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { // Walk the generated async arguments if this is an `async fn`, otherwise walk the // normal arguments. if let IsAsync::Async { ref arguments, .. } = asyncness { - for a in arguments { add_argument(&a.arg); } + for (i, a) in arguments.iter().enumerate() { + if let Some(arg) = &a.arg { + add_argument(&arg); + } else { + add_argument(&declaration.inputs[i]); + } + } } else { for a in &declaration.inputs { add_argument(a); } } @@ -882,8 +888,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { let mut body = body.clone(); // Insert the generated statements into the body before attempting to // resolve names. - for a in arguments { - body.stmts.insert(0, a.stmt.clone()); + for a in arguments.iter().rev() { + if let Some(pat_stmt) = a.pat_stmt.clone() { + body.stmts.insert(0, pat_stmt); + } + body.stmts.insert(0, a.move_stmt.clone()); } self.visit_block(&body); } else { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a20bf91a6ad4..33b8c76bb531 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1865,10 +1865,14 @@ pub enum Unsafety { pub struct AsyncArgument { /// `__arg0` pub ident: Ident, - /// `__arg0: ` argument to replace existing function argument `: `. - pub arg: Arg, - /// `let : = __arg0;` statement to be inserted at the start of the block. - pub stmt: Stmt, + /// `__arg0: ` argument to replace existing function argument `: `. Only if + /// argument is not a simple binding. + pub arg: Option, + /// `let __arg0 = __arg0;` statement to be inserted at the start of the block. + pub move_stmt: Stmt, + /// `let = __arg0;` statement to be inserted at the start of the block, after matching + /// move statement. Only if argument is not a simple binding. + pub pat_stmt: Option, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 68cd3c28676f..f5e18e98436e 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -199,7 +199,10 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { if let ast::IsAsync::Async { ref mut arguments, .. } = a { for argument in arguments.iter_mut() { - self.next_id(&mut argument.stmt.id); + self.next_id(&mut argument.move_stmt.id); + if let Some(ref mut pat_stmt) = &mut argument.pat_stmt { + self.next_id(&mut pat_stmt.id); + } } } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index d3441a2039b1..2e09235ca77b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -694,13 +694,21 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => { vis.visit_id(closure_id); vis.visit_id(return_impl_trait_id); - for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() { + for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() { vis.visit_ident(ident); - vis.visit_arg(arg); - visit_clobber(stmt, |stmt| { + if let Some(arg) = arg { + vis.visit_arg(arg); + } + visit_clobber(move_stmt, |stmt| { vis.flat_map_stmt(stmt) .expect_one("expected visitor to produce exactly one item") }); + visit_opt(pat_stmt, |stmt| { + visit_clobber(stmt, |stmt| { + vis.flat_map_stmt(stmt) + .expect_one("expected visitor to produce exactly one item") + }) + }); } } IsAsync::NotAsync => {} diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8efe84cdf016..a10ee17b7e79 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8880,11 +8880,37 @@ impl<'a> Parser<'a> { let name = format!("__arg{}", index); let ident = Ident::from_str(&name); + // Check if this is a ident pattern, if so, we can optimize and avoid adding a + // `let = __argN;` statement, instead just adding a `let = ;` + // statement. + let (ident, is_simple_pattern) = match input.pat.node { + PatKind::Ident(_, ident, _) => (ident, true), + _ => (ident, false), + }; + // Construct an argument representing `__argN: ` to replace the argument of the - // async function. - let arg = Arg { - ty: input.ty.clone(), - id, + // async function if it isn't a simple pattern. + let arg = if is_simple_pattern { + None + } else { + Some(Arg { + ty: input.ty.clone(), + id, + pat: P(Pat { + id, + node: PatKind::Ident( + BindingMode::ByValue(Mutability::Immutable), ident, None, + ), + span, + }), + source: ArgSource::AsyncFn(input.pat.clone()), + }) + }; + + // Construct a `let __argN = __argN;` statement to insert at the top of the + // async closure. This makes sure that the argument is captured by the closure and + // that the drop order is correct. + let move_local = Local { pat: P(Pat { id, node: PatKind::Ident( @@ -8892,13 +8918,6 @@ impl<'a> Parser<'a> { ), span, }), - source: ArgSource::AsyncFn(input.pat.clone()), - }; - - // Construct a `let = __argN;` statement to insert at the top of the - // async closure. - let local = P(Local { - pat: input.pat.clone(), // We explicitly do not specify the type for this statement. When the user's // argument type is `impl Trait` then this would require the // `impl_trait_in_bindings` feature to also be present for that same type to @@ -8918,10 +8937,25 @@ impl<'a> Parser<'a> { span, attrs: ThinVec::new(), source: LocalSource::AsyncFn, - }); - let stmt = Stmt { id, node: StmtKind::Local(local), span, }; + }; - arguments.push(AsyncArgument { ident, arg, stmt }); + // Construct a `let = __argN;` statement to insert at the top of the + // async closure if this isn't a simple pattern. + let pat_stmt = if is_simple_pattern { + None + } else { + Some(Stmt { + id, + node: StmtKind::Local(P(Local { + pat: input.pat.clone(), + ..move_local.clone() + })), + span, + }) + }; + + let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span }; + arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt }); } } } diff --git a/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs b/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs new file mode 100644 index 000000000000..708c57049846 --- /dev/null +++ b/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs @@ -0,0 +1,263 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![allow(unused_variables)] +#![feature(async_await, await_macro)] + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn completes execution. +// See also #54716. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync((x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(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> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(&'a self, x: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(&'a self, x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync(&'a self, (x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_poll>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/run-pass/issue-54716.rs b/src/test/run-pass/issue-54716.rs deleted file mode 100644 index 961c412f5ecb..000000000000 --- a/src/test/run-pass/issue-54716.rs +++ /dev/null @@ -1,184 +0,0 @@ -// aux-build:arc_wake.rs -// edition:2018 -// run-pass - -#![allow(unused_variables)] -#![feature(async_await, await_macro)] - -extern crate arc_wake; - -use arc_wake::ArcWake; -use std::cell::RefCell; -use std::future::Future; -use std::marker::PhantomData; -use std::sync::Arc; -use std::rc::Rc; -use std::task::Context; - -struct EmptyWaker; - -impl ArcWake for EmptyWaker { - fn wake(self: Arc) {} -} - -#[derive(Debug, Eq, PartialEq)] -enum DropOrder { - Function, - Val(&'static str), -} - -type DropOrderListPtr = Rc>>; - -struct D(&'static str, DropOrderListPtr); - -impl Drop for D { - fn drop(&mut self) { - self.1.borrow_mut().push(DropOrder::Val(self.0)); - } -} - -/// Check that unused bindings are dropped after the function is polled. -async fn foo(x: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); -} - -/// Check that underscore patterns are dropped after the function is polled. -async fn bar(x: D, _: D) { - x.1.borrow_mut().push(DropOrder::Function); -} - -/// Check that underscore patterns within more complex patterns are dropped after the function -/// is polled. -async fn baz((x, _): (D, D)) { - x.1.borrow_mut().push(DropOrder::Function); -} - -/// Check that underscore and unused bindings within and outwith more complex patterns are dropped -/// after the function is polled. -async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); -} - -struct Foo; - -impl Foo { - /// Check that unused bindings are dropped after the method is polled. - async fn foo(x: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns are dropped after the method is polled. - async fn bar(x: D, _: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns within more complex patterns are dropped after the method - /// is polled. - async fn baz((x, _): (D, D)) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore and unused bindings within and outwith more complex patterns are - /// dropped after the method is polled. - 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> { - /// Check that unused bindings are dropped after the method with self is polled. - async fn foo(&'a self, x: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns are dropped after the method with self is polled. - async fn bar(&'a self, x: D, _: D) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore patterns within more complex patterns are dropped after the method - /// with self is polled. - async fn baz(&'a self, (x, _): (D, D)) { - x.1.borrow_mut().push(DropOrder::Function); - } - - /// Check that underscore and unused bindings within and outwith more complex patterns are - /// dropped after the method with self is polled. - async fn foobar(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) { - x.1.borrow_mut().push(DropOrder::Function); - } -} - -fn assert_drop_order_after_poll>( - f: impl FnOnce(DropOrderListPtr) -> Fut, - expected_order: &[DropOrder], -) { - let empty = Arc::new(EmptyWaker); - let waker = ArcWake::into_waker(empty); - let mut cx = Context::from_waker(&waker); - - let actual_order = Rc::new(RefCell::new(Vec::new())); - let mut fut = Box::pin(f(actual_order.clone())); - let _ = fut.as_mut().poll(&mut cx); - - assert_eq!(*actual_order.borrow(), expected_order); -} - -fn main() { - use DropOrder::*; - - // At time of writing (23/04/19), the `bar` and `foobar` tests do not output the same order as - // the equivalent 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 (see doc comment on function for what it tests). - assert_drop_order_after_poll(|l| foo(D("x", l.clone()), D("_y", l.clone())), - &[Function, Val("_y"), Val("x")]); - assert_drop_order_after_poll(|l| bar(D("x", l.clone()), D("_", l.clone())), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| baz((D("x", l.clone()), D("_", l.clone()))), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| { - foobar( - D("x", l.clone()), - (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), - D("_", l.clone()), - D("_y", l.clone()), - ) - }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]); - - // Methods w/out self (see doc comment on function for what it tests). - assert_drop_order_after_poll(|l| Foo::foo(D("x", l.clone()), D("_y", l.clone())), - &[Function, Val("_y"), Val("x")]); - assert_drop_order_after_poll(|l| Foo::bar(D("x", l.clone()), D("_", l.clone())), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| Foo::baz((D("x", l.clone()), D("_", l.clone()))), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| { - Foo::foobar( - D("x", l.clone()), - (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), - D("_", l.clone()), - D("_y", l.clone()), - ) - }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]); - - // Methods (see doc comment on function for what it tests). - let b = Bar(Default::default()); - assert_drop_order_after_poll(|l| b.foo(D("x", l.clone()), D("_y", l.clone())), - &[Function, Val("_y"), Val("x")]); - assert_drop_order_after_poll(|l| b.bar(D("x", l.clone()), D("_", l.clone())), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| b.baz((D("x", l.clone()), D("_", l.clone()))), - &[Function, Val("x"), Val("_")]); - assert_drop_order_after_poll(|l| { - b.foobar( - D("x", l.clone()), - (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), - D("_", l.clone()), - D("_y", l.clone()), - ) - }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]); -}