aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/arena.rs66
-rw-r--r--crates/ra_hir/src/db.rs6
-rw-r--r--crates/ra_hir/src/function.rs17
-rw-r--r--crates/ra_hir/src/function/scope.rs12
-rw-r--r--crates/ra_hir/src/ids.rs31
-rw-r--r--crates/ra_hir/src/impl_block.rs180
-rw-r--r--crates/ra_hir/src/krate.rs2
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/macros.rs18
-rw-r--r--crates/ra_hir/src/mock.rs5
-rw-r--r--crates/ra_hir/src/module.rs32
-rw-r--r--crates/ra_hir/src/module/nameres.rs10
-rw-r--r--crates/ra_hir/src/name.rs5
-rw-r--r--crates/ra_hir/src/path.rs5
-rw-r--r--crates/ra_hir/src/source_binder.rs39
-rw-r--r--crates/ra_hir/src/ty.rs168
-rw-r--r--crates/ra_hir/src/ty/tests.rs19
-rw-r--r--crates/ra_hir/src/ty/tests/data/0007_self.txt6
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
5use std::{
6 fmt,
7 hash::{Hash, Hasher},
8 marker::PhantomData,
9};
10
11pub struct Id<T> {
12 idx: u32,
13 _ty: PhantomData<fn() -> T>,
14}
15
16impl<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}
21impl<T> Copy for Id<T> {}
22impl<T> Clone for Id<T> {
23 fn clone(&self) -> Id<T> {
24 *self
25 }
26}
27
28impl<T> PartialEq for Id<T> {
29 fn eq(&self, other: &Id<T>) -> bool {
30 self.idx == other.idx
31 }
32}
33
34impl<T> Eq for Id<T> {}
35
36impl<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)]
43pub(crate) struct ArenaBehavior<T> {
44 _ty: PhantomData<T>,
45}
46
47impl<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
66pub(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
18salsa::query_group! { 19salsa::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
14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module}; 14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock};
15 15
16pub use self::scope::FnScopes; 16pub use self::scope::FnScopes;
17 17
18#[derive(Debug)] 18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Function { 19pub 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};
8use ra_arena::{Arena, RawId, impl_arena_id};
8use ra_db::LocalSyntaxPtr; 9use ra_db::LocalSyntaxPtr;
9 10
10use crate::{ 11use crate::{Name, AsName};
11 arena::{Arena, Id},
12 Name, AsName,
13};
14 12
15pub(crate) type ScopeId = Id<ScopeData>; 13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct ScopeId(RawId);
15impl_arena_id!(ScopeId);
16 16
17#[derive(Debug, PartialEq, Eq)] 17#[derive(Debug, PartialEq, Eq)]
18pub struct FnScopes { 18pub 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 @@
1use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId}; 1use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId};
2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; 2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id};
3 4
4use crate::{ 5use 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
177impl DefLoc { 194impl 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.
202pub(crate) type SourceFileItemId = Id<SyntaxNode>; 219#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
220pub struct SourceFileItemId(RawId);
221impl_arena_id!(SourceFileItemId);
203 222
204#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 223#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
205pub struct SourceItemId { 224pub struct SourceItemId {
@@ -212,7 +231,7 @@ pub struct SourceItemId {
212#[derive(Debug, PartialEq, Eq)] 231#[derive(Debug, PartialEq, Eq)]
213pub struct SourceFileItems { 232pub struct SourceFileItems {
214 file_id: HirFileId, 233 file_id: HirFileId,
215 arena: Arena<SyntaxNode>, 234 arena: Arena<SourceFileItemId, SyntaxNode>,
216} 235}
217 236
218impl SourceFileItems { 237impl 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 @@
1use std::sync::Arc;
2use rustc_hash::FxHashMap;
3
4use ra_arena::{Arena, RawId, impl_arena_id};
5use ra_syntax::ast::{self, AstNode};
6use ra_db::{LocationIntener, Cancelable, SourceRootId};
7
8use 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)]
17pub struct ImplBlock {
18 module_impl_blocks: Arc<ModuleImplBlocks>,
19 impl_id: ImplId,
20}
21
22impl 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)]
52pub struct ImplData {
53 target_trait: Option<TypeRef>,
54 target_type: TypeRef,
55 items: Vec<ImplItem>,
56}
57
58impl 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)]
107pub enum ImplItem {
108 Method(Function),
109 // these don't have their own types yet
110 Const(DefId),
111 Type(DefId),
112 // Existential
113}
114
115impl 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)]
126pub struct ImplId(pub RawId);
127impl_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)]
137pub struct ModuleImplBlocks {
138 impls: Arena<ImplId, ImplData>,
139 impls_by_def: FxHashMap<DefId, ImplId>,
140}
141
142impl 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
171pub(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)]
9pub struct Crate { 9pub 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;
19mod mock; 19mod mock;
20mod query_definitions; 20mod query_definitions;
21mod path; 21mod path;
22mod arena;
23pub mod source_binder; 22pub mod source_binder;
24 23
25mod ids; 24mod ids;
@@ -32,6 +31,7 @@ mod function;
32mod adt; 31mod adt;
33mod type_ref; 32mod type_ref;
34mod ty; 33mod ty;
34mod impl_block;
35 35
36use crate::{ 36use 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
54pub use self::function::FnSignatureInfo; 55pub 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)]
22pub enum MacroDef { 22pub 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};
12use ra_arena::{Arena, RawId, impl_arena_id};
12use ra_db::{SourceRootId, FileId, Cancelable}; 13use ra_db::{SourceRootId, FileId, Cancelable};
13use relative_path::RelativePathBuf; 14use 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
22pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs}; 22pub 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)]
192pub struct ModuleId(RawId);
193impl_arena_id!(ModuleId);
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
196pub struct LinkId(RawId);
197impl_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)]
184pub struct ModuleTree { 207pub struct ModuleTree {
185 mods: Arena<ModuleData>, 208 mods: Arena<ModuleId, ModuleData>,
186 links: Arena<LinkData>, 209 links: Arena<LinkId, LinkData>,
187} 210}
188 211
189impl ModuleTree { 212impl ModuleTree {
@@ -210,9 +233,6 @@ pub(crate) enum ModuleSourceNode {
210 Module(ast::ModuleNode), 233 Module(ast::ModuleNode),
211} 234}
212 235
213pub type ModuleId = Id<ModuleData>;
214type LinkId = Id<LinkData>;
215
216#[derive(Clone, Debug, Hash, PartialEq, Eq)] 236#[derive(Clone, Debug, Hash, PartialEq, Eq)]
217pub enum Problem { 237pub 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)]
66pub struct InputModuleItems { 66pub 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)]
72struct ModuleItem { 72pub(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)]
88pub(crate) enum KnownName { 89pub(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 @@
8use ra_db::{FileId, FilePosition, Cancelable}; 8use ra_db::{FileId, FilePosition, Cancelable};
9use ra_editor::find_node_at_offset; 9use ra_editor::find_node_at_offset;
10use ra_syntax::{ 10use ra_syntax::{
11 SmolStr, TextRange, SyntaxNodeRef,
11 ast::{self, AstNode, NameOwner}, 12 ast::{self, AstNode, NameOwner},
12 SyntaxNodeRef,
13}; 13};
14 14
15use crate::{ 15use 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
130pub 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
33use crate::{ 33use 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 {
402fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { 420fn 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 {
496struct InferenceContext<'a, D: HirDatabase> { 516struct 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
504impl<'a, D: HirDatabase> InferenceContext<'a, D> { 529impl<'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
911pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 1017pub 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]
138fn infer_self() {
139 check_inference(
140 r#"
141struct S;
142
143impl 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
137fn infer(content: &str) -> String { 156fn 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