--- /dev/null
+// 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
+}
--- /dev/null
+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`.
--- /dev/null
+// 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());
+}
--- /dev/null
+// 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);
+}