Source file
src/go/types/operand.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "bytes"
11 "fmt"
12 "go/ast"
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 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
54 type operand struct {
55 mode operandMode
56 expr ast.Expr
57 typ Type
58 val constant.Value
59 id builtinId
60 }
61
62
63
64
65 func (x *operand) Pos() token.Pos {
66
67 if x.expr == nil {
68 return token.NoPos
69 }
70 return x.expr.Pos()
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
105
106
107 func operandString(x *operand, qf Qualifier) string {
108 var buf bytes.Buffer
109
110 var expr string
111 if x.expr != nil {
112 expr = ExprString(x.expr)
113 } else {
114 switch x.mode {
115 case builtin:
116 expr = predeclaredFuncs[x.id].name
117 case typexpr:
118 expr = TypeString(x.typ, qf)
119 case constant_:
120 expr = x.val.String()
121 }
122 }
123
124
125 if expr != "" {
126 buf.WriteString(expr)
127 buf.WriteString(" (")
128 }
129
130
131 hasType := false
132 switch x.mode {
133 case invalid, novalue, builtin, typexpr:
134
135 default:
136
137 if x.typ != nil {
138 if isUntyped(x.typ) {
139 buf.WriteString(x.typ.(*Basic).name)
140 buf.WriteByte(' ')
141 break
142 }
143 hasType = true
144 }
145 }
146
147
148 buf.WriteString(operandModeString[x.mode])
149
150
151 if x.mode == constant_ {
152 if s := x.val.String(); s != expr {
153 buf.WriteByte(' ')
154 buf.WriteString(s)
155 }
156 }
157
158
159 if hasType {
160 if x.typ != Typ[Invalid] {
161 var intro string
162 switch {
163 case isGeneric(x.typ):
164 intro = " of generic type "
165 case asTypeParam(x.typ) != nil:
166 intro = " of type parameter type "
167 default:
168 intro = " of type "
169 }
170 buf.WriteString(intro)
171 WriteType(&buf, x.typ, qf)
172 } else {
173 buf.WriteString(" with invalid type")
174 }
175 }
176
177
178 if expr != "" {
179 buf.WriteByte(')')
180 }
181
182 return buf.String()
183 }
184
185 func (x *operand) String() string {
186 return operandString(x, nil)
187 }
188
189
190 func (x *operand) setConst(tok token.Token, lit string) {
191 var kind BasicKind
192 switch tok {
193 case token.INT:
194 kind = UntypedInt
195 case token.FLOAT:
196 kind = UntypedFloat
197 case token.IMAG:
198 kind = UntypedComplex
199 case token.CHAR:
200 kind = UntypedRune
201 case token.STRING:
202 kind = UntypedString
203 default:
204 unreachable()
205 }
206
207 val := constant.MakeFromLiteral(lit, tok, 0)
208 if val.Kind() == constant.Unknown {
209 x.mode = invalid
210 x.typ = Typ[Invalid]
211 return
212 }
213 x.mode = constant_
214 x.typ = Typ[kind]
215 x.val = val
216 }
217
218
219 func (x *operand) isNil() bool {
220 return x.mode == value && x.typ == Typ[UntypedNil]
221 }
222
223
224
225
226
227
228
229 func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
230 if x.mode == invalid || T == Typ[Invalid] {
231 return true, 0
232 }
233
234 V := x.typ
235
236
237 if check.identical(V, T) {
238 return true, 0
239 }
240
241 Vu := optype(V)
242 Tu := optype(T)
243
244
245 if isUntyped(Vu) {
246 if t, ok := Tu.(*_Sum); ok {
247 return t.is(func(t Type) bool {
248
249 ok, _ := x.assignableTo(check, t, reason)
250 return ok
251 }), _IncompatibleAssign
252 }
253 newType, _, _ := check.implicitTypeAndValue(x, Tu)
254 return newType != nil, _IncompatibleAssign
255 }
256
257
258
259
260 if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
261 return true, 0
262 }
263
264
265 if Ti, ok := Tu.(*Interface); ok {
266 if m, wrongType := check.missingMethod(V, Ti, true); m != nil {
267 if reason != nil {
268 if wrongType != nil {
269 if check.identical(m.typ, wrongType.typ) {
270 *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
271 } else {
272 *reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
273 }
274
275 } else {
276 *reason = "missing method " + m.Name()
277 }
278 }
279 return false, _InvalidIfaceAssign
280 }
281 return true, 0
282 }
283
284
285
286
287 if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
288 if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) {
289 return !isNamed(V) || !isNamed(T), _InvalidChanAssign
290 }
291 }
292
293 return false, _IncompatibleAssign
294 }
295
View as plain text