From aae76304f98e4830c405b2ae16821ddcdf03c2b9 Mon Sep 17 00:00:00 2001 From: Agustin Fernandez Date: Tue, 29 Oct 2019 11:48:14 -0400 Subject: [PATCH 1/5] Add more context to `async fn` trait error. Suggest `async-trait`. --- src/librustc_passes/ast_validation.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index edb91d5bf18ed..b7ec2893bb39e 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -174,7 +174,12 @@ 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() + "trait fns cannot be declared `async`") + .note("Due to technical restrictions rust does not currently support `async` \ + trait fns.") + .note("Consider using the `async-trait` crate in the meantime until further \ + notice.") + .emit(); } } From a7678779a168d7b49cc22b073c8b68feb6d02d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 18 Nov 2019 12:08:03 -0800 Subject: [PATCH 2/5] Reword help and add test --- src/librustc_passes/ast_validation.rs | 10 ++++------ src/test/ui/async-await/async-trait-fn.rs | 7 +++++++ src/test/ui/async-await/async-trait-fn.stderr | 20 +++++++++++++++++++ .../edition-deny-async-fns-2015.stderr | 3 +++ 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/async-await/async-trait-fn.rs create mode 100644 src/test/ui/async-await/async-trait-fn.stderr diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index b7ec2893bb39e..c4032ec5dd0db 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -173,12 +173,10 @@ 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`") - .note("Due to technical restrictions rust does not currently support `async` \ - trait fns.") - .note("Consider using the `async-trait` crate in the meantime until further \ - notice.") + 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(); } } diff --git a/src/test/ui/async-await/async-trait-fn.rs b/src/test/ui/async-await/async-trait-fn.rs new file mode 100644 index 0000000000000..786100e916da0 --- /dev/null +++ b/src/test/ui/async-await/async-trait-fn.rs @@ -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() {} diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr new file mode 100644 index 0000000000000..fb6e0c57d6a0d --- /dev/null +++ b/src/test/ui/async-await/async-trait-fn.stderr @@ -0,0 +1,20 @@ +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 + diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index 7633825eb32ab..dc1c891c591eb 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -57,6 +57,9 @@ 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 From e565329144fec8ab2aa87afa170c41dc17ad018e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 18 Nov 2019 12:34:22 -0800 Subject: [PATCH 3/5] Add error code documentation --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_error_codes/error_codes/E0706.md | 78 +++++++++++++++++++ src/test/ui/async-await/async-trait-fn.stderr | 1 + .../edition-deny-async-fns-2015.stderr | 3 +- 4 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0706.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 428cecf13a3b0..325b79ba25f68 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -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"), @@ -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 diff --git a/src/librustc_error_codes/error_codes/E0706.md b/src/librustc_error_codes/error_codes/E0706.md new file mode 100644 index 0000000000000..1eb1271a9e82e --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0706.md @@ -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 + '_ { + 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 + '_ { + 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>`): + +```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 + 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 \ No newline at end of file diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr index fb6e0c57d6a0d..9acfa2cc06912 100644 --- a/src/test/ui/async-await/async-trait-fn.stderr +++ b/src/test/ui/async-await/async-trait-fn.stderr @@ -18,3 +18,4 @@ LL | async fn bar(&self) {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0706`. diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index dc1c891c591eb..bb09ee9a93296 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -63,4 +63,5 @@ LL | async fn foo() {} 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`. From 846f5e6bb97c269da4feb171b1837c43de66a38b Mon Sep 17 00:00:00 2001 From: Dylan DPC Date: Tue, 19 Nov 2019 17:09:39 +0100 Subject: [PATCH 4/5] Update E0706.md --- src/librustc_error_codes/error_codes/E0706.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0706.md b/src/librustc_error_codes/error_codes/E0706.md index 1eb1271a9e82e..909b08fb17486 100644 --- a/src/librustc_error_codes/error_codes/E0706.md +++ b/src/librustc_error_codes/error_codes/E0706.md @@ -1,4 +1,4 @@ - `async fn`s are not yet supported in Rust. + `async fn`s are not yet supported in traits in Rust. Erroneous code example: @@ -10,7 +10,7 @@ trait T { } ``` -`async fn`s normally return an `impl Future`, making the following two examples equivalent: +`async fn`s return an `impl Future`, making the following two examples equivalent: ```edition2018,ignore (example-of-desugaring-equivalence) async fn foo() -> User { @@ -23,7 +23,7 @@ fn foo(&self) -> impl Future + '_ { ``` 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, +issues][async-is-hard]. One of them is returning `impl Trait` in traits is not supported, as it would require [Generic Associated Types] to be supported: ```edition2018,ignore (example-of-desugaring-equivalence) @@ -40,8 +40,8 @@ impl MyDatabase { } ``` -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" +Until these issues are resolved, you can use the [`async-trait` crate], allowing you to use +`async fn` in traits by desugaring to "boxed futures" (`Pin>`): ```edition2018,ignore (example-of-desugaring-equivalence) @@ -75,4 +75,4 @@ 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 \ No newline at end of file +[async book]: https://rust-lang.github.io/async-book/07_workarounds/06_async_in_traits.html From a079159c64bfd7b379a9c574d21dbcedb78c5b0c Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 19 Nov 2019 11:29:20 -0800 Subject: [PATCH 5/5] Remove desugared `async-trait` example --- src/librustc_error_codes/error_codes/E0706.md | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0706.md b/src/librustc_error_codes/error_codes/E0706.md index 909b08fb17486..bee9219af7cf6 100644 --- a/src/librustc_error_codes/error_codes/E0706.md +++ b/src/librustc_error_codes/error_codes/E0706.md @@ -42,28 +42,7 @@ impl MyDatabase { Until these issues are resolved, you can use the [`async-trait` crate], allowing you to use `async fn` in traits by desugaring to "boxed futures" -(`Pin>`): - -```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 + Send + 'async>> - where - Self: Sync + 'async, - { - unimplemented!() - } -} -``` +(`Pin>`). 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