Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/find_path.rs')
| -rw-r--r-- | crates/hir-def/src/find_path.rs | 114 |
1 files changed, 56 insertions, 58 deletions
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index e8a6ebcffa..5d1cac8e93 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -39,20 +39,23 @@ pub fn find_path( // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so // default to plain paths. let item_module = item.module(db)?; - if item_module.is_within_block() { + if item_module.block(db).is_some() { prefix_kind = PrefixKind::Plain; } - cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate()); + cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate(db)); + let from_def_map = from.def_map(db); find_path_inner( &FindPathCtx { db, prefix: prefix_kind, cfg, ignore_local_imports, - is_std_item: item_module.krate().data(db).origin.is_lang(), + is_std_item: item_module.krate(db).data(db).origin.is_lang(), from, - from_def_map: from.def_map(db), + from_crate: from.krate(db), + crate_root: from_def_map.crate_root(db), + from_def_map, fuel: Cell::new(FIND_PATH_FUEL), }, item, @@ -100,6 +103,8 @@ struct FindPathCtx<'db> { ignore_local_imports: bool, is_std_item: bool, from: ModuleId, + from_crate: Crate, + crate_root: ModuleId, from_def_map: &'db DefMap, fuel: Cell<usize>, } @@ -116,7 +121,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => ctx.from.is_crate_root(), + PrefixKind::ByCrate => ctx.crate_root == ctx.from, }; if may_be_in_scope { // - if the item is already in scope, return the name under which it is @@ -163,8 +168,9 @@ fn find_path_for_module( // recursive base case, we can't find a path of length 0 return None; } - if let Some(crate_root) = module_id.as_crate_root() { - if !maybe_extern || crate_root == ctx.from.derive_crate_root() { + let module_crate_root = module_id.def_map(ctx.db).crate_root(ctx.db); + if module_crate_root == module_id { + if !maybe_extern || module_crate_root == ctx.crate_root { // - if the item is the crate root, return `crate` return Some(Choice { path: ModPath::from_segments(PathKind::Crate, None), @@ -175,19 +181,19 @@ fn find_path_for_module( } // - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude - let root_local_def_map = ctx.from.derive_crate_root().local_def_map(ctx.db).1; + let root_local_def_map = ctx.crate_root.local_def_map(ctx.db).1; // rev here so we prefer looking at renamed extern decls first for (name, (def_id, _extern_crate)) in root_local_def_map.extern_prelude().rev() { - if crate_root != def_id { + if module_crate_root != def_id { continue; } let name_already_occupied_in_type_ns = ctx .from_def_map - .with_ancestor_maps(ctx.db, ctx.from.local_id, &mut |def_map, local_id| { + .with_ancestor_maps(ctx.db, ctx.from, &mut |def_map, local_id| { def_map[local_id] .scope .type_(name) - .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id.into())) + .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id)) }) .is_some(); let kind = if name_already_occupied_in_type_ns { @@ -204,7 +210,7 @@ fn find_path_for_module( let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => ctx.from.is_crate_root(), + PrefixKind::ByCrate => ctx.crate_root == ctx.from, }; if may_be_in_scope { let scope_name = find_in_scope( @@ -226,7 +232,7 @@ fn find_path_for_module( } // - if the module can be referenced as self, super or crate, do that - if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) + if let Some(kind) = is_kw_kind_relative_to_from(ctx.db, ctx.from_def_map, module_id, ctx.from) && (ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate) { return Some(Choice { @@ -259,7 +265,7 @@ fn find_in_scope( ignore_local_imports: bool, ) -> Option<Name> { // FIXME: We could have multiple applicable names here, but we currently only return the first - def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| { def_map[local_id].scope.names_of(item, |name, _, declared| { (declared || !ignore_local_imports).then(|| name.clone()) }) @@ -276,7 +282,7 @@ fn find_in_prelude( ) -> Option<Choice> { let (prelude_module, _) = local_def_map.prelude()?; let prelude_def_map = prelude_module.def_map(db); - let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; + let prelude_scope = &prelude_def_map[prelude_module].scope; let (name, vis, _declared) = prelude_scope.name_of(item)?; if !vis.is_visible_from(db, from) { return None; @@ -284,7 +290,7 @@ fn find_in_prelude( // Check if the name is in current scope and it points to the same def. let found_and_same_def = - local_def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + local_def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| { let per_ns = def_map[local_id].scope.get(name); let same_def = match item { ItemInNs::Types(it) => per_ns.take_types()? == it, @@ -302,22 +308,21 @@ fn find_in_prelude( } fn is_kw_kind_relative_to_from( + db: &dyn DefDatabase, def_map: &DefMap, item: ModuleId, from: ModuleId, ) -> Option<PathKind> { - if item.krate != from.krate || item.is_within_block() || from.is_within_block() { + if item.krate(db) != from.krate(db) || item.block(db).is_some() || from.block(db).is_some() { return None; } - let item = item.local_id; - let from = from.local_id; if item == from { // - if the item is the module we're in, use `self` Some(PathKind::SELF) } else if let Some(parent_id) = def_map[from].parent { if item == parent_id { // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) - Some(if parent_id == DefMap::ROOT { PathKind::Crate } else { PathKind::Super(1) }) + Some(if parent_id == def_map.root { PathKind::Crate } else { PathKind::Super(1) }) } else { None } @@ -340,13 +345,13 @@ fn calculate_best_path( tracing::warn!( "ran out of fuel while searching for a path for item {item:?} of krate {:?} from krate {:?}", item.krate(ctx.db), - ctx.from.krate() + ctx.from_crate ); return; } ctx.fuel.set(fuel - 1); - if item.krate(ctx.db) == Some(ctx.from.krate) { + if item.krate(ctx.db) == Some(ctx.from_crate) { // Item was defined in the same crate that wants to import it. It cannot be found in any // dependency in this case. calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice) @@ -361,7 +366,7 @@ fn calculate_best_path( // too (unless we can't name it at all). It could *also* be (re)exported by the same crate // that wants to import it here, but we always prefer to use the external path here. - ctx.from.krate.data(ctx.db).dependencies.iter().for_each(|dep| { + ctx.from_crate.data(ctx.db).dependencies.iter().for_each(|dep| { find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id) }); } @@ -374,7 +379,7 @@ fn find_in_sysroot( max_len: usize, best_choice: &mut Option<Choice>, ) { - let dependencies = &ctx.from.krate.data(ctx.db).dependencies; + let dependencies = &ctx.from_crate.data(ctx.db).dependencies; let mut search = |lang, best_choice: &mut _| { if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| { match dep.crate_id.data(ctx.db).origin { @@ -464,26 +469,19 @@ fn calculate_best_path_local( best_choice: &mut Option<Choice>, ) { // FIXME: cache the `find_local_import_locations` output? - find_local_import_locations( - ctx.db, - item, - ctx.from, - ctx.from_def_map, - visited_modules, - |visited_modules, name, module_id| { - // we are looking for paths of length up to best_path_len, any longer will make it be - // less optimal. The -1 is due to us pushing name onto it afterwards. - if let Some(choice) = find_path_for_module( - ctx, - visited_modules, - module_id, - false, - best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1, - ) { - Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone()); - } - }, - ); + find_local_import_locations(ctx, item, visited_modules, |visited_modules, name, module_id| { + // we are looking for paths of length up to best_path_len, any longer will make it be + // less optimal. The -1 is due to us pushing name onto it afterwards. + if let Some(choice) = find_path_for_module( + ctx, + visited_modules, + module_id, + false, + best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1, + ) { + Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone()); + } + }); } #[derive(Debug)] @@ -561,14 +559,13 @@ fn path_kind_len(kind: PathKind) -> usize { /// Finds locations in `from.krate` from which `item` can be imported by `from`. fn find_local_import_locations( - db: &dyn DefDatabase, + ctx: &FindPathCtx<'_>, item: ItemInNs, - from: ModuleId, - def_map: &DefMap, visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleId)>, &Name, ModuleId), ) { let _p = tracing::info_span!("find_local_import_locations").entered(); + let db = ctx.db; // `from` can import anything below `from` with visibility of at least `from`, and anything // above `from` with any visibility. That means we do not need to descend into private siblings @@ -576,15 +573,16 @@ fn find_local_import_locations( // Compute the initial worklist. We start with all direct child modules of `from` as well as all // of its (recursive) parent modules. - let mut worklist = def_map[from.local_id] + let mut worklist = ctx.from_def_map[ctx.from] .children .values() - .map(|&child| def_map.module_id(child)) - .chain(iter::successors(from.containing_module(db), |m| m.containing_module(db))) + .copied() + .chain(iter::successors(ctx.from.containing_module(db), |m| m.containing_module(db))) .zip(iter::repeat(false)) .collect::<Vec<_>>(); - let def_map = def_map.crate_root().def_map(db); + let def_map = + if ctx.crate_root == ctx.from { ctx.from_def_map } else { ctx.crate_root.def_map(db) }; let mut block_def_map; let mut cursor = 0; @@ -595,17 +593,17 @@ fn find_local_import_locations( continue; } *processed = true; - let data = if module.block.is_some() { + let data = if module.block(db).is_some() { // Re-query the block's DefMap block_def_map = module.def_map(db); - &block_def_map[module.local_id] + &block_def_map[module] } else { // Reuse the root DefMap - &def_map[module.local_id] + &def_map[module] }; if let Some((name, vis, declared)) = data.scope.name_of(item) - && vis.is_visible_from(db, from) + && vis.is_visible_from(db, ctx.from) { let is_pub_or_explicit = match vis { Visibility::Module(_, VisibilityExplicitness::Explicit) => { @@ -632,7 +630,7 @@ fn find_local_import_locations( // Descend into all modules visible from `from`. for (module, vis) in data.scope.modules_in_scope() { - if module.krate != from.krate { + if module.krate(db) != ctx.from.krate(db) { // We don't need to look at modules from other crates as our item has to be in the // current crate continue; @@ -641,7 +639,7 @@ fn find_local_import_locations( continue; } - if vis.is_visible_from(db, from) { + if vis.is_visible_from(db, ctx.from) { worklist.push((module, false)); } } @@ -694,7 +692,7 @@ mod tests { .resolve_path( local_def_map, &db, - module.local_id, + module, &mod_path, crate::item_scope::BuiltinShadowMode::Module, None, |