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