mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 22:54:58 +00:00
Re-use the resolver in InferenceContext instead of rebuilding it on every expression change
This commit is contained in:
parent
e6ba791dce
commit
a8606e5363
7 changed files with 116 additions and 38 deletions
|
@ -1,5 +1,5 @@
|
|||
//! Name resolution façade.
|
||||
use std::{hash::BuildHasherDefault, sync::Arc};
|
||||
use std::{fmt, hash::BuildHasherDefault, sync::Arc};
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_expand::name::{name, Name};
|
||||
|
@ -36,19 +36,34 @@ pub struct Resolver {
|
|||
module_scope: ModuleItemMap,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
struct ModuleItemMap {
|
||||
def_map: Arc<DefMap>,
|
||||
module_id: LocalModuleId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
impl fmt::Debug for ModuleItemMap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ModuleItemMap").field("module_id", &self.module_id).finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ExprScope {
|
||||
owner: DefWithBodyId,
|
||||
expr_scopes: Arc<ExprScopes>,
|
||||
scope_id: ScopeId,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ExprScope {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ExprScope")
|
||||
.field("owner", &self.owner)
|
||||
.field("scope_id", &self.scope_id)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Scope {
|
||||
/// All the items and imported names of a module
|
||||
|
@ -478,8 +493,72 @@ impl Resolver {
|
|||
_ => None,
|
||||
})
|
||||
}
|
||||
/// `expr_id` is required to be an expression id that comes after the top level expression scope in the given resolver
|
||||
#[must_use]
|
||||
pub fn update_to_inner_scope(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
owner: DefWithBodyId,
|
||||
expr_id: ExprId,
|
||||
) -> UpdateGuard {
|
||||
#[inline(always)]
|
||||
fn append_expr_scope(
|
||||
db: &dyn DefDatabase,
|
||||
resolver: &mut Resolver,
|
||||
owner: DefWithBodyId,
|
||||
expr_scopes: &Arc<ExprScopes>,
|
||||
scope_id: ScopeId,
|
||||
) {
|
||||
resolver.scopes.push(Scope::ExprScope(ExprScope {
|
||||
owner,
|
||||
expr_scopes: expr_scopes.clone(),
|
||||
scope_id,
|
||||
}));
|
||||
if let Some(block) = expr_scopes.block(scope_id) {
|
||||
if let Some(def_map) = db.block_def_map(block) {
|
||||
let root = def_map.root();
|
||||
resolver
|
||||
.scopes
|
||||
.push(Scope::BlockScope(ModuleItemMap { def_map, module_id: 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?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let start = self.scopes.len();
|
||||
let innermost_scope = self.scopes().next();
|
||||
match innermost_scope {
|
||||
Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => {
|
||||
let expr_scopes = expr_scopes.clone();
|
||||
let scope_chain = expr_scopes
|
||||
.scope_chain(expr_scopes.scope_for(expr_id))
|
||||
.take_while(|&it| it != scope_id);
|
||||
for scope_id in scope_chain {
|
||||
append_expr_scope(db, self, owner, &expr_scopes, scope_id);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let expr_scopes = db.expr_scopes(owner);
|
||||
let scope_chain = expr_scopes.scope_chain(expr_scopes.scope_for(expr_id));
|
||||
|
||||
for scope_id in scope_chain {
|
||||
append_expr_scope(db, self, owner, &expr_scopes, scope_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.scopes[start..].reverse();
|
||||
UpdateGuard(start)
|
||||
}
|
||||
|
||||
pub fn reset_to_guard(&mut self, UpdateGuard(start): UpdateGuard) {
|
||||
self.scopes.truncate(start);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UpdateGuard(usize);
|
||||
|
||||
impl Resolver {
|
||||
fn scopes(&self) -> impl Iterator<Item = &Scope> {
|
||||
self.scopes.iter().rev()
|
||||
|
@ -576,10 +655,11 @@ impl Scope {
|
|||
}
|
||||
}
|
||||
|
||||
// needs arbitrary_self_types to be a method... or maybe move to the def?
|
||||
pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
|
||||
let r = owner.resolver(db);
|
||||
let scopes = db.expr_scopes(owner);
|
||||
resolver_for_scope(db, owner, scopes.scope_for(expr_id))
|
||||
let scope_id = scopes.scope_for(expr_id);
|
||||
resolver_for_scope_(db, scopes, scope_id, r, owner)
|
||||
}
|
||||
|
||||
pub fn resolver_for_scope(
|
||||
|
@ -587,8 +667,18 @@ pub fn resolver_for_scope(
|
|||
owner: DefWithBodyId,
|
||||
scope_id: Option<ScopeId>,
|
||||
) -> Resolver {
|
||||
let mut r = owner.resolver(db);
|
||||
let r = owner.resolver(db);
|
||||
let scopes = db.expr_scopes(owner);
|
||||
resolver_for_scope_(db, scopes, scope_id, r, owner)
|
||||
}
|
||||
|
||||
fn resolver_for_scope_(
|
||||
db: &dyn DefDatabase,
|
||||
scopes: Arc<ExprScopes>,
|
||||
scope_id: Option<ScopeId>,
|
||||
mut r: Resolver,
|
||||
owner: DefWithBodyId,
|
||||
) -> Resolver {
|
||||
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
|
||||
r.scopes.reserve(scope_chain.len());
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue