diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/arena.rs | 66 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/function.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/function/scope.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 180 | ||||
-rw-r--r-- | crates/ra_hir/src/krate.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/macros.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/module.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 168 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0007_self.txt | 6 |
18 files changed, 486 insertions, 138 deletions
diff --git a/crates/ra_hir/src/arena.rs b/crates/ra_hir/src/arena.rs deleted file mode 100644 index d4f9d9cb9..000000000 --- a/crates/ra_hir/src/arena.rs +++ /dev/null | |||
@@ -1,66 +0,0 @@ | |||
1 | //! A simple id-based arena, similar to https://github.com/fitzgen/id-arena. | ||
2 | //! We use our own version for more compact id's and to allow inherent impls | ||
3 | //! on Ids. | ||
4 | |||
5 | use std::{ | ||
6 | fmt, | ||
7 | hash::{Hash, Hasher}, | ||
8 | marker::PhantomData, | ||
9 | }; | ||
10 | |||
11 | pub struct Id<T> { | ||
12 | idx: u32, | ||
13 | _ty: PhantomData<fn() -> T>, | ||
14 | } | ||
15 | |||
16 | impl<T> fmt::Debug for Id<T> { | ||
17 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
18 | f.debug_tuple("Id").field(&self.idx).finish() | ||
19 | } | ||
20 | } | ||
21 | impl<T> Copy for Id<T> {} | ||
22 | impl<T> Clone for Id<T> { | ||
23 | fn clone(&self) -> Id<T> { | ||
24 | *self | ||
25 | } | ||
26 | } | ||
27 | |||
28 | impl<T> PartialEq for Id<T> { | ||
29 | fn eq(&self, other: &Id<T>) -> bool { | ||
30 | self.idx == other.idx | ||
31 | } | ||
32 | } | ||
33 | |||
34 | impl<T> Eq for Id<T> {} | ||
35 | |||
36 | impl<T> Hash for Id<T> { | ||
37 | fn hash<H: Hasher>(&self, h: &mut H) { | ||
38 | self.idx.hash(h); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | #[derive(Debug, PartialEq, Eq)] | ||
43 | pub(crate) struct ArenaBehavior<T> { | ||
44 | _ty: PhantomData<T>, | ||
45 | } | ||
46 | |||
47 | impl<T> id_arena::ArenaBehavior for ArenaBehavior<T> { | ||
48 | type Id = Id<T>; | ||
49 | fn new_arena_id() -> u32 { | ||
50 | 0 | ||
51 | } | ||
52 | fn new_id(_arena_id: u32, index: usize) -> Id<T> { | ||
53 | Id { | ||
54 | idx: index as u32, | ||
55 | _ty: PhantomData, | ||
56 | } | ||
57 | } | ||
58 | fn index(id: Id<T>) -> usize { | ||
59 | id.idx as usize | ||
60 | } | ||
61 | fn arena_id(_id: Id<T>) -> u32 { | ||
62 | 0 | ||
63 | } | ||
64 | } | ||
65 | |||
66 | pub(crate) type Arena<T> = id_arena::Arena<T, ArenaBehavior<T>>; | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 73a4cdc5c..58296fc6f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -13,6 +13,7 @@ use crate::{ | |||
13 | nameres::{ItemMap, InputModuleItems}}, | 13 | nameres::{ItemMap, InputModuleItems}}, |
14 | ty::{InferenceResult, Ty}, | 14 | ty::{InferenceResult, Ty}, |
15 | adt::{StructData, EnumData}, | 15 | adt::{StructData, EnumData}, |
16 | impl_block::ModuleImplBlocks, | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | salsa::query_group! { | 19 | salsa::query_group! { |
@@ -87,6 +88,11 @@ pub trait HirDatabase: SyntaxDatabase | |||
87 | type ModuleTreeQuery; | 88 | type ModuleTreeQuery; |
88 | use fn crate::module::imp::module_tree; | 89 | use fn crate::module::imp::module_tree; |
89 | } | 90 | } |
91 | |||
92 | fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> { | ||
93 | type ImplsInModuleQuery; | ||
94 | use fn crate::impl_block::impls_in_module; | ||
95 | } | ||
90 | } | 96 | } |
91 | 97 | ||
92 | } | 98 | } |
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs index 5a44132fc..75ef308ae 100644 --- a/crates/ra_hir/src/function.rs +++ b/crates/ra_hir/src/function.rs | |||
@@ -11,11 +11,11 @@ use ra_syntax::{ | |||
11 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 11 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module}; | 14 | use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock}; |
15 | 15 | ||
16 | pub use self::scope::FnScopes; | 16 | pub use self::scope::FnScopes; |
17 | 17 | ||
18 | #[derive(Debug)] | 18 | #[derive(Debug, Clone, PartialEq, Eq)] |
19 | pub struct Function { | 19 | pub struct Function { |
20 | def_id: DefId, | 20 | def_id: DefId, |
21 | } | 21 | } |
@@ -25,6 +25,10 @@ impl Function { | |||
25 | Function { def_id } | 25 | Function { def_id } |
26 | } | 26 | } |
27 | 27 | ||
28 | pub fn def_id(&self) -> DefId { | ||
29 | self.def_id | ||
30 | } | ||
31 | |||
28 | pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { | 32 | pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { |
29 | let def_loc = self.def_id.loc(db); | 33 | let def_loc = self.def_id.loc(db); |
30 | assert!(def_loc.kind == DefKind::Function); | 34 | assert!(def_loc.kind == DefKind::Function); |
@@ -48,6 +52,15 @@ impl Function { | |||
48 | pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { | 52 | pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { |
49 | self.def_id.module(db) | 53 | self.def_id.module(db) |
50 | } | 54 | } |
55 | |||
56 | pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> { | ||
57 | self.def_id.krate(db) | ||
58 | } | ||
59 | |||
60 | /// The containing impl block, if this is a method. | ||
61 | pub fn impl_block(&self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> { | ||
62 | self.def_id.impl_block(db) | ||
63 | } | ||
51 | } | 64 | } |
52 | 65 | ||
53 | #[derive(Debug, Clone)] | 66 | #[derive(Debug, Clone)] |
diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs index 3e4cfad0c..42bfe4f32 100644 --- a/crates/ra_hir/src/function/scope.rs +++ b/crates/ra_hir/src/function/scope.rs | |||
@@ -5,19 +5,19 @@ use ra_syntax::{ | |||
5 | algo::generate, | 5 | algo::generate, |
6 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, | 6 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, |
7 | }; | 7 | }; |
8 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
8 | use ra_db::LocalSyntaxPtr; | 9 | use ra_db::LocalSyntaxPtr; |
9 | 10 | ||
10 | use crate::{ | 11 | use crate::{Name, AsName}; |
11 | arena::{Arena, Id}, | ||
12 | Name, AsName, | ||
13 | }; | ||
14 | 12 | ||
15 | pub(crate) type ScopeId = Id<ScopeData>; | 13 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
14 | pub struct ScopeId(RawId); | ||
15 | impl_arena_id!(ScopeId); | ||
16 | 16 | ||
17 | #[derive(Debug, PartialEq, Eq)] | 17 | #[derive(Debug, PartialEq, Eq)] |
18 | pub struct FnScopes { | 18 | pub struct FnScopes { |
19 | pub self_param: Option<LocalSyntaxPtr>, | 19 | pub self_param: Option<LocalSyntaxPtr>, |
20 | scopes: Arena<ScopeData>, | 20 | scopes: Arena<ScopeId, ScopeData>, |
21 | scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>, | 21 | scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>, |
22 | } | 22 | } |
23 | 23 | ||
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index a09dee8b1..4d6378e02 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -1,10 +1,8 @@ | |||
1 | use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId}; | 1 | use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId}; |
2 | use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; | 2 | use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; |
3 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
3 | 4 | ||
4 | use crate::{ | 5 | use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, ImplBlock, Crate}; |
5 | HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, | ||
6 | arena::{Arena, Id}, | ||
7 | }; | ||
8 | 6 | ||
9 | /// hir makes a heavy use of ids: integer (u32) handlers to various things. You | 7 | /// hir makes a heavy use of ids: integer (u32) handlers to various things. You |
10 | /// can think of id as a pointer (but without a lifetime) or a file descriptor | 8 | /// can think of id as a pointer (but without a lifetime) or a file descriptor |
@@ -48,6 +46,13 @@ impl HirFileId { | |||
48 | } | 46 | } |
49 | } | 47 | } |
50 | 48 | ||
49 | pub(crate) fn as_macro_call_id(self) -> Option<MacroCallId> { | ||
50 | match self.0 { | ||
51 | HirFileIdRepr::Macro(it) => Some(it), | ||
52 | _ => None, | ||
53 | } | ||
54 | } | ||
55 | |||
51 | pub(crate) fn hir_source_file(db: &impl HirDatabase, file_id: HirFileId) -> SourceFileNode { | 56 | pub(crate) fn hir_source_file(db: &impl HirDatabase, file_id: HirFileId) -> SourceFileNode { |
52 | match file_id.0 { | 57 | match file_id.0 { |
53 | HirFileIdRepr::File(file_id) => db.source_file(file_id), | 58 | HirFileIdRepr::File(file_id) => db.source_file(file_id), |
@@ -172,6 +177,18 @@ impl DefId { | |||
172 | let loc = self.loc(db); | 177 | let loc = self.loc(db); |
173 | Module::new(db, loc.source_root_id, loc.module_id) | 178 | Module::new(db, loc.source_root_id, loc.module_id) |
174 | } | 179 | } |
180 | |||
181 | /// Returns the containing crate. | ||
182 | pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> { | ||
183 | Ok(self.module(db)?.krate(db)) | ||
184 | } | ||
185 | |||
186 | /// Returns the containing impl block, if this is an impl item. | ||
187 | pub fn impl_block(self, db: &impl HirDatabase) -> Cancelable<Option<ImplBlock>> { | ||
188 | let loc = self.loc(db); | ||
189 | let module_impls = db.impls_in_module(loc.source_root_id, loc.module_id)?; | ||
190 | Ok(ImplBlock::containing(module_impls, self)) | ||
191 | } | ||
175 | } | 192 | } |
176 | 193 | ||
177 | impl DefLoc { | 194 | impl DefLoc { |
@@ -199,7 +216,9 @@ impl DefKind { | |||
199 | 216 | ||
200 | /// Identifier of item within a specific file. This is stable over reparses, so | 217 | /// Identifier of item within a specific file. This is stable over reparses, so |
201 | /// it's OK to use it as a salsa key/value. | 218 | /// it's OK to use it as a salsa key/value. |
202 | pub(crate) type SourceFileItemId = Id<SyntaxNode>; | 219 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
220 | pub struct SourceFileItemId(RawId); | ||
221 | impl_arena_id!(SourceFileItemId); | ||
203 | 222 | ||
204 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 223 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
205 | pub struct SourceItemId { | 224 | pub struct SourceItemId { |
@@ -212,7 +231,7 @@ pub struct SourceItemId { | |||
212 | #[derive(Debug, PartialEq, Eq)] | 231 | #[derive(Debug, PartialEq, Eq)] |
213 | pub struct SourceFileItems { | 232 | pub struct SourceFileItems { |
214 | file_id: HirFileId, | 233 | file_id: HirFileId, |
215 | arena: Arena<SyntaxNode>, | 234 | arena: Arena<SourceFileItemId, SyntaxNode>, |
216 | } | 235 | } |
217 | 236 | ||
218 | impl SourceFileItems { | 237 | impl SourceFileItems { |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs new file mode 100644 index 000000000..01afa84c4 --- /dev/null +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -0,0 +1,180 @@ | |||
1 | use std::sync::Arc; | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
5 | use ra_syntax::ast::{self, AstNode}; | ||
6 | use ra_db::{LocationIntener, Cancelable, SourceRootId}; | ||
7 | |||
8 | use crate::{ | ||
9 | DefId, DefLoc, DefKind, SourceItemId, SourceFileItems, | ||
10 | Module, Function, | ||
11 | db::HirDatabase, | ||
12 | type_ref::TypeRef, | ||
13 | module::{ModuleSourceNode, ModuleId}, | ||
14 | }; | ||
15 | |||
16 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
17 | pub struct ImplBlock { | ||
18 | module_impl_blocks: Arc<ModuleImplBlocks>, | ||
19 | impl_id: ImplId, | ||
20 | } | ||
21 | |||
22 | impl ImplBlock { | ||
23 | pub(crate) fn containing( | ||
24 | module_impl_blocks: Arc<ModuleImplBlocks>, | ||
25 | def_id: DefId, | ||
26 | ) -> Option<ImplBlock> { | ||
27 | let impl_id = *module_impl_blocks.impls_by_def.get(&def_id)?; | ||
28 | Some(ImplBlock { | ||
29 | module_impl_blocks, | ||
30 | impl_id, | ||
31 | }) | ||
32 | } | ||
33 | |||
34 | fn impl_data(&self) -> &ImplData { | ||
35 | &self.module_impl_blocks.impls[self.impl_id] | ||
36 | } | ||
37 | |||
38 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
39 | self.impl_data().target_trait.as_ref() | ||
40 | } | ||
41 | |||
42 | pub fn target_type(&self) -> &TypeRef { | ||
43 | &self.impl_data().target_type | ||
44 | } | ||
45 | |||
46 | pub fn items(&self) -> &[ImplItem] { | ||
47 | &self.impl_data().items | ||
48 | } | ||
49 | } | ||
50 | |||
51 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
52 | pub struct ImplData { | ||
53 | target_trait: Option<TypeRef>, | ||
54 | target_type: TypeRef, | ||
55 | items: Vec<ImplItem>, | ||
56 | } | ||
57 | |||
58 | impl ImplData { | ||
59 | pub(crate) fn from_ast( | ||
60 | db: &impl AsRef<LocationIntener<DefLoc, DefId>>, | ||
61 | file_items: &SourceFileItems, | ||
62 | module: &Module, | ||
63 | node: ast::ImplBlock, | ||
64 | ) -> Self { | ||
65 | let target_trait = node.target_type().map(TypeRef::from_ast); | ||
66 | let target_type = TypeRef::from_ast_opt(node.target_type()); | ||
67 | let file_id = module.source().file_id(); | ||
68 | let items = if let Some(item_list) = node.item_list() { | ||
69 | item_list | ||
70 | .impl_items() | ||
71 | .map(|item_node| { | ||
72 | let kind = match item_node { | ||
73 | ast::ImplItem::FnDef(..) => DefKind::Function, | ||
74 | ast::ImplItem::ConstDef(..) => DefKind::Item, | ||
75 | ast::ImplItem::TypeDef(..) => DefKind::Item, | ||
76 | }; | ||
77 | let item_id = file_items.id_of_unchecked(item_node.syntax()); | ||
78 | let def_loc = DefLoc { | ||
79 | kind, | ||
80 | source_root_id: module.source_root_id, | ||
81 | module_id: module.module_id, | ||
82 | source_item_id: SourceItemId { | ||
83 | file_id, | ||
84 | item_id: Some(item_id), | ||
85 | }, | ||
86 | }; | ||
87 | let def_id = def_loc.id(db); | ||
88 | match item_node { | ||
89 | ast::ImplItem::FnDef(..) => ImplItem::Method(Function::new(def_id)), | ||
90 | ast::ImplItem::ConstDef(..) => ImplItem::Const(def_id), | ||
91 | ast::ImplItem::TypeDef(..) => ImplItem::Type(def_id), | ||
92 | } | ||
93 | }) | ||
94 | .collect() | ||
95 | } else { | ||
96 | Vec::new() | ||
97 | }; | ||
98 | ImplData { | ||
99 | target_trait, | ||
100 | target_type, | ||
101 | items, | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | |||
106 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
107 | pub enum ImplItem { | ||
108 | Method(Function), | ||
109 | // these don't have their own types yet | ||
110 | Const(DefId), | ||
111 | Type(DefId), | ||
112 | // Existential | ||
113 | } | ||
114 | |||
115 | impl ImplItem { | ||
116 | pub fn def_id(&self) -> DefId { | ||
117 | match self { | ||
118 | ImplItem::Method(f) => f.def_id(), | ||
119 | ImplItem::Const(def_id) => *def_id, | ||
120 | ImplItem::Type(def_id) => *def_id, | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
126 | pub struct ImplId(pub RawId); | ||
127 | impl_arena_id!(ImplId); | ||
128 | |||
129 | /// Collection of impl blocks is a two-step process: First we collect the blocks | ||
130 | /// per-module; then we build an index of all impl blocks in the crate. This | ||
131 | /// way, we avoid having to do this process for the whole crate whenever someone | ||
132 | /// types in any file; as long as the impl blocks in the file don't change, we | ||
133 | /// don't need to do the second step again. | ||
134 | /// | ||
135 | /// (The second step does not yet exist currently.) | ||
136 | #[derive(Debug, PartialEq, Eq)] | ||
137 | pub struct ModuleImplBlocks { | ||
138 | impls: Arena<ImplId, ImplData>, | ||
139 | impls_by_def: FxHashMap<DefId, ImplId>, | ||
140 | } | ||
141 | |||
142 | impl ModuleImplBlocks { | ||
143 | fn new() -> Self { | ||
144 | ModuleImplBlocks { | ||
145 | impls: Arena::default(), | ||
146 | impls_by_def: FxHashMap::default(), | ||
147 | } | ||
148 | } | ||
149 | |||
150 | fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> { | ||
151 | let module_source_node = module.source().resolve(db); | ||
152 | let node = match &module_source_node { | ||
153 | ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(), | ||
154 | ModuleSourceNode::Module(node) => node.borrowed().syntax(), | ||
155 | }; | ||
156 | |||
157 | let source_file_items = db.file_items(module.source().file_id()); | ||
158 | |||
159 | for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { | ||
160 | let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast); | ||
161 | let id = self.impls.alloc(impl_block); | ||
162 | for impl_item in &self.impls[id].items { | ||
163 | self.impls_by_def.insert(impl_item.def_id(), id); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | Ok(()) | ||
168 | } | ||
169 | } | ||
170 | |||
171 | pub(crate) fn impls_in_module( | ||
172 | db: &impl HirDatabase, | ||
173 | source_root_id: SourceRootId, | ||
174 | module_id: ModuleId, | ||
175 | ) -> Cancelable<Arc<ModuleImplBlocks>> { | ||
176 | let mut result = ModuleImplBlocks::new(); | ||
177 | let module = Module::new(db, source_root_id, module_id)?; | ||
178 | result.collect(db, module)?; | ||
179 | Ok(Arc::new(result)) | ||
180 | } | ||
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs index a0821d15d..5194e280b 100644 --- a/crates/ra_hir/src/krate.rs +++ b/crates/ra_hir/src/krate.rs | |||
@@ -5,7 +5,7 @@ use crate::{HirDatabase, Module, Name, AsName, HirFileId}; | |||
5 | /// hir::Crate describes a single crate. It's the main inteface with which | 5 | /// hir::Crate describes a single crate. It's the main inteface with which |
6 | /// crate's dependencies interact. Mostly, it should be just a proxy for the | 6 | /// crate's dependencies interact. Mostly, it should be just a proxy for the |
7 | /// root module. | 7 | /// root module. |
8 | #[derive(Debug)] | 8 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
9 | pub struct Crate { | 9 | pub struct Crate { |
10 | crate_id: CrateId, | 10 | crate_id: CrateId, |
11 | } | 11 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 8ee52a466..2abcec441 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -19,7 +19,6 @@ pub mod db; | |||
19 | mod mock; | 19 | mod mock; |
20 | mod query_definitions; | 20 | mod query_definitions; |
21 | mod path; | 21 | mod path; |
22 | mod arena; | ||
23 | pub mod source_binder; | 22 | pub mod source_binder; |
24 | 23 | ||
25 | mod ids; | 24 | mod ids; |
@@ -32,6 +31,7 @@ mod function; | |||
32 | mod adt; | 31 | mod adt; |
33 | mod type_ref; | 32 | mod type_ref; |
34 | mod ty; | 33 | mod ty; |
34 | mod impl_block; | ||
35 | 35 | ||
36 | use crate::{ | 36 | use crate::{ |
37 | db::HirDatabase, | 37 | db::HirDatabase, |
@@ -49,6 +49,7 @@ pub use self::{ | |||
49 | function::{Function, FnScopes}, | 49 | function::{Function, FnScopes}, |
50 | adt::{Struct, Enum}, | 50 | adt::{Struct, Enum}, |
51 | ty::Ty, | 51 | ty::Ty, |
52 | impl_block::{ImplBlock, ImplItem}, | ||
52 | }; | 53 | }; |
53 | 54 | ||
54 | pub use self::function::FnSignatureInfo; | 55 | pub use self::function::FnSignatureInfo; |
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs index b7b75e702..1b378c977 100644 --- a/crates/ra_hir/src/macros.rs +++ b/crates/ra_hir/src/macros.rs | |||
@@ -21,6 +21,7 @@ use crate::{HirDatabase, MacroCallId}; | |||
21 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 21 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
22 | pub enum MacroDef { | 22 | pub enum MacroDef { |
23 | CTry, | 23 | CTry, |
24 | Vec, | ||
24 | QueryGroup, | 25 | QueryGroup, |
25 | } | 26 | } |
26 | 27 | ||
@@ -40,6 +41,8 @@ impl MacroDef { | |||
40 | let name_ref = path.segment()?.name_ref()?; | 41 | let name_ref = path.segment()?.name_ref()?; |
41 | if name_ref.text() == "ctry" { | 42 | if name_ref.text() == "ctry" { |
42 | MacroDef::CTry | 43 | MacroDef::CTry |
44 | } else if name_ref.text() == "vec" { | ||
45 | MacroDef::Vec | ||
43 | } else if name_ref.text() == "query_group" { | 46 | } else if name_ref.text() == "query_group" { |
44 | MacroDef::QueryGroup | 47 | MacroDef::QueryGroup |
45 | } else { | 48 | } else { |
@@ -59,6 +62,7 @@ impl MacroDef { | |||
59 | fn expand(self, input: MacroInput) -> Option<MacroExpansion> { | 62 | fn expand(self, input: MacroInput) -> Option<MacroExpansion> { |
60 | match self { | 63 | match self { |
61 | MacroDef::CTry => self.expand_ctry(input), | 64 | MacroDef::CTry => self.expand_ctry(input), |
65 | MacroDef::Vec => self.expand_vec(input), | ||
62 | MacroDef::QueryGroup => self.expand_query_group(input), | 66 | MacroDef::QueryGroup => self.expand_query_group(input), |
63 | } | 67 | } |
64 | } | 68 | } |
@@ -86,6 +90,20 @@ impl MacroDef { | |||
86 | }; | 90 | }; |
87 | Some(res) | 91 | Some(res) |
88 | } | 92 | } |
93 | fn expand_vec(self, input: MacroInput) -> Option<MacroExpansion> { | ||
94 | let text = format!(r"fn dummy() {{ {}; }}", input.text); | ||
95 | let file = SourceFileNode::parse(&text); | ||
96 | let array_expr = file.syntax().descendants().find_map(ast::ArrayExpr::cast)?; | ||
97 | let ptr = LocalSyntaxPtr::new(array_expr.syntax()); | ||
98 | let src_range = TextRange::offset_len(0.into(), TextUnit::of_str(&input.text)); | ||
99 | let ranges_map = vec![(src_range, array_expr.syntax().range())]; | ||
100 | let res = MacroExpansion { | ||
101 | text, | ||
102 | ranges_map, | ||
103 | ptr, | ||
104 | }; | ||
105 | Some(res) | ||
106 | } | ||
89 | fn expand_query_group(self, input: MacroInput) -> Option<MacroExpansion> { | 107 | fn expand_query_group(self, input: MacroInput) -> Option<MacroExpansion> { |
90 | let anchor = "trait "; | 108 | let anchor = "trait "; |
91 | let pos = input.text.find(anchor)? + anchor.len(); | 109 | let pos = input.text.find(anchor)? + anchor.len(); |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 89b18194a..a9db932ff 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -30,6 +30,10 @@ impl MockDatabase { | |||
30 | let file_id = db.add_file(&mut source_root, "/main.rs", text); | 30 | let file_id = db.add_file(&mut source_root, "/main.rs", text); |
31 | db.query_mut(ra_db::SourceRootQuery) | 31 | db.query_mut(ra_db::SourceRootQuery) |
32 | .set(WORKSPACE, Arc::new(source_root.clone())); | 32 | .set(WORKSPACE, Arc::new(source_root.clone())); |
33 | |||
34 | let mut crate_graph = CrateGraph::default(); | ||
35 | crate_graph.add_crate_root(file_id); | ||
36 | db.set_crate_graph(crate_graph); | ||
33 | (db, source_root, file_id) | 37 | (db, source_root, file_id) |
34 | } | 38 | } |
35 | 39 | ||
@@ -203,6 +207,7 @@ salsa::database_storage! { | |||
203 | fn type_for_field() for db::TypeForFieldQuery; | 207 | fn type_for_field() for db::TypeForFieldQuery; |
204 | fn struct_data() for db::StructDataQuery; | 208 | fn struct_data() for db::StructDataQuery; |
205 | fn enum_data() for db::EnumDataQuery; | 209 | fn enum_data() for db::EnumDataQuery; |
210 | fn impls_in_module() for db::ImplsInModuleQuery; | ||
206 | } | 211 | } |
207 | } | 212 | } |
208 | } | 213 | } |
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index a53b69d20..b9821115c 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs | |||
@@ -9,6 +9,7 @@ use ra_syntax::{ | |||
9 | ast::{self, AstNode, NameOwner}, | 9 | ast::{self, AstNode, NameOwner}, |
10 | SyntaxNode, | 10 | SyntaxNode, |
11 | }; | 11 | }; |
12 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
12 | use ra_db::{SourceRootId, FileId, Cancelable}; | 13 | use ra_db::{SourceRootId, FileId, Cancelable}; |
13 | use relative_path::RelativePathBuf; | 14 | use relative_path::RelativePathBuf; |
14 | 15 | ||
@@ -16,7 +17,6 @@ use crate::{ | |||
16 | Def, DefKind, DefLoc, DefId, | 17 | Def, DefKind, DefLoc, DefId, |
17 | Name, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate, | 18 | Name, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate, |
18 | HirFileId, | 19 | HirFileId, |
19 | arena::{Arena, Id}, | ||
20 | }; | 20 | }; |
21 | 21 | ||
22 | pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs}; | 22 | pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs}; |
@@ -71,6 +71,21 @@ impl Module { | |||
71 | }) | 71 | }) |
72 | } | 72 | } |
73 | 73 | ||
74 | /// Returns an iterator of all children of this module. | ||
75 | pub fn children<'a>(&'a self) -> impl Iterator<Item = (Name, Module)> + 'a { | ||
76 | self.module_id | ||
77 | .children(&self.tree) | ||
78 | .map(move |(name, module_id)| { | ||
79 | ( | ||
80 | name, | ||
81 | Module { | ||
82 | module_id, | ||
83 | ..self.clone() | ||
84 | }, | ||
85 | ) | ||
86 | }) | ||
87 | } | ||
88 | |||
74 | /// Returns the crate this module is part of. | 89 | /// Returns the crate this module is part of. |
75 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | 90 | pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { |
76 | let root_id = self.module_id.crate_root(&self.tree); | 91 | let root_id = self.module_id.crate_root(&self.tree); |
@@ -173,6 +188,14 @@ impl Module { | |||
173 | } | 188 | } |
174 | } | 189 | } |
175 | 190 | ||
191 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
192 | pub struct ModuleId(RawId); | ||
193 | impl_arena_id!(ModuleId); | ||
194 | |||
195 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
196 | pub struct LinkId(RawId); | ||
197 | impl_arena_id!(LinkId); | ||
198 | |||
176 | /// Physically, rust source is organized as a set of files, but logically it is | 199 | /// Physically, rust source is organized as a set of files, but logically it is |
177 | /// organized as a tree of modules. Usually, a single file corresponds to a | 200 | /// organized as a tree of modules. Usually, a single file corresponds to a |
178 | /// single module, but it is not nessary the case. | 201 | /// single module, but it is not nessary the case. |
@@ -182,8 +205,8 @@ impl Module { | |||
182 | /// always have one parent). | 205 | /// always have one parent). |
183 | #[derive(Default, Debug, PartialEq, Eq)] | 206 | #[derive(Default, Debug, PartialEq, Eq)] |
184 | pub struct ModuleTree { | 207 | pub struct ModuleTree { |
185 | mods: Arena<ModuleData>, | 208 | mods: Arena<ModuleId, ModuleData>, |
186 | links: Arena<LinkData>, | 209 | links: Arena<LinkId, LinkData>, |
187 | } | 210 | } |
188 | 211 | ||
189 | impl ModuleTree { | 212 | impl ModuleTree { |
@@ -210,9 +233,6 @@ pub(crate) enum ModuleSourceNode { | |||
210 | Module(ast::ModuleNode), | 233 | Module(ast::ModuleNode), |
211 | } | 234 | } |
212 | 235 | ||
213 | pub type ModuleId = Id<ModuleData>; | ||
214 | type LinkId = Id<LinkData>; | ||
215 | |||
216 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 236 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
217 | pub enum Problem { | 237 | pub enum Problem { |
218 | UnresolvedModule { | 238 | UnresolvedModule { |
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 40aa33ffa..3c6851a0a 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -64,14 +64,14 @@ impl ModuleScope { | |||
64 | /// running name resolution. | 64 | /// running name resolution. |
65 | #[derive(Debug, Default, PartialEq, Eq)] | 65 | #[derive(Debug, Default, PartialEq, Eq)] |
66 | pub struct InputModuleItems { | 66 | pub struct InputModuleItems { |
67 | items: Vec<ModuleItem>, | 67 | pub(crate) items: Vec<ModuleItem>, |
68 | imports: Vec<Import>, | 68 | imports: Vec<Import>, |
69 | } | 69 | } |
70 | 70 | ||
71 | #[derive(Debug, PartialEq, Eq)] | 71 | #[derive(Debug, PartialEq, Eq)] |
72 | struct ModuleItem { | 72 | pub(crate) struct ModuleItem { |
73 | id: SourceItemId, | 73 | pub(crate) id: SourceItemId, |
74 | name: Name, | 74 | pub(crate) name: Name, |
75 | kind: SyntaxKind, | 75 | kind: SyntaxKind, |
76 | vis: Vis, | 76 | vis: Vis, |
77 | } | 77 | } |
@@ -233,7 +233,7 @@ impl InputModuleItems { | |||
233 | ast::ModuleItem::TypeDef(it) => { | 233 | ast::ModuleItem::TypeDef(it) => { |
234 | self.items.push(ModuleItem::new(file_id, file_items, it)?) | 234 | self.items.push(ModuleItem::new(file_id, file_items, it)?) |
235 | } | 235 | } |
236 | ast::ModuleItem::ImplItem(_) => { | 236 | ast::ModuleItem::ImplBlock(_) => { |
237 | // impls don't define items | 237 | // impls don't define items |
238 | } | 238 | } |
239 | ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it), | 239 | ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it), |
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 51e8b3da8..017caf442 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -51,6 +51,7 @@ impl Name { | |||
51 | "u128" => KnownName::U128, | 51 | "u128" => KnownName::U128, |
52 | "f32" => KnownName::F32, | 52 | "f32" => KnownName::F32, |
53 | "f64" => KnownName::F64, | 53 | "f64" => KnownName::F64, |
54 | "Self" => KnownName::Self_, | ||
54 | _ => return None, | 55 | _ => return None, |
55 | }; | 56 | }; |
56 | Some(name) | 57 | Some(name) |
@@ -84,7 +85,7 @@ impl AsName for ra_db::Dependency { | |||
84 | // const ISIZE: Name = Name::new("isize") | 85 | // const ISIZE: Name = Name::new("isize") |
85 | // ``` | 86 | // ``` |
86 | // but const-fn is not that powerful yet. | 87 | // but const-fn is not that powerful yet. |
87 | #[derive(Debug)] | 88 | #[derive(Debug, PartialEq, Eq)] |
88 | pub(crate) enum KnownName { | 89 | pub(crate) enum KnownName { |
89 | Isize, | 90 | Isize, |
90 | I8, | 91 | I8, |
@@ -102,4 +103,6 @@ pub(crate) enum KnownName { | |||
102 | 103 | ||
103 | F32, | 104 | F32, |
104 | F64, | 105 | F64, |
106 | |||
107 | Self_, | ||
105 | } | 108 | } |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 93f7203fe..9fdfa0d13 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -70,6 +70,11 @@ impl Path { | |||
70 | self.kind == PathKind::Plain && self.segments.len() == 1 | 70 | self.kind == PathKind::Plain && self.segments.len() == 1 |
71 | } | 71 | } |
72 | 72 | ||
73 | /// `true` if this path is just a standalone `self` | ||
74 | pub fn is_self(&self) -> bool { | ||
75 | self.kind == PathKind::Self_ && self.segments.len() == 0 | ||
76 | } | ||
77 | |||
73 | /// If this path is a single identifier, like `foo`, return its name. | 78 | /// If this path is a single identifier, like `foo`, return its name. |
74 | pub fn as_ident(&self) -> Option<&Name> { | 79 | pub fn as_ident(&self) -> Option<&Name> { |
75 | if self.kind != PathKind::Plain || self.segments.len() > 1 { | 80 | if self.kind != PathKind::Plain || self.segments.len() > 1 { |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 24490d119..85bd84469 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -8,8 +8,8 @@ | |||
8 | use ra_db::{FileId, FilePosition, Cancelable}; | 8 | use ra_db::{FileId, FilePosition, Cancelable}; |
9 | use ra_editor::find_node_at_offset; | 9 | use ra_editor::find_node_at_offset; |
10 | use ra_syntax::{ | 10 | use ra_syntax::{ |
11 | SmolStr, TextRange, SyntaxNodeRef, | ||
11 | ast::{self, AstNode, NameOwner}, | 12 | ast::{self, AstNode, NameOwner}, |
12 | SyntaxNodeRef, | ||
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
@@ -126,3 +126,40 @@ pub fn function_from_child_node( | |||
126 | let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast)); | 126 | let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast)); |
127 | function_from_source(db, file_id, fn_def) | 127 | function_from_source(db, file_id, fn_def) |
128 | } | 128 | } |
129 | |||
130 | pub fn macro_symbols( | ||
131 | db: &impl HirDatabase, | ||
132 | file_id: FileId, | ||
133 | ) -> Cancelable<Vec<(SmolStr, TextRange)>> { | ||
134 | let module = match module_from_file_id(db, file_id)? { | ||
135 | Some(it) => it, | ||
136 | None => return Ok(Vec::new()), | ||
137 | }; | ||
138 | let items = db.input_module_items(module.source_root_id, module.module_id)?; | ||
139 | let mut res = Vec::new(); | ||
140 | |||
141 | for macro_call_id in items | ||
142 | .items | ||
143 | .iter() | ||
144 | .filter_map(|it| it.id.file_id.as_macro_call_id()) | ||
145 | { | ||
146 | if let Some(exp) = db.expand_macro_invocation(macro_call_id) { | ||
147 | let loc = macro_call_id.loc(db); | ||
148 | let syntax = db.file_item(loc.source_item_id); | ||
149 | let syntax = syntax.borrowed(); | ||
150 | let macro_call = ast::MacroCall::cast(syntax).unwrap(); | ||
151 | let off = macro_call.token_tree().unwrap().syntax().range().start(); | ||
152 | let file = exp.file(); | ||
153 | for trait_def in file.syntax().descendants().filter_map(ast::TraitDef::cast) { | ||
154 | if let Some(name) = trait_def.name() { | ||
155 | let dst_range = name.syntax().range(); | ||
156 | if let Some(src_range) = exp.map_range_back(dst_range) { | ||
157 | res.push((name.text(), src_range + off)) | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | |||
164 | Ok(res) | ||
165 | } | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 719b3f7cd..e33762e0d 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -31,9 +31,10 @@ use ra_syntax::{ | |||
31 | }; | 31 | }; |
32 | 32 | ||
33 | use crate::{ | 33 | use crate::{ |
34 | Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, | 34 | Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock, |
35 | db::HirDatabase, | 35 | db::HirDatabase, |
36 | type_ref::{TypeRef, Mutability}, | 36 | type_ref::{TypeRef, Mutability}, |
37 | name::KnownName, | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | /// The ID of a type variable. | 40 | /// The ID of a type variable. |
@@ -235,6 +236,7 @@ impl Ty { | |||
235 | pub(crate) fn from_hir( | 236 | pub(crate) fn from_hir( |
236 | db: &impl HirDatabase, | 237 | db: &impl HirDatabase, |
237 | module: &Module, | 238 | module: &Module, |
239 | impl_block: Option<&ImplBlock>, | ||
238 | type_ref: &TypeRef, | 240 | type_ref: &TypeRef, |
239 | ) -> Cancelable<Self> { | 241 | ) -> Cancelable<Self> { |
240 | Ok(match type_ref { | 242 | Ok(match type_ref { |
@@ -242,29 +244,29 @@ impl Ty { | |||
242 | TypeRef::Tuple(inner) => { | 244 | TypeRef::Tuple(inner) => { |
243 | let inner_tys = inner | 245 | let inner_tys = inner |
244 | .iter() | 246 | .iter() |
245 | .map(|tr| Ty::from_hir(db, module, tr)) | 247 | .map(|tr| Ty::from_hir(db, module, impl_block, tr)) |
246 | .collect::<Cancelable<Vec<_>>>()?; | 248 | .collect::<Cancelable<Vec<_>>>()?; |
247 | Ty::Tuple(inner_tys.into()) | 249 | Ty::Tuple(inner_tys.into()) |
248 | } | 250 | } |
249 | TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?, | 251 | TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, path)?, |
250 | TypeRef::RawPtr(inner, mutability) => { | 252 | TypeRef::RawPtr(inner, mutability) => { |
251 | let inner_ty = Ty::from_hir(db, module, inner)?; | 253 | let inner_ty = Ty::from_hir(db, module, impl_block, inner)?; |
252 | Ty::RawPtr(Arc::new(inner_ty), *mutability) | 254 | Ty::RawPtr(Arc::new(inner_ty), *mutability) |
253 | } | 255 | } |
254 | TypeRef::Array(_inner) => Ty::Unknown, // TODO | 256 | TypeRef::Array(_inner) => Ty::Unknown, // TODO |
255 | TypeRef::Slice(inner) => { | 257 | TypeRef::Slice(inner) => { |
256 | let inner_ty = Ty::from_hir(db, module, inner)?; | 258 | let inner_ty = Ty::from_hir(db, module, impl_block, inner)?; |
257 | Ty::Slice(Arc::new(inner_ty)) | 259 | Ty::Slice(Arc::new(inner_ty)) |
258 | } | 260 | } |
259 | TypeRef::Reference(inner, mutability) => { | 261 | TypeRef::Reference(inner, mutability) => { |
260 | let inner_ty = Ty::from_hir(db, module, inner)?; | 262 | let inner_ty = Ty::from_hir(db, module, impl_block, inner)?; |
261 | Ty::Ref(Arc::new(inner_ty), *mutability) | 263 | Ty::Ref(Arc::new(inner_ty), *mutability) |
262 | } | 264 | } |
263 | TypeRef::Placeholder => Ty::Unknown, | 265 | TypeRef::Placeholder => Ty::Unknown, |
264 | TypeRef::Fn(params) => { | 266 | TypeRef::Fn(params) => { |
265 | let mut inner_tys = params | 267 | let mut inner_tys = params |
266 | .iter() | 268 | .iter() |
267 | .map(|tr| Ty::from_hir(db, module, tr)) | 269 | .map(|tr| Ty::from_hir(db, module, impl_block, tr)) |
268 | .collect::<Cancelable<Vec<_>>>()?; | 270 | .collect::<Cancelable<Vec<_>>>()?; |
269 | let return_ty = inner_tys | 271 | let return_ty = inner_tys |
270 | .pop() | 272 | .pop() |
@@ -279,9 +281,21 @@ impl Ty { | |||
279 | }) | 281 | }) |
280 | } | 282 | } |
281 | 283 | ||
284 | pub(crate) fn from_hir_opt( | ||
285 | db: &impl HirDatabase, | ||
286 | module: &Module, | ||
287 | impl_block: Option<&ImplBlock>, | ||
288 | type_ref: Option<&TypeRef>, | ||
289 | ) -> Cancelable<Self> { | ||
290 | type_ref | ||
291 | .map(|t| Ty::from_hir(db, module, impl_block, t)) | ||
292 | .unwrap_or(Ok(Ty::Unknown)) | ||
293 | } | ||
294 | |||
282 | pub(crate) fn from_hir_path( | 295 | pub(crate) fn from_hir_path( |
283 | db: &impl HirDatabase, | 296 | db: &impl HirDatabase, |
284 | module: &Module, | 297 | module: &Module, |
298 | impl_block: Option<&ImplBlock>, | ||
285 | path: &Path, | 299 | path: &Path, |
286 | ) -> Cancelable<Self> { | 300 | ) -> Cancelable<Self> { |
287 | if let Some(name) = path.as_ident() { | 301 | if let Some(name) = path.as_ident() { |
@@ -291,6 +305,8 @@ impl Ty { | |||
291 | return Ok(Ty::Uint(uint_ty)); | 305 | return Ok(Ty::Uint(uint_ty)); |
292 | } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { | 306 | } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { |
293 | return Ok(Ty::Float(float_ty)); | 307 | return Ok(Ty::Float(float_ty)); |
308 | } else if name.as_known_name() == Some(KnownName::Self_) { | ||
309 | return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); | ||
294 | } | 310 | } |
295 | } | 311 | } |
296 | 312 | ||
@@ -308,18 +324,20 @@ impl Ty { | |||
308 | pub(crate) fn from_ast_opt( | 324 | pub(crate) fn from_ast_opt( |
309 | db: &impl HirDatabase, | 325 | db: &impl HirDatabase, |
310 | module: &Module, | 326 | module: &Module, |
327 | impl_block: Option<&ImplBlock>, | ||
311 | node: Option<ast::TypeRef>, | 328 | node: Option<ast::TypeRef>, |
312 | ) -> Cancelable<Self> { | 329 | ) -> Cancelable<Self> { |
313 | node.map(|n| Ty::from_ast(db, module, n)) | 330 | node.map(|n| Ty::from_ast(db, module, impl_block, n)) |
314 | .unwrap_or(Ok(Ty::Unknown)) | 331 | .unwrap_or(Ok(Ty::Unknown)) |
315 | } | 332 | } |
316 | 333 | ||
317 | pub(crate) fn from_ast( | 334 | pub(crate) fn from_ast( |
318 | db: &impl HirDatabase, | 335 | db: &impl HirDatabase, |
319 | module: &Module, | 336 | module: &Module, |
337 | impl_block: Option<&ImplBlock>, | ||
320 | node: ast::TypeRef, | 338 | node: ast::TypeRef, |
321 | ) -> Cancelable<Self> { | 339 | ) -> Cancelable<Self> { |
322 | Ty::from_hir(db, module, &TypeRef::from_ast(node)) | 340 | Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node)) |
323 | } | 341 | } |
324 | 342 | ||
325 | pub fn unit() -> Self { | 343 | pub fn unit() -> Self { |
@@ -402,18 +420,19 @@ impl fmt::Display for Ty { | |||
402 | fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { | 420 | fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { |
403 | let syntax = f.syntax(db); | 421 | let syntax = f.syntax(db); |
404 | let module = f.module(db)?; | 422 | let module = f.module(db)?; |
423 | let impl_block = f.impl_block(db)?; | ||
405 | let node = syntax.borrowed(); | 424 | let node = syntax.borrowed(); |
406 | // TODO we ignore type parameters for now | 425 | // TODO we ignore type parameters for now |
407 | let input = node | 426 | let input = node |
408 | .param_list() | 427 | .param_list() |
409 | .map(|pl| { | 428 | .map(|pl| { |
410 | pl.params() | 429 | pl.params() |
411 | .map(|p| Ty::from_ast_opt(db, &module, p.type_ref())) | 430 | .map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref())) |
412 | .collect() | 431 | .collect() |
413 | }) | 432 | }) |
414 | .unwrap_or_else(|| Ok(Vec::new()))?; | 433 | .unwrap_or_else(|| Ok(Vec::new()))?; |
415 | let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) { | 434 | let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) { |
416 | Ty::from_ast(db, &module, type_ref)? | 435 | Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)? |
417 | } else { | 436 | } else { |
418 | Ty::unit() | 437 | Ty::unit() |
419 | }; | 438 | }; |
@@ -467,12 +486,13 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) | |||
467 | ), | 486 | ), |
468 | }; | 487 | }; |
469 | let module = def_id.module(db)?; | 488 | let module = def_id.module(db)?; |
489 | let impl_block = def_id.impl_block(db)?; | ||
470 | let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) { | 490 | let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) { |
471 | tr | 491 | tr |
472 | } else { | 492 | } else { |
473 | return Ok(Ty::Unknown); | 493 | return Ok(Ty::Unknown); |
474 | }; | 494 | }; |
475 | Ty::from_hir(db, &module, &type_ref) | 495 | Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref) |
476 | } | 496 | } |
477 | 497 | ||
478 | /// The result of type inference: A mapping from expressions and patterns to types. | 498 | /// The result of type inference: A mapping from expressions and patterns to types. |
@@ -496,19 +516,32 @@ impl InferenceResult { | |||
496 | struct InferenceContext<'a, D: HirDatabase> { | 516 | struct InferenceContext<'a, D: HirDatabase> { |
497 | db: &'a D, | 517 | db: &'a D, |
498 | scopes: Arc<FnScopes>, | 518 | scopes: Arc<FnScopes>, |
519 | /// The self param for the current method, if it exists. | ||
520 | self_param: Option<LocalSyntaxPtr>, | ||
499 | module: Module, | 521 | module: Module, |
522 | impl_block: Option<ImplBlock>, | ||
500 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 523 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
501 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | 524 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, |
525 | /// The return type of the function being inferred. | ||
526 | return_ty: Ty, | ||
502 | } | 527 | } |
503 | 528 | ||
504 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 529 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
505 | fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self { | 530 | fn new( |
531 | db: &'a D, | ||
532 | scopes: Arc<FnScopes>, | ||
533 | module: Module, | ||
534 | impl_block: Option<ImplBlock>, | ||
535 | ) -> Self { | ||
506 | InferenceContext { | 536 | InferenceContext { |
507 | type_of: FxHashMap::default(), | 537 | type_of: FxHashMap::default(), |
508 | var_unification_table: InPlaceUnificationTable::new(), | 538 | var_unification_table: InPlaceUnificationTable::new(), |
539 | self_param: None, // set during parameter typing | ||
540 | return_ty: Ty::Unknown, // set in collect_fn_signature | ||
509 | db, | 541 | db, |
510 | scopes, | 542 | scopes, |
511 | module, | 543 | module, |
544 | impl_block, | ||
512 | } | 545 | } |
513 | } | 546 | } |
514 | 547 | ||
@@ -525,6 +558,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
525 | self.type_of.insert(LocalSyntaxPtr::new(node), ty); | 558 | self.type_of.insert(LocalSyntaxPtr::new(node), ty); |
526 | } | 559 | } |
527 | 560 | ||
561 | fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> { | ||
562 | Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref) | ||
563 | } | ||
564 | |||
565 | fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> { | ||
566 | Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref) | ||
567 | } | ||
568 | |||
528 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 569 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
529 | match (ty1, ty2) { | 570 | match (ty1, ty2) { |
530 | (Ty::Unknown, ..) => true, | 571 | (Ty::Unknown, ..) => true, |
@@ -628,6 +669,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
628 | let ty = self.resolve_ty_as_possible(ty.clone()); | 669 | let ty = self.resolve_ty_as_possible(ty.clone()); |
629 | return Ok(Some(ty)); | 670 | return Ok(Some(ty)); |
630 | }; | 671 | }; |
672 | } else if path.is_self() { | ||
673 | // resolve `self` param | ||
674 | let self_param = ctry!(self.self_param); | ||
675 | let ty = ctry!(self.type_of.get(&self_param)); | ||
676 | let ty = self.resolve_ty_as_possible(ty.clone()); | ||
677 | return Ok(Some(ty)); | ||
631 | }; | 678 | }; |
632 | 679 | ||
633 | // resolve in module | 680 | // resolve in module |
@@ -826,7 +873,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
826 | } | 873 | } |
827 | ast::Expr::CastExpr(e) => { | 874 | ast::Expr::CastExpr(e) => { |
828 | let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 875 | let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; |
829 | let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?; | 876 | let cast_ty = Ty::from_ast_opt( |
877 | self.db, | ||
878 | &self.module, | ||
879 | self.impl_block.as_ref(), | ||
880 | e.type_ref(), | ||
881 | )?; | ||
830 | let cast_ty = self.insert_type_vars(cast_ty); | 882 | let cast_ty = self.insert_type_vars(cast_ty); |
831 | // TODO do the coercion... | 883 | // TODO do the coercion... |
832 | cast_ty | 884 | cast_ty |
@@ -880,7 +932,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
880 | for stmt in node.statements() { | 932 | for stmt in node.statements() { |
881 | match stmt { | 933 | match stmt { |
882 | ast::Stmt::LetStmt(stmt) => { | 934 | ast::Stmt::LetStmt(stmt) => { |
883 | let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?; | 935 | let decl_ty = Ty::from_ast_opt( |
936 | self.db, | ||
937 | &self.module, | ||
938 | self.impl_block.as_ref(), | ||
939 | stmt.type_ref(), | ||
940 | )?; | ||
884 | let decl_ty = self.insert_type_vars(decl_ty); | 941 | let decl_ty = self.insert_type_vars(decl_ty); |
885 | let ty = if let Some(expr) = stmt.initializer() { | 942 | let ty = if let Some(expr) = stmt.initializer() { |
886 | let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; | 943 | let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; |
@@ -906,46 +963,71 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
906 | self.write_ty(node.syntax(), ty.clone()); | 963 | self.write_ty(node.syntax(), ty.clone()); |
907 | Ok(ty) | 964 | Ok(ty) |
908 | } | 965 | } |
966 | |||
967 | fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> { | ||
968 | if let Some(param_list) = node.param_list() { | ||
969 | if let Some(self_param) = param_list.self_param() { | ||
970 | let self_type = if let Some(type_ref) = self_param.type_ref() { | ||
971 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; | ||
972 | self.insert_type_vars(ty) | ||
973 | } else { | ||
974 | // TODO this should be handled by desugaring during HIR conversion | ||
975 | let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target_type()))?; | ||
976 | let ty = match self_param.flavor() { | ||
977 | ast::SelfParamFlavor::Owned => ty, | ||
978 | ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared), | ||
979 | ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut), | ||
980 | }; | ||
981 | self.insert_type_vars(ty) | ||
982 | }; | ||
983 | if let Some(self_kw) = self_param.self_kw() { | ||
984 | let self_param = LocalSyntaxPtr::new(self_kw.syntax()); | ||
985 | self.self_param = Some(self_param); | ||
986 | self.type_of.insert(self_param, self_type); | ||
987 | } | ||
988 | } | ||
989 | for param in param_list.params() { | ||
990 | let pat = if let Some(pat) = param.pat() { | ||
991 | pat | ||
992 | } else { | ||
993 | continue; | ||
994 | }; | ||
995 | let ty = if let Some(type_ref) = param.type_ref() { | ||
996 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; | ||
997 | self.insert_type_vars(ty) | ||
998 | } else { | ||
999 | // missing type annotation | ||
1000 | self.new_type_var() | ||
1001 | }; | ||
1002 | self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); | ||
1003 | } | ||
1004 | } | ||
1005 | |||
1006 | self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { | ||
1007 | let ty = self.make_ty(&TypeRef::from_ast(type_ref))?; | ||
1008 | self.insert_type_vars(ty) | ||
1009 | } else { | ||
1010 | Ty::unit() | ||
1011 | }; | ||
1012 | |||
1013 | Ok(()) | ||
1014 | } | ||
909 | } | 1015 | } |
910 | 1016 | ||
911 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { | 1017 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { |
912 | let function = Function::new(def_id); // TODO: consts also need inference | 1018 | let function = Function::new(def_id); // TODO: consts also need inference |
913 | let scopes = function.scopes(db); | 1019 | let scopes = function.scopes(db); |
914 | let module = function.module(db)?; | 1020 | let module = function.module(db)?; |
915 | let mut ctx = InferenceContext::new(db, scopes, module); | 1021 | let impl_block = function.impl_block(db)?; |
1022 | let mut ctx = InferenceContext::new(db, scopes, module, impl_block); | ||
916 | 1023 | ||
917 | let syntax = function.syntax(db); | 1024 | let syntax = function.syntax(db); |
918 | let node = syntax.borrowed(); | 1025 | let node = syntax.borrowed(); |
919 | 1026 | ||
920 | if let Some(param_list) = node.param_list() { | 1027 | ctx.collect_fn_signature(node)?; |
921 | for param in param_list.params() { | ||
922 | let pat = if let Some(pat) = param.pat() { | ||
923 | pat | ||
924 | } else { | ||
925 | continue; | ||
926 | }; | ||
927 | if let Some(type_ref) = param.type_ref() { | ||
928 | let ty = Ty::from_ast(db, &ctx.module, type_ref)?; | ||
929 | let ty = ctx.insert_type_vars(ty); | ||
930 | ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); | ||
931 | } else { | ||
932 | // TODO self param | ||
933 | let type_var = ctx.new_type_var(); | ||
934 | ctx.type_of | ||
935 | .insert(LocalSyntaxPtr::new(pat.syntax()), type_var); | ||
936 | }; | ||
937 | } | ||
938 | } | ||
939 | |||
940 | let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { | ||
941 | let ty = Ty::from_ast(db, &ctx.module, type_ref)?; | ||
942 | ctx.insert_type_vars(ty) | ||
943 | } else { | ||
944 | Ty::unit() | ||
945 | }; | ||
946 | 1028 | ||
947 | if let Some(block) = node.body() { | 1029 | if let Some(block) = node.body() { |
948 | ctx.infer_block(block, &Expectation::has_type(ret_ty))?; | 1030 | ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?; |
949 | } | 1031 | } |
950 | 1032 | ||
951 | Ok(Arc::new(ctx.resolve_all())) | 1033 | Ok(Arc::new(ctx.resolve_all())) |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 93bf431c4..fb53fcf0b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -134,6 +134,25 @@ fn test() -> &mut &f64 { | |||
134 | ); | 134 | ); |
135 | } | 135 | } |
136 | 136 | ||
137 | #[test] | ||
138 | fn infer_self() { | ||
139 | check_inference( | ||
140 | r#" | ||
141 | struct S; | ||
142 | |||
143 | impl S { | ||
144 | fn test(&self) { | ||
145 | self; | ||
146 | } | ||
147 | fn test2(self: &Self) { | ||
148 | self; | ||
149 | } | ||
150 | } | ||
151 | "#, | ||
152 | "0007_self.txt", | ||
153 | ); | ||
154 | } | ||
155 | |||
137 | fn infer(content: &str) -> String { | 156 | fn infer(content: &str) -> String { |
138 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 157 | let (db, _, file_id) = MockDatabase::with_single_file(content); |
139 | let source_file = db.source_file(file_id); | 158 | let source_file = db.source_file(file_id); |
diff --git a/crates/ra_hir/src/ty/tests/data/0007_self.txt b/crates/ra_hir/src/ty/tests/data/0007_self.txt new file mode 100644 index 000000000..db4ba17d0 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/0007_self.txt | |||
@@ -0,0 +1,6 @@ | |||
1 | [50; 54) 'self': &S | ||
2 | [34; 38) 'self': &S | ||
3 | [40; 61) '{ ... }': () | ||
4 | [88; 109) '{ ... }': () | ||
5 | [98; 102) 'self': &S | ||
6 | [75; 79) 'self': &S | ||