aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-09 22:09:23 +0100
committerGitHub <[email protected]>2019-09-09 22:09:23 +0100
commitc3d96f64ef1b2a5ded9cf5950f8e0f5798de4e1b (patch)
treea0d6c8121ca6845a48acbb3e9a895a07bfc584ce /crates/ra_hir/src/nameres.rs
parent5fbdf57c4fe7ee99ba94549766a2644431f61b26 (diff)
parent5f48ef39024f62c135197e764741354611e02b6f (diff)
Merge #1795
1795: Make macro scope a real name scope and fix some details r=matklad a=uHOOCCOOHu This PR make macro's module scope a real name scope in `PerNs`, instead of handling `Either<PerNs, MacroDef>` everywhere. In `rustc`, the macro scope behave exactly the same as type and value scope. It is valid that macros, types and values having exact the same name, and a `use` statement will import all of them. This happened to module `alloc::vec` and macro `alloc::vec!`. So `Either` is not suitable here. There is a trap that not only does `#[macro_use]` import all `#[macro_export] macro_rules`, but also imports all macros `use`d in the crate root. In other words, it just _imports all macros in the module scope of crate root_. (Visibility of `use` doesn't matter.) And it also happened to `libstd` which has `use alloc_crate::vec;` in crate root to re-export `alloc::vec`, which it both a module and a macro. The current implementation of `#[macro_use] extern crate` doesn't work here, so that is why only macros directly from `libstd` like `dbg!` work, while `vec!` from `liballoc` doesn't. This PR fixes this. Another point is that, after some tests, I figure out that _`macro_rules` does NOT define macro in current module scope at all_. It defines itself in legacy textual scope. And if `#[macro_export]` is given, it also is defined ONLY in module scope of crate root. (Then being `macro_use`d, as mentioned above) (Well, the nightly [Declarative Macro 2.0](https://github.com/rust-lang/rust/issues/39412) simply always define in current module scope only, just like normal items do. But it is not yet supported by us) After this PR, in my test, all non-builtin macros are resolved now. (Hover text for documentation is available) So it fixes #1688 . Since compiler builtin macros are marked as `#[rustc_doc_only_macro]` instead of `#[macro_export]`, we can simply tweak the condition to let it resolved, but it may cause expansion error. Some critical notes are also given in doc-comments. <img width="447" alt="Screenshot_20190909_223859" src="https://user-images.githubusercontent.com/14816024/64540366-ac1ef600-d352-11e9-804f-566ba7559206.png"> Co-authored-by: uHOOCCOOHu <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r--crates/ra_hir/src/nameres.rs158
1 files changed, 65 insertions, 93 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 74546e5e2..7488d75a5 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -67,7 +67,6 @@ use test_utils::tested_by;
67use crate::{ 67use crate::{
68 db::{AstDatabase, DefDatabase}, 68 db::{AstDatabase, DefDatabase},
69 diagnostics::DiagnosticSink, 69 diagnostics::DiagnosticSink,
70 either::Either,
71 ids::MacroDefId, 70 ids::MacroDefId,
72 nameres::diagnostics::DefDiagnostic, 71 nameres::diagnostics::DefDiagnostic,
73 AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, 72 AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait,
@@ -105,8 +104,6 @@ pub struct CrateDefMap {
105 /// However, do we want to put it as a global variable? 104 /// However, do we want to put it as a global variable?
106 poison_macros: FxHashSet<MacroDefId>, 105 poison_macros: FxHashSet<MacroDefId>,
107 106
108 exported_macros: FxHashMap<Name, MacroDefId>,
109
110 diagnostics: Vec<DefDiagnostic>, 107 diagnostics: Vec<DefDiagnostic>,
111} 108}
112 109
@@ -138,12 +135,6 @@ pub(crate) struct ModuleData {
138#[derive(Debug, Default, PartialEq, Eq, Clone)] 135#[derive(Debug, Default, PartialEq, Eq, Clone)]
139pub struct ModuleScope { 136pub struct ModuleScope {
140 items: FxHashMap<Name, Resolution>, 137 items: FxHashMap<Name, Resolution>,
141 /// Macros in current module scoped
142 ///
143 /// This scope works exactly the same way that item scoping does.
144 /// Macro invocation with quantified path will search in it.
145 /// See details below.
146 macros: FxHashMap<Name, MacroDef>,
147 /// Macros visable in current module in legacy textual scope 138 /// Macros visable in current module in legacy textual scope
148 /// 139 ///
149 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. 140 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -152,6 +143,10 @@ pub struct ModuleScope {
152 /// and only normal scoped `macros` will be searched in. 143 /// and only normal scoped `macros` will be searched in.
153 /// 144 ///
154 /// Note that this automatically inherit macros defined textually before the definition of module itself. 145 /// Note that this automatically inherit macros defined textually before the definition of module itself.
146 ///
147 /// Module scoped macros will be inserted into `items` instead of here.
148 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
149 // be all resolved to the last one defined if shadowing happens.
155 legacy_macros: FxHashMap<Name, MacroDef>, 150 legacy_macros: FxHashMap<Name, MacroDef>,
156} 151}
157 152
@@ -164,35 +159,43 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
164 .collect() 159 .collect()
165}); 160});
166 161
162/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
163/// Other methods will only resolve values, types and module scoped macros only.
167impl ModuleScope { 164impl ModuleScope {
168 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a { 165 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
169 //FIXME: shadowing 166 //FIXME: shadowing
170 self.items.iter().chain(BUILTIN_SCOPE.iter()) 167 self.items.iter().chain(BUILTIN_SCOPE.iter())
171 } 168 }
169
170 /// Iterate over all module scoped macros
171 pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
172 self.items
173 .iter()
174 .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
175 }
176
177 /// Iterate over all legacy textual scoped macros visable at the end of the module
178 pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
179 self.legacy_macros.iter().map(|(name, def)| (name, *def))
180 }
181
182 /// Get a name from current module scope, legacy macros are not included
172 pub fn get(&self, name: &Name) -> Option<&Resolution> { 183 pub fn get(&self, name: &Name) -> Option<&Resolution> {
173 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) 184 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
174 } 185 }
186
175 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { 187 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
176 self.items.values().filter_map(|r| match r.def.take_types() { 188 self.items.values().filter_map(|r| match r.def.take_types() {
177 Some(ModuleDef::Trait(t)) => Some(t), 189 Some(ModuleDef::Trait(t)) => Some(t),
178 _ => None, 190 _ => None,
179 }) 191 })
180 } 192 }
181 /// It resolves in module scope. Textual scoped macros are ignored here. 193
182 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
183 match (self.get(name), self.macros.get(name)) {
184 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)),
185 (_, Some(macro_)) => Some(Either::B(*macro_)),
186 _ => None,
187 }
188 }
189 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> { 194 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> {
190 self.legacy_macros.get(name).copied() 195 self.legacy_macros.get(name).copied()
191 } 196 }
192} 197}
193 198
194type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>;
195
196#[derive(Debug, Clone, PartialEq, Eq, Default)] 199#[derive(Debug, Clone, PartialEq, Eq, Default)]
197pub struct Resolution { 200pub struct Resolution {
198 /// None for unresolved 201 /// None for unresolved
@@ -201,20 +204,26 @@ pub struct Resolution {
201 pub import: Option<ImportId>, 204 pub import: Option<ImportId>,
202} 205}
203 206
207impl Resolution {
208 pub(crate) fn from_macro(macro_: MacroDef) -> Self {
209 Resolution { def: PerNs::macros(macro_), import: None }
210 }
211}
212
204#[derive(Debug, Clone)] 213#[derive(Debug, Clone)]
205struct ResolvePathResult { 214struct ResolvePathResult {
206 resolved_def: ItemOrMacro, 215 resolved_def: PerNs<ModuleDef>,
207 segment_index: Option<usize>, 216 segment_index: Option<usize>,
208 reached_fixedpoint: ReachedFixedPoint, 217 reached_fixedpoint: ReachedFixedPoint,
209} 218}
210 219
211impl ResolvePathResult { 220impl ResolvePathResult {
212 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { 221 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
213 ResolvePathResult::with(Either::A(PerNs::none()), reached_fixedpoint, None) 222 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
214 } 223 }
215 224
216 fn with( 225 fn with(
217 resolved_def: ItemOrMacro, 226 resolved_def: PerNs<ModuleDef>,
218 reached_fixedpoint: ReachedFixedPoint, 227 reached_fixedpoint: ReachedFixedPoint,
219 segment_index: Option<usize>, 228 segment_index: Option<usize>,
220 ) -> ResolvePathResult { 229 ) -> ResolvePathResult {
@@ -234,21 +243,6 @@ enum ReachedFixedPoint {
234 No, 243 No,
235} 244}
236 245
237/// helper function for select item or macro to use
238fn or(left: ItemOrMacro, right: ItemOrMacro) -> ItemOrMacro {
239 match (left, right) {
240 (Either::A(s), Either::A(o)) => Either::A(s.or(o)),
241 (Either::B(s), _) => Either::B(s),
242 (Either::A(s), Either::B(o)) => {
243 if !s.is_none() {
244 Either::A(s)
245 } else {
246 Either::B(o)
247 }
248 }
249 }
250}
251
252impl CrateDefMap { 246impl CrateDefMap {
253 pub(crate) fn crate_def_map_query( 247 pub(crate) fn crate_def_map_query(
254 // Note that this doesn't have `+ AstDatabase`! 248 // Note that this doesn't have `+ AstDatabase`!
@@ -269,7 +263,6 @@ impl CrateDefMap {
269 root, 263 root,
270 modules, 264 modules,
271 poison_macros: FxHashSet::default(), 265 poison_macros: FxHashSet::default(),
272 exported_macros: FxHashMap::default(),
273 diagnostics: Vec::new(), 266 diagnostics: Vec::new(),
274 } 267 }
275 }; 268 };
@@ -328,16 +321,6 @@ impl CrateDefMap {
328 path: &Path, 321 path: &Path,
329 ) -> (PerNs<ModuleDef>, Option<usize>) { 322 ) -> (PerNs<ModuleDef>, Option<usize>) {
330 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 323 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
331 (res.resolved_def.a().unwrap_or_else(PerNs::none), res.segment_index)
332 }
333
334 pub(crate) fn resolve_path_with_macro(
335 &self,
336 db: &impl DefDatabase,
337 original_module: CrateModuleId,
338 path: &Path,
339 ) -> (ItemOrMacro, Option<usize>) {
340 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
341 (res.resolved_def, res.segment_index) 324 (res.resolved_def, res.segment_index)
342 } 325 }
343 326
@@ -351,13 +334,13 @@ impl CrateDefMap {
351 path: &Path, 334 path: &Path,
352 ) -> ResolvePathResult { 335 ) -> ResolvePathResult {
353 let mut segments = path.segments.iter().enumerate(); 336 let mut segments = path.segments.iter().enumerate();
354 let mut curr_per_ns: ItemOrMacro = match path.kind { 337 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
355 PathKind::Crate => { 338 PathKind::Crate => {
356 Either::A(PerNs::types(Module { krate: self.krate, module_id: self.root }.into())) 339 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
340 }
341 PathKind::Self_ => {
342 PerNs::types(Module { krate: self.krate, module_id: original_module }.into())
357 } 343 }
358 PathKind::Self_ => Either::A(PerNs::types(
359 Module { krate: self.krate, module_id: original_module }.into(),
360 )),
361 // plain import or absolute path in 2015: crate-relative with 344 // plain import or absolute path in 2015: crate-relative with
362 // fallback to extern prelude (with the simplification in 345 // fallback to extern prelude (with the simplification in
363 // rust-lang/rust#57745) 346 // rust-lang/rust#57745)
@@ -379,11 +362,11 @@ impl CrateDefMap {
379 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 362 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
380 }; 363 };
381 log::debug!("resolving {:?} in module", segment); 364 log::debug!("resolving {:?} in module", segment);
382 self.resolve_name_in_module_with_macro(db, original_module, &segment.name) 365 self.resolve_name_in_module(db, original_module, &segment.name)
383 } 366 }
384 PathKind::Super => { 367 PathKind::Super => {
385 if let Some(p) = self.modules[original_module].parent { 368 if let Some(p) = self.modules[original_module].parent {
386 Either::A(PerNs::types(Module { krate: self.krate, module_id: p }.into())) 369 PerNs::types(Module { krate: self.krate, module_id: p }.into())
387 } else { 370 } else {
388 log::debug!("super path in root module"); 371 log::debug!("super path in root module");
389 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 372 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -397,7 +380,7 @@ impl CrateDefMap {
397 }; 380 };
398 if let Some(def) = self.extern_prelude.get(&segment.name) { 381 if let Some(def) = self.extern_prelude.get(&segment.name) {
399 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 382 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
400 Either::A(PerNs::types(*def)) 383 PerNs::types(*def)
401 } else { 384 } else {
402 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 385 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
403 } 386 }
@@ -405,7 +388,7 @@ impl CrateDefMap {
405 }; 388 };
406 389
407 for (i, segment) in segments { 390 for (i, segment) in segments {
408 let curr = match curr_per_ns.as_ref().a().and_then(|m| m.as_ref().take_types()) { 391 let curr = match curr_per_ns.as_ref().take_types() {
409 Some(r) => r, 392 Some(r) => r,
410 None => { 393 None => {
411 // we still have path segments left, but the path so far 394 // we still have path segments left, but the path so far
@@ -425,8 +408,7 @@ impl CrateDefMap {
425 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; 408 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
426 log::debug!("resolving {:?} in other crate", path); 409 log::debug!("resolving {:?} in other crate", path);
427 let defp_map = db.crate_def_map(module.krate); 410 let defp_map = db.crate_def_map(module.krate);
428 let (def, s) = 411 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
429 defp_map.resolve_path_with_macro(db, module.module_id, &path);
430 return ResolvePathResult::with( 412 return ResolvePathResult::with(
431 def, 413 def,
432 ReachedFixedPoint::Yes, 414 ReachedFixedPoint::Yes,
@@ -434,8 +416,9 @@ impl CrateDefMap {
434 ); 416 );
435 } 417 }
436 418
437 match self[module.module_id].scope.get_item_or_macro(&segment.name) { 419 // Since it is a quantified path here, it should not contains legacy macros
438 Some(res) => res, 420 match self[module.module_id].scope.get(&segment.name) {
421 Some(res) => res.def,
439 _ => { 422 _ => {
440 log::debug!("path segment {:?} not found", segment.name); 423 log::debug!("path segment {:?} not found", segment.name);
441 return ResolvePathResult::empty(ReachedFixedPoint::No); 424 return ResolvePathResult::empty(ReachedFixedPoint::No);
@@ -446,10 +429,10 @@ impl CrateDefMap {
446 // enum variant 429 // enum variant
447 tested_by!(can_import_enum_variant); 430 tested_by!(can_import_enum_variant);
448 match e.variant(db, &segment.name) { 431 match e.variant(db, &segment.name) {
449 Some(variant) => Either::A(PerNs::both(variant.into(), variant.into())), 432 Some(variant) => PerNs::both(variant.into(), variant.into()),
450 None => { 433 None => {
451 return ResolvePathResult::with( 434 return ResolvePathResult::with(
452 Either::A(PerNs::types((*e).into())), 435 PerNs::types((*e).into()),
453 ReachedFixedPoint::Yes, 436 ReachedFixedPoint::Yes,
454 Some(i), 437 Some(i),
455 ); 438 );
@@ -466,7 +449,7 @@ impl CrateDefMap {
466 ); 449 );
467 450
468 return ResolvePathResult::with( 451 return ResolvePathResult::with(
469 Either::A(PerNs::types(*s)), 452 PerNs::types(*s),
470 ReachedFixedPoint::Yes, 453 ReachedFixedPoint::Yes,
471 Some(i), 454 Some(i),
472 ); 455 );
@@ -476,14 +459,12 @@ impl CrateDefMap {
476 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 459 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
477 } 460 }
478 461
479 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> ItemOrMacro { 462 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
480 let from_crate_root = self[self.root] 463 let from_crate_root =
481 .scope 464 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
482 .get_item_or_macro(name)
483 .unwrap_or_else(|| Either::A(PerNs::none()));
484 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 465 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
485 466
486 or(from_crate_root, Either::A(from_extern_prelude)) 467 from_crate_root.or(from_extern_prelude)
487 } 468 }
488 469
489 pub(crate) fn resolve_name_in_module( 470 pub(crate) fn resolve_name_in_module(
@@ -492,47 +473,38 @@ impl CrateDefMap {
492 module: CrateModuleId, 473 module: CrateModuleId,
493 name: &Name, 474 name: &Name,
494 ) -> PerNs<ModuleDef> { 475 ) -> PerNs<ModuleDef> {
495 self.resolve_name_in_module_with_macro(db, module, name).a().unwrap_or_else(PerNs::none)
496 }
497
498 fn resolve_name_in_module_with_macro(
499 &self,
500 db: &impl DefDatabase,
501 module: CrateModuleId,
502 name: &Name,
503 ) -> ItemOrMacro {
504 // Resolve in: 476 // Resolve in:
505 // - legacy scope 477 // - legacy scope of macro
506 // - current module / scope 478 // - current module / scope
507 // - extern prelude 479 // - extern prelude
508 // - std prelude 480 // - std prelude
509 let from_legacy_macro = self[module] 481 let from_legacy_macro =
510 .scope 482 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
511 .get_legacy_macro(name) 483 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
512 .map_or_else(|| Either::A(PerNs::none()), Either::B);
513 let from_scope =
514 self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none()));
515 let from_extern_prelude = 484 let from_extern_prelude =
516 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 485 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
517 let from_prelude = self.resolve_in_prelude(db, name); 486 let from_prelude = self.resolve_in_prelude(db, name);
518 487
519 or(from_legacy_macro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude))) 488 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
520 } 489 }
521 490
522 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 491 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
523 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 492 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
524 } 493 }
525 494
526 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> ItemOrMacro { 495 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs<ModuleDef> {
527 if let Some(prelude) = self.prelude { 496 if let Some(prelude) = self.prelude {
528 let resolution = if prelude.krate == self.krate { 497 let keep;
529 self[prelude.module_id].scope.get_item_or_macro(name) 498 let def_map = if prelude.krate == self.krate {
499 self
530 } else { 500 } else {
531 db.crate_def_map(prelude.krate)[prelude.module_id].scope.get_item_or_macro(name) 501 // Extend lifetime
502 keep = db.crate_def_map(prelude.krate);
503 &keep
532 }; 504 };
533 resolution.unwrap_or_else(|| Either::A(PerNs::none())) 505 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
534 } else { 506 } else {
535 Either::A(PerNs::none()) 507 PerNs::none()
536 } 508 }
537 } 509 }
538} 510}