1 // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
2 // Source: ../../cmd/compile/internal/types2/assignments.go
3 4 // Copyright 2013 The Go Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file.
7 8 // This file implements initialization and assignment checks.
9 10 package types
11 12 import (
13 "fmt"
14 "go/ast"
15 . "internal/types/errors"
16 "strings"
17 )
18 19 // assignment reports whether x can be assigned to a variable of type T,
20 // if necessary by attempting to convert untyped values to the appropriate
21 // type. context describes the context in which the assignment takes place.
22 // Use T == nil to indicate assignment to an untyped blank identifier.
23 // If the assignment check fails, x.mode is set to invalid.
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 // error reported before
30 case nilvalue:
31 assert(isTypes2)
32 // ok
33 case constant_, variable, mapindex, value, commaok, commaerr:
34 // ok
35 default:
36 // we may get here because of other problems (go.dev/issue/39634, crash 12)
37 // TODO(gri) do we need a new "generic" error code here?
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 // spec: "If an untyped constant is assigned to a variable of interface
46 // type or the blank identifier, the constant is first converted to type
47 // bool, rune, int, float64, complex128 or string respectively, depending
48 // on whether the value is a boolean, rune, integer, floating-point,
49 // complex, or string constant."
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 { // go/types
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 // x.typ is typed
95 96 // A generic (non-instantiated) function value cannot be assigned to a variable.
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 // spec: "If a left-hand side is the blank identifier, any typed or
104 // non-constant value except for the predeclared identifier nil may
105 // be assigned to it."
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 // rhs must be a constant
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 // If the lhs doesn't have a type yet, use the type of x.
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 // initVar checks the initialization lhs = x in a variable declaration.
153 // If lhs doesn't have a type yet, it is given the type of x,
154 // or Typ[Invalid] in case of an error.
155 // If the initialization check fails, x.mode is set to invalid.
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 // If lhs doesn't have a type yet, use the type of x.
166 if lhs.typ == nil {
167 typ := x.typ
168 if isUntyped(typ) {
169 // convert untyped types to default types
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 // lhsVar checks a lhs variable in an assignment and returns its type.
185 // lhsVar takes care of not counting a lhs identifier as a "use" of
186 // that identifier. The result is nil if it is the blank identifier,
187 // and Typ[Invalid] if it is an invalid lhs expression.
188 func (check *Checker) lhsVar(lhs ast.Expr) Type {
189 // Determine if the lhs is a (possibly parenthesized) identifier.
190 ident, _ := ast.Unparen(lhs).(*ast.Ident)
191 192 // Don't evaluate lhs if it is the blank identifier.
193 if ident != nil && ident.Name == "_" {
194 check.recordDef(ident, nil)
195 return nil
196 }
197 198 // If the lhs is an identifier denoting a variable v, this reference
199 // is not a 'use' of v. Remember current value of v.used and restore
200 // after evaluating the lhs via check.expr.
201 var v *Var
202 var v_used bool
203 if ident != nil {
204 if obj := check.lookup(ident.Name); obj != nil {
205 // It's ok to mark non-local variables, but ignore variables
206 // from other packages to avoid potential race conditions with
207 // dot-imported variables.
208 if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
209 v = w
210 v_used = check.usedVars[v]
211 }
212 }
213 }
214 215 var x operand
216 check.expr(nil, &x, lhs)
217 218 if v != nil {
219 check.usedVars[v] = v_used // restore v.used
220 }
221 222 if x.mode == invalid || !isValid(x.typ) {
223 return Typ[Invalid]
224 }
225 226 // spec: "Each left-hand side operand must be addressable, a map index
227 // expression, or the blank identifier. Operands may be parenthesized."
228 switch x.mode {
229 case invalid:
230 return Typ[Invalid]
231 case variable, mapindex:
232 // ok
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 // assignVar checks the assignment lhs = rhs (if x == nil), or lhs = x (if x != nil).
250 // If x != nil, it must be the evaluation of rhs (and rhs will be ignored).
251 // If the assignment check fails and x != nil, x.mode is set to invalid.
252 func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand, context string) {
253 T := check.lhsVar(lhs) // nil if lhs is _
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 // avoid calling ExprString if not needed
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 // operandTypes returns the list of types for the given operands.
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 // varTypes returns the list of types for the given variables.
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 // typesSummary returns a string of the form "(t1, t2, ...)" where the
298 // ti's are user-friendly string representations for the given types.
299 // If variadic is set and the last type is a slice, its string is of
300 // the form "...E" where E is the slice's element type.
301 // If hasDots is set, the last argument string is of the form "T..."
302 // where T is the last type.
303 // Only one of variadic and hasDots may be set.
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 // should not happen but be cautious
312 case !isValid(t):
313 s = "unknown type"
314 case isUntyped(t): // => *Basic
315 if isNumeric(t) {
316 // Do not imply a specific type requirement:
317 // "have number, want float64" is better than
318 // "have untyped int, want float64" or
319 // "have int, want float64".
320 s = "number"
321 } else {
322 // If we don't have a number, omit the "untyped" qualifier
323 // for compactness.
324 s = strings.ReplaceAll(t.(*Basic).name, "untyped ", "")
325 }
326 default:
327 s = check.sprintf("%s", t)
328 }
329 // handle ... parameters/arguments
330 if i == len(list)-1 {
331 switch {
332 case variadic:
333 // In correct code, the parameter type is a slice, but be careful.
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] // report at first extra value
373 qualifier = "too many"
374 } else if r > 0 {
375 at = rhs[r-1] // report at last value
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 // initVars type-checks assignments of initialization expressions orig_rhs
385 // to variables lhs.
386 // If returnStmt is non-nil, initVars type-checks the implicit assignment
387 // of result expressions orig_rhs to function result parameters lhs.
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 // If l == 1 and the rhs is a single call, for a better
397 // error message don't handle it as n:n mapping below.
398 isCall := false
399 if r == 1 {
400 _, isCall = ast.Unparen(orig_rhs[0]).(*ast.CallExpr)
401 }
402 403 // If we have a n:n mapping from lhs variable to rhs expression,
404 // each value can be assigned to its corresponding variable.
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 // If we don't have an n:n mapping, the rhs must be a single expression
419 // resulting in 2 or more values; otherwise we have an assignment mismatch.
420 if r != 1 {
421 // Only report a mismatch error if there are no other errors on the rhs.
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 // ensure that LHS variables have a type
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 // Only record comma-ok expression if both initializations succeeded
446 // (go.dev/issue/59371).
447 if commaOk && rhs[0].mode != invalid && rhs[1].mode != invalid {
448 check.recordCommaOkTypes(orig_rhs[0], rhs)
449 }
450 return
451 }
452 453 // In all other cases we have an assignment mismatch.
454 // Only report a mismatch error if there are no other errors on the rhs.
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 // ensure that LHS variables have a type
463 for _, v := range lhs {
464 if v.typ == nil {
465 v.typ = Typ[Invalid]
466 }
467 }
468 // orig_rhs[0] was already evaluated
469 }
470 471 // assignVars type-checks assignments of expressions orig_rhs to variables lhs.
472 func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) {
473 l, r := len(lhs), len(orig_rhs)
474 475 // If l == 1 and the rhs is a single call, for a better
476 // error message don't handle it as n:n mapping below.
477 isCall := false
478 if r == 1 {
479 _, isCall = ast.Unparen(orig_rhs[0]).(*ast.CallExpr)
480 }
481 482 // If we have a n:n mapping from lhs variable to rhs expression,
483 // each value can be assigned to its corresponding variable.
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 // If we don't have an n:n mapping, the rhs must be a single expression
492 // resulting in 2 or more values; otherwise we have an assignment mismatch.
493 if r != 1 {
494 // Only report a mismatch error if there are no other errors on the lhs or rhs.
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 // Only record comma-ok expression if both assignments succeeded
510 // (go.dev/issue/59371).
511 if commaOk && rhs[0].mode != invalid && rhs[1].mode != invalid {
512 check.recordCommaOkTypes(orig_rhs[0], rhs)
513 }
514 return
515 }
516 517 // In all other cases we have an assignment mismatch.
518 // Only report a mismatch error if there are no other errors on the rhs.
519 if rhs[0].mode != invalid {
520 check.assignError(orig_rhs, l, r)
521 }
522 check.useLHS(lhs...)
523 // orig_rhs[0] was already evaluated
524 }
525 526 func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
527 top := len(check.delayed)
528 scope := check.scope
529 530 // collect lhs variables
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 // TODO(gri) This is redundant with a go/parser error. Consider omitting in go/types?
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 // Use the correct obj if the ident is redeclared. The
556 // variable's scope starts after the declaration; so we
557 // must use Scope.Lookup here and call Scope.Insert
558 // (via check.declare) later.
559 if alt := scope.Lookup(name); alt != nil {
560 check.recordUse(ident, alt)
561 // redeclared object must be a variable
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 // declare new variable
572 obj := newVar(LocalVar, 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 // create dummy variables where the lhs is invalid
581 for i, obj := range lhsVars {
582 if obj == nil {
583 lhsVars[i] = newVar(LocalVar, lhs[i].Pos(), check.pkg, "_", nil)
584 }
585 }
586 587 check.initVars(lhsVars, rhs, nil)
588 589 // process function literals in rhs expressions before scope changes
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 // declare new variables
598 // spec: "The scope of a constant or variable identifier declared inside
599 // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
600 // for short variable declarations) and ends at the end of the innermost
601 // containing block."
602 scopePos := endPos(rhs[len(rhs)-1])
603 for _, obj := range newVars {
604 check.declare(scope, nil, obj, scopePos) // id = nil: recordDef already called
605 }
606 }
607