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 func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, expanding *Named, ctxt *Context) (res Type) {
89
90
91
92
93
94 var ctxts []*Context
95 if expanding != nil {
96 ctxts = append(ctxts, expanding.inst.ctxt)
97 }
98 if ctxt != nil {
99 ctxts = append(ctxts, ctxt)
100 }
101 assert(len(ctxts) > 0)
102
103
104
105 hashes := make([]string, len(ctxts))
106 for i, ctxt := range ctxts {
107 hashes[i] = ctxt.instanceHash(orig, targs)
108 }
109
110
111
112
113 updateContexts := func(res Type) Type {
114 for i := len(ctxts) - 1; i >= 0; i-- {
115 res = ctxts[i].update(hashes[i], orig, targs, res)
116 }
117 return res
118 }
119
120
121
122 for i, ctxt := range ctxts {
123 if inst := ctxt.lookup(hashes[i], orig, targs); inst != nil {
124 return updateContexts(inst)
125 }
126 }
127
128 switch orig := orig.(type) {
129 case *Named:
130 res = check.newNamedInstance(pos, orig, targs, expanding)
131
132 case *Alias:
133 if !buildcfg.Experiment.AliasTypeParams {
134 assert(expanding == nil)
135 }
136
137 tparams := orig.TypeParams()
138
139 if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) {
140 return Typ[Invalid]
141 }
142 if tparams.Len() == 0 {
143 return orig
144 }
145
146 return check.newAliasInstance(pos, orig, targs, expanding, ctxt)
147
148 case *Signature:
149 assert(expanding == nil)
150
151 tparams := orig.TypeParams()
152
153 if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) {
154 return Typ[Invalid]
155 }
156 if tparams.Len() == 0 {
157 return orig
158 }
159 sig := check.subst(pos, orig, makeSubstMap(tparams.list(), targs), nil, ctxt).(*Signature)
160
161
162
163 if sig == orig {
164 copy := *sig
165 sig = ©
166 }
167
168
169 sig.tparams = nil
170 res = sig
171
172 default:
173
174 panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig))
175 }
176
177
178 return updateContexts(res)
179 }
180
181
182
183
184 func (check *Checker) validateTArgLen(pos token.Pos, name string, want, got int) bool {
185 var qual string
186 switch {
187 case got < want:
188 qual = "not enough"
189 case got > want:
190 qual = "too many"
191 default:
192 return true
193 }
194
195 msg := check.sprintf("%s type arguments for type %s: have %d, want %d", qual, name, got, want)
196 if check != nil {
197 check.error(atPos(pos), WrongTypeArgCount, msg)
198 return false
199 }
200
201 panic(fmt.Sprintf("%v: %s", pos, msg))
202 }
203
204 func (check *Checker) verify(pos token.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(pos, 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(pos token.Pos, 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 m, _ := check.missingMethod(V, T, true, Identical, cause); m != nil {
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 comparable(V, false , nil, nil) {
295 return true
296 }
297
298
299 if constraint && comparable(V, true , nil, nil) {
300
301 if check == nil || check.allowVersion(atPos(pos), 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