11use std:: marker:: PhantomData ;
2- use std:: mem;
32use std:: ops:: ControlFlow ;
43
54use rustc_data_structures:: thinvec:: ExtractIf ;
@@ -75,6 +74,13 @@ impl<'tcx> ObligationStorage<'tcx> {
7574 self . pending . push ( ( obligation, stalled_on) ) ;
7675 }
7776
77+ fn register_overflowed (
78+ & mut self ,
79+ overflowed : impl IntoIterator < Item = PredicateObligation < ' tcx > > ,
80+ ) {
81+ self . overflowed . extend ( overflowed) ;
82+ }
83+
7884 fn has_pending_obligations ( & self ) -> bool {
7985 !self . pending . is_empty ( ) || !self . overflowed . is_empty ( )
8086 }
@@ -88,35 +94,14 @@ impl<'tcx> ObligationStorage<'tcx> {
8894
8995 fn drain_pending (
9096 & 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 ( ) ) )
97101 }
98102
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 ( )
120105 }
121106}
122107
@@ -133,21 +118,6 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> {
133118 _errors : PhantomData ,
134119 }
135120 }
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- }
151121}
152122
153123impl < ' tcx , E > TraitEngine < ' tcx , E > for FulfillmentCtxt < ' tcx , E >
@@ -180,19 +150,27 @@ where
180150 }
181151
182152 fn select_where_possible ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < E > {
153+ if self . obligations . num_pending ( ) == 0 {
154+ return vec ! [ ] ;
155+ }
156+
183157 assert_eq ! ( self . usable_in_snapshot, infcx. num_open_snapshots( ) ) ;
158+ let delegate = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
184159 let mut errors = Vec :: new ( ) ;
185160 loop {
186161 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+ } ) {
188168 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 ;
192171 }
193172
194173 let goal = obligation. as_goal ( ) ;
195- let delegate = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
196174 if let Some ( certainty) =
197175 delegate. compute_goal_fast_path ( goal, obligation. cause . span )
198176 {
@@ -204,15 +182,21 @@ where
204182 //
205183 // Only goals proven via the trait solver should be region dependent.
206184 Certainty :: Yes => { }
207- Certainty :: Maybe ( _) => {
208- self . obligations . register ( obligation, None ) ;
209- }
185+ Certainty :: Maybe ( _) => pending. push ( ( obligation, None ) ) ,
210186 }
211187 continue ;
212188 }
213189
214190 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+
216200 let GoalEvaluation { goal, certainty, has_changed, stalled_on } = match result {
217201 Ok ( result) => result,
218202 Err ( NoSolution ) => {
@@ -256,10 +240,19 @@ where
256240 infcx. push_hir_typeck_potentially_region_dependent_goal ( obligation) ;
257241 }
258242 }
259- Certainty :: Maybe ( _) => self . obligations . register ( obligation, stalled_on) ,
243+ Certainty :: Maybe ( _) => pending . push ( ( obligation, stalled_on) ) ,
260244 }
261245 }
262246
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+
263256 if !any_changed {
264257 break ;
265258 }
@@ -295,7 +288,7 @@ where
295288 }
296289
297290 self . obligations
298- . drain_pending ( |obl| {
291+ . drain_pending ( |obl, _ | {
299292 infcx. probe ( |_| {
300293 infcx
301294 . visit_proof_tree (
0 commit comments