diff options
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 115 |
1 files changed, 81 insertions, 34 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 0290b3474..9b9212bfc 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -56,6 +56,7 @@ mod tests; | |||
56 | use std::sync::Arc; | 56 | use std::sync::Arc; |
57 | 57 | ||
58 | use rustc_hash::{FxHashMap, FxHashSet}; | 58 | use rustc_hash::{FxHashMap, FxHashSet}; |
59 | use either::Either; | ||
59 | use ra_arena::{Arena, RawId, impl_arena_id}; | 60 | use ra_arena::{Arena, RawId, impl_arena_id}; |
60 | use ra_db::{FileId, Edition}; | 61 | use ra_db::{FileId, Edition}; |
61 | use test_utils::tested_by; | 62 | use test_utils::tested_by; |
@@ -63,7 +64,7 @@ use ra_syntax::ast; | |||
63 | use ra_prof::profile; | 64 | use ra_prof::profile; |
64 | 65 | ||
65 | use crate::{ | 66 | use crate::{ |
66 | ModuleDef, Name, Crate, Module, | 67 | ModuleDef, Name, Crate, Module, MacroDef, |
67 | DefDatabase, Path, PathKind, HirFileId, Trait, | 68 | DefDatabase, Path, PathKind, HirFileId, Trait, |
68 | ids::MacroDefId, | 69 | ids::MacroDefId, |
69 | diagnostics::DiagnosticSink, | 70 | diagnostics::DiagnosticSink, |
@@ -136,6 +137,7 @@ pub(crate) struct ModuleData { | |||
136 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 137 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
137 | pub struct ModuleScope { | 138 | pub struct ModuleScope { |
138 | items: FxHashMap<Name, Resolution>, | 139 | items: FxHashMap<Name, Resolution>, |
140 | macros: FxHashMap<Name, MacroDef>, | ||
139 | } | 141 | } |
140 | 142 | ||
141 | impl ModuleScope { | 143 | impl ModuleScope { |
@@ -151,8 +153,17 @@ impl ModuleScope { | |||
151 | _ => None, | 153 | _ => None, |
152 | }) | 154 | }) |
153 | } | 155 | } |
156 | fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> { | ||
157 | match (self.items.get(name), self.macros.get(name)) { | ||
158 | (Some(item), _) if !item.def.is_none() => Some(Either::Left(item.def)), | ||
159 | (_, Some(macro_)) => Some(Either::Right(*macro_)), | ||
160 | _ => None, | ||
161 | } | ||
162 | } | ||
154 | } | 163 | } |
155 | 164 | ||
165 | type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>; | ||
166 | |||
156 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 167 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
157 | pub struct Resolution { | 168 | pub struct Resolution { |
158 | /// None for unresolved | 169 | /// None for unresolved |
@@ -163,18 +174,18 @@ pub struct Resolution { | |||
163 | 174 | ||
164 | #[derive(Debug, Clone)] | 175 | #[derive(Debug, Clone)] |
165 | struct ResolvePathResult { | 176 | struct ResolvePathResult { |
166 | resolved_def: PerNs<ModuleDef>, | 177 | resolved_def: ItemOrMacro, |
167 | segment_index: Option<usize>, | 178 | segment_index: Option<usize>, |
168 | reached_fixedpoint: ReachedFixedPoint, | 179 | reached_fixedpoint: ReachedFixedPoint, |
169 | } | 180 | } |
170 | 181 | ||
171 | impl ResolvePathResult { | 182 | impl ResolvePathResult { |
172 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | 183 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { |
173 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) | 184 | ResolvePathResult::with(Either::Left(PerNs::none()), reached_fixedpoint, None) |
174 | } | 185 | } |
175 | 186 | ||
176 | fn with( | 187 | fn with( |
177 | resolved_def: PerNs<ModuleDef>, | 188 | resolved_def: ItemOrMacro, |
178 | reached_fixedpoint: ReachedFixedPoint, | 189 | reached_fixedpoint: ReachedFixedPoint, |
179 | segment_index: Option<usize>, | 190 | segment_index: Option<usize>, |
180 | ) -> ResolvePathResult { | 191 | ) -> ResolvePathResult { |
@@ -194,6 +205,21 @@ enum ReachedFixedPoint { | |||
194 | No, | 205 | No, |
195 | } | 206 | } |
196 | 207 | ||
208 | /// helper function for select item or macro to use | ||
209 | fn or(left: ItemOrMacro, right: ItemOrMacro) -> ItemOrMacro { | ||
210 | match (left, right) { | ||
211 | (Either::Left(s), Either::Left(o)) => Either::Left(s.or(o)), | ||
212 | (Either::Right(s), _) => Either::Right(s), | ||
213 | (Either::Left(s), Either::Right(o)) => { | ||
214 | if !s.is_none() { | ||
215 | Either::Left(s) | ||
216 | } else { | ||
217 | Either::Right(o) | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
197 | impl CrateDefMap { | 223 | impl CrateDefMap { |
198 | pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> { | 224 | pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> { |
199 | let _p = profile("crate_def_map_query"); | 225 | let _p = profile("crate_def_map_query"); |
@@ -268,7 +294,17 @@ impl CrateDefMap { | |||
268 | original_module: CrateModuleId, | 294 | original_module: CrateModuleId, |
269 | path: &Path, | 295 | path: &Path, |
270 | ) -> (PerNs<ModuleDef>, Option<usize>) { | 296 | ) -> (PerNs<ModuleDef>, Option<usize>) { |
271 | let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path); | 297 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); |
298 | (res.resolved_def.left().unwrap_or_else(PerNs::none), res.segment_index) | ||
299 | } | ||
300 | |||
301 | fn resolve_path_with_macro( | ||
302 | &self, | ||
303 | db: &impl DefDatabase, | ||
304 | original_module: CrateModuleId, | ||
305 | path: &Path, | ||
306 | ) -> (ItemOrMacro, Option<usize>) { | ||
307 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); | ||
272 | (res.resolved_def, res.segment_index) | 308 | (res.resolved_def, res.segment_index) |
273 | } | 309 | } |
274 | 310 | ||
@@ -278,7 +314,7 @@ impl CrateDefMap { | |||
278 | 314 | ||
279 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | 315 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change |
280 | // the result. | 316 | // the result. |
281 | fn resolve_path_fp( | 317 | fn resolve_path_fp_with_macro( |
282 | &self, | 318 | &self, |
283 | db: &impl DefDatabase, | 319 | db: &impl DefDatabase, |
284 | mode: ResolveMode, | 320 | mode: ResolveMode, |
@@ -286,13 +322,13 @@ impl CrateDefMap { | |||
286 | path: &Path, | 322 | path: &Path, |
287 | ) -> ResolvePathResult { | 323 | ) -> ResolvePathResult { |
288 | let mut segments = path.segments.iter().enumerate(); | 324 | let mut segments = path.segments.iter().enumerate(); |
289 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { | 325 | let mut curr_per_ns: ItemOrMacro = match path.kind { |
290 | PathKind::Crate => { | 326 | PathKind::Crate => Either::Left(PerNs::types( |
291 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) | 327 | Module { krate: self.krate, module_id: self.root }.into(), |
292 | } | 328 | )), |
293 | PathKind::Self_ => { | 329 | PathKind::Self_ => Either::Left(PerNs::types( |
294 | PerNs::types(Module { krate: self.krate, module_id: original_module }.into()) | 330 | Module { krate: self.krate, module_id: original_module }.into(), |
295 | } | 331 | )), |
296 | // plain import or absolute path in 2015: crate-relative with | 332 | // plain import or absolute path in 2015: crate-relative with |
297 | // fallback to extern prelude (with the simplification in | 333 | // fallback to extern prelude (with the simplification in |
298 | // rust-lang/rust#57745) | 334 | // rust-lang/rust#57745) |
@@ -314,11 +350,11 @@ impl CrateDefMap { | |||
314 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 350 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
315 | }; | 351 | }; |
316 | log::debug!("resolving {:?} in module", segment); | 352 | log::debug!("resolving {:?} in module", segment); |
317 | self.resolve_name_in_module(db, original_module, &segment.name) | 353 | self.resolve_name_in_module_with_macro(db, original_module, &segment.name) |
318 | } | 354 | } |
319 | PathKind::Super => { | 355 | PathKind::Super => { |
320 | if let Some(p) = self.modules[original_module].parent { | 356 | if let Some(p) = self.modules[original_module].parent { |
321 | PerNs::types(Module { krate: self.krate, module_id: p }.into()) | 357 | Either::Left(PerNs::types(Module { krate: self.krate, module_id: p }.into())) |
322 | } else { | 358 | } else { |
323 | log::debug!("super path in root module"); | 359 | log::debug!("super path in root module"); |
324 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 360 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); |
@@ -332,7 +368,7 @@ impl CrateDefMap { | |||
332 | }; | 368 | }; |
333 | if let Some(def) = self.extern_prelude.get(&segment.name) { | 369 | if let Some(def) = self.extern_prelude.get(&segment.name) { |
334 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | 370 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); |
335 | PerNs::types(*def) | 371 | Either::Left(PerNs::types(*def)) |
336 | } else { | 372 | } else { |
337 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | 373 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude |
338 | } | 374 | } |
@@ -340,7 +376,7 @@ impl CrateDefMap { | |||
340 | }; | 376 | }; |
341 | 377 | ||
342 | for (i, segment) in segments { | 378 | for (i, segment) in segments { |
343 | let curr = match curr_per_ns.as_ref().take_types() { | 379 | let curr = match curr_per_ns.as_ref().left().map_or(None, |m| m.as_ref().take_types()) { |
344 | Some(r) => r, | 380 | Some(r) => r, |
345 | None => { | 381 | None => { |
346 | // we still have path segments left, but the path so far | 382 | // we still have path segments left, but the path so far |
@@ -362,7 +398,8 @@ impl CrateDefMap { | |||
362 | }; | 398 | }; |
363 | log::debug!("resolving {:?} in other crate", path); | 399 | log::debug!("resolving {:?} in other crate", path); |
364 | let defp_map = db.crate_def_map(module.krate); | 400 | let defp_map = db.crate_def_map(module.krate); |
365 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); | 401 | let (def, s) = |
402 | defp_map.resolve_path_with_macro(db, module.module_id, &path); | ||
366 | return ResolvePathResult::with( | 403 | return ResolvePathResult::with( |
367 | def, | 404 | def, |
368 | ReachedFixedPoint::Yes, | 405 | ReachedFixedPoint::Yes, |
@@ -370,8 +407,8 @@ impl CrateDefMap { | |||
370 | ); | 407 | ); |
371 | } | 408 | } |
372 | 409 | ||
373 | match self[module.module_id].scope.items.get(&segment.name) { | 410 | match self[module.module_id].scope.get_item_or_macro(&segment.name) { |
374 | Some(res) if !res.def.is_none() => res.def, | 411 | Some(res) => res, |
375 | _ => { | 412 | _ => { |
376 | log::debug!("path segment {:?} not found", segment.name); | 413 | log::debug!("path segment {:?} not found", segment.name); |
377 | return ResolvePathResult::empty(ReachedFixedPoint::No); | 414 | return ResolvePathResult::empty(ReachedFixedPoint::No); |
@@ -382,10 +419,10 @@ impl CrateDefMap { | |||
382 | // enum variant | 419 | // enum variant |
383 | tested_by!(can_import_enum_variant); | 420 | tested_by!(can_import_enum_variant); |
384 | match e.variant(db, &segment.name) { | 421 | match e.variant(db, &segment.name) { |
385 | Some(variant) => PerNs::both(variant.into(), variant.into()), | 422 | Some(variant) => Either::Left(PerNs::both(variant.into(), variant.into())), |
386 | None => { | 423 | None => { |
387 | return ResolvePathResult::with( | 424 | return ResolvePathResult::with( |
388 | PerNs::types((*e).into()), | 425 | Either::Left(PerNs::types((*e).into())), |
389 | ReachedFixedPoint::Yes, | 426 | ReachedFixedPoint::Yes, |
390 | Some(i), | 427 | Some(i), |
391 | ); | 428 | ); |
@@ -402,7 +439,7 @@ impl CrateDefMap { | |||
402 | ); | 439 | ); |
403 | 440 | ||
404 | return ResolvePathResult::with( | 441 | return ResolvePathResult::with( |
405 | PerNs::types((*s).into()), | 442 | Either::Left(PerNs::types((*s).into())), |
406 | ReachedFixedPoint::Yes, | 443 | ReachedFixedPoint::Yes, |
407 | Some(i), | 444 | Some(i), |
408 | ); | 445 | ); |
@@ -412,12 +449,12 @@ impl CrateDefMap { | |||
412 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | 449 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) |
413 | } | 450 | } |
414 | 451 | ||
415 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | 452 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> ItemOrMacro { |
416 | let from_crate_root = | 453 | let from_crate_root = |
417 | self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def); | 454 | self[self.root].scope.get_item_or_macro(name).unwrap_or(Either::Left(PerNs::none())); |
418 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | 455 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
419 | 456 | ||
420 | from_crate_root.or(from_extern_prelude) | 457 | or(from_crate_root, Either::Left(from_extern_prelude)) |
421 | } | 458 | } |
422 | 459 | ||
423 | pub(crate) fn resolve_name_in_module( | 460 | pub(crate) fn resolve_name_in_module( |
@@ -426,32 +463,42 @@ impl CrateDefMap { | |||
426 | module: CrateModuleId, | 463 | module: CrateModuleId, |
427 | name: &Name, | 464 | name: &Name, |
428 | ) -> PerNs<ModuleDef> { | 465 | ) -> PerNs<ModuleDef> { |
466 | self.resolve_name_in_module_with_macro(db, module, name).left().unwrap_or_else(PerNs::none) | ||
467 | } | ||
468 | |||
469 | fn resolve_name_in_module_with_macro( | ||
470 | &self, | ||
471 | db: &impl DefDatabase, | ||
472 | module: CrateModuleId, | ||
473 | name: &Name, | ||
474 | ) -> ItemOrMacro { | ||
429 | // Resolve in: | 475 | // Resolve in: |
430 | // - current module / scope | 476 | // - current module / scope |
431 | // - extern prelude | 477 | // - extern prelude |
432 | // - std prelude | 478 | // - std prelude |
433 | let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def); | 479 | let from_scope = |
480 | self[module].scope.get_item_or_macro(name).unwrap_or(Either::Left(PerNs::none()));; | ||
434 | let from_extern_prelude = | 481 | let from_extern_prelude = |
435 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | 482 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); |
436 | let from_prelude = self.resolve_in_prelude(db, name); | 483 | let from_prelude = self.resolve_in_prelude(db, name); |
437 | 484 | ||
438 | from_scope.or(from_extern_prelude).or(from_prelude) | 485 | or(from_scope, or(Either::Left(from_extern_prelude), from_prelude)) |
439 | } | 486 | } |
440 | 487 | ||
441 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | 488 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { |
442 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) | 489 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) |
443 | } | 490 | } |
444 | 491 | ||
445 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs<ModuleDef> { | 492 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> ItemOrMacro { |
446 | if let Some(prelude) = self.prelude { | 493 | if let Some(prelude) = self.prelude { |
447 | let resolution = if prelude.krate == self.krate { | 494 | let resolution = if prelude.krate == self.krate { |
448 | self[prelude.module_id].scope.items.get(name).cloned() | 495 | self[prelude.module_id].scope.get_item_or_macro(name) |
449 | } else { | 496 | } else { |
450 | db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned() | 497 | db.crate_def_map(prelude.krate)[prelude.module_id].scope.get_item_or_macro(name) |
451 | }; | 498 | }; |
452 | resolution.map(|r| r.def).unwrap_or_else(PerNs::none) | 499 | resolution.unwrap_or(Either::Left(PerNs::none())) |
453 | } else { | 500 | } else { |
454 | PerNs::none() | 501 | Either::Left(PerNs::none()) |
455 | } | 502 | } |
456 | } | 503 | } |
457 | } | 504 | } |
@@ -463,7 +510,7 @@ mod diagnostics { | |||
463 | use crate::{ | 510 | use crate::{ |
464 | AstId, DefDatabase, | 511 | AstId, DefDatabase, |
465 | nameres::CrateModuleId, | 512 | nameres::CrateModuleId, |
466 | diagnostics::{DiagnosticSink, UnresolvedModule}, | 513 | diagnostics::{DiagnosticSink, UnresolvedModule} |
467 | }; | 514 | }; |
468 | 515 | ||
469 | #[derive(Debug, PartialEq, Eq)] | 516 | #[derive(Debug, PartialEq, Eq)] |