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