From 0e6f7c6c7c8f64327150c973606c1a87d587a3cc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 17:41:51 +0000 Subject: [PATCH] Add AsyncFn family of traits --- library/core/src/lib.rs | 1 + library/core/src/ops/async_function.rs | 105 ++++++++++++++++++++++ library/core/src/ops/mod.rs | 4 + tests/ui/async-await/async-fn/simple.rs | 16 ++++ tests/ui/did_you_mean/bad-assoc-ty.stderr | 9 +- 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 library/core/src/ops/async_function.rs create mode 100644 tests/ui/async-await/async-fn/simple.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 07720f23598..1cd0240b87c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -227,6 +227,7 @@ #![feature(fundamental)] #![feature(generic_arg_infer)] #![feature(if_let_guard)] +#![feature(impl_trait_in_assoc_type)] #![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs new file mode 100644 index 00000000000..0e05badd06d --- /dev/null +++ b/library/core/src/ops/async_function.rs @@ -0,0 +1,105 @@ +use crate::future::Future; +use crate::marker::Tuple; + +/// An async-aware version of the [`Fn`](crate::ops::Fn) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFn: AsyncFnMut { + /// Future returned by [`AsyncFn::async_call`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFn`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>; +} + +/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFnMut: AsyncFnOnce { + /// Future returned by [`AsyncFnMut::async_call_mut`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallMutFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>; +} + +/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFnOnce { + /// Future returned by [`AsyncFnOnce::async_call_once`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallOnceFuture: Future; + + /// Output type of the called closure's future. + #[unstable(feature = "async_fn_traits", issue = "none")] + type Output; + + /// Call the [`AsyncFnOnce`], returning a future which may move out of the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture; +} + +mod impls { + use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + use crate::future::Future; + use crate::marker::Tuple; + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFn for F + where + >::Output: Future, + { + type CallFuture<'a> = impl Future where Self: 'a; + + extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { + async { self.call(args).await } + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnMut for F + where + >::Output: Future, + { + type CallMutFuture<'a> = impl Future where Self: 'a; + + extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { + async { self.call_mut(args).await } + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnOnce for F + where + >::Output: Future, + { + type CallOnceFuture = impl Future; + + type Output = <>::Output as Future>::Output; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + async { self.call_once(args).await } + } + } +} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 35654d0b853..4289a86f89b 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -139,6 +139,7 @@ #![stable(feature = "rust1", since = "1.0.0")] mod arith; +mod async_function; mod bit; mod control_flow; mod coroutine; @@ -173,6 +174,9 @@ pub use self::drop::Drop; #[stable(feature = "rust1", since = "1.0.0")] pub use self::function::{Fn, FnMut, FnOnce}; +#[unstable(feature = "async_fn_traits", issue = "none")] +pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::index::{Index, IndexMut}; diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs new file mode 100644 index 00000000000..36d1a6d7103 --- /dev/null +++ b/tests/ui/async-await/async-fn/simple.rs @@ -0,0 +1,16 @@ +// edition: 2021 +// check-pass + +#![feature(async_fn_traits)] + +use std::ops::AsyncFn; + +async fn foo() {} + +async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { + f.async_call((1i32,)).await +} + +fn main() { + let fut = call_asyncly(|x| async move { x + 1 }); +} diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index 5c0c7a0b94f..356ddf74bb6 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -191,7 +191,14 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as AsyncFnOnce>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:39:19