Source file
src/go/types/operand.go
1
2
3
4
5
6
7
8
9
10 package types
11
12 import (
13 "bytes"
14 "fmt"
15 "go/ast"
16 "go/constant"
17 "go/token"
18 . "internal/types/errors"
19 )
20
21
22 type operandMode byte
23
24 const (
25 invalid operandMode = iota
26 novalue
27 builtin
28 typexpr
29 constant_
30 variable
31 mapindex
32 value
33 nilvalue
34 commaok
35 commaerr
36 cgofunc
37 )
38
39 var operandModeString = [...]string{
40 invalid: "invalid operand",
41 novalue: "no value",
42 builtin: "built-in",
43 typexpr: "type",
44 constant_: "constant",
45 variable: "variable",
46 mapindex: "map index expression",
47 value: "value",
48 nilvalue: "nil",
49 commaok: "comma, ok expression",
50 commaerr: "comma, error expression",
51 cgofunc: "cgo function",
52 }
53
54
55
56
57
58
59 type operand struct {
60 mode operandMode
61 expr ast.Expr
62 typ Type
63 val constant.Value
64 id builtinId
65 }
66
67
68
69 func (x *operand) Pos() token.Pos {
70
71 if x.expr == nil {
72 return nopos
73 }
74 return x.expr.Pos()
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
104
105
106
107
108
109
110
111
112
113 func operandString(x *operand, qf Qualifier) string {
114
115 if isTypes2 {
116 if x.mode == nilvalue {
117 switch x.typ {
118 case nil, Typ[Invalid]:
119 return "nil (with invalid type)"
120 case Typ[UntypedNil]:
121 return "nil"
122 default:
123 return fmt.Sprintf("nil (of type %s)", TypeString(x.typ, qf))
124 }
125 }
126 } else {
127 if x.mode == value && x.typ == Typ[UntypedNil] {
128 return "nil"
129 }
130 }
131
132 var buf bytes.Buffer
133
134 var expr string
135 if x.expr != nil {
136 expr = ExprString(x.expr)
137 } else {
138 switch x.mode {
139 case builtin:
140 expr = predeclaredFuncs[x.id].name
141 case typexpr:
142 expr = TypeString(x.typ, qf)
143 case constant_:
144 expr = x.val.String()
145 }
146 }
147
148
149 if expr != "" {
150 buf.WriteString(expr)
151 buf.WriteString(" (")
152 }
153
154
155 hasType := false
156 switch x.mode {
157 case invalid, novalue, builtin, typexpr:
158
159 default:
160
161 if x.typ != nil {
162 if isUntyped(x.typ) {
163 buf.WriteString(x.typ.(*Basic).name)
164 buf.WriteByte(' ')
165 break
166 }
167 hasType = true
168 }
169 }
170
171
172 buf.WriteString(operandModeString[x.mode])
173
174
175 if x.mode == constant_ {
176 if s := x.val.String(); s != expr {
177 buf.WriteByte(' ')
178 buf.WriteString(s)
179 }
180 }
181
182
183 if hasType {
184 if isValid(x.typ) {
185 var desc string
186 if isGeneric(x.typ) {
187 desc = "generic "
188 }
189
190
191
192
193
194 tpar, _ := Unalias(x.typ).(*TypeParam)
195 if tpar == nil {
196 switch x.typ.(type) {
197 case *Alias, *Named:
198 what := compositeKind(x.typ)
199 if what == "" {
200
201 what = under(x.typ).(*Basic).name
202 }
203 desc += what + " "
204 }
205 }
206
207
208 buf.WriteString(" of " + desc + "type ")
209 WriteType(&buf, x.typ, qf)
210
211 if tpar != nil {
212 buf.WriteString(" constrained by ")
213 WriteType(&buf, tpar.bound, qf)
214
215 if hasEmptyTypeset(tpar) {
216 buf.WriteString(" with empty type set")
217 }
218 }
219 } else {
220 buf.WriteString(" with invalid type")
221 }
222 }
223
224
225 if expr != "" {
226 buf.WriteByte(')')
227 }
228
229 return buf.String()
230 }
231
232
233
234
235 func compositeKind(typ Type) string {
236 switch under(typ).(type) {
237 case *Basic:
238 return ""
239 case *Array:
240 return "array"
241 case *Slice:
242 return "slice"
243 case *Struct:
244 return "struct"
245 case *Pointer:
246 return "pointer"
247 case *Signature:
248 return "func"
249 case *Interface:
250 return "interface"
251 case *Map:
252 return "map"
253 case *Chan:
254 return "chan"
255 case *Tuple:
256 return "tuple"
257 case *Union:
258 return "union"
259 default:
260 panic("unreachable")
261 }
262 }
263
264 func (x *operand) String() string {
265 return operandString(x, nil)
266 }
267
268
269 func (x *operand) setConst(k token.Token, lit string) {
270 var kind BasicKind
271 switch k {
272 case token.INT:
273 kind = UntypedInt
274 case token.FLOAT:
275 kind = UntypedFloat
276 case token.IMAG:
277 kind = UntypedComplex
278 case token.CHAR:
279 kind = UntypedRune
280 case token.STRING:
281 kind = UntypedString
282 default:
283 panic("unreachable")
284 }
285
286 val := makeFromLiteral(lit, k)
287 if val.Kind() == constant.Unknown {
288 x.mode = invalid
289 x.typ = Typ[Invalid]
290 return
291 }
292 x.mode = constant_
293 x.typ = Typ[kind]
294 x.val = val
295 }
296
297
298 func (x *operand) isNil() bool {
299 if isTypes2 {
300 return x.mode == nilvalue
301 } else {
302 return x.mode == value && x.typ == Typ[UntypedNil]
303 }
304 }
305
306
307
308
309
310
311
312 func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Code) {
313 if x.mode == invalid || !isValid(T) {
314 return true, 0
315 }
316
317 origT := T
318 V := Unalias(x.typ)
319 T = Unalias(T)
320
321
322 if Identical(V, T) {
323 return true, 0
324 }
325
326 Vu := under(V)
327 Tu := under(T)
328 Vp, _ := V.(*TypeParam)
329 Tp, _ := T.(*TypeParam)
330
331
332 if isUntyped(Vu) {
333 assert(Vp == nil)
334 if Tp != nil {
335
336
337 return Tp.is(func(t *term) bool {
338 if t == nil {
339 return false
340 }
341
342
343
344 newType, _, _ := check.implicitTypeAndValue(x, t.typ)
345 return newType != nil
346 }), IncompatibleAssign
347 }
348 newType, _, _ := check.implicitTypeAndValue(x, T)
349 return newType != nil, IncompatibleAssign
350 }
351
352
353
354
355
356 if Identical(Vu, Tu) && (!hasName(V) || !hasName(T)) && Vp == nil && Tp == nil {
357 return true, 0
358 }
359
360
361
362
363 if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
364 if check.implements(V, T, false, cause) {
365 return true, 0
366 }
367
368
369 if Vp == nil {
370 return false, InvalidIfaceAssign
371 }
372 if cause != nil {
373 *cause = ""
374 }
375 }
376
377
378 if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
379 if check.implements(T, V, false, nil) {
380
381 if cause != nil {
382 *cause = "need type assertion"
383 }
384 return false, IncompatibleAssign
385 }
386 }
387
388
389
390
391 if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
392 if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
393 return !hasName(V) || !hasName(T), InvalidChanAssign
394 }
395 }
396
397
398 if Vp == nil && Tp == nil {
399 return false, IncompatibleAssign
400 }
401
402 errorf := func(format string, args ...any) {
403 if check != nil && cause != nil {
404 msg := check.sprintf(format, args...)
405 if *cause != "" {
406 msg += "\n\t" + *cause
407 }
408 *cause = msg
409 }
410 }
411
412
413
414 if !hasName(V) && Tp != nil {
415 ok := false
416 code := IncompatibleAssign
417 Tp.is(func(T *term) bool {
418 if T == nil {
419 return false
420 }
421 ok, code = x.assignableTo(check, T.typ, cause)
422 if !ok {
423 errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
424 return false
425 }
426 return true
427 })
428 return ok, code
429 }
430
431
432
433
434 if Vp != nil && !hasName(T) {
435 x := *x
436 ok := false
437 code := IncompatibleAssign
438 Vp.is(func(V *term) bool {
439 if V == nil {
440 return false
441 }
442 x.typ = V.typ
443 ok, code = x.assignableTo(check, T, cause)
444 if !ok {
445 errorf("cannot assign %s (in %s) to %s", V.typ, Vp, origT)
446 return false
447 }
448 return true
449 })
450 return ok, code
451 }
452
453 return false, IncompatibleAssign
454 }
455
View as plain text