From 52b68c053987c1567bacb6f14dad8ba92cd01afe Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 11 Dec 2023 23:14:08 -0800 Subject: fix(tvix/eval): fix catchables in named formals Fixes b/348. Change-Id: I5e8d56b5fd26a19eac32ec5e11baf93765691dc8 Reviewed-on: https://cl.tvl.fyi/c/depot/+/10296 Autosubmit: Adam Joseph Reviewed-by: tazjin Tested-by: BuildkiteCI --- tvix/eval/src/compiler/mod.rs | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'tvix/eval/src/compiler/mod.rs') diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs index 211fd079a047..b6b5bc6860f9 100644 --- a/tvix/eval/src/compiler/mod.rs +++ b/tvix/eval/src/compiler/mod.rs @@ -957,7 +957,7 @@ impl Compiler<'_> { /// by the caller. We need to take this into account and skip any /// operations specific to the expression like thunk finalisation in such /// cases. - fn compile_param_pattern(&mut self, pattern: &ast::Pattern) -> Formals { + fn compile_param_pattern(&mut self, pattern: &ast::Pattern) -> (Formals, CodeIdx) { let span = self.span_for(pattern); let set_idx = match pattern.pat_bind() { Some(name) => self.declare_local(&name, name.ident().unwrap().to_string()), @@ -967,6 +967,7 @@ impl Compiler<'_> { // At call time, the attribute set is already at the top of the stack. self.scope_mut().mark_initialised(set_idx); self.emit_force(pattern); + let throw_idx = self.push_op(OpCode::OpJumpIfCatchable(JumpOffset(0)), pattern); // Evaluation fails on a type error, even if the argument(s) are unused. self.push_op(OpCode::OpAssertAttrs, pattern); @@ -1106,14 +1107,17 @@ impl Compiler<'_> { } } - Formals { - arguments, - ellipsis, - span, - } + ( + (Formals { + arguments, + ellipsis, + span, + }), + throw_idx, + ) } - fn compile_lambda(&mut self, slot: LocalIdx, node: &ast::Lambda) { + fn compile_lambda(&mut self, slot: LocalIdx, node: &ast::Lambda) -> Option { // Compile the function itself, recording its formal arguments (if any) // for later use let formals = match node.param().unwrap() { @@ -1135,7 +1139,13 @@ impl Compiler<'_> { }; self.compile(slot, node.body().unwrap()); - self.context_mut().lambda.formals = formals; + if let Some((formals, throw_idx)) = formals { + self.context_mut().lambda.formals = Some(formals); + Some(throw_idx) + } else { + self.context_mut().lambda.formals = None; + None + } } fn thunk(&mut self, outer_slot: LocalIdx, node: &N, content: F) @@ -1143,7 +1153,10 @@ impl Compiler<'_> { N: ToSpan, F: FnOnce(&mut Compiler, LocalIdx), { - self.compile_lambda_or_thunk(true, outer_slot, node, content) + self.compile_lambda_or_thunk(true, outer_slot, node, |comp, idx| { + content(comp, idx); + None + }) } /// Mark the current thunk as redundant, i.e. possible to merge directly @@ -1161,7 +1174,7 @@ impl Compiler<'_> { content: F, ) where N: ToSpan, - F: FnOnce(&mut Compiler, LocalIdx), + F: FnOnce(&mut Compiler, LocalIdx) -> Option, { let name = self.scope()[outer_slot].name(); self.new_context(); @@ -1174,8 +1187,11 @@ impl Compiler<'_> { let slot = self.scope_mut().declare_phantom(span, false); self.scope_mut().begin_scope(); - content(self, slot); + let throw_idx = content(self, slot); self.cleanup_scope(node); + if let Some(throw_idx) = throw_idx { + self.patch_jump(throw_idx); + } // TODO: determine and insert enclosing name, if available. -- cgit 1.4.1