@@ -6,7 +6,7 @@ use rustc_hir as hir;
66use rustc_hir:: def:: { DefKind , Res } ;
77use rustc_middle:: ty:: Representability ;
88use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
9- use rustc_query_system:: query:: CycleError ;
9+ use rustc_query_system:: query:: { report_cycle , CycleError } ;
1010use rustc_query_system:: Value ;
1111use rustc_span:: def_id:: LocalDefId ;
1212use rustc_span:: { ErrorGuaranteed , Span } ;
@@ -97,7 +97,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
9797 }
9898 for info in & cycle_error. cycle {
9999 if info. query . dep_kind == dep_kinds:: representability_adt_ty
100- && let Some ( def_id) = info. query . ty_adt_id
100+ && let Some ( def_id) = info. query . ty_def_id
101101 && let Some ( def_id) = def_id. as_local ( )
102102 && !item_and_field_ids. iter ( ) . any ( |& ( id, _) | id == def_id)
103103 {
@@ -131,14 +131,43 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>
131131
132132impl < ' tcx , T > Value < TyCtxt < ' tcx > > for Result < T , & ' _ ty:: layout:: LayoutError < ' _ > > {
133133 fn from_cycle_error (
134- _tcx : TyCtxt < ' tcx > ,
135- _cycle_error : & CycleError ,
136- guar : ErrorGuaranteed ,
134+ tcx : TyCtxt < ' tcx > ,
135+ cycle_error : & CycleError ,
136+ _guar : ErrorGuaranteed ,
137137 ) -> 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+ && matches ! ( tcx. def_kind( def_id) , DefKind :: Coroutine )
142+ {
143+ let hir = tcx. hir ( ) ;
144+ let coroutine_kind = hir
145+ . body ( hir. body_owned_by ( def_id) )
146+ . coroutine_kind
147+ . expect ( "expected coroutine to have a coroutine_kind" ) ;
148+ // FIXME: `def_span` for an fn-like coroutine will point to the fn's body
149+ // due to interactions between the desugaring into a closure expr and the
150+ // def_span code. I'm not motivated to fix it, because I tried and it was
151+ // not working, so just hack around it by grabbing the parent fn's span.
152+ let span = if coroutine_kind. is_fn_like ( ) {
153+ tcx. def_span ( tcx. local_parent ( def_id) )
154+ } else {
155+ tcx. def_span ( def_id)
156+ } ;
157+ struct_span_err ! ( tcx. sess, span, E0733 , "recursion in an `async fn` requires boxing" )
158+ . span_label ( span, "recursive `async fn`" )
159+ . note ( "a recursive `async fn` must be rewritten to return a boxed `dyn Future`" )
160+ . note (
161+ "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion" ,
162+ )
163+ . emit ( )
164+ } else {
165+ report_cycle ( tcx. sess , cycle_error) . emit ( )
166+ } ;
167+
138168 // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
139169 // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
140170 // tcx.arena.alloc is pretty much equal to leaking).
141- // FIXME: `Cycle` should carry the ErrorGuaranteed
142171 Err ( Box :: leak ( Box :: new ( ty:: layout:: LayoutError :: Cycle ( guar) ) ) )
143172 }
144173}
0 commit comments