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