about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-27T00·17+0300
committertazjin <tazjin@tvl.su>2022-09-04T17·40+0000
commit10b0879c009098d3c5f9fe21067ff656a29442a5 (patch)
tree1e38d06f69e690571032135c9890efe4430907f3
parent7c2fdefcd8ff693be1afd15a08958f09d07a0e91 (diff)
fix(tvix/eval): ensure OpResolveWith can be traced r/4634
The previous implementation of OpResolveWith manually controlled the
loop iteration, which skipped over the disassembler's tracing
instruction.

Instead, the resolution of dynamic variables has been delegated to a
new helper function. This has the additional benefit that the loop
labels are no longer required, making things a bit cleaner.

Change-Id: If22b74c3d49c74bf3a1ec4497cb761a9ee6cf2a4
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6298
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
-rw-r--r--tvix/eval/src/vm.rs32
1 files changed, 16 insertions, 16 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index c851ad83ccad..4ce3505cdb9a 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -126,7 +126,7 @@ impl VM {
         #[cfg(feature = "disassembler")]
         let mut tracer = Tracer::new();
 
-        'dispatch: loop {
+        loop {
             if self.frame().ip == self.chunk().code.len() {
                 // If this is the end of the top-level function,
                 // return, otherwise pop the call frame.
@@ -330,21 +330,8 @@ impl VM {
 
                 OpCode::OpResolveWith => {
                     let ident = self.pop().to_string()?;
-
-                    // Attempt to resolve the variable, starting at
-                    // the back of the with_stack.
-                    'with: for idx in self.with_stack.iter().rev() {
-                        let with = self.stack[*idx].as_attrs()?;
-                        match with.select(ident.as_str()) {
-                            None => continue 'with,
-                            Some(val) => {
-                                self.push(val.clone());
-                                continue 'dispatch;
-                            }
-                        }
-                    }
-
-                    return Err(ErrorKind::UnknownDynamicVariable(ident.to_string()).into());
+                    let value = self.resolve_with(ident.as_str())?;
+                    self.push(value)
                 }
 
                 OpCode::OpAssert => {
@@ -450,6 +437,19 @@ impl VM {
         self.push(Value::String(out.into()));
         Ok(())
     }
+
+    /// Resolve a dynamic identifier through the with-stack at runtime.
+    fn resolve_with(&self, ident: &str) -> EvalResult<Value> {
+        for idx in self.with_stack.iter().rev() {
+            let with = self.stack[*idx].as_attrs()?;
+            match with.select(ident) {
+                None => continue,
+                Some(val) => return Ok(val.clone()),
+            }
+        }
+
+        Err(ErrorKind::UnknownDynamicVariable(ident.to_string()).into())
+    }
 }
 
 // TODO: use Rc::unwrap_or_clone once it is stabilised.