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