Source file
src/go/types/assignments.go
1
2
3
4
5
6
7
8
9
10 package types
11
12 import (
13 "fmt"
14 "go/ast"
15 . "internal/types/errors"
16 "strings"
17 )
18
19
20
21
22
23
24 func (check *Checker) assignment(x *operand, T Type, context string) {
25 check.singleValue(x)
26
27 switch x.mode() {
28 case invalid:
29 return
30 case nilvalue:
31 assert(isTypes2)
32
33 case constant_, variable, mapindex, value, commaok, commaerr:
34
35 default:
36
37
38 check.errorf(x, IncompatibleAssign, "cannot assign %s to %s in %s", x, T, context)
39 x.invalidate()
40 return
41 }
42
43 if isUntyped(x.typ()) {
44 target := T
45
46
47
48
49
50 if isTypes2 {
51 if x.isNil() {
52 if T == nil {
53 check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
54 x.invalidate()
55 return
56 }
57 } else if T == nil || isNonTypeParamInterface(T) {
58 target = Default(x.typ())
59 }
60 } else {
61 if T == nil || isNonTypeParamInterface(T) {
62 if T == nil && x.typ() == Typ[UntypedNil] {
63 check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
64 x.invalidate()
65 return
66 }
67 target = Default(x.typ())
68 }
69 }
70 newType, val, code := check.implicitTypeAndValue(x, target)
71 if code != 0 {
72 msg := check.sprintf("cannot use %s as %s value in %s", x, target, context)
73 switch code {
74 case TruncatedFloat:
75 msg += " (truncated)"
76 case NumericOverflow:
77 msg += " (overflows)"
78 default:
79 code = IncompatibleAssign
80 }
81 check.error(x, code, msg)
82 x.invalidate()
83 return
84 }
85 if val != nil {
86 x.val = val
87 check.updateExprVal(x.expr, val)
88 }
89 if newType != x.typ() {
90 x.typ_ = newType
91 check.updateExprType(x.expr, newType, false)
92 }
93 }
94
95
96
97 check.nonGeneric(newTarget(T, context), x)
98 if !x.isValid() {
99 return
100 }
101
102
103
104
105 if T == nil {
106 return
107 }
108
109 cause := ""
110 if ok, code := x.assignableTo(check, T, &cause); !ok {
111 if cause != "" {
112 check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, cause)
113 } else {
114 check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
115 }
116 x.invalidate()
117 }
118 }
119
120 func (check *Checker) initConst(lhs *Const, x *operand) {
121 if !x.isValid() || !isValid(x.typ()) || !isValid(lhs.typ) {
122 if lhs.typ == nil {
123 lhs.typ = Typ[Invalid]
124 }
125 return
126 }
127
128
129 if x.mode() != constant_ {
130 check.errorf(x, InvalidConstInit, "%s is not constant", x)
131 if lhs.typ == nil {
132 lhs.typ = Typ[Invalid]
133 }
134 return
135 }
136 assert(isConstType(x.typ()))
137
138
139 if lhs.typ == nil {
140 lhs.typ = x.typ()
141 }
142
143 check.assignment(x, lhs.typ, "constant declaration")
144 if !x.isValid() {
145 return
146 }
147
148 lhs.val = x.val
149 }
150
151
152
153
154
155 func (check *Checker) initVar(lhs *Var, x *operand, context string) {
156 if !x.isValid() || !isValid(x.typ()) || !isValid(lhs.typ) {
157 if lhs.typ == nil {
158 lhs.typ = Typ[Invalid]
159 }
160 x.invalidate()
161 return
162 }
163
164
165 if lhs.typ == nil {
166 typ := x.typ()
167 if isUntyped(typ) {
168
169 if typ == Typ[UntypedNil] {
170 check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
171 lhs.typ = Typ[Invalid]
172 x.invalidate()
173 return
174 }
175 typ = Default(typ)
176 }
177 lhs.typ = typ
178 }
179
180 check.assignment(x, lhs.typ, context)
181 }
182
183
184
185
186
187 func (check *Checker) lhsVar(lhs ast.Expr) Type {
188
189 ident, _ := ast.Unparen(lhs).(*ast.Ident)
190
191
192 if ident != nil && ident.Name == "_" {
193 check.recordDef(ident, nil)
194 return nil
195 }
196
197
198
199
200 var v *Var
201 var v_used bool
202 if ident != nil {
203 if obj := check.lookup(ident.Name); obj != nil {
204
205
206
207 if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
208 v = w
209 v_used = check.usedVars[v]
210 }
211 }
212 }
213
214 var x operand
215 check.expr(nil, &x, lhs)
216
217 if v != nil {
218 check.usedVars[v] = v_used
219 }
220
221 if !x.isValid() || !isValid(x.typ()) {
222 return Typ[Invalid]
223 }
224
225
226
227 switch x.mode() {
228 case invalid:
229 return Typ[Invalid]
230 case variable, mapindex:
231
232 default:
233 if sel, ok := x.expr.(*ast.SelectorExpr); ok {
234 var op operand
235 check.expr(nil, &op, sel.X)
236 if op.mode() == mapindex {
237 check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(x.expr))
238 return Typ[Invalid]
239 }
240 }
241 check.errorf(&x, UnassignableOperand, "cannot assign to %s (neither addressable nor a map index expression)", x.expr)
242 return Typ[Invalid]
243 }
244
245 return x.typ()
246 }
247
248
249
250
251 func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand, context string) {
252 T := check.lhsVar(lhs)
253 if !isValid(T) {
254 if x != nil {
255 x.invalidate()
256 } else {
257 check.use(rhs)
258 }
259 return
260 }
261
262 if x == nil {
263 var target *target
264
265 if T != nil {
266 if _, ok := T.Underlying().(*Signature); ok {
267 target = newTarget(T, ExprString(lhs))
268 }
269 }
270 x = new(operand)
271 check.expr(target, x, rhs)
272 }
273
274 if T == nil && context == "assignment" {
275 context = "assignment to _ identifier"
276 }
277 check.assignment(x, T, context)
278 }
279
280
281 func operandTypes(list []*operand) (res []Type) {
282 for _, x := range list {
283 res = append(res, x.typ())
284 }
285 return res
286 }
287
288
289 func varTypes(list []*Var) (res []Type) {
290 for _, x := range list {
291 res = append(res, x.typ)
292 }
293 return res
294 }
295
296
297
298
299
300
301
302
303 func (check *Checker) typesSummary(list []Type, variadic, hasDots bool) string {
304 assert(!(variadic && hasDots))
305 var res []string
306 for i, t := range list {
307 var s string
308 switch {
309 case t == nil:
310 fallthrough
311 case !isValid(t):
312 s = "unknown type"
313 case isUntyped(t):
314 if isNumeric(t) {
315
316
317
318
319 s = "number"
320 } else {
321
322
323 s = strings.ReplaceAll(t.(*Basic).name, "untyped ", "")
324 }
325 default:
326 s = check.sprintf("%s", t)
327 }
328
329 if i == len(list)-1 {
330 switch {
331 case variadic:
332
333 if t, _ := t.(*Slice); t != nil {
334 s = check.sprintf("%s", t.elem)
335 }
336 s = "..." + s
337 case hasDots:
338 s += "..."
339 }
340 }
341 res = append(res, s)
342 }
343 return "(" + strings.Join(res, ", ") + ")"
344 }
345
346 func measure(x int, unit string) string {
347 if x != 1 {
348 unit += "s"
349 }
350 return fmt.Sprintf("%d %s", x, unit)
351 }
352
353 func (check *Checker) assignError(rhs []ast.Expr, l, r int) {
354 vars := measure(l, "variable")
355 vals := measure(r, "value")
356 rhs0 := rhs[0]
357
358 if len(rhs) == 1 {
359 if call, _ := ast.Unparen(rhs0).(*ast.CallExpr); call != nil {
360 check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals)
361 return
362 }
363 }
364 check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s", vars, vals)
365 }
366
367 func (check *Checker) returnError(at positioner, lhs []*Var, rhs []*operand) {
368 l, r := len(lhs), len(rhs)
369 qualifier := "not enough"
370 if r > l {
371 at = rhs[l]
372 qualifier = "too many"
373 } else if r > 0 {
374 at = rhs[r-1]
375 }
376 err := check.newError(WrongResultCount)
377 err.addf(at, "%s return values", qualifier)
378 err.addf(noposn, "have %s", check.typesSummary(operandTypes(rhs), false, false))
379 err.addf(noposn, "want %s", check.typesSummary(varTypes(lhs), false, false))
380 err.report()
381 }
382
383
384
385
386
387 func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.Stmt) {
388 l, r := len(lhs), len(orig_rhs)
389
390 context := "assignment"
391 if returnStmt != nil {
392 context = "return statement"
393 } else if l > 1 {
394 context = "multiple assignment"
395 }
396
397
398
399 isCall := false
400 if r == 1 {
401 _, isCall = ast.Unparen(orig_rhs[0]).(*ast.CallExpr)
402 }
403
404
405
406 if l == r && !isCall {
407 var x operand
408 for i, lhs := range lhs {
409 desc := lhs.name
410 if returnStmt != nil && desc == "" {
411 desc = "result variable"
412 }
413 check.expr(newTarget(lhs.typ, desc), &x, orig_rhs[i])
414 check.initVar(lhs, &x, context)
415 }
416 return
417 }
418
419
420
421 if r != 1 {
422
423 if check.use(orig_rhs...) {
424 if returnStmt != nil {
425 rhs := check.exprList(orig_rhs)
426 check.returnError(returnStmt, lhs, rhs)
427 } else {
428 check.assignError(orig_rhs, l, r)
429 }
430 }
431
432 for _, v := range lhs {
433 if v.typ == nil {
434 v.typ = Typ[Invalid]
435 }
436 }
437 return
438 }
439
440 rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2 && returnStmt == nil)
441 r = len(rhs)
442 if l == r {
443 for i, lhs := range lhs {
444 check.initVar(lhs, rhs[i], context)
445 }
446
447
448 if commaOk && rhs[0].mode() != invalid && rhs[1].mode() != invalid {
449 check.recordCommaOkTypes(orig_rhs[0], rhs)
450 }
451 return
452 }
453
454
455
456 if rhs[0].mode() != invalid {
457 if returnStmt != nil {
458 check.returnError(returnStmt, lhs, rhs)
459 } else {
460 check.assignError(orig_rhs, l, r)
461 }
462 }
463
464 for _, v := range lhs {
465 if v.typ == nil {
466 v.typ = Typ[Invalid]
467 }
468 }
469
470 }
471
472
473 func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) {
474 l, r := len(lhs), len(orig_rhs)
475
476 context := "assignment"
477 if l > 1 {
478 context = "multiple assignment"
479 }
480
481
482
483 isCall := false
484 if r == 1 {
485 _, isCall = ast.Unparen(orig_rhs[0]).(*ast.CallExpr)
486 }
487
488
489
490 if l == r && !isCall {
491 for i, lhs := range lhs {
492 check.assignVar(lhs, orig_rhs[i], nil, context)
493 }
494 return
495 }
496
497
498
499 if r != 1 {
500
501 okLHS := check.useLHS(lhs...)
502 okRHS := check.use(orig_rhs...)
503 if okLHS && okRHS {
504 check.assignError(orig_rhs, l, r)
505 }
506 return
507 }
508
509 rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2)
510 r = len(rhs)
511 if l == r {
512 for i, lhs := range lhs {
513 check.assignVar(lhs, nil, rhs[i], context)
514 }
515
516
517 if commaOk && rhs[0].mode() != invalid && rhs[1].mode() != invalid {
518 check.recordCommaOkTypes(orig_rhs[0], rhs)
519 }
520 return
521 }
522
523
524
525 if rhs[0].mode() != invalid {
526 check.assignError(orig_rhs, l, r)
527 }
528 check.useLHS(lhs...)
529
530 }
531
532 func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
533 top := len(check.delayed)
534 scope := check.scope
535
536
537 seen := make(map[string]bool, len(lhs))
538 lhsVars := make([]*Var, len(lhs))
539 newVars := make([]*Var, 0, len(lhs))
540 hasErr := false
541 for i, lhs := range lhs {
542 ident, _ := lhs.(*ast.Ident)
543 if ident == nil {
544 check.useLHS(lhs)
545
546 check.errorf(lhs, BadDecl, "non-name %s on left side of :=", lhs)
547 hasErr = true
548 continue
549 }
550
551 name := ident.Name
552 if name != "_" {
553 if seen[name] {
554 check.errorf(lhs, RepeatedDecl, "%s repeated on left side of :=", lhs)
555 hasErr = true
556 continue
557 }
558 seen[name] = true
559 }
560
561
562
563
564
565 if alt := scope.Lookup(name); alt != nil {
566 check.recordUse(ident, alt)
567
568 if obj, _ := alt.(*Var); obj != nil {
569 lhsVars[i] = obj
570 } else {
571 check.errorf(lhs, UnassignableOperand, "cannot assign to %s", lhs)
572 hasErr = true
573 }
574 continue
575 }
576
577
578 obj := newVar(LocalVar, ident.Pos(), check.pkg, name, nil)
579 lhsVars[i] = obj
580 if name != "_" {
581 newVars = append(newVars, obj)
582 }
583 check.recordDef(ident, obj)
584 }
585
586
587 for i, obj := range lhsVars {
588 if obj == nil {
589 lhsVars[i] = newVar(LocalVar, lhs[i].Pos(), check.pkg, "_", nil)
590 }
591 }
592
593 check.initVars(lhsVars, rhs, nil)
594
595
596 check.processDelayed(top)
597
598 if len(newVars) == 0 && !hasErr {
599 check.softErrorf(pos, NoNewVar, "no new variables on left side of :=")
600 return
601 }
602
603
604
605
606
607
608 scopePos := endPos(rhs[len(rhs)-1])
609 for _, obj := range newVars {
610 check.declare(scope, nil, obj, scopePos)
611 }
612 }
613
View as plain text