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