1
1
use std:: marker:: PhantomData ;
2
2
use std:: mem;
3
+ use std:: ops:: ControlFlow ;
3
4
4
5
use rustc_data_structures:: thinvec:: ExtractIf ;
6
+ use rustc_hir:: def_id:: LocalDefId ;
5
7
use rustc_infer:: infer:: InferCtxt ;
6
8
use rustc_infer:: traits:: query:: NoSolution ;
7
9
use rustc_infer:: traits:: {
8
10
FromSolverError , PredicateObligation , PredicateObligations , TraitEngine ,
9
11
} ;
12
+ use rustc_middle:: ty:: {
13
+ self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitor , TypingMode ,
14
+ } ;
10
15
use rustc_next_trait_solver:: solve:: { GenerateProofTree , HasChanged , SolverDelegateEvalExt as _} ;
16
+ use rustc_span:: Span ;
11
17
use tracing:: instrument;
12
18
13
19
use self :: derive_errors:: * ;
14
20
use super :: Certainty ;
15
21
use super :: delegate:: SolverDelegate ;
22
+ use super :: inspect:: { self , ProofTreeInferCtxtExt } ;
16
23
use crate :: traits:: { FulfillmentError , ScrubbedTraitError } ;
17
24
18
25
mod derive_errors;
@@ -39,7 +46,7 @@ pub struct FulfillmentCtxt<'tcx, E: 'tcx> {
39
46
_errors : PhantomData < E > ,
40
47
}
41
48
42
- #[ derive( Default ) ]
49
+ #[ derive( Default , Debug ) ]
43
50
struct ObligationStorage < ' tcx > {
44
51
/// Obligations which resulted in an overflow in fulfillment itself.
45
52
///
@@ -55,20 +62,23 @@ impl<'tcx> ObligationStorage<'tcx> {
55
62
self . pending . push ( obligation) ;
56
63
}
57
64
65
+ fn has_pending_obligations ( & self ) -> bool {
66
+ !self . pending . is_empty ( ) || !self . overflowed . is_empty ( )
67
+ }
68
+
58
69
fn clone_pending ( & self ) -> PredicateObligations < ' tcx > {
59
70
let mut obligations = self . pending . clone ( ) ;
60
71
obligations. extend ( self . overflowed . iter ( ) . cloned ( ) ) ;
61
72
obligations
62
73
}
63
74
64
- fn take_pending ( & mut self ) -> PredicateObligations < ' tcx > {
65
- let mut obligations = mem:: take ( & mut self . pending ) ;
66
- obligations. append ( & mut self . overflowed ) ;
67
- obligations
68
- }
69
-
70
- fn unstalled_for_select ( & mut self ) -> impl Iterator < Item = PredicateObligation < ' tcx > > + ' tcx {
71
- mem:: take ( & mut self . pending ) . into_iter ( )
75
+ fn drain_pending (
76
+ & mut self ,
77
+ cond : impl Fn ( & PredicateObligation < ' tcx > ) -> bool ,
78
+ ) -> PredicateObligations < ' tcx > {
79
+ let ( unstalled, pending) = mem:: take ( & mut self . pending ) . into_iter ( ) . partition ( cond) ;
80
+ self . pending = pending;
81
+ unstalled
72
82
}
73
83
74
84
fn on_fulfillment_overflow ( & mut self , infcx : & InferCtxt < ' tcx > ) {
@@ -160,7 +170,7 @@ where
160
170
}
161
171
162
172
let mut has_changed = false ;
163
- for obligation in self . obligations . unstalled_for_select ( ) {
173
+ for obligation in self . obligations . drain_pending ( |_| true ) {
164
174
let goal = obligation. as_goal ( ) ;
165
175
let result = <& SolverDelegate < ' tcx > >:: from ( infcx)
166
176
. evaluate_root_goal ( goal, GenerateProofTree :: No , obligation. cause . span )
@@ -196,15 +206,79 @@ where
196
206
}
197
207
198
208
fn has_pending_obligations ( & self ) -> bool {
199
- ! self . obligations . pending . is_empty ( ) || ! self . obligations . overflowed . is_empty ( )
209
+ self . obligations . has_pending_obligations ( )
200
210
}
201
211
202
212
fn pending_obligations ( & self ) -> PredicateObligations < ' tcx > {
203
213
self . obligations . clone_pending ( )
204
214
}
205
215
206
- fn drain_unstalled_obligations ( & mut self , _: & InferCtxt < ' tcx > ) -> PredicateObligations < ' tcx > {
207
- self . obligations . take_pending ( )
216
+ fn drain_stalled_obligations_for_coroutines (
217
+ & mut self ,
218
+ infcx : & InferCtxt < ' tcx > ,
219
+ ) -> PredicateObligations < ' tcx > {
220
+ self . obligations . drain_pending ( |obl| {
221
+ let stalled_generators = match infcx. typing_mode ( ) {
222
+ TypingMode :: Analysis { defining_opaque_types : _, stalled_generators } => {
223
+ stalled_generators
224
+ }
225
+ TypingMode :: Coherence
226
+ | TypingMode :: Borrowck { defining_opaque_types : _ }
227
+ | TypingMode :: PostBorrowckAnalysis { defined_opaque_types : _ }
228
+ | TypingMode :: PostAnalysis => return false ,
229
+ } ;
230
+
231
+ if stalled_generators. is_empty ( ) {
232
+ return false ;
233
+ }
234
+
235
+ infcx. probe ( |_| {
236
+ infcx
237
+ . visit_proof_tree (
238
+ obl. as_goal ( ) ,
239
+ & mut StalledOnCoroutines { stalled_generators, span : obl. cause . span } ,
240
+ )
241
+ . is_break ( )
242
+ } )
243
+ } )
244
+ }
245
+ }
246
+
247
+ struct StalledOnCoroutines < ' tcx > {
248
+ stalled_generators : & ' tcx ty:: List < LocalDefId > ,
249
+ span : Span ,
250
+ // TODO: Cache
251
+ }
252
+
253
+ impl < ' tcx > inspect:: ProofTreeVisitor < ' tcx > for StalledOnCoroutines < ' tcx > {
254
+ type Result = ControlFlow < ( ) > ;
255
+
256
+ fn span ( & self ) -> rustc_span:: Span {
257
+ self . span
258
+ }
259
+
260
+ fn visit_goal ( & mut self , inspect_goal : & super :: inspect:: InspectGoal < ' _ , ' tcx > ) -> Self :: Result {
261
+ inspect_goal. goal ( ) . predicate . visit_with ( self ) ?;
262
+
263
+ if let Some ( candidate) = inspect_goal. unique_applicable_candidate ( ) {
264
+ candidate. visit_nested_no_probe ( self )
265
+ } else {
266
+ ControlFlow :: Continue ( ( ) )
267
+ }
268
+ }
269
+ }
270
+
271
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for StalledOnCoroutines < ' tcx > {
272
+ type Result = ControlFlow < ( ) > ;
273
+
274
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
275
+ if let ty:: CoroutineWitness ( def_id, _) = * ty. kind ( )
276
+ && def_id. as_local ( ) . is_some_and ( |def_id| self . stalled_generators . contains ( & def_id) )
277
+ {
278
+ return ControlFlow :: Break ( ( ) ) ;
279
+ }
280
+
281
+ ty. super_visit_with ( self )
208
282
}
209
283
}
210
284
0 commit comments