Skip to content

Commit 5ef268e

Browse files
Support non-body expression store for upvars_mentioned()
1 parent 251df51 commit 5ef268e

2 files changed

Lines changed: 86 additions & 18 deletions

File tree

crates/hir-ty/src/infer/coerce.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,9 +1718,6 @@ fn coerce<'db>(
17181718

17191719
fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool {
17201720
let InternedClosure(owner, expr) = closure.loc(db);
1721-
let Some(body_owner) = owner.as_def_with_body() else {
1722-
return false;
1723-
};
1724-
upvars_mentioned(db, body_owner)
1721+
upvars_mentioned(db, owner)
17251722
.is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty()))
17261723
}

crates/hir-ty/src/upvars.rs

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! A simple query to collect tall locals (upvars) a closure use.
22
33
use hir_def::{
4-
DefWithBodyId,
5-
expr_store::{Body, path::Path},
4+
DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId,
5+
expr_store::{ExpressionStore, path::Path},
66
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
77
resolver::{HasResolver, Resolver, ValueNs},
88
};
@@ -36,18 +36,89 @@ impl Upvars {
3636
pub fn is_empty(&self) -> bool {
3737
self.0.is_empty()
3838
}
39+
40+
#[inline]
41+
pub fn as_ref(&self) -> UpvarsRef<'_> {
42+
UpvarsRef(&self.0)
43+
}
44+
}
45+
46+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
47+
// Kept sorted.
48+
pub struct UpvarsRef<'db>(&'db [BindingId]);
49+
50+
impl UpvarsRef<'_> {
51+
#[inline]
52+
pub fn contains(self, local: BindingId) -> bool {
53+
self.0.binary_search(&local).is_ok()
54+
}
55+
56+
#[inline]
57+
pub fn iter(self) -> impl ExactSizeIterator<Item = BindingId> {
58+
self.0.iter().copied()
59+
}
60+
61+
#[inline]
62+
pub fn is_empty(self) -> bool {
63+
self.0.is_empty()
64+
}
65+
66+
#[inline]
67+
pub const fn empty() -> Self {
68+
UpvarsRef(&[])
69+
}
3970
}
4071

4172
/// Returns a map from `Expr::Closure` to its upvars.
42-
#[salsa::tracked(returns(as_deref))]
4373
pub fn upvars_mentioned(
4474
db: &dyn HirDatabase,
45-
owner: DefWithBodyId,
75+
owner: ExpressionStoreOwnerId,
76+
) -> Option<&FxHashMap<ExprId, Upvars>> {
77+
return match owner {
78+
ExpressionStoreOwnerId::Signature(owner) => signature_upvars_mentioned(db, owner),
79+
ExpressionStoreOwnerId::Body(owner) => body_upvars_mentioned(db, owner),
80+
ExpressionStoreOwnerId::VariantFields(owner) => variant_fields_upvars_mentioned(db, owner),
81+
};
82+
83+
#[salsa::tracked(returns(as_deref))]
84+
pub fn signature_upvars_mentioned(
85+
db: &dyn HirDatabase,
86+
owner: GenericDefId,
87+
) -> Option<Box<FxHashMap<ExprId, Upvars>>> {
88+
upvars_mentioned_impl(db, owner.into())
89+
}
90+
91+
#[salsa::tracked(returns(as_deref))]
92+
pub fn body_upvars_mentioned(
93+
db: &dyn HirDatabase,
94+
owner: DefWithBodyId,
95+
) -> Option<Box<FxHashMap<ExprId, Upvars>>> {
96+
upvars_mentioned_impl(db, owner.into())
97+
}
98+
99+
#[salsa::tracked(returns(as_deref))]
100+
pub fn variant_fields_upvars_mentioned(
101+
db: &dyn HirDatabase,
102+
owner: VariantId,
103+
) -> Option<Box<FxHashMap<ExprId, Upvars>>> {
104+
upvars_mentioned_impl(db, owner.into())
105+
}
106+
}
107+
108+
pub fn upvars_mentioned_impl(
109+
db: &dyn HirDatabase,
110+
owner: ExpressionStoreOwnerId,
46111
) -> Option<Box<FxHashMap<ExprId, Upvars>>> {
47-
let body = Body::of(db, owner);
112+
let store = ExpressionStore::of(db, owner);
113+
if store.const_expr_origins().is_empty() {
114+
// Save constructing a Resolver.
115+
return None;
116+
}
48117
let mut resolver = owner.resolver(db);
49118
let mut result = FxHashMap::default();
50-
handle_expr_outside_closure(db, &mut resolver, owner, body, body.root_expr(), &mut result);
119+
for root_expr in store.expr_roots() {
120+
handle_expr_outside_closure(db, &mut resolver, owner, store, root_expr, &mut result);
121+
}
51122
return if result.is_empty() {
52123
None
53124
} else {
@@ -58,8 +129,8 @@ pub fn upvars_mentioned(
58129
fn handle_expr_outside_closure<'db>(
59130
db: &'db dyn HirDatabase,
60131
resolver: &mut Resolver<'db>,
61-
owner: DefWithBodyId,
62-
body: &Body,
132+
owner: ExpressionStoreOwnerId,
133+
body: &ExpressionStore,
63134
expr: ExprId,
64135
closures_map: &mut FxHashMap<ExprId, Upvars>,
65136
) {
@@ -89,8 +160,8 @@ pub fn upvars_mentioned(
89160
fn handle_expr_inside_closure<'db>(
90161
db: &'db dyn HirDatabase,
91162
resolver: &mut Resolver<'db>,
92-
owner: DefWithBodyId,
93-
body: &Body,
163+
owner: ExpressionStoreOwnerId,
164+
body: &ExpressionStore,
94165
current_closure: ExprId,
95166
expr: ExprId,
96167
upvars: &mut FxHashSet<BindingId>,
@@ -170,8 +241,8 @@ pub fn upvars_mentioned(
170241
fn resolve_maybe_upvar<'db>(
171242
db: &'db dyn HirDatabase,
172243
resolver: &mut Resolver<'db>,
173-
owner: DefWithBodyId,
174-
body: &Body,
244+
owner: ExpressionStoreOwnerId,
245+
body: &ExpressionStore,
175246
current_closure: ExprId,
176247
expr: ExprId,
177248
id: ExprOrPatId,
@@ -198,7 +269,7 @@ fn resolve_maybe_upvar<'db>(
198269
#[cfg(test)]
199270
mod tests {
200271
use expect_test::{Expect, expect};
201-
use hir_def::{ModuleDefId, expr_store::Body, nameres::crate_def_map};
272+
use hir_def::{DefWithBodyId, ModuleDefId, expr_store::Body, nameres::crate_def_map};
202273
use itertools::Itertools;
203274
use span::Edition;
204275
use test_fixture::WithFixture;
@@ -220,7 +291,7 @@ mod tests {
220291
.exactly_one()
221292
.unwrap_or_else(|_| panic!("expected one function"));
222293
let (body, source_map) = Body::with_source_map(&db, func.into());
223-
let Some(upvars) = upvars_mentioned(&db, func.into()) else {
294+
let Some(upvars) = upvars_mentioned(&db, DefWithBodyId::from(func).into()) else {
224295
expectation.assert_eq("");
225296
return;
226297
};

0 commit comments

Comments
 (0)