]> git.lizzy.rs Git - rust.git/commitdiff
Add more tests for async/await
authorTaylor Cramer <cramertj@google.com>
Tue, 25 Jun 2019 00:48:21 +0000 (17:48 -0700)
committerTaylor Cramer <cramertj@google.com>
Tue, 25 Jun 2019 18:46:33 +0000 (11:46 -0700)
src/test/ui/async-await/async-fn-nonsend.rs [new file with mode: 0644]
src/test/ui/async-await/async-fn-nonsend.stderr [new file with mode: 0644]
src/test/ui/async-await/async-fn-send-uses-nonsend.rs [new file with mode: 0644]
src/test/ui/async-await/generics-and-bounds.rs [new file with mode: 0644]
src/test/ui/async-await/no-async-const.rs [new file with mode: 0644]
src/test/ui/async-await/no-async-const.stderr [new file with mode: 0644]
src/test/ui/async-await/no-const-async.rs [new file with mode: 0644]
src/test/ui/async-await/no-const-async.stderr [new file with mode: 0644]

diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
new file mode 100644 (file)
index 0000000..612c1e2
--- /dev/null
@@ -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
+}
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
new file mode 100644 (file)
index 0000000..7776a36
--- /dev/null
@@ -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`.
diff --git a/src/test/ui/async-await/async-fn-send-uses-nonsend.rs b/src/test/ui/async-await/async-fn-send-uses-nonsend.rs
new file mode 100644 (file)
index 0000000..f07fc2f
--- /dev/null
@@ -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());
+}
diff --git a/src/test/ui/async-await/generics-and-bounds.rs b/src/test/ui/async-await/generics-and-bounds.rs
new file mode 100644 (file)
index 0000000..913f143
--- /dev/null
@@ -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);
+}
diff --git a/src/test/ui/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs
new file mode 100644 (file)
index 0000000..1db314a
--- /dev/null
@@ -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`
diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr
new file mode 100644 (file)
index 0000000..cdb1c6e
--- /dev/null
@@ -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
+
diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs
new file mode 100644 (file)
index 0000000..9f09d21
--- /dev/null
@@ -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`
diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr
new file mode 100644 (file)
index 0000000..693fbf1
--- /dev/null
@@ -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
+