Rollup merge of #62871 - gilescope:async-recursion-error, r=Centril
Explicit error message for async recursion. Attempt at clearer error message when async recusion is attempted. In response to #62539 (and #53690).
This commit is contained in:
commit
2ac9b89d7b
3 changed files with 78 additions and 16 deletions
|
@ -1325,19 +1325,35 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
|
||||||
check_packed(tcx, span, def_id);
|
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 Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
|
||||||
let mut err = struct_span_err!(
|
if let hir::ExistTyOrigin::AsyncFn = origin {
|
||||||
tcx.sess, span, E0720,
|
struct_span_err!(
|
||||||
"opaque type expands to a recursive type",
|
tcx.sess, span, E0733,
|
||||||
);
|
"recursion in an `async fn` requires boxing",
|
||||||
err.span_label(span, "expands to a recursive type");
|
)
|
||||||
if let ty::Opaque(..) = partially_expanded_type.sty {
|
.span_label(span, "an `async fn` cannot invoke itself directly")
|
||||||
err.note("type resolves to itself");
|
.note("a recursive `async fn` must be rewritten to return a boxed future.")
|
||||||
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
err.note(&format!("expanded type is `{}`", partially_expanded_type));
|
let mut err = struct_span_err!(
|
||||||
|
tcx.sess, span, E0720,
|
||||||
|
"opaque type expands to a recursive type",
|
||||||
|
);
|
||||||
|
err.span_label(span, "expands to a recursive type");
|
||||||
|
if let ty::Opaque(..) = partially_expanded_type.sty {
|
||||||
|
err.note("type resolves to itself");
|
||||||
|
} else {
|
||||||
|
err.note(&format!("expanded type is `{}`", partially_expanded_type));
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
}
|
}
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1387,11 +1403,11 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item) {
|
||||||
hir::ItemKind::Union(..) => {
|
hir::ItemKind::Union(..) => {
|
||||||
check_union(tcx, it.hir_id, it.span);
|
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 def_id = tcx.hir().local_def_id(it.hir_id);
|
||||||
|
|
||||||
let substs = InternalSubsts::identity_for_item(tcx, def_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(..) => {
|
hir::ItemKind::Ty(..) => {
|
||||||
let def_id = tcx.hir().local_def_id(it.hir_id);
|
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! {
|
register_diagnostics! {
|
||||||
// E0035, merged into E0087/E0089
|
// 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
|
--> $DIR/recursive-async-impl-trait-type.rs:7:40
|
||||||
|
|
|
|
||||||
LL | async fn recursive_async_function() -> () {
|
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
|
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