Commit Graph
4 Commits
Author SHA1 Message Date
Colby MchenryandClaude Opus 5.5 847f1df77d fix(go): an interface or struct embedding a standard-library type counts its methods (#2759)
goImplementsEdges (#584) follows declared embeddings since #2402, but an
embedding of a type outside the index resolves to nothing, so it added no
methods: prometheus's TBRun (testing.TB plus Run) went to a struct with only
a Run, QueryLogger (slog.Handler plus io.Closer) had no implementations,
kapacitor's Diagnostic (a third-party Logger plus Log) took every struct with
a Log, and the predeclared `error` was not recorded at all.

- go-stdlib-methods.ts lists the methods of 130 standard-library types, each
  as `name:params/results`, generated from go1.27.3's source and counted the
  way goSignatureArity counts a stored signature.
- Both extractors record an embedded `error`, which stays unresolved. The
  predeclared-type set is unchanged, so alias and defined-type references
  still skip it.
- goImplementsEdges reads each Go type's failed `extends` rows and reads the
  package back off the line (goRefQualification, now exported). A
  standard-library type's methods join the method set, keyed as goMethodKey
  keys the project's (`std:<import path>` for an unexported one), and the
  arity gate holds them to the table's counts on both sides: a `sync.Mutex`
  makes a struct hugo's `Locker`, not etcd's gRPC `LockClient`. Any other
  outside type is met by a type embedding the same one, or by the only type
  with every other method the interface names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 18:13:54 +00:00
Colby MchenryandClaude Opus 5.5 d8a7f868b3 fix(go): an unaliased import is also known by the name goimports assumes for its package (#2410)
An unaliased Go import was named by its path's last element, so the
qualifier in yaml.Node (go.yaml.in/yaml/v3), klog.V (k8s.io/klog/v2) or
sqlite3.Error (github.com/mattn/go-sqlite3) matched none of the file's
imports. The reference then resolved by its bare name to whatever project
symbol shared it.

An unaliased import now also takes the name goimports'
ImportPathToAssumedName gives its path (the last element that isn't a
major version, without a go- prefix, cut at the first non-identifier
character), unless another import of the file is bound to that name or a
second import assumes it too. The last element stays registered:
k8s.io/api/core/v1 really is package v1.

The import scan now reads only the import section, without comments: the
last word of a comment had become the next import's alias, and imports
spelled in doc comments or string literals were read as real ones.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 08:15:52 +00:00
Colby MchenryandClaude Opus 5.5 fe9518357c fix(go): satisfying an interface counts the methods embedding brings in (#2402)
* fix(go): satisfying an interface counts the methods embedding brings in

goImplementsEdges (#584) built each interface's method set and each struct's
from their own `contains` edges only. Embedded interfaces are `extends` edges
since #2397, and embedded structs `extends` (or `implements` for an embedded
interface), so both sides now follow those declared edges, recursively and
around cycles: an interface asks for the methods of the interfaces it embeds,
and a struct has the methods promoted from the structs, interfaces and
defined types it embeds. Synthesized edges are never followed.

A struct that embeds the interface keeps its declared edge rather than gaining
a synthesized duplicate, and under the per-interface cap, structs that declare
every method themselves are linked before those that need promoted ones, so
the cap keeps the implementations interface-impl dispatch reaches. The
empty-interface skip and the cap are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(go): the embedding test's supertype list reads declared edges only

Store in that fixture now satisfies other.Closer through the Close that
*storage.Base promotes, a go-implements edge synthesized from method names.
The assertion is about how declared embeddings resolve, as the rest of the
test already treats synthesized edges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 02:39:46 +00:00
Colby MchenryandClaude Opus 5.5 24501fa66c fix(go): an interface links the interfaces it embeds (#2397)
extractInheritance's Go interface-embedding branch matched a
`constraint_elem`, a node type neither the vendored tree-sitter-go wasm
nor the kernel's tree-sitter-go 0.23 crate has: both parse an embedded
interface as a `type_elem` holding one type. So no Go interface ever
extended anything, in either engine; gin's IRouter never reached IRoutes.

Read an embedded type the same way in an interface and in a struct:
`T`, `*T`, `pkg.T` and `T[X]` all embed `T`, recorded at the name so
resolution reads the package back from the source (#2322). A type_elem
holding a union, a `~T` term or a lone predeclared type is a type-set
constraint and records nothing, and predeclared names (`error`, `any`)
are skipped in structs too. Qualified and generic struct embeddings,
skipped until now, link the same way.

Resolution keeps an embedded type in its package. The Go framework
resolver's naming heuristics no longer take extends/implements refs: its
PascalCase-model pattern saw structs only, so an embedded interface went
to another package's same-named struct (promql/parser's Node, etcd's
Lease), as #1827 did for Spring. And a Go supertype written through a
package that is none of the file's imports as indexed (`yaml` under an
unaliased go.yaml.in/yaml/v3, registered as `v3`) stays unresolved
instead of binding by its bare name.

Validated on gin, prometheus and etcd (before/after edge diffs, every
added supertype edge checked against its package; kernel/wasm parity
sweeps unchanged).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 00:29:50 +00:00