Source file
src/go/types/subst.go
1
2
3
4
5
6
7
8
9 package types
10
11 import (
12 "bytes"
13 "fmt"
14 "go/token"
15 )
16
17
18
19
20 type substMap struct {
21
22
23
24 targs []Type
25 proj map[*_TypeParam]Type
26 }
27
28
29
30 func makeSubstMap(tpars []*TypeName, targs []Type) *substMap {
31 assert(len(tpars) == len(targs))
32 proj := make(map[*_TypeParam]Type, len(tpars))
33 for i, tpar := range tpars {
34
35
36
37 targ := expand(targs[i])
38 targs[i] = targ
39 proj[tpar.typ.(*_TypeParam)] = targ
40 }
41 return &substMap{targs, proj}
42 }
43
44 func (m *substMap) String() string {
45 return fmt.Sprintf("%s", m.proj)
46 }
47
48 func (m *substMap) empty() bool {
49 return len(m.proj) == 0
50 }
51
52 func (m *substMap) lookup(tpar *_TypeParam) Type {
53 if t := m.proj[tpar]; t != nil {
54 return t
55 }
56 return tpar
57 }
58
59 func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist []token.Pos) (res Type) {
60 if trace {
61 check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs))
62 check.indent++
63 defer func() {
64 check.indent--
65 var under Type
66 if res != nil {
67
68
69
70 under = res.Underlying()
71 }
72 check.trace(pos, "=> %s (under = %s)", res, under)
73 }()
74 }
75
76 assert(len(poslist) <= len(targs))
77
78
79 var tparams []*TypeName
80 switch t := typ.(type) {
81 case *Named:
82 tparams = t.tparams
83 case *Signature:
84 tparams = t.tparams
85 defer func() {
86
87
88
89 if _, ok := res.(*Signature); !ok {
90 return
91 }
92
93
94
95 if t == res {
96 copy := *t
97 res = ©
98 }
99
100
101 res.(*Signature).tparams = nil
102 }()
103
104 default:
105 check.dump("%v: cannot instantiate %v", pos, typ)
106 unreachable()
107 }
108
109
110 if len(targs) != len(tparams) {
111
112 check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", len(targs), len(tparams))
113 return Typ[Invalid]
114 }
115
116 if len(tparams) == 0 {
117 return typ
118 }
119
120 smap := makeSubstMap(tparams, targs)
121
122
123 for i, tname := range tparams {
124 tpar := tname.typ.(*_TypeParam)
125 iface := tpar.Bound()
126 if iface.Empty() {
127 continue
128 }
129
130 targ := targs[i]
131
132
133 pos := pos
134 if i < len(poslist) {
135 pos = poslist[i]
136 }
137
138
139
140
141
142 iface = check.subst(pos, iface, smap).(*Interface)
143
144
145
146 check.completeInterface(token.NoPos, iface)
147 if len(iface.allMethods) > 0 {
148
149
150
151 if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
152 check.errorf(atPos(pos), 0, "%s has no methods", targ)
153 break
154 }
155 if m, wrong := check.missingMethod(targ, iface, true); m != nil {
156
157
158
159
160 if m.name == "==" {
161
162 check.softErrorf(atPos(pos), 0, "%s does not satisfy comparable", targ)
163 } else if wrong != nil {
164
165
166
167 check.softErrorf(atPos(pos), _Todo,
168 "%s does not satisfy %s: wrong method signature\n\tgot %s\n\twant %s",
169 targ, tpar.bound, wrong, m,
170 )
171 } else {
172 check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m.name)
173 }
174 break
175 }
176 }
177
178
179 if iface.allTypes == nil {
180 continue
181 }
182
183
184
185 if targ := asTypeParam(targ); targ != nil {
186 targBound := targ.Bound()
187 if targBound.allTypes == nil {
188 check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
189 break
190 }
191 for _, t := range unpackType(targBound.allTypes) {
192 if !iface.isSatisfiedBy(t) {
193
194 check.softErrorf(atPos(pos), 0, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
195 break
196 }
197 }
198 break
199 }
200
201
202 if !iface.isSatisfiedBy(targ) {
203 check.softErrorf(atPos(pos), _Todo, "%s does not satisfy %s (%s or %s not found in %s)", targ, tpar.bound, targ, under(targ), iface.allTypes)
204 break
205 }
206 }
207
208 return check.subst(pos, typ, smap)
209 }
210
211
212
213
214
215
216 func (check *Checker) subst(pos token.Pos, typ Type, smap *substMap) Type {
217 if smap.empty() {
218 return typ
219 }
220
221
222 switch t := typ.(type) {
223 case *Basic:
224 return typ
225 case *_TypeParam:
226 return smap.lookup(t)
227 }
228
229
230 subst := subster{check, pos, make(map[Type]Type), smap}
231 return subst.typ(typ)
232 }
233
234 type subster struct {
235 check *Checker
236 pos token.Pos
237 cache map[Type]Type
238 smap *substMap
239 }
240
241 func (subst *subster) typ(typ Type) Type {
242 switch t := typ.(type) {
243 case nil:
244
245 panic("nil typ")
246
247 case *Basic, *bottom, *top:
248
249
250 case *Array:
251 elem := subst.typOrNil(t.elem)
252 if elem != t.elem {
253 return &Array{len: t.len, elem: elem}
254 }
255
256 case *Slice:
257 elem := subst.typOrNil(t.elem)
258 if elem != t.elem {
259 return &Slice{elem: elem}
260 }
261
262 case *Struct:
263 if fields, copied := subst.varList(t.fields); copied {
264 return &Struct{fields: fields, tags: t.tags}
265 }
266
267 case *Pointer:
268 base := subst.typ(t.base)
269 if base != t.base {
270 return &Pointer{base: base}
271 }
272
273 case *Tuple:
274 return subst.tuple(t)
275
276 case *Signature:
277
278
279 recv := t.recv
280 params := subst.tuple(t.params)
281 results := subst.tuple(t.results)
282 if recv != t.recv || params != t.params || results != t.results {
283 return &Signature{
284 rparams: t.rparams,
285
286
287 tparams: t.tparams,
288 scope: t.scope,
289 recv: recv,
290 params: params,
291 results: results,
292 variadic: t.variadic,
293 }
294 }
295
296 case *_Sum:
297 types, copied := subst.typeList(t.types)
298 if copied {
299
300
301
302 return _NewSum(types)
303 }
304
305 case *Interface:
306 methods, mcopied := subst.funcList(t.methods)
307 types := t.types
308 if t.types != nil {
309 types = subst.typ(t.types)
310 }
311 embeddeds, ecopied := subst.typeList(t.embeddeds)
312 if mcopied || types != t.types || ecopied {
313 iface := &Interface{methods: methods, types: types, embeddeds: embeddeds}
314 subst.check.posMap[iface] = subst.check.posMap[t]
315 subst.check.completeInterface(token.NoPos, iface)
316 return iface
317 }
318
319 case *Map:
320 key := subst.typ(t.key)
321 elem := subst.typ(t.elem)
322 if key != t.key || elem != t.elem {
323 return &Map{key: key, elem: elem}
324 }
325
326 case *Chan:
327 elem := subst.typ(t.elem)
328 if elem != t.elem {
329 return &Chan{dir: t.dir, elem: elem}
330 }
331
332 case *Named:
333 subst.check.indent++
334 defer func() {
335 subst.check.indent--
336 }()
337 dump := func(format string, args ...interface{}) {
338 if trace {
339 subst.check.trace(subst.pos, format, args...)
340 }
341 }
342
343 if t.tparams == nil {
344 dump(">>> %s is not parameterized", t)
345 return t
346 }
347
348 var newTargs []Type
349
350 if len(t.targs) > 0 {
351
352 dump(">>> %s already instantiated", t)
353 assert(len(t.targs) == len(t.tparams))
354
355
356
357 for i, targ := range t.targs {
358 dump(">>> %d targ = %s", i, targ)
359 newTarg := subst.typ(targ)
360 if newTarg != targ {
361 dump(">>> substituted %d targ %s => %s", i, targ, newTarg)
362 if newTargs == nil {
363 newTargs = make([]Type, len(t.tparams))
364 copy(newTargs, t.targs)
365 }
366 newTargs[i] = newTarg
367 }
368 }
369
370 if newTargs == nil {
371 dump(">>> nothing to substitute in %s", t)
372 return t
373 }
374 } else {
375
376 dump(">>> first instantiation of %s", t)
377
378 newTargs = subst.smap.targs
379 }
380
381
382 h := instantiatedHash(t, newTargs)
383 dump(">>> new type hash: %s", h)
384 if named, found := subst.check.typMap[h]; found {
385 dump(">>> found %s", named)
386 subst.cache[t] = named
387 return named
388 }
389
390
391 tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
392 named := subst.check.newNamed(tname, t.underlying, t.methods)
393 named.tparams = t.tparams
394 named.targs = newTargs
395 subst.check.typMap[h] = named
396 subst.cache[t] = named
397
398
399 dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTargs)
400 named.underlying = subst.typOrNil(t.underlying)
401 named.orig = named.underlying
402
403 return named
404
405 case *_TypeParam:
406 return subst.smap.lookup(t)
407
408 case *instance:
409
410 return subst.typ(t.expand())
411
412 default:
413 panic("unimplemented")
414 }
415
416 return typ
417 }
418
419
420
421 func instantiatedHash(typ *Named, targs []Type) string {
422 var buf bytes.Buffer
423 writeTypeName(&buf, typ.obj, nil)
424 buf.WriteByte('[')
425 writeTypeList(&buf, targs, nil, nil)
426 buf.WriteByte(']')
427
428
429
430
431
432 res := buf.Bytes()
433 i := 0
434 for _, b := range res {
435 if b != instanceMarker {
436 res[i] = b
437 i++
438 }
439 }
440
441 return string(res[:i])
442 }
443
444 func typeListString(list []Type) string {
445 var buf bytes.Buffer
446 writeTypeList(&buf, list, nil, nil)
447 return buf.String()
448 }
449
450
451
452
453 func (subst *subster) typOrNil(typ Type) Type {
454 if typ == nil {
455 return Typ[Invalid]
456 }
457 return subst.typ(typ)
458 }
459
460 func (subst *subster) var_(v *Var) *Var {
461 if v != nil {
462 if typ := subst.typ(v.typ); typ != v.typ {
463 copy := *v
464 copy.typ = typ
465 return ©
466 }
467 }
468 return v
469 }
470
471 func (subst *subster) tuple(t *Tuple) *Tuple {
472 if t != nil {
473 if vars, copied := subst.varList(t.vars); copied {
474 return &Tuple{vars: vars}
475 }
476 }
477 return t
478 }
479
480 func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
481 out = in
482 for i, v := range in {
483 if w := subst.var_(v); w != v {
484 if !copied {
485
486
487 new := make([]*Var, len(in))
488 copy(new, out)
489 out = new
490 copied = true
491 }
492 out[i] = w
493 }
494 }
495 return
496 }
497
498 func (subst *subster) func_(f *Func) *Func {
499 if f != nil {
500 if typ := subst.typ(f.typ); typ != f.typ {
501 copy := *f
502 copy.typ = typ
503 return ©
504 }
505 }
506 return f
507 }
508
509 func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
510 out = in
511 for i, f := range in {
512 if g := subst.func_(f); g != f {
513 if !copied {
514
515
516 new := make([]*Func, len(in))
517 copy(new, out)
518 out = new
519 copied = true
520 }
521 out[i] = g
522 }
523 }
524 return
525 }
526
527 func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
528 out = in
529 for i, t := range in {
530 if u := subst.typ(t); u != t {
531 if !copied {
532
533
534 new := make([]Type, len(in))
535 copy(new, out)
536 out = new
537 copied = true
538 }
539 out[i] = u
540 }
541 }
542 return
543 }
544
View as plain text