Repository navigation
test(conformance): an object concatenated over a substitution is a merge - #28
Merged
Merged
Conversation
`top : ${x} { ... }` is a merge (array-and-object-concatenation.6), the same as `top : ${x}` and `top { ... }` written as two fields, so inside it:
- a self-reference, `+=` or the long form, looks back at the field ${x} gives (examples-of-self-referential-substitutions.3): plus-equals-field-separator/009–012, self-referential-examples/027–028
- any other reference to the object looks forward and sees the merged value (.14, .16): self-referential-examples/029–030
typesafe/config drops the inherited element of a += (lightbend/config#375, #608, fix proposed in #882) and reports the rest as cycles (#586, #728). zig-hocon gets the two-field form right and fails 7 of the 8 in one value: 447/454.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CbBo1aotFTDLY2gery7qYD
`top = ${x} { ... }` was one value joined once its parts were resolved, so nothing inside the object saw what ${x} gives: a += there dropped the inherited list, a self-reference had nothing below, and ${top.n} closed a cycle. The object is now resolved as a layer over the parts in front of it, as if written as a field of its own (spec L398), so it goes through the same code as `top = ${x}` and `top { ... }`. Next to a list or text, or under `.keep` while ${x} waits, it is still a concatenation.
zig-hocon passes all 454 cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CbBo1aotFTDLY2gery7qYD
- self-referential-examples/031: an object a substitution gives on top hides a field of the object below it, so a substitution there is never evaluated (examples-of-self-referential-substitutions.8; lightbend/config#838) - self-referential-examples/032: the same inside `${base} { ... }`, hidden by a later `child.foo = x` (lightbend/config#812, Java evaluates it) - self-referential-examples/033: a reference in the object below looks forward at the merged value (.16, .17) zig-hocon resolved the layer below first and fails all three: 454/457. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbBo1aotFTDLY2gery7qYD
An object layer, or an object a substitution gives, was merged onto the layers below it only after they were resolved, so a field it hides was evaluated anyway (an error for `p : { a : ${y} }`, `p : ${x}` with x.a set) and a reference below saw the old value. `mergedBelow` now merges the objects among the layers as written and resolves only what decides whether they merge, the refs; the merged object is resolved once, on top.
zig-hocon passes all 457 cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CbBo1aotFTDLY2gery7qYD
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The spec defines object concatenation as merging (array-and-object-concatenation.6) and lists
a : { b : 1 } { c : 2 }beside two fieldsa : { b : 1 },a : { c : 2 }as the same value. Sotop : ${x} { arr += four }istop : ${x}andtop { arr += four }, and the suite had no case where that matters: nothing referred to the object from inside a${x} { ... }. lightbend/config#882 brought it up.Eight cases, each citing array-and-object-concatenation.6:
top : ${x} { arr += four }[one, four][four][four](#608)y : ${x} { l += 2 },z : ${y} { l += 3 }z.l = [1, 2, 3][3][3]top : ${x} { a { b { c += 2 } } }[1, 2][2][2]y = ${x} { l = [1, 2] },y.l += 3[1, 2, 3][3](#375)c : ${d} { x : ${c.x} [1, 2] }[0, 1, 2]c : ${d} ${e} { x : ${c.x} [1], w : ${e.z} }x = [0, 1],w = 5a = ${mixin} { y = ${a.hello} }y = worldtop = ${x} { n = 2, seen = ${top.n} }seen = 2${x}.zig-hocon gets every one of these right written as two fields and fails 7 of the 8 in one value: 447/454. Java 402/454 against the spec (all 8 are
java: divergesorunsupported), pyhocon 318/454. The other four reports are behind as before.A second commit fixes zig-hocon (454/454).
Layers merge before they are resolved
The same review turned up a neighbour (lightbend/config#838, #812): the layers of a key merge first and are resolved after, so a field an upper layer hides is never evaluated (examples-of-self-referential-substitutions.8), and a reference below looks forward at the merged value (.16).
p : { a : ${y} },p : ${x},x : { a : 42 }p.a = 42${y}child = ${base} { foo = ${missing} },child.foo = xfoo = xbar : { foo : 42, baz : ${bar.foo} },bar : ${r},r = { foo : 43 }baz = 4342A third and fourth commit add the cases and the fix (
mergedBelowinsrc/Value/Resolver/stack.zig): the PR merges at 457/457. Java 404/457 against the spec, pyhocon 320/457.🤖 Generated with Claude Code
https://claude.ai/code/session_01CbBo1aotFTDLY2gery7qYD