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 rhs := subst.typ(t.fromRHS)
103 if rhs != t.fromRHS {
104
105
106
107
108
109 panic("unreachable for unparameterized aliases")
110
111 }
112
113 case *Array:
114 elem := subst.typOrNil(t.elem)
115 if elem != t.elem {
116 return &Array{len: t.len, elem: elem}
117 }
118
119 case *Slice:
120 elem := subst.typOrNil(t.elem)
121 if elem != t.elem {
122 return &Slice{elem: elem}
123 }
124
125 case *Struct:
126 if fields, copied := subst.varList(t.fields); copied {
127 s := &Struct{fields: fields, tags: t.tags}
128 s.markComplete()
129 return s
130 }
131
132 case *Pointer:
133 base := subst.typ(t.base)
134 if base != t.base {
135 return &Pointer{base: base}
136 }
137
138 case *Tuple:
139 return subst.tuple(t)
140
141 case *Signature:
142
143
144
145
146
147
148
149
150
151
152
153
154
155 recv := t.recv
156
157 params := subst.tuple(t.params)
158 results := subst.tuple(t.results)
159 if params != t.params || results != t.results {
160 return &Signature{
161 rparams: t.rparams,
162
163 tparams: t.tparams,
164
165 recv: recv,
166 params: params,
167 results: results,
168 variadic: t.variadic,
169 }
170 }
171
172 case *Union:
173 terms, copied := subst.termlist(t.terms)
174 if copied {
175
176
177
178 return &Union{terms}
179 }
180
181 case *Interface:
182 methods, mcopied := subst.funcList(t.methods)
183 embeddeds, ecopied := subst.typeList(t.embeddeds)
184 if mcopied || ecopied {
185 iface := subst.check.newInterface()
186 iface.embeddeds = embeddeds
187 iface.embedPos = t.embedPos
188 iface.implicit = t.implicit
189 assert(t.complete)
190 iface.complete = t.complete
191
192
193
194
195
196
197
198
199
200
201
202
203
204 iface.methods, _ = replaceRecvType(methods, t, iface)
205
206
207 if subst.check == nil {
208 iface.typeSet()
209 }
210 return iface
211 }
212
213 case *Map:
214 key := subst.typ(t.key)
215 elem := subst.typ(t.elem)
216 if key != t.key || elem != t.elem {
217 return &Map{key: key, elem: elem}
218 }
219
220 case *Chan:
221 elem := subst.typ(t.elem)
222 if elem != t.elem {
223 return &Chan{dir: t.dir, elem: elem}
224 }
225
226 case *Named:
227
228 dump := func(string, ...interface{}) {}
229 if subst.check != nil && subst.check.conf._Trace {
230 subst.check.indent++
231 defer func() {
232 subst.check.indent--
233 }()
234 dump = func(format string, args ...interface{}) {
235 subst.check.trace(subst.pos, format, args...)
236 }
237 }
238
239
240
241
242
243
244 orig := t.Origin()
245 n := orig.TypeParams().Len()
246 if n == 0 {
247 dump(">>> %s is not parameterized", t)
248 return t
249 }
250
251 var newTArgs []Type
252 if t.TypeArgs().Len() != n {
253 return Typ[Invalid]
254 }
255
256
257 dump(">>> %s already instantiated", t)
258
259
260
261 for i, targ := range t.TypeArgs().list() {
262 dump(">>> %d targ = %s", i, targ)
263 new_targ := subst.typ(targ)
264 if new_targ != targ {
265 dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
266 if newTArgs == nil {
267 newTArgs = make([]Type, n)
268 copy(newTArgs, t.TypeArgs().list())
269 }
270 newTArgs[i] = new_targ
271 }
272 }
273
274 if newTArgs == nil {
275 dump(">>> nothing to substitute in %s", t)
276 return t
277 }
278
279
280
281
282
283 return subst.check.instance(subst.pos, orig, newTArgs, subst.expanding, subst.ctxt)
284
285 case *TypeParam:
286 return subst.smap.lookup(t)
287
288 default:
289 panic("unreachable")
290 }
291
292 return typ
293 }
294
295
296
297
298 func (subst *subster) typOrNil(typ Type) Type {
299 if typ == nil {
300 return Typ[Invalid]
301 }
302 return subst.typ(typ)
303 }
304
305 func (subst *subster) var_(v *Var) *Var {
306 if v != nil {
307 if typ := subst.typ(v.typ); typ != v.typ {
308 return substVar(v, typ)
309 }
310 }
311 return v
312 }
313
314 func substVar(v *Var, typ Type) *Var {
315 copy := *v
316 copy.typ = typ
317 copy.origin = v.Origin()
318 return ©
319 }
320
321 func (subst *subster) tuple(t *Tuple) *Tuple {
322 if t != nil {
323 if vars, copied := subst.varList(t.vars); copied {
324 return &Tuple{vars: vars}
325 }
326 }
327 return t
328 }
329
330 func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
331 out = in
332 for i, v := range in {
333 if w := subst.var_(v); w != v {
334 if !copied {
335
336
337 new := make([]*Var, len(in))
338 copy(new, out)
339 out = new
340 copied = true
341 }
342 out[i] = w
343 }
344 }
345 return
346 }
347
348 func (subst *subster) func_(f *Func) *Func {
349 if f != nil {
350 if typ := subst.typ(f.typ); typ != f.typ {
351 return substFunc(f, typ)
352 }
353 }
354 return f
355 }
356
357 func substFunc(f *Func, typ Type) *Func {
358 copy := *f
359 copy.typ = typ
360 copy.origin = f.Origin()
361 return ©
362 }
363
364 func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
365 out = in
366 for i, f := range in {
367 if g := subst.func_(f); g != f {
368 if !copied {
369
370
371 new := make([]*Func, len(in))
372 copy(new, out)
373 out = new
374 copied = true
375 }
376 out[i] = g
377 }
378 }
379 return
380 }
381
382 func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
383 out = in
384 for i, t := range in {
385 if u := subst.typ(t); u != t {
386 if !copied {
387
388
389 new := make([]Type, len(in))
390 copy(new, out)
391 out = new
392 copied = true
393 }
394 out[i] = u
395 }
396 }
397 return
398 }
399
400 func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
401 out = in
402 for i, t := range in {
403 if u := subst.typ(t.typ); u != t.typ {
404 if !copied {
405
406
407 new := make([]*Term, len(in))
408 copy(new, out)
409 out = new
410 copied = true
411 }
412 out[i] = NewTerm(t.tilde, u)
413 }
414 }
415 return
416 }
417
418
419
420
421
422
423
424 func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
425 out = in
426 for i, method := range in {
427 sig := method.Signature()
428 if sig.recv != nil && sig.recv.Type() == old {
429 if !copied {
430
431
432
433 out = make([]*Func, len(in))
434 copy(out, in)
435 copied = true
436 }
437 newsig := *sig
438 newsig.recv = substVar(sig.recv, new)
439 out[i] = substFunc(method, &newsig)
440 }
441 }
442 return
443 }
444
View as plain text