use crate::class_table::{self, ClassTableQueryContext}; use crate::compiler::{CompilerQueryContext, Interner}; use salsa::dyn_descriptor::DynDescriptor; use salsa::BaseQueryContext; use salsa::Query; use salsa::QueryTable; use std::cell::RefCell; use std::fmt::Write; #[derive(Default)] pub struct QueryContextImpl { storage: QueryContextImplStorage, interner: Interner, execution_stack: RefCell>, } // The intention is that plus the impl of `ClassTableQueryContext` // below will eventually be generated by a macro, so that you just // have to name the queries. #[allow(non_snake_case)] #[derive(Default)] struct QueryContextImplStorage { AllClasses: >::Storage, AllFields: >::Storage, Fields: >::Storage, } impl ClassTableQueryContext for QueryContextImpl { fn all_classes(&self) -> QueryTable<'_, Self, class_table::AllClasses> { QueryTable::new( self, &self.storage.AllClasses, DynDescriptor::from_key::, ) } fn all_fields(&self) -> QueryTable<'_, Self, class_table::AllFields> { QueryTable::new( self, &self.storage.AllFields, DynDescriptor::from_key::, ) } fn fields(&self) -> QueryTable<'_, Self, class_table::Fields> { QueryTable::new( self, &self.storage.Fields, DynDescriptor::from_key::, ) } } impl CompilerQueryContext for QueryContextImpl { fn interner(&self) -> &Interner { &self.interner } } impl BaseQueryContext for QueryContextImpl { type QueryDescriptor = DynDescriptor; fn execute_query_implementation( &self, descriptor: Self::QueryDescriptor, key: &Q::Key, ) -> Q::Value where Q: Query, { 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) } }