2018-03-15 04:03:36 -05:00
|
|
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2018-03-24 00:19:20 -05:00
|
|
|
use rustc_data_structures::sync::{Lock, Lrc};
|
2018-03-15 04:03:36 -05:00
|
|
|
use syntax_pos::Span;
|
|
|
|
use ty::tls;
|
|
|
|
use ty::maps::Query;
|
|
|
|
use ty::maps::plumbing::CycleError;
|
|
|
|
use ty::context::TyCtxt;
|
|
|
|
use errors::Diagnostic;
|
|
|
|
|
2018-03-24 00:19:20 -05:00
|
|
|
/// Indicates the state of a query for a given key in a query map
|
|
|
|
pub(super) enum QueryResult<'tcx, T> {
|
|
|
|
/// An already executing query. The query job can be used to await for its completion
|
|
|
|
Started(Lrc<QueryJob<'tcx>>),
|
|
|
|
|
|
|
|
/// The query is complete and produced `T`
|
|
|
|
Complete(T),
|
2018-03-15 04:03:36 -05:00
|
|
|
|
2018-03-24 00:19:20 -05:00
|
|
|
/// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic
|
|
|
|
Poisoned,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A span and a query key
|
2018-03-15 04:03:36 -05:00
|
|
|
#[derive(Clone, Debug)]
|
2018-03-24 00:19:20 -05:00
|
|
|
pub struct QueryInfo<'tcx> {
|
2018-04-13 15:20:10 -05:00
|
|
|
/// The span for a reason this query was required
|
2018-03-15 04:03:36 -05:00
|
|
|
pub span: Span,
|
|
|
|
pub query: Query<'tcx>,
|
|
|
|
}
|
|
|
|
|
2018-03-24 00:19:20 -05:00
|
|
|
/// A object representing an active query job.
|
2018-03-15 04:03:36 -05:00
|
|
|
pub struct QueryJob<'tcx> {
|
2018-03-24 00:19:20 -05:00
|
|
|
pub info: QueryInfo<'tcx>,
|
|
|
|
|
|
|
|
/// The parent query job which created this job and is implicitly waiting on it.
|
2018-03-15 04:03:36 -05:00
|
|
|
pub parent: Option<Lrc<QueryJob<'tcx>>>,
|
2018-03-24 00:19:20 -05:00
|
|
|
|
|
|
|
/// Diagnostic messages which are emitted while the query executes
|
2018-03-15 04:03:36 -05:00
|
|
|
pub diagnostics: Lock<Vec<Diagnostic>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> QueryJob<'tcx> {
|
2018-03-24 00:19:20 -05:00
|
|
|
/// Creates a new query job
|
|
|
|
pub fn new(info: QueryInfo<'tcx>, parent: Option<Lrc<QueryJob<'tcx>>>) -> Self {
|
2018-03-15 04:03:36 -05:00
|
|
|
QueryJob {
|
|
|
|
diagnostics: Lock::new(Vec::new()),
|
2018-03-24 00:19:20 -05:00
|
|
|
info,
|
2018-03-15 04:03:36 -05:00
|
|
|
parent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-24 00:19:20 -05:00
|
|
|
/// Awaits for the query job to complete.
|
|
|
|
///
|
|
|
|
/// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any
|
|
|
|
/// query that means that there is a query cycle, thus this always running a cycle error.
|
2018-03-15 04:03:36 -05:00
|
|
|
pub(super) fn await<'lcx>(
|
|
|
|
&self,
|
|
|
|
tcx: TyCtxt<'_, 'tcx, 'lcx>,
|
|
|
|
span: Span,
|
|
|
|
) -> Result<(), CycleError<'tcx>> {
|
2018-03-24 00:19:20 -05:00
|
|
|
// Get the current executing query (waiter) and find the waitee amongst its parents
|
2018-03-15 04:03:36 -05:00
|
|
|
let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone());
|
|
|
|
let mut cycle = Vec::new();
|
|
|
|
|
|
|
|
while let Some(job) = current_job {
|
2018-03-24 00:19:20 -05:00
|
|
|
cycle.insert(0, job.info.clone());
|
2018-03-15 04:03:36 -05:00
|
|
|
|
|
|
|
if &*job as *const _ == self as *const _ {
|
2018-04-13 15:20:10 -05:00
|
|
|
// 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 });
|
2018-03-15 04:03:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
current_job = job.parent.clone();
|
|
|
|
}
|
|
|
|
|
2018-04-13 15:20:10 -05:00
|
|
|
panic!("did not find a cycle")
|
2018-03-15 04:03:36 -05:00
|
|
|
}
|
|
|
|
|
2018-03-24 00:19:20 -05:00
|
|
|
/// Signals to waiters that the query is complete.
|
|
|
|
///
|
|
|
|
/// This does nothing for single threaded rustc,
|
|
|
|
/// as there are no concurrent jobs which could be waiting on us
|
|
|
|
pub fn signal_complete(&self) {}
|
2018-03-15 04:03:36 -05:00
|
|
|
}
|