aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres/crate_def_map/collector.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-03-13 13:04:28 +0000
committerAleksey Kladov <[email protected]>2019-03-17 09:46:13 +0000
commit182c05a96c25321ac3ff262cea098e0c4d7ed6f8 (patch)
tree151c81b7b5f55dda12a555c69993a86a61b84243 /crates/ra_hir/src/nameres/crate_def_map/collector.rs
parent0d8d9186563637f493ac7691268319373251b18a (diff)
add name resolution from the old impl
unlike the old impl, this also handles macro imports across crates
Diffstat (limited to 'crates/ra_hir/src/nameres/crate_def_map/collector.rs')
-rw-r--r--crates/ra_hir/src/nameres/crate_def_map/collector.rs283
1 files changed, 260 insertions, 23 deletions
diff --git a/crates/ra_hir/src/nameres/crate_def_map/collector.rs b/crates/ra_hir/src/nameres/crate_def_map/collector.rs
index 46bef3dbe..cd328b755 100644
--- a/crates/ra_hir/src/nameres/crate_def_map/collector.rs
+++ b/crates/ra_hir/src/nameres/crate_def_map/collector.rs
@@ -2,12 +2,13 @@ use std::sync::Arc;
2 2
3use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
4use ra_arena::Arena; 4use ra_arena::Arena;
5use test_utils::tested_by;
5 6
6use crate::{ 7use crate::{
7 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
8 Crate, PersistentHirDatabase, HirFileId, Name, Path, 9 Crate, PersistentHirDatabase, HirFileId, Name, Path,
9 KnownName, 10 KnownName,
10 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint}, 11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode},
11 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
12 module_tree::resolve_module_declaration, 13 module_tree::resolve_module_declaration,
13}; 14};
@@ -19,12 +20,41 @@ pub(crate) fn crate_def_map_query(
19 db: &impl PersistentHirDatabase, 20 db: &impl PersistentHirDatabase,
20 krate: Crate, 21 krate: Crate,
21) -> Arc<CrateDefMap> { 22) -> Arc<CrateDefMap> {
22 let mut modules: Arena<ModuleId, ModuleData> = Arena::default(); 23 let mut def_map = {
23 let root = modules.alloc(ModuleData::default()); 24 let edition = krate.edition(db);
25 let mut modules: Arena<ModuleId, ModuleData> = Arena::default();
26 let root = modules.alloc(ModuleData::default());
27 CrateDefMap {
28 krate,
29 edition,
30 extern_prelude: FxHashMap::default(),
31 prelude: None,
32 root,
33 modules,
34 public_macros: FxHashMap::default(),
35 }
36 };
37
38 // populate external prelude
39 for dep in krate.dependencies(db) {
40 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
41 if let Some(module) = dep.krate.root_module(db) {
42 def_map.extern_prelude.insert(dep.name.clone(), module.into());
43 }
44 // look for the prelude
45 if def_map.prelude.is_none() {
46 let item_map = db.item_map(dep.krate);
47 if item_map.prelude.is_some() {
48 def_map.prelude = item_map.prelude;
49 }
50 }
51 }
52
24 let mut collector = DefCollector { 53 let mut collector = DefCollector {
25 db, 54 db,
26 krate, 55 krate,
27 def_map: CrateDefMap { modules, root }, 56 def_map,
57 glob_imports: FxHashMap::default(),
28 unresolved_imports: Vec::new(), 58 unresolved_imports: Vec::new(),
29 unexpanded_macros: Vec::new(), 59 unexpanded_macros: Vec::new(),
30 global_macro_scope: FxHashMap::default(), 60 global_macro_scope: FxHashMap::default(),
@@ -39,8 +69,9 @@ struct DefCollector<DB> {
39 db: DB, 69 db: DB,
40 krate: Crate, 70 krate: Crate,
41 def_map: CrateDefMap, 71 def_map: CrateDefMap,
42 unresolved_imports: Vec<(ModuleId, raw::Import)>, 72 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, raw::ImportId)>>,
43 unexpanded_macros: Vec<(ModuleId, MacroCallId, tt::Subtree)>, 73 unresolved_imports: Vec<(ModuleId, raw::ImportId, raw::ImportData)>,
74 unexpanded_macros: Vec<(ModuleId, MacroCallId, Path, tt::Subtree)>,
44 global_macro_scope: FxHashMap<Name, mbe::MacroRules>, 75 global_macro_scope: FxHashMap<Name, mbe::MacroRules>,
45} 76}
46 77
@@ -83,8 +114,11 @@ where
83 } 114 }
84 } 115 }
85 116
86 fn define_macro(&mut self, name: Name, tt: &tt::Subtree) { 117 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) {
87 if let Ok(rules) = mbe::MacroRules::parse(tt) { 118 if let Ok(rules) = mbe::MacroRules::parse(tt) {
119 if export {
120 self.def_map.public_macros.insert(name.clone(), rules.clone());
121 }
88 self.global_macro_scope.insert(name, rules); 122 self.global_macro_scope.insert(name, rules);
89 } 123 }
90 } 124 }
@@ -94,22 +128,218 @@ where
94 } 128 }
95 129
96 fn resolve_imports(&mut self) -> ReachedFixedPoint { 130 fn resolve_imports(&mut self) -> ReachedFixedPoint {
131 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
132 let mut resolved = Vec::new();
133 imports.retain(|(module_id, import, import_data)| {
134 let (def, fp) = self.resolve_import(*module_id, import_data);
135 if fp == ReachedFixedPoint::Yes {
136 resolved.push((*module_id, def, *import, import_data.clone()))
137 }
138 fp == ReachedFixedPoint::No
139 });
140 self.unresolved_imports = imports;
97 // Resolves imports, filling-in module scopes 141 // Resolves imports, filling-in module scopes
98 ReachedFixedPoint::Yes 142 let result =
143 if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
144 for (module_id, def, import, import_data) in resolved {
145 self.record_resolved_import(module_id, def, import, &import_data)
146 }
147 result
99 } 148 }
100 149
101 fn resolve_macros(&mut self) -> ReachedFixedPoint { 150 fn resolve_import(
102 // Resolve macros, calling into `expand_macro` to actually do the 151 &mut self,
103 // expansion. 152 module_id: ModuleId,
104 ReachedFixedPoint::Yes 153 import: &raw::ImportData,
154 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
155 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
156 if import.is_extern_crate {
157 let res = self.def_map.resolve_name_in_extern_prelude(
158 &import
159 .path
160 .as_ident()
161 .expect("extern crate should have been desugared to one-element path"),
162 );
163 // FIXME: why do we return No here?
164 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
165 } else {
166 let res =
167 self.def_map.resolve_path_fp(self.db, ResolveMode::Import, module_id, &import.path);
168
169 (res.resolved_def, res.reached_fixedpoint)
170 }
171 }
172
173 fn record_resolved_import(
174 &mut self,
175 module_id: ModuleId,
176 def: PerNs<ModuleDef>,
177 import_id: raw::ImportId,
178 import: &raw::ImportData,
179 ) {
180 if import.is_glob {
181 log::debug!("glob import: {:?}", import);
182 match def.take_types() {
183 Some(ModuleDef::Module(m)) => {
184 if import.is_prelude {
185 tested_by!(std_prelude);
186 self.def_map.prelude = Some(m);
187 } else if m.krate != self.krate {
188 tested_by!(glob_across_crates);
189 // glob import from other crate => we can just import everything once
190 let item_map = self.db.item_map(m.krate);
191 let scope = &item_map[m.module_id];
192 let items = scope
193 .items
194 .iter()
195 .map(|(name, res)| (name.clone(), res.clone()))
196 .collect::<Vec<_>>();
197 self.update(module_id, Some(import_id), &items);
198 } else {
199 // glob import from same crate => we do an initial
200 // import, and then need to propagate any further
201 // additions
202 let scope = &self.def_map[m.module_id];
203 let items = scope
204 .items
205 .iter()
206 .map(|(name, res)| (name.clone(), res.clone()))
207 .collect::<Vec<_>>();
208 self.update(module_id, Some(import_id), &items);
209 // record the glob import in case we add further items
210 self.glob_imports
211 .entry(m.module_id)
212 .or_default()
213 .push((module_id, import_id));
214 }
215 }
216 Some(ModuleDef::Enum(e)) => {
217 tested_by!(glob_enum);
218 // glob import from enum => just import all the variants
219 let variants = e.variants(self.db);
220 let resolutions = variants
221 .into_iter()
222 .filter_map(|variant| {
223 let res = Resolution {
224 def: PerNs::both(variant.into(), variant.into()),
225 import: Some(import_id),
226 };
227 let name = variant.name(self.db)?;
228 Some((name, res))
229 })
230 .collect::<Vec<_>>();
231 self.update(module_id, Some(import_id), &resolutions);
232 }
233 Some(d) => {
234 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
235 }
236 None => {
237 log::debug!("glob import {:?} didn't resolve as type", import);
238 }
239 }
240 } else {
241 let last_segment = import.path.segments.last().unwrap();
242 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
243 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
244
245 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
246 if let Some(root_module) = self.krate.root_module(self.db) {
247 if import.is_extern_crate && module_id == root_module.module_id {
248 if let Some(def) = def.take_types() {
249 self.def_map.extern_prelude.insert(name.clone(), def);
250 }
251 }
252 }
253 let resolution = Resolution { def, import: Some(import_id) };
254 self.update(module_id, None, &[(name, resolution)]);
255 }
256 }
257
258 fn update(
259 &mut self,
260 module_id: ModuleId,
261 import: Option<raw::ImportId>,
262 resolutions: &[(Name, Resolution)],
263 ) {
264 self.update_recursive(module_id, import, resolutions, 0)
105 } 265 }
106 266
107 #[allow(unused)] 267 fn update_recursive(
108 fn expand_macro(&mut self, idx: usize, rules: &mbe::MacroRules) { 268 &mut self,
109 let (module_id, call_id, arg) = self.unexpanded_macros.swap_remove(idx); 269 module_id: ModuleId,
110 if let Ok(tt) = rules.expand(&arg) { 270 import: Option<raw::ImportId>,
111 self.collect_macro_expansion(module_id, call_id, tt); 271 resolutions: &[(Name, Resolution)],
272 depth: usize,
273 ) {
274 if depth > 100 {
275 // prevent stack overflows (but this shouldn't be possible)
276 panic!("infinite recursion in glob imports!");
112 } 277 }
278 let module_items = &mut self.def_map.modules[module_id].scope;
279 let mut changed = false;
280 for (name, res) in resolutions {
281 let existing = module_items.items.entry(name.clone()).or_default();
282 if existing.def.types.is_none() && res.def.types.is_some() {
283 existing.def.types = res.def.types;
284 existing.import = import.or(res.import);
285 changed = true;
286 }
287 if existing.def.values.is_none() && res.def.values.is_some() {
288 existing.def.values = res.def.values;
289 existing.import = import.or(res.import);
290 changed = true;
291 }
292 }
293 if !changed {
294 return;
295 }
296 let glob_imports = self
297 .glob_imports
298 .get(&module_id)
299 .into_iter()
300 .flat_map(|v| v.iter())
301 .cloned()
302 .collect::<Vec<_>>();
303 for (glob_importing_module, glob_import) in glob_imports {
304 // We pass the glob import so that the tracked import in those modules is that glob import
305 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
306 }
307 }
308
309 // XXX: this is just a pile of hacks now, because `PerNs` does not handle
310 // macro namespace.
311 fn resolve_macros(&mut self) -> ReachedFixedPoint {
312 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
313 let mut resolved = Vec::new();
314 macros.retain(|(module_id, call_id, path, tt)| {
315 if path.segments.len() != 2 {
316 return true;
317 }
318 let crate_name = &path.segments[0].name;
319 let krate = match self.def_map.resolve_name_in_extern_prelude(crate_name).take_types() {
320 Some(ModuleDef::Module(m)) => m.krate(self.db),
321 _ => return true,
322 };
323 let krate = match krate {
324 Some(it) => it,
325 _ => return true,
326 };
327 // FIXME: this should be a proper query
328 let def_map = crate_def_map_query(self.db, krate);
329 let rules = def_map.public_macros.get(&path.segments[1].name).cloned();
330 resolved.push((*module_id, *call_id, rules, tt.clone()));
331 false
332 });
333 let res = if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
334
335 for (module_id, macro_call_id, rules, arg) in resolved {
336 if let Some(rules) = rules {
337 if let Ok(tt) = rules.expand(&arg) {
338 self.collect_macro_expansion(module_id, macro_call_id, tt);
339 }
340 }
341 }
342 res
113 } 343 }
114 344
115 fn collect_macro_expansion( 345 fn collect_macro_expansion(
@@ -145,9 +375,11 @@ where
145 for item in items { 375 for item in items {
146 match *item { 376 match *item {
147 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), 377 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]),
148 raw::RawItem::Import(import) => { 378 raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push((
149 self.def_collector.unresolved_imports.push((self.module_id, import)) 379 self.module_id,
150 } 380 import,
381 self.raw_items[import].clone(),
382 )),
151 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), 383 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]),
152 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 384 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
153 } 385 }
@@ -216,14 +448,14 @@ where
216 raw::DefKind::TypeAlias => PerNs::types(TypeAlias { id: id!() }.into()), 448 raw::DefKind::TypeAlias => PerNs::types(TypeAlias { id: id!() }.into()),
217 }; 449 };
218 let resolution = Resolution { def, import: None }; 450 let resolution = Resolution { def, import: None };
219 self.def_collector.def_map.modules[self.module_id].scope.items.insert(name, resolution); 451 self.def_collector.update(self.module_id, None, &[(name, resolution)])
220 } 452 }
221 453
222 fn collect_macro(&mut self, mac: &raw::MacroData) { 454 fn collect_macro(&mut self, mac: &raw::MacroData) {
223 // Case 1: macro rules, define a macro in crate-global mutable scope 455 // Case 1: macro rules, define a macro in crate-global mutable scope
224 if is_macro_rules(&mac.path) { 456 if is_macro_rules(&mac.path) {
225 if let Some(name) = &mac.name { 457 if let Some(name) = &mac.name {
226 self.def_collector.define_macro(name.clone(), &mac.arg) 458 self.def_collector.define_macro(name.clone(), &mac.arg, mac.export)
227 } 459 }
228 return; 460 return;
229 } 461 }
@@ -247,7 +479,12 @@ where
247 } 479 }
248 480
249 // Case 3: path to a macro from another crate, expand during name resolution 481 // Case 3: path to a macro from another crate, expand during name resolution
250 self.def_collector.unexpanded_macros.push((self.module_id, macro_call_id, mac.arg.clone())) 482 self.def_collector.unexpanded_macros.push((
483 self.module_id,
484 macro_call_id,
485 mac.path.clone(),
486 mac.arg.clone(),
487 ))
251 } 488 }
252} 489}
253 490