aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2018-12-24 19:32:39 +0000
committerFlorian Diebold <[email protected]>2018-12-25 14:16:42 +0000
commit4ff161852016c6c15954d6f30bd637834a2b2b68 (patch)
tree7ea2d34a8f58f5a242481e6d6294bef22546fcaf /crates/ra_hir/src
parentb5b68f2094d49cacde6d7f0c49f521a0b25f34bd (diff)
Do name resolution by namespace (types/values)
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/lib.rs25
-rw-r--r--crates/ra_hir/src/module.rs42
-rw-r--r--crates/ra_hir/src/module/nameres.rs154
-rw-r--r--crates/ra_hir/src/module/nameres/tests.rs6
-rw-r--r--crates/ra_hir/src/ty.rs22
-rw-r--r--crates/ra_hir/src/ty/tests/data/0004_struct.txt4
6 files changed, 182 insertions, 71 deletions
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 7e9824de9..81526fe9c 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -41,7 +41,7 @@ use crate::{
41pub use self::{ 41pub use self::{
42 path::{Path, PathKind}, 42 path::{Path, PathKind},
43 krate::Crate, 43 krate::Crate,
44 module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution}, 44 module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
45 function::{Function, FnScopes}, 45 function::{Function, FnScopes},
46 adt::{Struct, Enum}, 46 adt::{Struct, Enum},
47}; 47};
@@ -61,6 +61,8 @@ pub(crate) enum DefKind {
61 Struct, 61 Struct,
62 Enum, 62 Enum,
63 Item, 63 Item,
64
65 StructCtor,
64} 66}
65 67
66#[derive(Clone, Debug, PartialEq, Eq, Hash)] 68#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -72,18 +74,18 @@ pub struct DefLoc {
72} 74}
73 75
74impl DefKind { 76impl DefKind {
75 pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> { 77 pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
76 match kind { 78 match kind {
77 SyntaxKind::FN_DEF => Some(DefKind::Function), 79 SyntaxKind::FN_DEF => PerNs::values(DefKind::Function),
78 SyntaxKind::MODULE => Some(DefKind::Module), 80 SyntaxKind::MODULE => PerNs::types(DefKind::Module),
81 SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor),
82 SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum),
79 // These define items, but don't have their own DefKinds yet: 83 // These define items, but don't have their own DefKinds yet:
80 SyntaxKind::STRUCT_DEF => Some(DefKind::Struct), 84 SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Item),
81 SyntaxKind::ENUM_DEF => Some(DefKind::Enum), 85 SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Item),
82 SyntaxKind::TRAIT_DEF => Some(DefKind::Item), 86 SyntaxKind::CONST_DEF => PerNs::values(DefKind::Item),
83 SyntaxKind::TYPE_DEF => Some(DefKind::Item), 87 SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Item),
84 SyntaxKind::CONST_DEF => Some(DefKind::Item), 88 _ => PerNs::none(),
85 SyntaxKind::STATIC_DEF => Some(DefKind::Item),
86 _ => None,
87 } 89 }
88 } 90 }
89} 91}
@@ -128,6 +130,7 @@ impl DefId {
128 let enum_def = Enum::new(self); 130 let enum_def = Enum::new(self);
129 Def::Enum(enum_def) 131 Def::Enum(enum_def)
130 } 132 }
133 DefKind::StructCtor => Def::Item,
131 DefKind::Item => Def::Item, 134 DefKind::Item => Def::Item,
132 }; 135 };
133 Ok(res) 136 Ok(res)
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index 891119953..e1a0e4b59 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -17,7 +17,7 @@ use crate::{
17 arena::{Arena, Id}, 17 arena::{Arena, Id},
18}; 18};
19 19
20pub use self::nameres::{ModuleScope, Resolution}; 20pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs};
21 21
22/// `Module` is API entry point to get all the information 22/// `Module` is API entry point to get all the information
23/// about a particular module. 23/// about a particular module.
@@ -115,16 +115,29 @@ impl Module {
115 Ok(res) 115 Ok(res)
116 } 116 }
117 117
118 pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<Option<DefId>> { 118 pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<PerNs<DefId>> {
119 let mut curr = match path.kind { 119 let mut curr_per_ns = PerNs::types(
120 PathKind::Crate => self.crate_root(), 120 match path.kind {
121 PathKind::Self_ | PathKind::Plain => self.clone(), 121 PathKind::Crate => self.crate_root(),
122 PathKind::Super => ctry!(self.parent()), 122 PathKind::Self_ | PathKind::Plain => self.clone(),
123 } 123 PathKind::Super => {
124 .def_id(db); 124 if let Some(p) = self.parent() {
125 p
126 } else {
127 return Ok(PerNs::none());
128 }
129 }
130 }
131 .def_id(db),
132 );
125 133
126 let segments = path.segments; 134 let segments = path.segments;
127 for name in segments.iter() { 135 for name in segments.iter() {
136 let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) {
137 r
138 } else {
139 return Ok(PerNs::none());
140 };
128 let module = match curr.loc(db) { 141 let module = match curr.loc(db) {
129 DefLoc { 142 DefLoc {
130 kind: DefKind::Module, 143 kind: DefKind::Module,
@@ -132,12 +145,17 @@ impl Module {
132 module_id, 145 module_id,
133 .. 146 ..
134 } => Module::new(db, source_root_id, module_id)?, 147 } => Module::new(db, source_root_id, module_id)?,
135 _ => return Ok(None), 148 // TODO here would be the place to handle enum variants...
149 _ => return Ok(PerNs::none()),
136 }; 150 };
137 let scope = module.scope(db)?; 151 let scope = module.scope(db)?;
138 curr = ctry!(ctry!(scope.get(&name)).def_id); 152 curr_per_ns = if let Some(r) = scope.get(&name) {
153 r.def_id
154 } else {
155 return Ok(PerNs::none());
156 };
139 } 157 }
140 Ok(Some(curr)) 158 Ok(curr_per_ns)
141 } 159 }
142 160
143 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> { 161 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
@@ -145,7 +163,7 @@ impl Module {
145 } 163 }
146} 164}
147 165
148/// Phisically, rust source is organized as a set of files, but logically it is 166/// Physically, rust source is organized as a set of files, but logically it is
149/// organized as a tree of modules. Usually, a single file corresponds to a 167/// organized as a tree of modules. Usually, a single file corresponds to a
150/// single module, but it is not nessary the case. 168/// single module, but it is not nessary the case.
151/// 169///
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 0b152a406..33c9d93c2 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -118,22 +118,96 @@ enum ImportKind {
118#[derive(Debug, Clone, PartialEq, Eq)] 118#[derive(Debug, Clone, PartialEq, Eq)]
119pub struct Resolution { 119pub struct Resolution {
120 /// None for unresolved 120 /// None for unresolved
121 pub def_id: Option<DefId>, 121 pub def_id: PerNs<DefId>,
122 /// ident by whitch this is imported into local scope. 122 /// ident by whitch this is imported into local scope.
123 pub import: Option<NamedImport>, 123 pub import: Option<NamedImport>,
124} 124}
125 125
126// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 126#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
127// enum Namespace { 127pub enum Namespace {
128// Types, 128 Types,
129// Values, 129 Values,
130// } 130}
131
132#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
133pub struct PerNs<T> {
134 pub types: Option<T>,
135 pub values: Option<T>,
136}
137
138impl<T> PerNs<T> {
139 pub fn none() -> PerNs<T> {
140 PerNs {
141 types: None,
142 values: None,
143 }
144 }
145
146 pub fn values(t: T) -> PerNs<T> {
147 PerNs {
148 types: None,
149 values: Some(t),
150 }
151 }
152
153 pub fn types(t: T) -> PerNs<T> {
154 PerNs {
155 types: Some(t),
156 values: None,
157 }
158 }
159
160 pub fn both(types: T, values: T) -> PerNs<T> {
161 PerNs {
162 types: Some(types),
163 values: Some(values),
164 }
165 }
166
167 pub fn is_none(&self) -> bool {
168 self.types.is_none() && self.values.is_none()
169 }
170
171 pub fn take(self, namespace: Namespace) -> Option<T> {
172 match namespace {
173 Namespace::Types => self.types,
174 Namespace::Values => self.values,
175 }
176 }
177
178 pub fn take_types(self) -> Option<T> {
179 self.types
180 }
181
182 pub fn take_values(self) -> Option<T> {
183 self.values
184 }
131 185
132// #[derive(Debug)] 186 pub fn get(&self, namespace: Namespace) -> Option<&T> {
133// struct PerNs<T> { 187 self.as_ref().take(namespace)
134// types: Option<T>, 188 }
135// values: Option<T>, 189
136// } 190 pub fn as_ref(&self) -> PerNs<&T> {
191 PerNs {
192 types: self.types.as_ref(),
193 values: self.values.as_ref(),
194 }
195 }
196
197 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
198 PerNs {
199 types: self.types.and_then(&f),
200 values: self.values.and_then(&f),
201 }
202 }
203
204 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
205 PerNs {
206 types: self.types.map(&f),
207 values: self.values.map(&f),
208 }
209 }
210}
137 211
138impl InputModuleItems { 212impl InputModuleItems {
139 pub(crate) fn new<'a>( 213 pub(crate) fn new<'a>(
@@ -254,7 +328,7 @@ where
254 for dep in krate.dependencies(self.db) { 328 for dep in krate.dependencies(self.db) {
255 if let Some(module) = dep.krate.root_module(self.db)? { 329 if let Some(module) = dep.krate.root_module(self.db)? {
256 let def_id = module.def_id(self.db); 330 let def_id = module.def_id(self.db);
257 self.add_module_item(&mut module_items, dep.name, def_id); 331 self.add_module_item(&mut module_items, dep.name, PerNs::types(def_id));
258 } 332 }
259 } 333 }
260 }; 334 };
@@ -265,7 +339,7 @@ where
265 module_items.items.insert( 339 module_items.items.insert(
266 name.clone(), 340 name.clone(),
267 Resolution { 341 Resolution {
268 def_id: None, 342 def_id: PerNs::none(),
269 import: Some(import), 343 import: Some(import),
270 }, 344 },
271 ); 345 );
@@ -277,18 +351,23 @@ where
277 if item.kind == MODULE { 351 if item.kind == MODULE {
278 continue; 352 continue;
279 } 353 }
280 let def_loc = DefLoc { 354 // depending on the item kind, the location can define something in
281 kind: DefKind::for_syntax_kind(item.kind).unwrap_or(DefKind::Item), 355 // the values namespace, the types namespace, or both
282 source_root_id: self.source_root, 356 let kind = DefKind::for_syntax_kind(item.kind);
283 module_id, 357 let def_id = kind.map(|k| {
284 source_item_id: SourceItemId { 358 let def_loc = DefLoc {
285 file_id, 359 kind: k,
286 item_id: Some(item.id), 360 source_root_id: self.source_root,
287 }, 361 module_id,
288 }; 362 source_item_id: SourceItemId {
289 let def_id = def_loc.id(self.db); 363 file_id,
364 item_id: Some(item.id),
365 },
366 };
367 def_loc.id(self.db)
368 });
290 let resolution = Resolution { 369 let resolution = Resolution {
291 def_id: Some(def_id), 370 def_id,
292 import: None, 371 import: None,
293 }; 372 };
294 module_items.items.insert(item.name.clone(), resolution); 373 module_items.items.insert(item.name.clone(), resolution);
@@ -303,16 +382,16 @@ where
303 source_item_id: module_id.source(&self.module_tree).0, 382 source_item_id: module_id.source(&self.module_tree).0,
304 }; 383 };
305 let def_id = def_loc.id(self.db); 384 let def_id = def_loc.id(self.db);
306 self.add_module_item(&mut module_items, name, def_id); 385 self.add_module_item(&mut module_items, name, PerNs::types(def_id));
307 } 386 }
308 387
309 self.result.per_module.insert(module_id, module_items); 388 self.result.per_module.insert(module_id, module_items);
310 Ok(()) 389 Ok(())
311 } 390 }
312 391
313 fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: DefId) { 392 fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: PerNs<DefId>) {
314 let resolution = Resolution { 393 let resolution = Resolution {
315 def_id: Some(def_id), 394 def_id,
316 import: None, 395 import: None,
317 }; 396 };
318 module_items.items.insert(name, resolution); 397 module_items.items.insert(name, resolution);
@@ -347,15 +426,17 @@ where
347 let is_last = i == import.path.segments.len() - 1; 426 let is_last = i == import.path.segments.len() - 1;
348 427
349 let def_id = match self.result.per_module[&curr].items.get(name) { 428 let def_id = match self.result.per_module[&curr].items.get(name) {
350 None => return Ok(()), 429 Some(res) if !res.def_id.is_none() => res.def_id,
351 Some(res) => match res.def_id { 430 _ => return Ok(()),
352 Some(it) => it,
353 None => return Ok(()),
354 },
355 }; 431 };
356 432
357 if !is_last { 433 if !is_last {
358 curr = match def_id.loc(self.db) { 434 let type_def_id = if let Some(d) = def_id.take(Namespace::Types) {
435 d
436 } else {
437 return Ok(());
438 };
439 curr = match type_def_id.loc(self.db) {
359 DefLoc { 440 DefLoc {
360 kind: DefKind::Module, 441 kind: DefKind::Module,
361 module_id: target_module_id, 442 module_id: target_module_id,
@@ -370,10 +451,11 @@ where
370 segments: import.path.segments[i + 1..].iter().cloned().collect(), 451 segments: import.path.segments[i + 1..].iter().cloned().collect(),
371 kind: PathKind::Crate, 452 kind: PathKind::Crate,
372 }; 453 };
373 if let Some(def_id) = module.resolve_path(self.db, path)? { 454 let def_id = module.resolve_path(self.db, path)?;
455 if !def_id.is_none() {
374 self.update(module_id, |items| { 456 self.update(module_id, |items| {
375 let res = Resolution { 457 let res = Resolution {
376 def_id: Some(def_id), 458 def_id: def_id,
377 import: Some(ptr), 459 import: Some(ptr),
378 }; 460 };
379 items.items.insert(name.clone(), res); 461 items.items.insert(name.clone(), res);
@@ -387,7 +469,7 @@ where
387 } else { 469 } else {
388 self.update(module_id, |items| { 470 self.update(module_id, |items| {
389 let res = Resolution { 471 let res = Resolution {
390 def_id: Some(def_id), 472 def_id: def_id,
391 import: Some(ptr), 473 import: Some(ptr),
392 }; 474 };
393 items.items.insert(name.clone(), res); 475 items.items.insert(name.clone(), res);
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs
index 3e29c3954..03ea5c1d6 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/module/nameres/tests.rs
@@ -40,7 +40,7 @@ fn item_map_smoke_test() {
40 ); 40 );
41 let name = SmolStr::from("Baz"); 41 let name = SmolStr::from("Baz");
42 let resolution = &item_map.per_module[&module_id].items[&name]; 42 let resolution = &item_map.per_module[&module_id].items[&name];
43 assert!(resolution.def_id.is_some()); 43 assert!(resolution.def_id.take_types().is_some());
44} 44}
45 45
46#[test] 46#[test]
@@ -59,7 +59,7 @@ fn test_self() {
59 ); 59 );
60 let name = SmolStr::from("Baz"); 60 let name = SmolStr::from("Baz");
61 let resolution = &item_map.per_module[&module_id].items[&name]; 61 let resolution = &item_map.per_module[&module_id].items[&name];
62 assert!(resolution.def_id.is_some()); 62 assert!(resolution.def_id.take_types().is_some());
63} 63}
64 64
65#[test] 65#[test]
@@ -92,7 +92,7 @@ fn item_map_across_crates() {
92 92
93 let name = SmolStr::from("Baz"); 93 let name = SmolStr::from("Baz");
94 let resolution = &item_map.per_module[&module_id].items[&name]; 94 let resolution = &item_map.per_module[&module_id].items[&name];
95 assert!(resolution.def_id.is_some()); 95 assert!(resolution.def_id.take_types().is_some());
96} 96}
97 97
98#[test] 98#[test]
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index f86b749ec..429292cfc 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -15,7 +15,11 @@ use ra_syntax::{
15 SyntaxNodeRef 15 SyntaxNodeRef
16}; 16};
17 17
18use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase}; 18use crate::{
19 Def, DefId, FnScopes, Module, Function,
20 Path, db::HirDatabase,
21 module::nameres::Namespace
22};
19 23
20#[derive(Clone, PartialEq, Eq, Hash, Debug)] 24#[derive(Clone, PartialEq, Eq, Hash, Debug)]
21pub enum Ty { 25pub enum Ty {
@@ -149,11 +153,12 @@ impl Ty {
149 } 153 }
150 154
151 // Resolve in module (in type namespace) 155 // Resolve in module (in type namespace)
152 let resolved = if let Some(r) = module.resolve_path(db, path)? { 156 let resolved =
153 r 157 if let Some(r) = module.resolve_path(db, path)?.take(Namespace::Types) {
154 } else { 158 r
155 return Ok(Ty::Unknown); 159 } else {
156 }; 160 return Ok(Ty::Unknown);
161 };
157 let ty = db.type_for_def(resolved)?; 162 let ty = db.type_for_def(resolved)?;
158 ty 163 ty
159 } 164 }
@@ -325,7 +330,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
325 }; 330 };
326 331
327 // resolve in module 332 // resolve in module
328 let resolved = ctry!(self.module.resolve_path(self.db, path)?); 333 let resolved = ctry!(self
334 .module
335 .resolve_path(self.db, path)?
336 .take(Namespace::Values));
329 let ty = self.db.type_for_def(resolved)?; 337 let ty = self.db.type_for_def(resolved)?;
330 // TODO we will need to add type variables for type parameters etc. here 338 // TODO we will need to add type variables for type parameters etc. here
331 Ok(Some(ty)) 339 Ok(Some(ty))
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 70ad055ff..a4371c5a5 100644
--- a/crates/ra_hir/src/ty/tests/data/0004_struct.txt
+++ b/crates/ra_hir/src/ty/tests/data/0004_struct.txt
@@ -1,10 +1,10 @@
1[86; 90) 'C(1)': [unknown] 1[86; 90) 'C(1)': [unknown]
2[72; 153) '{ ...a.c; }': () 2[72; 153) '{ ...a.c; }': ()
3[86; 87) 'C': C 3[86; 87) 'C': [unknown]
4[107; 108) 'a': A 4[107; 108) 'a': A
5[114; 132) 'A { b:... C() }': [unknown] 5[114; 132) 'A { b:... C() }': [unknown]
6[138; 141) 'a.b': [unknown] 6[138; 141) 'a.b': [unknown]
7[147; 150) 'a.c': [unknown] 7[147; 150) 'a.c': [unknown]
8[96; 97) 'B': B 8[96; 97) 'B': [unknown]
9[88; 89) '1': [unknown] 9[88; 89) '1': [unknown]
10[82; 83) 'c': [unknown] 10[82; 83) 'c': [unknown]