Source file
src/go/types/subst.go
1
2
3
4
5
6
7 package types
8
9 import "go/token"
10
11 type substMap map[*TypeParam]Type
12
13
14
15 func makeSubstMap(tpars []*TypeParam, targs []Type) substMap {
16 assert(len(tpars) == len(targs))
17 proj := make(substMap, len(tpars))
18 for i, tpar := range tpars {
19 proj[tpar] = targs[i]
20 }
21 return proj
22 }
23
24
25
26 func makeRenameMap(from, to []*TypeParam) substMap {
27 assert(len(from) == len(to))
28 proj := make(substMap, len(from))
29 for i, tpar := range from {
30 proj[tpar] = to[i]
31 }
32 return proj
33 }
34
35 func (m substMap) empty() bool {
36 return len(m) == 0
37 }
38
39 func (m substMap) lookup(tpar *TypeParam) Type {
40 if t := m[tpar]; t != nil {
41 return t
42 }
43 return tpar
44 }
45
46
47
48
49
50
51
52
53 func (check *Checker) subst(pos token.Pos, typ Type, smap substMap, expanding *Named, ctxt *Context) Type {
54 assert(expanding != nil || ctxt != nil)
55
56 if smap.empty() {
57 return typ
58 }
59
60
61 switch t := typ.(type) {
62 case *Basic:
63 return typ
64 case *TypeParam:
65 return smap.lookup(t)
66 }
67
68
69 subst := subster{
70 pos: pos,
71 smap: smap,
72 check: check,
73 expanding: expanding,
74 ctxt: ctxt,
75 }
76 return subst.typ(typ)
77 }
78
79 type subster struct {
80 pos token.Pos
81 smap substMap
82 check *Checker
83 expanding *Named
84 ctxt *Context
85 }
86
87 func (subst *subster) typ(typ Type) Type {
88 switch t := typ.(type) {
89 case nil:
90
91 panic("nil typ")
92
93 case *Basic:
94
95
96 case *Array:
97 elem := subst.typOrNil(t.elem)
98 if elem != t.elem {
99 return &Array{len: t.len, elem: elem}
100 }
101
102 case *Slice:
103 elem := subst.typOrNil(t.elem)
104 if elem != t.elem {
105 return &Slice{elem: elem}
106 }
107
108 case *Struct:
109 if fields, copied := subst.varList(t.fields); copied {
110 s := &Struct{fields: fields, tags: t.tags}
111 s.markComplete()
112 return s
113 }
114
115 case *Pointer:
116 base := subst.typ(t.base)
117 if base != t.base {
118 return &Pointer{base: base}
119 }
120
121 case *Tuple:
122 return subst.tuple(t)
123
124 case *Signature:
125
126
127
128
129
130
131
132
133
134
135
136
137
138 recv := t.recv
139
140 params := subst.tuple(t.params)
141 results := subst.tuple(t.results)
142 if params != t.params || results != t.results {
143 return &Signature{
144 rparams: t.rparams,
145
146 tparams: t.tparams,
147
148 recv: recv,
149 params: params,
150 results: results,
151 variadic: t.variadic,
152 }
153 }
154
155 case *Union:
156 terms, copied := subst.termlist(t.terms)
157 if copied {
158
159
160
161 return &Union{terms}
162 }
163
164 case *Interface:
165 methods, mcopied := subst.funcList(t.methods)
166 embeddeds, ecopied := subst.typeList(t.embeddeds)
167 if mcopied || ecopied {
168 iface := subst.check.newInterface()
169 iface.embeddeds = embeddeds
170 iface.implicit = t.implicit
171 iface.complete = t.complete
172
173
174
175
176
177
178
179
180
181
182
183
184
185 iface.methods, _ = replaceRecvType(methods, t, iface)
186 return iface
187 }
188
189 case *Map:
190 key := subst.typ(t.key)
191 elem := subst.typ(t.elem)
192 if key != t.key || elem != t.elem {
193 return &Map{key: key, elem: elem}
194 }
195
196 case *Chan:
197 elem := subst.typ(t.elem)
198 if elem != t.elem {
199 return &Chan{dir: t.dir, elem: elem}
200 }
201
202 case *Named:
203
204 dump := func(string, ...any) {}
205 if subst.check != nil && trace {
206 subst.check.indent++
207 defer func() {
208 subst.check.indent--
209 }()
210 dump = func(format string, args ...any) {
211 subst.check.trace(subst.pos, format, args...)
212 }
213 }
214
215
216
217
218
219
220 orig := t.Origin()
221 n := orig.TypeParams().Len()
222 if n == 0 {
223 dump(">>> %s is not parameterized", t)
224 return t
225 }
226
227 var newTArgs []Type
228 if t.TypeArgs().Len() != n {
229 return Typ[Invalid]
230 }
231
232
233 dump(">>> %s already instantiated", t)
234
235
236
237 for i, targ := range t.TypeArgs().list() {
238 dump(">>> %d targ = %s", i, targ)
239 new_targ := subst.typ(targ)
240 if new_targ != targ {
241 dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
242 if newTArgs == nil {
243 newTArgs = make([]Type, n)
244 copy(newTArgs, t.TypeArgs().list())
245 }
246 newTArgs[i] = new_targ
247 }
248 }
249
250 if newTArgs == nil {
251 dump(">>> nothing to substitute in %s", t)
252 return t
253 }
254
255
256
257
258
259 return subst.check.instance(subst.pos, orig, newTArgs, subst.expanding, subst.ctxt)
260
261 case *TypeParam:
262 return subst.smap.lookup(t)
263
264 default:
265 panic("unimplemented")
266 }
267
268 return typ
269 }
270
271
272
273
274 func (subst *subster) typOrNil(typ Type) Type {
275 if typ == nil {
276 return Typ[Invalid]
277 }
278 return subst.typ(typ)
279 }
280
281 func (subst *subster) var_(v *Var) *Var {
282 if v != nil {
283 if typ := subst.typ(v.typ); typ != v.typ {
284 return substVar(v, typ)
285 }
286 }
287 return v
288 }
289
290 func substVar(v *Var, typ Type) *Var {
291 copy := *v
292 copy.typ = typ
293 copy.origin = v.Origin()
294 return ©
295 }
296
297 func (subst *subster) tuple(t *Tuple) *Tuple {
298 if t != nil {
299 if vars, copied := subst.varList(t.vars); copied {
300 return &Tuple{vars: vars}
301 }
302 }
303 return t
304 }
305
306 func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
307 out = in
308 for i, v := range in {
309 if w := subst.var_(v); w != v {
310 if !copied {
311
312
313 new := make([]*Var, len(in))
314 copy(new, out)
315 out = new
316 copied = true
317 }
318 out[i] = w
319 }
320 }
321 return
322 }
323
324 func (subst *subster) func_(f *Func) *Func {
325 if f != nil {
326 if typ := subst.typ(f.typ); typ != f.typ {
327 return substFunc(f, typ)
328 }
329 }
330 return f
331 }
332
333 func substFunc(f *Func, typ Type) *Func {
334 copy := *f
335 copy.typ = typ
336 copy.origin = f.Origin()
337 return ©
338 }
339
340 func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
341 out = in
342 for i, f := range in {
343 if g := subst.func_(f); g != f {
344 if !copied {
345
346
347 new := make([]*Func, len(in))
348 copy(new, out)
349 out = new
350 copied = true
351 }
352 out[i] = g
353 }
354 }
355 return
356 }
357
358 func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
359 out = in
360 for i, t := range in {
361 if u := subst.typ(t); u != t {
362 if !copied {
363
364
365 new := make([]Type, len(in))
366 copy(new, out)
367 out = new
368 copied = true
369 }
370 out[i] = u
371 }
372 }
373 return
374 }
375
376 func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
377 out = in
378 for i, t := range in {
379 if u := subst.typ(t.typ); u != t.typ {
380 if !copied {
381
382
383 new := make([]*Term, len(in))
384 copy(new, out)
385 out = new
386 copied = true
387 }
388 out[i] = NewTerm(t.tilde, u)
389 }
390 }
391 return
392 }
393
394
395
396
397
398
399
400 func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
401 out = in
402 for i, method := range in {
403 sig := method.Type().(*Signature)
404 if sig.recv != nil && sig.recv.Type() == old {
405 if !copied {
406
407
408
409 out = make([]*Func, len(in))
410 copy(out, in)
411 copied = true
412 }
413 newsig := *sig
414 newsig.recv = substVar(sig.recv, new)
415 out[i] = substFunc(method, &newsig)
416 }
417 }
418 return
419 }
420
View as plain text