aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-01-25 18:24:04 +0000
committerGitHub <[email protected]>2021-01-25 18:24:04 +0000
commita37091d2d0175b0999d6383d48f538cdbf0267a0 (patch)
tree06981374f0c397b45e31b74c97ed337853fe59d2 /crates
parent2c735ed734be9b9041921478e0049fffd7160f78 (diff)
parent08253d5473348e2f3061e0c8d84c62de537a5821 (diff)
Merge #7431
7431: Handle `super` paths inside blocks correctly r=jonas-schievink a=jonas-schievink We now intern `BlockLoc` and use `BlockId` to refer to block expressions. This is needed to keep `ModuleId` simple, since it would otherwise have to store an arbitrarily long chain of blocks and couldn't be `Copy`. The `DefMap` hierarchy is now created as the caller descends into an item body. This is necessary to link the correct module as the block's parent, which is important for correct name resolution. As a result, we can now resolve `super` paths inside block expressions by climbing the `DefMap` chain. bors r+ Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_def/src/db.rs15
-rw-r--r--crates/hir_def/src/lib.rs15
-rw-r--r--crates/hir_def/src/nameres.rs73
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs41
-rw-r--r--crates/hir_def/src/nameres/tests.rs62
-rw-r--r--crates/hir_def/src/nameres/tests/block.rs26
6 files changed, 158 insertions, 74 deletions
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index a87c80b8a..aef7e1f6c 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -2,9 +2,9 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use base_db::{salsa, CrateId, SourceDatabase, Upcast}; 4use base_db::{salsa, CrateId, SourceDatabase, Upcast};
5use hir_expand::{db::AstDatabase, AstId, HirFileId}; 5use hir_expand::{db::AstDatabase, HirFileId};
6use la_arena::ArenaMap; 6use la_arena::ArenaMap;
7use syntax::{ast, SmolStr}; 7use syntax::SmolStr;
8 8
9use crate::{ 9use crate::{
10 adt::{EnumData, StructData}, 10 adt::{EnumData, StructData},
@@ -16,9 +16,10 @@ use crate::{
16 item_tree::ItemTree, 16 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 17 lang_item::{LangItemTarget, LangItems},
18 nameres::DefMap, 18 nameres::DefMap,
19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, 19 AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId,
20 GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId, 20 FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId,
21 StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, 21 StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
22 UnionLoc, VariantId,
22}; 23};
23 24
24#[salsa::query_group(InternDatabaseStorage)] 25#[salsa::query_group(InternDatabaseStorage)]
@@ -41,6 +42,8 @@ pub trait InternDatabase: SourceDatabase {
41 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; 42 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
42 #[salsa::interned] 43 #[salsa::interned]
43 fn intern_impl(&self, loc: ImplLoc) -> ImplId; 44 fn intern_impl(&self, loc: ImplLoc) -> ImplId;
45 #[salsa::interned]
46 fn intern_block(&self, loc: BlockLoc) -> BlockId;
44} 47}
45 48
46#[salsa::query_group(DefDatabaseStorage)] 49#[salsa::query_group(DefDatabaseStorage)]
@@ -56,7 +59,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
56 fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>; 59 fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>;
57 60
58 #[salsa::invoke(DefMap::block_def_map_query)] 61 #[salsa::invoke(DefMap::block_def_map_query)]
59 fn block_def_map(&self, krate: CrateId, block: AstId<ast::BlockExpr>) -> Arc<DefMap>; 62 fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
60 63
61 #[salsa::invoke(StructData::struct_data_query)] 64 #[salsa::invoke(StructData::struct_data_query)]
62 fn struct_data(&self, id: StructId) -> Arc<StructData>; 65 fn struct_data(&self, id: StructId) -> Arc<StructData>;
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index cf09ebd3f..42b50b5b7 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -74,12 +74,16 @@ use stdx::impl_from;
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
75pub struct ModuleId { 75pub struct ModuleId {
76 krate: CrateId, 76 krate: CrateId,
77 block: Option<BlockId>,
77 pub local_id: LocalModuleId, 78 pub local_id: LocalModuleId,
78} 79}
79 80
80impl ModuleId { 81impl ModuleId {
81 pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> { 82 pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
82 db.crate_def_map(self.krate) 83 match self.block {
84 Some(block) => db.block_def_map(block),
85 None => db.crate_def_map(self.krate),
86 }
83 } 87 }
84 88
85 pub fn krate(&self) -> CrateId { 89 pub fn krate(&self) -> CrateId {
@@ -230,6 +234,15 @@ pub struct ImplId(salsa::InternId);
230type ImplLoc = ItemLoc<Impl>; 234type ImplLoc = ItemLoc<Impl>;
231impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); 235impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
232 236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
238pub struct BlockId(salsa::InternId);
239#[derive(Debug, Hash, PartialEq, Eq, Clone)]
240pub struct BlockLoc {
241 ast_id: AstId<ast::BlockExpr>,
242 module: ModuleId,
243}
244impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
245
233#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 246#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
234pub struct TypeParamId { 247pub struct TypeParamId {
235 pub parent: GenericDefId, 248 pub parent: GenericDefId,
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 4fbbecb38..199771e9a 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -62,7 +62,7 @@ use la_arena::Arena;
62use profile::Count; 62use profile::Count;
63use rustc_hash::FxHashMap; 63use rustc_hash::FxHashMap;
64use stdx::format_to; 64use stdx::format_to;
65use syntax::{ast, AstNode}; 65use syntax::ast;
66 66
67use crate::{ 67use crate::{
68 db::DefDatabase, 68 db::DefDatabase,
@@ -70,14 +70,14 @@ use crate::{
70 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, 70 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
71 path::ModPath, 71 path::ModPath,
72 per_ns::PerNs, 72 per_ns::PerNs,
73 AstId, LocalModuleId, ModuleDefId, ModuleId, 73 AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId,
74}; 74};
75 75
76/// Contains all top-level defs from a macro-expanded crate 76/// Contains all top-level defs from a macro-expanded crate
77#[derive(Debug, PartialEq, Eq)] 77#[derive(Debug, PartialEq, Eq)]
78pub struct DefMap { 78pub struct DefMap {
79 _c: Count<Self>, 79 _c: Count<Self>,
80 parent: Option<Arc<DefMap>>, 80 block: Option<BlockInfo>,
81 root: LocalModuleId, 81 root: LocalModuleId,
82 modules: Arena<ModuleData>, 82 modules: Arena<ModuleData>,
83 krate: CrateId, 83 krate: CrateId,
@@ -91,6 +91,13 @@ pub struct DefMap {
91 diagnostics: Vec<DefDiagnostic>, 91 diagnostics: Vec<DefDiagnostic>,
92} 92}
93 93
94#[derive(Debug, PartialEq, Eq)]
95struct BlockInfo {
96 block: BlockId,
97 parent: Arc<DefMap>,
98 parent_module: LocalModuleId,
99}
100
94impl std::ops::Index<LocalModuleId> for DefMap { 101impl std::ops::Index<LocalModuleId> for DefMap {
95 type Output = ModuleData; 102 type Output = ModuleData;
96 fn index(&self, id: LocalModuleId) -> &ModuleData { 103 fn index(&self, id: LocalModuleId) -> &ModuleData {
@@ -190,15 +197,12 @@ impl DefMap {
190 Arc::new(def_map) 197 Arc::new(def_map)
191 } 198 }
192 199
193 pub(crate) fn block_def_map_query( 200 pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
194 db: &dyn DefDatabase, 201 let block: BlockLoc = db.lookup_intern_block(block_id);
195 krate: CrateId, 202 let item_tree = db.item_tree(block.ast_id.file_id);
196 block: AstId<ast::BlockExpr>, 203 let block_items = item_tree.inner_items_of_block(block.ast_id.value);
197 ) -> Arc<DefMap> {
198 let item_tree = db.item_tree(block.file_id);
199 let block_items = item_tree.inner_items_of_block(block.value);
200 204
201 let parent = parent_def_map(db, krate, block); 205 let parent = block.module.def_map(db);
202 206
203 if block_items.is_empty() { 207 if block_items.is_empty() {
204 // If there are no inner items, nothing new is brought into scope, so we can just return 208 // If there are no inner items, nothing new is brought into scope, so we can just return
@@ -206,10 +210,13 @@ impl DefMap {
206 return parent; 210 return parent;
207 } 211 }
208 212
209 let mut def_map = DefMap::empty(krate, parent.edition); 213 let block_info =
210 def_map.parent = Some(parent); 214 BlockInfo { block: block_id, parent, parent_module: block.module.local_id };
215
216 let mut def_map = DefMap::empty(block.module.krate, block_info.parent.edition);
217 def_map.block = Some(block_info);
211 218
212 let def_map = collector::collect_defs(db, def_map, Some(block.value)); 219 let def_map = collector::collect_defs(db, def_map, Some(block.ast_id.value));
213 Arc::new(def_map) 220 Arc::new(def_map)
214 } 221 }
215 222
@@ -218,7 +225,7 @@ impl DefMap {
218 let root = modules.alloc(ModuleData::default()); 225 let root = modules.alloc(ModuleData::default());
219 DefMap { 226 DefMap {
220 _c: Count::new(), 227 _c: Count::new(),
221 parent: None, 228 block: None,
222 krate, 229 krate,
223 edition, 230 edition,
224 extern_prelude: FxHashMap::default(), 231 extern_prelude: FxHashMap::default(),
@@ -266,7 +273,8 @@ impl DefMap {
266 } 273 }
267 274
268 pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { 275 pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
269 ModuleId { krate: self.krate, local_id } 276 let block = self.block.as_ref().map(|b| b.block);
277 ModuleId { krate: self.krate, local_id, block }
270 } 278 }
271 279
272 pub(crate) fn resolve_path( 280 pub(crate) fn resolve_path(
@@ -286,9 +294,9 @@ impl DefMap {
286 pub fn dump(&self) -> String { 294 pub fn dump(&self) -> String {
287 let mut buf = String::new(); 295 let mut buf = String::new();
288 let mut current_map = self; 296 let mut current_map = self;
289 while let Some(parent) = &current_map.parent { 297 while let Some(block) = &current_map.block {
290 go(&mut buf, current_map, "block scope", current_map.root); 298 go(&mut buf, current_map, "block scope", current_map.root);
291 current_map = &**parent; 299 current_map = &*block.parent;
292 } 300 }
293 go(&mut buf, current_map, "crate", current_map.root); 301 go(&mut buf, current_map, "crate", current_map.root);
294 return buf; 302 return buf;
@@ -342,35 +350,6 @@ impl ModuleData {
342 } 350 }
343} 351}
344 352
345fn parent_def_map(
346 db: &dyn DefDatabase,
347 krate: CrateId,
348 block: AstId<ast::BlockExpr>,
349) -> Arc<DefMap> {
350 // FIXME: store this info in the item tree instead of reparsing here
351 let ast_id_map = db.ast_id_map(block.file_id);
352 let block_ptr = ast_id_map.get(block.value);
353 let root = match db.parse_or_expand(block.file_id) {
354 Some(it) => it,
355 None => {
356 return Arc::new(DefMap::empty(krate, Edition::Edition2018));
357 }
358 };
359 let ast = block_ptr.to_node(&root);
360
361 for ancestor in ast.syntax().ancestors().skip(1) {
362 if let Some(block_expr) = ast::BlockExpr::cast(ancestor) {
363 let ancestor_id = ast_id_map.ast_id(&block_expr);
364 let ast_id = InFile::new(block.file_id, ancestor_id);
365 let parent_map = db.block_def_map(krate, ast_id);
366 return parent_map;
367 }
368 }
369
370 // No enclosing block scope, so the parent is the crate-level DefMap.
371 db.crate_def_map(krate)
372}
373
374#[derive(Debug, Clone, PartialEq, Eq)] 353#[derive(Debug, Clone, PartialEq, Eq)]
375pub enum ModuleSource { 354pub enum ModuleSource {
376 SourceFile(ast::SourceFile), 355 SourceFile(ast::SourceFile),
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index c1eded5f2..419e465ed 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -10,8 +10,6 @@
10//! 10//!
11//! `ReachedFixedPoint` signals about this. 11//! `ReachedFixedPoint` signals about this.
12 12
13use std::iter::successors;
14
15use base_db::Edition; 13use base_db::Edition;
16use hir_expand::name; 14use hir_expand::name;
17use hir_expand::name::Name; 15use hir_expand::name::Name;
@@ -131,8 +129,8 @@ impl DefMap {
131 result.krate = result.krate.or(new.krate); 129 result.krate = result.krate.or(new.krate);
132 result.segment_index = result.segment_index.min(new.segment_index); 130 result.segment_index = result.segment_index.min(new.segment_index);
133 131
134 match &current_map.parent { 132 match &current_map.block {
135 Some(map) => current_map = map, 133 Some(block) => current_map = &block.parent,
136 None => return result, 134 None => return result,
137 } 135 }
138 } 136 }
@@ -193,14 +191,35 @@ impl DefMap {
193 self.resolve_name_in_module(db, original_module, &segment, prefer_module) 191 self.resolve_name_in_module(db, original_module, &segment, prefer_module)
194 } 192 }
195 PathKind::Super(lvl) => { 193 PathKind::Super(lvl) => {
196 let m = successors(Some(original_module), |m| self.modules[*m].parent) 194 let mut module = original_module;
197 .nth(lvl as usize); 195 for i in 0..lvl {
198 if let Some(local_id) = m { 196 match self.modules[module].parent {
199 PerNs::types(self.module_id(local_id).into(), Visibility::Public) 197 Some(it) => module = it,
200 } else { 198 None => match &self.block {
201 log::debug!("super path in root module"); 199 Some(block) => {
202 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 200 // Look up remaining path in parent `DefMap`
201 let new_path = ModPath {
202 kind: PathKind::Super(lvl - i),
203 segments: path.segments.clone(),
204 };
205 log::debug!("`super` path: {} -> {} in parent map", path, new_path);
206 return block.parent.resolve_path_fp_with_macro(
207 db,
208 mode,
209 block.parent_module,
210 &new_path,
211 shadow,
212 );
213 }
214 None => {
215 log::debug!("super path in root module");
216 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
217 }
218 },
219 }
203 } 220 }
221
222 PerNs::types(self.module_id(module).into(), Visibility::Public)
204 } 223 }
205 PathKind::Abs => { 224 PathKind::Abs => {
206 // 2018-style absolute path -- only extern prelude 225 // 2018-style absolute path -- only extern prelude
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 73e3a4702..b36d0b59b 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -8,12 +8,12 @@ mod block;
8 8
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use base_db::{fixture::WithFixture, SourceDatabase}; 11use base_db::{fixture::WithFixture, FilePosition, SourceDatabase};
12use expect_test::{expect, Expect}; 12use expect_test::{expect, Expect};
13use hir_expand::db::AstDatabase; 13use syntax::AstNode;
14use test_utils::mark; 14use test_utils::mark;
15 15
16use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 16use crate::{db::DefDatabase, nameres::*, test_db::TestDB, Lookup};
17 17
18fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { 18fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
19 let db = TestDB::with_files(ra_fixture); 19 let db = TestDB::with_files(ra_fixture);
@@ -23,14 +23,58 @@ fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> {
23 23
24fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> { 24fn compute_block_def_map(ra_fixture: &str) -> Arc<DefMap> {
25 let (db, position) = TestDB::with_position(ra_fixture); 25 let (db, position) = TestDB::with_position(ra_fixture);
26
27 // FIXME: perhaps we should make this use body lowering tests instead?
28
26 let module = db.module_for_file(position.file_id); 29 let module = db.module_for_file(position.file_id);
27 let ast_map = db.ast_id_map(position.file_id.into()); 30 let mut def_map = db.crate_def_map(module.krate);
28 let ast = db.parse(position.file_id); 31 while let Some(new_def_map) = descend_def_map_at_position(&db, position, def_map.clone()) {
29 let block: ast::BlockExpr = 32 def_map = new_def_map;
30 syntax::algo::find_node_at_offset(&ast.syntax_node(), position.offset).unwrap(); 33 }
31 let block_id = ast_map.ast_id(&block); 34
35 // FIXME: select the right module, not the root
36
37 def_map
38}
39
40fn descend_def_map_at_position(
41 db: &dyn DefDatabase,
42 position: FilePosition,
43 def_map: Arc<DefMap>,
44) -> Option<Arc<DefMap>> {
45 for (local_id, module_data) in def_map.modules() {
46 let mod_def = module_data.origin.definition_source(db);
47 let ast_map = db.ast_id_map(mod_def.file_id);
48 let item_tree = db.item_tree(mod_def.file_id);
49 let root = db.parse_or_expand(mod_def.file_id).unwrap();
50 for item in module_data.scope.declarations() {
51 match item {
52 ModuleDefId::FunctionId(it) => {
53 // Technically blocks can be inside any type (due to arrays and const generics),
54 // and also in const/static initializers. For tests we only really care about
55 // functions though.
56
57 let ast = ast_map.get(item_tree[it.lookup(db).id.value].ast_id).to_node(&root);
58
59 if ast.syntax().text_range().contains(position.offset) {
60 // Cursor inside function, descend into its body's DefMap.
61 // Note that we don't handle block *expressions* inside function bodies.
62 let ast_map = db.ast_id_map(position.file_id.into());
63 let ast_id = ast_map.ast_id(&ast.body().unwrap());
64 let block = BlockLoc {
65 ast_id: InFile::new(position.file_id.into(), ast_id),
66 module: def_map.module_id(local_id),
67 };
68 let block_id = db.intern_block(block);
69 return Some(db.block_def_map(block_id));
70 }
71 }
72 _ => continue,
73 }
74 }
75 }
32 76
33 db.block_def_map(module.krate, InFile::new(position.file_id.into(), block_id)) 77 None
34} 78}
35 79
36fn check(ra_fixture: &str, expect: Expect) { 80fn check(ra_fixture: &str, expect: Expect) {
diff --git a/crates/hir_def/src/nameres/tests/block.rs b/crates/hir_def/src/nameres/tests/block.rs
index 01d6326a7..470ca593e 100644
--- a/crates/hir_def/src/nameres/tests/block.rs
+++ b/crates/hir_def/src/nameres/tests/block.rs
@@ -95,3 +95,29 @@ fn outer() {
95 "#]], 95 "#]],
96 ); 96 );
97} 97}
98
99#[test]
100fn super_imports() {
101 check_at(
102 r#"
103mod module {
104 fn f() {
105 use super::Struct;
106 $0
107 }
108}
109
110struct Struct {}
111"#,
112 expect![[r#"
113 block scope
114 Struct: t
115 crate
116 Struct: t
117 module: t
118
119 crate::module
120 f: v
121 "#]],
122 );
123}