From 758bc72873efe36f579236d1abf240d14866fd82 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 23 Jan 2019 23:08:41 +0100 Subject: Implement methods to build a resolver --- crates/ra_hir/src/code_model_api.rs | 22 +++++- crates/ra_hir/src/expr.rs | 129 +++++++++++++++++++++--------------- crates/ra_hir/src/expr/scope.rs | 11 ++- crates/ra_hir/src/impl_block.rs | 45 ++++++++----- crates/ra_hir/src/resolve.rs | 32 ++++++++- 5 files changed, 166 insertions(+), 73 deletions(-) diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 73541a8c3..b8ca04c5c 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -184,9 +184,9 @@ impl Module { self.problems_impl(db) } - #[allow(unused_variables)] pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { - unimplemented!() + let item_map = db.item_map(self.krate); + Resolver::default().push_module_scope(item_map, self.module_id) } } @@ -480,6 +480,24 @@ impl Function { pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc { db.generic_params((*self).into()) } + + // TODO move to a more general type for 'body-having' items + /// Builds a resolver for code inside this item. + pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { + // take the outer scope... + let r = self + .impl_block(db) + .map(|ib| ib.resolver(db)) + .unwrap_or_else(|| self.module(db).resolver(db)); + // ...and add generic params, if present + let p = self.generic_params(db); + let r = if !p.params.is_empty() { + r.push_generic_params_scope(p) + } else { + r + }; + r + } } impl Docs for Function { diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 6d124fe2f..c09d3fbf9 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -27,6 +27,9 @@ impl_arena_id!(ExprId); /// The body of an item (function, const etc.). #[derive(Debug, Eq, PartialEq)] pub struct Body { + // TODO: this should be more general, consts & statics also have bodies + /// The Function of the item this body belongs to + owner: Function, exprs: Arena, pats: Arena, /// The patterns for the function's parameters. While the parameter types are @@ -63,12 +66,26 @@ impl Body { self.body_expr } - #[allow(unused_variables)] - pub fn resolver_for_expr(&self, expr_id: ExprId) -> Resolver { - unimplemented!() + pub fn owner(&self) -> Function { + self.owner } } +// needs arbitrary_self_types to be a method... or maybe move to the def? +#[allow(dead_code)] +pub fn resolver_for_expr(body: Arc, db: &impl HirDatabase, expr_id: ExprId) -> Resolver { + let mut r = body.owner.resolver(db); + if !body.params.is_empty() { + r = r.push_function_params(Arc::clone(&body)); + } + let scopes = db.expr_scopes(body.owner); + let scope_chain = scopes.scope_chain_for(expr_id).collect::>(); + for scope in scope_chain.into_iter().rev() { + r = r.push_expr_scope(Arc::clone(&scopes), scope); + } + r +} + impl Index for Body { type Output = Expr; @@ -453,23 +470,29 @@ pub(crate) fn body_hir(db: &impl HirDatabase, func: Function) -> Arc { } struct ExprCollector { + owner: Function, exprs: Arena, pats: Arena, expr_syntax_mapping: FxHashMap, expr_syntax_mapping_back: ArenaMap, pat_syntax_mapping: FxHashMap, pat_syntax_mapping_back: ArenaMap, + params: Vec, + body_expr: Option, } impl ExprCollector { - fn new() -> Self { + fn new(owner: Function) -> Self { ExprCollector { + owner, exprs: Arena::default(), pats: Arena::default(), expr_syntax_mapping: FxHashMap::default(), expr_syntax_mapping_back: ArenaMap::default(), pat_syntax_mapping: FxHashMap::default(), pat_syntax_mapping_back: ArenaMap::default(), + params: Vec::new(), + body_expr: None, } } @@ -907,10 +930,7 @@ impl ExprCollector { }); fields.extend(iter); - Pat::Struct { - path: path, - args: fields, - } + Pat::Struct { path, args: fields } } // TODO: implement @@ -928,12 +948,48 @@ impl ExprCollector { } } - fn into_body_syntax_mapping(self, params: Vec, body_expr: ExprId) -> BodySyntaxMapping { + fn collect_fn_body(&mut self, node: &ast::FnDef) { + if let Some(param_list) = node.param_list() { + if let Some(self_param) = param_list.self_param() { + let self_param = SyntaxNodePtr::new( + self_param + .self_kw() + .expect("self param without self keyword") + .syntax(), + ); + let param_pat = self.alloc_pat( + Pat::Bind { + name: Name::self_param(), + mode: BindingAnnotation::Unannotated, + subpat: None, + }, + self_param, + ); + self.params.push(param_pat); + } + + for param in param_list.params() { + let pat = if let Some(pat) = param.pat() { + pat + } else { + continue; + }; + let param_pat = self.collect_pat(pat); + self.params.push(param_pat); + } + }; + + let body = self.collect_block_opt(node.body()); + self.body_expr = Some(body); + } + + fn into_body_syntax_mapping(self) -> BodySyntaxMapping { let body = Body { + owner: self.owner, exprs: self.exprs, pats: self.pats, - params, - body_expr, + params: self.params, + body_expr: self.body_expr.expect("A body should have been collected"), }; BodySyntaxMapping { body: Arc::new(body), @@ -945,49 +1001,18 @@ impl ExprCollector { } } -pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping { - let mut collector = ExprCollector::new(); - - let params = if let Some(param_list) = node.param_list() { - let mut params = Vec::new(); - - if let Some(self_param) = param_list.self_param() { - let self_param = SyntaxNodePtr::new( - self_param - .self_kw() - .expect("self param without self keyword") - .syntax(), - ); - let param = collector.alloc_pat( - Pat::Bind { - name: Name::self_param(), - mode: BindingAnnotation::Unannotated, - subpat: None, - }, - self_param, - ); - params.push(param); - } +pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc { + let mut collector = ExprCollector::new(func); - for param in param_list.params() { - let pat = if let Some(pat) = param.pat() { - pat - } else { - continue; - }; - params.push(collector.collect_pat(pat)); - } - params - } else { - Vec::new() - }; + // TODO: consts, etc. + collector.collect_fn_body(&func.source(db).1); - let body = collector.collect_block_opt(node.body()); - collector.into_body_syntax_mapping(params, body) + Arc::new(collector.into_body_syntax_mapping()) } -pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc { - let (_, fn_def) = func.source(db); - let body_syntax_mapping = collect_fn_body_syntax(&fn_def); - Arc::new(body_syntax_mapping) +#[cfg(test)] +pub(crate) fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> BodySyntaxMapping { + let mut collector = ExprCollector::new(function); + collector.collect_fn_body(node); + collector.into_body_syntax_mapping() } diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 504a087a3..887ad8dd8 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs @@ -338,6 +338,7 @@ pub struct ReferenceDescriptor { mod tests { use ra_syntax::{SourceFile, algo::find_node_at_offset}; use test_utils::{extract_offset, assert_eq_text}; + use ra_arena::ArenaId; use crate::expr; @@ -356,7 +357,10 @@ mod tests { let file = SourceFile::parse(&code); let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); - let body_hir = expr::collect_fn_body_syntax(fn_def); + let irrelevant_function = Function { + id: crate::ids::FunctionId::from_raw(0.into()), + }; + let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def); let scopes = ExprScopes::new(Arc::clone(body_hir.body())); let scopes = ScopesWithSyntaxMapping { scopes: Arc::new(scopes), @@ -456,7 +460,10 @@ mod tests { let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); - let body_hir = expr::collect_fn_body_syntax(fn_def); + let irrelevant_function = Function { + id: crate::ids::FunctionId::from_raw(0.into()), + }; + let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def); let scopes = ExprScopes::new(Arc::clone(body_hir.body())); let scopes = ScopesWithSyntaxMapping { scopes: Arc::new(scopes), diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 36d72b103..5fa49d456 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -9,9 +9,11 @@ ast::{self, AstNode}}; use crate::{ Const, Type, Function, HirFileId, + HirDatabase, PersistentHirDatabase, type_ref::TypeRef, ids::LocationCtx, + resolve::Resolver, }; use crate::code_model_api::{Module, ModuleSource}; @@ -69,6 +71,10 @@ impl ImplBlock { &self.module_impl_blocks.impls[self.impl_id] } + pub fn module(&self) -> Module { + self.module_impl_blocks.module.clone() + } + pub fn target_trait(&self) -> Option<&TypeRef> { self.impl_data().target_trait() } @@ -80,6 +86,13 @@ impl ImplBlock { pub fn items(&self) -> &[ImplItem] { self.impl_data().items() } + + pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { + let r = self.module().resolver(db); + // FIXME: add generics + let r = r.push_impl_block_scope(self.clone()); + r + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -162,25 +175,24 @@ impl_arena_id!(ImplId); /// we don't need to do the second step again. #[derive(Debug, PartialEq, Eq)] pub struct ModuleImplBlocks { + module: Module, pub(crate) impls: Arena, impls_by_def: FxHashMap, } impl ModuleImplBlocks { - fn new() -> Self { - ModuleImplBlocks { - impls: Arena::default(), - impls_by_def: FxHashMap::default(), - } - } - fn collect( - &mut self, db: &impl PersistentHirDatabase, module: Module, source_map: &mut ImplSourceMap, - ) { - let (file_id, module_source) = module.definition_source(db); + ) -> Self { + let mut m = ModuleImplBlocks { + module, + impls: Arena::default(), + impls_by_def: FxHashMap::default(), + }; + + let (file_id, module_source) = m.module.definition_source(db); let file_id: HirFileId = file_id.into(); let node = match &module_source { ModuleSource::SourceFile(node) => node.syntax(), @@ -191,14 +203,16 @@ impl ModuleImplBlocks { }; for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { - let impl_block = ImplData::from_ast(db, file_id, module, impl_block_ast); - let id = self.impls.alloc(impl_block); - for &impl_item in &self.impls[id].items { - self.impls_by_def.insert(impl_item, id); + let impl_block = ImplData::from_ast(db, file_id, m.module, impl_block_ast); + let id = m.impls.alloc(impl_block); + for &impl_item in &m.impls[id].items { + m.impls_by_def.insert(impl_item, id); } source_map.insert(id, impl_block_ast); } + + m } } @@ -208,8 +222,7 @@ pub(crate) fn impls_in_module_with_source_map_query( ) -> (Arc, Arc) { let mut source_map = ImplSourceMap::default(); - let mut result = ModuleImplBlocks::new(); - result.collect(db, module, &mut source_map); + let result = ModuleImplBlocks::collect(db, module, &mut source_map); (Arc::new(result), Arc::new(source_map)) } diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 41fcb35bc..b7fbf6df2 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -15,7 +15,7 @@ use crate::{ path::Path, }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Resolver { scopes: Vec, // maybe a 'linked list' of scopes? or allow linking a Resolver to a parent Resolver? that's an optimization that might not be necessary, though } @@ -87,6 +87,36 @@ impl Resolver { self } + pub(crate) fn push_generic_params_scope(self, params: Arc) -> Resolver { + self.push_scope(Scope::GenericParams(params)) + } + + pub(crate) fn push_impl_block_scope(self, impl_block: ImplBlock) -> Resolver { + self.push_scope(Scope::ImplBlockScope(impl_block)) + } + + pub(crate) fn push_module_scope(self, item_map: Arc, module_id: ModuleId) -> Resolver { + self.push_scope(Scope::ModuleScope(ModuleItemMap { + item_map, + module_id, + })) + } + + pub(crate) fn push_expr_scope( + self, + expr_scopes: Arc, + scope_id: ScopeId, + ) -> Resolver { + self.push_scope(Scope::ExprScope(ExprScope { + expr_scopes, + scope_id, + })) + } + + pub(crate) fn push_function_params(self, body: Arc) -> Resolver { + self.push_scope(Scope::FunctionParams(body)) + } + pub(crate) fn pop_scope(mut self) -> Resolver { self.scopes.pop(); self -- cgit v1.2.3