diff options
Diffstat (limited to 'tvix/eval/src/vm')
-rw-r--r-- | tvix/eval/src/vm/generators.rs | 8 | ||||
-rw-r--r-- | tvix/eval/src/vm/mod.rs | 66 |
2 files changed, 49 insertions, 25 deletions
diff --git a/tvix/eval/src/vm/generators.rs b/tvix/eval/src/vm/generators.rs index bbf79f47c05d..f2ce73a0c742 100644 --- a/tvix/eval/src/vm/generators.rs +++ b/tvix/eval/src/vm/generators.rs @@ -763,9 +763,13 @@ pub(crate) async fn request_span(co: &GenCo) -> LightSpan { } } -pub(crate) async fn request_to_json(co: &GenCo, value: Value) -> serde_json::Value { +pub(crate) async fn request_to_json( + co: &GenCo, + value: Value, +) -> Result<serde_json::Value, CatchableErrorKind> { match co.yield_(VMRequest::ToJson(value)).await { - VMResponse::Value(Value::Json(json)) => json, + VMResponse::Value(Value::Json(json)) => Ok(json), + VMResponse::Value(Value::Catchable(cek)) => Err(cek), msg => panic!( "Tvix bug: VM responded with incorrect generator message: {}", msg diff --git a/tvix/eval/src/vm/mod.rs b/tvix/eval/src/vm/mod.rs index 057a47bc008c..d9a8a2c411df 100644 --- a/tvix/eval/src/vm/mod.rs +++ b/tvix/eval/src/vm/mod.rs @@ -646,7 +646,7 @@ impl<'o> VM<'o> { // exactly. OpCode::OpAssertBool => { let val = self.stack_peek(0); - if !val.is_bool() { + if !val.is_catchable() && !val.is_bool() { return frame.error( self, ErrorKind::TypeError { @@ -732,17 +732,17 @@ impl<'o> VM<'o> { } OpCode::OpConcat => { - let rhs = self - .stack_pop() - .to_list() - .with_span(&frame, self)? - .into_inner(); - let lhs = self - .stack_pop() - .to_list() - .with_span(&frame, self)? - .into_inner(); - self.stack.push(Value::List(NixList::from(lhs + rhs))) + // right hand side, left hand side + match (self.stack_pop(), self.stack_pop()) { + (Value::Catchable(cek), _) | (_, Value::Catchable(cek)) => { + self.stack.push(Value::Catchable(cek)); + } + (rhs, lhs) => { + let rhs = rhs.to_list().with_span(&frame, self)?.into_inner(); + let lhs = lhs.to_list().with_span(&frame, self)?.into_inner(); + self.stack.push(Value::List(NixList::from(lhs + rhs))) + } + } } OpCode::OpResolveWith => { @@ -797,7 +797,12 @@ impl<'o> VM<'o> { "OpValidateClosedFormals called within the frame of a lambda without formals", ); - let args = self.stack_peek(0).to_attrs().with_span(&frame, self)?; + let peeked = self.stack_peek(0); + if peeked.is_catchable() { + continue; + } + + let args = peeked.to_attrs().with_span(&frame, self)?; for arg in args.keys() { if !formals.contains(arg) { return frame.error( @@ -812,17 +817,24 @@ impl<'o> VM<'o> { } OpCode::OpAdd => { - let b = self.stack_pop(); - let a = self.stack_pop(); - - let gen_span = frame.current_light_span(); - self.push_call_frame(span, frame); + match (self.stack_pop(), self.stack_pop()) { + (Value::Catchable(cek), _) | (_, Value::Catchable(cek)) => { + self.stack.push(Value::Catchable(cek)); + } - // OpAdd can add not just numbers, but also string-like - // things, which requires more VM logic. This operation is - // evaluated in a generator frame. - self.enqueue_generator("add_values", gen_span, |co| add_values(co, a, b)); - return Ok(false); + (b, a) => { + let gen_span = frame.current_light_span(); + self.push_call_frame(span, frame); + + // OpAdd can add not just numbers, but also string-like + // things, which requires more VM logic. This operation is + // evaluated in a generator frame. + self.enqueue_generator("add_values", gen_span, |co| { + add_values(co, a, b) + }); + return Ok(false); + } + } } OpCode::OpSub => { @@ -1204,6 +1216,10 @@ async fn resolve_with( // TODO(tazjin): is this branch still live with the current with-thunking? let with = fetch_forced_with(&co, with_stack_idx).await; + if with.is_catchable() { + return Ok(with); + } + match with.to_attrs()?.select(&ident) { None => continue, Some(val) => return Ok(val.clone()), @@ -1213,6 +1229,10 @@ async fn resolve_with( for upvalue_with_idx in (0..upvalue_with_len).rev() { let with = fetch_captured_with(&co, upvalue_with_idx).await; + if with.is_catchable() { + return Ok(with); + } + match with.to_attrs()?.select(&ident) { None => continue, Some(val) => return Ok(val.clone()), |