Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc_error_codes/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ E0700: include_str!("./error_codes/E0700.md"),
E0701: include_str!("./error_codes/E0701.md"),
E0704: include_str!("./error_codes/E0704.md"),
E0705: include_str!("./error_codes/E0705.md"),
E0706: include_str!("./error_codes/E0706.md"),
E0712: include_str!("./error_codes/E0712.md"),
E0713: include_str!("./error_codes/E0713.md"),
E0714: include_str!("./error_codes/E0714.md"),
Expand Down Expand Up @@ -595,7 +596,6 @@ E0744: include_str!("./error_codes/E0744.md"),
E0696, // `continue` pointing to a labeled block
// E0702, // replaced with a generic attribute input check
E0703, // invalid ABI
E0706, // `async fn` in trait
// E0707, // multiple elided lifetimes used in arguments of `async fn`
E0708, // `async` non-`move` closures with parameters are not currently
// supported
Expand Down
78 changes: 78 additions & 0 deletions src/librustc_error_codes/error_codes/E0706.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
`async fn`s are not yet supported in Rust.

Erroneous code example:

```compile_fail,edition2018
trait T {
// Neither case is currently supported.
async fn foo() {}
async fn bar(&self) {}
}
```

`async fn`s normally return an `impl Future`, making the following two examples equivalent:

```edition2018,ignore (example-of-desugaring-equivalence)
async fn foo() -> User {
unimplemented!()
}
// The async fn above gets desugared as follows:
fn foo(&self) -> impl Future<Output = User> + '_ {
unimplemented!()
}
```

But when it comes to supporting this in traits, there are [a few implementation
issues][async-is-hard], one of which is that returning `impl Trait` in traits is not supported,
as it would require [Generic Associated Types] to be supported:

```edition2018,ignore (example-of-desugaring-equivalence)
impl MyDatabase {
async fn get_user(&self) -> User {
unimplemented!()
}
}

impl MyDatabase {
fn get_user(&self) -> impl Future<Output = User> + '_ {
unimplemented!()
}
}
```

Until these issues are resolved, you can use the [`async-trait` crate], which allows you to use
this feature by sidesteping the language feature issue by desugaring to "boxed futures"
(`Pin<Box<dyn Future + Send + 'async>>`):

```edition2018,ignore (example-of-desugaring-equivalence)
#[async_trait]
impl MyDatabase {
async fn get_user(&self) -> User {
unimplemented!()
}
}

// The annotated impl above gets desugared as follows:
impl MyDatabase {
fn get_user<'async>(
&'async self,
) -> Pin<Box<dyn std::future::Future<Output = User> + Send + 'async>>
where
Self: Sync + 'async,
{
unimplemented!()
}
}
```

Note that using these trait methods will result in a heap allocation per-function-call. This is not
a significant cost for the vast majority of applications, but should be considered when deciding
whether to use this functionality in the public API of a low-level function that is expected to be
called millions of times a second.

You might be interested in visiting the [async book] for further information.

[`async-trait` crate]: https://crates.io/crates/async-trait
[async-is-hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
[Generic Associated Types]: https://github.com/rust-lang/rust/issues/44265
[async book]: https://rust-lang.github.io/async-book/07_workarounds/06_async_in_traits.html
7 changes: 5 additions & 2 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,11 @@ impl<'a> AstValidator<'a> {

fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
if asyncness.is_async() {
struct_span_err!(self.session, span, E0706,
"trait fns cannot be declared `async`").emit()
struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`")
.note("`async` trait functions are not currently supported")
.note("consider using the `async-trait` crate: \
https://crates.io/crates/async-trait")
.emit();
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/async-await/async-trait-fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// edition:2018
trait T {
async fn foo() {} //~ ERROR trait fns cannot be declared `async`
async fn bar(&self) {} //~ ERROR trait fns cannot be declared `async`
}

fn main() {}
21 changes: 21 additions & 0 deletions src/test/ui/async-await/async-trait-fn.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0706]: trait fns cannot be declared `async`
--> $DIR/async-trait-fn.rs:3:5
|
LL | async fn foo() {}
| ^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait

error[E0706]: trait fns cannot be declared `async`
--> $DIR/async-trait-fn.rs:4:5
|
LL | async fn bar(&self) {}
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0706`.
6 changes: 5 additions & 1 deletion src/test/ui/async-await/edition-deny-async-fns-2015.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ error[E0706]: trait fns cannot be declared `async`
|
LL | async fn foo() {}
| ^^^^^^^^^^^^^^^^^
|
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait

error: aborting due to 10 previous errors

For more information about this error, try `rustc --explain E0670`.
Some errors have detailed explanations: E0670, E0706.
For more information about an error, try `rustc --explain E0670`.