fe_analyzer/
db.rs

1#![allow(clippy::arc_with_non_send_sync)]
2use crate::namespace::items::{
3    self, AttributeId, ContractFieldId, ContractId, DepGraphWrapper, EnumVariantKind, FunctionId,
4    FunctionSigId, ImplId, IngotId, Item, ModuleConstantId, ModuleId, StructFieldId, StructId,
5    TraitId, TypeAliasId,
6};
7use crate::namespace::types::{self, Type, TypeId};
8use crate::{
9    context::{Analysis, Constant, FunctionBody},
10    namespace::items::EnumId,
11};
12use crate::{
13    errors::{ConstEvalError, TypeError},
14    namespace::items::EnumVariantId,
15};
16use fe_common::db::{SourceDb, SourceDbStorage, Upcast, UpcastMut};
17use fe_common::{SourceFileId, Span};
18use fe_parser::ast;
19use indexmap::map::IndexMap;
20use smol_str::SmolStr;
21use std::rc::Rc;
22mod queries;
23
24#[salsa::query_group(AnalyzerDbStorage)]
25pub trait AnalyzerDb: SourceDb + Upcast<dyn SourceDb> + UpcastMut<dyn SourceDb> {
26    #[salsa::interned]
27    fn intern_ingot(&self, data: Rc<items::Ingot>) -> IngotId;
28    #[salsa::interned]
29    fn intern_module(&self, data: Rc<items::Module>) -> ModuleId;
30    #[salsa::interned]
31    fn intern_module_const(&self, data: Rc<items::ModuleConstant>) -> ModuleConstantId;
32    #[salsa::interned]
33    fn intern_struct(&self, data: Rc<items::Struct>) -> StructId;
34    #[salsa::interned]
35    fn intern_struct_field(&self, data: Rc<items::StructField>) -> StructFieldId;
36    #[salsa::interned]
37    fn intern_enum(&self, data: Rc<items::Enum>) -> EnumId;
38    #[salsa::interned]
39    fn intern_attribute(&self, data: Rc<items::Attribute>) -> AttributeId;
40    #[salsa::interned]
41    fn intern_enum_variant(&self, data: Rc<items::EnumVariant>) -> EnumVariantId;
42    #[salsa::interned]
43    fn intern_trait(&self, data: Rc<items::Trait>) -> TraitId;
44    #[salsa::interned]
45    fn intern_impl(&self, data: Rc<items::Impl>) -> ImplId;
46    #[salsa::interned]
47    fn intern_type_alias(&self, data: Rc<items::TypeAlias>) -> TypeAliasId;
48    #[salsa::interned]
49    fn intern_contract(&self, data: Rc<items::Contract>) -> ContractId;
50    #[salsa::interned]
51    fn intern_contract_field(&self, data: Rc<items::ContractField>) -> ContractFieldId;
52    #[salsa::interned]
53    fn intern_function_sig(&self, data: Rc<items::FunctionSig>) -> FunctionSigId;
54    #[salsa::interned]
55    fn intern_function(&self, data: Rc<items::Function>) -> FunctionId;
56    #[salsa::interned]
57    fn intern_type(&self, data: Type) -> TypeId;
58
59    // Ingot
60
61    // These are inputs so that the (future) language server can add
62    // and remove files/dependencies. Set via eg `db.set_ingot_files`.
63    // If an input is used before it's set, salsa will panic.
64    #[salsa::input]
65    fn ingot_files(&self, ingot: IngotId) -> Rc<[SourceFileId]>;
66    #[salsa::input]
67    fn ingot_external_ingots(&self, ingot: IngotId) -> Rc<IndexMap<SmolStr, IngotId>>;
68    // Having the root ingot available as a "global" might offend functional
69    // programming purists but it makes for much nicer ergonomics in queries
70    // that just need the global entrypoint
71    #[salsa::input]
72    fn root_ingot(&self) -> IngotId;
73
74    #[salsa::invoke(queries::ingots::ingot_modules)]
75    fn ingot_modules(&self, ingot: IngotId) -> Rc<[ModuleId]>;
76    #[salsa::invoke(queries::ingots::ingot_root_module)]
77    fn ingot_root_module(&self, ingot: IngotId) -> Option<ModuleId>;
78
79    // Module
80    #[salsa::invoke(queries::module::module_file_path)]
81    fn module_file_path(&self, module: ModuleId) -> SmolStr;
82    #[salsa::invoke(queries::module::module_parse)]
83    fn module_parse(&self, module: ModuleId) -> Analysis<Rc<ast::Module>>;
84    #[salsa::invoke(queries::module::module_is_incomplete)]
85    fn module_is_incomplete(&self, module: ModuleId) -> bool;
86    #[salsa::invoke(queries::module::module_all_items)]
87    fn module_all_items(&self, module: ModuleId) -> Rc<[Item]>;
88    #[salsa::invoke(queries::module::module_all_impls)]
89    fn module_all_impls(&self, module: ModuleId) -> Analysis<Rc<[ImplId]>>;
90    #[salsa::invoke(queries::module::module_item_map)]
91    fn module_item_map(&self, module: ModuleId) -> Analysis<Rc<IndexMap<SmolStr, Item>>>;
92    #[salsa::invoke(queries::module::module_impl_map)]
93    fn module_impl_map(
94        &self,
95        module: ModuleId,
96    ) -> Analysis<Rc<IndexMap<(TraitId, TypeId), ImplId>>>;
97    #[salsa::invoke(queries::module::module_contracts)]
98    fn module_contracts(&self, module: ModuleId) -> Rc<[ContractId]>;
99    #[salsa::invoke(queries::module::module_structs)]
100    fn module_structs(&self, module: ModuleId) -> Rc<[StructId]>;
101    #[salsa::invoke(queries::module::module_constants)]
102    fn module_constants(&self, module: ModuleId) -> Rc<Vec<ModuleConstantId>>;
103    #[salsa::invoke(queries::module::module_used_item_map)]
104    fn module_used_item_map(
105        &self,
106        module: ModuleId,
107    ) -> Analysis<Rc<IndexMap<SmolStr, (Span, Item)>>>;
108    #[salsa::invoke(queries::module::module_parent_module)]
109    fn module_parent_module(&self, module: ModuleId) -> Option<ModuleId>;
110    #[salsa::invoke(queries::module::module_submodules)]
111    fn module_submodules(&self, module: ModuleId) -> Rc<[ModuleId]>;
112    #[salsa::invoke(queries::module::module_tests)]
113    fn module_tests(&self, module: ModuleId) -> Vec<FunctionId>;
114
115    // Module Constant
116    #[salsa::cycle(queries::module::module_constant_type_cycle)]
117    #[salsa::invoke(queries::module::module_constant_type)]
118    fn module_constant_type(&self, id: ModuleConstantId) -> Analysis<Result<TypeId, TypeError>>;
119    #[salsa::cycle(queries::module::module_constant_value_cycle)]
120    #[salsa::invoke(queries::module::module_constant_value)]
121    fn module_constant_value(
122        &self,
123        id: ModuleConstantId,
124    ) -> Analysis<Result<Constant, ConstEvalError>>;
125
126    // Contract
127    #[salsa::invoke(queries::contracts::contract_all_functions)]
128    fn contract_all_functions(&self, id: ContractId) -> Rc<[FunctionId]>;
129    #[salsa::invoke(queries::contracts::contract_function_map)]
130    fn contract_function_map(&self, id: ContractId) -> Analysis<Rc<IndexMap<SmolStr, FunctionId>>>;
131    #[salsa::invoke(queries::contracts::contract_public_function_map)]
132    fn contract_public_function_map(&self, id: ContractId) -> Rc<IndexMap<SmolStr, FunctionId>>;
133    #[salsa::invoke(queries::contracts::contract_init_function)]
134    fn contract_init_function(&self, id: ContractId) -> Analysis<Option<FunctionId>>;
135    #[salsa::invoke(queries::contracts::contract_call_function)]
136    fn contract_call_function(&self, id: ContractId) -> Analysis<Option<FunctionId>>;
137
138    #[salsa::invoke(queries::contracts::contract_all_fields)]
139    fn contract_all_fields(&self, id: ContractId) -> Rc<[ContractFieldId]>;
140    #[salsa::invoke(queries::contracts::contract_field_map)]
141    fn contract_field_map(
142        &self,
143        id: ContractId,
144    ) -> Analysis<Rc<IndexMap<SmolStr, ContractFieldId>>>;
145    #[salsa::invoke(queries::contracts::contract_field_type)]
146    fn contract_field_type(&self, field: ContractFieldId) -> Analysis<Result<TypeId, TypeError>>;
147    #[salsa::cycle(queries::contracts::contract_dependency_graph_cycle)]
148    #[salsa::invoke(queries::contracts::contract_dependency_graph)]
149    fn contract_dependency_graph(&self, id: ContractId) -> DepGraphWrapper;
150    #[salsa::cycle(queries::contracts::contract_runtime_dependency_graph_cycle)]
151    #[salsa::invoke(queries::contracts::contract_runtime_dependency_graph)]
152    fn contract_runtime_dependency_graph(&self, id: ContractId) -> DepGraphWrapper;
153
154    // Function
155    #[salsa::invoke(queries::functions::function_signature)]
156    fn function_signature(&self, id: FunctionSigId) -> Analysis<Rc<types::FunctionSignature>>;
157    #[salsa::invoke(queries::functions::function_body)]
158    fn function_body(&self, id: FunctionId) -> Analysis<Rc<FunctionBody>>;
159    #[salsa::cycle(queries::functions::function_dependency_graph_cycle)]
160    #[salsa::invoke(queries::functions::function_dependency_graph)]
161    fn function_dependency_graph(&self, id: FunctionId) -> DepGraphWrapper;
162
163    // Struct
164    #[salsa::invoke(queries::structs::struct_all_fields)]
165    fn struct_all_fields(&self, id: StructId) -> Rc<[StructFieldId]>;
166    #[salsa::invoke(queries::structs::struct_field_map)]
167    fn struct_field_map(&self, id: StructId) -> Analysis<Rc<IndexMap<SmolStr, StructFieldId>>>;
168    #[salsa::invoke(queries::structs::struct_field_type)]
169    fn struct_field_type(&self, field: StructFieldId) -> Analysis<Result<TypeId, TypeError>>;
170    #[salsa::invoke(queries::structs::struct_all_functions)]
171    fn struct_all_functions(&self, id: StructId) -> Rc<[FunctionId]>;
172    #[salsa::invoke(queries::structs::struct_function_map)]
173    fn struct_function_map(&self, id: StructId) -> Analysis<Rc<IndexMap<SmolStr, FunctionId>>>;
174    #[salsa::cycle(queries::structs::struct_cycle)]
175    #[salsa::invoke(queries::structs::struct_dependency_graph)]
176    fn struct_dependency_graph(&self, id: StructId) -> Analysis<DepGraphWrapper>;
177
178    // Enum
179    #[salsa::invoke(queries::enums::enum_all_variants)]
180    fn enum_all_variants(&self, id: EnumId) -> Rc<[EnumVariantId]>;
181    #[salsa::invoke(queries::enums::enum_variant_map)]
182    fn enum_variant_map(&self, id: EnumId) -> Analysis<Rc<IndexMap<SmolStr, EnumVariantId>>>;
183    #[salsa::invoke(queries::enums::enum_all_functions)]
184    fn enum_all_functions(&self, id: EnumId) -> Rc<[FunctionId]>;
185    #[salsa::invoke(queries::enums::enum_function_map)]
186    fn enum_function_map(&self, id: EnumId) -> Analysis<Rc<IndexMap<SmolStr, FunctionId>>>;
187    #[salsa::cycle(queries::enums::enum_cycle)]
188    #[salsa::invoke(queries::enums::enum_dependency_graph)]
189    fn enum_dependency_graph(&self, id: EnumId) -> Analysis<DepGraphWrapper>;
190    #[salsa::invoke(queries::enums::enum_variant_kind)]
191    fn enum_variant_kind(&self, id: EnumVariantId) -> Analysis<Result<EnumVariantKind, TypeError>>;
192
193    // Trait
194    #[salsa::invoke(queries::traits::trait_all_functions)]
195    fn trait_all_functions(&self, id: TraitId) -> Rc<[FunctionSigId]>;
196    #[salsa::invoke(queries::traits::trait_function_map)]
197    fn trait_function_map(&self, id: TraitId) -> Analysis<Rc<IndexMap<SmolStr, FunctionSigId>>>;
198    #[salsa::invoke(queries::traits::trait_is_implemented_for)]
199    fn trait_is_implemented_for(&self, id: TraitId, typ: TypeId) -> bool;
200
201    // Impl
202    #[salsa::invoke(queries::impls::impl_all_functions)]
203    fn impl_all_functions(&self, id: ImplId) -> Rc<[FunctionId]>;
204    #[salsa::invoke(queries::impls::impl_function_map)]
205    fn impl_function_map(&self, id: ImplId) -> Analysis<Rc<IndexMap<SmolStr, FunctionId>>>;
206
207    // Type
208    #[salsa::invoke(queries::types::all_impls)]
209    fn all_impls(&self, ty: TypeId) -> Rc<[ImplId]>;
210    #[salsa::invoke(queries::types::impl_for)]
211    fn impl_for(&self, ty: TypeId, treit: TraitId) -> Option<ImplId>;
212    #[salsa::invoke(queries::types::function_sigs)]
213    fn function_sigs(&self, ty: TypeId, name: SmolStr) -> Rc<[FunctionSigId]>;
214
215    // Type alias
216    #[salsa::invoke(queries::types::type_alias_type)]
217    #[salsa::cycle(queries::types::type_alias_type_cycle)]
218    fn type_alias_type(&self, id: TypeAliasId) -> Analysis<Result<TypeId, TypeError>>;
219}
220
221#[salsa::database(AnalyzerDbStorage, SourceDbStorage)]
222#[derive(Default)]
223pub struct TestDb {
224    storage: salsa::Storage<TestDb>,
225}
226impl salsa::Database for TestDb {}
227
228impl Upcast<dyn SourceDb> for TestDb {
229    fn upcast(&self) -> &(dyn SourceDb + 'static) {
230        self
231    }
232}
233
234impl UpcastMut<dyn SourceDb> for TestDb {
235    fn upcast_mut(&mut self) -> &mut (dyn SourceDb + 'static) {
236        &mut *self
237    }
238}