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