Improve query cycle error message
This commit is contained in:
parent
21f6e55ce9
commit
5841c687a3
2 changed files with 31 additions and 17 deletions
|
@ -31,6 +31,7 @@ pub(super) enum QueryResult<'tcx, T> {
|
||||||
/// A span and a query key
|
/// A span and a query key
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct QueryInfo<'tcx> {
|
pub struct QueryInfo<'tcx> {
|
||||||
|
/// The span for a reason this query was required
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub query: Query<'tcx>,
|
pub query: Query<'tcx>,
|
||||||
}
|
}
|
||||||
|
@ -73,13 +74,22 @@ impl<'tcx> QueryJob<'tcx> {
|
||||||
cycle.insert(0, job.info.clone());
|
cycle.insert(0, job.info.clone());
|
||||||
|
|
||||||
if &*job as *const _ == self as *const _ {
|
if &*job as *const _ == self as *const _ {
|
||||||
break;
|
// This is the end of the cycle
|
||||||
|
// The span entry we included was for the usage
|
||||||
|
// of the cycle itself, and not part of the cycle
|
||||||
|
// Replace it with the span which caused the cycle to form
|
||||||
|
cycle[0].span = span;
|
||||||
|
// Find out why the cycle itself was used
|
||||||
|
let usage = job.parent.as_ref().map(|parent| {
|
||||||
|
(job.info.span, parent.info.query.clone())
|
||||||
|
});
|
||||||
|
return Err(CycleError { usage, cycle });
|
||||||
}
|
}
|
||||||
|
|
||||||
current_job = job.parent.clone();
|
current_job = job.parent.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(CycleError { span, cycle })
|
panic!("did not find a cycle")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signals to waiters that the query is complete.
|
/// Signals to waiters that the query is complete.
|
||||||
|
|
|
@ -64,8 +64,8 @@ pub(super) trait GetCacheInternal<'tcx>: QueryDescription<'tcx> + Sized {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(super) struct CycleError<'tcx> {
|
pub(super) struct CycleError<'tcx> {
|
||||||
/// The span of the reason the first query in `cycle` ran the last query in `cycle`
|
/// The query and related span which uses the cycle
|
||||||
pub(super) span: Span,
|
pub(super) usage: Option<(Span, Query<'tcx>)>,
|
||||||
pub(super) cycle: Vec<QueryInfo<'tcx>>,
|
pub(super) cycle: Vec<QueryInfo<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ pub(super) enum TryGetLock<'a, 'tcx: 'a, T, D: QueryDescription<'tcx> + 'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
pub(super) fn report_cycle(self, CycleError { span, cycle: stack }: CycleError<'gcx>)
|
pub(super) fn report_cycle(self, CycleError { usage, cycle: stack }: CycleError<'gcx>)
|
||||||
-> DiagnosticBuilder<'a>
|
-> DiagnosticBuilder<'a>
|
||||||
{
|
{
|
||||||
assert!(!stack.is_empty());
|
assert!(!stack.is_empty());
|
||||||
|
@ -95,23 +95,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
// (And cycle errors around impls tend to occur during the
|
// (And cycle errors around impls tend to occur during the
|
||||||
// collect/coherence phases anyhow.)
|
// collect/coherence phases anyhow.)
|
||||||
item_path::with_forced_impl_filename_line(|| {
|
item_path::with_forced_impl_filename_line(|| {
|
||||||
let span = fix_span(span, &stack.first().unwrap().query);
|
let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
|
||||||
let mut err =
|
let mut err = struct_span_err!(self.sess,
|
||||||
struct_span_err!(self.sess, span, E0391,
|
span,
|
||||||
"cyclic dependency detected");
|
E0391,
|
||||||
err.span_label(span, "cyclic reference");
|
"cycle detected when {}",
|
||||||
|
stack[0].query.describe(self));
|
||||||
|
|
||||||
err.span_note(fix_span(stack[0].span, &stack[0].query),
|
for i in 1..stack.len() {
|
||||||
&format!("the cycle begins when {}...", stack[0].query.describe(self)));
|
let query = &stack[i].query;
|
||||||
|
let span = fix_span(stack[(i + 1) % stack.len()].span, query);
|
||||||
for &QueryInfo { span, ref query, .. } in &stack[1..] {
|
err.span_note(span, &format!("...which requires {}...", query.describe(self)));
|
||||||
err.span_note(fix_span(span, query),
|
|
||||||
&format!("...which then requires {}...", query.describe(self)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err.note(&format!("...which then again requires {}, completing the cycle.",
|
err.note(&format!("...which again requires {}, completing the cycle",
|
||||||
stack[0].query.describe(self)));
|
stack[0].query.describe(self)));
|
||||||
|
|
||||||
|
if let Some((span, query)) = usage {
|
||||||
|
err.span_note(fix_span(span, &query),
|
||||||
|
&format!("cycle used when {}", query.describe(self)));
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue