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