Add more tests for async/await
This commit is contained in:
parent
bbbb3e5974
commit
ba12e7862c
8 changed files with 338 additions and 0 deletions
59
src/test/ui/async-await/async-fn-nonsend.rs
Normal file
59
src/test/ui/async-await/async-fn-nonsend.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
// compile-fail
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fmt::Debug,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
fn non_sync() -> impl Debug { RefCell::new(()) }
|
||||
|
||||
fn non_send() -> impl Debug { Rc::new(()) }
|
||||
|
||||
fn take_ref<T>(_: &T) {}
|
||||
|
||||
async fn fut() {}
|
||||
|
||||
async fn fut_arg<T>(_: T) {}
|
||||
|
||||
async fn local_dropped_before_await() {
|
||||
// FIXME: it'd be nice for this to be allowed in a `Send` `async fn`
|
||||
let x = non_send();
|
||||
drop(x);
|
||||
fut().await;
|
||||
}
|
||||
|
||||
async fn non_send_temporary_in_match() {
|
||||
// We could theoretically make this work as well (produce a `Send` future)
|
||||
// for scrutinees / temporaries that can or will
|
||||
// be dropped prior to the match body
|
||||
// (e.g. `Copy` types).
|
||||
match Some(non_send()) {
|
||||
Some(_) => fut().await,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn non_sync_with_method_call() {
|
||||
// FIXME: it'd be nice for this to work.
|
||||
let f: &mut std::fmt::Formatter = panic!();
|
||||
if non_sync().fmt(f).unwrap() == () {
|
||||
fut().await;
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_send(_: impl Send) {}
|
||||
|
||||
pub fn pass_assert() {
|
||||
assert_send(local_dropped_before_await());
|
||||
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
assert_send(non_send_temporary_in_match());
|
||||
//~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
assert_send(non_sync_with_method_call());
|
||||
//~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely
|
||||
//~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
|
||||
}
|
87
src/test/ui/async-await/async-fn-nonsend.stderr
Normal file
87
src/test/ui/async-await/async-fn-nonsend.stderr
Normal file
|
@ -0,0 +1,87 @@
|
|||
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:52:5
|
||||
|
|
||||
LL | assert_send(local_dropped_before_await());
|
||||
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
|
||||
= note: required because it appears within the type `impl std::fmt::Debug`
|
||||
= note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, ()}`
|
||||
= 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, ()}]`
|
||||
= 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, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:54:5
|
||||
|
|
||||
LL | assert_send(non_send_temporary_in_match());
|
||||
| ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
|
||||
= note: required because it appears within the type `impl std::fmt::Debug`
|
||||
= 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, ()}`
|
||||
= 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, ()}]`
|
||||
= 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, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:56:5
|
||||
|
|
||||
LL | assert_send(non_sync_with_method_call());
|
||||
| ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely
|
||||
|
|
||||
= help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
|
||||
= note: required because it appears within the type `std::fmt::Formatter<'_>`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
|
||||
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
|
||||
= 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, ()}]`
|
||||
= 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, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
|
||||
--> $DIR/async-fn-nonsend.rs:56:5
|
||||
|
|
||||
LL | assert_send(non_sync_with_method_call());
|
||||
| ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
|
||||
|
|
||||
= help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
|
||||
= note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>`
|
||||
= note: required because it appears within the type `core::fmt::Void`
|
||||
= note: required because it appears within the type `&core::fmt::Void`
|
||||
= note: required because it appears within the type `std::fmt::ArgumentV1<'_>`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
|
||||
= note: required because it appears within the type `std::fmt::Formatter<'_>`
|
||||
= note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
|
||||
= note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}`
|
||||
= 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, ()}]`
|
||||
= 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, ()}]>`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
= note: required because it appears within the type `impl std::future::Future`
|
||||
note: required by `assert_send`
|
||||
--> $DIR/async-fn-nonsend.rs:49:1
|
||||
|
|
||||
LL | fn assert_send(_: impl Send) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
59
src/test/ui/async-await/async-fn-send-uses-nonsend.rs
Normal file
59
src/test/ui/async-await/async-fn-send-uses-nonsend.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
// compile-pass
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fmt::Debug,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
fn non_sync() -> impl Debug { RefCell::new(()) }
|
||||
|
||||
fn non_send() -> impl Debug { Rc::new(()) }
|
||||
|
||||
fn take_ref<T>(_: &T) {}
|
||||
|
||||
async fn fut() {}
|
||||
|
||||
async fn fut_arg<T>(_: T) {}
|
||||
|
||||
async fn still_send() {
|
||||
fut().await;
|
||||
println!("{:?} {:?}", non_send(), non_sync());
|
||||
fut().await;
|
||||
drop(non_send());
|
||||
drop(non_sync());
|
||||
fut().await;
|
||||
fut_arg(non_sync()).await;
|
||||
|
||||
// Note: all temporaries in `if let` and `match` scrutinee
|
||||
// are dropped at the *end* of the blocks, so using `non_send()`
|
||||
// in either of those positions with an await in the middle will
|
||||
// cause a `!Send` future. It might be nice in the future to allow
|
||||
// this for `Copy` types, since they can be "dropped" early without
|
||||
// affecting the end user.
|
||||
if let Some(_) = Some(non_sync()) {
|
||||
fut().await;
|
||||
}
|
||||
match Some(non_sync()) {
|
||||
Some(_) => fut().await,
|
||||
None => fut().await,
|
||||
}
|
||||
|
||||
let _ = non_send();
|
||||
fut().await;
|
||||
|
||||
{
|
||||
let _x = non_send();
|
||||
}
|
||||
fut().await;
|
||||
}
|
||||
|
||||
fn assert_send(_: impl Send) {}
|
||||
|
||||
pub fn pass_assert() {
|
||||
assert_send(still_send());
|
||||
}
|
90
src/test/ui/async-await/generics-and-bounds.rs
Normal file
90
src/test/ui/async-await/generics-and-bounds.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
// compile-pass
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
pub async fn simple_generic<T>() {}
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
struct FooType;
|
||||
impl Foo for FooType {}
|
||||
|
||||
pub async fn call_generic_bound<F: Foo>(f: F) {
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub async fn call_where_clause<F>(f: F)
|
||||
where
|
||||
F: Foo,
|
||||
{
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub async fn call_impl_trait(f: impl Foo) {
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub async fn call_with_ref(f: &impl Foo) {
|
||||
f.foo()
|
||||
}
|
||||
|
||||
pub fn async_fn_with_same_generic_params_unifies() {
|
||||
let mut a = call_generic_bound(FooType);
|
||||
a = call_generic_bound(FooType);
|
||||
|
||||
let mut b = call_where_clause(FooType);
|
||||
b = call_where_clause(FooType);
|
||||
|
||||
let mut c = call_impl_trait(FooType);
|
||||
c = call_impl_trait(FooType);
|
||||
|
||||
let f_one = FooType;
|
||||
let f_two = FooType;
|
||||
let mut d = call_with_ref(&f_one);
|
||||
d = call_with_ref(&f_two);
|
||||
}
|
||||
|
||||
pub fn simple_generic_block<T>() -> impl Future<Output = ()> {
|
||||
async move {}
|
||||
}
|
||||
|
||||
pub fn call_generic_bound_block<F: Foo>(f: F) -> impl Future<Output = ()> {
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn call_where_clause_block<F>(f: F) -> impl Future<Output = ()>
|
||||
where
|
||||
F: Foo,
|
||||
{
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn call_impl_trait_block(f: impl Foo) -> impl Future<Output = ()> {
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future<Output = ()> + 'a {
|
||||
async move { f.foo() }
|
||||
}
|
||||
|
||||
pub fn async_block_with_same_generic_params_unifies() {
|
||||
let mut a = call_generic_bound_block(FooType);
|
||||
a = call_generic_bound_block(FooType);
|
||||
|
||||
let mut b = call_where_clause_block(FooType);
|
||||
b = call_where_clause_block(FooType);
|
||||
|
||||
let mut c = call_impl_trait_block(FooType);
|
||||
c = call_impl_trait_block(FooType);
|
||||
|
||||
let f_one = FooType;
|
||||
let f_two = FooType;
|
||||
let mut d = call_with_ref_block(&f_one);
|
||||
d = call_with_ref_block(&f_two);
|
||||
}
|
8
src/test/ui/async-await/no-async-const.rs
Normal file
8
src/test/ui/async-await/no-async-const.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
// compile-fail
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
pub async const fn x() {}
|
||||
//~^ ERROR expected one of `fn` or `unsafe`, found `const`
|
8
src/test/ui/async-await/no-async-const.stderr
Normal file
8
src/test/ui/async-await/no-async-const.stderr
Normal file
|
@ -0,0 +1,8 @@
|
|||
error: expected one of `fn` or `unsafe`, found `const`
|
||||
--> $DIR/no-async-const.rs:7:11
|
||||
|
|
||||
LL | pub async const fn x() {}
|
||||
| ^^^^^ expected one of `fn` or `unsafe` here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
9
src/test/ui/async-await/no-const-async.rs
Normal file
9
src/test/ui/async-await/no-const-async.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// compile-fail
|
||||
// edition:2018
|
||||
// compile-flags: --crate-type lib
|
||||
|
||||
#![feature(async_await)]
|
||||
|
||||
pub const async fn x() {}
|
||||
//~^ ERROR expected identifier, found reserved keyword `async`
|
||||
//~^^ expected `:`, found keyword `fn`
|
18
src/test/ui/async-await/no-const-async.stderr
Normal file
18
src/test/ui/async-await/no-const-async.stderr
Normal file
|
@ -0,0 +1,18 @@
|
|||
error: expected identifier, found reserved keyword `async`
|
||||
--> $DIR/no-const-async.rs:7:11
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^^^^ expected identifier, found reserved keyword
|
||||
help: you can escape reserved keywords to use them as identifiers
|
||||
|
|
||||
LL | pub const r#async fn x() {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: expected `:`, found keyword `fn`
|
||||
--> $DIR/no-const-async.rs:7:17
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^ expected `:`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue