1
1
use std:: marker:: PhantomData ;
2
- use std:: mem;
3
2
use std:: ops:: ControlFlow ;
4
3
5
4
use rustc_data_structures:: thinvec:: ExtractIf ;
@@ -75,6 +74,13 @@ impl<'tcx> ObligationStorage<'tcx> {
75
74
self . pending . push ( ( obligation, stalled_on) ) ;
76
75
}
77
76
77
+ fn register_overflowed (
78
+ & mut self ,
79
+ overflowed : impl IntoIterator < Item = PredicateObligation < ' tcx > > ,
80
+ ) {
81
+ self . overflowed . extend ( overflowed) ;
82
+ }
83
+
78
84
fn has_pending_obligations ( & self ) -> bool {
79
85
!self . pending . is_empty ( ) || !self . overflowed . is_empty ( )
80
86
}
@@ -88,35 +94,14 @@ impl<'tcx> ObligationStorage<'tcx> {
88
94
89
95
fn drain_pending (
90
96
& mut self ,
91
- cond : impl Fn ( & PredicateObligation < ' tcx > ) -> bool ,
92
- ) -> PendingObligations < ' tcx > {
93
- let ( unstalled, pending) =
94
- mem:: take ( & mut self . pending ) . into_iter ( ) . partition ( |( o, _) | cond ( o) ) ;
95
- self . pending = pending;
96
- unstalled
97
+ cond : impl Fn ( & PredicateObligation < ' tcx > , Option < & GoalStalledOn < TyCtxt < ' tcx > > > ) -> bool ,
98
+ ) -> impl Iterator < Item = ( PredicateObligation < ' tcx > , Option < GoalStalledOn < TyCtxt < ' tcx > > > ) >
99
+ {
100
+ ExtractIf :: new ( & mut self . pending , move |( o, stalled) | cond ( o, stalled. as_ref ( ) ) )
97
101
}
98
102
99
- fn on_fulfillment_overflow ( & mut self , infcx : & InferCtxt < ' tcx > ) {
100
- infcx. probe ( |_| {
101
- // IMPORTANT: we must not use solve any inference variables in the obligations
102
- // as this is all happening inside of a probe. We use a probe to make sure
103
- // we get all obligations involved in the overflow. We pretty much check: if
104
- // we were to do another step of `select_where_possible`, which goals would
105
- // change.
106
- // FIXME: <https://github.com/Gankra/thin-vec/pull/66> is merged, this can be removed.
107
- self . overflowed . extend (
108
- ExtractIf :: new ( & mut self . pending , |( o, stalled_on) | {
109
- let goal = o. as_goal ( ) ;
110
- let result = <& SolverDelegate < ' tcx > >:: from ( infcx) . evaluate_root_goal (
111
- goal,
112
- o. cause . span ,
113
- stalled_on. take ( ) ,
114
- ) ;
115
- matches ! ( result, Ok ( GoalEvaluation { has_changed: HasChanged :: Yes , .. } ) )
116
- } )
117
- . map ( |( o, _) | o) ,
118
- ) ;
119
- } )
103
+ fn num_pending ( & self ) -> usize {
104
+ self . pending . len ( )
120
105
}
121
106
}
122
107
@@ -133,21 +118,6 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> {
133
118
_errors : PhantomData ,
134
119
}
135
120
}
136
-
137
- fn inspect_evaluated_obligation (
138
- & self ,
139
- infcx : & InferCtxt < ' tcx > ,
140
- obligation : & PredicateObligation < ' tcx > ,
141
- result : & Result < GoalEvaluation < TyCtxt < ' tcx > > , NoSolution > ,
142
- ) {
143
- if let Some ( inspector) = infcx. obligation_inspector . get ( ) {
144
- let result = match result {
145
- Ok ( GoalEvaluation { certainty, .. } ) => Ok ( * certainty) ,
146
- Err ( NoSolution ) => Err ( NoSolution ) ,
147
- } ;
148
- ( inspector) ( infcx, & obligation, result) ;
149
- }
150
- }
151
121
}
152
122
153
123
impl < ' tcx , E > TraitEngine < ' tcx , E > for FulfillmentCtxt < ' tcx , E >
@@ -180,19 +150,27 @@ where
180
150
}
181
151
182
152
fn select_where_possible ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < E > {
153
+ if self . obligations . num_pending ( ) == 0 {
154
+ return vec ! [ ] ;
155
+ }
156
+
183
157
assert_eq ! ( self . usable_in_snapshot, infcx. num_open_snapshots( ) ) ;
158
+ let delegate = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
184
159
let mut errors = Vec :: new ( ) ;
185
160
loop {
186
161
let mut any_changed = false ;
187
- for ( mut obligation, stalled_on) in self . obligations . drain_pending ( |_| true ) {
162
+ let mut overflowed = vec ! [ ] ;
163
+ let mut pending = vec ! [ ] ;
164
+
165
+ for ( mut obligation, stalled_on) in self . obligations . drain_pending ( |_, stalled_on| {
166
+ stalled_on. is_none_or ( |s| !delegate. is_still_stalled ( s) )
167
+ } ) {
188
168
if !infcx. tcx . recursion_limit ( ) . value_within_limit ( obligation. recursion_depth ) {
189
- self . obligations . on_fulfillment_overflow ( infcx) ;
190
- // Only return true errors that we have accumulated while processing.
191
- return errors;
169
+ overflowed. push ( obligation) ;
170
+ continue ;
192
171
}
193
172
194
173
let goal = obligation. as_goal ( ) ;
195
- let delegate = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
196
174
if let Some ( certainty) =
197
175
delegate. compute_goal_fast_path ( goal, obligation. cause . span )
198
176
{
@@ -204,15 +182,21 @@ where
204
182
//
205
183
// Only goals proven via the trait solver should be region dependent.
206
184
Certainty :: Yes => { }
207
- Certainty :: Maybe ( _) => {
208
- self . obligations . register ( obligation, None ) ;
209
- }
185
+ Certainty :: Maybe ( _) => pending. push ( ( obligation, None ) ) ,
210
186
}
211
187
continue ;
212
188
}
213
189
214
190
let result = delegate. evaluate_root_goal ( goal, obligation. cause . span , stalled_on) ;
215
- self . inspect_evaluated_obligation ( infcx, & obligation, & result) ;
191
+
192
+ if let Some ( inspector) = infcx. obligation_inspector . get ( ) {
193
+ let result = match result {
194
+ Ok ( GoalEvaluation { certainty, .. } ) => Ok ( certainty) ,
195
+ Err ( NoSolution ) => Err ( NoSolution ) ,
196
+ } ;
197
+ ( inspector) ( infcx, & obligation, result) ;
198
+ }
199
+
216
200
let GoalEvaluation { goal, certainty, has_changed, stalled_on } = match result {
217
201
Ok ( result) => result,
218
202
Err ( NoSolution ) => {
@@ -256,10 +240,19 @@ where
256
240
infcx. push_hir_typeck_potentially_region_dependent_goal ( obligation) ;
257
241
}
258
242
}
259
- Certainty :: Maybe ( _) => self . obligations . register ( obligation, stalled_on) ,
243
+ Certainty :: Maybe ( _) => pending . push ( ( obligation, stalled_on) ) ,
260
244
}
261
245
}
262
246
247
+ if !overflowed. is_empty ( ) {
248
+ self . obligations . register_overflowed ( overflowed) ;
249
+ return errors;
250
+ }
251
+
252
+ for ( obligation, stalled_on) in pending {
253
+ self . obligations . register ( obligation, stalled_on) ;
254
+ }
255
+
263
256
if !any_changed {
264
257
break ;
265
258
}
@@ -295,7 +288,7 @@ where
295
288
}
296
289
297
290
self . obligations
298
- . drain_pending ( |obl| {
291
+ . drain_pending ( |obl, _ | {
299
292
infcx. probe ( |_| {
300
293
infcx
301
294
. visit_proof_tree (
0 commit comments