Skip to content

fix(go): extract method requirements declared in an interface body - #3672

Open
rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/go-interface-method-requirements
Open

rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/go-interface-method-requirements

Conversation

@rajatnagda45

Copy link
Copy Markdown
Contributor

Problem

The Go interface_type branch 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_elem nodes — were skipped entirely.

So an interface like:

type Shape interface {
    Area() float64
    Perimeter() (float64, error)
}

became an empty node. Area and Perimeter never 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_elem children of the interface body too, mirroring the existing receiver-method path: each requirement becomes a .Method() node hung off the interface via a method edge, id-scoped under the interface type node (so an interface Area and a struct Area stay distinct). Embedding and type-set constraints are untouched — they still flow through the type_elem branch as embeds/references, so a bare embedded interface never gets mistaken for a method.

Test

New tests/test_go_interface_methods.py covers three things, all failing before the change and passing after:

  • method requirements surface as method nodes under the interface;
  • an embedded interface stays a heritage (embeds) edge and only the directly declared requirement is counted a method;
  • an interface's Area and a concrete struct's Area remain two separate nodes.

The full Go / resolver / cross-language suite (927 tests) still passes.

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.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-test
  • tests/test_languages.py — impact
  • tests/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).

@rajatnagda45

Copy link
Copy Markdown
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant