github.com/AndrienkoAleksandr/go@v0.0.19/src/go/types/assignments.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file implements initialization and assignment checks. 6 7 package types 8 9 import ( 10 "fmt" 11 "go/ast" 12 . "internal/types/errors" 13 "strings" 14 ) 15 16 // assignment reports whether x can be assigned to a variable of type T, 17 // if necessary by attempting to convert untyped values to the appropriate 18 // type. context describes the context in which the assignment takes place. 19 // Use T == nil to indicate assignment to an untyped blank identifier. 20 // If the assignment check fails, x.mode is set to invalid. 21 func (check *Checker) assignment(x *operand, T Type, context string) { 22 check.singleValue(x) 23 24 switch x.mode { 25 case invalid: 26 return // error reported before 27 case constant_, variable, mapindex, value, commaok, commaerr: 28 // ok 29 default: 30 // we may get here because of other problems (go.dev/issue/39634, crash 12) 31 // TODO(gri) do we need a new "generic" error code here? 32 check.errorf(x, IncompatibleAssign, "cannot assign %s to %s in %s", x, T, context) 33 x.mode = invalid 34 return 35 } 36 37 if isUntyped(x.typ) { 38 target := T 39 // spec: "If an untyped constant is assigned to a variable of interface 40 // type or the blank identifier, the constant is first converted to type 41 // bool, rune, int, float64, complex128 or string respectively, depending 42 // on whether the value is a boolean, rune, integer, floating-point, 43 // complex, or string constant." 44 if T == nil || isNonTypeParamInterface(T) { 45 if T == nil && x.typ == Typ[UntypedNil] { 46 check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context) 47 x.mode = invalid 48 return 49 } 50 target = Default(x.typ) 51 } 52 newType, val, code := check.implicitTypeAndValue(x, target) 53 if code != 0 { 54 msg := check.sprintf("cannot use %s as %s value in %s", x, target, context) 55 switch code { 56 case TruncatedFloat: 57 msg += " (truncated)" 58 case NumericOverflow: 59 msg += " (overflows)" 60 default: 61 code = IncompatibleAssign 62 } 63 check.error(x, code, msg) 64 x.mode = invalid 65 return 66 } 67 if val != nil { 68 x.val = val 69 check.updateExprVal(x.expr, val) 70 } 71 if newType != x.typ { 72 x.typ = newType 73 check.updateExprType(x.expr, newType, false) 74 } 75 } 76 // x.typ is typed 77 78 // A generic (non-instantiated) function value cannot be assigned to a variable. 79 if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 { 80 check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context) 81 x.mode = invalid 82 return 83 } 84 85 // spec: "If a left-hand side is the blank identifier, any typed or 86 // non-constant value except for the predeclared identifier nil may 87 // be assigned to it." 88 if T == nil { 89 return 90 } 91 92 cause := "" 93 if ok, code := x.assignableTo(check, T, &cause); !ok { 94 if cause != "" { 95 check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, cause) 96 } else { 97 check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context) 98 } 99 x.mode = invalid 100 } 101 } 102 103 func (check *Checker) initConst(lhs *Const, x *operand) { 104 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { 105 if lhs.typ == nil { 106 lhs.typ = Typ[Invalid] 107 } 108 return 109 } 110 111 // rhs must be a constant 112 if x.mode != constant_ { 113 check.errorf(x, InvalidConstInit, "%s is not constant", x) 114 if lhs.typ == nil { 115 lhs.typ = Typ[Invalid] 116 } 117 return 118 } 119 assert(isConstType(x.typ)) 120 121 // If the lhs doesn't have a type yet, use the type of x. 122 if lhs.typ == nil { 123 lhs.typ = x.typ 124 } 125 126 check.assignment(x, lhs.typ, "constant declaration") 127 if x.mode == invalid { 128 return 129 } 130 131 lhs.val = x.val 132 } 133 134 // initVar checks the initialization lhs = x in a variable declaration. 135 // If lhs doesn't have a type yet, it is given the type of x, 136 // or Typ[Invalid] in case of an error. 137 // If the initialization check fails, x.mode is set to invalid. 138 func (check *Checker) initVar(lhs *Var, x *operand, context string) { 139 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { 140 if lhs.typ == nil { 141 lhs.typ = Typ[Invalid] 142 } 143 x.mode = invalid 144 return 145 } 146 147 // If lhs doesn't have a type yet, use the type of x. 148 if lhs.typ == nil { 149 typ := x.typ 150 if isUntyped(typ) { 151 // convert untyped types to default types 152 if typ == Typ[UntypedNil] { 153 check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context) 154 lhs.typ = Typ[Invalid] 155 x.mode = invalid 156 return 157 } 158 typ = Default(typ) 159 } 160 lhs.typ = typ 161 } 162 163 check.assignment(x, lhs.typ, context) 164 } 165 166 // lhsVar checks a lhs variable in an assignment and returns its type. 167 // lhsVar takes care of not counting a lhs identifier as a "use" of 168 // that identifier. The result is nil if it is the blank identifier, 169 // and Typ[Invalid] if it is an invalid lhs expression. 170 func (check *Checker) lhsVar(lhs ast.Expr) Type { 171 // Determine if the lhs is a (possibly parenthesized) identifier. 172 ident, _ := unparen(lhs).(*ast.Ident) 173 174 // Don't evaluate lhs if it is the blank identifier. 175 if ident != nil && ident.Name == "_" { 176 check.recordDef(ident, nil) 177 return nil 178 } 179 180 // If the lhs is an identifier denoting a variable v, this reference 181 // is not a 'use' of v. Remember current value of v.used and restore 182 // after evaluating the lhs via check.expr. 183 var v *Var 184 var v_used bool 185 if ident != nil { 186 if obj := check.lookup(ident.Name); obj != nil { 187 // It's ok to mark non-local variables, but ignore variables 188 // from other packages to avoid potential race conditions with 189 // dot-imported variables. 190 if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg { 191 v = w 192 v_used = v.used 193 } 194 } 195 } 196 197 var x operand 198 check.expr(nil, &x, lhs) 199 200 if v != nil { 201 v.used = v_used // restore v.used 202 } 203 204 if x.mode == invalid || x.typ == Typ[Invalid] { 205 return Typ[Invalid] 206 } 207 208 // spec: "Each left-hand side operand must be addressable, a map index 209 // expression, or the blank identifier. Operands may be parenthesized." 210 switch x.mode { 211 case invalid: 212 return Typ[Invalid] 213 case variable, mapindex: 214 // ok 215 default: 216 if sel, ok := x.expr.(*ast.SelectorExpr); ok { 217 var op operand 218 check.expr(nil, &op, sel.X) 219 if op.mode == mapindex { 220 check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(x.expr)) 221 return Typ[Invalid] 222 } 223 } 224 check.errorf(&x, UnassignableOperand, "cannot assign to %s (neither addressable nor a map index expression)", x.expr) 225 return Typ[Invalid] 226 } 227 228 return x.typ 229 } 230 231 // assignVar checks the assignment lhs = rhs (if x == nil), or lhs = x (if x != nil). 232 // If x != nil, it must be the evaluation of rhs (and rhs will be ignored). 233 // If the assignment check fails and x != nil, x.mode is set to invalid. 234 func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand) { 235 T := check.lhsVar(lhs) // nil if lhs is _ 236 if T == Typ[Invalid] { 237 if x != nil { 238 x.mode = invalid 239 } else { 240 check.use(rhs) 241 } 242 return 243 } 244 245 if x == nil { 246 x = new(operand) 247 check.expr(T, x, rhs) 248 } 249 250 context := "assignment" 251 if T == nil { 252 context = "assignment to _ identifier" 253 } 254 check.assignment(x, T, context) 255 } 256 257 // operandTypes returns the list of types for the given operands. 258 func operandTypes(list []*operand) (res []Type) { 259 for _, x := range list { 260 res = append(res, x.typ) 261 } 262 return res 263 } 264 265 // varTypes returns the list of types for the given variables. 266 func varTypes(list []*Var) (res []Type) { 267 for _, x := range list { 268 res = append(res, x.typ) 269 } 270 return res 271 } 272 273 // typesSummary returns a string of the form "(t1, t2, ...)" where the 274 // ti's are user-friendly string representations for the given types. 275 // If variadic is set and the last type is a slice, its string is of 276 // the form "...E" where E is the slice's element type. 277 func (check *Checker) typesSummary(list []Type, variadic bool) string { 278 var res []string 279 for i, t := range list { 280 var s string 281 switch { 282 case t == nil: 283 fallthrough // should not happen but be cautious 284 case t == Typ[Invalid]: 285 s = "unknown type" 286 case isUntyped(t): 287 if isNumeric(t) { 288 // Do not imply a specific type requirement: 289 // "have number, want float64" is better than 290 // "have untyped int, want float64" or 291 // "have int, want float64". 292 s = "number" 293 } else { 294 // If we don't have a number, omit the "untyped" qualifier 295 // for compactness. 296 s = strings.Replace(t.(*Basic).name, "untyped ", "", -1) 297 } 298 case variadic && i == len(list)-1: 299 s = check.sprintf("...%s", t.(*Slice).elem) 300 } 301 if s == "" { 302 s = check.sprintf("%s", t) 303 } 304 res = append(res, s) 305 } 306 return "(" + strings.Join(res, ", ") + ")" 307 } 308 309 func measure(x int, unit string) string { 310 if x != 1 { 311 unit += "s" 312 } 313 return fmt.Sprintf("%d %s", x, unit) 314 } 315 316 func (check *Checker) assignError(rhs []ast.Expr, l, r int) { 317 vars := measure(l, "variable") 318 vals := measure(r, "value") 319 rhs0 := rhs[0] 320 321 if len(rhs) == 1 { 322 if call, _ := unparen(rhs0).(*ast.CallExpr); call != nil { 323 check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals) 324 return 325 } 326 } 327 check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s", vars, vals) 328 } 329 330 func (check *Checker) returnError(at positioner, lhs []*Var, rhs []*operand) { 331 l, r := len(lhs), len(rhs) 332 qualifier := "not enough" 333 if r > l { 334 at = rhs[l] // report at first extra value 335 qualifier = "too many" 336 } else if r > 0 { 337 at = rhs[r-1] // report at last value 338 } 339 var err error_ 340 err.code = WrongResultCount 341 err.errorf(at.Pos(), "%s return values", qualifier) 342 err.errorf(nopos, "have %s", check.typesSummary(operandTypes(rhs), false)) 343 err.errorf(nopos, "want %s", check.typesSummary(varTypes(lhs), false)) 344 check.report(&err) 345 } 346 347 // initVars type-checks assignments of initialization expressions orig_rhs 348 // to variables lhs. 349 // If returnStmt is non-nil, initVars type-checks the implicit assignment 350 // of result expressions orig_rhs to function result parameters lhs. 351 func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.Stmt) { 352 context := "assignment" 353 if returnStmt != nil { 354 context = "return statement" 355 } 356 357 l, r := len(lhs), len(orig_rhs) 358 359 // If l == 1 and the rhs is a single call, for a better 360 // error message don't handle it as n:n mapping below. 361 isCall := false 362 if r == 1 { 363 _, isCall = unparen(orig_rhs[0]).(*ast.CallExpr) 364 } 365 366 // If we have a n:n mapping from lhs variable to rhs expression, 367 // each value can be assigned to its corresponding variable. 368 if l == r && !isCall { 369 var x operand 370 for i, lhs := range lhs { 371 check.expr(lhs.typ, &x, orig_rhs[i]) 372 check.initVar(lhs, &x, context) 373 } 374 return 375 } 376 377 // If we don't have an n:n mapping, the rhs must be a single expression 378 // resulting in 2 or more values; otherwise we have an assignment mismatch. 379 if r != 1 { 380 // Only report a mismatch error if there are no other errors on the rhs. 381 if check.use(orig_rhs...) { 382 if returnStmt != nil { 383 rhs := check.exprList(orig_rhs) 384 check.returnError(returnStmt, lhs, rhs) 385 } else { 386 check.assignError(orig_rhs, l, r) 387 } 388 } 389 // ensure that LHS variables have a type 390 for _, v := range lhs { 391 if v.typ == nil { 392 v.typ = Typ[Invalid] 393 } 394 } 395 return 396 } 397 398 rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2 && returnStmt == nil) 399 r = len(rhs) 400 if l == r { 401 for i, lhs := range lhs { 402 check.initVar(lhs, rhs[i], context) 403 } 404 // Only record comma-ok expression if both initializations succeeded 405 // (go.dev/issue/59371). 406 if commaOk && rhs[0].mode != invalid && rhs[1].mode != invalid { 407 check.recordCommaOkTypes(orig_rhs[0], rhs) 408 } 409 return 410 } 411 412 // In all other cases we have an assignment mismatch. 413 // Only report a mismatch error if there are no other errors on the rhs. 414 if rhs[0].mode != invalid { 415 if returnStmt != nil { 416 check.returnError(returnStmt, lhs, rhs) 417 } else { 418 check.assignError(orig_rhs, l, r) 419 } 420 } 421 // ensure that LHS variables have a type 422 for _, v := range lhs { 423 if v.typ == nil { 424 v.typ = Typ[Invalid] 425 } 426 } 427 // orig_rhs[0] was already evaluated 428 } 429 430 // assignVars type-checks assignments of expressions orig_rhs to variables lhs. 431 func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) { 432 l, r := len(lhs), len(orig_rhs) 433 434 // If l == 1 and the rhs is a single call, for a better 435 // error message don't handle it as n:n mapping below. 436 isCall := false 437 if r == 1 { 438 _, isCall = unparen(orig_rhs[0]).(*ast.CallExpr) 439 } 440 441 // If we have a n:n mapping from lhs variable to rhs expression, 442 // each value can be assigned to its corresponding variable. 443 if l == r && !isCall { 444 for i, lhs := range lhs { 445 check.assignVar(lhs, orig_rhs[i], nil) 446 } 447 return 448 } 449 450 // If we don't have an n:n mapping, the rhs must be a single expression 451 // resulting in 2 or more values; otherwise we have an assignment mismatch. 452 if r != 1 { 453 // Only report a mismatch error if there are no other errors on the lhs or rhs. 454 okLHS := check.useLHS(lhs...) 455 okRHS := check.use(orig_rhs...) 456 if okLHS && okRHS { 457 check.assignError(orig_rhs, l, r) 458 } 459 return 460 } 461 462 rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2) 463 r = len(rhs) 464 if l == r { 465 for i, lhs := range lhs { 466 check.assignVar(lhs, nil, rhs[i]) 467 } 468 // Only record comma-ok expression if both assignments succeeded 469 // (go.dev/issue/59371). 470 if commaOk && rhs[0].mode != invalid && rhs[1].mode != invalid { 471 check.recordCommaOkTypes(orig_rhs[0], rhs) 472 } 473 return 474 } 475 476 // In all other cases we have an assignment mismatch. 477 // Only report a mismatch error if there are no other errors on the rhs. 478 if rhs[0].mode != invalid { 479 check.assignError(orig_rhs, l, r) 480 } 481 check.useLHS(lhs...) 482 // orig_rhs[0] was already evaluated 483 } 484 485 func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) { 486 top := len(check.delayed) 487 scope := check.scope 488 489 // collect lhs variables 490 seen := make(map[string]bool, len(lhs)) 491 lhsVars := make([]*Var, len(lhs)) 492 newVars := make([]*Var, 0, len(lhs)) 493 hasErr := false 494 for i, lhs := range lhs { 495 ident, _ := lhs.(*ast.Ident) 496 if ident == nil { 497 check.useLHS(lhs) 498 // TODO(rFindley) this is redundant with a parser error. Consider omitting? 499 check.errorf(lhs, BadDecl, "non-name %s on left side of :=", lhs) 500 hasErr = true 501 continue 502 } 503 504 name := ident.Name 505 if name != "_" { 506 if seen[name] { 507 check.errorf(lhs, RepeatedDecl, "%s repeated on left side of :=", lhs) 508 hasErr = true 509 continue 510 } 511 seen[name] = true 512 } 513 514 // Use the correct obj if the ident is redeclared. The 515 // variable's scope starts after the declaration; so we 516 // must use Scope.Lookup here and call Scope.Insert 517 // (via check.declare) later. 518 if alt := scope.Lookup(name); alt != nil { 519 check.recordUse(ident, alt) 520 // redeclared object must be a variable 521 if obj, _ := alt.(*Var); obj != nil { 522 lhsVars[i] = obj 523 } else { 524 check.errorf(lhs, UnassignableOperand, "cannot assign to %s", lhs) 525 hasErr = true 526 } 527 continue 528 } 529 530 // declare new variable 531 obj := NewVar(ident.Pos(), check.pkg, name, nil) 532 lhsVars[i] = obj 533 if name != "_" { 534 newVars = append(newVars, obj) 535 } 536 check.recordDef(ident, obj) 537 } 538 539 // create dummy variables where the lhs is invalid 540 for i, obj := range lhsVars { 541 if obj == nil { 542 lhsVars[i] = NewVar(lhs[i].Pos(), check.pkg, "_", nil) 543 } 544 } 545 546 check.initVars(lhsVars, rhs, nil) 547 548 // process function literals in rhs expressions before scope changes 549 check.processDelayed(top) 550 551 if len(newVars) == 0 && !hasErr { 552 check.softErrorf(pos, NoNewVar, "no new variables on left side of :=") 553 return 554 } 555 556 // declare new variables 557 // spec: "The scope of a constant or variable identifier declared inside 558 // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl 559 // for short variable declarations) and ends at the end of the innermost 560 // containing block." 561 scopePos := rhs[len(rhs)-1].End() 562 for _, obj := range newVars { 563 check.declare(scope, nil, obj, scopePos) // id = nil: recordDef already called 564 } 565 }