Skip to content

Commit b96a286

Browse files
authored
Rollup merge of rust-lang#62106 - cramertj:test-await, r=centril
Add more tests for async/await I'll follow up with more of these, but here's an initial few. r? @Centril
2 parents af407c1 + ba12e78 commit b96a286

8 files changed

+338
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// compile-fail
2+
// edition:2018
3+
// compile-flags: --crate-type lib
4+
5+
#![feature(async_await)]
6+
7+
use std::{
8+
cell::RefCell,
9+
fmt::Debug,
10+
rc::Rc,
11+
};
12+
13+
fn non_sync() -> impl Debug { RefCell::new(()) }
14+
15+
fn non_send() -> impl Debug { Rc::new(()) }
16+
17+
fn take_ref<T>(_: &T) {}
18+
19+
async fn fut() {}
20+
21+
async fn fut_arg<T>(_: T) {}
22+
23+
async fn local_dropped_before_await() {
24+
// FIXME: it'd be nice for this to be allowed in a `Send` `async fn`
25+
let x = non_send();
26+
drop(x);
27+
fut().await;
28+
}
29+
30+
async fn non_send_temporary_in_match() {
31+
// We could theoretically make this work as well (produce a `Send` future)
32+
// for scrutinees / temporaries that can or will
33+
// be dropped prior to the match body
34+
// (e.g. `Copy` types).
35+
match Some(non_send()) {
36+
Some(_) => fut().await,
37+
None => {}
38+
}
39+
}
40+
41+
async fn non_sync_with_method_call() {
42+
// FIXME: it'd be nice for this to work.
43+
let f: &mut std::fmt::Formatter = panic!();
44+
if non_sync().fmt(f).unwrap() == () {
45+
fut().await;
46+
}
47+
}
48+
49+
fn assert_send(_: impl Send) {}
50+
51+
pub fn pass_assert() {
52+
assert_send(local_dropped_before_await());
53+
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
54+
assert_send(non_send_temporary_in_match());
55+
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
56+
assert_send(non_sync_with_method_call());
57+
//~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely
58+
//~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
2+
--> $DIR/async-fn-nonsend.rs:52:5
3+
|
4+
LL | assert_send(local_dropped_before_await());
5+
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
6+
|
7+
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
8+
= note: required because it appears within the type `impl std::fmt::Debug`
9+
= note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, ()}`
10+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]`
11+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:23:39: 28:2 {impl std::fmt::Debug, impl std::future::Future, ()}]>`
12+
= note: required because it appears within the type `impl std::future::Future`
13+
= note: required because it appears within the type `impl std::future::Future`
14+
note: required by `assert_send`
15+
--> $DIR/async-fn-nonsend.rs:49:1
16+
|
17+
LL | fn assert_send(_: impl Send) {}
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19+
20+
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
21+
--> $DIR/async-fn-nonsend.rs:54:5
22+
|
23+
LL | assert_send(non_send_temporary_in_match());
24+
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
25+
|
26+
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
27+
= note: required because it appears within the type `impl std::fmt::Debug`
28+
= note: required because it appears within the type `{fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}`
29+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]`
30+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:30:40: 39:2 {fn(impl std::fmt::Debug) -> std::option::Option<impl std::fmt::Debug> {std::option::Option::<impl std::fmt::Debug>::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, ()}]>`
31+
= note: required because it appears within the type `impl std::future::Future`
32+
= note: required because it appears within the type `impl std::future::Future`
33+
note: required by `assert_send`
34+
--> $DIR/async-fn-nonsend.rs:49:1
35+
|
36+
LL | fn assert_send(_: impl Send) {}
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
39+
error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely
40+
--> $DIR/async-fn-nonsend.rs:56:5
41+
|
42+
LL | assert_send(non_sync_with_method_call());
43+
| ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely
44+
|
45+
= help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write`
46+
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
47+
= note: required because it appears within the type `std::fmt::Formatter<'_>`
48+
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
49+
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
50+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
51+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
52+
= note: required because it appears within the type `impl std::future::Future`
53+
= note: required because it appears within the type `impl std::future::Future`
54+
note: required by `assert_send`
55+
--> $DIR/async-fn-nonsend.rs:49:1
56+
|
57+
LL | fn assert_send(_: impl Send) {}
58+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
59+
60+
error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
61+
--> $DIR/async-fn-nonsend.rs:56:5
62+
|
63+
LL | assert_send(non_sync_with_method_call());
64+
| ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
65+
|
66+
= help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
67+
= note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>`
68+
= note: required because it appears within the type `core::fmt::Void`
69+
= note: required because it appears within the type `&core::fmt::Void`
70+
= note: required because it appears within the type `std::fmt::ArgumentV1<'_>`
71+
= note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
72+
= note: required because it appears within the type `std::fmt::Formatter<'_>`
73+
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
74+
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
75+
= note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]`
76+
= note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:41:38: 47:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>`
77+
= note: required because it appears within the type `impl std::future::Future`
78+
= note: required because it appears within the type `impl std::future::Future`
79+
note: required by `assert_send`
80+
--> $DIR/async-fn-nonsend.rs:49:1
81+
|
82+
LL | fn assert_send(_: impl Send) {}
83+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
84+
85+
error: aborting due to 4 previous errors
86+
87+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// compile-pass
2+
// edition:2018
3+
// compile-flags: --crate-type lib
4+
5+
#![feature(async_await)]
6+
7+
use std::{
8+
cell::RefCell,
9+
fmt::Debug,
10+
rc::Rc,
11+
};
12+
13+
fn non_sync() -> impl Debug { RefCell::new(()) }
14+
15+
fn non_send() -> impl Debug { Rc::new(()) }
16+
17+
fn take_ref<T>(_: &T) {}
18+
19+
async fn fut() {}
20+
21+
async fn fut_arg<T>(_: T) {}
22+
23+
async fn still_send() {
24+
fut().await;
25+
println!("{:?} {:?}", non_send(), non_sync());
26+
fut().await;
27+
drop(non_send());
28+
drop(non_sync());
29+
fut().await;
30+
fut_arg(non_sync()).await;
31+
32+
// Note: all temporaries in `if let` and `match` scrutinee
33+
// are dropped at the *end* of the blocks, so using `non_send()`
34+
// in either of those positions with an await in the middle will
35+
// cause a `!Send` future. It might be nice in the future to allow
36+
// this for `Copy` types, since they can be "dropped" early without
37+
// affecting the end user.
38+
if let Some(_) = Some(non_sync()) {
39+
fut().await;
40+
}
41+
match Some(non_sync()) {
42+
Some(_) => fut().await,
43+
None => fut().await,
44+
}
45+
46+
let _ = non_send();
47+
fut().await;
48+
49+
{
50+
let _x = non_send();
51+
}
52+
fut().await;
53+
}
54+
55+
fn assert_send(_: impl Send) {}
56+
57+
pub fn pass_assert() {
58+
assert_send(still_send());
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// compile-pass
2+
// edition:2018
3+
// compile-flags: --crate-type lib
4+
5+
#![feature(async_await)]
6+
7+
use std::future::Future;
8+
9+
pub async fn simple_generic<T>() {}
10+
11+
pub trait Foo {
12+
fn foo(&self) {}
13+
}
14+
15+
struct FooType;
16+
impl Foo for FooType {}
17+
18+
pub async fn call_generic_bound<F: Foo>(f: F) {
19+
f.foo()
20+
}
21+
22+
pub async fn call_where_clause<F>(f: F)
23+
where
24+
F: Foo,
25+
{
26+
f.foo()
27+
}
28+
29+
pub async fn call_impl_trait(f: impl Foo) {
30+
f.foo()
31+
}
32+
33+
pub async fn call_with_ref(f: &impl Foo) {
34+
f.foo()
35+
}
36+
37+
pub fn async_fn_with_same_generic_params_unifies() {
38+
let mut a = call_generic_bound(FooType);
39+
a = call_generic_bound(FooType);
40+
41+
let mut b = call_where_clause(FooType);
42+
b = call_where_clause(FooType);
43+
44+
let mut c = call_impl_trait(FooType);
45+
c = call_impl_trait(FooType);
46+
47+
let f_one = FooType;
48+
let f_two = FooType;
49+
let mut d = call_with_ref(&f_one);
50+
d = call_with_ref(&f_two);
51+
}
52+
53+
pub fn simple_generic_block<T>() -> impl Future<Output = ()> {
54+
async move {}
55+
}
56+
57+
pub fn call_generic_bound_block<F: Foo>(f: F) -> impl Future<Output = ()> {
58+
async move { f.foo() }
59+
}
60+
61+
pub fn call_where_clause_block<F>(f: F) -> impl Future<Output = ()>
62+
where
63+
F: Foo,
64+
{
65+
async move { f.foo() }
66+
}
67+
68+
pub fn call_impl_trait_block(f: impl Foo) -> impl Future<Output = ()> {
69+
async move { f.foo() }
70+
}
71+
72+
pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future<Output = ()> + 'a {
73+
async move { f.foo() }
74+
}
75+
76+
pub fn async_block_with_same_generic_params_unifies() {
77+
let mut a = call_generic_bound_block(FooType);
78+
a = call_generic_bound_block(FooType);
79+
80+
let mut b = call_where_clause_block(FooType);
81+
b = call_where_clause_block(FooType);
82+
83+
let mut c = call_impl_trait_block(FooType);
84+
c = call_impl_trait_block(FooType);
85+
86+
let f_one = FooType;
87+
let f_two = FooType;
88+
let mut d = call_with_ref_block(&f_one);
89+
d = call_with_ref_block(&f_two);
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// compile-fail
2+
// edition:2018
3+
// compile-flags: --crate-type lib
4+
5+
#![feature(async_await)]
6+
7+
pub async const fn x() {}
8+
//~^ ERROR expected one of `fn` or `unsafe`, found `const`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected one of `fn` or `unsafe`, found `const`
2+
--> $DIR/no-async-const.rs:7:11
3+
|
4+
LL | pub async const fn x() {}
5+
| ^^^^^ expected one of `fn` or `unsafe` here
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// compile-fail
2+
// edition:2018
3+
// compile-flags: --crate-type lib
4+
5+
#![feature(async_await)]
6+
7+
pub const async fn x() {}
8+
//~^ ERROR expected identifier, found reserved keyword `async`
9+
//~^^ expected `:`, found keyword `fn`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: expected identifier, found reserved keyword `async`
2+
--> $DIR/no-const-async.rs:7:11
3+
|
4+
LL | pub const async fn x() {}
5+
| ^^^^^ expected identifier, found reserved keyword
6+
help: you can escape reserved keywords to use them as identifiers
7+
|
8+
LL | pub const r#async fn x() {}
9+
| ^^^^^^^
10+
11+
error: expected `:`, found keyword `fn`
12+
--> $DIR/no-const-async.rs:7:17
13+
|
14+
LL | pub const async fn x() {}
15+
| ^^ expected `:`
16+
17+
error: aborting due to 2 previous errors
18+

0 commit comments

Comments
 (0)