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 | 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) // may not be unique |
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, // share with origin |
168 | typeargs: targs, |
169 | info: insts.info, // on synthetic packages info is nil. |
170 | subst: subst, |
171 | } |
172 | |
173 | cr.Add(instance) |
174 | insts.instances[key] = instance |
175 | return instance |
176 | } |
177 |
Members