From 896dfacfc47068df716fe4969a68adefadb1693e Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 21 Jan 2021 15:22:17 +0100 Subject: Add name resolution query for block expressions --- crates/hir_def/src/nameres/collector.rs | 58 ++++++++++++++++++++++--------- crates/hir_def/src/nameres/tests.rs | 20 +++++++++++ crates/hir_def/src/nameres/tests/block.rs | 47 +++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 crates/hir_def/src/nameres/tests/block.rs (limited to 'crates/hir_def/src/nameres') diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 61da56340..cd68efbe6 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -45,7 +45,11 @@ const GLOB_RECURSION_LIMIT: usize = 100; const EXPANSION_DEPTH_LIMIT: usize = 128; const FIXED_POINT_LIMIT: usize = 8192; -pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap) -> DefMap { +pub(super) fn collect_defs( + db: &dyn DefDatabase, + mut def_map: DefMap, + block: Option>, +) -> DefMap { let crate_graph = db.crate_graph(); // populate external prelude @@ -93,6 +97,14 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap) -> DefMap exports_proc_macros: false, from_glob_import: Default::default(), }; + match block { + Some(block) => { + collector.seed_with_inner(block); + } + None => { + collector.seed_with_top_level(); + } + } collector.collect(); collector.finish() } @@ -228,7 +240,7 @@ struct DefCollector<'a> { } impl DefCollector<'_> { - fn collect(&mut self) { + fn seed_with_top_level(&mut self) { let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; let item_tree = self.db.item_tree(file_id.into()); let module_id = self.def_map.root; @@ -248,7 +260,31 @@ impl DefCollector<'_> { } .collect(item_tree.top_level_items()); } + } + + fn seed_with_inner(&mut self, block: FileAstId) { + let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; + let item_tree = self.db.item_tree(file_id.into()); + let module_id = self.def_map.root; + self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; + if item_tree + .top_level_attrs(self.db, self.def_map.krate) + .cfg() + .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) + { + ModCollector { + def_collector: &mut *self, + macro_depth: 0, + module_id, + file_id: file_id.into(), + item_tree: &item_tree, + mod_dir: ModDir::root(), + } + .collect(item_tree.inner_items_of_block(block)); + } + } + fn collect(&mut self) { // main name resolution fixed-point loop. let mut i = 0; loop { @@ -1470,7 +1506,6 @@ impl ModCollector<'_, '_> { mod tests { use crate::{db::DefDatabase, test_db::TestDB}; use base_db::{fixture::WithFixture, SourceDatabase}; - use la_arena::Arena; use super::*; @@ -1489,6 +1524,7 @@ mod tests { exports_proc_macros: false, from_glob_import: Default::default(), }; + collector.seed_with_top_level(); collector.collect(); collector.def_map } @@ -1497,20 +1533,8 @@ mod tests { let (db, _file_id) = TestDB::with_single_file(&code); let krate = db.test_crate(); - let def_map = { - let edition = db.crate_graph()[krate].edition; - let mut modules: Arena = Arena::default(); - let root = modules.alloc(ModuleData::default()); - DefMap { - krate, - edition, - extern_prelude: FxHashMap::default(), - prelude: None, - root, - modules, - diagnostics: Vec::new(), - } - }; + let edition = db.crate_graph()[krate].edition; + let def_map = DefMap::empty(krate, edition); do_collect_defs(&db, def_map) } diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 723481c36..73e3a4702 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs @@ -4,11 +4,13 @@ mod macros; mod mod_resolution; mod diagnostics; mod primitives; +mod block; use std::sync::Arc; use base_db::{fixture::WithFixture, SourceDatabase}; use expect_test::{expect, Expect}; +use hir_expand::db::AstDatabase; use test_utils::mark; use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; @@ -19,12 +21,30 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc { db.crate_def_map(krate) } +fn compute_block_def_map(ra_fixture: &str) -> Arc { + let (db, position) = TestDB::with_position(ra_fixture); + let module = db.module_for_file(position.file_id); + let ast_map = db.ast_id_map(position.file_id.into()); + let ast = db.parse(position.file_id); + let block: ast::BlockExpr = + syntax::algo::find_node_at_offset(&ast.syntax_node(), position.offset).unwrap(); + let block_id = ast_map.ast_id(&block); + + db.block_def_map(module.krate, InFile::new(position.file_id.into(), block_id)) +} + fn check(ra_fixture: &str, expect: Expect) { let def_map = compute_crate_def_map(ra_fixture); let actual = def_map.dump(); expect.assert_eq(&actual); } +fn check_at(ra_fixture: &str, expect: Expect) { + let def_map = compute_block_def_map(ra_fixture); + let actual = def_map.dump(); + expect.assert_eq(&actual); +} + #[test] fn crate_def_map_smoke_test() { check( diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs new file mode 100644 index 000000000..996704308 --- /dev/null +++ b/crates/hir_def/src/nameres/tests/block.rs @@ -0,0 +1,47 @@ +use super::*; + +#[test] +fn inner_item_smoke() { + check_at( + r#" +//- /lib.rs +struct inner {} +fn outer() { + $0 + fn inner() {} +} +"#, + expect![[r#" + block scope + inner: v + crate + inner: t + outer: v + "#]], + ); +} + +#[test] +fn use_from_crate() { + check_at( + r#" +//- /lib.rs +struct Struct; +fn outer() { + use Struct; + use crate::Struct as CrateStruct; + use self::Struct as SelfStruct; + $0 +} +"#, + expect![[r#" + block scope + CrateStruct: t v + SelfStruct: t v + Struct: t v + crate + Struct: t v + outer: v + "#]], + ); +} -- cgit v1.2.3 From f8f44cfb9b598efea7cfbabdad356912e9b09afd Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 21 Jan 2021 15:24:15 +0100 Subject: Fall back to parent DefMaps when resolving paths --- crates/hir_def/src/nameres/path_resolution.rs | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'crates/hir_def/src/nameres') diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index 096a7d0ac..ec90f4e65 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs @@ -103,6 +103,43 @@ impl DefMap { original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, + ) -> ResolvePathResult { + let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); + result.segment_index = Some(usize::max_value()); + + let mut current_map = self; + loop { + let new = current_map.resolve_path_fp_with_macro_single( + db, + mode, + original_module, + path, + shadow, + ); + + // Merge `new` into `result`. + result.resolved_def = result.resolved_def.or(new.resolved_def); + if result.reached_fixedpoint == ReachedFixedPoint::No { + result.reached_fixedpoint = new.reached_fixedpoint; + } + // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates? + result.krate = result.krate.or(new.krate); + result.segment_index = result.segment_index.min(new.segment_index); + + match ¤t_map.parent { + Some(map) => current_map = map, + None => return result, + } + } + } + + pub(super) fn resolve_path_fp_with_macro_single( + &self, + db: &dyn DefDatabase, + mode: ResolveMode, + original_module: LocalModuleId, + path: &ModPath, + shadow: BuiltinShadowMode, ) -> ResolvePathResult { let mut segments = path.segments.iter().enumerate(); let mut curr_per_ns: PerNs = match path.kind { -- cgit v1.2.3 From ec4a1dc297eb90dde4c22c682a35606aaa50b4d4 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 21 Jan 2021 16:23:50 +0100 Subject: Add test that merges inner and outer names --- crates/hir_def/src/nameres/tests/block.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'crates/hir_def/src/nameres') diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs index 996704308..ab7ec9d62 100644 --- a/crates/hir_def/src/nameres/tests/block.rs +++ b/crates/hir_def/src/nameres/tests/block.rs @@ -45,3 +45,28 @@ fn outer() { "#]], ); } + +#[test] +fn merge_namespaces() { + check_at( + r#" +//- /lib.rs +struct name {} +fn outer() { + fn name() {} + + use name as imported; // should import both `name`s + + $0 +} +"#, + expect![[r#" + block scope + imported: t v + name: v + crate + name: t + outer: v + "#]], + ); +} -- cgit v1.2.3