From 1956286368809718c70692e422893559ec487c62 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 17:11:44 +0100 Subject: Add expression scopes for blocks --- crates/hir_def/src/body/scope.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs index 49f1427b4..210b4a617 100644 --- a/crates/hir_def/src/body/scope.rs +++ b/crates/hir_def/src/body/scope.rs @@ -9,7 +9,7 @@ use crate::{ body::Body, db::DefDatabase, expr::{Expr, ExprId, Pat, PatId, Statement}, - DefWithBodyId, + BlockId, DefWithBodyId, }; pub type ScopeId = Idx; @@ -39,6 +39,7 @@ impl ScopeEntry { #[derive(Debug, PartialEq, Eq)] pub struct ScopeData { parent: Option, + block: Option, entries: Vec, } @@ -61,6 +62,11 @@ impl ExprScopes { &self.scopes[scope].entries } + /// If `scope` refers to a block expression scope, returns the corresponding `BlockId`. + pub fn block(&self, scope: ScopeId) -> Option { + self.scopes[scope].block + } + pub fn scope_chain(&self, scope: Option) -> impl Iterator + '_ { std::iter::successors(scope, move |&scope| self.scopes[scope].parent) } @@ -79,11 +85,15 @@ impl ExprScopes { } fn root_scope(&mut self) -> ScopeId { - self.scopes.alloc(ScopeData { parent: None, entries: vec![] }) + self.scopes.alloc(ScopeData { parent: None, block: None, entries: vec![] }) } fn new_scope(&mut self, parent: ScopeId) -> ScopeId { - self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] }) + self.scopes.alloc(ScopeData { parent: Some(parent), block: None, entries: vec![] }) + } + + fn new_block_scope(&mut self, parent: ScopeId, block: BlockId) -> ScopeId { + self.scopes.alloc(ScopeData { parent: Some(parent), block: Some(block), entries: vec![] }) } fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { @@ -136,7 +146,11 @@ fn compute_block_scopes( fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { scopes.set_scope(expr, scope); match &body[expr] { - Expr::Block { statements, tail, .. } => { + Expr::Block { statements, tail, id, .. } => { + let scope = scopes.new_block_scope(scope, *id); + // Overwrite the old scope for the block expr, so that every block scope can be found + // via the block itself (important for blocks that only contain items, no expressions). + scopes.set_scope(expr, scope); compute_block_scopes(&statements, *tail, body, scopes, scope); } Expr::For { iterable, pat, body: body_expr, .. } => { -- cgit v1.2.3 From 27f77060e2452fda5c2896c9b46feaa8399c3eae Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 17:22:57 +0100 Subject: Add `TestDB::module_at_position` --- crates/hir_def/src/body/tests.rs | 104 ++------------------------------------- crates/hir_def/src/test_db.rs | 99 +++++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 104 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index a92134ba7..bb43569d7 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs @@ -1,10 +1,10 @@ mod block; -use base_db::{fixture::WithFixture, FilePosition, SourceDatabase}; +use base_db::{fixture::WithFixture, SourceDatabase}; use expect_test::Expect; use test_utils::mark; -use crate::{test_db::TestDB, BlockId, ModuleDefId}; +use crate::{test_db::TestDB, ModuleDefId}; use super::*; @@ -37,104 +37,8 @@ fn check_diagnostics(ra_fixture: &str) { fn block_def_map_at(ra_fixture: &str) -> String { let (db, position) = crate::test_db::TestDB::with_position(ra_fixture); - let krate = db.crate_graph().iter().next().unwrap(); - let def_map = db.crate_def_map(krate); - - let mut block = - block_at_pos(&db, &def_map, position).expect("couldn't find enclosing function or block"); - loop { - let def_map = db.block_def_map(block).unwrap_or_else(|| def_map.clone()); - let new_block = block_at_pos(&db, &def_map, position); - match new_block { - Some(new_block) => { - assert_ne!(block, new_block); - block = new_block; - } - None => { - return def_map.dump(&db); - } - } - } -} - -fn block_at_pos(db: &dyn DefDatabase, def_map: &DefMap, position: FilePosition) -> Option { - // Find the smallest (innermost) function containing the cursor. - let mut size = None; - let mut fn_def = None; - for (_, module) in def_map.modules() { - let file_id = module.definition_source(db).file_id; - if file_id != position.file_id.into() { - continue; - } - let root = db.parse_or_expand(file_id).unwrap(); - let ast_map = db.ast_id_map(file_id); - let item_tree = db.item_tree(file_id); - for decl in module.scope.declarations() { - if let ModuleDefId::FunctionId(it) = decl { - let ast = ast_map.get(item_tree[it.lookup(db).id.value].ast_id).to_node(&root); - let range = ast.syntax().text_range(); - - if !range.contains(position.offset) { - continue; - } - - let new_size = match size { - None => range.len(), - Some(size) => { - if range.len() < size { - range.len() - } else { - size - } - } - }; - if size != Some(new_size) { - size = Some(new_size); - fn_def = Some(it); - } - } - } - } - - let (body, source_map) = db.body_with_source_map(fn_def?.into()); - - // Now find the smallest encompassing block expression in the function body. - let mut size = None; - let mut block_id = None; - for (expr_id, expr) in body.exprs.iter() { - if let Expr::Block { id, .. } = expr { - if let Ok(ast) = source_map.expr_syntax(expr_id) { - if ast.file_id != position.file_id.into() { - continue; - } - - let root = db.parse_or_expand(ast.file_id).unwrap(); - let ast = ast.value.to_node(&root); - let range = ast.syntax().text_range(); - - if !range.contains(position.offset) { - continue; - } - - let new_size = match size { - None => range.len(), - Some(size) => { - if range.len() < size { - range.len() - } else { - size - } - } - }; - if size != Some(new_size) { - size = Some(new_size); - block_id = Some(*id); - } - } - } - } - - Some(block_id.expect("can't find block containing cursor")) + let module = db.module_at_position(position); + module.def_map(&db).dump(&db) } fn check_at(ra_fixture: &str, expect: Expect) { diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 6665d902d..eda982c85 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs @@ -5,17 +5,17 @@ use std::{ sync::{Arc, Mutex}, }; -use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; +use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, Upcast}; use base_db::{AnchoredPath, SourceDatabase}; -use hir_expand::db::AstDatabase; use hir_expand::diagnostics::Diagnostic; use hir_expand::diagnostics::DiagnosticSinkBuilder; +use hir_expand::{db::AstDatabase, InFile}; use rustc_hash::FxHashMap; use rustc_hash::FxHashSet; -use syntax::{TextRange, TextSize}; +use syntax::{algo, ast, AstNode, TextRange, TextSize}; use test_utils::extract_annotations; -use crate::{db::DefDatabase, ModuleDefId, ModuleId}; +use crate::{db::DefDatabase, nameres::DefMap, Lookup, ModuleDefId, ModuleId}; #[salsa::database( base_db::SourceDatabaseExtStorage, @@ -84,6 +84,97 @@ impl TestDB { panic!("Can't find module for file") } + pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId { + let file_module = self.module_for_file(position.file_id); + let mut def_map = file_module.def_map(self); + + def_map = match self.block_at_position(&def_map, position) { + Some(it) => it, + None => return file_module, + }; + loop { + let new_map = self.block_at_position(&def_map, position); + match new_map { + Some(new_block) if !Arc::ptr_eq(&new_block, &def_map) => { + def_map = new_block; + } + _ => { + // FIXME: handle `mod` inside block expression + return def_map.module_id(def_map.root()); + } + } + } + } + + fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option> { + // Find the smallest (innermost) function in `def_map` containing the cursor. + let mut size = None; + let mut fn_def = None; + for (_, module) in def_map.modules() { + let file_id = module.definition_source(self).file_id; + if file_id != position.file_id.into() { + continue; + } + let root = self.parse_or_expand(file_id).unwrap(); + let ast_map = self.ast_id_map(file_id); + let item_tree = self.item_tree(file_id); + for decl in module.scope.declarations() { + if let ModuleDefId::FunctionId(it) = decl { + let ast = + ast_map.get(item_tree[it.lookup(self).id.value].ast_id).to_node(&root); + let range = ast.syntax().text_range(); + + if !range.contains(position.offset) { + continue; + } + + let new_size = match size { + None => range.len(), + Some(size) => { + if range.len() < size { + range.len() + } else { + size + } + } + }; + if size != Some(new_size) { + size = Some(new_size); + fn_def = Some(it); + } + } + } + } + + // Find the innermost block expression that has a `DefMap`. + let def_with_body = fn_def?.into(); + let (_, source_map) = self.body_with_source_map(def_with_body); + let scopes = self.expr_scopes(def_with_body); + let root = self.parse(position.file_id); + + let scope_iter = algo::ancestors_at_offset(&root.syntax_node(), position.offset) + .filter_map(|node| { + let block = ast::BlockExpr::cast(node)?; + let expr = ast::Expr::from(block); + let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?; + let scope = scopes.scope_for(expr_id).unwrap(); + Some(scope) + }); + + for scope in scope_iter { + let containing_blocks = + scopes.scope_chain(Some(scope)).filter_map(|scope| scopes.block(scope)); + + for block in containing_blocks { + if let Some(def_map) = self.block_def_map(block) { + return Some(def_map); + } + } + } + + None + } + pub(crate) fn log(&self, f: impl FnOnce()) -> Vec { *self.events.lock().unwrap() = Some(Vec::new()); f(); -- cgit v1.2.3 From b9c213da7abcb49e59ecdb630653ae61b4d5c8f2 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 17:23:25 +0100 Subject: Make `with_ancestor_maps` public --- crates/hir_def/src/nameres.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index ad2e9bcac..34ff07f3c 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs @@ -316,7 +316,7 @@ impl DefMap { /// /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns /// `None`, iteration continues. - fn with_ancestor_maps( + pub fn with_ancestor_maps( &self, db: &dyn DefDatabase, local_mod: LocalModuleId, -- cgit v1.2.3 From 7067a22e1c1ab9041475359922d1863f7d9a4f5c Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 17:24:43 +0100 Subject: Add another block def map test --- crates/hir_def/src/body/tests/block.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs index b599c6269..a5ec0883f 100644 --- a/crates/hir_def/src/body/tests/block.rs +++ b/crates/hir_def/src/body/tests/block.rs @@ -232,3 +232,30 @@ fn f() { "#]], ) } + +#[test] +fn super_does_not_resolve_to_block_module() { + check_at( + r#" +fn main() { + struct Struct {} + mod module { + use super::Struct; + + $0 + } +} + "#, + expect![[r#" + block scope + Struct: t + module: t + + block scope::module + Struct: _ + + crate + main: v + "#]], + ); +} -- cgit v1.2.3 From 34ad3d629a75c8bbc419c0159c213901ce8ad28d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 17:25:03 +0100 Subject: Teach `find_path` about inner items --- crates/hir_def/src/find_path.rs | 101 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 10 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index aa2c6e04e..5e2a711b8 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs @@ -13,8 +13,6 @@ use crate::{ ModuleDefId, ModuleId, }; -// FIXME: handle local items - /// Find a path that can be used to refer to a certain item. This can depend on /// *from where* you're referring to the item, hence the `from` parameter. pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option { @@ -107,9 +105,9 @@ fn find_path_inner( // - if the item is already in scope, return the name under which it is let def_map = from.def_map(db); - let from_scope: &crate::item_scope::ItemScope = &def_map[from.local_id].scope; - let scope_name = - if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None }; + let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone()) + }); if prefixed.is_none() && scope_name.is_some() { return scope_name .map(|scope_name| ModPath::from_segments(PathKind::Plain, vec![scope_name])); @@ -117,7 +115,7 @@ fn find_path_inner( // - if the item is the crate root, return `crate` let root = def_map.module_id(def_map.root()); - if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) { + if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() { return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); } @@ -230,7 +228,12 @@ fn find_path_inner( } } - if let Some(prefix) = prefixed.map(PrefixKind::prefix) { + if let Some(mut prefix) = prefixed.map(PrefixKind::prefix) { + if matches!(prefix, PathKind::Crate | PathKind::Super(0)) && def_map.block_id().is_some() { + // Inner items cannot be referred to via `crate::` or `self::` paths. + prefix = PathKind::Plain; + } + best_path.or_else(|| { scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name])) }) @@ -358,14 +361,14 @@ mod tests { /// module the cursor is in. fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option) { let (db, pos) = TestDB::with_position(ra_fixture); - let module = db.module_for_file(pos.file_id); + let module = db.module_at_position(pos); let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); let ast_path = parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); - let crate_def_map = module.def_map(&db); - let resolved = crate_def_map + let def_map = module.def_map(&db); + let resolved = def_map .resolve_path( &db, module.local_id, @@ -788,4 +791,82 @@ mod tests { check_found_path(code, "u8", "u8", "u8", "u8"); check_found_path(code, "u16", "u16", "u16", "u16"); } + + #[test] + fn inner_items() { + check_found_path( + r#" + fn main() { + struct Inner {} + $0 + } + "#, + "Inner", + "Inner", + "Inner", + "Inner", + ); + } + + #[test] + fn inner_items_from_outer_scope() { + check_found_path( + r#" + fn main() { + struct Struct {} + { + $0 + } + } + "#, + "Struct", + "Struct", + "Struct", + "Struct", + ); + } + + #[test] + fn inner_items_from_inner_module() { + check_found_path( + r#" + fn main() { + mod module { + struct Struct {} + } + { + $0 + } + } + "#, + "module::Struct", + "module::Struct", + "module::Struct", + "module::Struct", + ); + } + + #[test] + #[ignore] + fn inner_items_from_parent_module() { + // FIXME: ItemTree currently associates all inner items with `main`. Luckily, this sort of + // code is very rare, so this isn't terrible. + // To fix it, we should probably build dedicated `ItemTree`s for inner items, and not store + // them in the file's main ItemTree. This would also allow us to stop parsing function + // bodies when we only want to compute the crate's main DefMap. + check_found_path( + r#" + fn main() { + struct Struct {} + mod module { + $0 + } + } + "#, + "super::Struct", + "super::Struct", + "super::Struct", + "super::Struct", + ); + } } -- cgit v1.2.3 From e16d9dc5bd78dc0d2139367f25b403926f682df9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 17:27:04 +0100 Subject: Use `block_def_map` in `Resolver` This required a few changes to not bail out immediately if a `ModuleScope` doesn't resolve a path. The `LocalItemsScope` hack is now removed. --- crates/hir_def/src/resolver.rs | 215 +++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 118 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index f9ad50301..e293aa425 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs @@ -10,7 +10,6 @@ use rustc_hash::FxHashSet; use crate::{ body::scope::{ExprScopes, ScopeId}, - body::Body, builtin_type::BuiltinType, db::DefDatabase, expr::{ExprId, PatId}, @@ -58,8 +57,6 @@ enum Scope { AdtScope(AdtId), /// Local bindings ExprScope(ExprScope), - /// Temporary hack to support local items. - LocalItemsScope(Arc), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -169,13 +166,7 @@ impl Resolver { for scope in self.scopes.iter().rev() { match scope { Scope::ExprScope(_) => continue, - Scope::GenericParams { .. } - | Scope::ImplDefScope(_) - | Scope::LocalItemsScope(_) - if skip_to_mod => - { - continue - } + Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue, Scope::GenericParams { params, def } => { if let Some(local_id) = params.find_type_by_name(first_name) { @@ -199,41 +190,13 @@ impl Resolver { } } Scope::ModuleScope(m) => { - let (module_def, idx) = m.crate_def_map.resolve_path( - db, - m.module_id, - &path, - BuiltinShadowMode::Other, - ); - let res = to_type_ns(module_def)?; - return Some((res, idx)); - } - Scope::LocalItemsScope(body) => { - let def = body.item_scope.get(first_name); - if let Some(res) = to_type_ns(def) { - return Some((res, None)); + if let Some(res) = m.resolve_path_in_type_ns(db, path) { + return Some(res); } } } } - return None; - fn to_type_ns(per_ns: PerNs) -> Option { - let res = match per_ns.take_types()? { - ModuleDefId::AdtId(it) => TypeNs::AdtId(it), - ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), - - ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), - ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), - - ModuleDefId::TraitId(it) => TypeNs::TraitId(it), - - ModuleDefId::FunctionId(_) - | ModuleDefId::ConstId(_) - | ModuleDefId::StaticId(_) - | ModuleDefId::ModuleId(_) => return None, - }; - Some(res) - } + None } pub fn resolve_path_in_type_ns_fully( @@ -280,7 +243,6 @@ impl Resolver { | Scope::ExprScope(_) | Scope::GenericParams { .. } | Scope::ImplDefScope(_) - | Scope::LocalItemsScope(_) if skip_to_mod => { continue @@ -335,63 +297,14 @@ impl Resolver { } Scope::ModuleScope(m) => { - let (module_def, idx) = m.crate_def_map.resolve_path( - db, - m.module_id, - &path, - BuiltinShadowMode::Other, - ); - return match idx { - None => { - let value = to_value_ns(module_def)?; - Some(ResolveValueResult::ValueNs(value)) - } - Some(idx) => { - let ty = match module_def.take_types()? { - ModuleDefId::AdtId(it) => TypeNs::AdtId(it), - ModuleDefId::TraitId(it) => TypeNs::TraitId(it), - ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), - ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), - - ModuleDefId::ModuleId(_) - | ModuleDefId::FunctionId(_) - | ModuleDefId::EnumVariantId(_) - | ModuleDefId::ConstId(_) - | ModuleDefId::StaticId(_) => return None, - }; - Some(ResolveValueResult::Partial(ty, idx)) - } - }; - } - Scope::LocalItemsScope(body) => { - // we don't bother looking in the builtin scope here because there are no builtin values - let def = to_value_ns(body.item_scope.get(first_name)); - - if let Some(res) = def { - return Some(ResolveValueResult::ValueNs(res)); + if let Some(def) = m.resolve_path_in_value_ns(db, path) { + return Some(def); } } } } - return None; - - fn to_value_ns(per_ns: PerNs) -> Option { - let res = match per_ns.take_values()? { - ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), - ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it), - ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it), - ModuleDefId::ConstId(it) => ValueNs::ConstId(it), - ModuleDefId::StaticId(it) => ValueNs::StaticId(it), - - ModuleDefId::AdtId(AdtId::EnumId(_)) - | ModuleDefId::AdtId(AdtId::UnionId(_)) - | ModuleDefId::TraitId(_) - | ModuleDefId::TypeAliasId(_) - | ModuleDefId::BuiltinType(_) - | ModuleDefId::ModuleId(_) => return None, - }; - Some(res) - } + + None } pub fn resolve_path_in_value_ns_fully( @@ -410,11 +323,6 @@ impl Resolver { db: &dyn DefDatabase, path: &ModPath, ) -> Option { - // Search item scope legacy macro first - if let Some(def) = self.resolve_local_macro_def(path) { - return Some(def); - } - let (item_map, module) = self.module_scope()?; item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() } @@ -447,16 +355,6 @@ impl Resolver { }) } - fn resolve_local_macro_def(&self, path: &ModPath) -> Option { - let name = path.as_ident()?; - self.scopes.iter().rev().find_map(|scope| { - if let Scope::LocalItemsScope(body) = scope { - return body.item_scope.get_legacy_macro(name); - } - None - }) - } - pub fn module(&self) -> Option { let (def_map, local_id) = self.module_scope()?; Some(def_map.module_id(local_id)) @@ -538,9 +436,6 @@ impl Scope { }); } } - Scope::LocalItemsScope(body) => body.item_scope.entries().for_each(|(name, def)| { - f(name.clone(), ScopeDef::PerNs(def)); - }), &Scope::GenericParams { ref params, def: parent } => { for (local_id, param) in params.types.iter() { if let Some(ref name) = param.name { @@ -584,10 +479,19 @@ pub fn resolver_for_scope( scope_id: Option, ) -> Resolver { let mut r = owner.resolver(db); - r = r.push_local_items_scope(db.body(owner)); let scopes = db.expr_scopes(owner); let scope_chain = scopes.scope_chain(scope_id).collect::>(); for scope in scope_chain.into_iter().rev() { + if let Some(block) = scopes.block(scope) { + if let Some(def_map) = db.block_def_map(block) { + let root = def_map.root(); + r = r.push_module_scope(def_map, root); + // FIXME: This adds as many module scopes as there are blocks, but resolving in each + // already traverses all parents, so this is O(n²). I think we could only store the + // innermost module scope instead? + } + } + r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); } r @@ -612,10 +516,6 @@ impl Resolver { self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) } - fn push_local_items_scope(self, body: Arc) -> Resolver { - self.push_scope(Scope::LocalItemsScope(body)) - } - fn push_expr_scope( self, owner: DefWithBodyId, @@ -626,6 +526,85 @@ impl Resolver { } } +impl ModuleItemMap { + pub fn resolve_path_in_value_ns( + &self, + db: &dyn DefDatabase, + path: &ModPath, + ) -> Option { + let (module_def, idx) = + self.crate_def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); + return match idx { + None => { + let value = to_value_ns(module_def)?; + Some(ResolveValueResult::ValueNs(value)) + } + Some(idx) => { + let ty = match module_def.take_types()? { + ModuleDefId::AdtId(it) => TypeNs::AdtId(it), + ModuleDefId::TraitId(it) => TypeNs::TraitId(it), + ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), + ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), + + ModuleDefId::ModuleId(_) + | ModuleDefId::FunctionId(_) + | ModuleDefId::EnumVariantId(_) + | ModuleDefId::ConstId(_) + | ModuleDefId::StaticId(_) => return None, + }; + Some(ResolveValueResult::Partial(ty, idx)) + } + }; + } + + pub fn resolve_path_in_type_ns( + &self, + db: &dyn DefDatabase, + path: &ModPath, + ) -> Option<(TypeNs, Option)> { + let (module_def, idx) = + self.crate_def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); + let res = to_type_ns(module_def)?; + Some((res, idx)) + } +} + +fn to_value_ns(per_ns: PerNs) -> Option { + let res = match per_ns.take_values()? { + ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), + ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it), + ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it), + ModuleDefId::ConstId(it) => ValueNs::ConstId(it), + ModuleDefId::StaticId(it) => ValueNs::StaticId(it), + + ModuleDefId::AdtId(AdtId::EnumId(_)) + | ModuleDefId::AdtId(AdtId::UnionId(_)) + | ModuleDefId::TraitId(_) + | ModuleDefId::TypeAliasId(_) + | ModuleDefId::BuiltinType(_) + | ModuleDefId::ModuleId(_) => return None, + }; + Some(res) +} + +fn to_type_ns(per_ns: PerNs) -> Option { + let res = match per_ns.take_types()? { + ModuleDefId::AdtId(it) => TypeNs::AdtId(it), + ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), + + ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), + ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), + + ModuleDefId::TraitId(it) => TypeNs::TraitId(it), + + ModuleDefId::FunctionId(_) + | ModuleDefId::ConstId(_) + | ModuleDefId::StaticId(_) + | ModuleDefId::ModuleId(_) => return None, + }; + Some(res) +} + pub trait HasResolver: Copy { /// Builds a resolver for type references inside this def. fn resolver(self, db: &dyn DefDatabase) -> Resolver; -- cgit v1.2.3 From 51f68863b19b7499e4257dfcb39a40d69cbc9f97 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 17:36:10 +0100 Subject: Remove `pub` --- crates/hir_def/src/resolver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index e293aa425..ef0b751b1 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs @@ -527,7 +527,7 @@ impl Resolver { } impl ModuleItemMap { - pub fn resolve_path_in_value_ns( + fn resolve_path_in_value_ns( &self, db: &dyn DefDatabase, path: &ModPath, @@ -557,7 +557,7 @@ impl ModuleItemMap { }; } - pub fn resolve_path_in_type_ns( + fn resolve_path_in_type_ns( &self, db: &dyn DefDatabase, path: &ModPath, -- cgit v1.2.3 From 85906aa304c2265f3ae692d62306ba07694ece45 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 9 Feb 2021 18:40:05 +0100 Subject: Remove unneeded return --- crates/hir_def/src/resolver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index ef0b751b1..a8467c88e 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs @@ -534,7 +534,7 @@ impl ModuleItemMap { ) -> Option { let (module_def, idx) = self.crate_def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); - return match idx { + match idx { None => { let value = to_value_ns(module_def)?; Some(ResolveValueResult::ValueNs(value)) @@ -554,7 +554,7 @@ impl ModuleItemMap { }; Some(ResolveValueResult::Partial(ty, idx)) } - }; + } } fn resolve_path_in_type_ns( -- cgit v1.2.3