fix(tvix/eval): don't force lambda arg in map, mapAttrs & genList

It is pretty pointless to force the function argument if we are going to
use a suspended call later since forcing the function may fail in ways
that are not covered by Catchables (non-recoverable errors, infinite
recursions). From this, it kind of seems as if using #[catch] is never
correct and should be replaced by #[lazy]. Also we should probably try
to come up with more test cases for stuff where laziness gets us out of
the jam as an equivalent to the catchable tests for nonrecoverable
errors.

Fixes b/386.

Change-Id: Ia926df4ac1b440ec430403ab7b40924a0c97221b
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11153
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Autosubmit: sterni <sternenseemann@systemli.org>
This commit is contained in:
sterni 2024-03-15 14:36:34 +01:00 committed by clbot
parent 3633d846f8
commit d1b7e08726
8 changed files with 38 additions and 4 deletions

View file

@ -523,7 +523,7 @@ mod pure_builtins {
async fn builtin_gen_list( async fn builtin_gen_list(
co: GenCo, co: GenCo,
// Nix 2.3 doesn't propagate failures here // Nix 2.3 doesn't propagate failures here
#[catch] generator: Value, #[lazy] generator: Value,
length: Value, length: Value,
) -> Result<Value, ErrorKind> { ) -> Result<Value, ErrorKind> {
let mut out = imbl::Vector::<Value>::new(); let mut out = imbl::Vector::<Value>::new();
@ -905,7 +905,7 @@ mod pure_builtins {
} }
#[builtin("map")] #[builtin("map")]
async fn builtin_map(co: GenCo, #[catch] f: Value, list: Value) -> Result<Value, ErrorKind> { async fn builtin_map(co: GenCo, #[lazy] f: Value, list: Value) -> Result<Value, ErrorKind> {
let mut out = imbl::Vector::<Value>::new(); let mut out = imbl::Vector::<Value>::new();
// the best span we can get… // the best span we can get…
@ -920,7 +920,11 @@ mod pure_builtins {
} }
#[builtin("mapAttrs")] #[builtin("mapAttrs")]
async fn builtin_map_attrs(co: GenCo, f: Value, attrs: Value) -> Result<Value, ErrorKind> { async fn builtin_map_attrs(
co: GenCo,
#[lazy] f: Value,
attrs: Value,
) -> Result<Value, ErrorKind> {
let attrs = attrs.to_attrs()?; let attrs = attrs.to_attrs()?;
let mut out = imbl::OrdMap::new(); let mut out = imbl::OrdMap::new();

View file

@ -0,0 +1 @@
[ <LAMBDA> 0 1 2 ]

View file

@ -0,0 +1,8 @@
let
self =
let
l = builtins.genList (builtins.head self) 3;
in
[ (x: x) ] ++ l;
in
self

View file

@ -0,0 +1 @@
[ <LAMBDA> 2 "." 18 "https://github.com/NixOS/nix/issues/9779" "-.-" ]

View file

@ -0,0 +1,8 @@
let
self =
let
l = builtins.map (builtins.head self) [ 2 "." 18 https://github.com/NixOS/nix/issues/9779 "-.-" ];
in
[ (x: x) ] ++ l;
in
self

View file

@ -0,0 +1 @@
{ a = 1; b = 2; f = <LAMBDA>; }

View file

@ -0,0 +1,8 @@
let
self =
let
s = builtins.mapAttrs self.f { a = 1; b = 2; };
in
{ f = _: x: x; } // s;
in
self

View file

@ -76,11 +76,14 @@ let
# b72bc4a972fe568744d98b89d63adcd504cb586c # b72bc4a972fe568744d98b89d63adcd504cb586c
"eval-okay-identifier-formatting.nix" = [ nix ]; "eval-okay-identifier-formatting.nix" = [ nix ];
# Different catchable behavior between nix 2.3 and 2.18 # Differing strictness in the function argument for some builtins in Nix 2.18
# https://github.com/NixOS/nix/issues/9779
"eval-okay-builtins-map-propagate-catchable.nix" = [ nix_latest ]; "eval-okay-builtins-map-propagate-catchable.nix" = [ nix_latest ];
"eval-okay-builtins-gen-list-propagate-catchable.nix" = [ nix_latest ]; "eval-okay-builtins-gen-list-propagate-catchable.nix" = [ nix_latest ];
"eval-okay-builtins-replace-strings-propagate-catchable.nix" = "eval-okay-builtins-replace-strings-propagate-catchable.nix" =
[ nix_latest ]; [ nix_latest ];
"eval-okay-builtins-map-function-strictness.nix" = [ nix_latest ];
"eval-okay-builtins-genList-function-strictness.nix" = [ nix_latest ];
# TODO(sterni): support diffing working directory and home relative paths # TODO(sterni): support diffing working directory and home relative paths
# like C++ Nix test suite (using string replacement). # like C++ Nix test suite (using string replacement).