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