Skip to content

Commit

Permalink
Rollup merge of rust-lang#63294 - alsuren:async-tests, r=cramertj
Browse files Browse the repository at this point in the history
tests for async/await drop order

This is just me helping out with rust-lang#62121 where I can.

I'm also going to use this as a public place to collect my thoughts about what has already been done and what hasn't (adding comments to the dropbox paper doc was quickly getting spammy).

I've tried to keep my commit messages similar to the line items on https://paper.dropbox.com/doc/async.await-Call-for-Tests--AiKouT0L41mSnK1741s~TiiRAg-nMyZGrra7dz9KcFRMLKJy as possible.

A bunch of my tests are likely to be either redundant with other tests, or lower quality than other tests that people are writing. A reasonable approach might be to tell me which commits you want to keep and I'll throw away the rest of them.

The part from the dropbox paper doc that I'm concentrating on here is:
(items marked with `?` are ones that I can't immediately think of how to test, so I will leave for other people. Items with checkboxes are things that I have done or will try to do next)

### Dynamic semantics
- `async`/`await` with unusual locals:
    - ? partially uninhabited
    - ? conditionally initialized
    - ~drop impls~ already done in src/test/ui/async-await/drop-order/*
    - ? nested drop impls
    - ~partially moved (e.g., `let x = (vec![], vec![]); drop(x.0); foo.await; drop(x.1);`)~ see  rust-lang#63310
- Control flow:
    - basic
    - complex
- [x] `.await` while holding variables of different sizes
- (possibly) drop order
    - [x] including drop order for locals when a future is dropped part-way through execution
         - Parameters' drop order is covered in my commit f40190a
    - ~An async fn version of `dynamic-drop.rs`~
        - already done by matthewjasper in https://github.com/rust-lang/rust/pull/62193/files
- ? interaction with const eval, promoteds, and temporaries
- [x] drop the resulting future and check that local variables and parameters are dropped in the expected order (interaction with cancellation, in other words)
    - also in f40190a

Explanation of commits:

* 0a1bdd4 is the simplest place I could think of to explicitly test `.await` while holding variables of different sizes. I'm pretty sure that this will end up being redundant with something else, so I'm happy to drop it.
* f40190a is a copy-paste from `drop-order-for-async-fn-parameters.rs` with `NeverReady.await` dumped on the end of each testcase.
    * Normally I don't like copy-paste-based tests, but `drop-order-for-async-fn-parameters-by-ref-binding.rs` is also copy-paste, so I thought it might be okay.
    * [x] I'm a bit sad that this doesn't cover non-parameter locals, but I think it should be easy enough to extend in that direction, so I might have a crack at that tomorrow.
* c4940e0 makes a bunch of local variables and moves them into either `{}` blocks or `async move {}` blocks, checking for any surprising differences.
    * I have tried to give the test functions descriptive names
    * I have not duplicated the tests for methods with/without self.
    * I think that all of these tests could be rewritten to be clearer if I could write down the expected drop order next to each test.
  • Loading branch information
Centril committed Aug 6, 2019
2 parents fb79a74 + c4940e0 commit 7860cf4
Show file tree
Hide file tree
Showing 3 changed files with 501 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/test/ui/async-await/async-fn-size-moved-locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,27 @@ async fn joined_with_noop() {
joiner.await
}

async fn mixed_sizes() {
let a = BigFut::new();
let b = BigFut::new();
let c = BigFut::new();
let d = BigFut::new();
let e = BigFut::new();
let joiner = Joiner {
a: Some(a),
b: Some(b),
c: Some(c),
};

d.await;
e.await;
joiner.await;
}

fn main() {
assert_eq!(1028, std::mem::size_of_val(&single()));
assert_eq!(1032, std::mem::size_of_val(&single_with_noop()));
assert_eq!(3084, std::mem::size_of_val(&joined()));
assert_eq!(3084, std::mem::size_of_val(&joined_with_noop()));
assert_eq!(7188, std::mem::size_of_val(&mixed_sizes()));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// aux-build:arc_wake.rs
// edition:2018
// run-pass

#![allow(unused_variables)]
#![deny(dead_code)]
#![feature(async_await)]

// Test that the drop order for locals in a fn and async fn matches up.
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(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Poll::Pending
}
}

async fn simple_variable_declaration_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
NeverReady.await;
}

fn simple_variable_declaration_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
}

async fn varable_completely_contained_within_block_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
async {
let x = D("x", l.clone());
}
.await;
let y = D("y", l.clone());
NeverReady.await;
}

fn varable_completely_contained_within_block_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
{
let x = D("x", l.clone());
}
let y = D("y", l.clone());
}

async fn variables_moved_into_separate_blocks_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
async move { x }.await;
async move { y }.await;
NeverReady.await;
}

fn variables_moved_into_separate_blocks_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
{
x
};
{
y
};
}

async fn variables_moved_into_same_block_async(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
async move {
x;
y;
};
NeverReady.await;
}

fn variables_moved_into_same_block_sync(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
{
x;
y;
};
return;
}

async fn move_after_current_await_doesnt_affect_order(l: DropOrderListPtr) {
l.borrow_mut().push(DropOrder::Function);
let x = D("x", l.clone());
let y = D("y", l.clone());
NeverReady.await;
async move {
x;
y;
};
}

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);
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() {
assert_drop_order_after_cancel(
simple_variable_declaration_async,
simple_variable_declaration_sync,
);
assert_drop_order_after_cancel(
varable_completely_contained_within_block_async,
varable_completely_contained_within_block_sync,
);
assert_drop_order_after_cancel(
variables_moved_into_separate_blocks_async,
variables_moved_into_separate_blocks_sync,
);
assert_drop_order_after_cancel(
variables_moved_into_same_block_async,
variables_moved_into_same_block_sync,
);
assert_drop_order_after_cancel(
move_after_current_await_doesnt_affect_order,
simple_variable_declaration_sync,
);
}
Loading

0 comments on commit 7860cf4

Please sign in to comment.