From 0e6f7c6c7c8f64327150c973606c1a87d587a3cc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 17:41:51 +0000 Subject: [PATCH 1/3] 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 From fde86e586dfc9826d0db81d1230aba77eb043bc6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 17:46:34 +0000 Subject: [PATCH 2/3] We do not need impl_trait_in_assoc_ty --- library/core/src/lib.rs | 1 - library/core/src/ops/async_function.rs | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1cd0240b87c..07720f23598 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -227,7 +227,6 @@ #![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 index 0e05badd06d..5e5267ed97a 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -70,10 +70,10 @@ mod impls { where >::Output: Future, { - type CallFuture<'a> = impl Future where Self: 'a; + type CallFuture<'a> = >::Output where Self: 'a; extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { - async { self.call(args).await } + self.call(args) } } @@ -82,10 +82,10 @@ mod impls { where >::Output: Future, { - type CallMutFuture<'a> = impl Future where Self: 'a; + type CallMutFuture<'a> = >::Output where Self: 'a; extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { - async { self.call_mut(args).await } + self.call_mut(args) } } @@ -94,12 +94,12 @@ mod impls { where >::Output: Future, { - type CallOnceFuture = impl Future; + type CallOnceFuture = >::Output; type Output = <>::Output as Future>::Output; extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { - async { self.call_once(args).await } + self.call_once(args) } } } From 17b433351d6c9ef4fb74dae985291b4eb073c807 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 18:03:21 +0000 Subject: [PATCH 3/3] select AsyncFn traits during overloaded call op --- compiler/rustc_hir/src/lang_items.rs | 4 ++++ compiler/rustc_hir_typeck/src/callee.rs | 11 +++++++++++ compiler/rustc_span/src/symbol.rs | 6 ++++++ library/core/src/ops/async_function.rs | 3 +++ tests/ui/async-await/async-fn/simple.rs | 2 +- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3f3b57ba94f..783a050742d 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -208,6 +208,10 @@ language_item_table! { FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 2146effd84f..e464dd45124 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -220,6 +220,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true), (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true), (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false), + (self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true), + ( + self.tcx.lang_items().async_fn_mut_trait(), + Ident::with_dummy_span(sym::async_call_mut), + true, + ), + ( + self.tcx.lang_items().async_fn_once_trait(), + Ident::with_dummy_span(sym::async_call_once), + false, + ), ] { let Some(trait_def_id) = opt_trait_def_id else { continue }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 95106cc64c1..a123a953520 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -423,8 +423,14 @@ symbols! { assume, assume_init, async_await, + async_call, + async_call_mut, + async_call_once, async_closure, + async_fn, async_fn_in_trait, + async_fn_mut, + async_fn_once, async_fn_track_caller, async_for_loop, async_iterator, diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 5e5267ed97a..965873f163e 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -8,6 +8,7 @@ use crate::marker::Tuple; #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn")] pub trait AsyncFn: AsyncFnMut { /// Future returned by [`AsyncFn::async_call`]. #[unstable(feature = "async_fn_traits", issue = "none")] @@ -27,6 +28,7 @@ pub trait AsyncFn: AsyncFnMut { #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_mut")] pub trait AsyncFnMut: AsyncFnOnce { /// Future returned by [`AsyncFnMut::async_call_mut`]. #[unstable(feature = "async_fn_traits", issue = "none")] @@ -46,6 +48,7 @@ pub trait AsyncFnMut: AsyncFnOnce { #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_once")] pub trait AsyncFnOnce { /// Future returned by [`AsyncFnOnce::async_call_once`]. #[unstable(feature = "async_fn_traits", issue = "none")] diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs index 36d1a6d7103..99a5d56a309 100644 --- a/tests/ui/async-await/async-fn/simple.rs +++ b/tests/ui/async-await/async-fn/simple.rs @@ -8,7 +8,7 @@ use std::ops::AsyncFn; async fn foo() {} async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { - f.async_call((1i32,)).await + f(1).await } fn main() {