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