Source file src/go/types/assignments.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "go/ast"
11 "go/token"
12 )
13
14
15
16
17
18
19 func (check *Checker) assignment(x *operand, T Type, context string) {
20 check.singleValue(x)
21
22 switch x.mode {
23 case invalid:
24 return
25 case constant_, variable, mapindex, value, commaok:
26
27 default:
28 unreachable()
29 }
30
31 if isUntyped(x.typ) {
32 target := T
33
34
35
36
37
38 if T == nil || IsInterface(T) {
39 if T == nil && x.typ == Typ[UntypedNil] {
40 check.errorf(x.pos(), "use of untyped nil in %s", context)
41 x.mode = invalid
42 return
43 }
44 target = Default(x.typ)
45 }
46 check.convertUntyped(x, target)
47 if x.mode == invalid {
48 return
49 }
50 }
51
52
53
54
55
56 if T == nil {
57 return
58 }
59
60 if reason := ""; !x.assignableTo(check, T, &reason) {
61 if reason != "" {
62 check.errorf(x.pos(), "cannot use %s as %s value in %s: %s", x, T, context, reason)
63 } else {
64 check.errorf(x.pos(), "cannot use %s as %s value in %s", x, T, context)
65 }
66 x.mode = invalid
67 }
68 }
69
70 func (check *Checker) initConst(lhs *Const, x *operand) {
71 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
72 if lhs.typ == nil {
73 lhs.typ = Typ[Invalid]
74 }
75 return
76 }
77
78
79 if x.mode != constant_ {
80 check.errorf(x.pos(), "%s is not constant", x)
81 if lhs.typ == nil {
82 lhs.typ = Typ[Invalid]
83 }
84 return
85 }
86 assert(isConstType(x.typ))
87
88
89 if lhs.typ == nil {
90 lhs.typ = x.typ
91 }
92
93 check.assignment(x, lhs.typ, "constant declaration")
94 if x.mode == invalid {
95 return
96 }
97
98 lhs.val = x.val
99 }
100
101 func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
102 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
103 if lhs.typ == nil {
104 lhs.typ = Typ[Invalid]
105 }
106 return nil
107 }
108
109
110 if lhs.typ == nil {
111 typ := x.typ
112 if isUntyped(typ) {
113
114 if typ == Typ[UntypedNil] {
115 check.errorf(x.pos(), "use of untyped nil in %s", context)
116 lhs.typ = Typ[Invalid]
117 return nil
118 }
119 typ = Default(typ)
120 }
121 lhs.typ = typ
122 }
123
124 check.assignment(x, lhs.typ, context)
125 if x.mode == invalid {
126 return nil
127 }
128
129 return x.typ
130 }
131
132 func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
133 if x.mode == invalid || x.typ == Typ[Invalid] {
134 return nil
135 }
136
137
138 ident, _ := unparen(lhs).(*ast.Ident)
139
140
141 if ident != nil && ident.Name == "_" {
142 check.recordDef(ident, nil)
143 check.assignment(x, nil, "assignment to _ identifier")
144 if x.mode == invalid {
145 return nil
146 }
147 return x.typ
148 }
149
150
151
152
153 var v *Var
154 var v_used bool
155 if ident != nil {
156 if obj := check.lookup(ident.Name); obj != nil {
157
158
159
160 if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
161 v = w
162 v_used = v.used
163 }
164 }
165 }
166
167 var z operand
168 check.expr(&z, lhs)
169 if v != nil {
170 v.used = v_used
171 }
172
173 if z.mode == invalid || z.typ == Typ[Invalid] {
174 return nil
175 }
176
177
178
179 switch z.mode {
180 case invalid:
181 return nil
182 case variable, mapindex:
183
184 default:
185 if sel, ok := z.expr.(*ast.SelectorExpr); ok {
186 var op operand
187 check.expr(&op, sel.X)
188 if op.mode == mapindex {
189 check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr))
190 return nil
191 }
192 }
193 check.errorf(z.pos(), "cannot assign to %s", &z)
194 return nil
195 }
196
197 check.assignment(x, z.typ, "assignment")
198 if x.mode == invalid {
199 return nil
200 }
201
202 return x.typ
203 }
204
205
206
207 func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
208 l := len(lhs)
209 get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
210 if get == nil || l != r {
211
212 for _, obj := range lhs {
213 if obj.typ == nil {
214 obj.typ = Typ[Invalid]
215 }
216 }
217 if get == nil {
218 return
219 }
220 check.useGetter(get, r)
221 if returnPos.IsValid() {
222 check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
223 return
224 }
225 check.errorf(rhs[0].Pos(), "cannot initialize %d variables with %d values", l, r)
226 return
227 }
228
229 context := "assignment"
230 if returnPos.IsValid() {
231 context = "return statement"
232 }
233
234 var x operand
235 if commaOk {
236 var a [2]Type
237 for i := range a {
238 get(&x, i)
239 a[i] = check.initVar(lhs[i], &x, context)
240 }
241 check.recordCommaOkTypes(rhs[0], a)
242 return
243 }
244
245 for i, lhs := range lhs {
246 get(&x, i)
247 check.initVar(lhs, &x, context)
248 }
249 }
250
251 func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
252 l := len(lhs)
253 get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
254 if get == nil {
255 check.useLHS(lhs...)
256 return
257 }
258 if l != r {
259 check.useGetter(get, r)
260 check.errorf(rhs[0].Pos(), "cannot assign %d values to %d variables", r, l)
261 return
262 }
263
264 var x operand
265 if commaOk {
266 var a [2]Type
267 for i := range a {
268 get(&x, i)
269 a[i] = check.assignVar(lhs[i], &x)
270 }
271 check.recordCommaOkTypes(rhs[0], a)
272 return
273 }
274
275 for i, lhs := range lhs {
276 get(&x, i)
277 check.assignVar(lhs, &x)
278 }
279 }
280
281 func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
282 top := len(check.delayed)
283 scope := check.scope
284
285
286 var newVars []*Var
287 var lhsVars = make([]*Var, len(lhs))
288 for i, lhs := range lhs {
289 var obj *Var
290 if ident, _ := lhs.(*ast.Ident); ident != nil {
291
292
293
294
295 name := ident.Name
296 if alt := scope.Lookup(name); alt != nil {
297
298 if alt, _ := alt.(*Var); alt != nil {
299 obj = alt
300 } else {
301 check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
302 }
303 check.recordUse(ident, alt)
304 } else {
305
306 obj = NewVar(ident.Pos(), check.pkg, name, nil)
307 if name != "_" {
308 newVars = append(newVars, obj)
309 }
310 check.recordDef(ident, obj)
311 }
312 } else {
313 check.useLHS(lhs)
314 check.errorf(lhs.Pos(), "cannot declare %s", lhs)
315 }
316 if obj == nil {
317 obj = NewVar(lhs.Pos(), check.pkg, "_", nil)
318 }
319 lhsVars[i] = obj
320 }
321
322 check.initVars(lhsVars, rhs, token.NoPos)
323
324
325 check.processDelayed(top)
326
327
328 if len(newVars) > 0 {
329
330
331
332
333 scopePos := rhs[len(rhs)-1].End()
334 for _, obj := range newVars {
335 check.declare(scope, nil, obj, scopePos)
336 }
337 } else {
338 check.softErrorf(pos, "no new variables on left side of :=")
339 }
340 }
341
View as plain text