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