310 lines
9.2 KiB
Rust
310 lines
9.2 KiB
Rust
// aux-build:arc_wake.rs
|
|
// edition:2018
|
|
// run-pass
|
|
|
|
// revisions: default nomiropt
|
|
//[nomiropt]compile-flags: -Z mir-opt-level=0
|
|
|
|
// 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 is cancelled.
|
|
// This file is mostly copy-pasted from drop-order-for-async-fn-parameters.rs
|
|
|
|
#![allow(unused_variables)]
|
|
|
|
extern crate arc_wake;
|
|
|
|
use arc_wake::ArcWake;
|
|
use std::cell::RefCell;
|
|
use std::future::Future;
|
|
use std::marker::PhantomData;
|
|
use std::pin::Pin;
|
|
use std::rc::Rc;
|
|
use std::sync::Arc;
|
|
use std::task::{Context, Poll};
|
|
|
|
struct EmptyWaker;
|
|
|
|
impl ArcWake for EmptyWaker {
|
|
fn wake(self: Arc<Self>) {}
|
|
}
|
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
enum DropOrder {
|
|
Function,
|
|
Val(&'static str),
|
|
}
|
|
|
|
type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
|
|
|
|
struct D(&'static str, DropOrderListPtr);
|
|
|
|
impl Drop for D {
|
|
fn drop(&mut self) {
|
|
self.1.borrow_mut().push(DropOrder::Val(self.0));
|
|
}
|
|
}
|
|
|
|
struct NeverReady;
|
|
|
|
impl Future for NeverReady {
|
|
type Output = ();
|
|
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
|
Poll::Pending
|
|
}
|
|
}
|
|
|
|
/// 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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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);
|
|
NeverReady.await;
|
|
}
|
|
|
|
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_cancel<Fut: Future<Output = ()>>(
|
|
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);
|
|
|
|
// Parameters are never dropped until the future completes.
|
|
assert_eq!(*actual_order.borrow(), vec![DropOrder::Function]);
|
|
|
|
drop(fut);
|
|
|
|
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_cancel(
|
|
|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_cancel(
|
|
|l| bar_async(D("x", l.clone()), D("_", l.clone())),
|
|
|l| bar_sync(D("x", l.clone()), D("_", l.clone())),
|
|
);
|
|
assert_drop_order_after_cancel(
|
|
|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
|
|
|l| baz_sync((D("x", l.clone()), D("_", l.clone()))),
|
|
);
|
|
assert_drop_order_after_cancel(
|
|
|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_cancel(
|
|
|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_cancel(
|
|
|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_cancel(
|
|
|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_cancel(
|
|
|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_cancel(
|
|
|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_cancel(
|
|
|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_cancel(
|
|
|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_cancel(
|
|
|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()),
|
|
)
|
|
},
|
|
);
|
|
}
|