From c0aeb5204c010a11db2015113a7858b517415de1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 18 Jan 2019 16:36:56 +0300 Subject: switched to lowerd module --- crates/ra_hir/src/code_model_api.rs | 11 +- crates/ra_hir/src/code_model_impl/module.rs | 17 ++- crates/ra_hir/src/db.rs | 23 ++- crates/ra_hir/src/nameres.rs | 44 +++--- crates/ra_hir/src/nameres/lower.rs | 213 +++++++++++++++++++++++++--- crates/ra_hir/src/path.rs | 25 ++-- crates/ra_hir/src/query_definitions.rs | 2 +- 7 files changed, 277 insertions(+), 58 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 0cf7deac9..865e5e809 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -7,7 +7,7 @@ use ra_syntax::{ast, TreeArc, SyntaxNode}; use crate::{ Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId, type_ref::TypeRef, - nameres::ModuleScope, + nameres::{ModuleScope, lower::LoweredImport}, db::HirDatabase, expr::BodySyntaxMapping, ty::InferenceResult, @@ -96,6 +96,15 @@ impl Module { self.declaration_source_impl(db) } + /// Returns the syntax of the last path segment corresponding to this import + pub fn import_source( + &self, + db: &impl HirDatabase, + import: LoweredImport, + ) -> TreeArc { + self.import_source_impl(db, import) + } + /// Returns the crate this module is part of. pub fn krate(&self, db: &impl HirDatabase) -> Option { self.krate_impl(db) diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index a5c032d69..f110548c6 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs @@ -5,7 +5,7 @@ use crate::{ Module, ModuleSource, Problem, Crate, DefId, DefLoc, DefKind, Name, Path, PathKind, PerNs, Def, module_tree::ModuleId, - nameres::ModuleScope, + nameres::{ModuleScope, lower::LoweredImport}, db::HirDatabase, }; @@ -37,7 +37,7 @@ impl Module { Some(link.name(&module_tree).clone()) } - pub fn definition_source_impl(&self, db: &impl HirDatabase) -> (FileId, ModuleSource) { + pub(crate) fn definition_source_impl(&self, db: &impl HirDatabase) -> (FileId, ModuleSource) { let loc = self.def_id.loc(db); let file_id = loc.source_item_id.file_id.as_original_file(); let syntax_node = db.file_item(loc.source_item_id); @@ -50,7 +50,7 @@ impl Module { (file_id, module_source) } - pub fn declaration_source_impl( + pub(crate) fn declaration_source_impl( &self, db: &impl HirDatabase, ) -> Option<(FileId, TreeArc)> { @@ -66,6 +66,17 @@ impl Module { Some((file_id, src)) } + pub(crate) fn import_source_impl( + &self, + db: &impl HirDatabase, + import: LoweredImport, + ) -> TreeArc { + let loc = self.def_id.loc(db); + let source_map = db.lower_module_source_map(loc.source_root_id, loc.module_id); + let (_, source) = self.definition_source(db); + source_map.get(&source, import) + } + pub(crate) fn krate_impl(&self, db: &impl HirDatabase) -> Option { let root = self.crate_root(db); let loc = root.def_id.loc(db); diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 4a3e0fed2..ccc53c454 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -10,7 +10,7 @@ use crate::{ FnSignature, FnScopes, macros::MacroExpansion, module_tree::{ModuleId, ModuleTree}, - nameres::{ItemMap, lower::InputModuleItems}, + nameres::{ItemMap, lower::{InputModuleItems, LoweredModule, ImportSourceMap}}, ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks}, adt::{StructData, EnumData, EnumVariantData}, impl_block::ModuleImplBlocks, @@ -65,6 +65,27 @@ pub trait HirDatabase: module_id: ModuleId, ) -> Arc; + #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] + fn lower_module( + &self, + source_root_id: SourceRootId, + module_id: ModuleId, + ) -> (Arc, Arc); + + #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_module_query)] + fn lower_module_module( + &self, + source_root_id: SourceRootId, + module_id: ModuleId, + ) -> Arc; + + #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_source_map_query)] + fn lower_module_source_map( + &self, + source_root_id: SourceRootId, + module_id: ModuleId, + ) -> Arc; + #[salsa::invoke(query_definitions::item_map)] fn item_map(&self, source_root_id: SourceRootId) -> Arc; diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index aea95e08c..ab0a9041d 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -60,7 +60,7 @@ pub struct Resolution { /// None for unresolved pub def_id: PerNs, /// ident by whitch this is imported into local scope. - pub import: Option, + pub import: Option, } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -151,10 +151,10 @@ impl PerNs { pub(crate) struct Resolver<'a, DB> { db: &'a DB, - input: &'a FxHashMap>, + input: &'a FxHashMap>, source_root: SourceRootId, module_tree: Arc, - processed_imports: FxHashSet<(ModuleId, usize)>, + processed_imports: FxHashSet<(ModuleId, LoweredImport)>, result: ItemMap, } @@ -164,7 +164,7 @@ where { pub(crate) fn new( db: &'a DB, - input: &'a FxHashMap>, + input: &'a FxHashMap>, source_root: SourceRootId, module_tree: Arc, ) -> Resolver<'a, DB> { @@ -197,7 +197,7 @@ where self.result } - fn populate_module(&mut self, module_id: ModuleId, input: Arc) { + fn populate_module(&mut self, module_id: ModuleId, input: Arc) { let mut module_items = ModuleScope::default(); // Populate extern crates prelude @@ -220,14 +220,14 @@ where } }; } - for import in input.imports.iter() { - if let Some(name) = import.path.segments.iter().last() { - if let ImportKind::Named(import) = import.kind { + for (import_id, import_data) in input.imports.iter() { + if let Some(name) = import_data.path.segments.iter().last() { + if !import_data.is_glob { module_items.items.insert( name.clone(), Resolution { def_id: PerNs::none(), - import: Some(import), + import: Some(import_id), }, ); } @@ -281,23 +281,27 @@ where } fn resolve_imports(&mut self, module_id: ModuleId) { - for (i, import) in self.input[&module_id].imports.iter().enumerate() { - if self.processed_imports.contains(&(module_id, i)) { + for (import_id, import_data) in self.input[&module_id].imports.iter() { + if self.processed_imports.contains(&(module_id, import_id)) { // already done continue; } - if self.resolve_import(module_id, import) { - log::debug!("import {:?} resolved (or definite error)", import); - self.processed_imports.insert((module_id, i)); + if self.resolve_import(module_id, import_id, import_data) { + log::debug!("import {:?} resolved (or definite error)", import_id); + self.processed_imports.insert((module_id, import_id)); } } } - fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> bool { + fn resolve_import( + &mut self, + module_id: ModuleId, + import_id: LoweredImport, + import: &ImportData, + ) -> bool { log::debug!("resolving import: {:?}", import); - let ptr = match import.kind { - ImportKind::Glob => return false, - ImportKind::Named(ptr) => ptr, + if import.is_glob { + return false; }; let mut curr: ModuleId = match import.path.kind { @@ -358,7 +362,7 @@ where self.update(module_id, |items| { let res = Resolution { def_id, - import: Some(ptr), + import: Some(import_id), }; items.items.insert(name.clone(), res); }); @@ -394,7 +398,7 @@ where self.update(module_id, |items| { let res = Resolution { def_id, - import: Some(ptr), + import: Some(import_id), }; items.items.insert(name.clone(), res); }) diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index 35bdbafbf..6bca14444 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs @@ -1,10 +1,11 @@ use std::sync::Arc; use ra_syntax::{ - TextRange, SyntaxKind, AstNode, + TextRange, SyntaxKind, AstNode, SourceFile, TreeArc, ast::{self, ModuleItemOwner}, }; -use ra_db::{FileId, SourceRootId}; +use ra_db::{SourceRootId, LocalSyntaxPtr}; +use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; use crate::{ SourceItemId, SourceFileItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems, @@ -139,12 +140,12 @@ impl InputModuleItems { fn add_use_item(&mut self, file_items: &SourceFileItems, item: &ast::UseItem) { let file_item_id = file_items.id_of_unchecked(item.syntax()); let start_offset = item.syntax().range().start(); - Path::expand_use_item(item, |path, range| { - let kind = match range { + Path::expand_use_item(item, |path, segment| { + let kind = match segment { None => ImportKind::Glob, - Some(range) => ImportKind::Named(NamedImport { + Some(segment) => ImportKind::Named(NamedImport { file_item_id, - relative_range: range - start_offset, + relative_range: segment.syntax().range() - start_offset, }), }; self.imports.push(Import { kind, path }) @@ -199,22 +200,194 @@ pub struct NamedImport { pub relative_range: TextRange, } -impl NamedImport { - // FIXME: this is only here for one use-case in completion. Seems like a - // pretty gross special case. - pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange { - let source_item_id = SourceItemId { - file_id: file_id.into(), - item_id: Some(self.file_item_id), - }; - let syntax = db.file_item(source_item_id); - let offset = syntax.range().start(); - self.relative_range + offset - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub(super) enum ImportKind { Glob, Named(NamedImport), } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct LoweredImport(RawId); +impl_arena_id!(LoweredImport); + +#[derive(Debug, PartialEq, Eq)] +pub(super) struct ImportData { + pub(super) path: Path, + pub(super) is_glob: bool, +} + +#[derive(Debug, Default, PartialEq, Eq)] +pub struct LoweredModule { + pub(super) items: Vec, + pub(super) imports: Arena, +} + +#[derive(Debug, Default, PartialEq, Eq)] +pub struct ImportSourceMap { + map: ArenaMap, +} + +impl ImportSourceMap { + fn insert(&mut self, import: LoweredImport, segment: &ast::PathSegment) { + self.map + .insert(import, LocalSyntaxPtr::new(segment.syntax())) + } + + pub fn get(&self, source: &ModuleSource, import: LoweredImport) -> TreeArc { + let file = match source { + ModuleSource::SourceFile(file) => &*file, + ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), + }; + + ast::PathSegment::cast(&self.map[import].resolve(file)) + .unwrap() + .to_owned() + } +} + +impl LoweredModule { + pub(crate) fn lower_module_module_query( + db: &impl HirDatabase, + source_root_id: SourceRootId, + module_id: ModuleId, + ) -> Arc { + db.lower_module(source_root_id, module_id).0 + } + + pub(crate) fn lower_module_source_map_query( + db: &impl HirDatabase, + source_root_id: SourceRootId, + module_id: ModuleId, + ) -> Arc { + db.lower_module(source_root_id, module_id).1 + } + + pub(crate) fn lower_module_query( + db: &impl HirDatabase, + source_root_id: SourceRootId, + module_id: ModuleId, + ) -> (Arc, Arc) { + let module_tree = db.module_tree(source_root_id); + let source = module_id.source(&module_tree); + let file_id = source.file_id; + let source = ModuleSource::from_source_item_id(db, source); + let mut source_map = ImportSourceMap::default(); + let mut res = LoweredModule::default(); + match source { + ModuleSource::SourceFile(it) => res.fill( + &mut source_map, + db, + source_root_id, + module_id, + file_id, + &mut it.items_with_macros(), + ), + ModuleSource::Module(it) => { + if let Some(item_list) = it.item_list() { + res.fill( + &mut source_map, + db, + source_root_id, + module_id, + file_id, + &mut item_list.items_with_macros(), + ) + } + } + }; + (Arc::new(res), Arc::new(source_map)) + } + + fn fill( + &mut self, + source_map: &mut ImportSourceMap, + db: &impl HirDatabase, + source_root_id: SourceRootId, + module_id: ModuleId, + file_id: HirFileId, + items: &mut Iterator, + ) { + let file_items = db.file_items(file_id); + + for item in items { + match item { + ast::ItemOrMacro::Item(it) => { + self.add_item(source_map, file_id, &file_items, it); + } + ast::ItemOrMacro::Macro(macro_call) => { + let item_id = file_items.id_of_unchecked(macro_call.syntax()); + let loc = MacroCallLoc { + source_root_id, + module_id, + source_item_id: SourceItemId { + file_id, + item_id: Some(item_id), + }, + }; + let id = loc.id(db); + let file_id = HirFileId::from(id); + let file_items = db.file_items(file_id); + //FIXME: expand recursively + for item in db.hir_source_file(file_id).items() { + self.add_item(source_map, file_id, &file_items, item); + } + } + } + } + } + + fn add_item( + &mut self, + source_map: &mut ImportSourceMap, + file_id: HirFileId, + file_items: &SourceFileItems, + item: &ast::ModuleItem, + ) -> Option<()> { + match item.kind() { + ast::ModuleItemKind::StructDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::EnumDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::FnDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::TraitDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::TypeDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::ImplBlock(_) => { + // impls don't define items + } + ast::ModuleItemKind::UseItem(it) => self.add_use_item(source_map, it), + ast::ModuleItemKind::ExternCrateItem(_) => { + // TODO + } + ast::ModuleItemKind::ConstDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::StaticDef(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + ast::ModuleItemKind::Module(it) => { + self.items.push(ModuleItem::new(file_id, file_items, it)?) + } + } + Some(()) + } + + fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { + Path::expand_use_item(item, |path, segment| { + let import = self.imports.alloc(ImportData { + path, + is_glob: segment.is_none(), + }); + if let Some(segment) = segment { + source_map.insert(import, segment) + } + }) + } +} diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 370e10bb8..7b0ce3b61 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -1,4 +1,4 @@ -use ra_syntax::{ast, AstNode, TextRange}; +use ra_syntax::{ast, AstNode}; use crate::{Name, AsName}; @@ -18,7 +18,10 @@ pub enum PathKind { impl Path { /// Calls `cb` with all paths, represented by this use item. - pub fn expand_use_item(item: &ast::UseItem, mut cb: impl FnMut(Path, Option)) { + pub fn expand_use_item<'a>( + item: &'a ast::UseItem, + mut cb: impl FnMut(Path, Option<&'a ast::PathSegment>), + ) { if let Some(tree) = item.use_tree() { expand_use_tree(None, tree, &mut cb); } @@ -98,10 +101,10 @@ impl From for Path { } } -fn expand_use_tree( +fn expand_use_tree<'a>( prefix: Option, - tree: &ast::UseTree, - cb: &mut impl FnMut(Path, Option), + tree: &'a ast::UseTree, + cb: &mut impl FnMut(Path, Option<&'a ast::PathSegment>), ) { if let Some(use_tree_list) = tree.use_tree_list() { let prefix = match tree.path() { @@ -125,20 +128,18 @@ fn expand_use_tree( if let Some(segment) = ast_path.segment() { if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { if let Some(prefix) = prefix { - cb(prefix, Some(segment.syntax().range())); + cb(prefix, Some(segment)); return; } } } } if let Some(path) = convert_path(prefix, ast_path) { - let range = if tree.has_star() { - None - } else { - let range = ast_path.segment().unwrap().syntax().range(); - Some(range) + if tree.has_star() { + cb(path, None) + } else if let Some(segment) = ast_path.segment() { + cb(path, Some(segment)) }; - cb(path, range) } // TODO: report errors somewhere // We get here if we do diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index 985a02410..074153862 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs @@ -46,7 +46,7 @@ pub(super) fn item_map(db: &impl HirDatabase, source_root: SourceRootId) -> Arc< let module_tree = db.module_tree(source_root); let input = module_tree .modules() - .map(|id| (id, db.input_module_items(source_root, id))) + .map(|id| (id, db.lower_module_module(source_root, id))) .collect::>(); let resolver = Resolver::new(db, &input, source_root, module_tree); -- cgit v1.2.3