...
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 )
15
16
17 type operandMode byte
18
19 const (
20 invalid operandMode = iota
21 novalue
22 builtin
23 typexpr
24 constant_
25 variable
26 mapindex
27 value
28 commaok
29 )
30
31 var operandModeString = [...]string{
32 invalid: "invalid operand",
33 novalue: "no value",
34 builtin: "built-in",
35 typexpr: "type",
36 constant_: "constant",
37 variable: "variable",
38 mapindex: "map index expression",
39 value: "value",
40 commaok: "comma, ok expression",
41 }
42
43
44
45
46
47
48
49 type operand struct {
50 mode operandMode
51 expr ast.Expr
52 typ Type
53 val constant.Value
54 id builtinId
55 }
56
57
58
59
60 func (x *operand) pos() token.Pos {
61
62 if x.expr == nil {
63 return token.NoPos
64 }
65 return x.expr.Pos()
66 }
67
68
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 func operandString(x *operand, qf Qualifier) string {
97 var buf bytes.Buffer
98
99 var expr string
100 if x.expr != nil {
101 expr = ExprString(x.expr)
102 } else {
103 switch x.mode {
104 case builtin:
105 expr = predeclaredFuncs[x.id].name
106 case typexpr:
107 expr = TypeString(x.typ, qf)
108 case constant_:
109 expr = x.val.String()
110 }
111 }
112
113
114 if expr != "" {
115 buf.WriteString(expr)
116 buf.WriteString(" (")
117 }
118
119
120 hasType := false
121 switch x.mode {
122 case invalid, novalue, builtin, typexpr:
123
124 default:
125
126 if x.typ != nil {
127 if isUntyped(x.typ) {
128 buf.WriteString(x.typ.(*Basic).name)
129 buf.WriteByte(' ')
130 break
131 }
132 hasType = true
133 }
134 }
135
136
137 buf.WriteString(operandModeString[x.mode])
138
139
140 if x.mode == constant_ {
141 if s := x.val.String(); s != expr {
142 buf.WriteByte(' ')
143 buf.WriteString(s)
144 }
145 }
146
147
148 if hasType {
149 if x.typ != Typ[Invalid] {
150 buf.WriteString(" of type ")
151 WriteType(&buf, x.typ, qf)
152 } else {
153 buf.WriteString(" with invalid type")
154 }
155 }
156
157
158 if expr != "" {
159 buf.WriteByte(')')
160 }
161
162 return buf.String()
163 }
164
165 func (x *operand) String() string {
166 return operandString(x, nil)
167 }
168
169
170 func (x *operand) setConst(tok token.Token, lit string) {
171 var kind BasicKind
172 switch tok {
173 case token.INT:
174 kind = UntypedInt
175 case token.FLOAT:
176 kind = UntypedFloat
177 case token.IMAG:
178 kind = UntypedComplex
179 case token.CHAR:
180 kind = UntypedRune
181 case token.STRING:
182 kind = UntypedString
183 default:
184 unreachable()
185 }
186
187 x.mode = constant_
188 x.typ = Typ[kind]
189 x.val = constant.MakeFromLiteral(lit, tok, 0)
190 }
191
192
193 func (x *operand) isNil() bool {
194 return x.mode == value && x.typ == Typ[UntypedNil]
195 }
196
197
198
199
200
201
202
203
204
205
206 func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
207 if x.mode == invalid || T == Typ[Invalid] {
208 return true
209 }
210
211 V := x.typ
212
213
214 if Identical(V, T) {
215 return true
216 }
217
218 Vu := V.Underlying()
219 Tu := T.Underlying()
220
221
222
223
224 if isUntyped(Vu) {
225 switch t := Tu.(type) {
226 case *Basic:
227 if x.isNil() && t.kind == UnsafePointer {
228 return true
229 }
230 if x.mode == constant_ {
231 return representableConst(x.val, check, t, nil)
232 }
233
234
235 if Vb, _ := Vu.(*Basic); Vb != nil {
236 return Vb.kind == UntypedBool && isBoolean(Tu)
237 }
238 case *Interface:
239 return x.isNil() || t.Empty()
240 case *Pointer, *Signature, *Slice, *Map, *Chan:
241 return x.isNil()
242 }
243 }
244
245
246
247
248 if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
249 return true
250 }
251
252
253 if Ti, ok := Tu.(*Interface); ok {
254 if m, wrongType := check.missingMethod(x.typ, Ti, true); m != nil {
255 if reason != nil {
256 if wrongType {
257 *reason = "wrong type for method " + m.Name()
258 } else {
259 *reason = "missing method " + m.Name()
260 }
261 }
262 return false
263 }
264 return true
265 }
266
267
268
269
270 if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
271 if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
272 return !isNamed(V) || !isNamed(T)
273 }
274 }
275
276 return false
277 }
278
View as plain text