Source file
src/go/types/instantiate.go
1
2
3
4
5
6
7
8
9
10
11 package types
12
13 import (
14 "errors"
15 "fmt"
16 "go/token"
17 "internal/buildcfg"
18 . "internal/types/errors"
19 )
20
21
22 type genericType interface {
23 Type
24 TypeParams() *TypeParamList
25 }
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, error) {
56 assert(len(targs) > 0)
57 if ctxt == nil {
58 ctxt = NewContext()
59 }
60 orig_ := orig.(genericType)
61
62 if validate {
63 tparams := orig_.TypeParams().list()
64 assert(len(tparams) > 0)
65 if len(targs) != len(tparams) {
66 return nil, fmt.Errorf("got %d type arguments but %s has %d type parameters", len(targs), orig, len(tparams))
67 }
68 if i, err := (*Checker)(nil).verify(nopos, tparams, targs, ctxt); err != nil {
69 return nil, &ArgumentError{i, err}
70 }
71 }
72
73 inst := (*Checker)(nil).instance(nopos, orig_, targs, nil, ctxt)
74 return inst, nil
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, expanding *Named, ctxt *Context) (res Type) {
92
93
94
95
96
97 var ctxts []*Context
98 if expanding != nil {
99 ctxts = append(ctxts, expanding.inst.ctxt)
100 }
101 if ctxt != nil {
102 ctxts = append(ctxts, ctxt)
103 }
104 assert(len(ctxts) > 0)
105
106
107
108 hashes := make([]string, len(ctxts))
109 for i, ctxt := range ctxts {
110 hashes[i] = ctxt.instanceHash(orig, targs)
111 }
112
113
114
115
116 updateContexts := func(res Type) Type {
117 for i := len(ctxts) - 1; i >= 0; i-- {
118 res = ctxts[i].update(hashes[i], orig, targs, res)
119 }
120 return res
121 }
122
123
124
125 for i, ctxt := range ctxts {
126 if inst := ctxt.lookup(hashes[i], orig, targs); inst != nil {
127 return updateContexts(inst)
128 }
129 }
130
131 switch orig := orig.(type) {
132 case *Named:
133 res = check.newNamedInstance(pos, orig, targs, expanding)
134
135 case *Alias:
136 if !buildcfg.Experiment.AliasTypeParams {
137 assert(expanding == nil)
138 }
139
140
141 tparams := orig.TypeParams()
142 if !check.validateTArgLen(pos, orig.obj.Name(), tparams.Len(), len(targs)) {
143
144
145
146
147 return Typ[Invalid]
148 }
149 if tparams.Len() == 0 {
150 return orig
151 }
152
153 res = check.newAliasInstance(pos, orig, targs, expanding, ctxt)
154
155 case *Signature:
156 assert(expanding == nil)
157
158 tparams := orig.TypeParams()
159
160 if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) {
161 return Typ[Invalid]
162 }
163 if tparams.Len() == 0 {
164 return orig
165 }
166 sig := check.subst(pos, orig, makeSubstMap(tparams.list(), targs), nil, ctxt).(*Signature)
167
168
169
170 if sig == orig {
171 copy := *sig
172 sig = ©
173 }
174
175
176 sig.tparams = nil
177 res = sig
178
179 default:
180
181 panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig))
182 }
183
184
185 return updateContexts(res)
186 }
187
188
189
190
191 func (check *Checker) validateTArgLen(pos token.Pos, name string, want, got int) bool {
192 var qual string
193 switch {
194 case got < want:
195 qual = "not enough"
196 case got > want:
197 qual = "too many"
198 default:
199 return true
200 }
201
202 msg := check.sprintf("%s type arguments for type %s: have %d, want %d", qual, name, got, want)
203 if check != nil {
204 check.error(atPos(pos), WrongTypeArgCount, msg)
205 return false
206 }
207
208 panic(fmt.Sprintf("%v: %s", pos, msg))
209 }
210
211
212 func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type, ctxt *Context) (int, error) {
213 smap := makeSubstMap(tparams, targs)
214 for i, tpar := range tparams {
215
216 tpar.iface()
217
218
219
220
221 bound := check.subst(pos, tpar.bound, smap, nil, ctxt)
222 var cause string
223 if !check.implements(targs[i], bound, true, &cause) {
224 return i, errors.New(cause)
225 }
226 }
227 return -1, nil
228 }
229
230
231
232
233
234
235
236 func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool {
237 Vu := under(V)
238 Tu := under(T)
239 if !isValid(Vu) || !isValid(Tu) {
240 return true
241 }
242 if p, _ := Vu.(*Pointer); p != nil && !isValid(under(p.base)) {
243 return true
244 }
245
246 verb := "implement"
247 if constraint {
248 verb = "satisfy"
249 }
250
251 Ti, _ := Tu.(*Interface)
252 if Ti == nil {
253 if cause != nil {
254 var detail string
255 if isInterfacePtr(Tu) {
256 detail = check.sprintf("type %s is pointer to interface, not interface", T)
257 } else {
258 detail = check.sprintf("%s is not an interface", T)
259 }
260 *cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
261 }
262 return false
263 }
264
265
266 if Ti.Empty() {
267 return true
268 }
269
270
271
272
273 Vi, _ := Vu.(*Interface)
274 if Vi != nil && Vi.typeSet().IsEmpty() {
275 return true
276 }
277
278
279
280 if Ti.typeSet().IsEmpty() {
281 if cause != nil {
282 *cause = check.sprintf("cannot %s %s (empty type set)", verb, T)
283 }
284 return false
285 }
286
287
288 if !check.hasAllMethods(V, T, true, Identical, cause) {
289 if cause != nil {
290 *cause = check.sprintf("%s does not %s %s %s", V, verb, T, *cause)
291 }
292 return false
293 }
294
295
296 checkComparability := func() bool {
297 if !Ti.IsComparable() {
298 return true
299 }
300
301
302 if comparableType(V, false , nil, nil) {
303 return true
304 }
305
306
307 if constraint && comparableType(V, true , nil, nil) {
308
309 if check == nil || check.allowVersion(go1_20) {
310 return true
311 }
312 if cause != nil {
313 *cause = check.sprintf("%s to %s comparable requires go1.20 or later", V, verb)
314 }
315 return false
316 }
317 if cause != nil {
318 *cause = check.sprintf("%s does not %s comparable", V, verb)
319 }
320 return false
321 }
322
323
324
325 if !Ti.typeSet().hasTerms() {
326 return checkComparability()
327 }
328
329
330
331
332 if Vi != nil {
333 if !Vi.typeSet().subsetOf(Ti.typeSet()) {
334
335 if cause != nil {
336 *cause = check.sprintf("%s does not %s %s", V, verb, T)
337 }
338 return false
339 }
340 return checkComparability()
341 }
342
343
344 var alt Type
345 if Ti.typeSet().is(func(t *term) bool {
346 if !t.includes(V) {
347
348
349
350 if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) {
351 tt := *t
352 tt.tilde = true
353 if tt.includes(V) {
354 alt = t.typ
355 }
356 }
357 return true
358 }
359 return false
360 }) {
361 if cause != nil {
362 var detail string
363 switch {
364 case alt != nil:
365 detail = check.sprintf("possibly missing ~ for %s in %s", alt, T)
366 case mentions(Ti, V):
367 detail = check.sprintf("%s mentions %s, but %s is not in the type set of %s", T, V, V, T)
368 default:
369 detail = check.sprintf("%s missing in %s", V, Ti.typeSet().terms)
370 }
371 *cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
372 }
373 return false
374 }
375
376 return checkComparability()
377 }
378
379
380
381 func mentions(T, typ Type) bool {
382 switch T := T.(type) {
383 case *Interface:
384 for _, e := range T.embeddeds {
385 if mentions(e, typ) {
386 return true
387 }
388 }
389 case *Union:
390 for _, t := range T.terms {
391 if mentions(t.typ, typ) {
392 return true
393 }
394 }
395 default:
396 if Identical(T, typ) {
397 return true
398 }
399 }
400 return false
401 }
402
View as plain text