diff options
author | Vincent Ambo <mail@tazj.in> | 2022-09-06T14·05+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-09-11T12·04+0000 |
commit | 9da99af86045b59867e6082ca99d602308553006 (patch) | |
tree | 0f6c05cc114e2ca6f168bbf7770fbc4cc474824f /tvix/eval/src/compiler/scope.rs | |
parent | 27e69503a7374d7758a7c6145427265712d45f9c (diff) |
refactor(tvix/eval): encapsulate scope cleanup logic in module r/4794
Moves the logic for removing tracked locals from a given scope from the compiler's locals list, and leaves only the actual compiler-related stuff (emitting warnings, cleaning up locals at runtime) in the compiler itself. Change-Id: I9da6eb54967f0a7775f624d602fe11be4c7ed5c4 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6466 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
Diffstat (limited to 'tvix/eval/src/compiler/scope.rs')
-rw-r--r-- | tvix/eval/src/compiler/scope.rs | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/tvix/eval/src/compiler/scope.rs b/tvix/eval/src/compiler/scope.rs index b6fa61e7759b..7c1e65265e1d 100644 --- a/tvix/eval/src/compiler/scope.rs +++ b/tvix/eval/src/compiler/scope.rs @@ -188,11 +188,11 @@ impl Scope { self.poisoned_tokens.contains_key(name) } - /// "Unpoison" tokens that were poisoned at a given depth. Used - /// when scopes are closed. - pub fn unpoison(&mut self, depth: usize) { + /// "Unpoison" tokens that were poisoned at the current depth. + /// Used when scopes are closed. + fn unpoison(&mut self) { self.poisoned_tokens - .retain(|_, poisoned_at| *poisoned_at != depth); + .retain(|_, poisoned_at| *poisoned_at != self.scope_depth); } /// Increase the `with`-stack size of this scope. @@ -284,4 +284,45 @@ impl Scope { StackIdx(idx.0 - uninitialised_count) } + + /// Decrease the scope depth and remove all locals still tracked + /// for the current scope. + /// + /// Returns the count of locals that were dropped while marked as + /// initialised (used by the compiler to determine whether to emit + /// scope cleanup operations), as well as the spans of the + /// definitions of unused locals (used by the compiler to emit + /// unused binding warnings). + pub fn end_scope(&mut self) -> (usize, Vec<codemap::Span>) { + debug_assert!(self.scope_depth != 0, "can not end top scope"); + + // If this scope poisoned any builtins or special identifiers, + // they need to be reset. + self.unpoison(); + + let mut pops = 0; + let mut unused_spans = vec![]; + + // TL;DR - iterate from the back while things belonging to the + // ended scope still exist. + while self.locals.last().unwrap().depth == self.scope_depth { + if let Some(local) = self.locals.pop() { + // pop the local from the stack if it was actually + // initialised + if local.initialised { + pops += 1; + } + + // analyse whether the local was accessed during its + // lifetime, and emit a warning otherwise (unless the + // user explicitly chose to ignore it by prefixing the + // identifier with `_`) + if !local.used && !local.is_ignored() { + unused_spans.push(local.span); + } + } + } + + (pops, unused_spans) + } } |