Repository navigation
fix(go): a defined type links the types it is defined from - #2441
Merged
Merged
Conversation
A Go defined type (`type WatchChan <-chan WatchResponse`, gin's `type HandlerFunc func(*Context)` and `type HandlersChain []HandlerFunc`) is a `type_alias` node, and it referenced nothing: only an `=` alias (#2417) named the types on its right-hand side. Impact on `WatchResponse` or gin's `Context` missed the declarations built from them, and everything that uses those. Fix (TS extractor and the Rust kernel, mirrored): goAliasTypeNames / alias_type_names walk the `type` field of every type_alias node, a defined type's as well as an alias's, so each type it names becomes a `references` ref on that name, where resolution reads the package qualifier back. Still skipped: the declaration's own type parameters, Go's predeclared types, and now its own name written bare, which in a recursive type (prometheus' `type stateFn func(*Lexer) stateFn`) is the declaration itself: no self-edge, and no failed row that would make dead code treat every namesake as referenced. A qualified name is never skipped (`type PutResponse pb.PutResponse` names pb's). Resolution is unchanged. A defined type is a new type: goAliasTarget still follows `=` aliases only, so a method called on a defined type is not looked up on its underlying type. The gateTargetKind rule that leaves a type_alias's reference written through a package the index doesn't know unresolved now covers defined types too; without it, every such name bound to the same-file declaration of its name (`type Op clientv3.Op` linked itself). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kov-a3877b # Conflicts: # CHANGELOG.md
This was referenced Oct 7, 2026
Merged
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.
A Go defined type such as etcd's
type WatchChan <-chan WatchResponse(client/v3/watch.go), gin'stype HandlerFunc func(*Context)ortype HandlersChain []HandlerFuncwas atype_aliasnode with noreferencesedge to the types it is defined from. Impact onWatchResponseor gin'sContextmissed those declarations and everything that uses them. Only=aliases (#2417) named their right-hand side.Fix
TS extractor and Rust kernel, mirrored:
goAliasTypeNames(src/extraction/languages/go.ts) andalias_type_names(codegraph-kernel/src/go.rs) now walk thetypefield of everytype_aliasnode: a defined type's (a non-struct, non-interfacetype_spec) as well as an alias's.referencesref on that name, where resolution reads the package qualifier back.type PutResponse pb.PutResponsenames pb's type.No resolver change.
Design points
Method lookup stays alias-only. A defined type is a new type, and Go doesn't give it the methods of the type it is defined from.
goAliasTargetstill recognizes only declarations with=, soresolveGoMethodInPackagedoesn't follow a defined type's newreferencesedge. A test pins it:r.GetHeader()ontype PutResponse pb.PutResponsestays unresolved, rather than reaching pb'sGetHeaderor a namesake's.The unknown-qualifier gate covers defined types too, and that's wanted. #2417's
gateTargetKindrule leaves areferencesref from anytype_aliasunresolved when it is written through a package the index doesn't know.import "go.etcd.io/etcd/client/v3"(packageclientv3, which the index knows only asv3orclient), disabling the rule bound every such name to the same-file declaration of its name:type Op clientv3.Oplinked itself;type WatchResponse clientv3.WatchResponselinked itself;type Watcher clientv3.Opandfunc(op clientv3.Op)linked the localordering.Op.A recursive type's self-reference is skipped at extraction. Example: prometheus'
type stateFn func(*Lexer) stateFn, the only one in the three repos.ontype, field types, generic arguments in expressions and top-level initializers) #2327).failedunresolved row namedstateFn. Dead code reads such a row as a reference it couldn't follow, for every symbol of that name.Validation
Before/after full indexes on current main (ed199e6, which has #2417, #2414, #2416 and #2419), with site-keyed diffs. Each added edge was judged against Go's scoping: a bare name is its own package's type, and
pkg.Xis the type of the package whose real package clause ispkg.pkg.X→ that packagereferencesedge from a defined type to a struct, interface or other type, in the right package. There are 0 new self-loops, and no node, synthesized-edge or metadata changes.context,http,time,k8s.io/utils/cpuset,k8s.io/gengo/v2/types.scripts/kernel-parity.mjs --lang go: gin 99/99, prometheus 736/736, etcd 1065/1105 with 0 diffs. etcd's 40 deferred files are the same 40 as before.Impact at depth 3, before → after:
WatchResponseWatchChanand its usersContextHandlerFunc,HandlersChain,RecoveryFunc,SkipperPutResponsePutResponseand its usersTests
__tests__/go-defined-type-refs.test.ts:__tests__/go-type-alias.test.ts: the defined types in fix(go): a type aliastype A = Bis indexed and links to the type it names #2417's fixture (WatchChan,Defined) now reference too.__tests__/fixtures/kernel-parity/torture.gogains the defined-type shapes, so parity is checked in LF and CRLF.go-nested-module.test.tsskipped onedescribeunder load in the batch run and passed 11/11 when rerun alone.function-ref's Python Caller/impact graph misses methods passed as first-class references (callbacks), e.g. executor.submit(obj.method, …) #1820 case passes in 286 s once its in-file 60 s limit is raised.mpeg-ts-not-typescript's TypeScript-only 2 s indexing bound fails the same way on main's source at this load (2.2 s, 3.2 s).HandlerFunc→ a latercontext.go'sContext).Notes
type A = Bis indexed and links to the type it names #2417, which landed while this was in progress; this branch is rebased onto it.referencesedges out of structs at all, so impact onResponseHeadermissesPutResponse{Header *ResponseHeader}. That gap is filed as a follow-up task rather than widened into this PR.🤖 Generated with Claude Code