package gotypes
Import Path
go.pact.im/x/plumb/internal/gotypes (on go.dev)
Dependency Relation
imports 6 packages, and imported by 4 packages
Involved Source Files
cmp.go
Package gotypes is plumb's go/types toolkit: the type-graph walks, structural
matching, substitution, and predicates the core needs to reason about loaded
types. Everything here is a pure function of its go/types inputs (no plumb
concepts, no diagnostics), so it can sit below every phase and be tested on its
own. It is to go/types what the gopackages package is to go/packages.
subst.go
unify.go
walk.go
Package-Level Type Names (total 3, in which 2 are exported)
Type Parameters:
K: types.Type
V: any
Map is a type-keyed map with typed values. The zero value is an empty map ready
to use.
m typeutil.Map
All iterates the entries in unspecified order; it satisfies iter.Seq2[K, V].
At returns the value stored for key and whether it was present.
Len returns the number of entries.
Set stores value for key, replacing any previous value.
func go.pact.im/x/plumb/internal/solve.sortTypesByProducer(ts []types.Type, supply *Map[types.Type, *solve.Instance])
Type Parameters:
T: types.Type
Set is a type-keyed set. The zero value is an empty set ready to use; it is the
visited-set for cyclic-type-safe graph walks and the presence-set the solver
keeps of demanded, consumed, and already-instantiated types.
m typeutil.Map
Add records t and reports whether it was newly added: false if t was already
present. A cyclic-type walk guards recursion with `if !seen.Add(t) { return }`,
which stops on a revisit.
Contains reports whether t is in the set.
Elements iterates the members in unspecified order; it satisfies iter.Seq[T].
Callers that need a deterministic order sort what they collect.
func tupleContains(tup *types.Tuple, seen *Set[types.Type], pred func(types.Type) bool) bool
func typeContains(t types.Type, seen *Set[types.Type], pred func(types.Type) bool) bool
func typeDepthRec(t types.Type, seen *Set[types.Type]) int
func walkNamed(t types.Type, seen *Set[types.Type], visit func(*types.TypeName) bool)
func walkTuple(tup *types.Tuple, seen *Set[types.Type], visit func(*types.TypeName) bool)
Package-Level Functions (total 38, in which 25 are exported)
CmpType is a deterministic, environment-independent order over types, used to
sort type slices into a stable order, never for identity (that goes through
typeutil.Map) and never for output (that goes through a qualifier). Named types
are ordered by package path + name rather than pointer, and every level is
unaliased before comparison, so the order never depends on pointer addresses,
load order, or whether a type was first seen through an alias. It is the
ordering authority for types, so gotypes never has to serialize a type to a
string except when rendering output or diagnostics.
It is a WEAK order, not a structural total order: types that are not
types.Identical can still compare equal. Named types are keyed on package
path + name + type args (not their full definition), and type parameters on
name + index (see the TypeParam case). Determinism therefore rests entirely on
the absence of ties, not on the sort: every sorted slice holds types drawn from
identity-keyed sets of provider-signature types that already differ in those
keys, so no two elements ever compare equal, and the determinism tests guard
that empirically: solve's TestNoCmpTypeTiesInSortedSlices asserts no tie
reaches those sort sites. A structural string tiebreaker cannot substitute for
this invariant: two distinct type parameters that share a name render
identically, so no deterministic key separates them (their only distinguisher
is object identity, which is exactly what this order avoids). Stability cannot
be the safeguard either: several of these slices are collected from
nondeterministically-ordered maps, where a stable sort would only preserve a
nondeterministic input order. Callers still use a stable sort, but for
consistency with plumb's other ordering sites rather than for determinism here.
ConstraintCollapsesToAny reports whether a type-parameter constraint renders as
the bare keyword "any": an interface with no methods and no embeddeds that is
not the predeclared comparable. emit renders such a constraint as "any" and
names neither it nor its package, so solve's reachability check must agree.
This is the single predicate both consult, so they cannot drift (a collapsed
unexported constraint must not be rejected, and a rendered one must be imported).
ContainsInvalid reports whether t mentions the invalid type anywhere, meaning
it failed to type-check and plumb must not render it.
ContainsTypeParam reports whether t mentions any type parameter anywhere:
the test for a pinning that cannot survive a resolution restart, since lifted
parameters are per-run objects.
DualType returns the value/pointer dual of a bridgeable type. The argument
may be either form: for a pointer to a bridgeable type it returns the element
(*E → E), for a bridgeable non-pointer the pointer type (T → *T), and for
everything else (nil, false).
GenericOrigin returns the generic origin of t. t is a provider's declared or
receiver type, which is always a *types.Named or a *types.Alias; any other
shape is a broken invariant and panics rather than passing t through, which
would mask the bug downstream.
IsBareCleanup reports whether t is the bare type func() (no params, no
results). A *named* function type is not bare; a type *alias* to func() is,
since an alias and its target are the same type.
IsBareTypeParam reports whether t is exactly one of the given type parameters.
IsErrorType reports whether t is exactly the predeclared error interface.
IsFailableCleanup reports whether t is the bare type func() error.
IsPointerToBareTypeParam reports whether t is *T for a type parameter T in
params. Such a result matches every pointer demand, and through the
value/pointer bridge every value demand too, so, like a bare T, it cannot be
a demand-driven producer.
IsUniverseName reports whether name is a predeclared identifier.
IsUntyped reports whether t is an untyped basic type (e.g. an untyped
constant's default-less type).
IsUntypedNil reports whether t is the predeclared untyped nil.
KindOfType names the broad shape of t for a "not a struct" diagnostic:
interfaces are called out by name, and everything else is "a non-struct type".
ListKey packs a type list into a tuple usable as a typeutil.Map key:
types.Identical compares tuples element-wise (ignoring the synthetic names), so
two identical lists collapse to one entry. It backs the (provider, type-args)
instantiation keys, where the provider supplies the outer map dimension.
MentionsParam reports whether t mentions the single type parameter tp. It is
the singular form of MentionsParams over the same typeContains walk, for
callers testing one parameter at a time without building a one-element set.
MentionsParams reports whether t mentions any of the given type parameters.
It shares typeContains's exhaustive type walk (which panics on an unhandled
go/types kind rather than silently reporting false), testing membership in
params at each type-parameter leaf.
Subst returns t with every type parameter in m replaced by its mapped type.
Only the nodes on the path to a substituted parameter are rebuilt; a subtree
that mentions none of the mapped parameters is returned unchanged, so special
types such as the predeclared comparable constraint and named cross-package
interfaces keep their identity.
ctxt deduplicates any generic types Subst must re-instantiate; pass the caller's
shared context so identical instantiations resolve to one instance. A nil ctxt
is valid (a throwaway): correctness never depends on instance identity, because
the result is rendered to source text and inspected structurally (go/types
Identical, underlying-type assertions, reachability walks), never keyed by an
instance pointer.
TypeDepth returns a structural nesting depth used to bound non-terminating
generic instantiation.
TypeName renders t for diagnostics, qualifying foreign packages by name.
TypeNameOf returns the declaring object of t. t is a provider's declared or
receiver type, always a *types.Named or a *types.Alias; any other shape
panics. Returning a nil *types.TypeName instead would wrap a nil pointer in a
non-nil types.Object interface (a typed-nil that slips past a caller's
obj != nil guard and nil-panics on first use), so the invariant is enforced
here, where every caller then gets a non-nil result.
TypeParamsOf returns the type parameters of t. As with GenericOrigin, t is a
provider's declared or receiver type and is always a *types.Named or a
*types.Alias; any other shape panics.
Unify matches a pattern type (which may mention the template's type
parameters) against a concrete demand type, recording the type-parameter
bindings it discovers. It reports whether the match succeeds. Only the type
parameters in params are treated as variables; every other type node must be
structurally identical.
WalkNamed visits every named type reachable from t, invoking visit for each type
name. It does not descend into a type parameter's constraint; a caller that needs
the constraint walks it separately. When visit returns false for a name, the walk does
not descend into that name's type arguments (it prunes below the node); it
still visits the rest of the tree, so this controls descent, not whole-walk
termination. A caller that wants to stop entirely self-guards inside visit.
Package-Level Variables (total 3, none are exported)
The pages are generated with Golds v0.8.4. (GOOS=linux GOARCH=amd64)