test(archtest): record a lowering handed on as a value - #225
Conversation
e93db1b to
ae988fb
Compare
0ac57f8 to
1eead21
Compare
ae988fb to
79fc0ce
Compare
1eead21 to
53cd85d
Compare
79fc0ce to
fd79b40
Compare
53cd85d to
627f6dc
Compare
fd79b40 to
9507c5d
Compare
627f6dc to
233cc84
Compare
9507c5d to
b7b3daf
Compare
233cc84 to
279cb9a
Compare
b7b3daf to
575683c
Compare
279cb9a to
e5a931d
Compare
575683c to
a616e0e
Compare
e5a931d to
0670aa0
Compare
a616e0e to
f15c353
Compare
0670aa0 to
3d80f64
Compare
f15c353 to
d6b1be1
Compare
3d80f64 to
aebda3e
Compare
d6b1be1 to
ea384fd
Compare
aebda3e to
a072c1f
Compare
Closes #210. The lowering call graph was built from call expressions alone, so a lowering named at a site without being called there was described as no dependency at all. Three live handoffs were invisible: classifyUnionSiblings, unionBranchesDeclareShape and oneOfAnyOfHasNull each decide which lowering runs by passing one to slices.ContainsFunc. An identifier now counts in value position too. Position is judged, not scope: a selector's field, a composite literal's key and a parameter's own name are identifiers as well, and every one of them collides with some lowering here. Reading them all first tied nine unrelated functions into the schema walk's cycle, because a parsed schema's `.Ref` field is spelled the same as the walk's entry point. The pinned sets are unchanged, which is what makes the fix legible: the edges were missing, not the answers. The receiver branch is gone with it. It matched methods on the lowerer type, which #217 deleted, so it had been dead since. What it leaves unseen is filed as #224 rather than folded in here — adding methods makes anchorWalk a fourth set, and re-baselining the pin in the same change would have hidden whether the value edges moved anything. The list of packages the graph reads is derived rather than trusted. A lowering is a function over the immutable context, so a package declaring one holds lowerings by definition; a package added without being listed is a directory the pin silently stops reading, with its recursions absent and the pinned sets still matching. That is the same unheld-invariant shape as the value edges, one level up — in the input rather than in the graph. The list now fails both ways: a package that lowers and is not read, and one that is read and no longer lowers. The planted-source cases gain the shape #210 was filed about — a lowering named as a composite literal's field value — and one where the same name appears as both key and value, which is what makes the skip positional rather than by name.
a072c1f to
f71cddb
Compare
|
Rebased onto the new 1. The shape #210 was filed about was not among the planted cases. The issue's own example is a lowering named as a struct literal's field value — 2. Nothing held the skip as positional. It is keyed on the identifier node, not its text, which matters when one name appears in both positions — The two catch different regressions, which is why both are there rather than one. 3. The list of packages the graph reads was trusted rather than checked. The doc comment named the risk itself — "a new one that is not is a directory this pin stops seeing" — and then left it as prose. That is the same unheld-invariant shape as the value edges, one level up: in the graph's input rather than in the graph. It is derived now. A lowering is a function over the immutable context (micro-compiler-design §4), so a package declaring one holds lowerings by definition; walking The value-edge fix itself was re-verified after the restructure: a cycle closed only by a handoff still reddens the pin, and the three earlier probes (selector fields, parameter names, the name-collision refusal) still hold. Unrelated finding, filed rather than fixed: running the coverage gate repeatedly across this stack produced two different statement counts for the same commit — 4186 and 5278 — because |
Closes #210. Stacked on #223 → #222 → #221 → #220 → #219 → #218.
Summary
The lowering call graph was built from call expressions alone, so a lowering named at a site without being called there was described as no dependency at all. Three live handoffs were invisible —
classifyUnionSiblings,unionBranchesDeclareShapeandoneOfAnyOfHasNulleach decide which lowering runs by passing one toslices.ContainsFunc:(#210 was filed against two
l.methodvalues that #217 has since deleted. The mechanism outlived its examples, which is the reason to fix the mechanism.)An identifier now counts in value position too. Position is judged; scope is not — and getting that wrong is the interesting part of this change. A selector's field, a composite literal's key and a parameter's own name are identifiers as well, and every one of them collides with some lowering here. My first attempt recorded them all, and
.Refon a parsed schema — spelled exactly like the schema walk's entry point — pulled nine unrelated functions into the walk's cycle. The skip set is what makes the pass usable.Scope is deliberately not judged: a local shadowing a lowering's name would read as an edge. Nothing here does that, and the error runs in the safe direction for a pin whose job is to notice dependencies — a spurious member shows up in a pinned set and gets read, where a missing one is the silence this issue was about.
The pinned sets are unchanged, which is what makes the fix legible: the edges were missing, not the answers.
The receiver branch goes with it. It matched methods on the
lowerertype that #217 deleted, so it had been dead since. What that leaves unseen —anchorWalk.walkandwalkMappingare genuinely mutually recursive and this graph cannot see them — is filed as #224 rather than folded in, because adding methods makesanchorWalka fourth set and re-baselining the pin in the same change would hide whether the value edges moved anything.Test plan
gofmt,go vet,golangci-lint run(0 issues),go build ./...,./scripts/check-coverage.sh— all pass, 4188/4188.TestLoweringCallGraph_RecordsAHandoffAsAnEdgeasserts the three edges directly — it asserts edges rather than cycles because none of them closes one today, and a dependency the graph cannot see is unheld whether or not it currently changes an answer.isNullSchemareferencingoneOfAnyOfHasNull, whose only reference back is theContainsFuncargument) makes the pin fail with a fourth set. Before this change that cycle was invisible.TestCalleesOf_SeparatesAValueFromWhatIsNotOnewalks eight shapes — a call, a value argument, a value assignment, a selector's field, a literal key, a parameter list, self-reference, and one name appearing both ways.