From e04ccc9354ee2112622fe9e6e6df8765bd7685fe Mon Sep 17 00:00:00 2001 From: sterni Date: Mon, 19 Sep 2022 11:47:34 +0200 Subject: fix(tvix/eval): make sure to deref thunk in type predicate builtins Previously we only matched the outer constructor after forcing which would mean that we would always return `false` if the inspected value was a thunk, regardless what value would be present inside. Change-Id: I361ea6e855e23ef8e5b59098a50b9cd59253803f Reviewed-on: https://cl.tvl.fyi/c/depot/+/6692 Reviewed-by: tazjin Autosubmit: sterni Tested-by: BuildkiteCI --- tvix/eval/src/builtins/mod.rs | 46 +++++++++++++--------- .../eval-okay-builtins-type-predicates.exp | 1 + .../eval-okay-builtins-type-predicates.nix | 34 ++++++++++++++++ 3 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.exp create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.nix (limited to 'tvix/eval') diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs index 18a50f255a50..dfc1986141a0 100644 --- a/tvix/eval/src/builtins/mod.rs +++ b/tvix/eval/src/builtins/mod.rs @@ -154,35 +154,45 @@ fn pure_builtins() -> Vec { Some(x) => Ok(x.clone()), None => Err(ErrorKind::IndexOutOfBounds { index: 0 }), }), - Builtin::new("isAttrs", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::Attrs(_)))) + // For `is*` predicates we force manually, as Value::force also unwraps any Thunks + Builtin::new("isAttrs", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::Attrs(_)))) }), - Builtin::new("isBool", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::Bool(_)))) + Builtin::new("isBool", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::Bool(_)))) }), - Builtin::new("isFloat", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::Float(_)))) + Builtin::new("isFloat", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::Float(_)))) }), - Builtin::new("isFunction", &[true], |args, _| { + Builtin::new("isFunction", &[false], |args, vm| { + let value = args[0].force(vm)?; Ok(Value::Bool(matches!( - args[0], + *value, Value::Closure(_) | Value::Builtin(_) ))) }), - Builtin::new("isInt", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::Integer(_)))) + Builtin::new("isInt", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::Integer(_)))) }), - Builtin::new("isList", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::List(_)))) + Builtin::new("isList", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::List(_)))) }), - Builtin::new("isNull", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::Null))) + Builtin::new("isNull", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::Null))) }), - Builtin::new("isPath", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::Path(_)))) + Builtin::new("isPath", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::Path(_)))) }), - Builtin::new("isString", &[true], |args, _| { - Ok(Value::Bool(matches!(args[0], Value::String(_)))) + Builtin::new("isString", &[false], |args, vm| { + let value = args[0].force(vm)?; + Ok(Value::Bool(matches!(*value, Value::String(_)))) }), Builtin::new("mul", &[true, true], |mut args, _| { let b = args.pop().unwrap(); diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.exp new file mode 100644 index 000000000000..724c1f9c34b9 --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.exp @@ -0,0 +1 @@ +[ true true false true true false true true false true true false true true false true true false true true false true true false true true true false ] diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.nix new file mode 100644 index 000000000000..3d688cb8bd68 --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-builtins-type-predicates.nix @@ -0,0 +1,34 @@ +let + # apply is thunked, so we can create a thunked value using the identity function + thunk = x: x; +in +[ + (builtins.isAttrs { bar = throw "baz"; }) + (builtins.isAttrs (thunk { foo = 13; })) + (builtins.isAttrs (thunk 123)) + (builtins.isBool true) + (builtins.isBool (thunk false)) + (builtins.isBool (thunk "lol")) + (builtins.isFloat 1.2) + (builtins.isFloat (thunk (1 * 1.0))) + (builtins.isFloat 1) + (builtins.isFunction thunk) + (builtins.isFunction (thunk thunk)) + (builtins.isFunction {}) + (builtins.isInt 1) + (builtins.isInt (thunk 42)) + (builtins.isInt 1.0) + (builtins.isList [ (throw "oh no") (abort "it's over") ]) + (builtins.isList (thunk [ 21 21 ])) + (builtins.isList (thunk {})) + (builtins.isNull null) + (builtins.isNull (thunk null)) + (builtins.isNull 42) + (builtins.isPath ./relative) + (builtins.isPath (thunk /absolute)) + (builtins.isPath "/not/a/path") + (builtins.isString "simple") + (builtins.isString "${{ outPath = "coerced"; }}") + (builtins.isString "hello ${"interpolation"}") + (builtins.isString true) +] -- cgit 1.4.1