@@ -11,6 +11,7 @@ use rustc_query_system::Value;
11
11
use rustc_span:: def_id:: LocalDefId ;
12
12
use rustc_span:: { ErrorGuaranteed , Span } ;
13
13
14
+ use std:: collections:: VecDeque ;
14
15
use std:: fmt:: Write ;
15
16
16
17
impl < ' tcx > Value < TyCtxt < ' tcx > > for Ty < ' _ > {
@@ -135,73 +136,79 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
135
136
cycle_error : & CycleError ,
136
137
_guar : ErrorGuaranteed ,
137
138
) -> Self {
138
- let guar = if cycle_error. cycle [ 0 ] . query . dep_kind == dep_kinds:: layout_of
139
- && let Some ( def_id) = cycle_error. cycle [ 0 ] . query . ty_def_id
140
- && let Some ( def_id) = def_id. as_local ( )
141
- && let def_kind = tcx. def_kind ( def_id)
142
- && matches ! ( def_kind, DefKind :: Closure )
143
- && let Some ( coroutine_kind) = tcx. coroutine_kind ( def_id)
144
- {
145
- // FIXME: `def_span` for an fn-like coroutine will point to the fn's body
146
- // due to interactions between the desugaring into a closure expr and the
147
- // def_span code. I'm not motivated to fix it, because I tried and it was
148
- // not working, so just hack around it by grabbing the parent fn's span.
149
- let span = if coroutine_kind. is_fn_like ( ) {
150
- tcx. def_span ( tcx. local_parent ( def_id) )
151
- } else {
152
- tcx. def_span ( def_id)
153
- } ;
154
- let mut diag = struct_span_err ! (
155
- tcx. sess. dcx( ) ,
156
- span,
157
- E0733 ,
158
- "recursion in {} {} requires boxing" ,
159
- tcx. def_kind_descr_article( def_kind, def_id. to_def_id( ) ) ,
160
- tcx. def_kind_descr( def_kind, def_id. to_def_id( ) ) ,
161
- ) ;
162
- for ( i, frame) in cycle_error. cycle . iter ( ) . enumerate ( ) {
163
- if frame. query . dep_kind != dep_kinds:: layout_of {
164
- continue ;
165
- }
166
- let Some ( frame_def_id) = frame. query . ty_def_id else {
167
- continue ;
168
- } ;
169
- let Some ( frame_coroutine_kind) = tcx. coroutine_kind ( frame_def_id) else {
170
- continue ;
171
- } ;
172
- let frame_span = frame
173
- . query
174
- . default_span ( cycle_error. cycle [ ( i + 1 ) % cycle_error. cycle . len ( ) ] . span ) ;
175
- if frame_span. is_dummy ( ) {
176
- continue ;
177
- }
178
- if i == 0 {
179
- diag. span_label ( frame_span, "recursive call here" ) ;
180
- } else {
181
- let coroutine_span = if frame_coroutine_kind. is_fn_like ( ) {
182
- tcx. def_span ( tcx. parent ( frame_def_id) )
139
+ let mut cycle: VecDeque < _ > = cycle_error. cycle . iter ( ) . collect ( ) ;
140
+
141
+ let guar = ' search: {
142
+ for _ in 0 ..cycle. len ( ) {
143
+ if cycle[ 0 ] . query . dep_kind == dep_kinds:: layout_of
144
+ && let Some ( def_id) = cycle[ 0 ] . query . ty_def_id
145
+ && let Some ( def_id) = def_id. as_local ( )
146
+ && let def_kind = tcx. def_kind ( def_id)
147
+ && matches ! ( def_kind, DefKind :: Closure )
148
+ && let Some ( coroutine_kind) = tcx. coroutine_kind ( def_id)
149
+ {
150
+ // FIXME: `def_span` for an fn-like coroutine will point to the fn's body
151
+ // due to interactions between the desugaring into a closure expr and the
152
+ // def_span code. I'm not motivated to fix it, because I tried and it was
153
+ // not working, so just hack around it by grabbing the parent fn's span.
154
+ let span = if coroutine_kind. is_fn_like ( ) {
155
+ tcx. def_span ( tcx. local_parent ( def_id) )
183
156
} else {
184
- tcx. def_span ( frame_def_id )
157
+ tcx. def_span ( def_id )
185
158
} ;
186
- let mut multispan = MultiSpan :: from_span ( coroutine_span) ;
187
- multispan. push_span_label ( frame_span, "...leading to this recursive call" ) ;
188
- diag. span_note (
189
- multispan,
190
- format ! ( "which leads to this {}" , tcx. def_descr( frame_def_id) ) ,
159
+ let mut diag = struct_span_err ! (
160
+ tcx. sess. dcx( ) ,
161
+ span,
162
+ E0733 ,
163
+ "recursion in {} {} requires boxing" ,
164
+ tcx. def_kind_descr_article( def_kind, def_id. to_def_id( ) ) ,
165
+ tcx. def_kind_descr( def_kind, def_id. to_def_id( ) ) ,
191
166
) ;
167
+ for ( i, frame) in cycle. iter ( ) . enumerate ( ) {
168
+ if frame. query . dep_kind != dep_kinds:: layout_of {
169
+ continue ;
170
+ }
171
+ let Some ( frame_def_id) = frame. query . ty_def_id else {
172
+ continue ;
173
+ } ;
174
+ let Some ( frame_coroutine_kind) = tcx. coroutine_kind ( frame_def_id) else {
175
+ continue ;
176
+ } ;
177
+ let frame_span =
178
+ frame. query . default_span ( cycle[ ( i + 1 ) % cycle. len ( ) ] . span ) ;
179
+ if frame_span. is_dummy ( ) {
180
+ continue ;
181
+ }
182
+ if i == 0 {
183
+ diag. span_label ( frame_span, "recursive call here" ) ;
184
+ } else {
185
+ let coroutine_span: Span = if frame_coroutine_kind. is_fn_like ( ) {
186
+ tcx. def_span ( tcx. parent ( frame_def_id) )
187
+ } else {
188
+ tcx. def_span ( frame_def_id)
189
+ } ;
190
+ let mut multispan = MultiSpan :: from_span ( coroutine_span) ;
191
+ multispan
192
+ . push_span_label ( frame_span, "...leading to this recursive call" ) ;
193
+ diag. span_note (
194
+ multispan,
195
+ format ! ( "which leads to this {}" , tcx. def_descr( frame_def_id) ) ,
196
+ ) ;
197
+ }
198
+ }
199
+ // FIXME: We could report a structured suggestion if we had
200
+ // enough info here... Maybe we can use a hacky HIR walker.
201
+ if matches ! (
202
+ coroutine_kind,
203
+ hir:: CoroutineKind :: Desugared ( hir:: CoroutineDesugaring :: Async , _)
204
+ ) {
205
+ diag. note ( "a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future" ) ;
206
+ }
207
+ break ' search diag. emit ( ) ;
208
+ } else {
209
+ cycle. rotate_left ( 1 ) ;
192
210
}
193
211
}
194
- if matches ! (
195
- coroutine_kind,
196
- hir:: CoroutineKind :: Desugared ( hir:: CoroutineDesugaring :: Async , _)
197
- ) {
198
- diag. note ( "a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future" ) ;
199
- diag. note (
200
- "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion" ,
201
- ) ;
202
- }
203
- diag. emit ( )
204
- } else {
205
212
report_cycle ( tcx. sess , cycle_error) . emit ( )
206
213
} ;
207
214
0 commit comments