1
2
3
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
16
17
18
19
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
31 type instanceSet struct {
32 fn *Function
33 instances map[*typeList]*Function
34 syntax *ast.FuncDecl
35 info *types.Info
36
37
38
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
54
55
56
57
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
77
78
79
80
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
89
90
91
92
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
98
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
108
109
110
111
112
113 key := prog.canon.List(targs)
114 if inst, ok := insts.instances[key]; ok {
115 return inst
116 }
117
118
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
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)
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 subst = makeSubster(prog.ctxt, fn.typeparams, targs, false)
152 } else {
153 synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name())
154 }
155
156 name := fmt.Sprintf("%s%s", fn.Name(), targs)
157 instance := &Function{
158 name: name,
159 object: obj,
160 Signature: sig,
161 Synthetic: synthetic,
162 syntax: syntax,
163 topLevelOrigin: fn,
164 pos: obj.Pos(),
165 Pkg: nil,
166 Prog: fn.Prog,
167 typeparams: fn.typeparams,
168 typeargs: targs,
169 info: insts.info,
170 subst: subst,
171 }
172
173 cr.Add(instance)
174 insts.instances[key] = instance
175 return instance
176 }
177
View as plain text