add a "runtime" and use that from query context impls

This commit is contained in:
Niko Matsakis 2018-09-29 05:31:26 -04:00
parent ac7b02b7ef
commit 288fe5b25f
6 changed files with 82 additions and 62 deletions

View file

@ -1,17 +1,13 @@
use crate::class_table; use crate::class_table;
use crate::compiler::{CompilerQueryContext, Interner}; use crate::compiler::{CompilerQueryContext, Interner};
use salsa::dyn_descriptor::DynDescriptor;
use salsa::query_context_storage; use salsa::query_context_storage;
use salsa::BaseQueryContext; use salsa::BaseQueryContext;
use salsa::Query;
use std::cell::RefCell;
use std::fmt::Write;
#[derive(Default)] #[derive(Default)]
pub struct QueryContextImpl { pub struct QueryContextImpl {
runtime: salsa::Runtime<QueryContextImpl>,
storage: QueryContextImplStorage, storage: QueryContextImplStorage,
interner: Interner, interner: Interner,
execution_stack: RefCell<Vec<DynDescriptor>>,
} }
// This is an example of how you "link up" all the queries in your // This is an example of how you "link up" all the queries in your
@ -42,34 +38,9 @@ impl CompilerQueryContext for QueryContextImpl {
// permit behavior refinement. // permit behavior refinement.
impl BaseQueryContext for QueryContextImpl { impl BaseQueryContext for QueryContextImpl {
type QueryDescriptor = DynDescriptor; type QueryDescriptor = salsa::dyn_descriptor::DynDescriptor;
fn execute_query_implementation<Q>( fn salsa_runtime(&self) -> &salsa::runtime::Runtime<QueryContextImpl> {
&self, &self.runtime
descriptor: Self::QueryDescriptor,
key: &Q::Key,
) -> Q::Value
where
Q: Query<Self>,
{
self.execution_stack.borrow_mut().push(descriptor);
let value = Q::execute(self, key.clone());
self.execution_stack.borrow_mut().pop();
value
}
fn report_unexpected_cycle(&self, descriptor: Self::QueryDescriptor) -> ! {
let execution_stack = self.execution_stack.borrow();
let start_index = (0..execution_stack.len())
.rev()
.filter(|&i| execution_stack[i] == descriptor)
.next()
.unwrap();
let mut message = format!("Internal error, cycle detected:\n");
for descriptor in &execution_stack[start_index..] {
writeln!(message, "- {:?}\n", descriptor).unwrap();
}
panic!(message)
} }
} }

View file

@ -3,6 +3,7 @@ use std::cell::Cell;
#[derive(Default)] #[derive(Default)]
pub struct QueryContextImpl { pub struct QueryContextImpl {
runtime: salsa::Runtime<QueryContextImpl>,
storage: QueryContextImplStorage, storage: QueryContextImplStorage,
counter: Cell<usize>, counter: Cell<usize>,
} }
@ -27,19 +28,7 @@ impl queries::CounterContext for QueryContextImpl {
impl salsa::BaseQueryContext for QueryContextImpl { impl salsa::BaseQueryContext for QueryContextImpl {
type QueryDescriptor = salsa::dyn_descriptor::DynDescriptor; type QueryDescriptor = salsa::dyn_descriptor::DynDescriptor;
fn execute_query_implementation<Q>( fn salsa_runtime(&self) -> &salsa::runtime::Runtime<QueryContextImpl> {
&self, &self.runtime
_descriptor: Self::QueryDescriptor,
key: &Q::Key,
) -> Q::Value
where
Q: salsa::Query<Self>,
{
let value = Q::execute(self, key.clone());
value
}
fn report_unexpected_cycle(&self, _descriptor: Self::QueryDescriptor) -> ! {
panic!("cycle")
} }
} }

View file

@ -1,5 +1,6 @@
#![deny(rust_2018_idioms)] #![deny(rust_2018_idioms)]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
#![feature(nll)] #![feature(nll)]
#![feature(min_const_fn)] #![feature(min_const_fn)]
#![feature(const_fn)] #![feature(const_fn)]
@ -20,8 +21,11 @@ use std::hash::Hash;
pub mod dyn_descriptor; pub mod dyn_descriptor;
pub mod memoized; pub mod memoized;
pub mod runtime;
pub mod transparent; pub mod transparent;
pub use self::runtime::Runtime;
pub trait BaseQueryContext: Sized { pub trait BaseQueryContext: Sized {
/// A "query descriptor" packages up all the possible queries and a key. /// A "query descriptor" packages up all the possible queries and a key.
/// It is used to store information about (e.g.) the stack. /// It is used to store information about (e.g.) the stack.
@ -31,16 +35,8 @@ pub trait BaseQueryContext: Sized {
/// for a more open-ended option. /// for a more open-ended option.
type QueryDescriptor: Debug + Eq; type QueryDescriptor: Debug + Eq;
fn execute_query_implementation<Q>( /// Gives access to the underlying salsa runtime.
&self, fn salsa_runtime(&self) -> &runtime::Runtime<Self>;
descriptor: Self::QueryDescriptor,
key: &Q::Key,
) -> Q::Value
where
Q: Query<Self>;
/// Reports an unexpected cycle attempting to access the query Q with the given key.
fn report_unexpected_cycle(&self, descriptor: Self::QueryDescriptor) -> !;
} }
pub trait Query<QC: BaseQueryContext>: Debug + Default + Sized + 'static { pub trait Query<QC: BaseQueryContext>: Debug + Default + Sized + 'static {
@ -86,7 +82,9 @@ where
self.storage self.storage
.try_fetch(self.query, &key, || self.descriptor(&key)) .try_fetch(self.query, &key, || self.descriptor(&key))
.unwrap_or_else(|CycleDetected| { .unwrap_or_else(|CycleDetected| {
self.query.report_unexpected_cycle(self.descriptor(&key)) self.query
.salsa_runtime()
.report_unexpected_cycle(self.descriptor(&key))
}) })
} }
@ -301,6 +299,8 @@ macro_rules! query_definition {
}; };
} }
/// This macro generates the "query storage" that goes into your query
/// context.
#[macro_export] #[macro_export]
macro_rules! query_context_storage { macro_rules! query_context_storage {
( (
@ -336,8 +336,6 @@ macro_rules! query_context_storage {
self, self,
&self.$storage_field.$query_method, &self.$storage_field.$query_method,
// FIXME: we should not hardcode the descriptor like this.
// Have to think of the best fix.
$crate::dyn_descriptor::DynDescriptor::from_key::< $crate::dyn_descriptor::DynDescriptor::from_key::<
Self, Self,
$QueryType, $QueryType,

View file

@ -75,7 +75,9 @@ where
// If we get here, the query is in progress, and we are the // If we get here, the query is in progress, and we are the
// ones tasked with finding its final value. // ones tasked with finding its final value.
let descriptor = descriptor(); let descriptor = descriptor();
let value = query.execute_query_implementation::<Q>(descriptor, key); let value = query
.salsa_runtime()
.execute_query_implementation::<Q>(query, descriptor, key);
{ {
let mut map_write = self.map.write(); let mut map_write = self.map.write();

58
src/runtime.rs Normal file
View file

@ -0,0 +1,58 @@
use crate::BaseQueryContext;
use crate::Query;
use std::cell::RefCell;
use std::fmt::Write;
pub struct Runtime<QC>
where
QC: BaseQueryContext,
{
execution_stack: RefCell<Vec<QC::QueryDescriptor>>,
}
impl<QC> Default for Runtime<QC>
where
QC: BaseQueryContext,
{
fn default() -> Self {
Runtime {
execution_stack: RefCell::default(),
}
}
}
impl<QC> Runtime<QC>
where
QC: BaseQueryContext,
{
crate fn execute_query_implementation<Q>(
&self,
query: &QC,
descriptor: QC::QueryDescriptor,
key: &Q::Key,
) -> Q::Value
where
Q: Query<QC>,
{
self.execution_stack.borrow_mut().push(descriptor);
let value = Q::execute(query, key.clone());
self.execution_stack.borrow_mut().pop();
value
}
/// Obviously, this should be user configurable at some point.
crate fn report_unexpected_cycle(&self, descriptor: QC::QueryDescriptor) -> ! {
let execution_stack = self.execution_stack.borrow();
let start_index = (0..execution_stack.len())
.rev()
.filter(|&i| execution_stack[i] == descriptor)
.next()
.unwrap();
let mut message = format!("Internal error, cycle detected:\n");
for descriptor in &execution_stack[start_index..] {
writeln!(message, "- {:?}\n", descriptor).unwrap();
}
panic!(message)
}
}

View file

@ -35,6 +35,8 @@ where
// here? Or should we just call `Q::execute`, and maybe // here? Or should we just call `Q::execute`, and maybe
// separate out the `push`/`pop` operations. // separate out the `push`/`pop` operations.
let descriptor = descriptor(); let descriptor = descriptor();
Ok(query.execute_query_implementation::<Q>(descriptor, key)) Ok(query
.salsa_runtime()
.execute_query_implementation::<Q>(query, descriptor, key))
} }
} }