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 <adam@westernsemico.com>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
This commit is contained in:
Adam Joseph 2023-12-11 23:14:08 -08:00 committed by clbot
parent e516046ed2
commit 52b68c0539
3 changed files with 27 additions and 11 deletions

View file

@ -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<CodeIdx> {
// 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<N, F>(&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<CodeIdx>,
{
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.