Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/body.rs')
| -rw-r--r-- | crates/hir-def/src/body.rs | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 36626ed1a9..94dc39b117 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -37,6 +37,9 @@ pub struct Body { pub pats: Arena<Pat>, pub bindings: Arena<Binding>, pub labels: Arena<Label>, + /// Id of the closure/generator that owns the corresponding binding. If a binding is owned by the + /// top level expression, it will not be listed in here. + pub binding_owners: FxHashMap<BindingId, ExprId>, /// The patterns for the function's parameters. While the parameter types are /// part of the function signature, the patterns are not (they don't change /// the external type of the function). @@ -118,7 +121,8 @@ impl Body { let _p = profile::span("body_with_source_map_query"); let mut params = None; - let (file_id, module, body, is_async_fn) = { + let mut is_async_fn = false; + let InFile { file_id, value: body } = { match def { DefWithBodyId::FunctionId(f) => { let data = db.function_data(f); @@ -138,31 +142,27 @@ impl Body { }), ) }); - ( - src.file_id, - f.module(db), - src.value.body().map(ast::Expr::from), - data.has_async_kw(), - ) + is_async_fn = data.has_async_kw(); + src.map(|it| it.body().map(ast::Expr::from)) } DefWithBodyId::ConstId(c) => { let c = c.lookup(db); let src = c.source(db); - (src.file_id, c.module(db), src.value.body(), false) + src.map(|it| it.body()) } DefWithBodyId::StaticId(s) => { let s = s.lookup(db); let src = s.source(db); - (src.file_id, s.module(db), src.value.body(), false) + src.map(|it| it.body()) } DefWithBodyId::VariantId(v) => { - let e = v.parent.lookup(db); let src = v.parent.child_source(db); - let variant = &src.value[v.local_id]; - (src.file_id, e.container, variant.expr(), false) + src.map(|it| it[v.local_id].expr()) } + DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()), } }; + let module = def.module(db); let expander = Expander::new(db, file_id, module); let (mut body, source_map) = Body::new(db, def, expander, params, body, module.krate, is_async_fn); @@ -209,14 +209,24 @@ impl Body { } fn shrink_to_fit(&mut self) { - let Self { _c: _, body_expr: _, block_scopes, exprs, labels, params, pats, bindings } = - self; + let Self { + _c: _, + body_expr: _, + block_scopes, + exprs, + labels, + params, + pats, + bindings, + binding_owners, + } = self; block_scopes.shrink_to_fit(); exprs.shrink_to_fit(); labels.shrink_to_fit(); params.shrink_to_fit(); pats.shrink_to_fit(); bindings.shrink_to_fit(); + binding_owners.shrink_to_fit(); } pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) { @@ -260,6 +270,17 @@ impl Body { f(pat_id); self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f)); } + + pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool { + match self.binding_owners.get(&binding) { + Some(x) => { + // We assign expression ids in a way that outer closures will receive + // a lower id + x.into_raw() < relative_to.into_raw() + } + None => true, + } + } } impl Default for Body { @@ -272,6 +293,7 @@ impl Default for Body { labels: Default::default(), params: Default::default(), block_scopes: Default::default(), + binding_owners: Default::default(), _c: Default::default(), } } |