From 7c5655fe89431871b6f13ef0d2e8f3884deae48f Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sun, 08 Feb 2026 23:20:55 +0000 Subject: [PATCH] feat: lazily evaluate source field in mergePatch --- --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -1183,6 +1183,12 @@ let entry = receiver.0.new.this_entries.entry(name); entry.insert_entry(member); } + /// Inserts thunk, replacing if it is already defined + pub fn thunk(self, value: impl Into>) { + let (receiver, name, member) = self.build_member(MaybeUnbound::Bound(value.into())); + let entry = receiver.0.new.this_entries.entry(name); + entry.insert_entry(member); + } /// Tries to insert value, returns an error if it was already defined pub fn try_value(self, value: impl Into) -> Result<()> { --- a/crates/jrsonnet-formatter/src/lib.rs +++ b/crates/jrsonnet-formatter/src/lib.rs @@ -5,8 +5,7 @@ condition_helpers::is_multiple_lines, condition_resolvers::true_resolver, ir_helpers::{new_line_group, with_indent}, - ConditionResolver, ConditionResolverContext, LineNumber, PrintItemPath, PrintItems, - PrintOptions, Signal, + ConditionResolver, ConditionResolverContext, LineNumber, PrintItems, PrintOptions, }; use hi_doc::{Formatting, SnippetBuilder}; use jrsonnet_rowan_parser::{ @@ -14,7 +13,7 @@ Arg, ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart, DestructRest, Expr, ExprBase, FieldName, ForSpec, IfSpec, ImportKind, Literal, Member, Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Stmt, Suffix, Text, - Trivia, TriviaKind, UnaryOperator, Visibility, + UnaryOperator, Visibility, }, AstNode, AstToken as _, SyntaxToken, }; --- a/crates/jrsonnet-stdlib/src/misc.rs +++ b/crates/jrsonnet-stdlib/src/misc.rs @@ -201,7 +201,9 @@ let mut out = ObjValueBuilder::new(); for field in target_fields.union(&patch_fields) { let Some(field_patch) = patch.get(field.clone())? else { - out.field(field.clone()).value(target.get(field.clone())?.expect("we're iterating over fields union, if field is missing in patch - it exists in target")); + // All lazy fields might be unified into a single filtered object core instead of creating a thunk per, but this implementation is good enough. + let target_field = target.get_lazy(field.clone()).expect("we're iterating over fields union, if field is missing in patch - it exists in target"); + out.field(field.clone()).thunk(target_field); continue; }; if matches!(field_patch, Val::Null) { --- /dev/null +++ b/tests/golden/issue188.jsonnet @@ -0,0 +1 @@ +std.mergePatch({ val: error 'should not error' }, {}) + { val+:: {} } --- /dev/null +++ b/tests/golden/issue188.jsonnet.golden @@ -0,0 +1 @@ +{ } \ No newline at end of file -- gitstuff