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,10 @@ 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- }
98-
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- } )
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 ( ) ) )
120101 }
121102}
122103
@@ -133,21 +114,6 @@ impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> {
133114 _errors : PhantomData ,
134115 }
135116 }
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- }
151117}
152118
153119impl < ' tcx , E > TraitEngine < ' tcx , E > for FulfillmentCtxt < ' tcx , E >
@@ -181,32 +147,42 @@ where
181147
182148 fn select_where_possible ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < E > {
183149 assert_eq ! ( self . usable_in_snapshot, infcx. num_open_snapshots( ) ) ;
150+ let delegate = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
184151 let mut errors = Vec :: new ( ) ;
185152 loop {
186153 let mut any_changed = false ;
187- for ( mut obligation, stalled_on) in self . obligations . drain_pending ( |_| true ) {
154+ let mut overflowed = vec ! [ ] ;
155+ let mut pending = vec ! [ ] ;
156+
157+ for ( mut obligation, stalled_on) in self . obligations . drain_pending ( |_, stalled_on| {
158+ stalled_on. is_none_or ( |s| !delegate. is_still_stalled ( s) )
159+ } ) {
188160 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;
161+ overflowed. push ( obligation) ;
162+ continue ;
192163 }
193164
194165 let goal = obligation. as_goal ( ) ;
195- let delegate = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
196166 if let Some ( certainty) =
197167 delegate. compute_goal_fast_path ( goal, obligation. cause . span )
198168 {
199169 match certainty {
200170 Certainty :: Yes => { }
201- Certainty :: Maybe ( _) => {
202- self . obligations . register ( obligation, None ) ;
203- }
171+ Certainty :: Maybe ( _) => pending. push ( ( obligation, None ) ) ,
204172 }
205173 continue ;
206174 }
207175
208176 let result = delegate. evaluate_root_goal ( goal, obligation. cause . span , stalled_on) ;
209- self . inspect_evaluated_obligation ( infcx, & obligation, & result) ;
177+
178+ if let Some ( inspector) = infcx. obligation_inspector . get ( ) {
179+ let result = match result {
180+ Ok ( GoalEvaluation { certainty, .. } ) => Ok ( certainty) ,
181+ Err ( NoSolution ) => Err ( NoSolution ) ,
182+ } ;
183+ ( inspector) ( infcx, & obligation, result) ;
184+ }
185+
210186 let GoalEvaluation { certainty, has_changed, stalled_on } = match result {
211187 Ok ( result) => result,
212188 Err ( NoSolution ) => {
@@ -231,10 +207,19 @@ where
231207
232208 match certainty {
233209 Certainty :: Yes => { }
234- Certainty :: Maybe ( _) => self . obligations . register ( obligation, stalled_on) ,
210+ Certainty :: Maybe ( _) => pending . push ( ( obligation, stalled_on) ) ,
235211 }
236212 }
237213
214+ if !overflowed. is_empty ( ) {
215+ self . obligations . register_overflowed ( overflowed) ;
216+ return errors;
217+ }
218+
219+ for ( obligation, stalled_on) in pending {
220+ self . obligations . register ( obligation, stalled_on) ;
221+ }
222+
238223 if !any_changed {
239224 break ;
240225 }
@@ -270,7 +255,7 @@ where
270255 }
271256
272257 self . obligations
273- . drain_pending ( |obl| {
258+ . drain_pending ( |obl, _ | {
274259 infcx. probe ( |_| {
275260 infcx
276261 . visit_proof_tree (
0 commit comments