diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs index 0082d36d5..03466af65 100644 --- a/tvix/eval/src/builtins/mod.rs +++ b/tvix/eval/src/builtins/mod.rs @@ -309,6 +309,21 @@ fn pure_builtins() -> Vec { None => Err(ErrorKind::IndexOutOfBounds { index: 0 }), } }), + Builtin::new( + "intersectAttrs", + &[true, true], + |args: Vec, _: &mut VM| { + let mut res = BTreeMap::new(); + let attrs1 = args[0].to_attrs()?; + let attrs2 = args[1].to_attrs()?; + for (k, v) in attrs2.iter() { + if attrs1.contains(k) { + res.insert(k.clone(), v.clone()); + } + } + Ok(Value::attrs(NixAttrs::from_map(res))) + }, + ), // For `is*` predicates we force manually, as Value::force also unwraps any Thunks Builtin::new("isAttrs", &[false], |args: Vec, vm: &mut VM| { let value = args[0].force(vm)?; diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-intersectattrs.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-intersectattrs.exp new file mode 100644 index 000000000..25001b211 --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-intersectattrs.exp @@ -0,0 +1 @@ +{ a = 100; b = 200; } diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-intersectattrs.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-intersectattrs.nix new file mode 100644 index 000000000..3534132ed --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-intersectattrs.nix @@ -0,0 +1,3 @@ +builtins.intersectAttrs + { a = 1; b = 2; c = 3; } + { a = 100; b = 200; d = 5; }