fix: collapse agreeing definitions in the route merge (#674) - #675
Merged
Merged
Conversation
`mergeableType` deep-merges attrsets and concatenates lists, and threw on everything else — including definitions that all held the same value. Derivations are deliberately held opaque so they never reach the attrset branch, which left two aspects producing the same package in conflict. #574 introduced the type claiming NixOS module semantics, but NixOS's `mergeEqualOption` accepts agreeing definitions and only throws on disagreement. Accepts all-equal definitions before the conflict throw, checked last so it forces values only on the path that already threw. Lambdas never compare equal in Nix, so function-valued leaves keep the existing conflict behaviour.
`builtins.readFile` on the merged package built an `x86_64-linux` derivation, which fails the macos-latest runner on platform mismatch. The line came verbatim from the issue's repro; the oracle never needed the build, only the forcing of the merged option. Reads `.name` instead. Falsified against the pre-fix tree: it still fails with `den: the option 'shared' has conflicting definitions`, and the disagreeing-values control stays green.
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.
Closes #674
Summary
mergeableType— the freeform type route nesting evaluates modules under — deep-merges attrsets, concatenates lists, and throws on everything else. Derivations are deliberately excluded from the attrset branch so they stay opaque, so two aspects producing the same package fell to the conflict throw even though the definitions agreed. Same for the reportedenable = trueshape, where deep-merging descends to a scalar leaf with two definitions.mergeEqualOption. Checked last, so it forces values only on the path that already threw.#574 introduced the type claiming NixOS module semantics, but
mergeEqualOptionaccepts agreeing definitions and only throws on disagreement — so the divergence is latent from #574, and #671 made the path reachable, which is the reporter's own reading of the bisect. This is the same collapse-agreeing-definitions rule #671 applied tometa.provider, now on the route freeform type.Testing:
appsattrset defined by two aspects), and a negative control pinning that disagreeing definitions still throw.Validation
nix develop -c just ci: 1118/1118, exit 0, zero failures and zero errors.nix develop -c just fmta no-op at the final rev.origin/mainworktree at 36c8ba5: the issue's test verbatim fails withden: the option 'shared' has conflicting definitions from multiple aspects, so the fix is measured against a red baseline rather than a green assumption.tryEvalprints that same conflict error, so it fails for the guard's reason and not incidentally.just ci deadbugs-issue-674(3/3). The backgroundjust cilog truncates to 42 lines, so the suite's absence from that log is not evidence either way and was not read as such.Known limitation
The equality check cannot reach function-valued leaves. Measured against this nixpkgs:
(x: x) == (x: x)falselet f = x: x; in f == ffalse{ a = 1; f = x: x; } == { a = 1; f = x: x; }falseA lambda never compares equal, not even to itself, and one lambda anywhere in an attrset makes the whole comparison false. So two aspects delivering the same function at one option still conflict, and no
==-level rule can fix that — it needs identity carried alongside the value. Derivations are unaffected because Nix short-circuits their comparison onoutPath, which is why the reported case is fully fixable here.