aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-02-21 14:34:06 +0000
committerFlorian Diebold <[email protected]>2020-02-21 14:39:51 +0000
commit31af774254d1fb4e9105ba050546db16b9b54fb6 (patch)
tree587c84243cf6f4db8fa9d403f50178afab7ffe4f /crates/ra_hir_def/src/nameres
parente3037c2631ecb55996b676ce2c18b9df1858abaa (diff)
Refactor how builtins are resolved
This fixes autocompletion suggesting e.g. self::usize.
Diffstat (limited to 'crates/ra_hir_def/src/nameres')
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs63
1 files changed, 33 insertions, 30 deletions
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index fd6422d60..c058e70aa 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -18,6 +18,7 @@ use test_utils::tested_by;
18 18
19use crate::{ 19use crate::{
20 db::DefDatabase, 20 db::DefDatabase,
21 item_scope::BUILTIN_SCOPE,
21 nameres::{BuiltinShadowMode, CrateDefMap}, 22 nameres::{BuiltinShadowMode, CrateDefMap},
22 path::{ModPath, PathKind}, 23 path::{ModPath, PathKind},
23 per_ns::PerNs, 24 per_ns::PerNs,
@@ -103,15 +104,6 @@ impl CrateDefMap {
103 path: &ModPath, 104 path: &ModPath,
104 shadow: BuiltinShadowMode, 105 shadow: BuiltinShadowMode,
105 ) -> ResolvePathResult { 106 ) -> ResolvePathResult {
106 // if it is not the last segment, we prefer the module to the builtin
107 let prefer_module = |index| {
108 if index == path.segments.len() - 1 {
109 shadow
110 } else {
111 BuiltinShadowMode::Module
112 }
113 };
114
115 let mut segments = path.segments.iter().enumerate(); 107 let mut segments = path.segments.iter().enumerate();
116 let mut curr_per_ns: PerNs = match path.kind { 108 let mut curr_per_ns: PerNs = match path.kind {
117 PathKind::DollarCrate(krate) => { 109 PathKind::DollarCrate(krate) => {
@@ -140,20 +132,29 @@ impl CrateDefMap {
140 if self.edition == Edition::Edition2015 132 if self.edition == Edition::Edition2015
141 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => 133 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
142 { 134 {
143 let (idx, segment) = match segments.next() { 135 let (_, segment) = match segments.next() {
144 Some((idx, segment)) => (idx, segment), 136 Some((idx, segment)) => (idx, segment),
145 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 137 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
146 }; 138 };
147 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 139 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
148 self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx)) 140 self.resolve_name_in_crate_root_or_extern_prelude(&segment)
149 } 141 }
150 PathKind::Plain => { 142 PathKind::Plain => {
151 let (idx, segment) = match segments.next() { 143 let (_, segment) = match segments.next() {
152 Some((idx, segment)) => (idx, segment), 144 Some((idx, segment)) => (idx, segment),
153 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 145 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
154 }; 146 };
147 // The first segment may be a builtin type. If the path has more
148 // than one segment, we first try resolving it as a module
149 // anyway.
150 // FIXME: If the next segment doesn't resolve in the module and
151 // BuiltinShadowMode wasn't Module, then we need to try
152 // resolving it as a builtin.
153 let prefer_module =
154 if path.segments.len() == 1 { shadow } else { BuiltinShadowMode::Module };
155
155 log::debug!("resolving {:?} in module", segment); 156 log::debug!("resolving {:?} in module", segment);
156 self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx)) 157 self.resolve_name_in_module(db, original_module, &segment, prefer_module)
157 } 158 }
158 PathKind::Super(lvl) => { 159 PathKind::Super(lvl) => {
159 let m = successors(Some(original_module), |m| self.modules[*m].parent) 160 let m = successors(Some(original_module), |m| self.modules[*m].parent)
@@ -216,7 +217,7 @@ impl CrateDefMap {
216 } 217 }
217 218
218 // Since it is a qualified path here, it should not contains legacy macros 219 // Since it is a qualified path here, it should not contains legacy macros
219 self[module.local_id].scope.get(&segment, prefer_module(i)) 220 self[module.local_id].scope.get(&segment)
220 } 221 }
221 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 222 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
222 // enum variant 223 // enum variant
@@ -275,33 +276,35 @@ impl CrateDefMap {
275 .scope 276 .scope
276 .get_legacy_macro(name) 277 .get_legacy_macro(name)
277 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); 278 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
278 let from_scope = self[module].scope.get(name, shadow); 279 let from_scope = self[module].scope.get(name);
280 let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none);
281 let from_scope_or_builtin = match shadow {
282 BuiltinShadowMode::Module => from_scope.or(from_builtin),
283 BuiltinShadowMode::Other => {
284 if let Some(ModuleDefId::ModuleId(_)) = from_scope.take_types() {
285 from_builtin.or(from_scope)
286 } else {
287 from_scope.or(from_builtin)
288 }
289 }
290 };
279 let from_extern_prelude = self 291 let from_extern_prelude = self
280 .extern_prelude 292 .extern_prelude
281 .get(name) 293 .get(name)
282 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)); 294 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
283 let from_prelude = self.resolve_in_prelude(db, name, shadow); 295 let from_prelude = self.resolve_in_prelude(db, name);
284 296
285 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) 297 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
286 } 298 }
287 299
288 fn resolve_name_in_crate_root_or_extern_prelude( 300 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
289 &self, 301 let from_crate_root = self[self.root].scope.get(name);
290 name: &Name,
291 shadow: BuiltinShadowMode,
292 ) -> PerNs {
293 let from_crate_root = self[self.root].scope.get(name, shadow);
294 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 302 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
295 303
296 from_crate_root.or(from_extern_prelude) 304 from_crate_root.or(from_extern_prelude)
297 } 305 }
298 306
299 fn resolve_in_prelude( 307 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
300 &self,
301 db: &impl DefDatabase,
302 name: &Name,
303 shadow: BuiltinShadowMode,
304 ) -> PerNs {
305 if let Some(prelude) = self.prelude { 308 if let Some(prelude) = self.prelude {
306 let keep; 309 let keep;
307 let def_map = if prelude.krate == self.krate { 310 let def_map = if prelude.krate == self.krate {
@@ -311,7 +314,7 @@ impl CrateDefMap {
311 keep = db.crate_def_map(prelude.krate); 314 keep = db.crate_def_map(prelude.krate);
312 &keep 315 &keep
313 }; 316 };
314 def_map[prelude.local_id].scope.get(name, shadow) 317 def_map[prelude.local_id].scope.get(name)
315 } else { 318 } else {
316 PerNs::none() 319 PerNs::none()
317 } 320 }