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 params := subst.tuple(t.params)
168 results := subst.tuple(t.results)
169 if params != t.params || results != t.results {
170 return &Signature{
171 rparams: t.rparams,
172
173 tparams: t.tparams,
174
175 recv: recv,
176 params: params,
177 results: results,
178 variadic: t.variadic,
179 }
180 }
181
182 case *Union:
183 if terms := substList(t.terms, subst.term); terms != nil {
184
185
186
187 return &Union{terms}
188 }
189
190 case *Interface:
191 methods := substList(t.methods, subst.func_)
192 embeddeds := substList(t.embeddeds, subst.typ)
193 if methods != nil || embeddeds != nil {
194 if methods == nil {
195 methods = t.methods
196 }
197 if embeddeds == nil {
198 embeddeds = t.embeddeds
199 }
200 iface := subst.check.newInterface()
201 iface.embeddeds = embeddeds
202 iface.embedPos = t.embedPos
203 iface.implicit = t.implicit
204 assert(t.complete)
205 iface.complete = t.complete
206
207
208
209
210
211
212
213
214
215
216
217
218
219 iface.methods, _ = replaceRecvType(methods, t, iface)
220
221
222 if subst.check == nil {
223 iface.typeSet()
224 }
225 return iface
226 }
227
228 case *Map:
229 key := subst.typ(t.key)
230 elem := subst.typ(t.elem)
231 if key != t.key || elem != t.elem {
232 return &Map{key: key, elem: elem}
233 }
234
235 case *Chan:
236 elem := subst.typ(t.elem)
237 if elem != t.elem {
238 return &Chan{dir: t.dir, elem: elem}
239 }
240
241 case *Named:
242
243
244
245
246
247 orig := t.Origin()
248 n := orig.TypeParams().Len()
249 if n == 0 {
250 return t
251 }
252
253 if t.TypeArgs().Len() != n {
254 return Typ[Invalid]
255 }
256
257
258
259
260
261 if targs := substList(t.TypeArgs().list(), subst.typ); targs != nil {
262
263
264
265
266 return subst.check.instance(subst.pos, orig, targs, subst.expanding, subst.ctxt)
267 }
268
269 case *TypeParam:
270 return subst.smap.lookup(t)
271
272 default:
273 panic("unreachable")
274 }
275
276 return typ
277 }
278
279
280
281
282 func (subst *subster) typOrNil(typ Type) Type {
283 if typ == nil {
284 return Typ[Invalid]
285 }
286 return subst.typ(typ)
287 }
288
289 func (subst *subster) var_(v *Var) *Var {
290 if v != nil {
291 if typ := subst.typ(v.typ); typ != v.typ {
292 return cloneVar(v, typ)
293 }
294 }
295 return v
296 }
297
298 func cloneVar(v *Var, typ Type) *Var {
299 copy := *v
300 copy.typ = typ
301 copy.origin = v.Origin()
302 return ©
303 }
304
305 func (subst *subster) tuple(t *Tuple) *Tuple {
306 if t != nil {
307 if vars := substList(t.vars, subst.var_); vars != nil {
308 return &Tuple{vars: vars}
309 }
310 }
311 return t
312 }
313
314
315
316
317
318 func substList[T comparable](in []T, subst func(T) T) (out []T) {
319 for i, t := range in {
320 if u := subst(t); u != t {
321 if out == nil {
322
323 out = make([]T, len(in))
324 copy(out, in)
325 }
326 out[i] = u
327 }
328 }
329 return
330 }
331
332 func (subst *subster) func_(f *Func) *Func {
333 if f != nil {
334 if typ := subst.typ(f.typ); typ != f.typ {
335 return cloneFunc(f, typ)
336 }
337 }
338 return f
339 }
340
341 func cloneFunc(f *Func, typ Type) *Func {
342 copy := *f
343 copy.typ = typ
344 copy.origin = f.Origin()
345 return ©
346 }
347
348 func (subst *subster) term(t *Term) *Term {
349 if typ := subst.typ(t.typ); typ != t.typ {
350 return NewTerm(t.tilde, typ)
351 }
352 return t
353 }
354
355
356
357
358
359
360
361 func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
362 out = in
363 for i, method := range in {
364 sig := method.Signature()
365 if sig.recv != nil && sig.recv.Type() == old {
366 if !copied {
367
368
369
370 out = make([]*Func, len(in))
371 copy(out, in)
372 copied = true
373 }
374 newsig := *sig
375 newsig.recv = cloneVar(sig.recv, new)
376 out[i] = cloneFunc(method, &newsig)
377 }
378 }
379 return
380 }
381
View as plain text