Source file
src/go/types/operand.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "bytes"
11 "go/ast"
12 "go/constant"
13 "go/token"
14 )
15
16
17 type operandMode byte
18
19 const (
20 invalid operandMode = iota
21 novalue
22 builtin
23 typexpr
24 constant_
25 variable
26 mapindex
27 value
28 commaok
29 commaerr
30 cgofunc
31 )
32
33 var operandModeString = [...]string{
34 invalid: "invalid operand",
35 novalue: "no value",
36 builtin: "built-in",
37 typexpr: "type",
38 constant_: "constant",
39 variable: "variable",
40 mapindex: "map index expression",
41 value: "value",
42 commaok: "comma, ok expression",
43 commaerr: "comma, error expression",
44 cgofunc: "cgo function",
45 }
46
47
48
49
50
51
52 type operand struct {
53 mode operandMode
54 expr ast.Expr
55 typ Type
56 val constant.Value
57 id builtinId
58 }
59
60
61
62 func (x *operand) Pos() token.Pos {
63
64 if x.expr == nil {
65 return token.NoPos
66 }
67 return x.expr.Pos()
68 }
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 func operandString(x *operand, qf Qualifier) string {
104
105 if x.mode == value && x.typ == Typ[UntypedNil] {
106 return "nil"
107 }
108
109 var buf bytes.Buffer
110
111 var expr string
112 if x.expr != nil {
113 expr = ExprString(x.expr)
114 } else {
115 switch x.mode {
116 case builtin:
117 expr = predeclaredFuncs[x.id].name
118 case typexpr:
119 expr = TypeString(x.typ, qf)
120 case constant_:
121 expr = x.val.String()
122 }
123 }
124
125
126 if expr != "" {
127 buf.WriteString(expr)
128 buf.WriteString(" (")
129 }
130
131
132 hasType := false
133 switch x.mode {
134 case invalid, novalue, builtin, typexpr:
135
136 default:
137
138 if x.typ != nil {
139 if isUntyped(x.typ) {
140 buf.WriteString(x.typ.(*Basic).name)
141 buf.WriteByte(' ')
142 break
143 }
144 hasType = true
145 }
146 }
147
148
149 buf.WriteString(operandModeString[x.mode])
150
151
152 if x.mode == constant_ {
153 if s := x.val.String(); s != expr {
154 buf.WriteByte(' ')
155 buf.WriteString(s)
156 }
157 }
158
159
160 if hasType {
161 if x.typ != Typ[Invalid] {
162 var intro string
163 if isGeneric(x.typ) {
164 intro = " of parameterized type "
165 } else {
166 intro = " of type "
167 }
168 buf.WriteString(intro)
169 WriteType(&buf, x.typ, qf)
170 if tpar, _ := x.typ.(*TypeParam); tpar != nil {
171 buf.WriteString(" constrained by ")
172 WriteType(&buf, tpar.bound, qf)
173 }
174 } else {
175 buf.WriteString(" with invalid type")
176 }
177 }
178
179
180 if expr != "" {
181 buf.WriteByte(')')
182 }
183
184 return buf.String()
185 }
186
187 func (x *operand) String() string {
188 return operandString(x, nil)
189 }
190
191
192 func (x *operand) setConst(tok token.Token, lit string) {
193 var kind BasicKind
194 switch tok {
195 case token.INT:
196 kind = UntypedInt
197 case token.FLOAT:
198 kind = UntypedFloat
199 case token.IMAG:
200 kind = UntypedComplex
201 case token.CHAR:
202 kind = UntypedRune
203 case token.STRING:
204 kind = UntypedString
205 default:
206 unreachable()
207 }
208
209 val := constant.MakeFromLiteral(lit, tok, 0)
210 if val.Kind() == constant.Unknown {
211 x.mode = invalid
212 x.typ = Typ[Invalid]
213 return
214 }
215 x.mode = constant_
216 x.typ = Typ[kind]
217 x.val = val
218 }
219
220
221 func (x *operand) isNil() bool {
222 return x.mode == value && x.typ == Typ[UntypedNil]
223 }
224
225
226
227
228
229
230
231 func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
232 if x.mode == invalid || T == Typ[Invalid] {
233 return true, 0
234 }
235
236 V := x.typ
237
238
239 if Identical(V, T) {
240 return true, 0
241 }
242
243 Vu := under(V)
244 Tu := under(T)
245 Vp, _ := V.(*TypeParam)
246 Tp, _ := T.(*TypeParam)
247
248
249 if isUntyped(Vu) {
250 assert(Vp == nil)
251 if Tp != nil {
252
253
254 return Tp.is(func(t *term) bool {
255 if t == nil {
256 return false
257 }
258
259
260
261 newType, _, _ := check.implicitTypeAndValue(x, t.typ)
262 return newType != nil
263 }), _IncompatibleAssign
264 }
265 newType, _, _ := check.implicitTypeAndValue(x, T)
266 return newType != nil, _IncompatibleAssign
267 }
268
269
270
271
272
273 if Identical(Vu, Tu) && (!hasName(V) || !hasName(T)) && Vp == nil && Tp == nil {
274 return true, 0
275 }
276
277
278
279 if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
280 if err := check.implements(V, T); err != nil {
281 if reason != nil {
282 *reason = err.Error()
283 }
284 return false, _InvalidIfaceAssign
285 }
286 return true, 0
287 }
288
289
290 if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
291 if check.implements(T, V) == nil {
292
293 if reason != nil {
294 *reason = "need type assertion"
295 }
296 return false, _IncompatibleAssign
297 }
298 }
299
300
301
302
303 if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
304 if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
305 return !hasName(V) || !hasName(T), _InvalidChanAssign
306 }
307 }
308
309
310 if Vp == nil && Tp == nil {
311 return false, _IncompatibleAssign
312 }
313
314 errorf := func(format string, args ...any) {
315 if check != nil && reason != nil {
316 msg := check.sprintf(format, args...)
317 if *reason != "" {
318 msg += "\n\t" + *reason
319 }
320 *reason = msg
321 }
322 }
323
324
325
326 if !hasName(V) && Tp != nil {
327 ok := false
328 code := _IncompatibleAssign
329 Tp.is(func(T *term) bool {
330 if T == nil {
331 return false
332 }
333 ok, code = x.assignableTo(check, T.typ, reason)
334 if !ok {
335 errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
336 return false
337 }
338 return true
339 })
340 return ok, code
341 }
342
343
344
345
346 if Vp != nil && !hasName(T) {
347 x := *x
348 ok := false
349 code := _IncompatibleAssign
350 Vp.is(func(V *term) bool {
351 if V == nil {
352 return false
353 }
354 x.typ = V.typ
355 ok, code = x.assignableTo(check, T, reason)
356 if !ok {
357 errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T)
358 return false
359 }
360 return true
361 })
362 return ok, code
363 }
364
365 return false, _IncompatibleAssign
366 }
367
View as plain text