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