diff options
author | sterni <sternenseemann@systemli.org> | 2022-09-19T09·47+0200 |
---|---|---|
committer | sterni <sternenseemann@systemli.org> | 2022-09-20T10·59+0000 |
commit | e04ccc9354ee2112622fe9e6e6df8765bd7685fe (patch) | |
tree | df5dccf977ea46babeec5427a75744748d3e384e /tvix | |
parent | fe3c4720a6f3276b5652b61937fa2ad19763af82 (diff) |
fix(tvix/eval): make sure to deref thunk in type predicate builtins r/4936
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 <tazjin@tvl.su> Autosubmit: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
Diffstat (limited to 'tvix')
3 files changed, 63 insertions, 18 deletions
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<Builtin> { 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) +] |