about summary refs log tree commit diff
path: root/tvix/eval/src/vm.rs
diff options
context:
space:
mode:
authorGriffin Smith <grfn@gws.fyi>2022-10-13T03·53-0400
committertazjin <tazjin@tvl.su>2022-10-17T11·29+0000
commit2a3d49810482b36de9f2d3087e5064545183dbb3 (patch)
tree9cce6ac0209ad046f2549b15041d89b5faa94c48 /tvix/eval/src/vm.rs
parente63d14419f5cc2ea1f0d9e9221062c2c8d40fe31 (diff)
feat(tvix/eval): Validate closed formals r/5154
Validate "closed formals" (formal parameters without an ellipsis) via a
new ValidateClosedFormals op, which checks the arguments (in an attr set
at the top of the stack) against the formal parameters on the Lambda in
the current frame, and returns a new UnexpectedArgument error (including
the span of the formals themselves!!) if any arguments aren't allowed

Change-Id: Idcc47a59167a83be1832a6229f137d84e426c56c
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7002
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r--tvix/eval/src/vm.rs15
1 files changed, 15 insertions, 0 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index 7fcdb9ea739b..65662ed555d3 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -500,6 +500,21 @@ impl<'o> VM<'o> {
                 self.push(Value::Bool(result));
             }
 
+            OpCode::OpValidateClosedFormals => {
+                let formals = self.frame().lambda.formals.as_ref().expect(
+                    "OpValidateClosedFormals called within the frame of a lambda without formals",
+                );
+                let args = self.peek(0).to_attrs().map_err(|err| self.error(err))?;
+                for arg in args.keys() {
+                    if !formals.contains(arg) {
+                        return Err(self.error(ErrorKind::UnexpectedArgument {
+                            arg: arg.clone(),
+                            formals_span: formals.span,
+                        }));
+                    }
+                }
+            }
+
             OpCode::OpList(Count(count)) => {
                 let list =
                     NixList::construct(count, self.stack.split_off(self.stack.len() - count));