Better recursive async fn error message.
Co-Authored-By: Mazdak Farrokhzad <twingoow@gmail.com>
This commit is contained in:
parent
a7f28678bb
commit
4b1d404d83
3 changed files with 78 additions and 16 deletions
|
@ -1325,8 +1325,23 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
|
|||
check_packed(tcx, span, def_id);
|
||||
}
|
||||
|
||||
fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, span: Span) {
|
||||
fn check_opaque<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
span: Span,
|
||||
origin: &hir::ExistTyOrigin
|
||||
) {
|
||||
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
|
||||
if let hir::ExistTyOrigin::AsyncFn = origin {
|
||||
struct_span_err!(
|
||||
tcx.sess, span, E0733,
|
||||
"recursion in an `async fn` requires boxing",
|
||||
)
|
||||
.span_label(span, "an `async fn` cannot invoke itself directly")
|
||||
.note("a recursive `async fn` must be rewritten to return a boxed future.")
|
||||
.emit();
|
||||
} else {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess, span, E0720,
|
||||
"opaque type expands to a recursive type",
|
||||
|
@ -1340,6 +1355,7 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>,
|
|||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) {
|
||||
debug!(
|
||||
|
@ -1387,11 +1403,11 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) {
|
|||
hir::ItemKind::Union(..) => {
|
||||
check_union(tcx, it.hir_id, it.span);
|
||||
}
|
||||
hir::ItemKind::Existential(..) => {
|
||||
hir::ItemKind::Existential(hir::ExistTy{origin, ..}) => {
|
||||
let def_id = tcx.hir().local_def_id(it.hir_id);
|
||||
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||
check_opaque(tcx, def_id, substs, it.span);
|
||||
check_opaque(tcx, def_id, substs, it.span, &origin);
|
||||
}
|
||||
hir::ItemKind::Ty(..) => {
|
||||
let def_id = tcx.hir().local_def_id(it.hir_id);
|
||||
|
|
|
@ -4765,7 +4765,53 @@ assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
|
|||
```
|
||||
"##,
|
||||
|
||||
E0733: r##"
|
||||
Recursion in an `async fn` requires boxing. For example, this will not compile:
|
||||
|
||||
```edition2018,compile_fail,E0733
|
||||
#![feature(async_await)]
|
||||
async fn foo(n: usize) {
|
||||
if n > 0 {
|
||||
foo(n - 1).await;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To achieve async recursion, the `async fn` needs to be desugared
|
||||
such that the `Future` is explicit in the return type:
|
||||
|
||||
```edition2018,compile_fail,E0720
|
||||
# #![feature(async_await)]
|
||||
use std::future::Future;
|
||||
fn foo_desugered(n: usize) -> impl Future<Output = ()> {
|
||||
async move {
|
||||
if n > 0 {
|
||||
foo_desugered(n - 1).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, the future is wrapped in a pinned box:
|
||||
|
||||
```edition2018
|
||||
# #![feature(async_await)]
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(async move {
|
||||
if n > 0 {
|
||||
foo_recursive(n - 1).await;
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
The `Box<...>` ensures that the result is of known size,
|
||||
and the pin is required to keep it in the same place in memory.
|
||||
"##,
|
||||
|
||||
} // (end of detailed error messages)
|
||||
|
||||
register_diagnostics! {
|
||||
// E0035, merged into E0087/E0089
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error[E0720]: opaque type expands to a recursive type
|
||||
error[E0733]: recursion in an `async fn` requires boxing
|
||||
--> $DIR/recursive-async-impl-trait-type.rs:7:40
|
||||
|
|
||||
LL | async fn recursive_async_function() -> () {
|
||||
| ^^ expands to a recursive type
|
||||
| ^^ an `async fn` cannot invoke itself directly
|
||||
|
|
||||
= note: expanded type is `std::future::GenFuture<[static generator@$DIR/recursive-async-impl-trait-type.rs:7:43: 9:2 {impl std::future::Future, ()}]>`
|
||||
= note: a recursive `async fn` must be rewritten to return a boxed future.
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0720`.
|
||||
For more information about this error, try `rustc --explain E0733`.
|
||||
|
|
Loading…
Reference in a new issue