Documentation
¶
Overview ¶
Package typesutil exposes small, dependency-light helpers around go/types for test and tool code in this module.
Boundary with tools/archtest/internal/typeseval:
- typeseval is archtest-internal (SharedResolver, build-tag matrix, generated-path skip, etc.) and lives under internal/ so it cannot be imported from outside tools/archtest.
- typesutil is non-internal and importable from any _test.go in the module (archtest rules, kernel/* tests).
Constraints:
- stdlib + golang.org/x/tools only.
- No runtime/cells/adapters imports.
- Each helper does one go/types operation.
ref: golang.org/x/tools/go/types/typeutil StaticCallee ref: golang.org/x/tools/internal/typesinternal ReceiverNamed (pattern source; the upstream package is internal and unimportable)
Index ¶
- func ImplementsInterface(t types.Type, iface *types.Interface) bool
- func ImplementsInterfaceExact(t types.Type, iface *types.Interface) bool
- func ResolveCallee(typesInfo *types.Info, call *ast.CallExpr) (fn *types.Func, named *types.Named, isPtr bool, ok bool)
- func ResolveReceiverType(typesInfo *types.Info, call *ast.CallExpr) (named *types.Named, isPtr bool, ok bool)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ImplementsInterface ¶
ImplementsInterface reports whether t — as a value OR via its pointer — satisfies iface. It mirrors the go/types.Implements(V, T) argument shape and adds the value-or-pointer convenience: a value type may satisfy iface only through its pointer method set, so when the value form does not implement and t is not already a pointer, the *t form is tried. The pointer wrap is skipped when t is already a *types.Pointer (a **T method set adds nothing over *T).
Use ImplementsInterfaceExact when the no-pointer-fallback semantic is intentional — e.g. t may itself be an interface type and a synthetic pointer-to-interface check would be meaningless.
Signature note: the previously-proposed (typesInfo, expr, ifaceObj) shape was deliberately rejected — none of the consolidated call sites hold an ast.Expr at the point of check (they take a struct field, obj.Type(), or a parameter type). This shape mirrors stdlib go/types.Implements(V, T).
AI-robust note: the ImplementsInterface vs ImplementsInterfaceExact choice is a name-level (Medium) distinction — both share one signature, so picking the wrong one is not a compile error. The fixture-level guard is the discriminating test case in implements_interface_test.go. The Hard layer (banning raw go/types.Implements outside this file) is enforced by archtest TYPESUTIL-IMPLEMENTS-FUNNEL-01 (tools/archtest/implements_funnel_test.go).
Edge cases (covered by implements_interface_test.go):
- value-receiver impl / pointer-receiver-only impl via value / via *T
- t already *types.Pointer (true path, no double-wrap)
- t already *types.Pointer and non-impl (no **T fallback)
- promoted (embedded) interface methods
- generic instantiated named types
- non-impl / nil t / nil iface
ref: golang.org/x/tools go/analysis/passes/copylock (types.Implements +
pointer-receiver method-set idiom)
func ImplementsInterfaceExact ¶
ImplementsInterfaceExact is the strict, value-only satisfaction check — the deliberate no-pointer-fallback counterpart of ImplementsInterface. Use it where t may itself be an interface type and a synthetic pointer-to-interface check would be semantically meaningless (e.g. the CELL-RAW-INFRA-PUBLIC-OPTION-PARAM-01 anonymous-interface bypass detector, where t is frequently a *types.Interface).
This file is the sole sanctioned site for raw go/types.Implements. The archtest TYPESUTIL-IMPLEMENTS-FUNNEL-01 (tools/archtest/implements_funnel_test.go) rejects any go/types.Implements reference — call, dot-import, import-alias, or func-value — anywhere else; route every interface-satisfaction check through ImplementsInterface / ImplementsInterfaceExact instead.
func ResolveCallee ¶
func ResolveCallee(typesInfo *types.Info, call *ast.CallExpr) (fn *types.Func, named *types.Named, isPtr bool, ok bool)
ResolveCallee returns the static method callee together with its receiver's named type for a method call. This is the canonical resolver for archtest / governance rules that need both pieces — typically the signature (for parameter / return type checks) AND the receiver named type (for owner-package or specific-type checks).
Returns ok=false in the same cases as ResolveReceiverType: builtins, interface dispatch, package-level functions, method values, methods on anonymous receivers.
Callers that only need the named receiver type should use ResolveReceiverType; this entry point exists so callers needing the signature don't pay a second typeutil.StaticCallee lookup.
func ResolveReceiverType ¶
func ResolveReceiverType(typesInfo *types.Info, call *ast.CallExpr) (named *types.Named, isPtr bool, ok bool)
ResolveReceiverType returns the named receiver type for a method call, e.g. (*scanner.Scanner) for s.EachInSubtree(...). It returns ok=false for any call that cannot be statically resolved to a method on a named type:
- builtins (StaticCallee returns nil)
- interface dispatch (StaticCallee filters interfaceMethod)
- package-level functions (Signature.Recv() is nil)
- method values (the call expression's Fun is a variable, not a Selector)
- methods on anonymous/unnamed types (no *types.Named to return)
The isPtr return distinguishes pointer- and value-receiver methods. Callers that only care about the named type may discard isPtr.
Edge cases:
- Promoted (embedded) methods return the embedded type's *types.Named, not the outer type. This mirrors what StaticCallee resolves to.
- Generic methods return the generic base *types.Named, not the instantiation. Callers needing instantiation info call TypeArgs() on the returned named type.
- Alias-pointer chains (`type P = *T; func (P) M()`) unalias before the pointer cast, matching upstream typesinternal.ReceiverNamed.
Types ¶
This section is empty.