github.com/bir3/gocompiler@v0.3.205/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 "github.com/bir3/gocompiler/src/go/ast" 12 "github.com/bir3/gocompiler/src/go/token" 13 . "github.com/bir3/gocompiler/src/internal/types/errors" 14 "strings" 15 ) 16 17 // assignment reports whether x can be assigned to a variable of type T, 18 // if necessary by attempting to convert untyped values to the appropriate 19 // type. context describes the context in which the assignment takes place. 20 // Use T == nil to indicate assignment to an untyped blank identifier. 21 // x.mode is set to invalid if the assignment failed. 22 func (check *Checker) assignment(x *operand, T Type, context string) { 23 check.singleValue(x) 24 25 switch x.mode { 26 case invalid: 27 return // error reported before 28 case constant_, variable, mapindex, value, commaok, commaerr: 29 // ok 30 default: 31 // we may get here because of other problems (issue #39634, crash 12) 32 // TODO(gri) do we need a new "generic" error code here? 33 check.errorf(x, IncompatibleAssign, "cannot assign %s to %s in %s", x, T, context) 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 77 // A generic (non-instantiated) function value cannot be assigned to a variable. 78 if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 { 79 check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context) 80 } 81 82 // spec: "If a left-hand side is the blank identifier, any typed or 83 // non-constant value except for the predeclared identifier nil may 84 // be assigned to it." 85 if T == nil { 86 return 87 } 88 89 cause := "" 90 if ok, code := x.assignableTo(check, T, &cause); !ok { 91 if cause != "" { 92 check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, cause) 93 } else { 94 check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context) 95 } 96 x.mode = invalid 97 } 98 } 99 100 func (check *Checker) initConst(lhs *Const, x *operand) { 101 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { 102 if lhs.typ == nil { 103 lhs.typ = Typ[Invalid] 104 } 105 return 106 } 107 108 // rhs must be a constant 109 if x.mode != constant_ { 110 check.errorf(x, InvalidConstInit, "%s is not constant", x) 111 if lhs.typ == nil { 112 lhs.typ = Typ[Invalid] 113 } 114 return 115 } 116 assert(isConstType(x.typ)) 117 118 // If the lhs doesn't have a type yet, use the type of x. 119 if lhs.typ == nil { 120 lhs.typ = x.typ 121 } 122 123 check.assignment(x, lhs.typ, "constant declaration") 124 if x.mode == invalid { 125 return 126 } 127 128 lhs.val = x.val 129 } 130 131 func (check *Checker) initVar(lhs *Var, x *operand, context string) Type { 132 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { 133 if lhs.typ == nil { 134 lhs.typ = Typ[Invalid] 135 } 136 return nil 137 } 138 139 // If the lhs doesn't have a type yet, use the type of x. 140 if lhs.typ == nil { 141 typ := x.typ 142 if isUntyped(typ) { 143 // convert untyped types to default types 144 if typ == Typ[UntypedNil] { 145 check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context) 146 lhs.typ = Typ[Invalid] 147 return nil 148 } 149 typ = Default(typ) 150 } 151 lhs.typ = typ 152 } 153 154 check.assignment(x, lhs.typ, context) 155 if x.mode == invalid { 156 return nil 157 } 158 159 return x.typ 160 } 161 162 func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type { 163 if x.mode == invalid || x.typ == Typ[Invalid] { 164 check.useLHS(lhs) 165 return nil 166 } 167 168 // Determine if the lhs is a (possibly parenthesized) identifier. 169 ident, _ := unparen(lhs).(*ast.Ident) 170 171 // Don't evaluate lhs if it is the blank identifier. 172 if ident != nil && ident.Name == "_" { 173 check.recordDef(ident, nil) 174 check.assignment(x, nil, "assignment to _ identifier") 175 if x.mode == invalid { 176 return nil 177 } 178 return x.typ 179 } 180 181 // If the lhs is an identifier denoting a variable v, this assignment 182 // is not a 'use' of v. Remember current value of v.used and restore 183 // after evaluating the lhs via check.expr. 184 var v *Var 185 var v_used bool 186 if ident != nil { 187 if obj := check.lookup(ident.Name); obj != nil { 188 // It's ok to mark non-local variables, but ignore variables 189 // from other packages to avoid potential race conditions with 190 // dot-imported variables. 191 if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg { 192 v = w 193 v_used = v.used 194 } 195 } 196 } 197 198 var z operand 199 check.expr(&z, lhs) 200 if v != nil { 201 v.used = v_used // restore v.used 202 } 203 204 if z.mode == invalid || z.typ == Typ[Invalid] { 205 return nil 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 z.mode { 211 case invalid: 212 return nil 213 case variable, mapindex: 214 // ok 215 default: 216 if sel, ok := z.expr.(*ast.SelectorExpr); ok { 217 var op operand 218 check.expr(&op, sel.X) 219 if op.mode == mapindex { 220 check.errorf(&z, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(z.expr)) 221 return nil 222 } 223 } 224 check.errorf(&z, UnassignableOperand, "cannot assign to %s", &z) 225 return nil 226 } 227 228 check.assignment(x, z.typ, "assignment") 229 if x.mode == invalid { 230 return nil 231 } 232 233 return x.typ 234 } 235 236 // operandTypes returns the list of types for the given operands. 237 func operandTypes(list []*operand) (res []Type) { 238 for _, x := range list { 239 res = append(res, x.typ) 240 } 241 return res 242 } 243 244 // varTypes returns the list of types for the given variables. 245 func varTypes(list []*Var) (res []Type) { 246 for _, x := range list { 247 res = append(res, x.typ) 248 } 249 return res 250 } 251 252 // typesSummary returns a string of the form "(t1, t2, ...)" where the 253 // ti's are user-friendly string representations for the given types. 254 // If variadic is set and the last type is a slice, its string is of 255 // the form "...E" where E is the slice's element type. 256 func (check *Checker) typesSummary(list []Type, variadic bool) string { 257 var res []string 258 for i, t := range list { 259 var s string 260 switch { 261 case t == nil: 262 fallthrough // should not happen but be cautious 263 case t == Typ[Invalid]: 264 s = "<T>" 265 case isUntyped(t): 266 if isNumeric(t) { 267 // Do not imply a specific type requirement: 268 // "have number, want float64" is better than 269 // "have untyped int, want float64" or 270 // "have int, want float64". 271 s = "number" 272 } else { 273 // If we don't have a number, omit the "untyped" qualifier 274 // for compactness. 275 s = strings.Replace(t.(*Basic).name, "untyped ", "", -1) 276 } 277 case variadic && i == len(list)-1: 278 s = check.sprintf("...%s", t.(*Slice).elem) 279 } 280 if s == "" { 281 s = check.sprintf("%s", t) 282 } 283 res = append(res, s) 284 } 285 return "(" + strings.Join(res, ", ") + ")" 286 } 287 288 func measure(x int, unit string) string { 289 if x != 1 { 290 unit += "s" 291 } 292 return fmt.Sprintf("%d %s", x, unit) 293 } 294 295 func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) { 296 vars := measure(nvars, "variable") 297 vals := measure(nvals, "value") 298 rhs0 := rhs[0] 299 300 if len(rhs) == 1 { 301 if call, _ := unparen(rhs0).(*ast.CallExpr); call != nil { 302 check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals) 303 return 304 } 305 } 306 check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s", vars, vals) 307 } 308 309 // If returnStmt != nil, initVars is called to type-check the assignment 310 // of return expressions, and returnStmt is the return statement. 311 func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnStmt ast.Stmt) { 312 rhs, commaOk := check.exprList(origRHS, len(lhs) == 2 && returnStmt == nil) 313 314 if len(lhs) != len(rhs) { 315 // invalidate lhs 316 for _, obj := range lhs { 317 obj.used = true // avoid declared and not used errors 318 if obj.typ == nil { 319 obj.typ = Typ[Invalid] 320 } 321 } 322 // don't report an error if we already reported one 323 for _, x := range rhs { 324 if x.mode == invalid { 325 return 326 } 327 } 328 if returnStmt != nil { 329 var at positioner = returnStmt 330 qualifier := "not enough" 331 if len(rhs) > len(lhs) { 332 at = rhs[len(lhs)].expr // report at first extra value 333 qualifier = "too many" 334 } else if len(rhs) > 0 { 335 at = rhs[len(rhs)-1].expr // report at last value 336 } 337 err := newErrorf(at, WrongResultCount, "%s return values", qualifier) 338 err.errorf(token.NoPos, "have %s", check.typesSummary(operandTypes(rhs), false)) 339 err.errorf(token.NoPos, "want %s", check.typesSummary(varTypes(lhs), false)) 340 check.report(err) 341 return 342 } 343 check.assignError(origRHS, len(lhs), len(rhs)) 344 return 345 } 346 347 context := "assignment" 348 if returnStmt != nil { 349 context = "return statement" 350 } 351 352 if commaOk { 353 var a [2]Type 354 for i := range a { 355 a[i] = check.initVar(lhs[i], rhs[i], context) 356 } 357 check.recordCommaOkTypes(origRHS[0], a) 358 return 359 } 360 361 for i, lhs := range lhs { 362 check.initVar(lhs, rhs[i], context) 363 } 364 } 365 366 func (check *Checker) assignVars(lhs, origRHS []ast.Expr) { 367 rhs, commaOk := check.exprList(origRHS, len(lhs) == 2) 368 369 if len(lhs) != len(rhs) { 370 check.useLHS(lhs...) 371 // don't report an error if we already reported one 372 for _, x := range rhs { 373 if x.mode == invalid { 374 return 375 } 376 } 377 check.assignError(origRHS, len(lhs), len(rhs)) 378 return 379 } 380 381 if commaOk { 382 var a [2]Type 383 for i := range a { 384 a[i] = check.assignVar(lhs[i], rhs[i]) 385 } 386 check.recordCommaOkTypes(origRHS[0], a) 387 return 388 } 389 390 for i, lhs := range lhs { 391 check.assignVar(lhs, rhs[i]) 392 } 393 } 394 395 func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) { 396 top := len(check.delayed) 397 scope := check.scope 398 399 // collect lhs variables 400 seen := make(map[string]bool, len(lhs)) 401 lhsVars := make([]*Var, len(lhs)) 402 newVars := make([]*Var, 0, len(lhs)) 403 hasErr := false 404 for i, lhs := range lhs { 405 ident, _ := lhs.(*ast.Ident) 406 if ident == nil { 407 check.useLHS(lhs) 408 // TODO(rFindley) this is redundant with a parser error. Consider omitting? 409 check.errorf(lhs, BadDecl, "non-name %s on left side of :=", lhs) 410 hasErr = true 411 continue 412 } 413 414 name := ident.Name 415 if name != "_" { 416 if seen[name] { 417 check.errorf(lhs, RepeatedDecl, "%s repeated on left side of :=", lhs) 418 hasErr = true 419 continue 420 } 421 seen[name] = true 422 } 423 424 // Use the correct obj if the ident is redeclared. The 425 // variable's scope starts after the declaration; so we 426 // must use Scope.Lookup here and call Scope.Insert 427 // (via check.declare) later. 428 if alt := scope.Lookup(name); alt != nil { 429 check.recordUse(ident, alt) 430 // redeclared object must be a variable 431 if obj, _ := alt.(*Var); obj != nil { 432 lhsVars[i] = obj 433 } else { 434 check.errorf(lhs, UnassignableOperand, "cannot assign to %s", lhs) 435 hasErr = true 436 } 437 continue 438 } 439 440 // declare new variable 441 obj := NewVar(ident.Pos(), check.pkg, name, nil) 442 lhsVars[i] = obj 443 if name != "_" { 444 newVars = append(newVars, obj) 445 } 446 check.recordDef(ident, obj) 447 } 448 449 // create dummy variables where the lhs is invalid 450 for i, obj := range lhsVars { 451 if obj == nil { 452 lhsVars[i] = NewVar(lhs[i].Pos(), check.pkg, "_", nil) 453 } 454 } 455 456 check.initVars(lhsVars, rhs, nil) 457 458 // process function literals in rhs expressions before scope changes 459 check.processDelayed(top) 460 461 if len(newVars) == 0 && !hasErr { 462 check.softErrorf(pos, NoNewVar, "no new variables on left side of :=") 463 return 464 } 465 466 // declare new variables 467 // spec: "The scope of a constant or variable identifier declared inside 468 // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl 469 // for short variable declarations) and ends at the end of the innermost 470 // containing block." 471 scopePos := rhs[len(rhs)-1].End() 472 for _, obj := range newVars { 473 check.declare(scope, nil, obj, scopePos) // id = nil: recordDef already called 474 } 475 }