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