fix(go): extract method requirements declared in an interface body - #3672
rajatnagda45 wants to merge 1 commit into
Conversation
The interface_type branch only handled interface embedding and generic
type-set constraints, so the method requirements that make up an
interface's contract were dropped. An interface such as
type Shape interface {
Area() float64
Perimeter() (float64, error)
}
became an empty node - Area and Perimeter never entered the graph, and
nothing could resolve against the interface's method set.
Walk the method_elem children too, mirroring the receiver-method path:
each requirement becomes a .Method() node hung off the interface via a
method edge. Embedding (type_elem) keeps emitting embeds/references, so
the two never blur.
Adds regression coverage: requirements surface as method nodes, an
embedded interface stays a heritage edge, and an interface method and a
concrete struct method of the same name remain distinct nodes.
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Emits a method node and method edge for each method requirement declared directly in a Go interface body, so interfaces are no longer left as empty shells and calls against them can resolve. Bare embedded interfaces continue to produce embeds heritage edges rather than methods, and an interface method stays a distinct node from a same-named concrete receiver method. Adds regression tests covering extraction, embedding, and interface/struct method separation.
No blocking issues surfaced. 2 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 44 functions depend on the 27 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract_go()— 19 callers, 7 callees - new:
walk()— 1 callers, 8 callees
Verification — 44 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 44 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
3 of 287 test file(s) selected (1%) via static blast radius.
tests/test_go_interface_methods.py— impact, changed-testtests/test_languages.py— impacttests/test_multilang.py— impact
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
Formal verification
Could not verify: Could not verify extract\_go.
The verifier did not have enough to check extract\_go, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 2 more finding(s) on lines outside this diff (see the check run).
|
Ran into this while poking at a Go service's graph — the interface nodes came out completely empty because only embedding/type-set constraints were handled, not the method requirements. Kept the fix scoped and mirrored the receiver-method path. @safishamsi would appreciate a look when you have a minute. |
Problem
The Go
interface_typebranch only handled two things: interface embedding (type_elem) and generic type-set constraints (A | B,~T). The method requirements that actually make up an interface's contract —method_elemnodes — were skipped entirely.So an interface like:
became an empty node.
AreaandPerimeternever entered the graph, the interface looked like it had no surface area, and nothing could resolve against its method set. For a language where interfaces are the primary abstraction boundary, that quietly erases the most important part of the type.Fix
Walk the
method_elemchildren of the interface body too, mirroring the existing receiver-method path: each requirement becomes a.Method()node hung off the interface via amethodedge, id-scoped under the interface type node (so an interfaceAreaand a structAreastay distinct). Embedding and type-set constraints are untouched — they still flow through thetype_elembranch asembeds/references, so a bare embedded interface never gets mistaken for a method.Test
New
tests/test_go_interface_methods.pycovers three things, all failing before the change and passing after:embeds) edge and only the directly declared requirement is counted a method;Areaand a concrete struct'sArearemain two separate nodes.The full Go / resolver / cross-language suite (927 tests) still passes.