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.rs204
1 files changed, 203 insertions, 1 deletions
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index f5dd2ae6f..4d6b9db03 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -1,5 +1,37 @@
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;
11
12use std::hash::{Hash, Hasher};
13
14use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId};
1use ra_arena::{impl_arena_id, RawId}; 15use ra_arena::{impl_arena_id, RawId};
2use ra_db::CrateId; 16use ra_db::{salsa, CrateId};
17use ra_syntax::{ast, AstNode, SyntaxNode};
18
19use crate::db::InternDatabase;
20
21#[derive(Debug, PartialEq, Eq, Clone, Copy)]
22pub struct Source<T> {
23 pub file_id: HirFileId,
24 pub ast: T,
25}
26
27impl<T> Source<T> {
28 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
29 Source { file_id: self.file_id, ast: f(self.ast) }
30 }
31 pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
32 db.parse_or_expand(self.file_id).expect("source created from invalid file")
33 }
34}
3 35
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct ModuleId { 37pub struct ModuleId {
@@ -12,3 +44,173 @@ pub struct ModuleId {
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 44#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct CrateModuleId(RawId); 45pub struct CrateModuleId(RawId);
14impl_arena_id!(CrateModuleId); 46impl_arena_id!(CrateModuleId);
47
48macro_rules! impl_intern_key {
49 ($name:ident) => {
50 impl salsa::InternKey for $name {
51 fn from_intern_id(v: salsa::InternId) -> Self {
52 $name(v)
53 }
54 fn as_intern_id(&self) -> salsa::InternId {
55 self.0
56 }
57 }
58 };
59}
60
61#[derive(Debug)]
62pub struct ItemLoc<N: AstNode> {
63 pub(crate) module: ModuleId,
64 ast_id: AstId<N>,
65}
66
67impl<N: AstNode> PartialEq for ItemLoc<N> {
68 fn eq(&self, other: &Self) -> bool {
69 self.module == other.module && self.ast_id == other.ast_id
70 }
71}
72impl<N: AstNode> Eq for ItemLoc<N> {}
73impl<N: AstNode> Hash for ItemLoc<N> {
74 fn hash<H: Hasher>(&self, hasher: &mut H) {
75 self.module.hash(hasher);
76 self.ast_id.hash(hasher);
77 }
78}
79
80impl<N: AstNode> Clone for ItemLoc<N> {
81 fn clone(&self) -> ItemLoc<N> {
82 ItemLoc { module: self.module, ast_id: self.ast_id }
83 }
84}
85
86#[derive(Clone, Copy)]
87pub struct LocationCtx<DB> {
88 db: DB,
89 module: ModuleId,
90 file_id: HirFileId,
91}
92
93impl<'a, DB> LocationCtx<&'a DB> {
94 pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> {
95 LocationCtx { db, module, file_id }
96 }
97}
98
99impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> {
100 pub fn to_def<N, DEF>(self, ast: &N) -> DEF
101 where
102 N: AstNode,
103 DEF: AstItemDef<N>,
104 {
105 DEF::from_ast(self, ast)
106 }
107}
108
109pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
110 fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
111 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;
112
113 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self {
114 let items = ctx.db.ast_id_map(ctx.file_id);
115 let item_id = items.ast_id(ast);
116 Self::from_ast_id(ctx, item_id)
117 }
118 fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
119 let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) };
120 Self::intern(ctx.db, loc)
121 }
122 fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> {
123 let loc = self.lookup_intern(db);
124 let ast = loc.ast_id.to_node(db);
125 Source { file_id: loc.ast_id.file_id(), ast }
126 }
127 fn module(self, db: &impl InternDatabase) -> ModuleId {
128 let loc = self.lookup_intern(db);
129 loc.module
130 }
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
134pub struct FunctionId(salsa::InternId);
135impl_intern_key!(FunctionId);
136
137impl AstItemDef<ast::FnDef> for FunctionId {
138 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
139 db.intern_function(loc)
140 }
141 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> {
142 db.lookup_intern_function(self)
143 }
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
147pub struct StructId(salsa::InternId);
148impl_intern_key!(StructId);
149impl AstItemDef<ast::StructDef> for StructId {
150 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
151 db.intern_struct(loc)
152 }
153 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
154 db.lookup_intern_struct(self)
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
159pub struct EnumId(salsa::InternId);
160impl_intern_key!(EnumId);
161impl AstItemDef<ast::EnumDef> for EnumId {
162 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
163 db.intern_enum(loc)
164 }
165 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
166 db.lookup_intern_enum(self)
167 }
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub struct ConstId(salsa::InternId);
172impl_intern_key!(ConstId);
173impl AstItemDef<ast::ConstDef> for ConstId {
174 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
175 db.intern_const(loc)
176 }
177 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> {
178 db.lookup_intern_const(self)
179 }
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
183pub struct StaticId(salsa::InternId);
184impl_intern_key!(StaticId);
185impl AstItemDef<ast::StaticDef> for StaticId {
186 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
187 db.intern_static(loc)
188 }
189 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> {
190 db.lookup_intern_static(self)
191 }
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
195pub struct TraitId(salsa::InternId);
196impl_intern_key!(TraitId);
197impl AstItemDef<ast::TraitDef> for TraitId {
198 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
199 db.intern_trait(loc)
200 }
201 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
202 db.lookup_intern_trait(self)
203 }
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
207pub struct TypeAliasId(salsa::InternId);
208impl_intern_key!(TypeAliasId);
209impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
210 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
211 db.intern_type_alias(loc)
212 }
213 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> {
214 db.lookup_intern_type_alias(self)
215 }
216}