Repository navigation
fix(resolve): a self-reference with nothing below reads the environment - #31
Merged
Merged
Conversation
HOME : ${HOME} with HOME set was Unresolved. The spec says a self-reference
that comes before its field has a value "is undefined, exactly as if the
substitution referenced a path not found in the document"
(examples-of-self-referential-substitutions.6), and such a path is searched
for in the environment (substitution-fallback-to-environment-variables.1).
The spec's author said so in lightbend/config#652; pyhocon does it since
chimpler/pyhocon#213. typesafe/config reports a cycle, which .7 rules out.
Found.gone is left for an optional that hit a cycle; a self-reference with
nothing below is absent, so it goes on to the variable, and kept with
--env=keep it waits for one. A kept self-reference from an include always
falls back to the path as written, so inDocument goes. The tests that pinned
the old rule are rewritten, the reason in their comments.
Conformance: substitution-fallback-to-environment/009 and 010, Java and
pyhocon measured on the 448.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J2cA6s3DDWV6BtSwCUZMuG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbBo1aotFTDLY2gery7qYD
lejmr
force-pushed
the
conformance/self-reference-reads-env
branch
from
October 25, 2026 09:48
06dcf00 to
81ada01
Compare
lejmr
added a commit
that referenced
this pull request
Oct 25, 2026
The tokenizer took every 0 byte for the sentinel past the input. In a comment that ended the file without an error: `a = 1 # note<NUL>` dropped every line below, and a UTF-16 file without a byte order mark read as {}. Only the NUL at input.len ends the input now; one before it is ignored in a comment, kept in unquoted and triple-quoted text, and rejected in a quoted string, as any control character (comments.1, unquoted-strings.14-15, multi-line-strings.1).
- four conformance cases: comments/015, unquoted-strings/031-032, multi-line-strings/010; typesafe/config does all four
- the oracle protocol carries a NUL as \0, since the adapter's shell variable dropped it and the oracles never saw one
- the CHANGELOG drops a sentence #31 left in twice
zig-hocon passes all 482, typesafe/config 423 against the spec, pyhocon 340.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CbBo1aotFTDLY2gery7qYD
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.
HOME : ${HOME}, withHOMEset, wasUnresolved. The spec says otherwise:A path not found in the document is looked up in the environment (substitution-fallback-to-environment-variables.1, substitutions.13). For
${?foo}the spec says the same thing: "as if it referred to a nonexistent value" (self-referential-substitutions.13). The blocking rule (substitution-fallback-to-environment-variables.4) is about a value the lookup finds, such asHOME : null. A self-reference with nothing below it has no such value. The spec's author said in lightbend/config#652 that it should work, and pyhocon has done it since chimpler/pyhocon#213. typesafe/config reports a cycle, which .7 rules out ("undefined" rather than "intractable cycle").Behaviour
HOMEsetHOME : ${HOME}Unresolved"/home/…""/home/…"HOME : ${?HOME}{}"/home/…"{}"/home/…"HOME : ${HOME}"/bin"Unresolved"/home/…/bin""/home/…/bin"HOME += x[x]UnsupportedConcatenation[x]"/home/… x"+=isHOME = ${?HOME} [x], so the variable's text meets a list and the result is an error. A value set earlier,nullincluded, still wins, and with--env=nonenothing changes.Code
Found.goneis left for an optional that hit a cycle (env.an optional cycle never reads the variableis unchanged). A self-reference with nothing below is.absent, so it goes on to the variable. With--env=keepit waits for one.keep.inDocumentgoes.stringify's row 10 used to be a known loss and now round-trips.env.zig,keep.zig,Include.zigandstringify.zigare rewritten, with the reason in their comments.Conformance
substitution-fallback-to-environment/009(${X},java: unsupported) and010(${?X},java: diverges).FINDINGS.md, a CHANGELOG line, and "all 478" in the READMEs andMIGRATING.md, pyhocon 337.Checks:
zig build testpasses,zig build test-pythonis at 100 %,zig fmt --check srcis clean, andfill-expected.py --checkreports 478 cases with 0 sidecars stale.The case numbers may need to move when #28/#29/#30 land first. None of them touches this section.