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