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