Source file
src/go/types/instantiate.go
1
2
3
4
5
6
7
8 package types
9
10 import (
11 "errors"
12 "fmt"
13 "go/token"
14 )
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 func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, error) {
43 if validate {
44 var tparams []*TypeParam
45 switch t := orig.(type) {
46 case *Named:
47 tparams = t.TypeParams().list()
48 case *Signature:
49 tparams = t.TypeParams().list()
50 }
51 if len(targs) != len(tparams) {
52 return nil, fmt.Errorf("got %d type arguments but %s has %d type parameters", len(targs), orig, len(tparams))
53 }
54 if i, err := (*Checker)(nil).verify(token.NoPos, tparams, targs); err != nil {
55 return nil, &ArgumentError{i, err}
56 }
57 }
58
59 inst := (*Checker)(nil).instance(token.NoPos, orig, targs, ctxt)
60 return inst, nil
61 }
62
63
64
65
66 func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, ctxt *Context) (res Type) {
67 var h string
68 if ctxt != nil {
69 h = ctxt.instanceHash(orig, targs)
70
71
72 if inst := ctxt.lookup(h, orig, targs); inst != nil {
73 return inst
74 }
75 }
76
77 switch orig := orig.(type) {
78 case *Named:
79 tname := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
80 named := check.newNamed(tname, orig, nil, nil, nil)
81 named.targs = newTypeList(targs)
82 named.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, *methodList) {
83 return expandNamed(ctxt, n, pos)
84 }
85 res = named
86
87 case *Signature:
88 tparams := orig.TypeParams()
89 if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
90 return Typ[Invalid]
91 }
92 if tparams.Len() == 0 {
93 return orig
94 }
95 sig := check.subst(pos, orig, makeSubstMap(tparams.list(), targs), ctxt).(*Signature)
96
97
98
99 if sig == orig {
100 copy := *sig
101 sig = ©
102 }
103
104
105 sig.tparams = nil
106 res = sig
107 default:
108
109 panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig))
110 }
111
112 if ctxt != nil {
113
114
115 res = ctxt.update(h, orig, targs, res)
116 }
117
118 return res
119 }
120
121
122
123
124 func (check *Checker) validateTArgLen(pos token.Pos, ntparams, ntargs int) bool {
125 if ntargs != ntparams {
126
127 if check != nil {
128 check.errorf(atPos(pos), _WrongTypeArgCount, "got %d arguments but %d type parameters", ntargs, ntparams)
129 return false
130 }
131 panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
132 }
133 return true
134 }
135
136 func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type) (int, error) {
137 smap := makeSubstMap(tparams, targs)
138 for i, tpar := range tparams {
139
140 tpar.iface()
141
142
143
144
145 bound := check.subst(pos, tpar.bound, smap, nil)
146 if err := check.implements(targs[i], bound); err != nil {
147 return i, err
148 }
149 }
150 return -1, nil
151 }
152
153
154
155
156 func (check *Checker) implements(V, T Type) error {
157 Vu := under(V)
158 Tu := under(T)
159 if Vu == Typ[Invalid] || Tu == Typ[Invalid] {
160 return nil
161 }
162 if p, _ := Vu.(*Pointer); p != nil && under(p.base) == Typ[Invalid] {
163 return nil
164 }
165
166 errorf := func(format string, args ...any) error {
167 return errors.New(check.sprintf(format, args...))
168 }
169
170 Ti, _ := Tu.(*Interface)
171 if Ti == nil {
172 var cause string
173 if isInterfacePtr(Tu) {
174 cause = check.sprintf("type %s is pointer to interface, not interface", T)
175 } else {
176 cause = check.sprintf("%s is not an interface", T)
177 }
178 return errorf("%s does not implement %s (%s)", V, T, cause)
179 }
180
181
182 if Ti.Empty() {
183 return nil
184 }
185
186
187
188
189 Vi, _ := Vu.(*Interface)
190 if Vi != nil && Vi.typeSet().IsEmpty() {
191 return nil
192 }
193
194
195
196 if Ti.typeSet().IsEmpty() {
197 return errorf("cannot implement %s (empty type set)", T)
198 }
199
200
201 if m, wrong := check.missingMethod(V, Ti, true); m != nil {
202 return errorf("%s does not implement %s %s", V, T, check.missingMethodReason(V, T, m, wrong))
203 }
204
205
206
207 var pending error
208 if Ti.IsComparable() && !comparable(V, false, nil, nil) {
209 pending = errorf("%s does not implement comparable", V)
210 }
211
212
213
214 if !Ti.typeSet().hasTerms() {
215 return pending
216 }
217
218
219
220
221 if Vi != nil {
222 if !Vi.typeSet().subsetOf(Ti.typeSet()) {
223
224 return errorf("%s does not implement %s", V, T)
225 }
226 return pending
227 }
228
229
230 var alt Type
231 if Ti.typeSet().is(func(t *term) bool {
232 if !t.includes(V) {
233
234
235
236 if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) {
237 tt := *t
238 tt.tilde = true
239 if tt.includes(V) {
240 alt = t.typ
241 }
242 }
243 return true
244 }
245 return false
246 }) {
247 if alt != nil {
248 return errorf("%s does not implement %s (possibly missing ~ for %s in constraint %s)", V, T, alt, T)
249 } else {
250 return errorf("%s does not implement %s", V, T)
251 }
252 }
253
254 return pending
255 }
256
View as plain text