github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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 "github.com/powerman/golang-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 len(fn._TypeParams) == 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 // len(fn._TypeParams) > 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 // 59 func (prog *Program) createInstanceSet(fn *Function) { 60 assert(len(fn._TypeParams) > 0 && len(fn._TypeArgs) == 0, "Can only create instance sets for generic functions") 61 62 prog.methodsMu.Lock() 63 defer prog.methodsMu.Unlock() 64 65 syntax, _ := fn.syntax.(*ast.FuncDecl) 66 assert((syntax == nil) == (fn.syntax == nil), "fn.syntax is either nil or a *ast.FuncDecl") 67 68 if _, ok := prog.instances[fn]; !ok { 69 prog.instances[fn] = &instanceSet{ 70 fn: fn, 71 syntax: syntax, 72 info: fn.info, 73 } 74 } 75 } 76 77 // needsInstance returns an Function that that is the instantiation of fn with the type arguments targs. 78 // 79 // Any CREATEd instance is added to cr. 80 // 81 // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu) 82 func (prog *Program) needsInstance(fn *Function, targs []types.Type, cr *creator) *Function { 83 prog.methodsMu.Lock() 84 defer prog.methodsMu.Unlock() 85 86 return prog.instances[fn].lookupOrCreate(targs, cr) 87 } 88 89 // lookupOrCreate returns the instantiation of insts.fn using targs. 90 // If the instantiation is reported, this is added to cr. 91 // 92 func (insts *instanceSet) lookupOrCreate(targs []types.Type, cr *creator) *Function { 93 if insts.instances == nil { 94 insts.instances = make(map[*typeList]*Function) 95 } 96 97 // canonicalize on a tuple of targs. Sig is not unique. 98 // 99 // func A[T any]() { 100 // var x T 101 // fmt.Println("%T", x) 102 // } 103 key := insts.fn.Prog.canon.List(targs) 104 if inst, ok := insts.instances[key]; ok { 105 return inst 106 } 107 instance := createInstance(insts.fn, targs, insts.info, insts.syntax, cr) 108 109 // TODO(taking): Allow for the function to be built after monomorphization is supported. 110 instance.syntax = nil // treat instance as an external function to prevent building. 111 112 insts.instances[key] = instance 113 return instance 114 } 115 116 // createInstance returns an CREATEd instantiation of fn using targs. 117 // 118 // Function is added to cr. 119 // 120 func createInstance(fn *Function, targs []types.Type, info *types.Info, syntax ast.Node, cr *creator) *Function { 121 prog := fn.Prog 122 var sig *types.Signature 123 var obj *types.Func 124 if recv := fn.Signature.Recv(); recv != nil { 125 // method 126 // instantiates m with targs and returns a canonical representative for this method. 127 m := fn.object.(*types.Func) 128 recv := recvType(m) 129 if p, ok := recv.(*types.Pointer); ok { 130 recv = p.Elem() 131 } 132 named := recv.(*types.Named) 133 inst, err := typeparams.Instantiate(prog.ctxt, typeparams.NamedTypeOrigin(named), targs, false) 134 if err != nil { 135 panic(err) 136 } 137 canon, _, _ := types.LookupFieldOrMethod(prog.canon.Type(inst), true, m.Pkg(), m.Name()) 138 obj = canon.(*types.Func) 139 sig = obj.Type().(*types.Signature) 140 } else { 141 instSig, err := typeparams.Instantiate(prog.ctxt, fn.Signature, targs, false) 142 if err != nil { 143 panic(err) 144 } 145 instance, ok := instSig.(*types.Signature) 146 if !ok { 147 panic("Instantiate of a Signature returned a non-signature") 148 } 149 obj = fn.object.(*types.Func) // instantiation does not exist yet 150 sig = prog.canon.Type(instance).(*types.Signature) 151 } 152 153 name := fmt.Sprintf("%s[%s]", fn.Name(), targs) // may not be unique 154 synthetic := fmt.Sprintf("instantiation of %s", fn.Name()) 155 instance := &Function{ 156 name: name, 157 object: obj, 158 Signature: sig, 159 Synthetic: synthetic, 160 syntax: syntax, // on synthetic packages syntax is nil. 161 _Origin: fn, 162 pos: obj.Pos(), 163 Pkg: nil, 164 Prog: fn.Prog, 165 _TypeParams: fn._TypeParams, 166 _TypeArgs: targs, 167 info: info, // on synthetic packages info is nil. 168 subst: makeSubster(prog.ctxt, fn._TypeParams, targs, false), 169 } 170 cr.Add(instance) 171 return instance 172 }