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