diff options
Diffstat (limited to 'crates/ra_hir')
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" | |||
5 | authors = ["Aleksey Kladov <[email protected]>"] | 5 | authors = ["Aleksey Kladov <[email protected]>"] |
6 | 6 | ||
7 | [dependencies] | 7 | [dependencies] |
8 | arrayvec = "0.4.9" | 8 | arrayvec = "0.4.10" |
9 | log = "0.4.5" | 9 | log = "0.4.5" |
10 | relative-path = "0.4.0" | 10 | relative-path = "0.4.0" |
11 | salsa = "0.8.0" | 11 | salsa = "0.9.0" |
12 | rustc-hash = "1.0" | 12 | rustc-hash = "1.0" |
13 | parking_lot = "0.6.4" | 13 | parking_lot = "0.7.0" |
14 | id-arena = "2.0" | 14 | id-arena = "2.0" |
15 | ena = "0.11" | ||
15 | ra_syntax = { path = "../ra_syntax" } | 16 | ra_syntax = { path = "../ra_syntax" } |
16 | ra_editor = { path = "../ra_editor" } | 17 | ra_editor = { path = "../ra_editor" } |
17 | ra_db = { path = "../ra_db" } | 18 | ra_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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}}; | 3 | use ra_syntax::ast::{self, NameOwner, StructFlavor}; |
4 | 4 | ||
5 | use crate::{ | 5 | use 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)] |
38 | pub struct StructData { | 38 | pub struct StructData { |
39 | name: Option<SmolStr>, | 39 | name: Option<Name>, |
40 | variant_data: Arc<VariantData>, | 40 | variant_data: Arc<VariantData>, |
41 | } | 41 | } |
42 | 42 | ||
43 | impl StructData { | 43 | impl 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)] |
79 | pub struct EnumData { | 83 | pub 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 | ||
84 | impl EnumData { | 88 | impl 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)] |
107 | pub struct StructField { | 109 | pub struct StructField { |
108 | name: SmolStr, | 110 | name: Name, |
109 | type_ref: TypeRef, | 111 | type_ref: TypeRef, |
110 | } | 112 | } |
111 | 113 | ||
112 | impl StructField { | 114 | impl 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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::SyntaxNode; |
4 | SmolStr, | ||
5 | SyntaxNode, | ||
6 | ast::FnDefNode, | ||
7 | }; | ||
8 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable}; | 4 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable}; |
9 | 5 | ||
10 | use crate::{ | 6 | use 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! { | |||
24 | pub trait HirDatabase: SyntaxDatabase | 19 | pub 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 | ||
14 | use crate::{ DefId, HirDatabase, ty::InferenceResult, Module }; | 14 | use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module}; |
15 | 15 | ||
16 | pub use self::scope::FnScopes; | 16 | pub use self::scope::FnScopes; |
17 | 17 | ||
18 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 18 | #[derive(Debug)] |
19 | pub struct FnId(pub(crate) DefId); | ||
20 | |||
21 | pub struct Function { | 19 | pub struct Function { |
22 | pub(crate) fn_id: FnId, | 20 | def_id: DefId, |
23 | } | 21 | } |
24 | 22 | ||
25 | impl Function { | 23 | impl 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 @@ | |||
1 | use rustc_hash::{FxHashMap, FxHashSet}; | 1 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use 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 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | arena::{Arena, Id}, | 11 | arena::{Arena, Id}, |
12 | Name, AsName, | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | pub(crate) type ScopeId = Id<ScopeData>; | 15 | pub(crate) type ScopeId = Id<ScopeData>; |
@@ -22,7 +23,7 @@ pub struct FnScopes { | |||
22 | 23 | ||
23 | #[derive(Debug, PartialEq, Eq)] | 24 | #[derive(Debug, PartialEq, Eq)] |
24 | pub struct ScopeEntry { | 25 | pub 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 | ||
171 | impl ScopeEntry { | 173 | impl 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 { | |||
334 | mod tests { | 336 | mod 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 @@ | |||
1 | use ra_syntax::SmolStr; | ||
2 | pub use ra_db::CrateId; | 1 | pub use ra_db::CrateId; |
3 | 2 | ||
4 | use crate::{HirDatabase, Module, Cancelable}; | 3 | use 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)] |
15 | pub struct CrateDependency { | 14 | pub struct CrateDependency { |
16 | pub krate: Crate, | 15 | pub krate: Crate, |
17 | pub name: SmolStr, | 16 | pub name: Name, |
18 | } | 17 | } |
19 | 18 | ||
20 | impl Crate { | 19 | impl 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; | |||
22 | mod arena; | 22 | mod arena; |
23 | pub mod source_binder; | 23 | pub mod source_binder; |
24 | 24 | ||
25 | mod name; | ||
25 | mod krate; | 26 | mod krate; |
26 | mod module; | 27 | mod module; |
27 | mod function; | 28 | mod function; |
@@ -37,10 +38,12 @@ use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable}; | |||
37 | use crate::{ | 38 | use crate::{ |
38 | db::HirDatabase, | 39 | db::HirDatabase, |
39 | arena::{Arena, Id}, | 40 | arena::{Arena, Id}, |
41 | name::{AsName, KnownName}, | ||
40 | }; | 42 | }; |
41 | 43 | ||
42 | pub use self::{ | 44 | pub 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; | |||
7 | use ra_syntax::{ | 7 | use 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 | }; |
12 | use ra_db::{SourceRootId, FileId, Cancelable}; | 12 | use ra_db::{SourceRootId, FileId, Cancelable}; |
13 | use relative_path::RelativePathBuf; | 13 | use relative_path::RelativePathBuf; |
14 | 14 | ||
15 | use crate::{ | 15 | use 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)] |
329 | struct LinkData { | 325 | struct 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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::ast::{self, NameOwner}; |
4 | ast::{self, NameOwner}, | ||
5 | SmolStr, | ||
6 | }; | ||
7 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
8 | use rustc_hash::{FxHashMap, FxHashSet}; | 5 | use rustc_hash::{FxHashMap, FxHashSet}; |
9 | use arrayvec::ArrayVec; | 6 | use arrayvec::ArrayVec; |
10 | use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; | 7 | use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId}; |
11 | 8 | ||
12 | use crate::{ | 9 | use crate::{ |
13 | HirDatabase, | 10 | HirDatabase, Name, AsName, |
14 | }; | 11 | }; |
15 | 12 | ||
16 | use super::{ | 13 | use super::{ |
@@ -20,12 +17,12 @@ use super::{ | |||
20 | 17 | ||
21 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] | 18 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] |
22 | pub enum Submodule { | 19 | pub enum Submodule { |
23 | Declaration(SmolStr), | 20 | Declaration(Name), |
24 | Definition(SmolStr, ModuleSource), | 21 | Definition(Name, ModuleSource), |
25 | } | 22 | } |
26 | 23 | ||
27 | impl Submodule { | 24 | impl 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 | ||
36 | pub(crate) fn modules<'a>( | 33 | pub(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( | |||
155 | fn resolve_submodule( | 152 | fn 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. |
17 | use std::{ | 17 | use std::sync::Arc; |
18 | sync::Arc, | ||
19 | }; | ||
20 | 18 | ||
21 | use rustc_hash::FxHashMap; | 19 | use rustc_hash::FxHashMap; |
22 | use ra_syntax::{ | 20 | use ra_syntax::{ |
23 | TextRange, | 21 | TextRange, |
24 | SmolStr, SyntaxKind::{self, *}, | 22 | SyntaxKind::{self, *}, |
25 | ast::{self, AstNode} | 23 | ast::{self, AstNode} |
26 | }; | 24 | }; |
27 | use ra_db::SourceRootId; | 25 | use 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)] |
47 | pub struct ModuleScope { | 46 | pub struct ModuleScope { |
48 | items: FxHashMap<SmolStr, Resolution>, | 47 | items: FxHashMap<Name, Resolution>, |
49 | } | 48 | } |
50 | 49 | ||
51 | impl ModuleScope { | 50 | impl 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)] |
73 | struct ModuleItem { | 72 | struct 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 | ||
261 | impl ModuleItem { | 260 | impl 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 | ||
3 | use salsa::Database; | 3 | use salsa::Database; |
4 | use ra_db::{FilesDatabase, CrateGraph}; | 4 | use ra_db::{FilesDatabase, CrateGraph}; |
5 | use ra_syntax::SmolStr; | ||
6 | use relative_path::RelativePath; | 5 | use relative_path::RelativePath; |
6 | use test_utils::assert_eq_text; | ||
7 | 7 | ||
8 | use crate::{ | 8 | use 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 | ||
24 | fn 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] |
25 | fn item_map_smoke_test() { | 54 | fn 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] |
47 | fn test_self() { | 81 | fn 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 @@ | |||
1 | use std::fmt; | ||
2 | |||
3 | use 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)] | ||
9 | pub struct Name { | ||
10 | text: SmolStr, | ||
11 | } | ||
12 | |||
13 | impl fmt::Display for Name { | ||
14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
15 | fmt::Display::fmt(&self.text, f) | ||
16 | } | ||
17 | } | ||
18 | |||
19 | impl fmt::Debug for Name { | ||
20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
21 | fmt::Debug::fmt(&self.text, f) | ||
22 | } | ||
23 | } | ||
24 | |||
25 | impl 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 | |||
60 | pub(crate) trait AsName { | ||
61 | fn as_name(&self) -> Name; | ||
62 | } | ||
63 | |||
64 | impl AsName for ast::NameRef<'_> { | ||
65 | fn as_name(&self) -> Name { | ||
66 | Name::new(self.text()) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | impl AsName for ast::Name<'_> { | ||
71 | fn as_name(&self) -> Name { | ||
72 | Name::new(self.text()) | ||
73 | } | ||
74 | } | ||
75 | |||
76 | impl 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)] | ||
88 | pub(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 @@ | |||
1 | use ra_syntax::{SmolStr, ast, AstNode, TextRange}; | 1 | use ra_syntax::{ast, AstNode, TextRange}; |
2 | |||
3 | use crate::{Name, AsName}; | ||
2 | 4 | ||
3 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 5 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
4 | pub struct Path { | 6 | pub 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 | ||
72 | fn expand_use_tree( | 82 | fn 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 | ||
6 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | AstNode, SyntaxNode, SmolStr, | 8 | AstNode, SyntaxNode, |
9 | ast::{self, FnDef, FnDefNode, NameOwner, ModuleItemOwner} | 9 | ast::{self, NameOwner, ModuleItemOwner} |
10 | }; | 10 | }; |
11 | use ra_db::{SourceRootId, FileId, Cancelable,}; | 11 | use ra_db::{SourceRootId, FileId, Cancelable,}; |
12 | 12 | ||
13 | use crate::{ | 13 | use 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` | 25 | pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> { |
27 | pub(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 | |||
34 | pub(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 | ||
40 | pub(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 | |||
45 | pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { | ||
46 | ty::type_for_def(db, def_id) | ||
47 | } | ||
48 | |||
49 | pub(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 | |||
57 | pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> { | 32 | pub(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 | ||
131 | pub(crate) fn modules<'a>( | 106 | pub(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 @@ | |||
8 | use ra_db::{FileId, FilePosition, Cancelable}; | 8 | use ra_db::{FileId, FilePosition, Cancelable}; |
9 | use ra_editor::find_node_at_offset; | 9 | use ra_editor::find_node_at_offset; |
10 | use ra_syntax::{ | 10 | use ra_syntax::{ |
11 | ast::{self, AstNode}, | 11 | ast::{self, AstNode, NameOwner}, |
12 | SyntaxNodeRef, | 12 | SyntaxNodeRef, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use 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. | ||
28 | pub 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. |
28 | pub fn module_from_position( | 47 | pub 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 | |||
1 | mod primitive; | 16 | mod primitive; |
2 | #[cfg(test)] | 17 | #[cfg(test)] |
3 | mod tests; | 18 | mod tests; |
4 | 19 | ||
5 | use std::sync::Arc; | 20 | use std::sync::Arc; |
6 | use std::fmt; | 21 | use std::{fmt, mem}; |
7 | 22 | ||
8 | use log; | 23 | use log; |
9 | use rustc_hash::{FxHashMap}; | 24 | use rustc_hash::FxHashMap; |
25 | use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; | ||
10 | 26 | ||
11 | use ra_db::{LocalSyntaxPtr, Cancelable}; | 27 | use ra_db::{LocalSyntaxPtr, Cancelable}; |
12 | use ra_syntax::{ | 28 | use 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 | ||
18 | use crate::{ | 33 | use 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)] | ||
41 | pub struct TypeVarId(u32); | ||
42 | |||
43 | impl 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)] | ||
62 | pub enum TypeVarValue { | ||
63 | Known(Ty), | ||
64 | Unknown, | ||
65 | } | ||
66 | |||
67 | impl TypeVarValue { | ||
68 | fn known(&self) -> Option<&Ty> { | ||
69 | match self { | ||
70 | TypeVarValue::Known(ty) => Some(ty), | ||
71 | TypeVarValue::Unknown => None, | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | impl 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)] | ||
101 | pub 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)] | ||
108 | struct 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 | |||
115 | impl 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)] |
26 | pub enum Ty { | 132 | pub 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 | ||
121 | type TyRef = Arc<Ty>; | 227 | /// A function signature. |
122 | |||
123 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 228 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
124 | pub struct FnSig { | 229 | pub 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 | ||
259 | pub 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). | ||
402 | fn 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 | ||
277 | pub fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Cancelable<Ty> { | 424 | fn 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 | ||
286 | pub fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Cancelable<Ty> { | 431 | pub 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 | ||
295 | pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { | 438 | pub(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 | ||
312 | pub(super) fn type_for_field( | 455 | pub(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)] |
340 | pub struct InferenceResult { | 480 | pub struct InferenceResult { |
341 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | 481 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, |
342 | } | 482 | } |
343 | 483 | ||
344 | impl InferenceResult { | 484 | impl 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)] |
351 | pub struct InferenceContext<'a, D: HirDatabase> { | 496 | struct 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 | ||
657 | pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceResult> { | 911 | pub 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 @@ | |||
1 | use std::fmt; | 1 | use std::fmt; |
2 | 2 | ||
3 | use crate::{Name, KnownName}; | ||
4 | |||
3 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] | 5 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] |
4 | pub enum IntTy { | 6 | pub 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] | ||
117 | fn infer_backwards() { | ||
118 | check_inference( | ||
119 | r#" | ||
120 | fn takes_u32(x: u32) {} | ||
121 | |||
122 | struct S { i32_field: i32 } | ||
123 | |||
124 | fn 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 | |||
116 | fn infer(content: &str) -> String { | 137 | fn 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 | ||