hir_def/nameres/
path_resolution.rs

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