github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/ssa/instantiate.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/types" 11 12 "golang.org/x/tools/internal/typeparams" 13 ) 14 15 // _Instances returns all of the instances generated by runtime types for this function in an unspecified order. 16 // 17 // Thread-safe. 18 // 19 // This is an experimental interface! It may change without warning. 20 func (prog *Program) _Instances(fn *Function) []*Function { 21 if fn.typeparams.Len() == 0 || len(fn.typeargs) > 0 { 22 return nil 23 } 24 25 prog.methodsMu.Lock() 26 defer prog.methodsMu.Unlock() 27 return prog.instances[fn].list() 28 } 29 30 // A set of instantiations of a generic function fn. 31 type instanceSet struct { 32 fn *Function // fn.typeparams.Len() > 0 and len(fn.typeargs) == 0. 33 instances map[*typeList]*Function // canonical type arguments to an instance. 34 syntax *ast.FuncDecl // fn.syntax copy for instantiating after fn is done. nil on synthetic packages. 35 info *types.Info // fn.pkg.info copy for building after fn is done.. nil on synthetic packages. 36 37 // TODO(taking): Consider ways to allow for clearing syntax and info when done building. 38 // May require a public API change as MethodValue can request these be built after prog.Build() is done. 39 } 40 41 func (insts *instanceSet) list() []*Function { 42 if insts == nil { 43 return nil 44 } 45 46 fns := make([]*Function, 0, len(insts.instances)) 47 for _, fn := range insts.instances { 48 fns = append(fns, fn) 49 } 50 return fns 51 } 52 53 // createInstanceSet adds a new instanceSet for a generic function fn if one does not exist. 54 // 55 // Precondition: fn is a package level declaration (function or method). 56 // 57 // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu) 58 func (prog *Program) createInstanceSet(fn *Function) { 59 assert(fn.typeparams.Len() > 0 && len(fn.typeargs) == 0, "Can only create instance sets for generic functions") 60 61 prog.methodsMu.Lock() 62 defer prog.methodsMu.Unlock() 63 64 syntax, _ := fn.syntax.(*ast.FuncDecl) 65 assert((syntax == nil) == (fn.syntax == nil), "fn.syntax is either nil or a *ast.FuncDecl") 66 67 if _, ok := prog.instances[fn]; !ok { 68 prog.instances[fn] = &instanceSet{ 69 fn: fn, 70 syntax: syntax, 71 info: fn.info, 72 } 73 } 74 } 75 76 // needsInstance returns a Function that is the instantiation of fn with the type arguments targs. 77 // 78 // Any CREATEd instance is added to cr. 79 // 80 // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu) 81 func (prog *Program) needsInstance(fn *Function, targs []types.Type, cr *creator) *Function { 82 prog.methodsMu.Lock() 83 defer prog.methodsMu.Unlock() 84 85 return prog.lookupOrCreateInstance(fn, targs, cr) 86 } 87 88 // lookupOrCreateInstance returns a Function that is the instantiation of fn with the type arguments targs. 89 // 90 // Any CREATEd instance is added to cr. 91 // 92 // EXCLUSIVE_LOCKS_REQUIRED(prog.methodMu) 93 func (prog *Program) lookupOrCreateInstance(fn *Function, targs []types.Type, cr *creator) *Function { 94 return prog.instances[fn].lookupOrCreate(targs, &prog.parameterized, cr) 95 } 96 97 // lookupOrCreate returns the instantiation of insts.fn using targs. 98 // If the instantiation is created, this is added to cr. 99 func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWalker, cr *creator) *Function { 100 if insts.instances == nil { 101 insts.instances = make(map[*typeList]*Function) 102 } 103 104 fn := insts.fn 105 prog := fn.Prog 106 107 // canonicalize on a tuple of targs. Sig is not unique. 108 // 109 // func A[T any]() { 110 // var x T 111 // fmt.Println("%T", x) 112 // } 113 key := prog.canon.List(targs) 114 if inst, ok := insts.instances[key]; ok { 115 return inst 116 } 117 118 // CREATE instance/instantiation wrapper 119 var syntax ast.Node 120 if insts.syntax != nil { 121 syntax = insts.syntax 122 } 123 124 var sig *types.Signature 125 var obj *types.Func 126 if recv := fn.Signature.Recv(); recv != nil { 127 // method 128 m := fn.object.(*types.Func) 129 obj = prog.canon.instantiateMethod(m, targs, prog.ctxt) 130 sig = obj.Type().(*types.Signature) 131 } else { 132 instSig, err := typeparams.Instantiate(prog.ctxt, fn.Signature, targs, false) 133 if err != nil { 134 panic(err) 135 } 136 instance, ok := instSig.(*types.Signature) 137 if !ok { 138 panic("Instantiate of a Signature returned a non-signature") 139 } 140 obj = fn.object.(*types.Func) // instantiation does not exist yet 141 sig = prog.canon.Type(instance).(*types.Signature) 142 } 143 144 var synthetic string 145 var subst *subster 146 147 concrete := !parameterized.anyParameterized(targs) 148 149 if prog.mode&InstantiateGenerics != 0 && concrete { 150 synthetic = fmt.Sprintf("instance of %s", fn.Name()) 151 scope := typeparams.OriginMethod(obj).Scope() 152 subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false) 153 } else { 154 synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name()) 155 } 156 157 name := fmt.Sprintf("%s%s", fn.Name(), targs) // may not be unique 158 instance := &Function{ 159 name: name, 160 object: obj, 161 Signature: sig, 162 Synthetic: synthetic, 163 syntax: syntax, 164 topLevelOrigin: fn, 165 pos: obj.Pos(), 166 Pkg: nil, 167 Prog: fn.Prog, 168 typeparams: fn.typeparams, // share with origin 169 typeargs: targs, 170 info: insts.info, // on synthetic packages info is nil. 171 subst: subst, 172 } 173 174 cr.Add(instance) 175 insts.instances[key] = instance 176 return instance 177 }