about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/compiler/mod.rs27
-rw-r--r--tvix/eval/src/compiler/scope.rs62
2 files changed, 33 insertions, 56 deletions
diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs
index 0d2ed66f5b..ca1098af64 100644
--- a/tvix/eval/src/compiler/mod.rs
+++ b/tvix/eval/src/compiler/mod.rs
@@ -29,7 +29,7 @@ use crate::opcode::{CodeIdx, Count, JumpOffset, OpCode, StackIdx, UpvalueIdx};
 use crate::value::{Closure, Lambda, Value};
 use crate::warnings::{EvalWarning, WarningKind};
 
-use self::scope::{Depth, Local, LocalPosition, Scope, Upvalue};
+use self::scope::{Local, LocalPosition, Scope, Upvalue};
 
 /// Represents the result of compiling a piece of Nix code. If
 /// compilation was successful, the resulting bytecode can be passed
@@ -752,7 +752,7 @@ impl Compiler {
             // Calculate the with_idx without taking into account
             // uninitialised variables that are not yet in their stack
             // slots.
-            .filter(|l| matches!(l.depth, Depth::At(_)))
+            .filter(|l| l.initialised)
             .count()
             - 1;
 
@@ -897,9 +897,7 @@ impl Compiler {
         // TL;DR - iterate from the back while things belonging to the
         // ended scope still exist.
         while !self.scope().locals.is_empty()
-            && self.scope().locals[self.scope().locals.len() - 1]
-                .depth
-                .above(self.scope().scope_depth)
+            && self.scope().locals[self.scope().locals.len() - 1].above(self.scope().scope_depth)
         {
             pops += 1;
 
@@ -944,13 +942,8 @@ impl Compiler {
         }
 
         let mut shadowed = false;
-        for local in self.scope().locals.iter().rev() {
-            if local.depth.below(self.scope().scope_depth) {
-                // Shadowing identifiers from higher scopes is allowed.
-                break;
-            }
-
-            if local.name == name {
+        for other in self.scope().locals.iter().rev() {
+            if other.name == name && other.depth == depth {
                 shadowed = true;
                 break;
             }
@@ -965,7 +958,8 @@ impl Compiler {
 
         self.scope_mut().locals.push(Local {
             name,
-            depth: Depth::Unitialised,
+            depth,
+            initialised: false,
             node: Some(node),
             phantom: false,
             used: false,
@@ -978,7 +972,8 @@ impl Compiler {
     fn declare_phantom(&mut self) {
         let depth = self.scope().scope_depth;
         self.scope_mut().locals.push(Local {
-            depth: Depth::At(depth),
+            depth,
+            initialised: true,
             name: "".into(),
             node: None,
             phantom: true,
@@ -990,8 +985,8 @@ impl Compiler {
     fn mark_initialised(&mut self, name: &str) {
         let depth = self.scope().scope_depth;
         for local in self.scope_mut().locals.iter_mut().rev() {
-            if matches!(local.depth, Depth::Unitialised) && local.name == name {
-                local.depth = Depth::At(depth);
+            if !local.initialised && local.depth == depth && local.name == name {
+                local.initialised = true;
                 return;
             }
         }
diff --git a/tvix/eval/src/compiler/scope.rs b/tvix/eval/src/compiler/scope.rs
index 3061e08ead..a76a411b46 100644
--- a/tvix/eval/src/compiler/scope.rs
+++ b/tvix/eval/src/compiler/scope.rs
@@ -16,34 +16,6 @@ use smol_str::SmolStr;
 
 use crate::opcode::{StackIdx, UpvalueIdx};
 
-/// Represents the initialisation status of a variable, tracking
-/// whether it is only known or also already defined.
-pub enum Depth {
-    /// Variable is defined and located at the given depth.
-    At(usize),
-
-    /// Variable is known but not yet defined.
-    Unitialised,
-}
-
-impl Depth {
-    /// Does this variable live above the other given depth?
-    pub fn above(&self, theirs: usize) -> bool {
-        match self {
-            Depth::Unitialised => false,
-            Depth::At(ours) => *ours > theirs,
-        }
-    }
-
-    /// Does this variable live below the other given depth?
-    pub fn below(&self, theirs: usize) -> bool {
-        match self {
-            Depth::Unitialised => false,
-            Depth::At(ours) => *ours < theirs,
-        }
-    }
-}
-
 /// Represents a single local already known to the compiler.
 pub struct Local {
     // Definition name, which can be different kinds of tokens (plain
@@ -55,7 +27,10 @@ pub struct Local {
     pub node: Option<rnix::SyntaxNode>,
 
     // Scope depth of this local.
-    pub depth: Depth,
+    pub depth: usize,
+
+    // Is this local initialised?
+    pub initialised: bool,
 
     // Phantom locals are not actually accessible by users (e.g.
     // intermediate values used for `with`).
@@ -65,6 +40,13 @@ pub struct Local {
     pub used: bool,
 }
 
+impl Local {
+    /// Does this local live above the other given depth?
+    pub fn above(&self, theirs: usize) -> bool {
+        self.depth > theirs
+    }
+}
+
 /// Represents the current position of a local as resolved in a scope.
 pub enum LocalPosition {
     /// Local is not known in this scope.
@@ -175,17 +157,17 @@ impl Scope {
             if !local.phantom && local.name == name {
                 local.used = true;
 
-                match local.depth {
-                    // This local is still being initialised, meaning
-                    // that we know its final runtime stack position,
-                    // but it is not yet on the stack.
-                    Depth::Unitialised => return LocalPosition::Recursive(StackIdx(idx)),
-
-                    // This local is known, but we need to account for
-                    // uninitialised variables in this "initialiser
-                    // stack".
-                    Depth::At(_) => return LocalPosition::Known(self.resolve_uninit(idx)),
+                // This local is still being initialised, meaning that
+                // we know its final runtime stack position, but it is
+                // not yet on the stack.
+                if !local.initialised {
+                    return LocalPosition::Recursive(StackIdx(idx));
                 }
+
+                // This local is known, but we need to account for
+                // uninitialised variables in this "initialiser
+                // stack".
+                return LocalPosition::Known(self.resolve_uninit(idx));
             }
         }
 
@@ -200,7 +182,7 @@ impl Scope {
         StackIdx(
             self.locals[..locals_idx]
                 .iter()
-                .filter(|local| matches!(local.depth, Depth::At(_)))
+                .filter(|local| local.initialised)
                 .count(),
         )
     }