Repository navigation
fix(go): a variable bound from a call is typed by what the call returns - #2961
Merged
Merged
Conversation
A Go method call on a local bound from a call or a conversion, like `r := newRing(); r.Reset()`, `v1 := router.Group(...); v1.GET(...)` or `c, r := CreateTestContext(w); r.Use(...)`, was matched by the method's name alone: inferLocalReceiverType reads a declaration's written type and a few line patterns, none of which reads a call's result. The by-name guess took a namesake (etcd's `lg := s.Logger()` linked `lg.Info(...)` to a project logger's Info, prometheus's `NewWriteHandler(...)` results to the read handler's ServeHTTP), or found nothing. Main already types a value from its declaration for indexed and chained calls (goDeclaredValueType, #2782). Plain receivers now use it too: a local whose in-scope declaration has a call or a conversion as its value takes that value's type (the k-th result of several, a method's result, a conversion's type), read in the file that writes it (GoReceiverDecl.file), for matchMethodCall, matchMemberFunctionRef and matchGoFieldChainCall. A value of a type from outside the project links nothing, including one a project function returns as an outside interface. Assertions stay with goAssertedLocalType, and a type switch's guard is not typed from its value. The typer itself, for every path that uses it: - a trailing `.(T)` is a T whatever its prefix (`pool.Get().(*Conv)`); - a call through a func-typed field gives the field's result type; - a bare call a dot import brings in is typed (`package watch_test` calling `NewStreamWatcher(...)`); - a method of a struct or interface literal, of an outside generic type (grpc's `ServerStreamingClient[Resp].Recv()`) or one the index doesn't show on a project type gives an unknown type, not "outside", so name matching runs as before. Validation: - go-receiver-type.test.ts (the PR's 23 cases, 2 expectations updated where the call is now typed, plus 4 ours), go-std-method-receivers.test.ts and go-chained-receivers.test.ts: on main 19 of 51 fail; all pass here. All 45 go-*.test.ts files pass (491 tests). - A/B vs main 2577601 (same kernel): gin +194/-52/65 moved, etcd +4,441/-359/743, prometheus +7,041/-239/1,409, a kubernetes staging subtree +1,154/-86/354, harbor without its portal +423/-138/366. express and flask byte-identical. Sampled additions right; removals are outside values (zap, os, grpc, otel, beego, pflag) and the outside- interface results, about 80% of which were wrong by sample. Known loss: a type defined over an interface (`type Codec Serializer`) has no methods in the index, so a coincidental guess on such a value goes, as in #2706. - Compared with PR #1954 on the same repos: 4,962 more links and 360 of its edges gone, those mostly wrong guesses (166 of them the outside- interface results); its declaration-line restriction also lost right links on range variables and field values, which this leaves to main's scan. - CPU (profile self time of receiver typing): prometheus 1.82 -> 1.72 s, k8s subtree 0.88 -> 0.92 s, harbor 1.02 -> 0.86 s. Reimplements PR #1954 by @danusha2345 on main's value typer; its tests are included. Co-authored-by: danusha2345 <ewidusoc498@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
danusha2345
pushed a commit
to danusha2345/codegraph
that referenced
this pull request
Oct 28, 2026
…mchenry#2972; 10 landed PRs yield to main; EXTRACTION_VERSION 56) Main landed ten more of our PRs as our own commits with the maintainer's additions (colbymchenry#2923 ← colbymchenry#1936, colbymchenry#2924 ← colbymchenry#1951, colbymchenry#2925 ← colbymchenry#1939, colbymchenry#2930 ← colbymchenry#2921, colbymchenry#2940 ← colbymchenry#1736, colbymchenry#2942 ← colbymchenry#1947, colbymchenry#2950 ← colbymchenry#1952, colbymchenry#2961 ← colbymchenry#1954, colbymchenry#2965 ← colbymchenry#1942, colbymchenry#2972 ← colbymchenry#1933) and the module-path half of colbymchenry#2308 (colbymchenry#2955). Where the integration carried our version, main's wins: the enclosing-scope member pick and its tests, the Go and Java receiver typers, the delegating-call self-loop rule, the duplicated-module copy confidence, the C #if collapse, the module-path resolution of Rust paths, the trail/path hardening in utils.ts. Kept beside main: colbymchenry#1875's Verilog hooks and status fields, colbymchenry#2839's implementations command, colbymchenry#1923, colbymchenry#2922, colbymchenry#2258, colbymchenry#1761, colbymchenry#1583, the bare-call half of colbymchenry#2308 (rust-use-bindings.ts). CHANGELOG is main's plus the open PRs' bullets. EXTRACTION_VERSION 56: the C #if group handling (colbymchenry#2940) and the kernel change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
Summary
In Go, a method called on a variable that holds what a call returns, like
r.Reset()afterr := newRing(),v1.GET(…)afterv1 := router.Group("/v1"), orr.Use(…)afterc, r := CreateTestContext(w), now links to the method of the type that call returns. Before, these were matched by the method's name alone. A value of a type from outside the project, such asc, _ := net.Dial(…), an*os.Fileor anhttp.Handlera project function returns, now links to nothing instead of a project namesake.This reimplements @danusha2345's PR #1954 on the value typer main already has (#2782), with their tests.
Root cause
inferLocalReceiverTypetypes a Go receiver from the type its in-scope declaration writes (s *store.Store,x := &T{…}) and from a few line patterns. None of them reads a call's result, so a local bound from a call fell through to name matching. That guess took a namesake: etcd'slg := s.Logger()linkedlg.Info(…)to a project logger'sInfo, and prometheus'sNewWriteHandler(…)results to the read handler'sServeHTTP. Or it found nothing.Fix
main has typed a value from its declaration since #2782 (
goDeclaredValueType→goCalledType/goSignatureResultType/goMethodResultType), but only for indexed and chained calls. PR #1954 added a second, regex-based derivation of the same thing (goBoundCallResultwith a paren scan of up to 40 lines per scanned line,goFirstResult,goMethodOfWrittenType). This change uses main's typer for plain receivers instead:GoReceiverDecl.file), formatchMethodCall,matchMemberFunctionRefandmatchGoFieldChainCall.goAssertedLocalType, and a type switch's guard is not typed from its value.Changes to the typer, for every path that uses it:
.(T)is a T whatever its prefix (prometheus'srw.converterPool.Get().(*PrometheusConverter));h.ArtifactControllerFunc());package watch_testcallingNewStreamWatcher(…));ServerStreamingClient[Resp].Recv()), or one the index doesn't show on a project type gives an unknown type rather than "outside", so name matching runs as before.Validation
Red→green:
go-receiver-type.test.ts(the PR's 23 cases plus 4 of ours),go-std-method-receivers.test.tsandgo-chained-receivers.test.ts: on main 19 of 51 fail; all pass here. All 45go-*.test.tsfiles pass (491 tests).Expectations changed, where a call is now typed:
selfArg: the innereofif e := wrap(e.Run())is wrap's*ringLog;chainedCtor:r := newRing().Reader()is areader;versionTextandurls(std-method file): typed at 0.9;h.get().Run()through aget func() Afield:A::Run;interfaceResultnow links nothing (policy above).A/B (same kernel; main 2577601 for this branch; the PR on its own cherry-pick; no Go drift between the bases):
express and flask are byte-identical.
Triage, by sample:
clus := testRunner.NewCluster(…),app := head.Appender(ctx),tx := b.BatchTx(),v1 := router.Group(…)).Outside-interface results (a project function's result written as an outside type), about 167 by-name links over the five repos, about 80% wrong:
Recv; everyNewWriteHandler(…)result linked toreadHandler::ServeHTTP; areflect.Valuelinked toQuantityValue::Type; harbor'sHTTPStatusCodeHealthChecker(…), docker'shealth.CheckFunc, linked toupdater::Check;PeriodicHealthChecker(updater), kubernetes'NewTracker(TrackerValue), etcd'sNewRaftLoggerFromZapCore(zapRaftLogger).return &T{…}to type that minority.Known loss, as in fix(go): a call through a variable declared with another package's type reaches that type's method #2706: a type defined over an interface (
type Codec Serializer) has no methods in the index, so a coincidental guess on such a value (codec := ….LegacyCodec(gv)) goes.The ~199 kubernetes call-result sites fix(go): a call on an indexed element reaches its element type's method #2755 left are indexed calls, which fix(go): a call further along a chain links the method of the type the chain reaches #2782 already serves: no change (etcd 24, prometheus 161, k8s 48, harbor 24 sites; 0 differ).
CPU, profile self time of receiver typing, main → this branch: prometheus 1.82 → 1.72 s, kubernetes subtree 0.88 → 0.92 s, harbor 1.02 → 0.86 s. For comparison, the PR's
goBoundCallResultalone took 390–699 ms on these.Full suite on the exact commit (Windows, kernel built,
CODEGRAPH_KERNEL_EXPECT=1,--maxWorkers=4): 777 files, 9,202 passed, 0 failed, 85 skipped.Reimplements #1954 by @danusha2345, whose tests are included (co-author on the commit). Its overlap with first-time PRs: #1640's cases already pass on main (#2782), and #1521 (multi-module layouts) is outside this change.
🤖 Generated with Claude Code