aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/Cargo.toml7
-rw-r--r--crates/ra_hir/src/adt.rs45
-rw-r--r--crates/ra_hir/src/db.rs25
-rw-r--r--crates/ra_hir/src/function.rs24
-rw-r--r--crates/ra_hir/src/function/scope.rs24
-rw-r--r--crates/ra_hir/src/krate.rs7
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/module.rs30
-rw-r--r--crates/ra_hir/src/module/imp.rs19
-rw-r--r--crates/ra_hir/src/module/nameres.rs25
-rw-r--r--crates/ra_hir/src/module/nameres/tests.rs66
-rw-r--r--crates/ra_hir/src/name.rs105
-rw-r--r--crates/ra_hir/src/path.rs18
-rw-r--r--crates/ra_hir/src/query_definitions.rs43
-rw-r--r--crates/ra_hir/src/source_binder.rs23
-rw-r--r--crates/ra_hir/src/ty.rs557
-rw-r--r--crates/ra_hir/src/ty/primitive.rs42
-rw-r--r--crates/ra_hir/src/ty/tests.rs21
-rw-r--r--crates/ra_hir/src/ty/tests/data/0002_let.txt2
-rw-r--r--crates/ra_hir/src/ty/tests/data/0003_paths.txt8
-rw-r--r--crates/ra_hir/src/ty/tests/data/0004_struct.txt4
-rw-r--r--crates/ra_hir/src/ty/tests/data/0006_backwards.txt20
23 files changed, 782 insertions, 337 deletions
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 594176337..c3fbd327d 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -5,13 +5,14 @@ version = "0.1.0"
5authors = ["Aleksey Kladov <[email protected]>"] 5authors = ["Aleksey Kladov <[email protected]>"]
6 6
7[dependencies] 7[dependencies]
8arrayvec = "0.4.9" 8arrayvec = "0.4.10"
9log = "0.4.5" 9log = "0.4.5"
10relative-path = "0.4.0" 10relative-path = "0.4.0"
11salsa = "0.8.0" 11salsa = "0.9.0"
12rustc-hash = "1.0" 12rustc-hash = "1.0"
13parking_lot = "0.6.4" 13parking_lot = "0.7.0"
14id-arena = "2.0" 14id-arena = "2.0"
15ena = "0.11"
15ra_syntax = { path = "../ra_syntax" } 16ra_syntax = { path = "../ra_syntax" }
16ra_editor = { path = "../ra_editor" } 17ra_editor = { path = "../ra_editor" }
17ra_db = { path = "../ra_db" } 18ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 65c461148..e839a5a90 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -1,10 +1,10 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}}; 3use ra_syntax::ast::{self, NameOwner, StructFlavor};
4 4
5use crate::{ 5use crate::{
6 DefId, Cancelable, 6 DefId, Cancelable, Name, AsName,
7 db::{HirDatabase}, 7 db::HirDatabase,
8 type_ref::TypeRef, 8 type_ref::TypeRef,
9}; 9};
10 10
@@ -29,26 +29,26 @@ impl Struct {
29 Ok(db.struct_data(self.def_id)?) 29 Ok(db.struct_data(self.def_id)?)
30 } 30 }
31 31
32 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<SmolStr>> { 32 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
33 Ok(db.struct_data(self.def_id)?.name.clone()) 33 Ok(db.struct_data(self.def_id)?.name.clone())
34 } 34 }
35} 35}
36 36
37#[derive(Debug, Clone, PartialEq, Eq)] 37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct StructData { 38pub struct StructData {
39 name: Option<SmolStr>, 39 name: Option<Name>,
40 variant_data: Arc<VariantData>, 40 variant_data: Arc<VariantData>,
41} 41}
42 42
43impl StructData { 43impl StructData {
44 pub(crate) fn new(struct_def: ast::StructDef) -> StructData { 44 pub(crate) fn new(struct_def: ast::StructDef) -> StructData {
45 let name = struct_def.name().map(|n| n.text()); 45 let name = struct_def.name().map(|n| n.as_name());
46 let variant_data = VariantData::new(struct_def.flavor()); 46 let variant_data = VariantData::new(struct_def.flavor());
47 let variant_data = Arc::new(variant_data); 47 let variant_data = Arc::new(variant_data);
48 StructData { name, variant_data } 48 StructData { name, variant_data }
49 } 49 }
50 50
51 pub fn name(&self) -> Option<&SmolStr> { 51 pub fn name(&self) -> Option<&Name> {
52 self.name.as_ref() 52 self.name.as_ref()
53 } 53 }
54 54
@@ -70,27 +70,29 @@ impl Enum {
70 self.def_id 70 self.def_id
71 } 71 }
72 72
73 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<SmolStr>> { 73 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
74 Ok(db.enum_data(self.def_id)?.name.clone()) 74 Ok(db.enum_data(self.def_id)?.name.clone())
75 } 75 }
76
77 pub fn variants(&self, db: &impl HirDatabase) -> Cancelable<Vec<(Name, Arc<VariantData>)>> {
78 Ok(db.enum_data(self.def_id)?.variants.clone())
79 }
76} 80}
77 81
78#[derive(Debug, Clone, PartialEq, Eq)] 82#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct EnumData { 83pub struct EnumData {
80 name: Option<SmolStr>, 84 name: Option<Name>,
81 variants: Vec<(SmolStr, Arc<VariantData>)>, 85 variants: Vec<(Name, Arc<VariantData>)>,
82} 86}
83 87
84impl EnumData { 88impl EnumData {
85 pub(crate) fn new(enum_def: ast::EnumDef) -> Self { 89 pub(crate) fn new(enum_def: ast::EnumDef) -> Self {
86 let name = enum_def.name().map(|n| n.text()); 90 let name = enum_def.name().map(|n| n.as_name());
87 let variants = if let Some(evl) = enum_def.variant_list() { 91 let variants = if let Some(evl) = enum_def.variant_list() {
88 evl.variants() 92 evl.variants()
89 .map(|v| { 93 .map(|v| {
90 ( 94 (
91 v.name() 95 v.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
92 .map(|n| n.text())
93 .unwrap_or_else(|| SmolStr::new("[error]")),
94 Arc::new(VariantData::new(v.flavor())), 96 Arc::new(VariantData::new(v.flavor())),
95 ) 97 )
96 }) 98 })
@@ -105,12 +107,12 @@ impl EnumData {
105/// A single field of an enum variant or struct 107/// A single field of an enum variant or struct
106#[derive(Debug, Clone, PartialEq, Eq)] 108#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct StructField { 109pub struct StructField {
108 name: SmolStr, 110 name: Name,
109 type_ref: TypeRef, 111 type_ref: TypeRef,
110} 112}
111 113
112impl StructField { 114impl StructField {
113 pub fn name(&self) -> SmolStr { 115 pub fn name(&self) -> Name {
114 self.name.clone() 116 self.name.clone()
115 } 117 }
116 pub fn type_ref(&self) -> &TypeRef { 118 pub fn type_ref(&self) -> &TypeRef {
@@ -134,7 +136,7 @@ impl VariantData {
134 .fields() 136 .fields()
135 .enumerate() 137 .enumerate()
136 .map(|(i, fd)| StructField { 138 .map(|(i, fd)| StructField {
137 name: SmolStr::new(i.to_string()), 139 name: Name::tuple_field_name(i),
138 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 140 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
139 }) 141 })
140 .collect(); 142 .collect();
@@ -144,10 +146,7 @@ impl VariantData {
144 let fields = fl 146 let fields = fl
145 .fields() 147 .fields()
146 .map(|fd| StructField { 148 .map(|fd| StructField {
147 name: fd 149 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
148 .name()
149 .map(|n| n.text())
150 .unwrap_or_else(|| SmolStr::new("[error]")),
151 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 150 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
152 }) 151 })
153 .collect(); 152 .collect();
@@ -157,10 +156,10 @@ impl VariantData {
157 } 156 }
158 } 157 }
159 158
160 pub(crate) fn get_field_type_ref(&self, field_name: &str) -> Option<&TypeRef> { 159 pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
161 self.fields() 160 self.fields()
162 .iter() 161 .iter()
163 .find(|f| f.name == field_name) 162 .find(|f| f.name == *field_name)
164 .map(|f| &f.type_ref) 163 .map(|f| &f.type_ref)
165 } 164 }
166 165
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index e7f9afa77..5a8ca3b47 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,18 +1,13 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::SyntaxNode;
4 SmolStr,
5 SyntaxNode,
6 ast::FnDefNode,
7};
8use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable}; 4use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable};
9 5
10use crate::{ 6use crate::{
11 DefLoc, DefId, 7 DefLoc, DefId, Name,
12 SourceFileItems, SourceItemId, 8 SourceFileItems, SourceItemId,
13 query_definitions, 9 query_definitions,
14 FnScopes, 10 FnScopes,
15 function::FnId,
16 module::{ModuleId, ModuleTree, ModuleSource, 11 module::{ModuleId, ModuleTree, ModuleSource,
17 nameres::{ItemMap, InputModuleItems}}, 12 nameres::{ItemMap, InputModuleItems}},
18 ty::{InferenceResult, Ty}, 13 ty::{InferenceResult, Ty},
@@ -24,14 +19,10 @@ salsa::query_group! {
24pub trait HirDatabase: SyntaxDatabase 19pub trait HirDatabase: SyntaxDatabase
25 + AsRef<LocationIntener<DefLoc, DefId>> 20 + AsRef<LocationIntener<DefLoc, DefId>>
26{ 21{
27 fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { 22 fn fn_scopes(def_id: DefId) -> Arc<FnScopes> {
28 type FnScopesQuery; 23 type FnScopesQuery;
29 use fn query_definitions::fn_scopes; 24 use fn query_definitions::fn_scopes;
30 } 25 }
31 fn fn_syntax(fn_id: FnId) -> FnDefNode {
32 type FnSyntaxQuery;
33 use fn query_definitions::fn_syntax;
34 }
35 26
36 fn struct_data(def_id: DefId) -> Cancelable<Arc<StructData>> { 27 fn struct_data(def_id: DefId) -> Cancelable<Arc<StructData>> {
37 type StructDataQuery; 28 type StructDataQuery;
@@ -43,19 +34,19 @@ pub trait HirDatabase: SyntaxDatabase
43 use fn query_definitions::enum_data; 34 use fn query_definitions::enum_data;
44 } 35 }
45 36
46 fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> { 37 fn infer(def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
47 type InferQuery; 38 type InferQuery;
48 use fn query_definitions::infer; 39 use fn crate::ty::infer;
49 } 40 }
50 41
51 fn type_for_def(def_id: DefId) -> Cancelable<Ty> { 42 fn type_for_def(def_id: DefId) -> Cancelable<Ty> {
52 type TypeForDefQuery; 43 type TypeForDefQuery;
53 use fn query_definitions::type_for_def; 44 use fn crate::ty::type_for_def;
54 } 45 }
55 46
56 fn type_for_field(def_id: DefId, field: SmolStr) -> Cancelable<Ty> { 47 fn type_for_field(def_id: DefId, field: Name) -> Cancelable<Ty> {
57 type TypeForFieldQuery; 48 type TypeForFieldQuery;
58 use fn query_definitions::type_for_field; 49 use fn crate::ty::type_for_field;
59 } 50 }
60 51
61 fn file_items(file_id: FileId) -> Arc<SourceFileItems> { 52 fn file_items(file_id: FileId) -> Arc<SourceFileItems> {
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index 01f0f3a66..5a44132fc 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -11,42 +11,42 @@ use ra_syntax::{
11 ast::{self, AstNode, DocCommentsOwner, NameOwner}, 11 ast::{self, AstNode, DocCommentsOwner, NameOwner},
12}; 12};
13 13
14use crate::{ DefId, HirDatabase, ty::InferenceResult, Module }; 14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module};
15 15
16pub use self::scope::FnScopes; 16pub use self::scope::FnScopes;
17 17
18#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 18#[derive(Debug)]
19pub struct FnId(pub(crate) DefId);
20
21pub struct Function { 19pub struct Function {
22 pub(crate) fn_id: FnId, 20 def_id: DefId,
23} 21}
24 22
25impl Function { 23impl Function {
26 pub(crate) fn new(def_id: DefId) -> Function { 24 pub(crate) fn new(def_id: DefId) -> Function {
27 let fn_id = FnId(def_id); 25 Function { def_id }
28 Function { fn_id }
29 } 26 }
30 27
31 pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { 28 pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode {
32 db.fn_syntax(self.fn_id) 29 let def_loc = self.def_id.loc(db);
30 assert!(def_loc.kind == DefKind::Function);
31 let syntax = db.file_item(def_loc.source_item_id);
32 ast::FnDef::cast(syntax.borrowed()).unwrap().owned()
33 } 33 }
34 34
35 pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> { 35 pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
36 db.fn_scopes(self.fn_id) 36 db.fn_scopes(self.def_id)
37 } 37 }
38 38
39 pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> { 39 pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> {
40 let syntax = db.fn_syntax(self.fn_id); 40 let syntax = self.syntax(db);
41 FnSignatureInfo::new(syntax.borrowed()) 41 FnSignatureInfo::new(syntax.borrowed())
42 } 42 }
43 43
44 pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> { 44 pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
45 db.infer(self.fn_id) 45 db.infer(self.def_id)
46 } 46 }
47 47
48 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { 48 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
49 self.fn_id.0.module(db) 49 self.def_id.module(db)
50 } 50 }
51} 51}
52 52
diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs
index a1a580979..3e4cfad0c 100644
--- a/crates/ra_hir/src/function/scope.rs
+++ b/crates/ra_hir/src/function/scope.rs
@@ -1,7 +1,7 @@
1use rustc_hash::{FxHashMap, FxHashSet}; 1use rustc_hash::{FxHashMap, FxHashSet};
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SmolStr, SyntaxNodeRef, TextUnit, TextRange, 4 AstNode, SyntaxNodeRef, TextUnit, TextRange,
5 algo::generate, 5 algo::generate,
6 ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, 6 ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
7}; 7};
@@ -9,6 +9,7 @@ use ra_db::LocalSyntaxPtr;
9 9
10use crate::{ 10use crate::{
11 arena::{Arena, Id}, 11 arena::{Arena, Id},
12 Name, AsName,
12}; 13};
13 14
14pub(crate) type ScopeId = Id<ScopeData>; 15pub(crate) type ScopeId = Id<ScopeData>;
@@ -22,7 +23,7 @@ pub struct FnScopes {
22 23
23#[derive(Debug, PartialEq, Eq)] 24#[derive(Debug, PartialEq, Eq)]
24pub struct ScopeEntry { 25pub struct ScopeEntry {
25 name: SmolStr, 26 name: Name,
26 ptr: LocalSyntaxPtr, 27 ptr: LocalSyntaxPtr,
27} 28}
28 29
@@ -101,11 +102,12 @@ impl FnScopes {
101 102
102 pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> { 103 pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> {
103 let mut shadowed = FxHashSet::default(); 104 let mut shadowed = FxHashSet::default();
105 let name = name_ref.as_name();
104 let ret = self 106 let ret = self
105 .scope_chain(name_ref.syntax()) 107 .scope_chain(name_ref.syntax())
106 .flat_map(|scope| self.entries(scope).iter()) 108 .flat_map(|scope| self.entries(scope).iter())
107 .filter(|entry| shadowed.insert(entry.name())) 109 .filter(|entry| shadowed.insert(entry.name()))
108 .filter(|entry| entry.name() == &name_ref.text()) 110 .filter(|entry| entry.name() == &name)
109 .nth(0); 111 .nth(0);
110 ret 112 ret
111 } 113 }
@@ -170,14 +172,14 @@ impl FnScopes {
170 172
171impl ScopeEntry { 173impl ScopeEntry {
172 fn new(pat: ast::BindPat) -> Option<ScopeEntry> { 174 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
173 let name = pat.name()?; 175 let name = pat.name()?.as_name();
174 let res = ScopeEntry { 176 let res = ScopeEntry {
175 name: name.text(), 177 name,
176 ptr: LocalSyntaxPtr::new(pat.syntax()), 178 ptr: LocalSyntaxPtr::new(pat.syntax()),
177 }; 179 };
178 Some(res) 180 Some(res)
179 } 181 }
180 pub fn name(&self) -> &SmolStr { 182 pub fn name(&self) -> &Name {
181 &self.name 183 &self.name
182 } 184 }
183 pub fn ptr(&self) -> LocalSyntaxPtr { 185 pub fn ptr(&self) -> LocalSyntaxPtr {
@@ -334,7 +336,7 @@ pub struct ReferenceDescriptor {
334mod tests { 336mod tests {
335 use ra_editor::find_node_at_offset; 337 use ra_editor::find_node_at_offset;
336 use ra_syntax::SourceFileNode; 338 use ra_syntax::SourceFileNode;
337 use test_utils::extract_offset; 339 use test_utils::{extract_offset, assert_eq_text};
338 340
339 use super::*; 341 use super::*;
340 342
@@ -355,9 +357,11 @@ mod tests {
355 let actual = scopes 357 let actual = scopes
356 .scope_chain(marker.syntax()) 358 .scope_chain(marker.syntax())
357 .flat_map(|scope| scopes.entries(scope)) 359 .flat_map(|scope| scopes.entries(scope))
358 .map(|it| it.name()) 360 .map(|it| it.name().to_string())
359 .collect::<Vec<_>>(); 361 .collect::<Vec<_>>()
360 assert_eq!(actual.as_slice(), expected); 362 .join("\n");
363 let expected = expected.join("\n");
364 assert_eq_text!(&actual, &expected);
361 } 365 }
362 366
363 #[test] 367 #[test]
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/krate.rs
index 1196dcef1..89b1e639e 100644
--- a/crates/ra_hir/src/krate.rs
+++ b/crates/ra_hir/src/krate.rs
@@ -1,7 +1,6 @@
1use ra_syntax::SmolStr;
2pub use ra_db::CrateId; 1pub use ra_db::CrateId;
3 2
4use crate::{HirDatabase, Module, Cancelable}; 3use crate::{HirDatabase, Module, Cancelable, Name, AsName};
5 4
6/// 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
7/// 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
@@ -14,7 +13,7 @@ pub struct Crate {
14#[derive(Debug)] 13#[derive(Debug)]
15pub struct CrateDependency { 14pub struct CrateDependency {
16 pub krate: Crate, 15 pub krate: Crate,
17 pub name: SmolStr, 16 pub name: Name,
18} 17}
19 18
20impl Crate { 19impl Crate {
@@ -27,7 +26,7 @@ impl Crate {
27 .dependencies(self.crate_id) 26 .dependencies(self.crate_id)
28 .map(|dep| { 27 .map(|dep| {
29 let krate = Crate::new(dep.crate_id()); 28 let krate = Crate::new(dep.crate_id());
30 let name = dep.name.clone(); 29 let name = dep.as_name();
31 CrateDependency { krate, name } 30 CrateDependency { krate, name }
32 }) 31 })
33 .collect() 32 .collect()
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index f1cc0ccd0..5bbb09c01 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -22,6 +22,7 @@ mod path;
22mod arena; 22mod arena;
23pub mod source_binder; 23pub mod source_binder;
24 24
25mod name;
25mod krate; 26mod krate;
26mod module; 27mod module;
27mod function; 28mod function;
@@ -37,10 +38,12 @@ use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable};
37use crate::{ 38use crate::{
38 db::HirDatabase, 39 db::HirDatabase,
39 arena::{Arena, Id}, 40 arena::{Arena, Id},
41 name::{AsName, KnownName},
40}; 42};
41 43
42pub use self::{ 44pub use self::{
43 path::{Path, PathKind}, 45 path::{Path, PathKind},
46 name::Name,
44 krate::Crate, 47 krate::Crate,
45 module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, 48 module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
46 function::{Function, FnScopes}, 49 function::{Function, FnScopes},
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index f6882cb77..a2507c9b5 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -189,7 +189,6 @@ salsa::database_storage! {
189 fn file_item() for db::FileItemQuery; 189 fn file_item() for db::FileItemQuery;
190 fn input_module_items() for db::InputModuleItemsQuery; 190 fn input_module_items() for db::InputModuleItemsQuery;
191 fn item_map() for db::ItemMapQuery; 191 fn item_map() for db::ItemMapQuery;
192 fn fn_syntax() for db::FnSyntaxQuery;
193 fn submodules() for db::SubmodulesQuery; 192 fn submodules() for db::SubmodulesQuery;
194 fn infer() for db::InferQuery; 193 fn infer() for db::InferQuery;
195 fn type_for_def() for db::TypeForDefQuery; 194 fn type_for_def() for db::TypeForDefQuery;
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index b9d36f01f..24c346984 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -7,13 +7,14 @@ use log;
7use ra_syntax::{ 7use ra_syntax::{
8 algo::generate, 8 algo::generate,
9 ast::{self, AstNode, NameOwner}, 9 ast::{self, AstNode, NameOwner},
10 SmolStr, SyntaxNode, 10 SyntaxNode,
11}; 11};
12use ra_db::{SourceRootId, FileId, Cancelable}; 12use ra_db::{SourceRootId, FileId, Cancelable};
13use relative_path::RelativePathBuf; 13use relative_path::RelativePathBuf;
14 14
15use crate::{ 15use crate::{
16 DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate, 16 Def, DefKind, DefLoc, DefId,
17 Name, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate,
17 arena::{Arena, Id}, 18 arena::{Arena, Id},
18}; 19};
19 20
@@ -84,7 +85,7 @@ impl Module {
84 } 85 }
85 86
86 /// `name` is `None` for the crate's root module 87 /// `name` is `None` for the crate's root module
87 pub fn name(&self) -> Option<SmolStr> { 88 pub fn name(&self) -> Option<&Name> {
88 let link = self.module_id.parent_link(&self.tree)?; 89 let link = self.module_id.parent_link(&self.tree)?;
89 Some(link.name(&self.tree)) 90 Some(link.name(&self.tree))
90 } 91 }
@@ -100,7 +101,7 @@ impl Module {
100 } 101 }
101 102
102 /// Finds a child module with the specified name. 103 /// Finds a child module with the specified name.
103 pub fn child(&self, name: &str) -> Option<Module> { 104 pub fn child(&self, name: &Name) -> Option<Module> {
104 let child_id = self.module_id.child(&self.tree, name)?; 105 let child_id = self.module_id.child(&self.tree, name)?;
105 Some(Module { 106 Some(Module {
106 module_id: child_id, 107 module_id: child_id,
@@ -138,13 +139,8 @@ impl Module {
138 } else { 139 } else {
139 return Ok(PerNs::none()); 140 return Ok(PerNs::none());
140 }; 141 };
141 let module = match curr.loc(db) { 142 let module = match curr.resolve(db)? {
142 DefLoc { 143 Def::Module(it) => it,
143 kind: DefKind::Module,
144 source_root_id,
145 module_id,
146 ..
147 } => Module::new(db, source_root_id, module_id)?,
148 // TODO here would be the place to handle enum variants... 144 // TODO here would be the place to handle enum variants...
149 _ => return Ok(PerNs::none()), 145 _ => return Ok(PerNs::none()),
150 }; 146 };
@@ -230,15 +226,15 @@ impl ModuleId {
230 .last() 226 .last()
231 .unwrap() 227 .unwrap()
232 } 228 }
233 fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> { 229 fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
234 let link = tree.mods[self] 230 let link = tree.mods[self]
235 .children 231 .children
236 .iter() 232 .iter()
237 .map(|&it| &tree.links[it]) 233 .map(|&it| &tree.links[it])
238 .find(|it| it.name == name)?; 234 .find(|it| it.name == *name)?;
239 Some(*link.points_to.first()?) 235 Some(*link.points_to.first()?)
240 } 236 }
241 fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (SmolStr, ModuleId)> + 'a { 237 fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
242 tree.mods[self].children.iter().filter_map(move |&it| { 238 tree.mods[self].children.iter().filter_map(move |&it| {
243 let link = &tree.links[it]; 239 let link = &tree.links[it];
244 let module = *link.points_to.first()?; 240 let module = *link.points_to.first()?;
@@ -263,8 +259,8 @@ impl LinkId {
263 fn owner(self, tree: &ModuleTree) -> ModuleId { 259 fn owner(self, tree: &ModuleTree) -> ModuleId {
264 tree.links[self].owner 260 tree.links[self].owner
265 } 261 }
266 fn name(self, tree: &ModuleTree) -> SmolStr { 262 fn name(self, tree: &ModuleTree) -> &Name {
267 tree.links[self].name.clone() 263 &tree.links[self].name
268 } 264 }
269 fn bind_source<'a>(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode { 265 fn bind_source<'a>(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode {
270 let owner = self.owner(tree); 266 let owner = self.owner(tree);
@@ -328,7 +324,7 @@ impl ModuleSource {
328#[derive(Hash, Debug, PartialEq, Eq)] 324#[derive(Hash, Debug, PartialEq, Eq)]
329struct LinkData { 325struct LinkData {
330 owner: ModuleId, 326 owner: ModuleId,
331 name: SmolStr, 327 name: Name,
332 points_to: Vec<ModuleId>, 328 points_to: Vec<ModuleId>,
333 problem: Option<Problem>, 329 problem: Option<Problem>,
334} 330}
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
index 748fdb64e..eded85a63 100644
--- a/crates/ra_hir/src/module/imp.rs
+++ b/crates/ra_hir/src/module/imp.rs
@@ -1,16 +1,13 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::ast::{self, NameOwner};
4 ast::{self, NameOwner},
5 SmolStr,
6};
7use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
8use rustc_hash::{FxHashMap, FxHashSet}; 5use rustc_hash::{FxHashMap, FxHashSet};
9use arrayvec::ArrayVec; 6use arrayvec::ArrayVec;
10use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; 7use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
11 8
12use crate::{ 9use crate::{
13 HirDatabase, 10 HirDatabase, Name, AsName,
14}; 11};
15 12
16use super::{ 13use super::{
@@ -20,12 +17,12 @@ use super::{
20 17
21#[derive(Clone, Hash, PartialEq, Eq, Debug)] 18#[derive(Clone, Hash, PartialEq, Eq, Debug)]
22pub enum Submodule { 19pub enum Submodule {
23 Declaration(SmolStr), 20 Declaration(Name),
24 Definition(SmolStr, ModuleSource), 21 Definition(Name, ModuleSource),
25} 22}
26 23
27impl Submodule { 24impl Submodule {
28 fn name(&self) -> &SmolStr { 25 fn name(&self) -> &Name {
29 match self { 26 match self {
30 Submodule::Declaration(name) => name, 27 Submodule::Declaration(name) => name,
31 Submodule::Definition(name, _) => name, 28 Submodule::Definition(name, _) => name,
@@ -35,14 +32,14 @@ impl Submodule {
35 32
36pub(crate) fn modules<'a>( 33pub(crate) fn modules<'a>(
37 root: impl ast::ModuleItemOwner<'a>, 34 root: impl ast::ModuleItemOwner<'a>,
38) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> { 35) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
39 root.items() 36 root.items()
40 .filter_map(|item| match item { 37 .filter_map(|item| match item {
41 ast::ModuleItem::Module(m) => Some(m), 38 ast::ModuleItem::Module(m) => Some(m),
42 _ => None, 39 _ => None,
43 }) 40 })
44 .filter_map(|module| { 41 .filter_map(|module| {
45 let name = module.name()?.text(); 42 let name = module.name()?.as_name();
46 Some((name, module)) 43 Some((name, module))
47 }) 44 })
48} 45}
@@ -155,7 +152,7 @@ fn build_subtree(
155fn resolve_submodule( 152fn resolve_submodule(
156 db: &impl HirDatabase, 153 db: &impl HirDatabase,
157 source: ModuleSource, 154 source: ModuleSource,
158 name: &SmolStr, 155 name: &Name,
159) -> (Vec<FileId>, Option<Problem>) { 156) -> (Vec<FileId>, Option<Problem>) {
160 // FIXME: handle submodules of inline modules properly 157 // FIXME: handle submodules of inline modules properly
161 let file_id = source.file_id(); 158 let file_id = source.file_id();
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 98cd225dd..68eb02a98 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -14,14 +14,12 @@
14//! modifications (that is, typing inside a function shold not change IMIs), 14//! modifications (that is, typing inside a function shold not change IMIs),
15//! such that the results of name resolution can be preserved unless the module 15//! such that the results of name resolution can be preserved unless the module
16//! structure itself is modified. 16//! structure itself is modified.
17use std::{ 17use std::sync::Arc;
18 sync::Arc,
19};
20 18
21use rustc_hash::FxHashMap; 19use rustc_hash::FxHashMap;
22use ra_syntax::{ 20use ra_syntax::{
23 TextRange, 21 TextRange,
24 SmolStr, SyntaxKind::{self, *}, 22 SyntaxKind::{self, *},
25 ast::{self, AstNode} 23 ast::{self, AstNode}
26}; 24};
27use ra_db::SourceRootId; 25use ra_db::SourceRootId;
@@ -32,6 +30,7 @@ use crate::{
32 SourceItemId, SourceFileItemId, SourceFileItems, 30 SourceItemId, SourceFileItemId, SourceFileItems,
33 Path, PathKind, 31 Path, PathKind,
34 HirDatabase, Crate, 32 HirDatabase, Crate,
33 Name, AsName,
35 module::{Module, ModuleId, ModuleTree}, 34 module::{Module, ModuleId, ModuleTree},
36}; 35};
37 36
@@ -45,14 +44,14 @@ pub struct ItemMap {
45 44
46#[derive(Debug, Default, PartialEq, Eq, Clone)] 45#[derive(Debug, Default, PartialEq, Eq, Clone)]
47pub struct ModuleScope { 46pub struct ModuleScope {
48 items: FxHashMap<SmolStr, Resolution>, 47 items: FxHashMap<Name, Resolution>,
49} 48}
50 49
51impl ModuleScope { 50impl ModuleScope {
52 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &'a Resolution)> + 'a { 51 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
53 self.items.iter() 52 self.items.iter()
54 } 53 }
55 pub fn get(&self, name: &SmolStr) -> Option<&Resolution> { 54 pub fn get(&self, name: &Name) -> Option<&Resolution> {
56 self.items.get(name) 55 self.items.get(name)
57 } 56 }
58} 57}
@@ -72,7 +71,7 @@ pub struct InputModuleItems {
72#[derive(Debug, PartialEq, Eq)] 71#[derive(Debug, PartialEq, Eq)]
73struct ModuleItem { 72struct ModuleItem {
74 id: SourceFileItemId, 73 id: SourceFileItemId,
75 name: SmolStr, 74 name: Name,
76 kind: SyntaxKind, 75 kind: SyntaxKind,
77 vis: Vis, 76 vis: Vis,
78} 77}
@@ -260,7 +259,7 @@ impl InputModuleItems {
260 259
261impl ModuleItem { 260impl ModuleItem {
262 fn new<'a>(file_items: &SourceFileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { 261 fn new<'a>(file_items: &SourceFileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> {
263 let name = item.name()?.text(); 262 let name = item.name()?.as_name();
264 let kind = item.syntax().kind(); 263 let kind = item.syntax().kind();
265 let vis = Vis::Other; 264 let vis = Vis::Other;
266 let id = file_items.id_of_unchecked(item.syntax()); 265 let id = file_items.id_of_unchecked(item.syntax());
@@ -328,7 +327,11 @@ where
328 for dep in krate.dependencies(self.db) { 327 for dep in krate.dependencies(self.db) {
329 if let Some(module) = dep.krate.root_module(self.db)? { 328 if let Some(module) = dep.krate.root_module(self.db)? {
330 let def_id = module.def_id(self.db); 329 let def_id = module.def_id(self.db);
331 self.add_module_item(&mut module_items, dep.name, PerNs::types(def_id)); 330 self.add_module_item(
331 &mut module_items,
332 dep.name.clone(),
333 PerNs::types(def_id),
334 );
332 } 335 }
333 } 336 }
334 }; 337 };
@@ -389,7 +392,7 @@ where
389 Ok(()) 392 Ok(())
390 } 393 }
391 394
392 fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: PerNs<DefId>) { 395 fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def_id: PerNs<DefId>) {
393 let resolution = Resolution { 396 let resolution = Resolution {
394 def_id, 397 def_id,
395 import: None, 398 import: None,
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs
index 03ea5c1d6..ca20f064f 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/module/nameres/tests.rs
@@ -2,8 +2,8 @@ use std::sync::Arc;
2 2
3use salsa::Database; 3use salsa::Database;
4use ra_db::{FilesDatabase, CrateGraph}; 4use ra_db::{FilesDatabase, CrateGraph};
5use ra_syntax::SmolStr;
6use relative_path::RelativePath; 5use relative_path::RelativePath;
6use test_utils::assert_eq_text;
7 7
8use crate::{ 8use crate::{
9 self as hir, 9 self as hir,
@@ -21,6 +21,35 @@ fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
21 (db.item_map(source_root).unwrap(), module_id) 21 (db.item_map(source_root).unwrap(), module_id)
22} 22}
23 23
24fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected: &str) {
25 let mut lines = map.per_module[&module_id]
26 .items
27 .iter()
28 .map(|(name, res)| format!("{}: {}", name, dump_resolution(res)))
29 .collect::<Vec<_>>();
30 lines.sort();
31 let actual = lines.join("\n");
32 let expected = expected
33 .trim()
34 .lines()
35 .map(|it| it.trim())
36 .collect::<Vec<_>>()
37 .join("\n");
38 assert_eq_text!(&actual, &expected);
39
40 fn dump_resolution(resolution: &hir::Resolution) -> &'static str {
41 match (
42 resolution.def_id.types.is_some(),
43 resolution.def_id.values.is_some(),
44 ) {
45 (true, true) => "t v",
46 (true, false) => "t",
47 (false, true) => "v",
48 (false, false) => "_",
49 }
50 }
51}
52
24#[test] 53#[test]
25fn item_map_smoke_test() { 54fn item_map_smoke_test() {
26 let (item_map, module_id) = item_map( 55 let (item_map, module_id) = item_map(
@@ -38,13 +67,18 @@ fn item_map_smoke_test() {
38 pub struct Baz; 67 pub struct Baz;
39 ", 68 ",
40 ); 69 );
41 let name = SmolStr::from("Baz"); 70 check_module_item_map(
42 let resolution = &item_map.per_module[&module_id].items[&name]; 71 &item_map,
43 assert!(resolution.def_id.take_types().is_some()); 72 module_id,
73 "
74 Baz: t v
75 foo: t
76 ",
77 );
44} 78}
45 79
46#[test] 80#[test]
47fn test_self() { 81fn item_map_using_self() {
48 let (item_map, module_id) = item_map( 82 let (item_map, module_id) = item_map(
49 " 83 "
50 //- /lib.rs 84 //- /lib.rs
@@ -57,9 +91,14 @@ fn test_self() {
57 pub struct Baz; 91 pub struct Baz;
58 ", 92 ",
59 ); 93 );
60 let name = SmolStr::from("Baz"); 94 check_module_item_map(
61 let resolution = &item_map.per_module[&module_id].items[&name]; 95 &item_map,
62 assert!(resolution.def_id.take_types().is_some()); 96 module_id,
97 "
98 Baz: t v
99 foo: t
100 ",
101 );
63} 102}
64 103
65#[test] 104#[test]
@@ -90,9 +129,14 @@ fn item_map_across_crates() {
90 let module_id = module.module_id; 129 let module_id = module.module_id;
91 let item_map = db.item_map(source_root).unwrap(); 130 let item_map = db.item_map(source_root).unwrap();
92 131
93 let name = SmolStr::from("Baz"); 132 check_module_item_map(
94 let resolution = &item_map.per_module[&module_id].items[&name]; 133 &item_map,
95 assert!(resolution.def_id.take_types().is_some()); 134 module_id,
135 "
136 Baz: t v
137 test_crate: t
138 ",
139 );
96} 140}
97 141
98#[test] 142#[test]
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs
new file mode 100644
index 000000000..51e8b3da8
--- /dev/null
+++ b/crates/ra_hir/src/name.rs
@@ -0,0 +1,105 @@
1use std::fmt;
2
3use ra_syntax::{ast, SmolStr};
4
5/// `Name` is a wrapper around string, which is used in hir for both references
6/// and declarations. In theory, names should also carry hygene info, but we are
7/// not there yet!
8#[derive(Clone, PartialEq, Eq, Hash)]
9pub struct Name {
10 text: SmolStr,
11}
12
13impl fmt::Display for Name {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 fmt::Display::fmt(&self.text, f)
16 }
17}
18
19impl fmt::Debug for Name {
20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21 fmt::Debug::fmt(&self.text, f)
22 }
23}
24
25impl Name {
26 fn new(text: SmolStr) -> Name {
27 Name { text }
28 }
29
30 pub(crate) fn missing() -> Name {
31 Name::new("[missing name]".into())
32 }
33
34 pub(crate) fn tuple_field_name(idx: usize) -> Name {
35 Name::new(idx.to_string().into())
36 }
37
38 pub(crate) fn as_known_name(&self) -> Option<KnownName> {
39 let name = match self.text.as_str() {
40 "isize" => KnownName::Isize,
41 "i8" => KnownName::I8,
42 "i16" => KnownName::I16,
43 "i32" => KnownName::I32,
44 "i64" => KnownName::I64,
45 "i128" => KnownName::I128,
46 "usize" => KnownName::Usize,
47 "u8" => KnownName::U8,
48 "u16" => KnownName::U16,
49 "u32" => KnownName::U32,
50 "u64" => KnownName::U64,
51 "u128" => KnownName::U128,
52 "f32" => KnownName::F32,
53 "f64" => KnownName::F64,
54 _ => return None,
55 };
56 Some(name)
57 }
58}
59
60pub(crate) trait AsName {
61 fn as_name(&self) -> Name;
62}
63
64impl AsName for ast::NameRef<'_> {
65 fn as_name(&self) -> Name {
66 Name::new(self.text())
67 }
68}
69
70impl AsName for ast::Name<'_> {
71 fn as_name(&self) -> Name {
72 Name::new(self.text())
73 }
74}
75
76impl AsName for ra_db::Dependency {
77 fn as_name(&self) -> Name {
78 Name::new(self.name.clone())
79 }
80}
81
82// Ideally, should be replaced with
83// ```
84// const ISIZE: Name = Name::new("isize")
85// ```
86// but const-fn is not that powerful yet.
87#[derive(Debug)]
88pub(crate) enum KnownName {
89 Isize,
90 I8,
91 I16,
92 I32,
93 I64,
94 I128,
95
96 Usize,
97 U8,
98 U16,
99 U32,
100 U64,
101 U128,
102
103 F32,
104 F64,
105}
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 0b260072c..93f7203fe 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -1,9 +1,11 @@
1use ra_syntax::{SmolStr, ast, AstNode, TextRange}; 1use ra_syntax::{ast, AstNode, TextRange};
2
3use crate::{Name, AsName};
2 4
3#[derive(Debug, Clone, PartialEq, Eq, Hash)] 5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4pub struct Path { 6pub struct Path {
5 pub kind: PathKind, 7 pub kind: PathKind,
6 pub segments: Vec<SmolStr>, 8 pub segments: Vec<Name>,
7} 9}
8 10
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -29,7 +31,7 @@ impl Path {
29 loop { 31 loop {
30 let segment = path.segment()?; 32 let segment = path.segment()?;
31 match segment.kind()? { 33 match segment.kind()? {
32 ast::PathSegmentKind::Name(name) => segments.push(name.text()), 34 ast::PathSegmentKind::Name(name) => segments.push(name.as_name()),
33 ast::PathSegmentKind::CrateKw => { 35 ast::PathSegmentKind::CrateKw => {
34 kind = PathKind::Crate; 36 kind = PathKind::Crate;
35 break; 37 break;
@@ -67,6 +69,14 @@ impl Path {
67 pub fn is_ident(&self) -> bool { 69 pub fn is_ident(&self) -> bool {
68 self.kind == PathKind::Plain && self.segments.len() == 1 70 self.kind == PathKind::Plain && self.segments.len() == 1
69 } 71 }
72
73 /// If this path is a single identifier, like `foo`, return its name.
74 pub fn as_ident(&self) -> Option<&Name> {
75 if self.kind != PathKind::Plain || self.segments.len() > 1 {
76 return None;
77 }
78 self.segments.first()
79 }
70} 80}
71 81
72fn expand_use_tree( 82fn expand_use_tree(
@@ -130,7 +140,7 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> {
130 kind: PathKind::Plain, 140 kind: PathKind::Plain,
131 segments: Vec::with_capacity(1), 141 segments: Vec::with_capacity(1),
132 }); 142 });
133 res.segments.push(name.text()); 143 res.segments.push(name.as_name());
134 res 144 res
135 } 145 }
136 ast::PathSegmentKind::CrateKw => { 146 ast::PathSegmentKind::CrateKw => {
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index 4a7958a12..721bd4195 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -5,55 +5,30 @@ use std::{
5 5
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use ra_syntax::{ 7use ra_syntax::{
8 AstNode, SyntaxNode, SmolStr, 8 AstNode, SyntaxNode,
9 ast::{self, FnDef, FnDefNode, NameOwner, ModuleItemOwner} 9 ast::{self, NameOwner, ModuleItemOwner}
10}; 10};
11use ra_db::{SourceRootId, FileId, Cancelable,}; 11use ra_db::{SourceRootId, FileId, Cancelable,};
12 12
13use crate::{ 13use crate::{
14 SourceFileItems, SourceItemId, DefKind, Function, DefId, 14 SourceFileItems, SourceItemId, DefKind, Function, DefId, Name, AsName,
15 db::HirDatabase, 15 db::HirDatabase,
16 function::{FnScopes, FnId}, 16 function::FnScopes,
17 module::{ 17 module::{
18 ModuleSource, ModuleSourceNode, ModuleId, 18 ModuleSource, ModuleSourceNode, ModuleId,
19 imp::Submodule, 19 imp::Submodule,
20 nameres::{InputModuleItems, ItemMap, Resolver}, 20 nameres::{InputModuleItems, ItemMap, Resolver},
21 }, 21 },
22 ty::{self, InferenceResult, Ty},
23 adt::{StructData, EnumData}, 22 adt::{StructData, EnumData},
24}; 23};
25 24
26/// Resolve `FnId` to the corresponding `SyntaxNode` 25pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> {
27pub(super) fn fn_syntax(db: &impl HirDatabase, fn_id: FnId) -> FnDefNode { 26 let function = Function::new(def_id);
28 let def_loc = fn_id.0.loc(db); 27 let syntax = function.syntax(db);
29 assert!(def_loc.kind == DefKind::Function);
30 let syntax = db.file_item(def_loc.source_item_id);
31 FnDef::cast(syntax.borrowed()).unwrap().owned()
32}
33
34pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> {
35 let syntax = db.fn_syntax(fn_id);
36 let res = FnScopes::new(syntax.borrowed()); 28 let res = FnScopes::new(syntax.borrowed());
37 Arc::new(res) 29 Arc::new(res)
38} 30}
39 31
40pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
41 let function = Function { fn_id };
42 ty::infer(db, function).map(Arc::new)
43}
44
45pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
46 ty::type_for_def(db, def_id)
47}
48
49pub(super) fn type_for_field(
50 db: &impl HirDatabase,
51 def_id: DefId,
52 field: SmolStr,
53) -> Cancelable<Ty> {
54 ty::type_for_field(db, def_id, field)
55}
56
57pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> { 32pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
58 let def_loc = def_id.loc(db); 33 let def_loc = def_id.loc(db);
59 assert!(def_loc.kind == DefKind::Struct); 34 assert!(def_loc.kind == DefKind::Struct);
@@ -130,14 +105,14 @@ pub(crate) fn submodules(
130 105
131pub(crate) fn modules<'a>( 106pub(crate) fn modules<'a>(
132 root: impl ast::ModuleItemOwner<'a>, 107 root: impl ast::ModuleItemOwner<'a>,
133) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> { 108) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
134 root.items() 109 root.items()
135 .filter_map(|item| match item { 110 .filter_map(|item| match item {
136 ast::ModuleItem::Module(m) => Some(m), 111 ast::ModuleItem::Module(m) => Some(m),
137 _ => None, 112 _ => None,
138 }) 113 })
139 .filter_map(|module| { 114 .filter_map(|module| {
140 let name = module.name()?.text(); 115 let name = module.name()?.as_name();
141 Some((name, module)) 116 Some((name, module))
142 }) 117 })
143} 118}
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index a0165aef2..a0d1daf71 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -8,14 +8,14 @@
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 ast::{self, AstNode}, 11 ast::{self, AstNode, NameOwner},
12 SyntaxNodeRef, 12 SyntaxNodeRef,
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Module, Function, SourceItemId, 16 HirDatabase, Module, Function, SourceItemId,
17 module::ModuleSource, 17 module::ModuleSource,
18 DefKind, DefLoc 18 DefKind, DefLoc, AsName,
19}; 19};
20 20
21/// Locates the module by `FileId`. Picks topmost module in the file. 21/// Locates the module by `FileId`. Picks topmost module in the file.
@@ -24,6 +24,25 @@ pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable
24 module_from_source(db, module_source) 24 module_from_source(db, module_source)
25} 25}
26 26
27/// Locates the child module by `mod child;` declaration.
28pub fn module_from_declaration(
29 db: &impl HirDatabase,
30 file_id: FileId,
31 decl: ast::Module,
32) -> Cancelable<Option<Module>> {
33 let parent_module = module_from_file_id(db, file_id)?;
34 let child_name = decl.name();
35 match (parent_module, child_name) {
36 (Some(parent_module), Some(child_name)) => {
37 if let Some(child) = parent_module.child(&child_name.as_name()) {
38 return Ok(Some(child));
39 }
40 }
41 _ => (),
42 }
43 Ok(None)
44}
45
27/// Locates the module by position in the source code. 46/// Locates the module by position in the source code.
28pub fn module_from_position( 47pub fn module_from_position(
29 db: &impl HirDatabase, 48 db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 67b523c2c..719b3f7cd 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -1,27 +1,133 @@
1//! The type system. We currently use this to infer types for completion.
2//!
3//! For type inference, compare the implementations in rustc (the various
4//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and
5//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
6//! inference here is the `infer` function, which infers the types of all
7//! expressions in a given function.
8//!
9//! The central struct here is `Ty`, which represents a type. During inference,
10//! it can contain type 'variables' which represent currently unknown types; as
11//! we walk through the expressions, we might determine that certain variables
12//! need to be equal to each other, or to certain types. To record this, we use
13//! the union-find implementation from the `ena` crate, which is extracted from
14//! rustc.
15
1mod primitive; 16mod primitive;
2#[cfg(test)] 17#[cfg(test)]
3mod tests; 18mod tests;
4 19
5use std::sync::Arc; 20use std::sync::Arc;
6use std::fmt; 21use std::{fmt, mem};
7 22
8use log; 23use log;
9use rustc_hash::{FxHashMap}; 24use rustc_hash::FxHashMap;
25use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError};
10 26
11use ra_db::{LocalSyntaxPtr, Cancelable}; 27use ra_db::{LocalSyntaxPtr, Cancelable};
12use ra_syntax::{ 28use ra_syntax::{
13 SmolStr,
14 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp}, 29 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp},
15 SyntaxNodeRef 30 SyntaxNodeRef
16}; 31};
17 32
18use crate::{ 33use crate::{
19 Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, 34 Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName,
20 db::HirDatabase, 35 db::HirDatabase,
21 adt::VariantData,
22 type_ref::{TypeRef, Mutability}, 36 type_ref::{TypeRef, Mutability},
23}; 37};
24 38
39/// The ID of a type variable.
40#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
41pub struct TypeVarId(u32);
42
43impl UnifyKey for TypeVarId {
44 type Value = TypeVarValue;
45
46 fn index(&self) -> u32 {
47 self.0
48 }
49
50 fn from_index(i: u32) -> Self {
51 TypeVarId(i)
52 }
53
54 fn tag() -> &'static str {
55 "TypeVarId"
56 }
57}
58
59/// The value of a type variable: either we already know the type, or we don't
60/// know it yet.
61#[derive(Clone, PartialEq, Eq, Debug)]
62pub enum TypeVarValue {
63 Known(Ty),
64 Unknown,
65}
66
67impl TypeVarValue {
68 fn known(&self) -> Option<&Ty> {
69 match self {
70 TypeVarValue::Known(ty) => Some(ty),
71 TypeVarValue::Unknown => None,
72 }
73 }
74}
75
76impl UnifyValue for TypeVarValue {
77 type Error = NoError;
78
79 fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
80 match (value1, value2) {
81 // We should never equate two type variables, both of which have
82 // known types. Instead, we recursively equate those types.
83 (TypeVarValue::Known(..), TypeVarValue::Known(..)) => {
84 panic!("equating two type variables, both of which have known types")
85 }
86
87 // If one side is known, prefer that one.
88 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()),
89 (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()),
90
91 (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown),
92 }
93 }
94}
95
96/// The kinds of placeholders we need during type inference. Currently, we only
97/// have type variables; in the future, we will probably also need int and float
98/// variables, for inference of literal values (e.g. `100` could be one of
99/// several integer types).
100#[derive(Clone, PartialEq, Eq, Hash, Debug)]
101pub enum InferTy {
102 TypeVar(TypeVarId),
103}
104
105/// When inferring an expression, we propagate downward whatever type hint we
106/// are able in the form of an `Expectation`.
107#[derive(Clone, PartialEq, Eq, Debug)]
108struct Expectation {
109 ty: Ty,
110 // TODO: In some cases, we need to be aware whether the expectation is that
111 // the type match exactly what we passed, or whether it just needs to be
112 // coercible to the expected type. See Expectation::rvalue_hint in rustc.
113}
114
115impl Expectation {
116 /// The expectation that the type of the expression needs to equal the given
117 /// type.
118 fn has_type(ty: Ty) -> Self {
119 Expectation { ty }
120 }
121
122 /// This expresses no expectation on the type.
123 fn none() -> Self {
124 Expectation { ty: Ty::Unknown }
125 }
126}
127
128/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
129///
130/// This should be cheap to clone.
25#[derive(Clone, PartialEq, Eq, Hash, Debug)] 131#[derive(Clone, PartialEq, Eq, Hash, Debug)]
26pub enum Ty { 132pub enum Ty {
27 /// The primitive boolean type. Written as `bool`. 133 /// The primitive boolean type. Written as `bool`.
@@ -45,7 +151,7 @@ pub enum Ty {
45 /// The DefId of the struct/enum. 151 /// The DefId of the struct/enum.
46 def_id: DefId, 152 def_id: DefId,
47 /// The name, for displaying. 153 /// The name, for displaying.
48 name: SmolStr, 154 name: Name,
49 // later we'll need generic substitutions here 155 // later we'll need generic substitutions here
50 }, 156 },
51 157
@@ -55,14 +161,14 @@ pub enum Ty {
55 // An array with the given length. Written as `[T; n]`. 161 // An array with the given length. Written as `[T; n]`.
56 // Array(Ty, ty::Const), 162 // Array(Ty, ty::Const),
57 /// The pointee of an array slice. Written as `[T]`. 163 /// The pointee of an array slice. Written as `[T]`.
58 Slice(TyRef), 164 Slice(Arc<Ty>),
59 165
60 /// A raw pointer. Written as `*mut T` or `*const T` 166 /// A raw pointer. Written as `*mut T` or `*const T`
61 RawPtr(TyRef, Mutability), 167 RawPtr(Arc<Ty>, Mutability),
62 168
63 /// A reference; a pointer with an associated lifetime. Written as 169 /// A reference; a pointer with an associated lifetime. Written as
64 /// `&'a mut T` or `&'a T`. 170 /// `&'a mut T` or `&'a T`.
65 Ref(TyRef, Mutability), 171 Ref(Arc<Ty>, Mutability),
66 172
67 /// A pointer to a function. Written as `fn() -> i32`. 173 /// A pointer to a function. Written as `fn() -> i32`.
68 /// 174 ///
@@ -74,52 +180,51 @@ pub enum Ty {
74 /// ``` 180 /// ```
75 FnPtr(Arc<FnSig>), 181 FnPtr(Arc<FnSig>),
76 182
183 // rustc has a separate type for each function, which just coerces to the
184 // above function pointer type. Once we implement generics, we will probably
185 // need this as well.
186
77 // A trait, defined with `dyn trait`. 187 // A trait, defined with `dyn trait`.
78 // Dynamic(), 188 // Dynamic(),
79 /// The anonymous type of a closure. Used to represent the type of 189 // The anonymous type of a closure. Used to represent the type of
80 /// `|a| a`. 190 // `|a| a`.
81 // Closure(DefId, ClosureSubsts<'tcx>), 191 // Closure(DefId, ClosureSubsts<'tcx>),
82 192
83 /// The anonymous type of a generator. Used to represent the type of 193 // The anonymous type of a generator. Used to represent the type of
84 /// `|a| yield a`. 194 // `|a| yield a`.
85 // Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), 195 // Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
86 196
87 /// A type representin the types stored inside a generator. 197 // A type representin the types stored inside a generator.
88 /// This should only appear in GeneratorInteriors. 198 // This should only appear in GeneratorInteriors.
89 // GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>), 199 // GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>),
90 200 /// The never type `!`.
91 /// The never type `!`
92 Never, 201 Never,
93 202
94 /// A tuple type. For example, `(i32, bool)`. 203 /// A tuple type. For example, `(i32, bool)`.
95 Tuple(Vec<Ty>), 204 Tuple(Arc<[Ty]>),
96 205
97 // The projection of an associated type. For example, 206 // The projection of an associated type. For example,
98 // `<T as Trait<..>>::N`. 207 // `<T as Trait<..>>::N`.pub
99 // Projection(ProjectionTy), 208 // Projection(ProjectionTy),
100 209
101 // Opaque (`impl Trait`) type found in a return type. 210 // Opaque (`impl Trait`) type found in a return type.
102 // The `DefId` comes either from
103 // * the `impl Trait` ast::Ty node,
104 // * or the `existential type` declaration
105 // The substitutions are for the generics of the function in question.
106 // Opaque(DefId, Substs), 211 // Opaque(DefId, Substs),
107 212
108 // A type parameter; for example, `T` in `fn f<T>(x: T) {} 213 // A type parameter; for example, `T` in `fn f<T>(x: T) {}
109 // Param(ParamTy), 214 // Param(ParamTy),
110 215 /// A type variable used during type checking. Not to be confused with a
111 // A placeholder type - universally quantified higher-ranked type. 216 /// type parameter.
112 // Placeholder(ty::PlaceholderType), 217 Infer(InferTy),
113 218
114 // A type variable used during type checking. 219 /// A placeholder for a type which could not be computed; this is propagated
115 // Infer(InferTy), 220 /// to avoid useless error messages. Doubles as a placeholder where type
116 /// A placeholder for a type which could not be computed; this is 221 /// variables are inserted before type checking, since we want to try to
117 /// propagated to avoid useless error messages. 222 /// infer a better type here anyway -- for the IDE use case, we want to try
223 /// to infer as much as possible even in the presence of type errors.
118 Unknown, 224 Unknown,
119} 225}
120 226
121type TyRef = Arc<Ty>; 227/// A function signature.
122
123#[derive(Clone, PartialEq, Eq, Hash, Debug)] 228#[derive(Clone, PartialEq, Eq, Hash, Debug)]
124pub struct FnSig { 229pub struct FnSig {
125 input: Vec<Ty>, 230 input: Vec<Ty>,
@@ -138,8 +243,8 @@ impl Ty {
138 let inner_tys = inner 243 let inner_tys = inner
139 .iter() 244 .iter()
140 .map(|tr| Ty::from_hir(db, module, tr)) 245 .map(|tr| Ty::from_hir(db, module, tr))
141 .collect::<Cancelable<_>>()?; 246 .collect::<Cancelable<Vec<_>>>()?;
142 Ty::Tuple(inner_tys) 247 Ty::Tuple(inner_tys.into())
143 } 248 }
144 TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?, 249 TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?,
145 TypeRef::RawPtr(inner, mutability) => { 250 TypeRef::RawPtr(inner, mutability) => {
@@ -155,7 +260,7 @@ impl Ty {
155 let inner_ty = Ty::from_hir(db, module, inner)?; 260 let inner_ty = Ty::from_hir(db, module, inner)?;
156 Ty::Ref(Arc::new(inner_ty), *mutability) 261 Ty::Ref(Arc::new(inner_ty), *mutability)
157 } 262 }
158 TypeRef::Placeholder => Ty::Unknown, // TODO 263 TypeRef::Placeholder => Ty::Unknown,
159 TypeRef::Fn(params) => { 264 TypeRef::Fn(params) => {
160 let mut inner_tys = params 265 let mut inner_tys = params
161 .iter() 266 .iter()
@@ -179,13 +284,12 @@ impl Ty {
179 module: &Module, 284 module: &Module,
180 path: &Path, 285 path: &Path,
181 ) -> Cancelable<Self> { 286 ) -> Cancelable<Self> {
182 if path.is_ident() { 287 if let Some(name) = path.as_ident() {
183 let name = &path.segments[0]; 288 if let Some(int_ty) = primitive::IntTy::from_name(name) {
184 if let Some(int_ty) = primitive::IntTy::from_string(&name) {
185 return Ok(Ty::Int(int_ty)); 289 return Ok(Ty::Int(int_ty));
186 } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) { 290 } else if let Some(uint_ty) = primitive::UintTy::from_name(name) {
187 return Ok(Ty::Uint(uint_ty)); 291 return Ok(Ty::Uint(uint_ty));
188 } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) { 292 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
189 return Ok(Ty::Float(float_ty)); 293 return Ok(Ty::Float(float_ty));
190 } 294 }
191 } 295 }
@@ -219,7 +323,41 @@ impl Ty {
219 } 323 }
220 324
221 pub fn unit() -> Self { 325 pub fn unit() -> Self {
222 Ty::Tuple(Vec::new()) 326 Ty::Tuple(Arc::new([]))
327 }
328
329 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
330 f(self);
331 match self {
332 Ty::Slice(t) => Arc::make_mut(t).walk_mut(f),
333 Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f),
334 Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f),
335 Ty::Tuple(ts) => {
336 // Without an Arc::make_mut_slice, we can't avoid the clone here:
337 let mut v: Vec<_> = ts.iter().cloned().collect();
338 for t in &mut v {
339 t.walk_mut(f);
340 }
341 *ts = v.into();
342 }
343 Ty::FnPtr(sig) => {
344 let sig_mut = Arc::make_mut(sig);
345 for input in &mut sig_mut.input {
346 input.walk_mut(f);
347 }
348 sig_mut.output.walk_mut(f);
349 }
350 Ty::Adt { .. } => {} // need to walk type parameters later
351 _ => {}
352 }
353 }
354
355 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
356 self.walk_mut(&mut |ty_mut| {
357 let ty = mem::replace(ty_mut, Ty::Unknown);
358 *ty_mut = f(ty);
359 });
360 self
223 } 361 }
224} 362}
225 363
@@ -238,7 +376,7 @@ impl fmt::Display for Ty {
238 Ty::Never => write!(f, "!"), 376 Ty::Never => write!(f, "!"),
239 Ty::Tuple(ts) => { 377 Ty::Tuple(ts) => {
240 write!(f, "(")?; 378 write!(f, "(")?;
241 for t in ts { 379 for t in ts.iter() {
242 write!(f, "{},", t)?; 380 write!(f, "{},", t)?;
243 } 381 }
244 write!(f, ")") 382 write!(f, ")")
@@ -252,11 +390,16 @@ impl fmt::Display for Ty {
252 } 390 }
253 Ty::Adt { name, .. } => write!(f, "{}", name), 391 Ty::Adt { name, .. } => write!(f, "{}", name),
254 Ty::Unknown => write!(f, "[unknown]"), 392 Ty::Unknown => write!(f, "[unknown]"),
393 Ty::Infer(..) => write!(f, "_"),
255 } 394 }
256 } 395 }
257} 396}
258 397
259pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { 398// Functions returning declared types for items
399
400/// Compute the declared type of a function. This should not need to look at the
401/// function body (but currently uses the function AST, so does anyway - TODO).
402fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
260 let syntax = f.syntax(db); 403 let syntax = f.syntax(db);
261 let module = f.module(db)?; 404 let module = f.module(db)?;
262 let node = syntax.borrowed(); 405 let node = syntax.borrowed();
@@ -269,30 +412,30 @@ pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
269 .collect() 412 .collect()
270 }) 413 })
271 .unwrap_or_else(|| Ok(Vec::new()))?; 414 .unwrap_or_else(|| Ok(Vec::new()))?;
272 let output = Ty::from_ast_opt(db, &module, node.ret_type().and_then(|rt| rt.type_ref()))?; 415 let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
416 Ty::from_ast(db, &module, type_ref)?
417 } else {
418 Ty::unit()
419 };
273 let sig = FnSig { input, output }; 420 let sig = FnSig { input, output };
274 Ok(Ty::FnPtr(Arc::new(sig))) 421 Ok(Ty::FnPtr(Arc::new(sig)))
275} 422}
276 423
277pub fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Cancelable<Ty> { 424fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Cancelable<Ty> {
278 Ok(Ty::Adt { 425 Ok(Ty::Adt {
279 def_id: s.def_id(), 426 def_id: s.def_id(),
280 name: s 427 name: s.name(db)?.unwrap_or_else(Name::missing),
281 .name(db)?
282 .unwrap_or_else(|| SmolStr::new("[unnamed struct]")),
283 }) 428 })
284} 429}
285 430
286pub fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Cancelable<Ty> { 431pub fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Cancelable<Ty> {
287 Ok(Ty::Adt { 432 Ok(Ty::Adt {
288 def_id: s.def_id(), 433 def_id: s.def_id(),
289 name: s 434 name: s.name(db)?.unwrap_or_else(Name::missing),
290 .name(db)?
291 .unwrap_or_else(|| SmolStr::new("[unnamed enum]")),
292 }) 435 })
293} 436}
294 437
295pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { 438pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
296 let def = def_id.resolve(db)?; 439 let def = def_id.resolve(db)?;
297 match def { 440 match def {
298 Def::Module(..) => { 441 Def::Module(..) => {
@@ -309,11 +452,7 @@ pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
309 } 452 }
310} 453}
311 454
312pub(super) fn type_for_field( 455pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) -> Cancelable<Ty> {
313 db: &impl HirDatabase,
314 def_id: DefId,
315 field: SmolStr,
316) -> Cancelable<Ty> {
317 let def = def_id.resolve(db)?; 456 let def = def_id.resolve(db)?;
318 let variant_data = match def { 457 let variant_data = match def {
319 Def::Struct(s) => { 458 Def::Struct(s) => {
@@ -336,23 +475,29 @@ pub(super) fn type_for_field(
336 Ty::from_hir(db, &module, &type_ref) 475 Ty::from_hir(db, &module, &type_ref)
337} 476}
338 477
478/// The result of type inference: A mapping from expressions and patterns to types.
339#[derive(Clone, PartialEq, Eq, Debug)] 479#[derive(Clone, PartialEq, Eq, Debug)]
340pub struct InferenceResult { 480pub struct InferenceResult {
341 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 481 type_of: FxHashMap<LocalSyntaxPtr, Ty>,
342} 482}
343 483
344impl InferenceResult { 484impl InferenceResult {
485 /// Returns the type of the given syntax node, if it was inferred. Will
486 /// return `None` for syntax nodes not in the inferred function or not
487 /// pointing to an expression/pattern, `Some(Ty::Unknown)` for
488 /// expressions/patterns that could not be inferred.
345 pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> { 489 pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> {
346 self.type_of.get(&LocalSyntaxPtr::new(node)).cloned() 490 self.type_of.get(&LocalSyntaxPtr::new(node)).cloned()
347 } 491 }
348} 492}
349 493
494/// The inference context contains all information needed during type inference.
350#[derive(Clone, Debug)] 495#[derive(Clone, Debug)]
351pub struct InferenceContext<'a, D: HirDatabase> { 496struct InferenceContext<'a, D: HirDatabase> {
352 db: &'a D, 497 db: &'a D,
353 scopes: Arc<FnScopes>, 498 scopes: Arc<FnScopes>,
354 module: Module, 499 module: Module,
355 // TODO unification tables... 500 var_unification_table: InPlaceUnificationTable<TypeVarId>,
356 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 501 type_of: FxHashMap<LocalSyntaxPtr, Ty>,
357} 502}
358 503
@@ -360,33 +505,116 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
360 fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self { 505 fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
361 InferenceContext { 506 InferenceContext {
362 type_of: FxHashMap::default(), 507 type_of: FxHashMap::default(),
508 var_unification_table: InPlaceUnificationTable::new(),
363 db, 509 db,
364 scopes, 510 scopes,
365 module, 511 module,
366 } 512 }
367 } 513 }
368 514
515 fn resolve_all(mut self) -> InferenceResult {
516 let mut types = mem::replace(&mut self.type_of, FxHashMap::default());
517 for ty in types.values_mut() {
518 let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
519 *ty = resolved;
520 }
521 InferenceResult { type_of: types }
522 }
523
369 fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) { 524 fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) {
370 self.type_of.insert(LocalSyntaxPtr::new(node), ty); 525 self.type_of.insert(LocalSyntaxPtr::new(node), ty);
371 } 526 }
372 527
373 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> { 528 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
374 if *ty1 == Ty::Unknown { 529 match (ty1, ty2) {
375 return Some(ty2.clone()); 530 (Ty::Unknown, ..) => true,
376 } 531 (.., Ty::Unknown) => true,
377 if *ty2 == Ty::Unknown { 532 (Ty::Bool, _)
378 return Some(ty1.clone()); 533 | (Ty::Str, _)
534 | (Ty::Never, _)
535 | (Ty::Char, _)
536 | (Ty::Int(..), Ty::Int(..))
537 | (Ty::Uint(..), Ty::Uint(..))
538 | (Ty::Float(..), Ty::Float(..)) => ty1 == ty2,
539 (
540 Ty::Adt {
541 def_id: def_id1, ..
542 },
543 Ty::Adt {
544 def_id: def_id2, ..
545 },
546 ) if def_id1 == def_id2 => true,
547 (Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2),
548 (Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2),
549 (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2),
550 (Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true,
551 (Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => ts1
552 .iter()
553 .zip(ts2.iter())
554 .all(|(t1, t2)| self.unify(t1, t2)),
555 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) => {
556 self.var_unification_table.union(*tv1, *tv2);
557 true
558 }
559 (Ty::Infer(InferTy::TypeVar(tv)), other) | (other, Ty::Infer(InferTy::TypeVar(tv))) => {
560 self.var_unification_table
561 .union_value(*tv, TypeVarValue::Known(other.clone()));
562 true
563 }
564 _ => false,
379 } 565 }
380 if ty1 == ty2 { 566 }
381 return Some(ty1.clone()); 567
568 fn new_type_var(&mut self) -> Ty {
569 Ty::Infer(InferTy::TypeVar(
570 self.var_unification_table.new_key(TypeVarValue::Unknown),
571 ))
572 }
573
574 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
575 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
576 match ty {
577 Ty::Unknown => self.new_type_var(),
578 _ => ty,
382 } 579 }
383 // TODO implement actual unification
384 return None;
385 } 580 }
386 581
387 fn unify_with_coercion(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> { 582 fn insert_type_vars(&mut self, ty: Ty) -> Ty {
388 // TODO implement coercion 583 ty.fold(&mut |ty| self.insert_type_vars_shallow(ty))
389 self.unify(ty1, ty2) 584 }
585
586 /// Resolves the type as far as currently possible, replacing type variables
587 /// by their known types. All types returned by the infer_* functions should
588 /// be resolved as far as possible, i.e. contain no type variables with
589 /// known type.
590 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
591 ty.fold(&mut |ty| match ty {
592 Ty::Infer(InferTy::TypeVar(tv)) => {
593 if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() {
594 // known_ty may contain other variables that are known by now
595 self.resolve_ty_as_possible(known_ty.clone())
596 } else {
597 Ty::Infer(InferTy::TypeVar(tv))
598 }
599 }
600 _ => ty,
601 })
602 }
603
604 /// Resolves the type completely; type variables without known type are
605 /// replaced by Ty::Unknown.
606 fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
607 ty.fold(&mut |ty| match ty {
608 Ty::Infer(InferTy::TypeVar(tv)) => {
609 if let Some(known_ty) = self.var_unification_table.probe_value(tv).known() {
610 // known_ty may contain other variables that are known by now
611 self.resolve_ty_completely(known_ty.clone())
612 } else {
613 Ty::Unknown
614 }
615 }
616 _ => ty,
617 })
390 } 618 }
391 619
392 fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> { 620 fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> {
@@ -397,21 +625,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
397 let name = ctry!(ast_path.segment().and_then(|s| s.name_ref())); 625 let name = ctry!(ast_path.segment().and_then(|s| s.name_ref()));
398 if let Some(scope_entry) = self.scopes.resolve_local_name(name) { 626 if let Some(scope_entry) = self.scopes.resolve_local_name(name) {
399 let ty = ctry!(self.type_of.get(&scope_entry.ptr())); 627 let ty = ctry!(self.type_of.get(&scope_entry.ptr()));
400 return Ok(Some(ty.clone())); 628 let ty = self.resolve_ty_as_possible(ty.clone());
629 return Ok(Some(ty));
401 }; 630 };
402 }; 631 };
403 632
404 // resolve in module 633 // resolve in module
405 let resolved = ctry!(self.module.resolve_path(self.db, &path)?.take_values()); 634 let resolved = ctry!(self.module.resolve_path(self.db, &path)?.take_values());
406 let ty = self.db.type_for_def(resolved)?; 635 let ty = self.db.type_for_def(resolved)?;
407 // TODO we will need to add type variables for type parameters etc. here 636 let ty = self.insert_type_vars(ty);
408 Ok(Some(ty)) 637 Ok(Some(ty))
409 } 638 }
410 639
411 fn resolve_variant( 640 fn resolve_variant(&self, path: Option<ast::Path>) -> Cancelable<(Ty, Option<DefId>)> {
412 &self,
413 path: Option<ast::Path>,
414 ) -> Cancelable<(Ty, Option<Arc<VariantData>>)> {
415 let path = if let Some(path) = path.and_then(Path::from_ast) { 641 let path = if let Some(path) = path.and_then(Path::from_ast) {
416 path 642 path
417 } else { 643 } else {
@@ -424,102 +650,116 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
424 }; 650 };
425 Ok(match def_id.resolve(self.db)? { 651 Ok(match def_id.resolve(self.db)? {
426 Def::Struct(s) => { 652 Def::Struct(s) => {
427 let struct_data = self.db.struct_data(def_id)?;
428 let ty = type_for_struct(self.db, s)?; 653 let ty = type_for_struct(self.db, s)?;
429 (ty, Some(struct_data.variant_data().clone())) 654 (ty, Some(def_id))
430 } 655 }
431 _ => (Ty::Unknown, None), 656 _ => (Ty::Unknown, None),
432 }) 657 })
433 } 658 }
434 659
435 fn infer_expr_opt(&mut self, expr: Option<ast::Expr>) -> Cancelable<Ty> { 660 fn infer_expr_opt(
661 &mut self,
662 expr: Option<ast::Expr>,
663 expected: &Expectation,
664 ) -> Cancelable<Ty> {
436 if let Some(e) = expr { 665 if let Some(e) = expr {
437 self.infer_expr(e) 666 self.infer_expr(e, expected)
438 } else { 667 } else {
439 Ok(Ty::Unknown) 668 Ok(Ty::Unknown)
440 } 669 }
441 } 670 }
442 671
443 fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> { 672 fn infer_expr(&mut self, expr: ast::Expr, expected: &Expectation) -> Cancelable<Ty> {
444 let ty = match expr { 673 let ty = match expr {
445 ast::Expr::IfExpr(e) => { 674 ast::Expr::IfExpr(e) => {
446 if let Some(condition) = e.condition() { 675 if let Some(condition) = e.condition() {
447 // TODO if no pat, this should be bool 676 let expected = if condition.pat().is_none() {
448 self.infer_expr_opt(condition.expr())?; 677 Expectation::has_type(Ty::Bool)
678 } else {
679 Expectation::none()
680 };
681 self.infer_expr_opt(condition.expr(), &expected)?;
449 // TODO write type for pat 682 // TODO write type for pat
450 }; 683 };
451 let if_ty = self.infer_block_opt(e.then_branch())?; 684 let if_ty = self.infer_block_opt(e.then_branch(), expected)?;
452 let else_ty = self.infer_block_opt(e.else_branch())?; 685 if let Some(else_branch) = e.else_branch() {
453 if let Some(ty) = self.unify(&if_ty, &else_ty) { 686 self.infer_block(else_branch, expected)?;
454 ty
455 } else { 687 } else {
456 // TODO report diagnostic 688 // no else branch -> unit
457 Ty::Unknown 689 self.unify(&expected.ty, &Ty::unit()); // actually coerce
458 } 690 }
691 if_ty
459 } 692 }
460 ast::Expr::BlockExpr(e) => self.infer_block_opt(e.block())?, 693 ast::Expr::BlockExpr(e) => self.infer_block_opt(e.block(), expected)?,
461 ast::Expr::LoopExpr(e) => { 694 ast::Expr::LoopExpr(e) => {
462 self.infer_block_opt(e.loop_body())?; 695 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?;
463 // TODO never, or the type of the break param 696 // TODO never, or the type of the break param
464 Ty::Unknown 697 Ty::Unknown
465 } 698 }
466 ast::Expr::WhileExpr(e) => { 699 ast::Expr::WhileExpr(e) => {
467 if let Some(condition) = e.condition() { 700 if let Some(condition) = e.condition() {
468 // TODO if no pat, this should be bool 701 let expected = if condition.pat().is_none() {
469 self.infer_expr_opt(condition.expr())?; 702 Expectation::has_type(Ty::Bool)
703 } else {
704 Expectation::none()
705 };
706 self.infer_expr_opt(condition.expr(), &expected)?;
470 // TODO write type for pat 707 // TODO write type for pat
471 }; 708 };
472 self.infer_block_opt(e.loop_body())?; 709 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?;
473 // TODO always unit? 710 // TODO always unit?
474 Ty::Unknown 711 Ty::unit()
475 } 712 }
476 ast::Expr::ForExpr(e) => { 713 ast::Expr::ForExpr(e) => {
477 let _iterable_ty = self.infer_expr_opt(e.iterable()); 714 let _iterable_ty = self.infer_expr_opt(e.iterable(), &Expectation::none());
478 if let Some(_pat) = e.pat() { 715 if let Some(_pat) = e.pat() {
479 // TODO write type for pat 716 // TODO write type for pat
480 } 717 }
481 self.infer_block_opt(e.loop_body())?; 718 self.infer_block_opt(e.loop_body(), &Expectation::has_type(Ty::unit()))?;
482 // TODO always unit? 719 // TODO always unit?
483 Ty::Unknown 720 Ty::unit()
484 } 721 }
485 ast::Expr::LambdaExpr(e) => { 722 ast::Expr::LambdaExpr(e) => {
486 let _body_ty = self.infer_expr_opt(e.body())?; 723 let _body_ty = self.infer_expr_opt(e.body(), &Expectation::none())?;
487 Ty::Unknown 724 Ty::Unknown
488 } 725 }
489 ast::Expr::CallExpr(e) => { 726 ast::Expr::CallExpr(e) => {
490 let callee_ty = self.infer_expr_opt(e.expr())?; 727 let callee_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
491 if let Some(arg_list) = e.arg_list() { 728 let (arg_tys, ret_ty) = match &callee_ty {
492 for arg in arg_list.args() { 729 Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()),
493 // TODO unify / expect argument type
494 self.infer_expr(arg)?;
495 }
496 }
497 match callee_ty {
498 Ty::FnPtr(sig) => sig.output.clone(),
499 _ => { 730 _ => {
500 // not callable 731 // not callable
501 // TODO report an error? 732 // TODO report an error?
502 Ty::Unknown 733 (&[][..], Ty::Unknown)
734 }
735 };
736 if let Some(arg_list) = e.arg_list() {
737 for (i, arg) in arg_list.args().enumerate() {
738 self.infer_expr(
739 arg,
740 &Expectation::has_type(arg_tys.get(i).cloned().unwrap_or(Ty::Unknown)),
741 )?;
503 } 742 }
504 } 743 }
744 ret_ty
505 } 745 }
506 ast::Expr::MethodCallExpr(e) => { 746 ast::Expr::MethodCallExpr(e) => {
507 let _receiver_ty = self.infer_expr_opt(e.expr())?; 747 let _receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
508 if let Some(arg_list) = e.arg_list() { 748 if let Some(arg_list) = e.arg_list() {
509 for arg in arg_list.args() { 749 for arg in arg_list.args() {
510 // TODO unify / expect argument type 750 // TODO unify / expect argument type
511 self.infer_expr(arg)?; 751 self.infer_expr(arg, &Expectation::none())?;
512 } 752 }
513 } 753 }
514 Ty::Unknown 754 Ty::Unknown
515 } 755 }
516 ast::Expr::MatchExpr(e) => { 756 ast::Expr::MatchExpr(e) => {
517 let _ty = self.infer_expr_opt(e.expr())?; 757 let _ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
518 if let Some(match_arm_list) = e.match_arm_list() { 758 if let Some(match_arm_list) = e.match_arm_list() {
519 for arm in match_arm_list.arms() { 759 for arm in match_arm_list.arms() {
520 // TODO type the bindings in pat 760 // TODO type the bindings in pat
521 // TODO type the guard 761 // TODO type the guard
522 let _ty = self.infer_expr_opt(arm.expr())?; 762 let _ty = self.infer_expr_opt(arm.expr(), &Expectation::none())?;
523 } 763 }
524 // TODO unify all the match arm types 764 // TODO unify all the match arm types
525 Ty::Unknown 765 Ty::Unknown
@@ -532,10 +772,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
532 ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown), 772 ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown),
533 ast::Expr::ContinueExpr(_e) => Ty::Never, 773 ast::Expr::ContinueExpr(_e) => Ty::Never,
534 ast::Expr::BreakExpr(_e) => Ty::Never, 774 ast::Expr::BreakExpr(_e) => Ty::Never,
535 ast::Expr::ParenExpr(e) => self.infer_expr_opt(e.expr())?, 775 ast::Expr::ParenExpr(e) => self.infer_expr_opt(e.expr(), expected)?,
536 ast::Expr::Label(_e) => Ty::Unknown, 776 ast::Expr::Label(_e) => Ty::Unknown,
537 ast::Expr::ReturnExpr(e) => { 777 ast::Expr::ReturnExpr(e) => {
538 self.infer_expr_opt(e.expr())?; 778 // TODO expect return type of function
779 self.infer_expr_opt(e.expr(), &Expectation::none())?;
539 Ty::Never 780 Ty::Never
540 } 781 }
541 ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => { 782 ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
@@ -543,11 +784,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
543 Ty::Unknown 784 Ty::Unknown
544 } 785 }
545 ast::Expr::StructLit(e) => { 786 ast::Expr::StructLit(e) => {
546 let (ty, _variant_data) = self.resolve_variant(e.path())?; 787 let (ty, def_id) = self.resolve_variant(e.path())?;
547 if let Some(nfl) = e.named_field_list() { 788 if let Some(nfl) = e.named_field_list() {
548 for field in nfl.fields() { 789 for field in nfl.fields() {
549 // TODO unify with / expect field type 790 let field_ty = if let (Some(def_id), Some(nr)) = (def_id, field.name_ref())
550 self.infer_expr_opt(field.expr())?; 791 {
792 self.db.type_for_field(def_id, nr.as_name())?
793 } else {
794 Ty::Unknown
795 };
796 self.infer_expr_opt(field.expr(), &Expectation::has_type(field_ty))?;
551 } 797 }
552 } 798 }
553 ty 799 ty
@@ -558,40 +804,42 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
558 } 804 }
559 ast::Expr::IndexExpr(_e) => Ty::Unknown, 805 ast::Expr::IndexExpr(_e) => Ty::Unknown,
560 ast::Expr::FieldExpr(e) => { 806 ast::Expr::FieldExpr(e) => {
561 let receiver_ty = self.infer_expr_opt(e.expr())?; 807 let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
562 if let Some(nr) = e.name_ref() { 808 if let Some(nr) = e.name_ref() {
563 let text = nr.text(); 809 let ty = match receiver_ty {
564 match receiver_ty {
565 Ty::Tuple(fields) => { 810 Ty::Tuple(fields) => {
566 let i = text.parse::<usize>().ok(); 811 let i = nr.text().parse::<usize>().ok();
567 i.and_then(|i| fields.get(i).cloned()) 812 i.and_then(|i| fields.get(i).cloned())
568 .unwrap_or(Ty::Unknown) 813 .unwrap_or(Ty::Unknown)
569 } 814 }
570 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, text)?, 815 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, nr.as_name())?,
571 _ => Ty::Unknown, 816 _ => Ty::Unknown,
572 } 817 };
818 self.insert_type_vars(ty)
573 } else { 819 } else {
574 Ty::Unknown 820 Ty::Unknown
575 } 821 }
576 } 822 }
577 ast::Expr::TryExpr(e) => { 823 ast::Expr::TryExpr(e) => {
578 let _inner_ty = self.infer_expr_opt(e.expr())?; 824 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
579 Ty::Unknown 825 Ty::Unknown
580 } 826 }
581 ast::Expr::CastExpr(e) => { 827 ast::Expr::CastExpr(e) => {
582 let _inner_ty = self.infer_expr_opt(e.expr())?; 828 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
583 let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?; 829 let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?;
830 let cast_ty = self.insert_type_vars(cast_ty);
584 // TODO do the coercion... 831 // TODO do the coercion...
585 cast_ty 832 cast_ty
586 } 833 }
587 ast::Expr::RefExpr(e) => { 834 ast::Expr::RefExpr(e) => {
588 let inner_ty = self.infer_expr_opt(e.expr())?; 835 // TODO pass the expectation down
836 let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
589 let m = Mutability::from_mutable(e.is_mut()); 837 let m = Mutability::from_mutable(e.is_mut());
590 // TODO reference coercions etc. 838 // TODO reference coercions etc.
591 Ty::Ref(Arc::new(inner_ty), m) 839 Ty::Ref(Arc::new(inner_ty), m)
592 } 840 }
593 ast::Expr::PrefixExpr(e) => { 841 ast::Expr::PrefixExpr(e) => {
594 let inner_ty = self.infer_expr_opt(e.expr())?; 842 let inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
595 match e.op() { 843 match e.op() {
596 Some(PrefixOp::Deref) => { 844 Some(PrefixOp::Deref) => {
597 match inner_ty { 845 match inner_ty {
@@ -609,28 +857,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
609 ast::Expr::BinExpr(_e) => Ty::Unknown, 857 ast::Expr::BinExpr(_e) => Ty::Unknown,
610 ast::Expr::Literal(_e) => Ty::Unknown, 858 ast::Expr::Literal(_e) => Ty::Unknown,
611 }; 859 };
860 // use a new type variable if we got Ty::Unknown here
861 let ty = self.insert_type_vars_shallow(ty);
862 self.unify(&ty, &expected.ty);
612 self.write_ty(expr.syntax(), ty.clone()); 863 self.write_ty(expr.syntax(), ty.clone());
613 Ok(ty) 864 Ok(ty)
614 } 865 }
615 866
616 fn infer_block_opt(&mut self, node: Option<ast::Block>) -> Cancelable<Ty> { 867 fn infer_block_opt(
868 &mut self,
869 node: Option<ast::Block>,
870 expected: &Expectation,
871 ) -> Cancelable<Ty> {
617 if let Some(b) = node { 872 if let Some(b) = node {
618 self.infer_block(b) 873 self.infer_block(b, expected)
619 } else { 874 } else {
620 Ok(Ty::Unknown) 875 Ok(Ty::Unknown)
621 } 876 }
622 } 877 }
623 878
624 fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> { 879 fn infer_block(&mut self, node: ast::Block, expected: &Expectation) -> Cancelable<Ty> {
625 for stmt in node.statements() { 880 for stmt in node.statements() {
626 match stmt { 881 match stmt {
627 ast::Stmt::LetStmt(stmt) => { 882 ast::Stmt::LetStmt(stmt) => {
628 let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?; 883 let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?;
884 let decl_ty = self.insert_type_vars(decl_ty);
629 let ty = if let Some(expr) = stmt.initializer() { 885 let ty = if let Some(expr) = stmt.initializer() {
630 // TODO pass expectation 886 let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?;
631 let expr_ty = self.infer_expr(expr)?; 887 expr_ty
632 self.unify_with_coercion(&expr_ty, &decl_ty)
633 .unwrap_or(decl_ty)
634 } else { 888 } else {
635 decl_ty 889 decl_ty
636 }; 890 };
@@ -640,12 +894,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
640 }; 894 };
641 } 895 }
642 ast::Stmt::ExprStmt(expr_stmt) => { 896 ast::Stmt::ExprStmt(expr_stmt) => {
643 self.infer_expr_opt(expr_stmt.expr())?; 897 self.infer_expr_opt(expr_stmt.expr(), &Expectation::none())?;
644 } 898 }
645 } 899 }
646 } 900 }
647 let ty = if let Some(expr) = node.expr() { 901 let ty = if let Some(expr) = node.expr() {
648 self.infer_expr(expr)? 902 self.infer_expr(expr, expected)?
649 } else { 903 } else {
650 Ty::unit() 904 Ty::unit()
651 }; 905 };
@@ -654,7 +908,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
654 } 908 }
655} 909}
656 910
657pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceResult> { 911pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
912 let function = Function::new(def_id); // TODO: consts also need inference
658 let scopes = function.scopes(db); 913 let scopes = function.scopes(db);
659 let module = function.module(db)?; 914 let module = function.module(db)?;
660 let mut ctx = InferenceContext::new(db, scopes, module); 915 let mut ctx = InferenceContext::new(db, scopes, module);
@@ -671,25 +926,27 @@ pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceR
671 }; 926 };
672 if let Some(type_ref) = param.type_ref() { 927 if let Some(type_ref) = param.type_ref() {
673 let ty = Ty::from_ast(db, &ctx.module, type_ref)?; 928 let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
929 let ty = ctx.insert_type_vars(ty);
674 ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); 930 ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
675 } else { 931 } else {
676 // TODO self param 932 // TODO self param
933 let type_var = ctx.new_type_var();
677 ctx.type_of 934 ctx.type_of
678 .insert(LocalSyntaxPtr::new(pat.syntax()), Ty::Unknown); 935 .insert(LocalSyntaxPtr::new(pat.syntax()), type_var);
679 }; 936 };
680 } 937 }
681 } 938 }
682 939
683 // TODO get Ty for node.ret_type() and pass that to infer_block as expectation 940 let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
684 // (see Expectation in rustc_typeck) 941 let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
942 ctx.insert_type_vars(ty)
943 } else {
944 Ty::unit()
945 };
685 946
686 if let Some(block) = node.body() { 947 if let Some(block) = node.body() {
687 ctx.infer_block(block)?; 948 ctx.infer_block(block, &Expectation::has_type(ret_ty))?;
688 } 949 }
689 950
690 // TODO 'resolve' the types: replace inference variables by their inferred results 951 Ok(Arc::new(ctx.resolve_all()))
691
692 Ok(InferenceResult {
693 type_of: ctx.type_of,
694 })
695} 952}
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index ad79b17e4..498d42d52 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -1,5 +1,7 @@
1use std::fmt; 1use std::fmt;
2 2
3use crate::{Name, KnownName};
4
3#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] 5#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
4pub enum IntTy { 6pub enum IntTy {
5 Isize, 7 Isize,
@@ -34,14 +36,14 @@ impl IntTy {
34 } 36 }
35 } 37 }
36 38
37 pub fn from_string(s: &str) -> Option<IntTy> { 39 pub fn from_name(name: &Name) -> Option<IntTy> {
38 match s { 40 match name.as_known_name()? {
39 "isize" => Some(IntTy::Isize), 41 KnownName::Isize => Some(IntTy::Isize),
40 "i8" => Some(IntTy::I8), 42 KnownName::I8 => Some(IntTy::I8),
41 "i16" => Some(IntTy::I16), 43 KnownName::I16 => Some(IntTy::I16),
42 "i32" => Some(IntTy::I32), 44 KnownName::I32 => Some(IntTy::I32),
43 "i64" => Some(IntTy::I64), 45 KnownName::I64 => Some(IntTy::I64),
44 "i128" => Some(IntTy::I128), 46 KnownName::I128 => Some(IntTy::I128),
45 _ => None, 47 _ => None,
46 } 48 }
47 } 49 }
@@ -69,14 +71,14 @@ impl UintTy {
69 } 71 }
70 } 72 }
71 73
72 pub fn from_string(s: &str) -> Option<UintTy> { 74 pub fn from_name(name: &Name) -> Option<UintTy> {
73 match s { 75 match name.as_known_name()? {
74 "usize" => Some(UintTy::Usize), 76 KnownName::Usize => Some(UintTy::Usize),
75 "u8" => Some(UintTy::U8), 77 KnownName::U8 => Some(UintTy::U8),
76 "u16" => Some(UintTy::U16), 78 KnownName::U16 => Some(UintTy::U16),
77 "u32" => Some(UintTy::U32), 79 KnownName::U32 => Some(UintTy::U32),
78 "u64" => Some(UintTy::U64), 80 KnownName::U64 => Some(UintTy::U64),
79 "u128" => Some(UintTy::U128), 81 KnownName::U128 => Some(UintTy::U128),
80 _ => None, 82 _ => None,
81 } 83 }
82 } 84 }
@@ -120,10 +122,10 @@ impl FloatTy {
120 } 122 }
121 } 123 }
122 124
123 pub fn from_string(s: &str) -> Option<FloatTy> { 125 pub fn from_name(name: &Name) -> Option<FloatTy> {
124 match s { 126 match name.as_known_name()? {
125 "f32" => Some(FloatTy::F32), 127 KnownName::F32 => Some(FloatTy::F32),
126 "f64" => Some(FloatTy::F64), 128 KnownName::F64 => Some(FloatTy::F64),
127 _ => None, 129 _ => None,
128 } 130 }
129 } 131 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index a76925b58..93bf431c4 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -113,6 +113,27 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
113 ); 113 );
114} 114}
115 115
116#[test]
117fn infer_backwards() {
118 check_inference(
119 r#"
120fn takes_u32(x: u32) {}
121
122struct S { i32_field: i32 }
123
124fn test() -> &mut &f64 {
125 let a = unknown_function();
126 takes_u32(a);
127 let b = unknown_function();
128 S { i32_field: b };
129 let c = unknown_function();
130 &mut &c
131}
132"#,
133 "0006_backwards.txt",
134 );
135}
136
116fn infer(content: &str) -> String { 137fn infer(content: &str) -> String {
117 let (db, _, file_id) = MockDatabase::with_single_file(content); 138 let (db, _, file_id) = MockDatabase::with_single_file(content);
118 let source_file = db.source_file(file_id); 139 let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty/tests/data/0002_let.txt b/crates/ra_hir/src/ty/tests/data/0002_let.txt
index 2d0d1f57b..916ca25a1 100644
--- a/crates/ra_hir/src/ty/tests/data/0002_let.txt
+++ b/crates/ra_hir/src/ty/tests/data/0002_let.txt
@@ -1,5 +1,5 @@
1[21; 22) 'a': [unknown] 1[21; 22) 'a': [unknown]
2[52; 53) '1': [unknown] 2[52; 53) '1': usize
3[11; 71) '{ ...= b; }': () 3[11; 71) '{ ...= b; }': ()
4[63; 64) 'c': usize 4[63; 64) 'c': usize
5[25; 31) '1isize': [unknown] 5[25; 31) '1isize': [unknown]
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.txt b/crates/ra_hir/src/ty/tests/data/0003_paths.txt
index dcb5456ae..2a12d264f 100644
--- a/crates/ra_hir/src/ty/tests/data/0003_paths.txt
+++ b/crates/ra_hir/src/ty/tests/data/0003_paths.txt
@@ -1,7 +1,7 @@
1[15; 20) '{ 1 }': [unknown] 1[15; 20) '{ 1 }': u32
2[17; 18) '1': [unknown] 2[17; 18) '1': u32
3[50; 51) '1': [unknown] 3[50; 51) '1': u32
4[48; 53) '{ 1 }': [unknown] 4[48; 53) '{ 1 }': u32
5[82; 88) 'b::c()': u32 5[82; 88) 'b::c()': u32
6[67; 91) '{ ...c(); }': () 6[67; 91) '{ ...c(); }': ()
7[73; 74) 'a': fn() -> u32 7[73; 74) 'a': fn() -> u32
diff --git a/crates/ra_hir/src/ty/tests/data/0004_struct.txt b/crates/ra_hir/src/ty/tests/data/0004_struct.txt
index cc8f3665b..b4af18b87 100644
--- a/crates/ra_hir/src/ty/tests/data/0004_struct.txt
+++ b/crates/ra_hir/src/ty/tests/data/0004_struct.txt
@@ -1,5 +1,5 @@
1[86; 90) 'C(1)': [unknown] 1[86; 90) 'C(1)': [unknown]
2[121; 122) 'B': [unknown] 2[121; 122) 'B': B
3[86; 87) 'C': [unknown] 3[86; 87) 'C': [unknown]
4[129; 130) '1': [unknown] 4[129; 130) '1': [unknown]
5[107; 108) 'a': A 5[107; 108) 'a': A
@@ -13,4 +13,4 @@
13[96; 97) 'B': [unknown] 13[96; 97) 'B': [unknown]
14[88; 89) '1': [unknown] 14[88; 89) '1': [unknown]
15[82; 83) 'c': [unknown] 15[82; 83) 'c': [unknown]
16[127; 131) 'C(1)': [unknown] 16[127; 131) 'C(1)': C
diff --git a/crates/ra_hir/src/ty/tests/data/0006_backwards.txt b/crates/ra_hir/src/ty/tests/data/0006_backwards.txt
new file mode 100644
index 000000000..120069401
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0006_backwards.txt
@@ -0,0 +1,20 @@
1[22; 24) '{}': ()
2[14; 15) 'x': u32
3[142; 158) 'unknow...nction': [unknown]
4[126; 127) 'a': u32
5[198; 216) 'unknow...tion()': f64
6[228; 229) 'c': f64
7[198; 214) 'unknow...nction': [unknown]
8[166; 184) 'S { i3...d: b }': S
9[222; 229) '&mut &c': &mut &f64
10[194; 195) 'c': f64
11[92; 110) 'unknow...tion()': u32
12[142; 160) 'unknow...tion()': i32
13[92; 108) 'unknow...nction': [unknown]
14[116; 128) 'takes_u32(a)': ()
15[78; 231) '{ ...t &c }': &mut &f64
16[227; 229) '&c': &f64
17[88; 89) 'a': u32
18[181; 182) 'b': i32
19[116; 125) 'takes_u32': fn(u32,) -> ()
20[138; 139) 'b': i32