mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
8c6cf3c934
Add `AsyncFn` family of traits I'm proposing to add a new family of `async`hronous `Fn`-like traits to the standard library for experimentation purposes. ## Why do we need new traits? On the user side, it is useful to be able to express `AsyncFn` trait bounds natively via the parenthesized sugar syntax, i.e. `x: impl AsyncFn(&str) -> String` when experimenting with async-closure code. This also does not preclude `AsyncFn` becoming something else like a trait alias if a more fundamental desugaring (which can take many[^1] different[^2] forms) comes around. I think we should be able to play around with `AsyncFn` well before that, though. I'm also not proposing stabilization of these trait names any time soon (we may even want to instead express them via new syntax, like `async Fn() -> ..`), but I also don't think we need to introduce an obtuse bikeshedding name, since `AsyncFn` just makes sense. ## The lending problem: why not add a more fundamental primitive of `LendingFn`/`LendingFnMut`? Firstly, for `async` closures to be as flexible as possible, they must be allowed to return futures which borrow from the async closure's captures. This can be done by introducing `LendingFn`/`LendingFnMut` traits, or (equivalently) by adding a new generic associated type to `FnMut` which allows the return type to capture lifetimes from the `&mut self` argument of the trait. This was proposed in one of [Niko's blog posts](https://smallcultfollowing.com/babysteps/blog/2023/05/09/giving-lending-and-async-closures/). Upon further experimentation, for the purposes of closure type- and borrow-checking, I've come to the conclusion that it's significantly harder to teach the compiler how to handle *general* lending closures which may borrow from their captures. This is, because unlike `Fn`/`FnMut`, the `LendingFn`/`LendingFnMut` traits don't form a simple "inheritance" hierarchy whose top trait is `FnOnce`. ```mermaid flowchart LR Fn FnMut FnOnce LendingFn LendingFnMut Fn -- isa --> FnMut FnMut -- isa --> FnOnce LendingFn -- isa --> LendingFnMut Fn -- isa --> LendingFn FnMut -- isa --> LendingFnMut ``` For example: ``` fn main() { let s = String::from("hello, world"); let f = move || &s; let x = f(); // This borrows `f` for some lifetime `'1` and returns `&'1 String`. ``` That trait hierarchy means that in general for "lending" closures, like `f` above, there's not really a meaningful return type for `<typeof(f) as FnOnce>::Output` -- it can't return `&'static str`, for example. ### Special-casing this problem: By splitting out these traits manually, and making sure that each trait has its own associated future type, we side-step the issue of having to answer the questions of a general `LendingFn`/`LendingFnMut` implementation, since the compiler knows how to generate built-in implementations for first-class constructs like async closures, including the required future types for the (by-move) `AsyncFnOnce` and (by-ref) `AsyncFnMut`/`AsyncFn` trait implementations. [^1]: For example, with trait transformers, we may eventually be able to write: `trait AsyncFn = async Fn;` [^2]: For example, via the introduction of a more fundamental "`LendingFn`" trait, plus a [special desugaring with augmented trait aliases](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Lending.20closures.20and.20Fn*.28.29.20-.3E.20impl.20Trait/near/408471480). |
||
---|---|---|
.. | ||
auxiliary | ||
bad-assoc-expr.rs | ||
bad-assoc-expr.stderr | ||
bad-assoc-pat.rs | ||
bad-assoc-pat.stderr | ||
bad-assoc-ty.rs | ||
bad-assoc-ty.stderr | ||
brackets-to-braces-single-element.rs | ||
brackets-to-braces-single-element.stderr | ||
compatible-variants-in-pat.rs | ||
compatible-variants-in-pat.stderr | ||
compatible-variants.rs | ||
compatible-variants.stderr | ||
dont-suggest-doc-hidden-fields.rs | ||
dont-suggest-doc-hidden-fields.stderr | ||
dont-suggest-hygienic-fields.rs | ||
dont-suggest-hygienic-fields.stderr | ||
E0178.rs | ||
E0178.stderr | ||
issue-21659-show-relevant-trait-impls-1.rs | ||
issue-21659-show-relevant-trait-impls-1.stderr | ||
issue-21659-show-relevant-trait-impls-2.rs | ||
issue-21659-show-relevant-trait-impls-2.stderr | ||
issue-31424.rs | ||
issue-31424.stderr | ||
issue-34126.rs | ||
issue-34126.stderr | ||
issue-34337.rs | ||
issue-34337.stderr | ||
issue-35937.rs | ||
issue-35937.stderr | ||
issue-36798_unknown_field.rs | ||
issue-36798_unknown_field.stderr | ||
issue-36798.rs | ||
issue-36798.stderr | ||
issue-37139.rs | ||
issue-37139.stderr | ||
issue-38054-do-not-show-unresolved-names.rs | ||
issue-38054-do-not-show-unresolved-names.stderr | ||
issue-38147-1.rs | ||
issue-38147-1.stderr | ||
issue-38147-2.rs | ||
issue-38147-2.stderr | ||
issue-38147-3.rs | ||
issue-38147-3.stderr | ||
issue-38147-4.rs | ||
issue-38147-4.stderr | ||
issue-39544.rs | ||
issue-39544.stderr | ||
issue-39802-show-5-trait-impls.rs | ||
issue-39802-show-5-trait-impls.stderr | ||
issue-40006.rs | ||
issue-40006.stderr | ||
issue-40396.rs | ||
issue-40396.stderr | ||
issue-40823.rs | ||
issue-40823.stderr | ||
issue-41679-tilde-bitwise-negation-attempt.fixed | ||
issue-41679-tilde-bitwise-negation-attempt.rs | ||
issue-41679-tilde-bitwise-negation-attempt.stderr | ||
issue-42599_available_fields_note.rs | ||
issue-42599_available_fields_note.stderr | ||
issue-42764.rs | ||
issue-42764.stderr | ||
issue-43871-enum-instead-of-variant.rs | ||
issue-43871-enum-instead-of-variant.stderr | ||
issue-46718-struct-pattern-dotdotdot.rs | ||
issue-46718-struct-pattern-dotdotdot.stderr | ||
issue-46836-identifier-not-instead-of-negation.rs | ||
issue-46836-identifier-not-instead-of-negation.stderr | ||
issue-48492-tuple-destructure-missing-parens.rs | ||
issue-48492-tuple-destructure-missing-parens.stderr | ||
issue-49746-unicode-confusable-in-float-literal-expt.rs | ||
issue-49746-unicode-confusable-in-float-literal-expt.stderr | ||
issue-53280-expected-float-found-integer-literal.rs | ||
issue-53280-expected-float-found-integer-literal.stderr | ||
issue-54109-and_instead_of_ampersands.rs | ||
issue-54109-and_instead_of_ampersands.stderr | ||
issue-54109-without-witness.fixed | ||
issue-54109-without-witness.rs | ||
issue-54109-without-witness.stderr | ||
issue-56028-there-is-an-enum-variant.rs | ||
issue-56028-there-is-an-enum-variant.stderr | ||
issue-87830-try-brackets-for-arrays.rs | ||
issue-87830-try-brackets-for-arrays.stderr | ||
issue-103909.rs | ||
issue-103909.stderr | ||
issue-105225-named-args.rs | ||
issue-105225-named-args.stderr | ||
issue-105225.fixed | ||
issue-105225.rs | ||
issue-105225.stderr | ||
issue-114112.rs | ||
issue-114112.stderr | ||
println-typo.rs | ||
println-typo.stderr | ||
pub-macro-rules.rs | ||
pub-macro-rules.stderr | ||
recursion_limit_deref.rs | ||
recursion_limit_deref.stderr | ||
recursion_limit_macro.rs | ||
recursion_limit_macro.stderr | ||
recursion_limit.rs | ||
recursion_limit.stderr | ||
replace-impl-infer-ty-from-trait.fixed | ||
replace-impl-infer-ty-from-trait.rs | ||
replace-impl-infer-ty-from-trait.stderr | ||
trait-object-reference-without-parens-suggestion.rs | ||
trait-object-reference-without-parens-suggestion.stderr | ||
use_instead_of_import.fixed | ||
use_instead_of_import.rs | ||
use_instead_of_import.stderr |