Skip to content

Commit 9a75603

Browse files
Last nits
1 parent 841184b commit 9a75603

File tree

2 files changed

+41
-37
lines changed

2 files changed

+41
-37
lines changed

compiler/rustc_error_codes/src/error_codes/E0733.md

+10-28
Original file line numberDiff line numberDiff line change
@@ -10,48 +10,30 @@ async fn foo(n: usize) {
1010
}
1111
```
1212

13-
To perform async recursion, the `async fn` needs to be desugared such that the
14-
`Future` is explicit in the return type:
15-
16-
```edition2018,compile_fail,E0733
17-
use std::future::Future;
18-
fn foo_desugared(n: usize) -> impl Future<Output = ()> {
19-
async move {
20-
if n > 0 {
21-
foo_desugared(n - 1).await;
22-
}
23-
}
24-
}
25-
```
26-
27-
Finally, the future is wrapped in a pinned box:
13+
The recursive invocation can be boxed:
2814

2915
```edition2018
30-
use std::future::Future;
31-
use std::pin::Pin;
32-
fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
33-
Box::pin(async move {
34-
if n > 0 {
35-
foo_recursive(n - 1).await;
36-
}
37-
})
16+
async fn foo(n: usize) {
17+
if n > 0 {
18+
Box::pin(foo(n - 1)).await;
19+
}
3820
}
3921
```
4022

4123
The `Box<...>` ensures that the result is of known size, and the pin is
4224
required to keep it in the same place in memory.
4325

44-
Alternatively, the recursive call-site can be boxed:
26+
Alternatively, the body can be boxed:
4527

4628
```edition2018
4729
use std::future::Future;
4830
use std::pin::Pin;
49-
fn foo_recursive(n: usize) -> impl Future<Output = ()> {
50-
async move {
31+
fn foo(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
32+
Box::pin(async move {
5133
if n > 0 {
52-
Box::pin(foo_recursive(n - 1)).await;
34+
foo(n - 1).await;
5335
}
54-
}
36+
})
5537
}
5638
```
5739

compiler/rustc_middle/src/values.rs

+31-9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_span::{ErrorGuaranteed, Span};
1313

1414
use std::collections::VecDeque;
1515
use std::fmt::Write;
16+
use std::ops::ControlFlow;
1617

1718
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
1819
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
@@ -130,16 +131,34 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>
130131
}
131132
}
132133

134+
// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`.
135+
fn search_for_cycle_permutation<Q, T>(
136+
cycle: &[Q],
137+
try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow<T, ()>,
138+
otherwise: impl FnOnce() -> T,
139+
) -> T {
140+
let mut cycle: VecDeque<_> = cycle.iter().collect();
141+
for _ in 0..cycle.len() {
142+
match try_cycle(&mut cycle) {
143+
ControlFlow::Continue(_) => {
144+
cycle.rotate_left(1);
145+
}
146+
ControlFlow::Break(t) => return t,
147+
}
148+
}
149+
150+
otherwise()
151+
}
152+
133153
impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
134154
fn from_cycle_error(
135155
tcx: TyCtxt<'tcx>,
136156
cycle_error: &CycleError,
137157
_guar: ErrorGuaranteed,
138158
) -> Self {
139-
let mut cycle: VecDeque<_> = cycle_error.cycle.iter().collect();
140-
141-
let guar = 'search: {
142-
for _ in 0..cycle.len() {
159+
let diag = search_for_cycle_permutation(
160+
&cycle_error.cycle,
161+
|cycle| {
143162
if cycle[0].query.dep_kind == dep_kinds::layout_of
144163
&& let Some(def_id) = cycle[0].query.ty_def_id
145164
&& let Some(def_id) = def_id.as_local()
@@ -204,13 +223,16 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
204223
) {
205224
diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future");
206225
}
207-
break 'search diag.emit();
226+
227+
ControlFlow::Break(diag)
208228
} else {
209-
cycle.rotate_left(1);
229+
ControlFlow::Continue(())
210230
}
211-
}
212-
report_cycle(tcx.sess, cycle_error).emit()
213-
};
231+
},
232+
|| report_cycle(tcx.sess, cycle_error),
233+
);
234+
235+
let guar = diag.emit();
214236

215237
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
216238
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,

0 commit comments

Comments
 (0)