Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store/scope.rs')
-rw-r--r--crates/hir-def/src/expr_store/scope.rs81
1 files changed, 68 insertions, 13 deletions
diff --git a/crates/hir-def/src/expr_store/scope.rs b/crates/hir-def/src/expr_store/scope.rs
index 1952dae9d7..40ae0b7de4 100644
--- a/crates/hir-def/src/expr_store/scope.rs
+++ b/crates/hir-def/src/expr_store/scope.rs
@@ -1,13 +1,16 @@
//! Name resolution for expressions.
use hir_expand::{MacroDefId, name::Name};
use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
-use triomphe::Arc;
use crate::{
- BlockId, DefWithBodyId,
+ BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId,
db::DefDatabase,
expr_store::{Body, ExpressionStore, HygieneId},
- hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
+ hir::{
+ Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement,
+ generics::GenericParams,
+ },
+ signatures::VariantFields,
};
pub type ScopeId = Idx<ScopeData>;
@@ -50,12 +53,45 @@ pub struct ScopeData {
entries: IdxRange<ScopeEntry>,
}
+#[salsa::tracked]
impl ExprScopes {
- pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
- let body = db.body(def);
- let mut scopes = ExprScopes::new_body(&body);
+ #[salsa::tracked(returns(ref))]
+ pub fn body_expr_scopes(db: &dyn DefDatabase, def: DefWithBodyId) -> ExprScopes {
+ let body = Body::of(db, def);
+ let mut scopes = ExprScopes::new_body(body);
scopes.shrink_to_fit();
- Arc::new(scopes)
+ scopes
+ }
+
+ #[salsa::tracked(returns(ref))]
+ pub fn sig_expr_scopes(db: &dyn DefDatabase, def: GenericDefId) -> ExprScopes {
+ let (_, store) = GenericParams::with_store(db, def);
+ let roots = store.expr_roots();
+ let mut scopes = ExprScopes::new_store(store, roots);
+ scopes.shrink_to_fit();
+ scopes
+ }
+
+ #[salsa::tracked(returns(ref))]
+ pub fn variant_scopes(db: &dyn DefDatabase, def: VariantId) -> ExprScopes {
+ let fields = VariantFields::of(db, def);
+ let roots = fields.store.expr_roots();
+ let mut scopes = ExprScopes::new_store(&fields.store, roots);
+ scopes.shrink_to_fit();
+ scopes
+ }
+}
+
+impl ExprScopes {
+ #[inline]
+ pub fn of(db: &dyn DefDatabase, def: impl Into<ExpressionStoreOwnerId>) -> &ExprScopes {
+ match def.into() {
+ ExpressionStoreOwnerId::Body(def) => Self::body_expr_scopes(db, def),
+ ExpressionStoreOwnerId::Signature(def) => Self::sig_expr_scopes(db, def),
+ ExpressionStoreOwnerId::VariantFields(variant_id) => {
+ Self::variant_scopes(db, variant_id)
+ }
+ }
}
pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
@@ -115,7 +151,23 @@ impl ExprScopes {
scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param));
}
scopes.add_params_bindings(body, root, &body.params);
- compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
+ compute_expr_scopes(body.root_expr(), body, &mut scopes, &mut root);
+ scopes
+ }
+
+ fn new_store(store: &ExpressionStore, roots: impl IntoIterator<Item = ExprId>) -> ExprScopes {
+ let mut scopes = ExprScopes {
+ scopes: Arena::default(),
+ scope_entries: Arena::default(),
+ scope_by_expr: ArenaMap::with_capacity(
+ store.expr_only.as_ref().map_or(0, |it| it.exprs.len()),
+ ),
+ };
+ let root = scopes.root_scope();
+ for root_expr in roots {
+ let mut scope = scopes.new_scope(root);
+ compute_expr_scopes(root_expr, store, &mut scopes, &mut scope);
+ }
scopes
}
@@ -327,7 +379,10 @@ mod tests {
use test_utils::{assert_eq_text, extract_offset};
use crate::{
- FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, test_db::TestDB,
+ DefWithBodyId, FunctionId, ModuleDefId,
+ expr_store::{Body, scope::ExprScopes},
+ nameres::crate_def_map,
+ test_db::TestDB,
};
fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
@@ -363,8 +418,8 @@ mod tests {
let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
let function = find_function(&db, file_id);
- let scopes = db.expr_scopes(function.into());
- let (_body, source_map) = db.body_with_source_map(function.into());
+ let scopes = ExprScopes::of(&db, DefWithBodyId::from(function));
+ let (_body, source_map) = Body::with_source_map(&db, function.into());
let expr_id = source_map
.node_expr(InFile { file_id: editioned_file_id.into(), value: &marker.into() })
@@ -522,8 +577,8 @@ fn foo() {
let function = find_function(&db, file_id);
- let scopes = db.expr_scopes(function.into());
- let (_, source_map) = db.body_with_source_map(function.into());
+ let scopes = ExprScopes::body_expr_scopes(&db, DefWithBodyId::from(function));
+ let (_, source_map) = Body::with_source_map(&db, function.into());
let expr_scope = {
let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();