Skip to content

Commit 2ee28ca

Browse files
committed
rustc_query_impl: Use ControlFlow in visit_waiters instead of nested options
1 parent d7daac0 commit 2ee28ca

1 file changed

Lines changed: 26 additions & 36 deletions

File tree

  • compiler/rustc_query_impl/src

compiler/rustc_query_impl/src/job.rs

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::io::Write;
22
use std::iter;
3+
use std::ops::ControlFlow;
34
use std::sync::Arc;
45

56
use 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

Comments
 (0)