diff options
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.rs | 283 |
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 | ||
3 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
4 | use ra_arena::Arena; | 4 | use ra_arena::Arena; |
5 | use test_utils::tested_by; | ||
5 | 6 | ||
6 | use crate::{ | 7 | use 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 | ||