about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-11-20 12:58:30 +0100
committerGitHub <noreply@github.com>2019-11-20 12:58:30 +0100
commit0a0d07a1fc712241ea9215a621d3f4fa9162ee20 (patch)
tree712d01bc3c26819c7c0b924d7bf4f7a66cd5475f /src
parent2d6e3764b4e2fecf1b1a8c3a174e93906d555703 (diff)
parenta079159c64bfd7b379a9c574d21dbcedb78c5b0c (diff)
downloadrust-0a0d07a1fc712241ea9215a621d3f4fa9162ee20.tar.gz
rust-0a0d07a1fc712241ea9215a621d3f4fa9162ee20.zip
Rollup merge of #66526 - estebank:async-fn-trait-information, r=Centril
Add more context to `async fn` trait error

Follow up to #65937. Fix #65899.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_error_codes/error_codes.rs2
-rw-r--r--src/librustc_error_codes/error_codes/E0706.md57
-rw-r--r--src/librustc_passes/ast_validation.rs7
-rw-r--r--src/test/ui/async-await/async-trait-fn.rs7
-rw-r--r--src/test/ui/async-await/async-trait-fn.stderr21
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.stderr6
6 files changed, 96 insertions, 4 deletions
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index e575528a463..b11fe33880c 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -383,6 +383,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 00000000000..bee9219af7c
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0706.md
@@ -0,0 +1,57 @@
+ `async fn`s are not yet supported in traits 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 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 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)
+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], allowing you to use
+`async fn` in traits by desugaring to "boxed futures"
+(`Pin<Box<dyn Future + Send + 'async>>`).
+
+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
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index edb91d5bf18..c4032ec5dd0 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -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();
         }
     }
 
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 00000000000..786100e916d
--- /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 00000000000..9acfa2cc069
--- /dev/null
+++ b/src/test/ui/async-await/async-trait-fn.stderr
@@ -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`.
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 7633825eb32..bb09ee9a932 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,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`.