11use std:: io:: Write ;
22use std:: iter;
3+ use std:: ops:: ControlFlow ;
34use std:: sync:: Arc ;
45
56use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
@@ -117,41 +118,33 @@ type Waiter = (QueryJobId, usize);
117118
118119/// Visits all the non-resumable and resumable waiters of a query.
119120/// Only waiters in a query are visited.
120- /// `visit` is called for every waiter and is passed a query waiting on `query_ref`
121- /// and a span indicating the reason the query waited on `query_ref`.
122- /// If `visit` returns Some, this function returns.
121+ /// `visit` is called for every waiter and is passed a query waiting on `query`
122+ /// and a span indicating the reason the query waited on `query`.
123+ /// If `visit` returns `Break`, this function also returns `Break`,
124+ /// and if all `visit` calls returns `Continue` it also returns `Continue`.
123125/// For visits of non-resumable waiters it returns the return value of `visit`.
124- /// For visits of resumable waiters it returns Some(Some(Waiter)) which has the
125- /// required information to resume the waiter.
126- /// If all `visit` calls returns None, this function also returns None.
127- fn visit_waiters < ' tcx , F > (
126+ /// For visits of resumable waiters it returns information required to resume that waiter.
127+ fn visit_waiters < ' tcx > (
128128 job_map : & QueryJobMap < ' tcx > ,
129129 query : QueryJobId ,
130- mut visit : F ,
131- ) -> Option < Option < Waiter > >
132- where
133- F : FnMut ( Span , QueryJobId ) -> Option < Option < Waiter > > ,
134- {
130+ mut visit : impl FnMut ( Span , QueryJobId ) -> ControlFlow < Option < Waiter > > ,
131+ ) -> ControlFlow < Option < Waiter > > {
135132 // Visit the parent query which is a non-resumable waiter since it's on the same stack
136- if let Some ( parent) = job_map. parent_of ( query)
137- && let Some ( cycle) = visit ( job_map. span_of ( query) , parent)
138- {
139- return Some ( cycle) ;
133+ if let Some ( parent) = job_map. parent_of ( query) {
134+ visit ( job_map. span_of ( query) , parent) ?;
140135 }
141136
142137 // Visit the explicit waiters which use condvars and are resumable
143138 if let Some ( latch) = job_map. latch_of ( query) {
144139 for ( i, waiter) in latch. info . lock ( ) . waiters . iter ( ) . enumerate ( ) {
145140 if let Some ( waiter_query) = waiter. query {
146- if visit ( waiter. span , waiter_query) . is_some ( ) {
147- // Return a value which indicates that this waiter can be resumed
148- return Some ( Some ( ( query, i) ) ) ;
149- }
141+ // Return a value which indicates that this waiter can be resumed
142+ visit ( waiter. span , waiter_query) . map_break ( |_| Some ( ( query, i) ) ) ?;
150143 }
151144 }
152145 }
153146
154- None
147+ ControlFlow :: Continue ( ( ) )
155148}
156149
157150/// Look for query cycles by doing a depth first search starting at `query`.
@@ -164,7 +157,7 @@ fn cycle_check<'tcx>(
164157 span : Span ,
165158 stack : & mut Vec < ( Span , QueryJobId ) > ,
166159 visited : & mut FxHashSet < QueryJobId > ,
167- ) -> Option < Option < Waiter > > {
160+ ) -> ControlFlow < Option < Waiter > > {
168161 if !visited. insert ( query) {
169162 return if let Some ( p) = stack. iter ( ) . position ( |q| q. 1 == query) {
170163 // We detected a query cycle, fix up the initial span and return Some
@@ -173,9 +166,9 @@ fn cycle_check<'tcx>(
173166 stack. drain ( 0 ..p) ;
174167 // Replace the span for the first query with the cycle cause
175168 stack[ 0 ] . 0 = span;
176- Some ( None )
169+ ControlFlow :: Break ( None )
177170 } else {
178- None
171+ ControlFlow :: Continue ( ( ) )
179172 } ;
180173 }
181174
@@ -188,7 +181,7 @@ fn cycle_check<'tcx>(
188181 } ) ;
189182
190183 // Remove the entry in our stack if we didn't find a cycle
191- if r. is_none ( ) {
184+ if r. is_continue ( ) {
192185 stack. pop ( ) ;
193186 }
194187
@@ -202,21 +195,18 @@ fn connected_to_root<'tcx>(
202195 job_map : & QueryJobMap < ' tcx > ,
203196 query : QueryJobId ,
204197 visited : & mut FxHashSet < QueryJobId > ,
205- ) -> bool {
198+ ) -> ControlFlow < Option < Waiter > > {
206199 // We already visited this or we're deliberately ignoring it
207200 if !visited. insert ( query) {
208- return false ;
201+ return ControlFlow :: Continue ( ( ) ) ;
209202 }
210203
211204 // This query is connected to the root (it has no query parent), return true
212205 if job_map. parent_of ( query) . is_none ( ) {
213- return true ;
206+ return ControlFlow :: Break ( None ) ;
214207 }
215208
216- visit_waiters ( job_map, query, |_, successor| {
217- connected_to_root ( job_map, successor, visited) . then_some ( None )
218- } )
219- . is_some ( )
209+ visit_waiters ( job_map, query, |_, successor| connected_to_root ( job_map, successor, visited) )
220210}
221211
222212// Deterministically pick an query from a list
@@ -253,7 +243,7 @@ fn remove_cycle<'tcx>(
253243 let mut visited = FxHashSet :: default ( ) ;
254244 let mut stack = Vec :: new ( ) ;
255245 // Look for a cycle starting with the last query in `jobs`
256- if let Some ( waiter) =
246+ if let ControlFlow :: Break ( waiter) =
257247 cycle_check ( job_map, jobs. pop ( ) . unwrap ( ) , DUMMY_SP , & mut stack, & mut visited)
258248 {
259249 // The stack is a vector of pairs of spans and queries; reverse it so that
@@ -284,15 +274,15 @@ fn remove_cycle<'tcx>(
284274 } else {
285275 let mut waiters = Vec :: new ( ) ;
286276 // Find all the direct waiters who lead to the root
287- visit_waiters ( job_map, query, |span, waiter| {
277+ let _ = visit_waiters ( job_map, query, |span, waiter| {
288278 // Mark all the other queries in the cycle as already visited
289279 let mut visited = FxHashSet :: from_iter ( stack. iter ( ) . map ( |q| q. 1 ) ) ;
290280
291- if connected_to_root ( job_map, waiter, & mut visited) {
281+ if connected_to_root ( job_map, waiter, & mut visited) . is_break ( ) {
292282 waiters. push ( ( span, waiter) ) ;
293283 }
294284
295- None
285+ ControlFlow :: Continue ( ( ) )
296286 } ) ;
297287 if waiters. is_empty ( ) {
298288 None
0 commit comments