mun_hir/
db.rs

1#![allow(clippy::type_repetition_in_bounds)]
2
3use crate::expr::BodySourceMap;
4use crate::ids::{DefWithBodyId, FunctionId};
5use crate::input::{SourceRoot, SourceRootId};
6use crate::item_tree::{self, ItemTree};
7use crate::module_tree::ModuleTree;
8use crate::name_resolution::Namespace;
9use crate::package_defs::PackageDefs;
10use crate::ty::lower::LowerTyMap;
11use crate::ty::{CallableDef, FnSig, Ty, TypableDef};
12use crate::{
13    code_model::{FunctionData, StructData, TypeAliasData},
14    ids,
15    line_index::LineIndex,
16    ty::InferenceResult,
17    AstIdMap, Body, ExprScopes, FileId, PackageId, PackageSet, Struct, TypeAlias,
18};
19use mun_paths::RelativePathBuf;
20use mun_syntax::{ast, Parse, SourceFile};
21use mun_target::abi;
22use mun_target::spec::Target;
23use std::sync::Arc;
24
25// TODO(bas): In the future maybe move this to a seperate crate (mun_db?)
26pub trait Upcast<T: ?Sized> {
27    fn upcast(&self) -> &T;
28}
29
30/// Database which stores all significant input facts: source code and project model.
31#[salsa::query_group(SourceDatabaseStorage)]
32pub trait SourceDatabase: salsa::Database {
33    /// Text of the file.
34    #[salsa::input]
35    fn file_text(&self, file_id: FileId) -> Arc<str>;
36
37    /// Source root of a file
38    #[salsa::input]
39    fn file_source_root(&self, file_id: FileId) -> SourceRootId;
40
41    /// Returns the relative path of a file
42    fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
43
44    /// Contents of the source root
45    #[salsa::input]
46    fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
47
48    /// For a package, returns its hierarchy of modules.
49    #[salsa::invoke(ModuleTree::module_tree_query)]
50    fn module_tree(&self, package: PackageId) -> Arc<ModuleTree>;
51
52    /// Returns the line index of a file
53    #[salsa::invoke(line_index_query)]
54    fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
55
56    /// Returns the set of packages
57    #[salsa::input]
58    fn packages(&self) -> Arc<PackageSet>;
59}
60
61/// The `AstDatabase` provides queries that transform text from the `SourceDatabase` into an
62/// Abstract Syntax Tree (AST).
63#[salsa::query_group(AstDatabaseStorage)]
64pub trait AstDatabase: SourceDatabase {
65    /// Parses the file into the syntax tree.
66    #[salsa::invoke(parse_query)]
67    fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
68
69    /// Returns the top level AST items of a file
70    #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)]
71    fn ast_id_map(&self, file_id: FileId) -> Arc<AstIdMap>;
72}
73
74/// The `InternDatabase` maps certain datastructures to ids. These ids refer to instances of
75/// concepts like a `Function`, `Struct` or `TypeAlias` in a semi-stable way.
76#[salsa::query_group(InternDatabaseStorage)]
77pub trait InternDatabase: SourceDatabase {
78    #[salsa::interned]
79    fn intern_function(&self, loc: ids::FunctionLoc) -> ids::FunctionId;
80    #[salsa::interned]
81    fn intern_struct(&self, loc: ids::StructLoc) -> ids::StructId;
82    #[salsa::interned]
83    fn intern_type_alias(&self, loc: ids::TypeAliasLoc) -> ids::TypeAliasId;
84}
85
86#[salsa::query_group(DefDatabaseStorage)]
87pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
88    /// Returns the `ItemTree` for a specific file. An `ItemTree` represents all the top level
89    /// declarations within a file.
90    #[salsa::invoke(item_tree::ItemTree::item_tree_query)]
91    fn item_tree(&self, file_id: FileId) -> Arc<ItemTree>;
92
93    #[salsa::invoke(StructData::struct_data_query)]
94    fn struct_data(&self, id: ids::StructId) -> Arc<StructData>;
95
96    #[salsa::invoke(TypeAliasData::type_alias_data_query)]
97    fn type_alias_data(&self, id: ids::TypeAliasId) -> Arc<TypeAliasData>;
98
99    #[salsa::invoke(crate::FunctionData::fn_data_query)]
100    fn fn_data(&self, func: FunctionId) -> Arc<FunctionData>;
101
102    /// Returns the `PackageDefs` for the specified `PackageId`. The `PackageDefs` contains all
103    /// resolved items defined for every module in the package.
104    #[salsa::invoke(crate::package_defs::PackageDefs::package_def_map_query)]
105    fn package_defs(&self, package_id: PackageId) -> Arc<PackageDefs>;
106
107    #[salsa::invoke(Body::body_query)]
108    fn body(&self, def: DefWithBodyId) -> Arc<Body>;
109
110    #[salsa::invoke(Body::body_with_source_map_query)]
111    fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>);
112
113    #[salsa::invoke(ExprScopes::expr_scopes_query)]
114    fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
115}
116
117#[salsa::query_group(HirDatabaseStorage)]
118pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
119    /// Returns the target for code generation.
120    #[salsa::input]
121    fn target(&self) -> Target;
122
123    /// Returns the `TargetDataLayout` for the current target
124    #[salsa::invoke(target_data_layout)]
125    fn target_data_layout(&self) -> Arc<abi::TargetDataLayout>;
126
127    #[salsa::invoke(crate::ty::infer_query)]
128    fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
129
130    #[salsa::invoke(crate::ty::lower::lower_struct_query)]
131    fn lower_struct(&self, def: Struct) -> Arc<LowerTyMap>;
132
133    #[salsa::invoke(crate::ty::lower::lower_type_alias_query)]
134    fn lower_type_alias(&self, def: TypeAlias) -> Arc<LowerTyMap>;
135
136    #[salsa::invoke(crate::ty::callable_item_sig)]
137    fn callable_sig(&self, def: CallableDef) -> FnSig;
138
139    #[salsa::invoke(crate::ty::type_for_def)]
140    #[salsa::cycle(crate::ty::type_for_cycle_recover)]
141    fn type_for_def(&self, def: TypableDef, ns: Namespace) -> (Ty, bool);
142}
143
144fn parse_query(db: &dyn AstDatabase, file_id: FileId) -> Parse<SourceFile> {
145    let text = db.file_text(file_id);
146    SourceFile::parse(&text)
147}
148
149fn line_index_query(db: &dyn SourceDatabase, file_id: FileId) -> Arc<LineIndex> {
150    let text = db.file_text(file_id);
151    Arc::new(LineIndex::new(text.as_ref()))
152}
153
154fn target_data_layout(db: &dyn HirDatabase) -> Arc<abi::TargetDataLayout> {
155    let target = db.target();
156    let data_layout = abi::TargetDataLayout::parse(&target)
157        .expect("unable to create TargetDataLayout from target");
158    Arc::new(data_layout)
159}
160
161fn file_relative_path(db: &dyn SourceDatabase, file_id: FileId) -> RelativePathBuf {
162    let source_root_id = db.file_source_root(file_id);
163    let source_root = db.source_root(source_root_id);
164    source_root.relative_path(file_id).to_relative_path_buf()
165}