diff options
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 158 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 178 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/per_ns.rs | 59 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 46 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 119 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 58 |
8 files changed, 399 insertions, 236 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; | |||
67 | use crate::{ | 67 | use 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)] |
139 | pub struct ModuleScope { | 136 | pub 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. | ||
167 | impl ModuleScope { | 164 | impl 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 | ||
194 | type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>; | ||
195 | |||
196 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 199 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
197 | pub struct Resolution { | 200 | pub 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 | ||
207 | impl 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)] |
205 | struct ResolvePathResult { | 214 | struct 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 | ||
211 | impl ResolvePathResult { | 220 | impl 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 | ||
238 | fn 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 | |||
252 | impl CrateDefMap { | 246 | impl 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 | } |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 09cda7656..03fbbd33f 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -5,14 +5,13 @@ use test_utils::tested_by; | |||
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | either::Either, | ||
9 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, | 8 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, |
10 | name::MACRO_RULES, | 9 | name::MACRO_RULES, |
11 | nameres::{ | 10 | nameres::{ |
12 | diagnostics::DefDiagnostic, | 11 | diagnostics::DefDiagnostic, |
13 | mod_resolution::{resolve_submodule, ParentModule}, | 12 | mod_resolution::{resolve_submodule, ParentModule}, |
14 | raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, | 13 | raw, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint, |
15 | ReachedFixedPoint, Resolution, ResolveMode, | 14 | Resolution, ResolveMode, |
16 | }, | 15 | }, |
17 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, | 16 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, |
18 | Struct, Trait, TypeAlias, Union, | 17 | Struct, Trait, TypeAlias, Union, |
@@ -123,30 +122,51 @@ where | |||
123 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 122 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
124 | // show unresolved imports in completion, etc | 123 | // show unresolved imports in completion, etc |
125 | for (module_id, import, import_data) in unresolved_imports { | 124 | for (module_id, import, import_data) in unresolved_imports { |
126 | self.record_resolved_import(module_id, Either::A(PerNs::none()), import, &import_data) | 125 | self.record_resolved_import(module_id, PerNs::none(), import, &import_data) |
127 | } | 126 | } |
128 | } | 127 | } |
129 | 128 | ||
129 | /// Define a macro with `macro_rules`. | ||
130 | /// | ||
131 | /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, | ||
132 | /// then it is also defined in the root module scope. | ||
133 | /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition. | ||
134 | /// | ||
135 | /// It is surprising that the macro will never be in the current module scope. | ||
136 | /// These code fails with "unresolved import/macro", | ||
137 | /// ```rust,compile_fail | ||
138 | /// mod m { macro_rules! foo { () => {} } } | ||
139 | /// use m::foo as bar; | ||
140 | /// ``` | ||
141 | /// | ||
142 | /// ```rust,compile_fail | ||
143 | /// macro_rules! foo { () => {} } | ||
144 | /// self::foo!(); | ||
145 | /// crate::foo!(); | ||
146 | /// ``` | ||
147 | /// | ||
148 | /// Well, this code compiles, bacause the plain path `foo` in `use` is searched | ||
149 | /// in the legacy textual scope only. | ||
150 | /// ```rust | ||
151 | /// macro_rules! foo { () => {} } | ||
152 | /// use foo as bar; | ||
153 | /// ``` | ||
130 | fn define_macro( | 154 | fn define_macro( |
131 | &mut self, | 155 | &mut self, |
132 | module_id: CrateModuleId, | 156 | module_id: CrateModuleId, |
133 | name: Name, | 157 | name: Name, |
134 | macro_id: MacroDefId, | 158 | macro_: MacroDef, |
135 | export: bool, | 159 | export: bool, |
136 | ) { | 160 | ) { |
137 | let def = Either::B(MacroDef { id: macro_id }); | 161 | // Textual scoping |
162 | self.define_legacy_macro(module_id, name.clone(), macro_); | ||
138 | 163 | ||
164 | // Module scoping | ||
139 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | 165 | // In Rust, `#[macro_export]` macros are unconditionally visible at the |
140 | // crate root, even if the parent modules is **not** visible. | 166 | // crate root, even if the parent modules is **not** visible. |
141 | if export { | 167 | if export { |
142 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); | 168 | self.update(self.def_map.root, None, &[(name.clone(), Resolution::from_macro(macro_))]); |
143 | |||
144 | // Exported macros are collected in crate level ready for | ||
145 | // glob import with `#[macro_use]`. | ||
146 | self.def_map.exported_macros.insert(name.clone(), macro_id); | ||
147 | } | 169 | } |
148 | self.update(module_id, None, &[(name.clone(), def)]); | ||
149 | self.define_legacy_macro(module_id, name.clone(), macro_id); | ||
150 | } | 170 | } |
151 | 171 | ||
152 | /// Define a legacy textual scoped macro in module | 172 | /// Define a legacy textual scoped macro in module |
@@ -156,14 +176,12 @@ where | |||
156 | /// the definition of current module. | 176 | /// the definition of current module. |
157 | /// And also, `macro_use` on a module will import all legacy macros visable inside to | 177 | /// And also, `macro_use` on a module will import all legacy macros visable inside to |
158 | /// current legacy scope, with possible shadowing. | 178 | /// current legacy scope, with possible shadowing. |
159 | fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { | 179 | fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) { |
160 | // Always shadowing | 180 | // Always shadowing |
161 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, MacroDef { id: macro_id }); | 181 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); |
162 | } | 182 | } |
163 | 183 | ||
164 | /// Import macros from `#[macro_use] extern crate`. | 184 | /// Import macros from `#[macro_use] extern crate`. |
165 | /// | ||
166 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | ||
167 | fn import_macros_from_extern_crate( | 185 | fn import_macros_from_extern_crate( |
168 | &mut self, | 186 | &mut self, |
169 | current_module_id: CrateModuleId, | 187 | current_module_id: CrateModuleId, |
@@ -184,14 +202,20 @@ where | |||
184 | 202 | ||
185 | if let Some(ModuleDef::Module(m)) = res.take_types() { | 203 | if let Some(ModuleDef::Module(m)) = res.take_types() { |
186 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | 204 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); |
187 | self.import_all_macros_exported(current_module_id, m); | 205 | self.import_all_macros_exported(current_module_id, m.krate); |
188 | } | 206 | } |
189 | } | 207 | } |
190 | 208 | ||
191 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) { | 209 | /// Import all exported macros from another crate |
192 | let item_map = self.db.crate_def_map(module.krate); | 210 | /// |
193 | for (name, ¯o_id) in &item_map.exported_macros { | 211 | /// Exported macros are just all macros in the root module scope. |
194 | self.define_legacy_macro(current_module_id, name.clone(), macro_id); | 212 | /// Note that it contains not only all `#[macro_export]` macros, but also all aliases |
213 | /// created by `use` in the root module, ignoring the visibility of `use`. | ||
214 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) { | ||
215 | let def_map = self.db.crate_def_map(krate); | ||
216 | for (name, def) in def_map[def_map.root].scope.macros() { | ||
217 | // `macro_use` only bring things into legacy scope. | ||
218 | self.define_legacy_macro(current_module_id, name.clone(), def); | ||
195 | } | 219 | } |
196 | } | 220 | } |
197 | 221 | ||
@@ -219,7 +243,7 @@ where | |||
219 | &self, | 243 | &self, |
220 | module_id: CrateModuleId, | 244 | module_id: CrateModuleId, |
221 | import: &raw::ImportData, | 245 | import: &raw::ImportData, |
222 | ) -> (ItemOrMacro, ReachedFixedPoint) { | 246 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { |
223 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); | 247 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); |
224 | if import.is_extern_crate { | 248 | if import.is_extern_crate { |
225 | let res = self.def_map.resolve_name_in_extern_prelude( | 249 | let res = self.def_map.resolve_name_in_extern_prelude( |
@@ -228,7 +252,7 @@ where | |||
228 | .as_ident() | 252 | .as_ident() |
229 | .expect("extern crate should have been desugared to one-element path"), | 253 | .expect("extern crate should have been desugared to one-element path"), |
230 | ); | 254 | ); |
231 | (Either::A(res), ReachedFixedPoint::Yes) | 255 | (res, ReachedFixedPoint::Yes) |
232 | } else { | 256 | } else { |
233 | let res = self.def_map.resolve_path_fp_with_macro( | 257 | let res = self.def_map.resolve_path_fp_with_macro( |
234 | self.db, | 258 | self.db, |
@@ -244,13 +268,13 @@ where | |||
244 | fn record_resolved_import( | 268 | fn record_resolved_import( |
245 | &mut self, | 269 | &mut self, |
246 | module_id: CrateModuleId, | 270 | module_id: CrateModuleId, |
247 | def: ItemOrMacro, | 271 | def: PerNs<ModuleDef>, |
248 | import_id: raw::ImportId, | 272 | import_id: raw::ImportId, |
249 | import: &raw::ImportData, | 273 | import: &raw::ImportData, |
250 | ) { | 274 | ) { |
251 | if import.is_glob { | 275 | if import.is_glob { |
252 | log::debug!("glob import: {:?}", import); | 276 | log::debug!("glob import: {:?}", import); |
253 | match def.a().and_then(|item| item.take_types()) { | 277 | match def.take_types() { |
254 | Some(ModuleDef::Module(m)) => { | 278 | Some(ModuleDef::Module(m)) => { |
255 | if import.is_prelude { | 279 | if import.is_prelude { |
256 | tested_by!(std_prelude); | 280 | tested_by!(std_prelude); |
@@ -260,30 +284,29 @@ where | |||
260 | // glob import from other crate => we can just import everything once | 284 | // glob import from other crate => we can just import everything once |
261 | let item_map = self.db.crate_def_map(m.krate); | 285 | let item_map = self.db.crate_def_map(m.krate); |
262 | let scope = &item_map[m.module_id].scope; | 286 | let scope = &item_map[m.module_id].scope; |
287 | |||
288 | // Module scoped macros is included | ||
263 | let items = scope | 289 | let items = scope |
264 | .items | 290 | .items |
265 | .iter() | 291 | .iter() |
266 | .map(|(name, res)| (name.clone(), Either::A(res.clone()))); | 292 | .map(|(name, res)| (name.clone(), res.clone())) |
267 | let macros = | 293 | .collect::<Vec<_>>(); |
268 | scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res))); | ||
269 | 294 | ||
270 | let all = items.chain(macros).collect::<Vec<_>>(); | 295 | self.update(module_id, Some(import_id), &items); |
271 | self.update(module_id, Some(import_id), &all); | ||
272 | } else { | 296 | } else { |
273 | // glob import from same crate => we do an initial | 297 | // glob import from same crate => we do an initial |
274 | // import, and then need to propagate any further | 298 | // import, and then need to propagate any further |
275 | // additions | 299 | // additions |
276 | let scope = &self.def_map[m.module_id].scope; | 300 | let scope = &self.def_map[m.module_id].scope; |
301 | |||
302 | // Module scoped macros is included | ||
277 | let items = scope | 303 | let items = scope |
278 | .items | 304 | .items |
279 | .iter() | 305 | .iter() |
280 | .map(|(name, res)| (name.clone(), Either::A(res.clone()))); | 306 | .map(|(name, res)| (name.clone(), res.clone())) |
281 | let macros = | 307 | .collect::<Vec<_>>(); |
282 | scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res))); | ||
283 | 308 | ||
284 | let all = items.chain(macros).collect::<Vec<_>>(); | 309 | self.update(module_id, Some(import_id), &items); |
285 | |||
286 | self.update(module_id, Some(import_id), &all); | ||
287 | // record the glob import in case we add further items | 310 | // record the glob import in case we add further items |
288 | self.glob_imports | 311 | self.glob_imports |
289 | .entry(m.module_id) | 312 | .entry(m.module_id) |
@@ -303,7 +326,7 @@ where | |||
303 | import: Some(import_id), | 326 | import: Some(import_id), |
304 | }; | 327 | }; |
305 | let name = variant.name(self.db)?; | 328 | let name = variant.name(self.db)?; |
306 | Some((name, Either::A(res))) | 329 | Some((name, res)) |
307 | }) | 330 | }) |
308 | .collect::<Vec<_>>(); | 331 | .collect::<Vec<_>>(); |
309 | self.update(module_id, Some(import_id), &resolutions); | 332 | self.update(module_id, Some(import_id), &resolutions); |
@@ -323,18 +346,12 @@ where | |||
323 | 346 | ||
324 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | 347 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 |
325 | if import.is_extern_crate && module_id == self.def_map.root { | 348 | if import.is_extern_crate && module_id == self.def_map.root { |
326 | if let Some(def) = def.a().and_then(|item| item.take_types()) { | 349 | if let Some(def) = def.take_types() { |
327 | self.def_map.extern_prelude.insert(name.clone(), def); | 350 | self.def_map.extern_prelude.insert(name.clone(), def); |
328 | } | 351 | } |
329 | } | 352 | } |
330 | 353 | ||
331 | let resolution = match def { | 354 | let resolution = Resolution { def, import: Some(import_id) }; |
332 | Either::A(item) => { | ||
333 | Either::A(Resolution { def: item, import: Some(import_id) }) | ||
334 | } | ||
335 | Either::B(macro_) => Either::B(macro_), | ||
336 | }; | ||
337 | |||
338 | self.update(module_id, Some(import_id), &[(name, resolution)]); | 355 | self.update(module_id, Some(import_id), &[(name, resolution)]); |
339 | } | 356 | } |
340 | None => tested_by!(bogus_paths), | 357 | None => tested_by!(bogus_paths), |
@@ -346,7 +363,7 @@ where | |||
346 | &mut self, | 363 | &mut self, |
347 | module_id: CrateModuleId, | 364 | module_id: CrateModuleId, |
348 | import: Option<raw::ImportId>, | 365 | import: Option<raw::ImportId>, |
349 | resolutions: &[(Name, Either<Resolution, MacroDef>)], | 366 | resolutions: &[(Name, Resolution)], |
350 | ) { | 367 | ) { |
351 | self.update_recursive(module_id, import, resolutions, 0) | 368 | self.update_recursive(module_id, import, resolutions, 0) |
352 | } | 369 | } |
@@ -355,7 +372,7 @@ where | |||
355 | &mut self, | 372 | &mut self, |
356 | module_id: CrateModuleId, | 373 | module_id: CrateModuleId, |
357 | import: Option<raw::ImportId>, | 374 | import: Option<raw::ImportId>, |
358 | resolutions: &[(Name, Either<Resolution, MacroDef>)], | 375 | resolutions: &[(Name, Resolution)], |
359 | depth: usize, | 376 | depth: usize, |
360 | ) { | 377 | ) { |
361 | if depth > 100 { | 378 | if depth > 100 { |
@@ -365,35 +382,30 @@ where | |||
365 | let module_items = &mut self.def_map.modules[module_id].scope; | 382 | let module_items = &mut self.def_map.modules[module_id].scope; |
366 | let mut changed = false; | 383 | let mut changed = false; |
367 | for (name, res) in resolutions { | 384 | for (name, res) in resolutions { |
368 | match res { | 385 | let existing = module_items.items.entry(name.clone()).or_default(); |
369 | // item | ||
370 | Either::A(res) => { | ||
371 | let existing = module_items.items.entry(name.clone()).or_default(); | ||
372 | |||
373 | if existing.def.types.is_none() && res.def.types.is_some() { | ||
374 | existing.def.types = res.def.types; | ||
375 | existing.import = import.or(res.import); | ||
376 | changed = true; | ||
377 | } | ||
378 | if existing.def.values.is_none() && res.def.values.is_some() { | ||
379 | existing.def.values = res.def.values; | ||
380 | existing.import = import.or(res.import); | ||
381 | changed = true; | ||
382 | } | ||
383 | 386 | ||
384 | if existing.def.is_none() | 387 | if existing.def.types.is_none() && res.def.types.is_some() { |
385 | && res.def.is_none() | 388 | existing.def.types = res.def.types; |
386 | && existing.import.is_none() | 389 | existing.import = import.or(res.import); |
387 | && res.import.is_some() | 390 | changed = true; |
388 | { | 391 | } |
389 | existing.import = res.import; | 392 | if existing.def.values.is_none() && res.def.values.is_some() { |
390 | } | 393 | existing.def.values = res.def.values; |
391 | } | 394 | existing.import = import.or(res.import); |
392 | // macro | 395 | changed = true; |
393 | Either::B(res) => { | 396 | } |
394 | // Always shadowing | 397 | if existing.def.macros.is_none() && res.def.macros.is_some() { |
395 | module_items.macros.insert(name.clone(), *res); | 398 | existing.def.macros = res.def.macros; |
396 | } | 399 | existing.import = import.or(res.import); |
400 | changed = true; | ||
401 | } | ||
402 | |||
403 | if existing.def.is_none() | ||
404 | && res.def.is_none() | ||
405 | && existing.import.is_none() | ||
406 | && res.import.is_some() | ||
407 | { | ||
408 | existing.import = res.import; | ||
397 | } | 409 | } |
398 | } | 410 | } |
399 | 411 | ||
@@ -425,7 +437,7 @@ where | |||
425 | path, | 437 | path, |
426 | ); | 438 | ); |
427 | 439 | ||
428 | if let Some(def) = resolved_res.resolved_def.b() { | 440 | if let Some(def) = resolved_res.resolved_def.get_macros() { |
429 | let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); | 441 | let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); |
430 | resolved.push((*module_id, call_id, def.id)); | 442 | resolved.push((*module_id, call_id, def.id)); |
431 | res = ReachedFixedPoint::No; | 443 | res = ReachedFixedPoint::No; |
@@ -528,7 +540,7 @@ where | |||
528 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 540 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
529 | if prelude_module.krate != self.def_collector.def_map.krate { | 541 | if prelude_module.krate != self.def_collector.def_map.krate { |
530 | tested_by!(prelude_is_macro_use); | 542 | tested_by!(prelude_is_macro_use); |
531 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module); | 543 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); |
532 | } | 544 | } |
533 | } | 545 | } |
534 | 546 | ||
@@ -636,7 +648,7 @@ where | |||
636 | ), | 648 | ), |
637 | import: None, | 649 | import: None, |
638 | }; | 650 | }; |
639 | self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]); | 651 | self.def_collector.update(self.module_id, None, &[(name, resolution)]); |
640 | res | 652 | res |
641 | } | 653 | } |
642 | 654 | ||
@@ -667,7 +679,7 @@ where | |||
667 | raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), | 679 | raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), |
668 | }; | 680 | }; |
669 | let resolution = Resolution { def, import: None }; | 681 | let resolution = Resolution { def, import: None }; |
670 | self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]) | 682 | self.def_collector.update(self.module_id, None, &[(name, resolution)]) |
671 | } | 683 | } |
672 | 684 | ||
673 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 685 | fn collect_macro(&mut self, mac: &raw::MacroData) { |
@@ -675,7 +687,8 @@ where | |||
675 | if is_macro_rules(&mac.path) { | 687 | if is_macro_rules(&mac.path) { |
676 | if let Some(name) = &mac.name { | 688 | if let Some(name) = &mac.name { |
677 | let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); | 689 | let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); |
678 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export) | 690 | let macro_ = MacroDef { id: macro_id }; |
691 | self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); | ||
679 | } | 692 | } |
680 | return; | 693 | return; |
681 | } | 694 | } |
@@ -706,7 +719,7 @@ where | |||
706 | fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { | 719 | fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { |
707 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); | 720 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); |
708 | for (name, macro_) in macros { | 721 | for (name, macro_) in macros { |
709 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_.id); | 722 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); |
710 | } | 723 | } |
711 | } | 724 | } |
712 | } | 725 | } |
@@ -758,7 +771,6 @@ mod tests { | |||
758 | root, | 771 | root, |
759 | modules, | 772 | modules, |
760 | poison_macros: FxHashSet::default(), | 773 | poison_macros: FxHashSet::default(), |
761 | exported_macros: FxHashMap::default(), | ||
762 | diagnostics: Vec::new(), | 774 | diagnostics: Vec::new(), |
763 | } | 775 | } |
764 | }; | 776 | }; |
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs index c40a3ff9d..6a50e05c1 100644 --- a/crates/ra_hir/src/nameres/per_ns.rs +++ b/crates/ra_hir/src/nameres/per_ns.rs | |||
@@ -1,78 +1,93 @@ | |||
1 | use crate::MacroDef; | ||
2 | |||
1 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 3 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
2 | pub enum Namespace { | 4 | pub enum Namespace { |
3 | Types, | 5 | Types, |
4 | Values, | 6 | Values, |
7 | Macro, | ||
5 | } | 8 | } |
6 | 9 | ||
7 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
8 | pub struct PerNs<T> { | 11 | pub struct PerNs<T> { |
9 | pub types: Option<T>, | 12 | pub types: Option<T>, |
10 | pub values: Option<T>, | 13 | pub values: Option<T>, |
14 | /// Since macros has different type, many methods simply ignore it. | ||
15 | /// We can only use special method like `get_macros` to access it. | ||
16 | pub macros: Option<MacroDef>, | ||
11 | } | 17 | } |
12 | 18 | ||
13 | impl<T> Default for PerNs<T> { | 19 | impl<T> Default for PerNs<T> { |
14 | fn default() -> Self { | 20 | fn default() -> Self { |
15 | PerNs { types: None, values: None } | 21 | PerNs { types: None, values: None, macros: None } |
16 | } | 22 | } |
17 | } | 23 | } |
18 | 24 | ||
19 | impl<T> PerNs<T> { | 25 | impl<T> PerNs<T> { |
20 | pub fn none() -> PerNs<T> { | 26 | pub fn none() -> PerNs<T> { |
21 | PerNs { types: None, values: None } | 27 | PerNs { types: None, values: None, macros: None } |
22 | } | 28 | } |
23 | 29 | ||
24 | pub fn values(t: T) -> PerNs<T> { | 30 | pub fn values(t: T) -> PerNs<T> { |
25 | PerNs { types: None, values: Some(t) } | 31 | PerNs { types: None, values: Some(t), macros: None } |
26 | } | 32 | } |
27 | 33 | ||
28 | pub fn types(t: T) -> PerNs<T> { | 34 | pub fn types(t: T) -> PerNs<T> { |
29 | PerNs { types: Some(t), values: None } | 35 | PerNs { types: Some(t), values: None, macros: None } |
30 | } | 36 | } |
31 | 37 | ||
32 | pub fn both(types: T, values: T) -> PerNs<T> { | 38 | pub fn both(types: T, values: T) -> PerNs<T> { |
33 | PerNs { types: Some(types), values: Some(values) } | 39 | PerNs { types: Some(types), values: Some(values), macros: None } |
34 | } | 40 | } |
35 | 41 | ||
36 | pub fn is_none(&self) -> bool { | 42 | pub fn macros(macro_: MacroDef) -> PerNs<T> { |
37 | self.types.is_none() && self.values.is_none() | 43 | PerNs { types: None, values: None, macros: Some(macro_) } |
38 | } | 44 | } |
39 | 45 | ||
40 | pub fn is_both(&self) -> bool { | 46 | pub fn is_none(&self) -> bool { |
41 | self.types.is_some() && self.values.is_some() | 47 | self.types.is_none() && self.values.is_none() && self.macros.is_none() |
42 | } | 48 | } |
43 | 49 | ||
44 | pub fn take(self, namespace: Namespace) -> Option<T> { | 50 | pub fn is_all(&self) -> bool { |
45 | match namespace { | 51 | self.types.is_some() && self.values.is_some() && self.macros.is_some() |
46 | Namespace::Types => self.types, | ||
47 | Namespace::Values => self.values, | ||
48 | } | ||
49 | } | 52 | } |
50 | 53 | ||
51 | pub fn take_types(self) -> Option<T> { | 54 | pub fn take_types(self) -> Option<T> { |
52 | self.take(Namespace::Types) | 55 | self.types |
53 | } | 56 | } |
54 | 57 | ||
55 | pub fn take_values(self) -> Option<T> { | 58 | pub fn take_values(self) -> Option<T> { |
56 | self.take(Namespace::Values) | 59 | self.values |
57 | } | 60 | } |
58 | 61 | ||
59 | pub fn get(&self, namespace: Namespace) -> Option<&T> { | 62 | pub fn get_macros(&self) -> Option<MacroDef> { |
60 | self.as_ref().take(namespace) | 63 | self.macros |
64 | } | ||
65 | |||
66 | pub fn only_macros(&self) -> PerNs<T> { | ||
67 | PerNs { types: None, values: None, macros: self.macros } | ||
61 | } | 68 | } |
62 | 69 | ||
63 | pub fn as_ref(&self) -> PerNs<&T> { | 70 | pub fn as_ref(&self) -> PerNs<&T> { |
64 | PerNs { types: self.types.as_ref(), values: self.values.as_ref() } | 71 | PerNs { types: self.types.as_ref(), values: self.values.as_ref(), macros: self.macros } |
65 | } | 72 | } |
66 | 73 | ||
67 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { | 74 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { |
68 | PerNs { types: self.types.or(other.types), values: self.values.or(other.values) } | 75 | PerNs { |
76 | types: self.types.or(other.types), | ||
77 | values: self.values.or(other.values), | ||
78 | macros: self.macros.or(other.macros), | ||
79 | } | ||
69 | } | 80 | } |
70 | 81 | ||
71 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { | 82 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { |
72 | PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) } | 83 | PerNs { |
84 | types: self.types.and_then(&f), | ||
85 | values: self.values.and_then(&f), | ||
86 | macros: self.macros, | ||
87 | } | ||
73 | } | 88 | } |
74 | 89 | ||
75 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { | 90 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { |
76 | PerNs { types: self.types.map(&f), values: self.values.map(&f) } | 91 | PerNs { types: self.types.map(&f), values: self.values.map(&f), macros: self.macros } |
77 | } | 92 | } |
78 | } | 93 | } |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 4ff897ca5..bc4b47b70 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -12,8 +12,7 @@ use test_utils::covers; | |||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | mock::{CrateGraphFixture, MockDatabase}, | 14 | mock::{CrateGraphFixture, MockDatabase}, |
15 | nameres::Resolution, | 15 | Crate, |
16 | Crate, Either, | ||
17 | }; | 16 | }; |
18 | 17 | ||
19 | use super::*; | 18 | use super::*; |
@@ -37,35 +36,38 @@ fn render_crate_def_map(map: &CrateDefMap) -> String { | |||
37 | *buf += path; | 36 | *buf += path; |
38 | *buf += "\n"; | 37 | *buf += "\n"; |
39 | 38 | ||
40 | let items = map.modules[module].scope.items.iter().map(|(name, it)| (name, Either::A(it))); | 39 | let mut entries = map.modules[module] |
41 | let macros = map.modules[module].scope.macros.iter().map(|(name, m)| (name, Either::B(m))); | 40 | .scope |
42 | let mut entries = items.chain(macros).collect::<Vec<_>>(); | 41 | .items |
43 | 42 | .iter() | |
43 | .map(|(name, res)| (name, res.def)) | ||
44 | .collect::<Vec<_>>(); | ||
44 | entries.sort_by_key(|(name, _)| *name); | 45 | entries.sort_by_key(|(name, _)| *name); |
46 | |||
45 | for (name, res) in entries { | 47 | for (name, res) in entries { |
46 | match res { | 48 | *buf += &format!("{}:", name); |
47 | Either::A(it) => { | 49 | |
48 | *buf += &format!("{}: {}\n", name, dump_resolution(it)); | 50 | if res.types.is_some() { |
49 | } | 51 | *buf += " t"; |
50 | Either::B(_) => { | 52 | } |
51 | *buf += &format!("{}: m\n", name); | 53 | if res.values.is_some() { |
52 | } | 54 | *buf += " v"; |
55 | } | ||
56 | if res.macros.is_some() { | ||
57 | *buf += " m"; | ||
58 | } | ||
59 | if res.is_none() { | ||
60 | *buf += " _"; | ||
53 | } | 61 | } |
62 | |||
63 | *buf += "\n"; | ||
54 | } | 64 | } |
65 | |||
55 | for (name, child) in map.modules[module].children.iter() { | 66 | for (name, child) in map.modules[module].children.iter() { |
56 | let path = path.to_string() + &format!("::{}", name); | 67 | let path = path.to_string() + &format!("::{}", name); |
57 | go(buf, map, &path, *child); | 68 | go(buf, map, &path, *child); |
58 | } | 69 | } |
59 | } | 70 | } |
60 | |||
61 | fn dump_resolution(resolution: &Resolution) -> &'static str { | ||
62 | match (resolution.def.types.is_some(), resolution.def.values.is_some()) { | ||
63 | (true, true) => "t v", | ||
64 | (true, false) => "t", | ||
65 | (false, true) => "v", | ||
66 | (false, false) => "_", | ||
67 | } | ||
68 | } | ||
69 | } | 71 | } |
70 | 72 | ||
71 | fn def_map(fixtute: &str) -> String { | 73 | fn def_map(fixtute: &str) -> String { |
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index ebc4d6890..20ee63c67 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -21,7 +21,6 @@ fn macro_rules_are_globally_visible() { | |||
21 | ⋮crate | 21 | ⋮crate |
22 | ⋮Foo: t v | 22 | ⋮Foo: t v |
23 | ⋮nested: t | 23 | ⋮nested: t |
24 | ⋮structs: m | ||
25 | ⋮ | 24 | ⋮ |
26 | ⋮crate::nested | 25 | ⋮crate::nested |
27 | ⋮Bar: t v | 26 | ⋮Bar: t v |
@@ -47,7 +46,6 @@ fn macro_rules_can_define_modules() { | |||
47 | ); | 46 | ); |
48 | assert_snapshot!(map, @r###" | 47 | assert_snapshot!(map, @r###" |
49 | ⋮crate | 48 | ⋮crate |
50 | ⋮m: m | ||
51 | ⋮n1: t | 49 | ⋮n1: t |
52 | ⋮ | 50 | ⋮ |
53 | ⋮crate::n1 | 51 | ⋮crate::n1 |
@@ -133,7 +131,6 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
133 | ⋮crate | 131 | ⋮crate |
134 | ⋮Foo: t v | 132 | ⋮Foo: t v |
135 | ⋮bar: m | 133 | ⋮bar: m |
136 | ⋮baz: m | ||
137 | ⋮foo: m | 134 | ⋮foo: m |
138 | "###); | 135 | "###); |
139 | } | 136 | } |
@@ -271,7 +268,6 @@ fn prelude_cycle() { | |||
271 | ⋮prelude: t | 268 | ⋮prelude: t |
272 | ⋮ | 269 | ⋮ |
273 | ⋮crate::prelude | 270 | ⋮crate::prelude |
274 | ⋮declare_mod: m | ||
275 | "###); | 271 | "###); |
276 | } | 272 | } |
277 | 273 | ||
@@ -345,7 +341,6 @@ fn plain_macros_are_legacy_textual_scoped() { | |||
345 | ⋮Ok: t v | 341 | ⋮Ok: t v |
346 | ⋮OkAfter: t v | 342 | ⋮OkAfter: t v |
347 | ⋮OkShadowStop: t v | 343 | ⋮OkShadowStop: t v |
348 | ⋮foo: m | ||
349 | ⋮m1: t | 344 | ⋮m1: t |
350 | ⋮m2: t | 345 | ⋮m2: t |
351 | ⋮m3: t | 346 | ⋮m3: t |
@@ -354,28 +349,132 @@ fn plain_macros_are_legacy_textual_scoped() { | |||
354 | ⋮ok_double_macro_use_shadow: v | 349 | ⋮ok_double_macro_use_shadow: v |
355 | ⋮ | 350 | ⋮ |
356 | ⋮crate::m7 | 351 | ⋮crate::m7 |
357 | ⋮baz: m | ||
358 | ⋮ | 352 | ⋮ |
359 | ⋮crate::m1 | 353 | ⋮crate::m1 |
360 | ⋮bar: m | ||
361 | ⋮ | 354 | ⋮ |
362 | ⋮crate::m5 | 355 | ⋮crate::m5 |
363 | ⋮m6: t | 356 | ⋮m6: t |
364 | ⋮ | 357 | ⋮ |
365 | ⋮crate::m5::m6 | 358 | ⋮crate::m5::m6 |
366 | ⋮foo: m | ||
367 | ⋮ | 359 | ⋮ |
368 | ⋮crate::m2 | 360 | ⋮crate::m2 |
369 | ⋮ | 361 | ⋮ |
370 | ⋮crate::m3 | 362 | ⋮crate::m3 |
371 | ⋮OkAfterInside: t v | 363 | ⋮OkAfterInside: t v |
372 | ⋮OkMacroUse: t v | 364 | ⋮OkMacroUse: t v |
373 | ⋮foo: m | ||
374 | ⋮m4: t | 365 | ⋮m4: t |
375 | ⋮ok_shadow: v | 366 | ⋮ok_shadow: v |
376 | ⋮ | 367 | ⋮ |
377 | ⋮crate::m3::m4 | 368 | ⋮crate::m3::m4 |
378 | ⋮bar: m | ||
379 | ⋮ok_shadow_deep: v | 369 | ⋮ok_shadow_deep: v |
380 | "###); | 370 | "###); |
381 | } | 371 | } |
372 | |||
373 | #[test] | ||
374 | fn type_value_macro_live_in_different_scopes() { | ||
375 | let map = def_map( | ||
376 | " | ||
377 | //- /main.rs | ||
378 | #[macro_export] | ||
379 | macro_rules! foo { | ||
380 | ($x:ident) => { type $x = (); } | ||
381 | } | ||
382 | |||
383 | foo!(foo); | ||
384 | use foo as bar; | ||
385 | |||
386 | use self::foo as baz; | ||
387 | fn baz() {} | ||
388 | ", | ||
389 | ); | ||
390 | assert_snapshot!(map, @r###" | ||
391 | ⋮crate | ||
392 | ⋮bar: t m | ||
393 | ⋮baz: t v m | ||
394 | ⋮foo: t m | ||
395 | "###); | ||
396 | } | ||
397 | |||
398 | #[test] | ||
399 | fn macro_use_can_be_aliased() { | ||
400 | let map = def_map_with_crate_graph( | ||
401 | " | ||
402 | //- /main.rs | ||
403 | #[macro_use] | ||
404 | extern crate foo; | ||
405 | |||
406 | foo!(Direct); | ||
407 | bar!(Alias); | ||
408 | |||
409 | //- /lib.rs | ||
410 | use crate::foo as bar; | ||
411 | |||
412 | mod m { | ||
413 | #[macro_export] | ||
414 | macro_rules! foo { | ||
415 | ($x:ident) => { struct $x; } | ||
416 | } | ||
417 | } | ||
418 | ", | ||
419 | crate_graph! { | ||
420 | "main": ("/main.rs", ["foo"]), | ||
421 | "foo": ("/lib.rs", []), | ||
422 | }, | ||
423 | ); | ||
424 | assert_snapshot!(map, @r###" | ||
425 | ⋮crate | ||
426 | ⋮Alias: t v | ||
427 | ⋮Direct: t v | ||
428 | ⋮foo: t | ||
429 | "###); | ||
430 | } | ||
431 | |||
432 | #[test] | ||
433 | fn path_quantified_macros() { | ||
434 | let map = def_map( | ||
435 | " | ||
436 | //- /main.rs | ||
437 | macro_rules! foo { | ||
438 | ($x:ident) => { struct $x; } | ||
439 | } | ||
440 | |||
441 | crate::foo!(NotResolved); | ||
442 | |||
443 | crate::bar!(OkCrate); | ||
444 | bar!(OkPlain); | ||
445 | alias1!(NotHere); | ||
446 | m::alias1!(OkAliasPlain); | ||
447 | m::alias2!(OkAliasSuper); | ||
448 | m::alias3!(OkAliasCrate); | ||
449 | not_found!(NotFound); | ||
450 | |||
451 | mod m { | ||
452 | #[macro_export] | ||
453 | macro_rules! bar { | ||
454 | ($x:ident) => { struct $x; } | ||
455 | } | ||
456 | |||
457 | pub use bar as alias1; | ||
458 | pub use super::bar as alias2; | ||
459 | pub use crate::bar as alias3; | ||
460 | pub use self::bar as not_found; | ||
461 | } | ||
462 | ", | ||
463 | ); | ||
464 | assert_snapshot!(map, @r###" | ||
465 | ⋮crate | ||
466 | ⋮OkAliasCrate: t v | ||
467 | ⋮OkAliasPlain: t v | ||
468 | ⋮OkAliasSuper: t v | ||
469 | ⋮OkCrate: t v | ||
470 | ⋮OkPlain: t v | ||
471 | ⋮bar: m | ||
472 | ⋮m: t | ||
473 | ⋮ | ||
474 | ⋮crate::m | ||
475 | ⋮alias1: m | ||
476 | ⋮alias2: m | ||
477 | ⋮alias3: m | ||
478 | ⋮not_found: _ | ||
479 | "###); | ||
480 | } | ||
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index ef75308f6..d9bdd0e22 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -6,7 +6,6 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | code_model::Crate, | 7 | code_model::Crate, |
8 | db::HirDatabase, | 8 | db::HirDatabase, |
9 | either::Either, | ||
10 | expr::{ | 9 | expr::{ |
11 | scope::{ExprScopes, ScopeId}, | 10 | scope::{ExprScopes, ScopeId}, |
12 | PatId, | 11 | PatId, |
@@ -126,7 +125,7 @@ impl Resolver { | |||
126 | let mut resolution = PerNs::none(); | 125 | let mut resolution = PerNs::none(); |
127 | for scope in self.scopes.iter().rev() { | 126 | for scope in self.scopes.iter().rev() { |
128 | resolution = resolution.or(scope.resolve_name(db, name)); | 127 | resolution = resolution.or(scope.resolve_name(db, name)); |
129 | if resolution.is_both() { | 128 | if resolution.is_all() { |
130 | return resolution; | 129 | return resolution; |
131 | } | 130 | } |
132 | } | 131 | } |
@@ -139,10 +138,7 @@ impl Resolver { | |||
139 | path: &Path, | 138 | path: &Path, |
140 | ) -> Option<MacroDef> { | 139 | ) -> Option<MacroDef> { |
141 | let (item_map, module) = self.module()?; | 140 | let (item_map, module) = self.module()?; |
142 | match item_map.resolve_path_with_macro(db, module, path) { | 141 | item_map.resolve_path(db, module, path).0.get_macros() |
143 | (Either::B(macro_def), None) => Some(macro_def), | ||
144 | _ => None, | ||
145 | } | ||
146 | } | 142 | } |
147 | 143 | ||
148 | /// Returns the resolved path segments | 144 | /// Returns the resolved path segments |
@@ -191,6 +187,9 @@ impl Resolver { | |||
191 | if current.values.is_none() { | 187 | if current.values.is_none() { |
192 | current.values = res.values; | 188 | current.values = res.values; |
193 | } | 189 | } |
190 | if current.macros.is_none() { | ||
191 | current.macros = res.macros; | ||
192 | } | ||
194 | }); | 193 | }); |
195 | } | 194 | } |
196 | names | 195 | names |
@@ -313,6 +312,9 @@ impl Scope { | |||
313 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { | 312 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { |
314 | f(name.clone(), res.def.map(Resolution::Def)); | 313 | f(name.clone(), res.def.map(Resolution::Def)); |
315 | }); | 314 | }); |
315 | m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { | ||
316 | f(name.clone(), PerNs::macros(macro_)); | ||
317 | }); | ||
316 | m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { | 318 | m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { |
317 | f(name.clone(), PerNs::types(Resolution::Def(*def))); | 319 | f(name.clone(), PerNs::types(Resolution::Def(*def))); |
318 | }); | 320 | }); |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 061229842..a2adbc4b8 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -429,6 +429,9 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace | |||
429 | (TypableDef::Const(_), Namespace::Types) => Ty::Unknown, | 429 | (TypableDef::Const(_), Namespace::Types) => Ty::Unknown, |
430 | (TypableDef::Static(_), Namespace::Types) => Ty::Unknown, | 430 | (TypableDef::Static(_), Namespace::Types) => Ty::Unknown, |
431 | (TypableDef::BuiltinType(_), Namespace::Values) => Ty::Unknown, | 431 | (TypableDef::BuiltinType(_), Namespace::Values) => Ty::Unknown, |
432 | |||
433 | // Macro is not typeable | ||
434 | (_, Namespace::Macro) => Ty::Unknown, | ||
432 | } | 435 | } |
433 | } | 436 | } |
434 | 437 | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 25716fe8c..38fe62279 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2838,6 +2838,64 @@ fn main() { | |||
2838 | ); | 2838 | ); |
2839 | } | 2839 | } |
2840 | 2840 | ||
2841 | #[test] | ||
2842 | fn infer_path_quantified_macros_expanded() { | ||
2843 | assert_snapshot!( | ||
2844 | infer(r#" | ||
2845 | #[macro_export] | ||
2846 | macro_rules! foo { | ||
2847 | () => { 42i32 } | ||
2848 | } | ||
2849 | |||
2850 | mod m { | ||
2851 | pub use super::foo as bar; | ||
2852 | } | ||
2853 | |||
2854 | fn main() { | ||
2855 | let x = crate::foo!(); | ||
2856 | let y = m::bar!(); | ||
2857 | } | ||
2858 | "#), | ||
2859 | @r###" | ||
2860 | ![0; 5) '42i32': i32 | ||
2861 | ![0; 5) '42i32': i32 | ||
2862 | [111; 164) '{ ...!(); }': () | ||
2863 | [121; 122) 'x': i32 | ||
2864 | [148; 149) 'y': i32 | ||
2865 | "### | ||
2866 | ); | ||
2867 | } | ||
2868 | |||
2869 | #[test] | ||
2870 | fn infer_type_value_macro_having_same_name() { | ||
2871 | assert_snapshot!( | ||
2872 | infer(r#" | ||
2873 | #[macro_export] | ||
2874 | macro_rules! foo { | ||
2875 | () => { | ||
2876 | mod foo { | ||
2877 | pub use super::foo; | ||
2878 | } | ||
2879 | }; | ||
2880 | ($x:tt) => { | ||
2881 | $x | ||
2882 | }; | ||
2883 | } | ||
2884 | |||
2885 | foo!(); | ||
2886 | |||
2887 | fn foo() { | ||
2888 | let foo = foo::foo!(42i32); | ||
2889 | } | ||
2890 | "#), | ||
2891 | @r###" | ||
2892 | ![0; 5) '42i32': i32 | ||
2893 | [171; 206) '{ ...32); }': () | ||
2894 | [181; 184) 'foo': i32 | ||
2895 | "### | ||
2896 | ); | ||
2897 | } | ||
2898 | |||
2841 | #[ignore] | 2899 | #[ignore] |
2842 | #[test] | 2900 | #[test] |
2843 | fn method_resolution_trait_before_autoref() { | 2901 | fn method_resolution_trait_before_autoref() { |