Skip to content

Commit ad91345

Browse files
committed
Split out the creation of CycleError to a new process_cycle function
1 parent 461e973 commit ad91345

1 file changed

Lines changed: 79 additions & 74 deletions

File tree

  • compiler/rustc_query_impl/src

compiler/rustc_query_impl/src/job.rs

Lines changed: 79 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,83 @@ fn connected_to_root<'tcx>(
232232
false
233233
}
234234

235+
/// Processes a found query cycle into a `CycleError`
236+
fn process_cycle<'tcx>(
237+
job_map: &QueryJobMap<'tcx>,
238+
stack: Vec<(Span, QueryJobId)>,
239+
) -> CycleError<'tcx> {
240+
// The stack is a vector of pairs of spans and queries; reverse it so that
241+
// the earlier entries require later entries
242+
let (mut spans, queries): (Vec<_>, Vec<_>) = stack.into_iter().rev().unzip();
243+
244+
// Shift the spans so that queries are matched with the span for their waitee
245+
spans.rotate_right(1);
246+
247+
// Zip them back together
248+
let mut stack: Vec<_> = iter::zip(spans, queries).collect();
249+
250+
struct EntryPoint {
251+
query_in_cycle: QueryJobId,
252+
query_waiting_on_cycle: Option<(Span, QueryJobId)>,
253+
}
254+
255+
// Find the queries in the cycle which are
256+
// connected to queries outside the cycle
257+
let entry_points = stack
258+
.iter()
259+
.filter_map(|&(_, query_in_cycle)| {
260+
let mut entrypoint = false;
261+
let mut query_waiting_on_cycle = None;
262+
263+
// Find a direct waiter who leads to the root
264+
for abstracted_waiter in abstracted_waiters_of(job_map, query_in_cycle) {
265+
let Some(parent) = abstracted_waiter.parent else {
266+
// The query in the cycle is directly connected to root.
267+
entrypoint = true;
268+
continue;
269+
};
270+
271+
// Mark all the other queries in the cycle as already visited,
272+
// so paths to the root through the cycle itself won't count.
273+
let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1));
274+
275+
if connected_to_root(job_map, parent, &mut visited) {
276+
query_waiting_on_cycle = Some((abstracted_waiter.span, parent));
277+
entrypoint = true;
278+
break;
279+
}
280+
}
281+
282+
entrypoint.then_some(EntryPoint { query_in_cycle, query_waiting_on_cycle })
283+
})
284+
.collect::<Vec<EntryPoint>>();
285+
286+
// Pick an entry point, preferring ones with waiters
287+
let entry_point = entry_points
288+
.iter()
289+
.find(|entry_point| entry_point.query_waiting_on_cycle.is_some())
290+
.unwrap_or(&entry_points[0]);
291+
292+
// Shift the stack so that our entry point is first
293+
let entry_point_pos = stack.iter().position(|(_, query)| *query == entry_point.query_in_cycle);
294+
if let Some(pos) = entry_point_pos {
295+
stack.rotate_left(pos);
296+
}
297+
298+
let usage = entry_point
299+
.query_waiting_on_cycle
300+
.map(|(span, job)| QueryStackFrame { span, tagged_key: job_map.tagged_key_of(job) });
301+
302+
// Create the cycle error
303+
CycleError {
304+
usage,
305+
cycle: stack
306+
.iter()
307+
.map(|&(span, job)| QueryStackFrame { span, tagged_key: job_map.tagged_key_of(job) })
308+
.collect(),
309+
}
310+
}
311+
235312
/// Looks for a query cycle using the last query in `jobs`.
236313
/// If a cycle is found, all queries in the cycle is removed from `jobs` and
237314
/// the function return true.
@@ -248,87 +325,15 @@ fn remove_cycle<'tcx>(
248325
if let ControlFlow::Break(resumable) =
249326
find_cycle(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited)
250327
{
251-
// The stack is a vector of pairs of spans and queries; reverse it so that
252-
// the earlier entries require later entries
253-
let (mut spans, queries): (Vec<_>, Vec<_>) = stack.into_iter().rev().unzip();
254-
255-
// Shift the spans so that queries are matched with the span for their waitee
256-
spans.rotate_right(1);
257-
258-
// Zip them back together
259-
let mut stack: Vec<_> = iter::zip(spans, queries).collect();
260-
261328
// Remove the queries in our cycle from the list of jobs to look at
262329
for r in &stack {
263330
if let Some(pos) = jobs.iter().position(|j| j == &r.1) {
264331
jobs.remove(pos);
265332
}
266333
}
267334

268-
struct EntryPoint {
269-
query_in_cycle: QueryJobId,
270-
query_waiting_on_cycle: Option<(Span, QueryJobId)>,
271-
}
272-
273-
// Find the queries in the cycle which are
274-
// connected to queries outside the cycle
275-
let entry_points = stack
276-
.iter()
277-
.filter_map(|&(_, query_in_cycle)| {
278-
let mut entrypoint = false;
279-
let mut query_waiting_on_cycle = None;
280-
281-
// Find a direct waiter who leads to the root
282-
for abstracted_waiter in abstracted_waiters_of(job_map, query_in_cycle) {
283-
let Some(parent) = abstracted_waiter.parent else {
284-
// The query in the cycle is directly connected to root.
285-
entrypoint = true;
286-
continue;
287-
};
288-
289-
// Mark all the other queries in the cycle as already visited,
290-
// so paths to the root through the cycle itself won't count.
291-
let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1));
292-
293-
if connected_to_root(job_map, parent, &mut visited) {
294-
query_waiting_on_cycle = Some((abstracted_waiter.span, parent));
295-
entrypoint = true;
296-
break;
297-
}
298-
}
299-
300-
entrypoint.then_some(EntryPoint { query_in_cycle, query_waiting_on_cycle })
301-
})
302-
.collect::<Vec<EntryPoint>>();
303-
304-
// Pick an entry point, preferring ones with waiters
305-
let entry_point = entry_points
306-
.iter()
307-
.find(|entry_point| entry_point.query_waiting_on_cycle.is_some())
308-
.unwrap_or(&entry_points[0]);
309-
310-
// Shift the stack so that our entry point is first
311-
let entry_point_pos =
312-
stack.iter().position(|(_, query)| *query == entry_point.query_in_cycle);
313-
if let Some(pos) = entry_point_pos {
314-
stack.rotate_left(pos);
315-
}
316-
317-
let usage = entry_point
318-
.query_waiting_on_cycle
319-
.map(|(span, job)| QueryStackFrame { span, tagged_key: job_map.tagged_key_of(job) });
320-
321-
// Create the cycle error
322-
let error = CycleError {
323-
usage,
324-
cycle: stack
325-
.iter()
326-
.map(|&(span, job)| QueryStackFrame {
327-
span,
328-
tagged_key: job_map.tagged_key_of(job),
329-
})
330-
.collect(),
331-
};
335+
// Create a `CycleError` for this cycle
336+
let error = process_cycle(job_map, stack);
332337

333338
// We unwrap `resumable` here since there must always be one
334339
// edge which is resumable / waited using a query latch

0 commit comments

Comments
 (0)