Skip to main content

hir_def/nameres/
path_resolution.rs

1//! This module implements a function to resolve a path `foo::bar::baz` to a
2//! def, which is used within name resolution.
3//!
4//! When name resolution is finished, the result of resolving a path is either
5//! `Some(def)` or `None`. However, when we are in the process of resolving imports
6//! or macros, there's a third possibility:
7//!
8//!   I can't resolve this path right now, but I might be able to resolve this path
9//!   later, when more macros are expanded.
10//!
11//! `ReachedFixedPoint` signals about this.
12
13use base_db::SourceDatabase;
14use either::Either;
15use hir_expand::{
16    mod_path::{ModPath, PathKind},
17    name::Name,
18};
19use span::Edition;
20use stdx::TupleExt;
21
22use crate::{
23    AdtId, ModuleDefId, ModuleId,
24    item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
25    nameres::{
26        BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, assoc::TraitItems,
27        crate_def_map, sub_namespace_match,
28    },
29    per_ns::PerNs,
30    visibility::{RawVisibility, Visibility},
31};
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub(super) enum ResolveMode {
35    Import,
36    Other,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub(super) enum ReachedFixedPoint {
41    Yes,
42    No,
43}
44
45#[derive(Debug, Clone)]
46pub(super) struct ResolvePathResult {
47    pub(super) resolved_def: PerNs,
48    /// The index of the last resolved segment, or `None` if the full path has been resolved.
49    pub(super) segment_index: Option<usize>,
50    pub(super) reached_fixedpoint: ReachedFixedPoint,
51    pub(super) prefix_info: ResolvePathResultPrefixInfo,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
55pub struct ResolvePathResultPrefixInfo {
56    pub(crate) differing_crate: bool,
57    /// Path of the form `Enum::Variant` (and not `Variant` alone).
58    pub enum_variant: bool,
59}
60
61impl ResolvePathResult {
62    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
63        ResolvePathResult::new(
64            PerNs::none(),
65            reached_fixedpoint,
66            None,
67            ResolvePathResultPrefixInfo::default(),
68        )
69    }
70
71    fn new(
72        resolved_def: PerNs,
73        reached_fixedpoint: ReachedFixedPoint,
74        segment_index: Option<usize>,
75        prefix_info: ResolvePathResultPrefixInfo,
76    ) -> ResolvePathResult {
77        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, prefix_info }
78    }
79}
80
81impl PerNs {
82    pub(super) fn filter_macro(
83        mut self,
84        db: &dyn SourceDatabase,
85        expected: Option<MacroSubNs>,
86    ) -> Self {
87        self.macros = self.macros.filter(|def| sub_namespace_match(db, def.def, expected));
88
89        self
90    }
91}
92
93impl DefMap {
94    pub(crate) fn resolve_visibility(
95        &self,
96        local_def_map: &LocalDefMap,
97        db: &dyn SourceDatabase,
98        // module to import to
99        original_module: ModuleId,
100        // pub(path)
101        //     ^^^^ this
102        visibility: &RawVisibility,
103        within_impl: bool,
104    ) -> Option<Visibility> {
105        let vis = match visibility {
106            RawVisibility::Module(path, explicitness) => {
107                let (result, remaining) = self.resolve_path(
108                    local_def_map,
109                    db,
110                    original_module,
111                    path,
112                    BuiltinShadowMode::Module,
113                    None,
114                );
115                if remaining.is_some() {
116                    return None;
117                }
118                let types = result.take_types()?;
119                let mut vis = match types {
120                    ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicitness),
121                    // error: visibility needs to refer to module
122                    _ => {
123                        return None;
124                    }
125                };
126
127                // In block expressions, `self` normally refers to the containing non-block module, and
128                // `super` to its parent (etc.). However, visibilities must only refer to a module in the
129                // DefMap they're written in, so we restrict them when that happens.
130                if let Visibility::Module(m, mv) = vis {
131                    // ...unless we're resolving visibility for an associated item in an impl.
132                    if self.block_id() != m.block(db) && !within_impl {
133                        vis = Visibility::Module(self.root, mv);
134                        tracing::debug!(
135                            "visibility {:?} points outside DefMap, adjusting to {:?}",
136                            m,
137                            vis
138                        );
139                    }
140                }
141                vis
142            }
143            RawVisibility::PubSelf(explicitness) => {
144                Visibility::Module(original_module, *explicitness)
145            }
146            RawVisibility::Public => Visibility::Public,
147            RawVisibility::PubCrate => Visibility::PubCrate(self.krate),
148        };
149        Some(vis)
150    }
151
152    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
153    // the result.
154    pub(super) fn resolve_path_fp_with_macro(
155        &self,
156        local_def_map: &LocalDefMap,
157        db: &dyn SourceDatabase,
158        mode: ResolveMode,
159        // module to import to
160        mut original_module: ModuleId,
161        path: &ModPath,
162        shadow: BuiltinShadowMode,
163        // Pass `MacroSubNs` if we know we're resolving macro names and which kind of macro we're
164        // resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths.
165        expected_macro_subns: Option<MacroSubNs>,
166    ) -> ResolvePathResult {
167        let mut result = self.resolve_path_fp_with_macro_single(
168            local_def_map,
169            db,
170            mode,
171            original_module,
172            path,
173            shadow,
174            expected_macro_subns,
175        );
176
177        if self.block.is_none() {
178            // If we're in the root `DefMap`, we can resolve the path directly.
179            return result;
180        }
181
182        let mut current_map = self;
183
184        let mut merge = |new: ResolvePathResult| {
185            result.resolved_def = result.resolved_def.or(new.resolved_def);
186            if result.reached_fixedpoint == ReachedFixedPoint::No {
187                result.reached_fixedpoint = new.reached_fixedpoint;
188            }
189            result.prefix_info.differing_crate |= new.prefix_info.differing_crate;
190            result.prefix_info.enum_variant |= new.prefix_info.enum_variant;
191            result.segment_index = match (result.segment_index, new.segment_index) {
192                (Some(idx), None) => Some(idx),
193                (Some(old), Some(new)) => Some(old.max(new)),
194                (None, new) => new,
195            };
196        };
197
198        loop {
199            match current_map.block {
200                Some(block) if original_module == current_map.root => {
201                    // Block modules "inherit" names from its parent module.
202                    original_module = block.parent;
203                    current_map = block.parent.def_map(db);
204                }
205                // Proper (non-block) modules, including those in block `DefMap`s, don't.
206                _ => {
207                    if original_module != current_map.root && current_map.block.is_some() {
208                        // A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
209                        // the prelude items (which are not inserted into blocks because they can be overridden there).
210                        original_module = current_map.root;
211                        current_map = crate_def_map(db, self.krate);
212
213                        let new = current_map.resolve_path_fp_in_all_preludes(
214                            local_def_map,
215                            db,
216                            mode,
217                            original_module,
218                            path,
219                            shadow,
220                        );
221                        merge(new);
222                    }
223
224                    return result;
225                }
226            }
227
228            let new = current_map.resolve_path_fp_with_macro_single(
229                local_def_map,
230                db,
231                mode,
232                original_module,
233                path,
234                shadow,
235                expected_macro_subns,
236            );
237
238            merge(new);
239        }
240    }
241
242    pub(super) fn resolve_path_fp_with_macro_single(
243        &self,
244        local_def_map: &LocalDefMap,
245        db: &dyn SourceDatabase,
246        mode: ResolveMode,
247        original_module: ModuleId,
248        path: &ModPath,
249        shadow: BuiltinShadowMode,
250        expected_macro_subns: Option<MacroSubNs>,
251    ) -> ResolvePathResult {
252        let mut segments = path.segments().iter().enumerate();
253        let curr_per_ns = match path.kind {
254            PathKind::DollarCrate(krate) => {
255                if krate == self.krate {
256                    cov_mark::hit!(macro_dollar_crate_self);
257                    PerNs::types(self.crate_root(db).into(), Visibility::Public, None)
258                } else {
259                    let def_map = crate_def_map(db, krate);
260                    let module = def_map.root;
261                    cov_mark::hit!(macro_dollar_crate_other);
262                    PerNs::types(module.into(), Visibility::Public, None)
263                }
264            }
265            PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public, None),
266            // plain import or absolute path in 2015: crate-relative with
267            // fallback to extern prelude (with the simplification in
268            // rust-lang/rust#57745)
269            PathKind::Plain | PathKind::Abs
270                if self.data.edition == Edition::Edition2015
271                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
272            {
273                let (_, segment) = match segments.next() {
274                    Some((idx, segment)) => (idx, segment),
275                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
276                };
277                tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
278                self.resolve_name_in_crate_root_or_extern_prelude(
279                    local_def_map,
280                    db,
281                    original_module,
282                    segment,
283                )
284            }
285            PathKind::Plain => {
286                let (_, segment) = match segments.next() {
287                    Some((idx, segment)) => (idx, segment),
288                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
289                };
290                // The first segment may be a builtin type. If the path has more
291                // than one segment, we first try resolving it as a module
292                // anyway.
293                // FIXME: If the next segment doesn't resolve in the module and
294                // BuiltinShadowMode wasn't Module, then we need to try
295                // resolving it as a builtin.
296                let prefer_module =
297                    if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
298
299                tracing::debug!("resolving {:?} in module", segment);
300                self.resolve_name_in_module(
301                    local_def_map,
302                    db,
303                    original_module,
304                    segment,
305                    prefer_module,
306                    expected_macro_subns,
307                )
308            }
309            PathKind::Super(lvl) => {
310                let mut local_id = original_module;
311                let mut def_map = self;
312
313                // Adjust `local_id` to `self`, i.e. the nearest non-block module.
314                (def_map, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
315
316                // Go up the module tree but skip block modules as `super` always refers to the
317                // nearest non-block module.
318                for _ in 0..lvl {
319                    // Loop invariant: at the beginning of each loop, `local_id` must refer to a
320                    // non-block module.
321                    if let Some(parent) = def_map.modules[local_id].parent {
322                        (def_map, local_id) =
323                            adjust_to_nearest_non_block_module(db, def_map, parent);
324                    } else {
325                        stdx::always!(def_map.block.is_none());
326                        tracing::debug!("super path in root module");
327                        return ResolvePathResult::empty(ReachedFixedPoint::Yes);
328                    }
329                }
330
331                if self.block != def_map.block {
332                    // If we have a different `DefMap` from `self` (the original `DefMap` we started
333                    // with), resolve the remaining path segments in that `DefMap`.
334                    let path =
335                        ModPath::from_segments(PathKind::SELF, path.segments().iter().cloned());
336                    // This is the same crate, so the local def map is the same.
337                    return def_map.resolve_path_fp_with_macro(
338                        local_def_map,
339                        db,
340                        mode,
341                        local_id,
342                        &path,
343                        shadow,
344                        expected_macro_subns,
345                    );
346                }
347
348                PerNs::types(local_id.into(), Visibility::Public, None)
349            }
350            PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) {
351                Either::Left(it) => it,
352                Either::Right(reached_fixed_point) => {
353                    return ResolvePathResult::empty(reached_fixed_point);
354                }
355            },
356        };
357
358        self.resolve_remaining_segments(
359            db,
360            mode,
361            segments,
362            curr_per_ns,
363            path,
364            shadow,
365            original_module,
366        )
367    }
368
369    /// Resolves a path only in the preludes, without accounting for item scopes.
370    pub(super) fn resolve_path_fp_in_all_preludes(
371        &self,
372        local_def_map: &LocalDefMap,
373        db: &dyn SourceDatabase,
374        mode: ResolveMode,
375        original_module: ModuleId,
376        path: &ModPath,
377        shadow: BuiltinShadowMode,
378    ) -> ResolvePathResult {
379        let mut segments = path.segments().iter().enumerate();
380        let curr_per_ns = match path.kind {
381            // plain import or absolute path in 2015: crate-relative with
382            // fallback to extern prelude (with the simplification in
383            // rust-lang/rust#57745)
384            PathKind::Plain | PathKind::Abs
385                if self.data.edition == Edition::Edition2015
386                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
387            {
388                let (_, segment) = match segments.next() {
389                    Some((idx, segment)) => (idx, segment),
390                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
391                };
392                tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
393                self.resolve_name_in_extern_prelude(local_def_map, segment)
394            }
395            PathKind::Plain => {
396                let (_, segment) = match segments.next() {
397                    Some((idx, segment)) => (idx, segment),
398                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
399                };
400                tracing::debug!("resolving {:?} in module", segment);
401                self.resolve_name_in_all_preludes(local_def_map, db, segment)
402            }
403            PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) {
404                Either::Left(it) => it,
405                Either::Right(reached_fixed_point) => {
406                    return ResolvePathResult::empty(reached_fixed_point);
407                }
408            },
409            PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
410                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
411            }
412        };
413
414        self.resolve_remaining_segments(
415            db,
416            mode,
417            segments,
418            curr_per_ns,
419            path,
420            shadow,
421            original_module,
422        )
423    }
424
425    /// 2018-style absolute path -- only extern prelude
426    fn resolve_path_abs<'a>(
427        &self,
428        local_def_map: &LocalDefMap,
429        segments: &mut impl Iterator<Item = (usize, &'a Name)>,
430        path: &ModPath,
431    ) -> Either<PerNs, ReachedFixedPoint> {
432        let segment = match segments.next() {
433            Some((_, segment)) => segment,
434            None => return Either::Right(ReachedFixedPoint::Yes),
435        };
436        if let Some(&(def, extern_crate)) = local_def_map.extern_prelude.get(segment) {
437            tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
438            Either::Left(PerNs::types(
439                def.into(),
440                Visibility::Public,
441                extern_crate.map(ImportOrExternCrate::ExternCrate),
442            ))
443        } else {
444            Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude
445        }
446    }
447
448    fn resolve_remaining_segments<'a>(
449        &self,
450        db: &dyn SourceDatabase,
451        mode: ResolveMode,
452        mut segments: impl Iterator<Item = (usize, &'a Name)>,
453        mut curr_per_ns: PerNs,
454        path: &ModPath,
455        shadow: BuiltinShadowMode,
456        original_module: ModuleId,
457    ) -> ResolvePathResult {
458        while let Some((i, segment)) = segments.next() {
459            let curr = match curr_per_ns.take_types_full() {
460                Some(r) => r,
461                None => {
462                    // we still have path segments left, but the path so far
463                    // didn't resolve in the types namespace => no resolution
464                    // (don't break here because `curr_per_ns` might contain
465                    // something in the value namespace, and it would be wrong
466                    // to return that)
467                    return ResolvePathResult::empty(ReachedFixedPoint::No);
468                }
469            };
470            // resolve segment in curr
471
472            curr_per_ns = match curr.def {
473                ModuleDefId::ModuleId(module) => {
474                    if module.krate(db) != self.krate {
475                        // FIXME: Inefficient
476                        let path = ModPath::from_segments(
477                            PathKind::SELF,
478                            path.segments()[i..].iter().cloned(),
479                        );
480                        tracing::debug!("resolving {:?} in other crate", path);
481                        let defp_map = module.def_map(db);
482                        // Macro sub-namespaces only matter when resolving single-segment paths
483                        // because `macro_use` and other preludes should be taken into account. At
484                        // this point, we know we're resolving a multi-segment path so macro kind
485                        // expectation is discarded.
486                        let resolution = defp_map.resolve_path_fp_with_macro(
487                            LocalDefMap::EMPTY,
488                            db,
489                            mode,
490                            module,
491                            &path,
492                            shadow,
493                            None,
494                        );
495                        return ResolvePathResult::new(
496                            resolution.resolved_def,
497                            ReachedFixedPoint::Yes,
498                            resolution.segment_index.map(|s| s + i),
499                            ResolvePathResultPrefixInfo {
500                                differing_crate: true,
501                                enum_variant: resolution.prefix_info.enum_variant,
502                            },
503                        );
504                    }
505
506                    let module_data = if module.block(db) == self.block_id() {
507                        &self[module]
508                    } else {
509                        &module.def_map(db)[module]
510                    };
511
512                    // Since it is a qualified path here, it should not contains legacy macros
513                    module_data.scope.get(segment)
514                }
515                ModuleDefId::AdtId(AdtId::EnumId(e)) => {
516                    // enum variant
517                    cov_mark::hit!(can_import_enum_variant);
518
519                    let res = e.enum_variants(db).variants.get(segment).map(|&(variant, shape)| {
520                        if shape.has_value_ns_ctor() {
521                            PerNs::both(variant.into(), variant.into(), curr.vis, None)
522                        } else {
523                            PerNs::types(variant.into(), curr.vis, None)
524                        }
525                    });
526                    // FIXME: Need to filter visibility here and below? Not sure.
527                    return match res {
528                        Some(res) => {
529                            if segments.next().is_some() {
530                                // Enum variants are in value namespace, segments left => no resolution.
531                                ResolvePathResult::empty(ReachedFixedPoint::No)
532                            } else {
533                                ResolvePathResult::new(
534                                    res,
535                                    ReachedFixedPoint::Yes,
536                                    None,
537                                    ResolvePathResultPrefixInfo {
538                                        enum_variant: true,
539                                        ..ResolvePathResultPrefixInfo::default()
540                                    },
541                                )
542                            }
543                        }
544                        None => ResolvePathResult::new(
545                            PerNs::types(e.into(), curr.vis, curr.import),
546                            ReachedFixedPoint::Yes,
547                            Some(i),
548                            ResolvePathResultPrefixInfo::default(),
549                        ),
550                    };
551                }
552                def @ ModuleDefId::TraitId(t) if mode == ResolveMode::Import => {
553                    // FIXME: Implement this correctly
554                    // We can't actually call `trait_items`, the reason being that if macro calls
555                    // occur, they will call back into the def map which we might be computing right
556                    // now resulting in a cycle.
557                    // To properly implement this, trait item collection needs to be done in def map
558                    // collection...
559                    let item = if true {
560                        None
561                    } else {
562                        TraitItems::query(db, t).assoc_item_by_name(segment)
563                    };
564                    return match item {
565                        Some(item) => ResolvePathResult::new(
566                            match item {
567                                crate::AssocItemId::FunctionId(function_id) => PerNs::values(
568                                    function_id.into(),
569                                    curr.vis,
570                                    curr.import.and_then(|it| it.import_or_glob()),
571                                ),
572                                crate::AssocItemId::ConstId(const_id) => PerNs::values(
573                                    const_id.into(),
574                                    curr.vis,
575                                    curr.import.and_then(|it| it.import_or_glob()),
576                                ),
577                                crate::AssocItemId::TypeAliasId(type_alias_id) => {
578                                    PerNs::types(type_alias_id.into(), curr.vis, curr.import)
579                                }
580                            },
581                            ReachedFixedPoint::Yes,
582                            segments.next().map(TupleExt::head),
583                            ResolvePathResultPrefixInfo::default(),
584                        ),
585                        None => ResolvePathResult::new(
586                            PerNs::types(def, curr.vis, curr.import),
587                            ReachedFixedPoint::Yes,
588                            Some(i),
589                            ResolvePathResultPrefixInfo::default(),
590                        ),
591                    };
592                }
593                s => {
594                    // could be an inherent method call in UFCS form
595                    // (`Struct::method`), or some other kind of associated item
596                    tracing::debug!(
597                        "path segment {:?} resolved to non-module {:?}, but is not last",
598                        segment,
599                        curr,
600                    );
601
602                    return ResolvePathResult::new(
603                        PerNs::types(s, curr.vis, curr.import),
604                        ReachedFixedPoint::Yes,
605                        Some(i),
606                        ResolvePathResultPrefixInfo::default(),
607                    );
608                }
609            };
610
611            curr_per_ns = curr_per_ns
612                .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module));
613        }
614
615        ResolvePathResult::new(
616            curr_per_ns,
617            ReachedFixedPoint::Yes,
618            None,
619            ResolvePathResultPrefixInfo::default(),
620        )
621    }
622
623    fn resolve_name_in_module(
624        &self,
625        local_def_map: &LocalDefMap,
626        db: &dyn SourceDatabase,
627        module: ModuleId,
628        name: &Name,
629        shadow: BuiltinShadowMode,
630        expected_macro_subns: Option<MacroSubNs>,
631    ) -> PerNs {
632        // Resolve in:
633        //  - legacy scope of macro
634        //  - current module / scope
635        //  - extern prelude / macro_use prelude
636        //  - std prelude
637        let from_legacy_macro = self[module]
638            .scope
639            .get_legacy_macro(name)
640            // FIXME: shadowing
641            .and_then(|it| it.last())
642            .copied()
643            .filter(|&id| sub_namespace_match(db, id, expected_macro_subns))
644            .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public, None));
645        let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns);
646        let from_builtin = match self.block {
647            Some(_) => {
648                // Only resolve to builtins in the root `DefMap`.
649                PerNs::none()
650            }
651            None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
652        };
653        let from_scope_or_builtin = match shadow {
654            BuiltinShadowMode::Module => from_scope.or(from_builtin),
655            BuiltinShadowMode::Other => match from_scope.take_types() {
656                Some(ModuleDefId::ModuleId(_)) => from_builtin.or(from_scope),
657                Some(_) | None => from_scope.or(from_builtin),
658            },
659        };
660
661        let extern_prelude = || {
662            if self.block.is_some() && module == self.root {
663                // Don't resolve extern prelude in pseudo-modules of blocks, because
664                // they might been shadowed by local names.
665                return PerNs::none();
666            }
667            self.resolve_name_in_extern_prelude(local_def_map, name)
668        };
669        let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
670        let prelude = || {
671            if self.block.is_some() && module == self.root {
672                return PerNs::none();
673            }
674            self.resolve_in_prelude(db, name)
675        };
676
677        from_legacy_macro
678            .or(from_scope_or_builtin)
679            .or_else(extern_prelude)
680            .or_else(macro_use_prelude)
681            .or_else(prelude)
682    }
683
684    fn resolve_name_in_all_preludes(
685        &self,
686        local_def_map: &LocalDefMap,
687        db: &dyn SourceDatabase,
688        name: &Name,
689    ) -> PerNs {
690        // Resolve in:
691        //  - extern prelude / macro_use prelude
692        //  - std prelude
693        let extern_prelude = self.resolve_name_in_extern_prelude(local_def_map, name);
694        let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
695        let prelude = || self.resolve_in_prelude(db, name);
696
697        extern_prelude.or_else(macro_use_prelude).or_else(prelude)
698    }
699
700    fn resolve_name_in_extern_prelude(&self, local_def_map: &LocalDefMap, name: &Name) -> PerNs {
701        local_def_map.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
702            PerNs::types(
703                it.into(),
704                Visibility::Public,
705                extern_crate.map(ImportOrExternCrate::ExternCrate),
706            )
707        })
708    }
709
710    fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
711        self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
712            PerNs::macros(
713                it,
714                Visibility::Public,
715                extern_crate.map(ImportOrExternCrate::ExternCrate),
716            )
717        })
718    }
719
720    fn resolve_name_in_crate_root_or_extern_prelude(
721        &self,
722        local_def_map: &LocalDefMap,
723        db: &dyn SourceDatabase,
724        module: ModuleId,
725        name: &Name,
726    ) -> PerNs {
727        let from_crate_root = match self.block {
728            Some(_) => {
729                let def_map = self.crate_root(db).def_map(db);
730                def_map[def_map.root].scope.get(name)
731            }
732            None => self[self.root].scope.get(name),
733        };
734        let from_extern_prelude = || {
735            if self.block.is_some() && module == self.root {
736                // Don't resolve extern prelude in pseudo-module of a block.
737                return PerNs::none();
738            }
739            self.resolve_name_in_extern_prelude(local_def_map, name)
740        };
741
742        from_crate_root.or_else(from_extern_prelude)
743    }
744
745    fn resolve_in_prelude(&self, db: &dyn SourceDatabase, name: &Name) -> PerNs {
746        if let Some((prelude, _use)) = self.prelude {
747            let def_map = if prelude.krate(db) == self.krate { self } else { prelude.def_map(db) };
748            def_map[prelude].scope.get(name)
749        } else {
750            PerNs::none()
751        }
752    }
753}
754
755/// Given a block module, returns its nearest non-block module and the `DefMap` it belongs to.
756#[inline]
757fn adjust_to_nearest_non_block_module<'db>(
758    db: &'db dyn SourceDatabase,
759    mut def_map: &'db DefMap,
760    mut local_id: ModuleId,
761) -> (&'db DefMap, ModuleId) {
762    if def_map.root_module_id() != local_id {
763        // if we aren't the root, we are either not a block module, or a non-block module inside a
764        // block def map.
765        return (def_map, local_id);
766    }
767    while let Some(BlockInfo { parent, .. }) = def_map.block {
768        def_map = parent.def_map(db);
769        local_id = parent;
770        if def_map.root_module_id() != local_id {
771            return (def_map, local_id);
772        }
773    }
774    (def_map, local_id)
775}