Skip to content

Commit 0a0d07a

Browse files
authored
Rollup merge of rust-lang#66526 - estebank:async-fn-trait-information, r=Centril
Add more context to `async fn` trait error Follow up to rust-lang#65937. Fix rust-lang#65899.
2 parents 2d6e376 + a079159 commit 0a0d07a

File tree

6 files changed

+96
-4
lines changed

6 files changed

+96
-4
lines changed

src/librustc_error_codes/error_codes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ E0700: include_str!("./error_codes/E0700.md"),
383383
E0701: include_str!("./error_codes/E0701.md"),
384384
E0704: include_str!("./error_codes/E0704.md"),
385385
E0705: include_str!("./error_codes/E0705.md"),
386+
E0706: include_str!("./error_codes/E0706.md"),
386387
E0712: include_str!("./error_codes/E0712.md"),
387388
E0713: include_str!("./error_codes/E0713.md"),
388389
E0714: include_str!("./error_codes/E0714.md"),
@@ -595,7 +596,6 @@ E0744: include_str!("./error_codes/E0744.md"),
595596
E0696, // `continue` pointing to a labeled block
596597
// E0702, // replaced with a generic attribute input check
597598
E0703, // invalid ABI
598-
E0706, // `async fn` in trait
599599
// E0707, // multiple elided lifetimes used in arguments of `async fn`
600600
E0708, // `async` non-`move` closures with parameters are not currently
601601
// supported
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
`async fn`s are not yet supported in traits in Rust.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,edition2018
6+
trait T {
7+
// Neither case is currently supported.
8+
async fn foo() {}
9+
async fn bar(&self) {}
10+
}
11+
```
12+
13+
`async fn`s return an `impl Future`, making the following two examples equivalent:
14+
15+
```edition2018,ignore (example-of-desugaring-equivalence)
16+
async fn foo() -> User {
17+
unimplemented!()
18+
}
19+
// The async fn above gets desugared as follows:
20+
fn foo(&self) -> impl Future<Output = User> + '_ {
21+
unimplemented!()
22+
}
23+
```
24+
25+
But when it comes to supporting this in traits, there are [a few implementation
26+
issues][async-is-hard]. One of them is returning `impl Trait` in traits is not supported,
27+
as it would require [Generic Associated Types] to be supported:
28+
29+
```edition2018,ignore (example-of-desugaring-equivalence)
30+
impl MyDatabase {
31+
async fn get_user(&self) -> User {
32+
unimplemented!()
33+
}
34+
}
35+
36+
impl MyDatabase {
37+
fn get_user(&self) -> impl Future<Output = User> + '_ {
38+
unimplemented!()
39+
}
40+
}
41+
```
42+
43+
Until these issues are resolved, you can use the [`async-trait` crate], allowing you to use
44+
`async fn` in traits by desugaring to "boxed futures"
45+
(`Pin<Box<dyn Future + Send + 'async>>`).
46+
47+
Note that using these trait methods will result in a heap allocation per-function-call. This is not
48+
a significant cost for the vast majority of applications, but should be considered when deciding
49+
whether to use this functionality in the public API of a low-level function that is expected to be
50+
called millions of times a second.
51+
52+
You might be interested in visiting the [async book] for further information.
53+
54+
[`async-trait` crate]: https://crates.io/crates/async-trait
55+
[async-is-hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
56+
[Generic Associated Types]: https://github.com/rust-lang/rust/issues/44265
57+
[async book]: https://rust-lang.github.io/async-book/07_workarounds/06_async_in_traits.html

src/librustc_passes/ast_validation.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,11 @@ impl<'a> AstValidator<'a> {
173173

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// edition:2018
2+
trait T {
3+
async fn foo() {} //~ ERROR trait fns cannot be declared `async`
4+
async fn bar(&self) {} //~ ERROR trait fns cannot be declared `async`
5+
}
6+
7+
fn main() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0706]: trait fns cannot be declared `async`
2+
--> $DIR/async-trait-fn.rs:3:5
3+
|
4+
LL | async fn foo() {}
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `async` trait functions are not currently supported
8+
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
9+
10+
error[E0706]: trait fns cannot be declared `async`
11+
--> $DIR/async-trait-fn.rs:4:5
12+
|
13+
LL | async fn bar(&self) {}
14+
| ^^^^^^^^^^^^^^^^^^^^^^
15+
|
16+
= note: `async` trait functions are not currently supported
17+
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0706`.

src/test/ui/async-await/edition-deny-async-fns-2015.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ error[E0706]: trait fns cannot be declared `async`
5757
|
5858
LL | async fn foo() {}
5959
| ^^^^^^^^^^^^^^^^^
60+
|
61+
= note: `async` trait functions are not currently supported
62+
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
6063

6164
error: aborting due to 10 previous errors
6265

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

0 commit comments

Comments
 (0)