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