aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/lib.rs')
-rw-r--r--crates/ra_hir_def/src/lib.rs362
1 files changed, 362 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
new file mode 100644
index 000000000..93ad40005
--- /dev/null
+++ b/crates/ra_hir_def/src/lib.rs
@@ -0,0 +1,362 @@
1//! `hir_def` crate contains everything between macro expansion and type
2//! inference.
3//!
4//! It defines various items (structs, enums, traits) which comprises Rust code,
5//! as well as an algorithm for resolving paths to such entities.
6//!
7//! Note that `hir_def` is a work in progress, so not all of the above is
8//! actually true.
9
10pub mod db;
11pub mod attr;
12pub mod path;
13pub mod type_ref;
14pub mod builtin_type;
15
16// FIXME: this should be private
17pub mod nameres;
18
19use std::hash::{Hash, Hasher};
20
21use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId};
22use ra_arena::{impl_arena_id, RawId};
23use ra_db::{salsa, CrateId, FileId};
24use ra_syntax::{ast, AstNode, SyntaxNode};
25
26use crate::{builtin_type::BuiltinType, db::InternDatabase};
27
28#[derive(Debug, PartialEq, Eq, Clone, Copy)]
29pub struct Source<T> {
30 pub file_id: HirFileId,
31 pub ast: T,
32}
33
34pub enum ModuleSource {
35 SourceFile(ast::SourceFile),
36 Module(ast::Module),
37}
38
39impl ModuleSource {
40 pub fn new(
41 db: &impl db::DefDatabase2,
42 file_id: Option<FileId>,
43 decl_id: Option<AstId<ast::Module>>,
44 ) -> ModuleSource {
45 match (file_id, decl_id) {
46 (Some(file_id), _) => {
47 let source_file = db.parse(file_id).tree();
48 ModuleSource::SourceFile(source_file)
49 }
50 (None, Some(item_id)) => {
51 let module = item_id.to_node(db);
52 assert!(module.item_list().is_some(), "expected inline module");
53 ModuleSource::Module(module)
54 }
55 (None, None) => panic!(),
56 }
57 }
58
59 // FIXME: this methods do not belong here
60 pub fn from_position(
61 db: &impl db::DefDatabase2,
62 position: ra_db::FilePosition,
63 ) -> ModuleSource {
64 let parse = db.parse(position.file_id);
65 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
66 parse.tree().syntax(),
67 position.offset,
68 ) {
69 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
70 _ => {
71 let source_file = parse.tree();
72 ModuleSource::SourceFile(source_file)
73 }
74 }
75 }
76
77 pub fn from_child_node(
78 db: &impl db::DefDatabase2,
79 file_id: FileId,
80 child: &SyntaxNode,
81 ) -> ModuleSource {
82 if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
83 ModuleSource::Module(m)
84 } else {
85 let source_file = db.parse(file_id).tree();
86 ModuleSource::SourceFile(source_file)
87 }
88 }
89
90 pub fn from_file_id(db: &impl db::DefDatabase2, file_id: FileId) -> ModuleSource {
91 let source_file = db.parse(file_id).tree();
92 ModuleSource::SourceFile(source_file)
93 }
94}
95
96impl<T> Source<T> {
97 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
98 Source { file_id: self.file_id, ast: f(self.ast) }
99 }
100 pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
101 db.parse_or_expand(self.file_id).expect("source created from invalid file")
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106pub struct ModuleId {
107 pub krate: CrateId,
108 pub module_id: CrateModuleId,
109}
110
111/// An ID of a module, **local** to a specific crate
112// FIXME: rename to `LocalModuleId`.
113#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub struct CrateModuleId(RawId);
115impl_arena_id!(CrateModuleId);
116
117macro_rules! impl_intern_key {
118 ($name:ident) => {
119 impl salsa::InternKey for $name {
120 fn from_intern_id(v: salsa::InternId) -> Self {
121 $name(v)
122 }
123 fn as_intern_id(&self) -> salsa::InternId {
124 self.0
125 }
126 }
127 };
128}
129
130#[derive(Debug)]
131pub struct ItemLoc<N: AstNode> {
132 pub(crate) module: ModuleId,
133 ast_id: AstId<N>,
134}
135
136impl<N: AstNode> PartialEq for ItemLoc<N> {
137 fn eq(&self, other: &Self) -> bool {
138 self.module == other.module && self.ast_id == other.ast_id
139 }
140}
141impl<N: AstNode> Eq for ItemLoc<N> {}
142impl<N: AstNode> Hash for ItemLoc<N> {
143 fn hash<H: Hasher>(&self, hasher: &mut H) {
144 self.module.hash(hasher);
145 self.ast_id.hash(hasher);
146 }
147}
148
149impl<N: AstNode> Clone for ItemLoc<N> {
150 fn clone(&self) -> ItemLoc<N> {
151 ItemLoc { module: self.module, ast_id: self.ast_id }
152 }
153}
154
155#[derive(Clone, Copy)]
156pub struct LocationCtx<DB> {
157 db: DB,
158 module: ModuleId,
159 file_id: HirFileId,
160}
161
162impl<'a, DB> LocationCtx<&'a DB> {
163 pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> {
164 LocationCtx { db, module, file_id }
165 }
166}
167
168impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> {
169 pub fn to_def<N, DEF>(self, ast: &N) -> DEF
170 where
171 N: AstNode,
172 DEF: AstItemDef<N>,
173 {
174 DEF::from_ast(self, ast)
175 }
176}
177
178pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
179 fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
180 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;
181
182 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self {
183 let items = ctx.db.ast_id_map(ctx.file_id);
184 let item_id = items.ast_id(ast);
185 Self::from_ast_id(ctx, item_id)
186 }
187 fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
188 let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) };
189 Self::intern(ctx.db, loc)
190 }
191 fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> {
192 let loc = self.lookup_intern(db);
193 let ast = loc.ast_id.to_node(db);
194 Source { file_id: loc.ast_id.file_id(), ast }
195 }
196 fn module(self, db: &impl InternDatabase) -> ModuleId {
197 let loc = self.lookup_intern(db);
198 loc.module
199 }
200}
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
203pub struct FunctionId(salsa::InternId);
204impl_intern_key!(FunctionId);
205
206impl AstItemDef<ast::FnDef> for FunctionId {
207 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
208 db.intern_function(loc)
209 }
210 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> {
211 db.lookup_intern_function(self)
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
216pub struct StructId(salsa::InternId);
217impl_intern_key!(StructId);
218impl AstItemDef<ast::StructDef> for StructId {
219 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
220 db.intern_struct(loc)
221 }
222 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
223 db.lookup_intern_struct(self)
224 }
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228pub struct UnionId(salsa::InternId);
229impl_intern_key!(UnionId);
230impl AstItemDef<ast::StructDef> for UnionId {
231 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
232 db.intern_union(loc)
233 }
234 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
235 db.lookup_intern_union(self)
236 }
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
240pub struct EnumId(salsa::InternId);
241impl_intern_key!(EnumId);
242impl AstItemDef<ast::EnumDef> for EnumId {
243 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
244 db.intern_enum(loc)
245 }
246 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
247 db.lookup_intern_enum(self)
248 }
249}
250
251// FIXME: rename to `VariantId`, only enums can ave variants
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
253pub struct EnumVariantId {
254 parent: EnumId,
255 local_id: LocalEnumVariantId,
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct LocalEnumVariantId(RawId);
260impl_arena_id!(LocalEnumVariantId);
261
262#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
263pub struct ConstId(salsa::InternId);
264impl_intern_key!(ConstId);
265impl AstItemDef<ast::ConstDef> for ConstId {
266 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
267 db.intern_const(loc)
268 }
269 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> {
270 db.lookup_intern_const(self)
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
275pub struct StaticId(salsa::InternId);
276impl_intern_key!(StaticId);
277impl AstItemDef<ast::StaticDef> for StaticId {
278 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
279 db.intern_static(loc)
280 }
281 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> {
282 db.lookup_intern_static(self)
283 }
284}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
287pub struct TraitId(salsa::InternId);
288impl_intern_key!(TraitId);
289impl AstItemDef<ast::TraitDef> for TraitId {
290 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
291 db.intern_trait(loc)
292 }
293 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
294 db.lookup_intern_trait(self)
295 }
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
299pub struct TypeAliasId(salsa::InternId);
300impl_intern_key!(TypeAliasId);
301impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
302 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
303 db.intern_type_alias(loc)
304 }
305 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> {
306 db.lookup_intern_type_alias(self)
307 }
308}
309
310macro_rules! impl_froms {
311 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
312 $(
313 impl From<$v> for $e {
314 fn from(it: $v) -> $e {
315 $e::$v(it)
316 }
317 }
318 $($(
319 impl From<$sv> for $e {
320 fn from(it: $sv) -> $e {
321 $e::$v($v::$sv(it))
322 }
323 }
324 )*)?
325 )*
326 }
327}
328
329/// A Data Type
330#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
331pub enum AdtId {
332 StructId(StructId),
333 UnionId(UnionId),
334 EnumId(EnumId),
335}
336impl_froms!(AdtId: StructId, UnionId, EnumId);
337
338/// The defs which can be visible in the module.
339#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
340pub enum ModuleDefId {
341 ModuleId(ModuleId),
342 FunctionId(FunctionId),
343 AdtId(AdtId),
344 // Can't be directly declared, but can be imported.
345 EnumVariantId(EnumVariantId),
346 ConstId(ConstId),
347 StaticId(StaticId),
348 TraitId(TraitId),
349 TypeAliasId(TypeAliasId),
350 BuiltinType(BuiltinType),
351}
352impl_froms!(
353 ModuleDefId: ModuleId,
354 FunctionId,
355 AdtId(StructId, EnumId, UnionId),
356 EnumVariantId,
357 ConstId,
358 StaticId,
359 TraitId,
360 TypeAliasId,
361 BuiltinType
362);