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