aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-22 11:25:09 +0000
committerGitHub <[email protected]>2020-02-22 11:25:09 +0000
commitf9acb4333f7c07969184d64793a84f8ad8efb309 (patch)
treeda6209649e2b775c5e0fcf569f5438e68f678cc3
parent62ddf617e2d2774744bd376dfb5a17ad4dc9cf19 (diff)
parent31af774254d1fb4e9105ba050546db16b9b54fb6 (diff)
Merge #3260
3260: Refactor how builtins are resolved r=matklad a=flodiebold This fixes autocompletion suggesting e.g. `self::usize`. (I thought we had a bug for that, but I didn't find it.) Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/ra_hir_def/src/item_scope.rs33
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs63
-rw-r--r--crates/ra_hir_def/src/resolver.rs13
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs13
-rw-r--r--crates/ra_ide/src/marks.rs1
5 files changed, 55 insertions, 68 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 6e958ca75..5e943b780 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -30,7 +30,7 @@ pub struct ItemScope {
30 legacy_macros: FxHashMap<Name, MacroDefId>, 30 legacy_macros: FxHashMap<Name, MacroDefId>,
31} 31}
32 32
33static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { 33pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
34 BuiltinType::ALL 34 BuiltinType::ALL
35 .iter() 35 .iter()
36 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) 36 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
@@ -40,9 +40,9 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
40/// Shadow mode for builtin type which can be shadowed by module. 40/// Shadow mode for builtin type which can be shadowed by module.
41#[derive(Debug, Copy, Clone, PartialEq, Eq)] 41#[derive(Debug, Copy, Clone, PartialEq, Eq)]
42pub(crate) enum BuiltinShadowMode { 42pub(crate) enum BuiltinShadowMode {
43 // Prefer Module 43 /// Prefer user-defined modules (or other types) over builtins.
44 Module, 44 Module,
45 // Prefer Other Types 45 /// Prefer builtins over user-defined modules (but not other types).
46 Other, 46 Other,
47} 47}
48 48
@@ -51,7 +51,7 @@ pub(crate) enum BuiltinShadowMode {
51impl ItemScope { 51impl ItemScope {
52 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 52 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
53 //FIXME: shadowing 53 //FIXME: shadowing
54 self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def)) 54 self.visible.iter().map(|(n, def)| (n, *def))
55 } 55 }
56 56
57 pub fn entries_without_primitives<'a>( 57 pub fn entries_without_primitives<'a>(
@@ -79,29 +79,8 @@ impl ItemScope {
79 } 79 }
80 80
81 /// Get a name from current module scope, legacy macros are not included 81 /// Get a name from current module scope, legacy macros are not included
82 pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs { 82 pub(crate) fn get(&self, name: &Name) -> PerNs {
83 match shadow { 83 self.visible.get(name).copied().unwrap_or_else(PerNs::none)
84 BuiltinShadowMode::Module => self
85 .visible
86 .get(name)
87 .or_else(|| BUILTIN_SCOPE.get(name))
88 .copied()
89 .unwrap_or_else(PerNs::none),
90 BuiltinShadowMode::Other => {
91 let item = self.visible.get(name).copied();
92 if let Some(def) = item {
93 if let Some(ModuleDefId::ModuleId(_)) = def.take_types() {
94 return BUILTIN_SCOPE
95 .get(name)
96 .copied()
97 .or(item)
98 .unwrap_or_else(PerNs::none);
99 }
100 }
101
102 item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none)
103 }
104 }
105 } 84 }
106 85
107 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { 86 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
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 }
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 5365b80e2..9dd4fa555 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -15,7 +15,7 @@ use crate::{
15 db::DefDatabase, 15 db::DefDatabase,
16 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
17 generics::GenericParams, 17 generics::GenericParams,
18 item_scope::BuiltinShadowMode, 18 item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
19 nameres::CrateDefMap, 19 nameres::CrateDefMap,
20 path::{ModPath, PathKind}, 20 path::{ModPath, PathKind},
21 per_ns::PerNs, 21 per_ns::PerNs,
@@ -193,7 +193,7 @@ impl Resolver {
193 return Some((res, idx)); 193 return Some((res, idx));
194 } 194 }
195 Scope::LocalItemsScope(body) => { 195 Scope::LocalItemsScope(body) => {
196 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); 196 let def = body.item_scope.get(first_name);
197 if let Some(res) = to_type_ns(def) { 197 if let Some(res) = to_type_ns(def) {
198 return Some((res, None)); 198 return Some((res, None));
199 } 199 }
@@ -335,8 +335,10 @@ impl Resolver {
335 }; 335 };
336 } 336 }
337 Scope::LocalItemsScope(body) => { 337 Scope::LocalItemsScope(body) => {
338 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other); 338 // we don't bother looking in the builtin scope here because there are no builtin values
339 if let Some(res) = to_value_ns(def) { 339 let def = to_value_ns(body.item_scope.get(first_name));
340
341 if let Some(res) = def {
340 return Some(ResolveValueResult::ValueNs(res)); 342 return Some(ResolveValueResult::ValueNs(res));
341 } 343 }
342 } 344 }
@@ -476,6 +478,9 @@ impl Scope {
476 m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| { 478 m.crate_def_map.extern_prelude.iter().for_each(|(name, &def)| {
477 f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public))); 479 f(name.clone(), ScopeDef::PerNs(PerNs::types(def, Visibility::Public)));
478 }); 480 });
481 BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
482 f(name.clone(), ScopeDef::PerNs(def));
483 });
479 if let Some(prelude) = m.crate_def_map.prelude { 484 if let Some(prelude) = m.crate_def_map.prelude {
480 let prelude_def_map = db.crate_def_map(prelude.krate); 485 let prelude_def_map = db.crate_def_map(prelude.krate);
481 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { 486 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index af24e9f48..2d7f09a6c 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Completion of paths, including when writing a single name.
2 2
3use hir::{Adt, PathResolution, ScopeDef}; 3use hir::{Adt, PathResolution, ScopeDef};
4use ra_syntax::AstNode; 4use ra_syntax::AstNode;
@@ -20,10 +20,6 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
20 let module_scope = module.scope(ctx.db); 20 let module_scope = module.scope(ctx.db);
21 for (name, def) in module_scope { 21 for (name, def) in module_scope {
22 if ctx.use_item_syntax.is_some() { 22 if ctx.use_item_syntax.is_some() {
23 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
24 tested_by!(dont_complete_primitive_in_use);
25 continue;
26 }
27 if let ScopeDef::Unknown = def { 23 if let ScopeDef::Unknown = def {
28 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { 24 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
29 if name_ref.syntax().text() == name.to_string().as_str() { 25 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -125,12 +121,17 @@ mod tests {
125 121
126 #[test] 122 #[test]
127 fn dont_complete_primitive_in_use() { 123 fn dont_complete_primitive_in_use() {
128 covers!(dont_complete_primitive_in_use);
129 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); 124 let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType);
130 assert!(completions.is_empty()); 125 assert!(completions.is_empty());
131 } 126 }
132 127
133 #[test] 128 #[test]
129 fn dont_complete_primitive_in_module_scope() {
130 let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType);
131 assert!(completions.is_empty());
132 }
133
134 #[test]
134 fn completes_primitives() { 135 fn completes_primitives() {
135 let completions = 136 let completions =
136 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); 137 do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType);
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs
index 5bf4d2062..bcb67e373 100644
--- a/crates/ra_ide/src/marks.rs
+++ b/crates/ra_ide/src/marks.rs
@@ -10,6 +10,5 @@ test_utils::marks!(
10 goto_def_for_field_init_shorthand 10 goto_def_for_field_init_shorthand
11 call_info_bad_offset 11 call_info_bad_offset
12 dont_complete_current_use 12 dont_complete_current_use
13 dont_complete_primitive_in_use
14 test_resolve_parent_module_on_module_decl 13 test_resolve_parent_module_on_module_decl
15); 14);