Documentation
¶
Index ¶
- func FindNestingFunc(obj types.Object) *types.Func
- func HasTypeParams(typ types.Type) bool
- func SignatureTypeParams(sig *types.Signature) *types.TypeParamList
- type Collector
- type Instance
- type InstanceMap
- func (im *InstanceMap[V]) Delete(key Instance) bool
- func (im *InstanceMap[V]) Get(key Instance) V
- func (im *InstanceMap[V]) Has(key Instance) bool
- func (im *InstanceMap[V]) Iterate(f func(key Instance, value V))
- func (im *InstanceMap[V]) Keys() []Instance
- func (im *InstanceMap[V]) Len() int
- func (im *InstanceMap[V]) Set(key Instance, value V) V
- func (im *InstanceMap[V]) String() string
- type InstanceSet
- func (iset *InstanceSet) Add(instances ...Instance) *InstanceSet
- func (iset *InstanceSet) ByObj() map[types.Object][]Instance
- func (iset *InstanceSet) ForObj(obj types.Object) []Instance
- func (iset *InstanceSet) ID(inst Instance) int
- func (iset *InstanceSet) ObjHasInstances(obj types.Object) bool
- func (iset *InstanceSet) Values() []Instance
- type PackageInstanceSets
- type Resolver
- func (r *Resolver) Nest() *types.Func
- func (r *Resolver) NestTypeArgs() []types.Type
- func (r *Resolver) NestTypeParams() *types.TypeParamList
- func (r *Resolver) String() string
- func (r *Resolver) Substitute(typ types.Type) types.Type
- func (r *Resolver) SubstituteAll(list *types.TypeList) []types.Type
- func (r *Resolver) SubstituteSelection(sel typesutil.Selection) typesutil.Selection
- func (r *Resolver) TypeArgs() []types.Type
- func (r *Resolver) TypeParams() *types.TypeParamList
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FindNestingFunc ¶
FindNestingFunc returns the function or method that the given object is nested in. Returns nil if the object was defined at the package level, the position is invalid, or if the object is a function or method.
This may get different results for some specific object types (e.g. receivers, type parameters) depending on the Go version. In go1.19 and earlier, some objects are not nested in the function they are part of the definition of, but in later versions they are.
func HasTypeParams ¶
HasTypeParams returns true if object defines type parameters.
Note: this function doe not check if the object definition actually uses the type parameters, neither its own, nor from the outer scope.
func SignatureTypeParams ¶
func SignatureTypeParams(sig *types.Signature) *types.TypeParamList
SignatureTypeParams returns receiver type params for methods, or function type params for standalone functions, or nil for non-generic functions and methods.
Types ¶
type Collector ¶
type Collector struct { TContext *types.Context Instances *PackageInstanceSets // contains filtered or unexported fields }
Collector scans type-checked AST tree and adds discovered generic type and function instances to the InstanceSet.
Collector will scan non-generic code for any instantiations of generic types or functions and add them to the InstanceSet. Then it will scan generic types and function with discovered sets of type arguments for more instantiations, until no new ones are discovered.
InstanceSet may contain unprocessed instances of generic types and functions, which will be also scanned, for example found in depending packages.
Note that instances of generic type methods are automatically added to the set whenever their receiver type instance is encountered.
func (*Collector) Finish ¶
func (c *Collector) Finish()
Finish will finish the collecting instances by propagating instances of generic types and functions found in generic code. The generic code is rescanned with in an instances context to find internally defined instances.
This should only be called after all the files are scanned.
type Instance ¶
type Instance struct { Object types.Object // Object to be instantiated. TArgs typesutil.TypeList // Type params to instantiate with. // TNest is the type params of the function this object was nested with-in. // e.g. In `func A[X any]() { type B[Y any] struct {} }` the `X` // from `A` is the context of `B[Y]` thus creating `B[X;Y]`. TNest typesutil.TypeList }
Instance of a generic type or function.
Non-generic objects can be represented as an Instance with zero type params, they are instances of themselves.
func (Instance) IsTrivial ¶
IsTrivial returns true if this is an instance of a non-generic object and it is not nested in a generic function.
func (Instance) Recv ¶
Recv returns an instance of the receiver type of a method.
Returns zero value if not a method.
func (Instance) Resolve ¶
Resolve instantiates and performs a substitution of the instance to get the concrete type or function. This will panic if the instance is not valid, e.g. if there are a different number of type arguments than the type parameters.
If `tc` is non-nil, it de-duplicates the instance against previous instances with the same identity. See types.Instantiate for more info.
Instances of named types may be lazily substituted, meaning the underlying type may not be fully substituted with the type arguments when returned.
This is useful for quickly resolving an instance for a test or for debugging but this uses a temporary Resolver that will not be reused. When resolving several instances in the same context, it is more efficient to use NewResolver to take advantage of caching.
func (Instance) String ¶
String returns a string representation of the Instance.
Two semantically different instances may have the same string representation if the instantiated object or its type arguments shadow other types.
func (Instance) TypeParamsString ¶
TypeParamsString returns part of a Go type string that represents the type parameters of the instance including the nesting type parameters, e.g. [X;Y,Z].
func (Instance) TypeString ¶
TypeString returns a Go type string representing the instance (suitable for %T verb).
type InstanceMap ¶
type InstanceMap[V any] struct { // contains filtered or unexported fields }
InstanceMap implements a map-like data structure keyed by instances.
Zero value is an equivalent of an empty map. Methods are not thread-safe.
Since Instance contains a slice and is not comparable, it can not be used as a regular map key, but we can compare its fields manually. When comparing instance equality, objects are compared by pointer equality, and type arguments with types.Identical(). To reduce access complexity, we bucket entries by a combined hash of type args. This type is generally inspired by [golang.org/x/tools/go/types/typeutil#Map]
func (*InstanceMap[V]) Delete ¶
func (im *InstanceMap[V]) Delete(key Instance) bool
Delete removes the entry with the given key, if any. It returns true if the entry was found.
func (*InstanceMap[V]) Get ¶
func (im *InstanceMap[V]) Get(key Instance) V
Get returns the stored value for the provided key. If the key is missing from the map, zero value is returned.
func (*InstanceMap[V]) Has ¶
func (im *InstanceMap[V]) Has(key Instance) bool
Has returns true if the given key is present in the map.
func (*InstanceMap[V]) Iterate ¶
func (im *InstanceMap[V]) Iterate(f func(key Instance, value V))
Iterate calls function f on each entry in the map in unspecified order.
Return true from f to continue the iteration, or false to stop it.
If f should mutate the map, Iterate provides the same guarantees as Go maps: if f deletes a map entry that Iterate has not yet reached, f will not be invoked for it, but if f inserts a map entry that Iterate has not yet reached, whether or not f will be invoked for it is unspecified.
func (*InstanceMap[V]) Keys ¶
func (im *InstanceMap[V]) Keys() []Instance
Keys returns a new slice containing the set of map keys. The order is unspecified.
func (*InstanceMap[V]) Len ¶
func (im *InstanceMap[V]) Len() int
Len returns the number of elements in the map.
func (*InstanceMap[V]) Set ¶
func (im *InstanceMap[V]) Set(key Instance, value V) V
Set new value for the key in the map. Returns the previous value that was stored in the map, or zero value if the key wasn't present before.
func (*InstanceMap[V]) String ¶
func (im *InstanceMap[V]) String() string
String returns a string representation of the map's entries. The entries are sorted by string representation of the entry.
type InstanceSet ¶
type InstanceSet struct {
// contains filtered or unexported fields
}
InstanceSet allows collecting and processing unique Instances.
Each Instance may be added to the set any number of times, but it will be returned for processing exactly once. Processing order is not specified.
func (*InstanceSet) Add ¶
func (iset *InstanceSet) Add(instances ...Instance) *InstanceSet
Add instances to the set. Instances that have been previously added to the set won't be requeued for processing regardless of whether they have been processed already.
func (*InstanceSet) ByObj ¶
func (iset *InstanceSet) ByObj() map[types.Object][]Instance
ByObj returns instances grouped by object they belong to. Order is not specified.
func (*InstanceSet) ForObj ¶
func (iset *InstanceSet) ForObj(obj types.Object) []Instance
ForObj returns the instances that belong to the given object type. Order is not specified. This returns the same values as `ByObj()[obj]`.
func (*InstanceSet) ID ¶
func (iset *InstanceSet) ID(inst Instance) int
ID returns a unique numeric identifier assigned to an instance in the set. The ID is guaranteed to be unique among all instances of the same object within a given program. The ID will be consistent, as long as instances are added to the set in the same order.
In order to have an ID assigned, the instance must have been previously added to the set.
Note: these ids are used in the generated code as keys to the specific type/function instantiation in the type/function object. Using this has two advantages:
- More compact generated code compared to string keys derived from type args.
- Collision avoidance in case of two different types having the same name due to shadowing.
Here's an example where it's very difficult to assign non-colliding name-based keys to the two different types T:
func foo() { type T int { type T string } // Code block creates a new nested scope allowing for shadowing. }
func (*InstanceSet) ObjHasInstances ¶
func (iset *InstanceSet) ObjHasInstances(obj types.Object) bool
ObjHasInstances returns true if there are any instances (either trivial or non-trivial) that belong to the given object type, otherwise false.
func (*InstanceSet) Values ¶
func (iset *InstanceSet) Values() []Instance
Values returns instances that are currently in the set. Order is not specified.
type PackageInstanceSets ¶
type PackageInstanceSets map[string]*InstanceSet
PackageInstanceSets stores an InstanceSet for each package in a program, keyed by import path.
func (PackageInstanceSets) Add ¶
func (i PackageInstanceSets) Add(instances ...Instance)
Add instances to the appropriate package's set. Automatically initialized new per-package sets upon a first encounter.
func (PackageInstanceSets) ID ¶
func (i PackageInstanceSets) ID(inst Instance) int
ID returns a unique numeric identifier assigned to an instance in the set.
See: InstanceSet.ID().
func (PackageInstanceSets) Pkg ¶
func (i PackageInstanceSets) Pkg(pkg *types.Package) *InstanceSet
Pkg returns InstanceSet for objects defined in the given package.
type Resolver ¶
type Resolver struct {
// contains filtered or unexported fields
}
Resolver translates types defined in terms of type parameters into concrete types, given a root instance. The root instance provides context for mapping from type parameters to type arguments so that the resolver can substitute any type parameters used in types to the corresponding type arguments.
In some cases, a generic type may not be able to be fully instantiated. Generic named types that have no type arguments applied will have the type parameters substituted, however the type arguments will not be applied to instantiate the named type.
For example, given `func Foo[T any]() { type Bar[U *T] struct { x T; y U } }`, and if `Foo[int]` is used as the root for the resolver, then `Bar[U *T]` will be substituted to create the generic `Bar[U *int] struct { x int; y U }`. Alternatively, the instantiated but still generic because of the `T`, `Bar[bool] struct { x T; y bool}` will be substituted for `Foo[int]` to create the concrete `Bar[bool] struct { x int; y bool }`.
Typically the instantiated type from `info.Instances` should be substituted to resolve the implicit nesting types and create a concrete type. See internal/govendor/subst/subst.go for more details.
func NewResolver ¶
NewResolver creates a new Resolver that will substitute type parameters with the type arguments as defined in the provided Instance.
func (*Resolver) Nest ¶
Nest is the nesting function that this resolver will resolve types with. This will be null if the resolver is not for a nested context,
func (*Resolver) NestTypeArgs ¶
NestTypeArgs is the list of type arguments from the nesting function that this resolver will resolve to.
func (*Resolver) NestTypeParams ¶
func (r *Resolver) NestTypeParams() *types.TypeParamList
NestTypeParams is the list of type parameters from the nesting function that this resolver will substitute.
func (*Resolver) Substitute ¶
Substitute replaces references to type params in the provided type definition with the corresponding concrete types.
func (*Resolver) SubstituteAll ¶
SubstituteAll same as Substitute, but accepts a TypeList are returns substitution results as a slice in the same order.
func (*Resolver) SubstituteSelection ¶
SubstituteSelection replaces a method of field selection on a generic type defined in terms of type parameters with a method selection on a concrete instantiation of the type.
func (*Resolver) TypeArgs ¶
TypeArgs is the list of type arguments that this resolver will resolve to.
func (*Resolver) TypeParams ¶
func (r *Resolver) TypeParams() *types.TypeParamList
TypeParams is the list of type parameters that this resolver will substitute.