summaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/tools/go/ssa/instantiate.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/tools/go/ssa/instantiate.go')
-rw-r--r--vendor/golang.org/x/tools/go/ssa/instantiate.go131
1 files changed, 131 insertions, 0 deletions
diff --git a/vendor/golang.org/x/tools/go/ssa/instantiate.go b/vendor/golang.org/x/tools/go/ssa/instantiate.go
new file mode 100644
index 0000000..2512f32
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/ssa/instantiate.go
@@ -0,0 +1,131 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+ "fmt"
+ "go/types"
+ "sync"
+)
+
+// A generic records information about a generic origin function,
+// including a cache of existing instantiations.
+type generic struct {
+ instancesMu sync.Mutex
+ instances map[*typeList]*Function // canonical type arguments to an instance.
+}
+
+// instance returns a Function that is the instantiation of generic
+// origin function fn with the type arguments targs.
+//
+// Any created instance is added to cr.
+//
+// Acquires fn.generic.instancesMu.
+func (fn *Function) instance(targs []types.Type, b *builder) *Function {
+ key := fn.Prog.canon.List(targs)
+
+ gen := fn.generic
+
+ gen.instancesMu.Lock()
+ defer gen.instancesMu.Unlock()
+ inst, ok := gen.instances[key]
+ if !ok {
+ inst = createInstance(fn, targs)
+ inst.buildshared = b.shared()
+ b.enqueue(inst)
+
+ if gen.instances == nil {
+ gen.instances = make(map[*typeList]*Function)
+ }
+ gen.instances[key] = inst
+ } else {
+ b.waitForSharedFunction(inst)
+ }
+ return inst
+}
+
+// createInstance returns the instantiation of generic function fn using targs.
+//
+// Requires fn.generic.instancesMu.
+func createInstance(fn *Function, targs []types.Type) *Function {
+ prog := fn.Prog
+
+ // Compute signature.
+ var sig *types.Signature
+ var obj *types.Func
+ if recv := fn.Signature.Recv(); recv != nil {
+ // method
+ obj = prog.canon.instantiateMethod(fn.object, targs, prog.ctxt)
+ sig = obj.Type().(*types.Signature)
+ } else {
+ // function
+ instSig, err := types.Instantiate(prog.ctxt, fn.Signature, targs, false)
+ if err != nil {
+ panic(err)
+ }
+ instance, ok := instSig.(*types.Signature)
+ if !ok {
+ panic("Instantiate of a Signature returned a non-signature")
+ }
+ obj = fn.object // instantiation does not exist yet
+ sig = prog.canon.Type(instance).(*types.Signature)
+ }
+
+ // Choose strategy (instance or wrapper).
+ var (
+ synthetic string
+ subst *subster
+ build buildFunc
+ )
+ if prog.mode&InstantiateGenerics != 0 && !prog.isParameterized(targs...) {
+ synthetic = fmt.Sprintf("instance of %s", fn.Name())
+ if fn.syntax != nil {
+ subst = makeSubster(prog.ctxt, obj, fn.typeparams, targs, false)
+ build = (*builder).buildFromSyntax
+ } else {
+ build = (*builder).buildParamsOnly
+ }
+ } else {
+ synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name())
+ build = (*builder).buildInstantiationWrapper
+ }
+
+ /* generic instance or instantiation wrapper */
+ return &Function{
+ name: fmt.Sprintf("%s%s", fn.Name(), targs), // may not be unique
+ object: obj,
+ Signature: sig,
+ Synthetic: synthetic,
+ syntax: fn.syntax, // \
+ info: fn.info, // } empty for non-created packages
+ goversion: fn.goversion, // /
+ build: build,
+ topLevelOrigin: fn,
+ pos: obj.Pos(),
+ Pkg: nil,
+ Prog: fn.Prog,
+ typeparams: fn.typeparams, // share with origin
+ typeargs: targs,
+ subst: subst,
+ }
+}
+
+// isParameterized reports whether any of the specified types contains
+// a free type parameter. It is safe to call concurrently.
+func (prog *Program) isParameterized(ts ...types.Type) bool {
+ prog.hasParamsMu.Lock()
+ defer prog.hasParamsMu.Unlock()
+
+ // TODO(adonovan): profile. If this operation is expensive,
+ // handle the most common but shallow cases such as T, pkg.T,
+ // *T without consulting the cache under the lock.
+
+ for _, t := range ts {
+ if prog.hasParams.Has(t) {
+ return true
+ }
+ }
+ return false
+}