Implement methods to build a resolver

This commit is contained in:
Florian Diebold 2019-01-23 23:08:41 +01:00
parent 5208c2aa93
commit 758bc72873
5 changed files with 169 additions and 76 deletions

View file

@ -184,9 +184,9 @@ impl Module {
self.problems_impl(db) self.problems_impl(db)
} }
#[allow(unused_variables)]
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 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<GenericParams> { pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into()) 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 { impl Docs for Function {

View file

@ -27,6 +27,9 @@ impl_arena_id!(ExprId);
/// The body of an item (function, const etc.). /// The body of an item (function, const etc.).
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Body { 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<ExprId, Expr>, exprs: Arena<ExprId, Expr>,
pats: Arena<PatId, Pat>, pats: Arena<PatId, Pat>,
/// The patterns for the function's parameters. While the parameter types are /// The patterns for the function's parameters. While the parameter types are
@ -63,12 +66,26 @@ impl Body {
self.body_expr self.body_expr
} }
#[allow(unused_variables)] pub fn owner(&self) -> Function {
pub fn resolver_for_expr(&self, expr_id: ExprId) -> Resolver { self.owner
unimplemented!()
} }
} }
// needs arbitrary_self_types to be a method... or maybe move to the def?
#[allow(dead_code)]
pub fn resolver_for_expr(body: Arc<Body>, 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::<Vec<_>>();
for scope in scope_chain.into_iter().rev() {
r = r.push_expr_scope(Arc::clone(&scopes), scope);
}
r
}
impl Index<ExprId> for Body { impl Index<ExprId> for Body {
type Output = Expr; type Output = Expr;
@ -453,23 +470,29 @@ pub(crate) fn body_hir(db: &impl HirDatabase, func: Function) -> Arc<Body> {
} }
struct ExprCollector { struct ExprCollector {
owner: Function,
exprs: Arena<ExprId, Expr>, exprs: Arena<ExprId, Expr>,
pats: Arena<PatId, Pat>, pats: Arena<PatId, Pat>,
expr_syntax_mapping: FxHashMap<SyntaxNodePtr, ExprId>, expr_syntax_mapping: FxHashMap<SyntaxNodePtr, ExprId>,
expr_syntax_mapping_back: ArenaMap<ExprId, SyntaxNodePtr>, expr_syntax_mapping_back: ArenaMap<ExprId, SyntaxNodePtr>,
pat_syntax_mapping: FxHashMap<SyntaxNodePtr, PatId>, pat_syntax_mapping: FxHashMap<SyntaxNodePtr, PatId>,
pat_syntax_mapping_back: ArenaMap<PatId, SyntaxNodePtr>, pat_syntax_mapping_back: ArenaMap<PatId, SyntaxNodePtr>,
params: Vec<PatId>,
body_expr: Option<ExprId>,
} }
impl ExprCollector { impl ExprCollector {
fn new() -> Self { fn new(owner: Function) -> Self {
ExprCollector { ExprCollector {
owner,
exprs: Arena::default(), exprs: Arena::default(),
pats: Arena::default(), pats: Arena::default(),
expr_syntax_mapping: FxHashMap::default(), expr_syntax_mapping: FxHashMap::default(),
expr_syntax_mapping_back: ArenaMap::default(), expr_syntax_mapping_back: ArenaMap::default(),
pat_syntax_mapping: FxHashMap::default(), pat_syntax_mapping: FxHashMap::default(),
pat_syntax_mapping_back: ArenaMap::default(), pat_syntax_mapping_back: ArenaMap::default(),
params: Vec::new(),
body_expr: None,
} }
} }
@ -907,10 +930,7 @@ impl ExprCollector {
}); });
fields.extend(iter); fields.extend(iter);
Pat::Struct { Pat::Struct { path, args: fields }
path: path,
args: fields,
}
} }
// TODO: implement // TODO: implement
@ -928,12 +948,48 @@ impl ExprCollector {
} }
} }
fn into_body_syntax_mapping(self, params: Vec<PatId>, 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 { let body = Body {
owner: self.owner,
exprs: self.exprs, exprs: self.exprs,
pats: self.pats, pats: self.pats,
params, params: self.params,
body_expr, body_expr: self.body_expr.expect("A body should have been collected"),
}; };
BodySyntaxMapping { BodySyntaxMapping {
body: Arc::new(body), 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);
}
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()
};
let body = collector.collect_block_opt(node.body());
collector.into_body_syntax_mapping(params, body)
}
pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc<BodySyntaxMapping> { pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc<BodySyntaxMapping> {
let (_, fn_def) = func.source(db); let mut collector = ExprCollector::new(func);
let body_syntax_mapping = collect_fn_body_syntax(&fn_def);
Arc::new(body_syntax_mapping) // TODO: consts, etc.
collector.collect_fn_body(&func.source(db).1);
Arc::new(collector.into_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()
} }

View file

@ -338,6 +338,7 @@ pub struct ReferenceDescriptor {
mod tests { mod tests {
use ra_syntax::{SourceFile, algo::find_node_at_offset}; use ra_syntax::{SourceFile, algo::find_node_at_offset};
use test_utils::{extract_offset, assert_eq_text}; use test_utils::{extract_offset, assert_eq_text};
use ra_arena::ArenaId;
use crate::expr; use crate::expr;
@ -356,7 +357,10 @@ mod tests {
let file = SourceFile::parse(&code); let file = SourceFile::parse(&code);
let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 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 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 = ExprScopes::new(Arc::clone(body_hir.body()));
let scopes = ScopesWithSyntaxMapping { let scopes = ScopesWithSyntaxMapping {
scopes: Arc::new(scopes), scopes: Arc::new(scopes),
@ -456,7 +460,10 @@ mod tests {
let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 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 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 = ExprScopes::new(Arc::clone(body_hir.body()));
let scopes = ScopesWithSyntaxMapping { let scopes = ScopesWithSyntaxMapping {
scopes: Arc::new(scopes), scopes: Arc::new(scopes),

View file

@ -9,9 +9,11 @@ ast::{self, AstNode}};
use crate::{ use crate::{
Const, Type, Const, Type,
Function, HirFileId, Function, HirFileId,
HirDatabase,
PersistentHirDatabase, PersistentHirDatabase,
type_ref::TypeRef, type_ref::TypeRef,
ids::LocationCtx, ids::LocationCtx,
resolve::Resolver,
}; };
use crate::code_model_api::{Module, ModuleSource}; use crate::code_model_api::{Module, ModuleSource};
@ -69,6 +71,10 @@ impl ImplBlock {
&self.module_impl_blocks.impls[self.impl_id] &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> { pub fn target_trait(&self) -> Option<&TypeRef> {
self.impl_data().target_trait() self.impl_data().target_trait()
} }
@ -80,6 +86,13 @@ impl ImplBlock {
pub fn items(&self) -> &[ImplItem] { pub fn items(&self) -> &[ImplItem] {
self.impl_data().items() 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)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -162,25 +175,24 @@ impl_arena_id!(ImplId);
/// we don't need to do the second step again. /// we don't need to do the second step again.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct ModuleImplBlocks { pub struct ModuleImplBlocks {
module: Module,
pub(crate) impls: Arena<ImplId, ImplData>, pub(crate) impls: Arena<ImplId, ImplData>,
impls_by_def: FxHashMap<ImplItem, ImplId>, impls_by_def: FxHashMap<ImplItem, ImplId>,
} }
impl ModuleImplBlocks { impl ModuleImplBlocks {
fn new() -> Self {
ModuleImplBlocks {
impls: Arena::default(),
impls_by_def: FxHashMap::default(),
}
}
fn collect( fn collect(
&mut self,
db: &impl PersistentHirDatabase, db: &impl PersistentHirDatabase,
module: Module, module: Module,
source_map: &mut ImplSourceMap, source_map: &mut ImplSourceMap,
) { ) -> Self {
let (file_id, module_source) = module.definition_source(db); 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 file_id: HirFileId = file_id.into();
let node = match &module_source { let node = match &module_source {
ModuleSource::SourceFile(node) => node.syntax(), ModuleSource::SourceFile(node) => node.syntax(),
@ -191,14 +203,16 @@ impl ModuleImplBlocks {
}; };
for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { 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 impl_block = ImplData::from_ast(db, file_id, m.module, impl_block_ast);
let id = self.impls.alloc(impl_block); let id = m.impls.alloc(impl_block);
for &impl_item in &self.impls[id].items { for &impl_item in &m.impls[id].items {
self.impls_by_def.insert(impl_item, id); m.impls_by_def.insert(impl_item, id);
} }
source_map.insert(id, impl_block_ast); source_map.insert(id, impl_block_ast);
} }
m
} }
} }
@ -208,8 +222,7 @@ pub(crate) fn impls_in_module_with_source_map_query(
) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) {
let mut source_map = ImplSourceMap::default(); let mut source_map = ImplSourceMap::default();
let mut result = ModuleImplBlocks::new(); let result = ModuleImplBlocks::collect(db, module, &mut source_map);
result.collect(db, module, &mut source_map);
(Arc::new(result), Arc::new(source_map)) (Arc::new(result), Arc::new(source_map))
} }

View file

@ -15,7 +15,7 @@ use crate::{
path::Path, path::Path,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone, Default)]
pub struct Resolver { pub struct Resolver {
scopes: Vec<Scope>, // 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 scopes: Vec<Scope>, // 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 self
} }
pub(crate) fn push_generic_params_scope(self, params: Arc<GenericParams>) -> 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<ItemMap>, module_id: ModuleId) -> Resolver {
self.push_scope(Scope::ModuleScope(ModuleItemMap {
item_map,
module_id,
}))
}
pub(crate) fn push_expr_scope(
self,
expr_scopes: Arc<ExprScopes>,
scope_id: ScopeId,
) -> Resolver {
self.push_scope(Scope::ExprScope(ExprScope {
expr_scopes,
scope_id,
}))
}
pub(crate) fn push_function_params(self, body: Arc<Body>) -> Resolver {
self.push_scope(Scope::FunctionParams(body))
}
pub(crate) fn pop_scope(mut self) -> Resolver { pub(crate) fn pop_scope(mut self) -> Resolver {
self.scopes.pop(); self.scopes.pop();
self self