github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 "go/ast" 11 "go/token" 12 ) 13 14 // assignment reports whether x can be assigned to a variable of type T, 15 // if necessary by attempting to convert untyped values to the appropriate 16 // type. context describes the context in which the assignment takes place. 17 // Use T == nil to indicate assignment to an untyped blank identifier. 18 // x.mode is set to invalid if the assignment failed. 19 func (check *Checker) assignment(x *operand, T Type, context string) { 20 check.singleValue(x) 21 22 switch x.mode { 23 case invalid: 24 return // error reported before 25 case constant_, variable, mapindex, value, commaok: 26 // ok 27 default: 28 unreachable() 29 } 30 31 if isUntyped(x.typ) { 32 target := T 33 // spec: "If an untyped constant is assigned to a variable of interface 34 // type or the blank identifier, the constant is first converted to type 35 // bool, rune, int, float64, complex128 or string respectively, depending 36 // on whether the value is a boolean, rune, integer, floating-point, complex, 37 // or string constant." 38 if T == nil || IsInterface(T) { 39 if T == nil && x.typ == Typ[UntypedNil] { 40 check.errorf(x.pos(), "use of untyped nil in %s", context) 41 x.mode = invalid 42 return 43 } 44 target = Default(x.typ) 45 } 46 check.convertUntyped(x, target) 47 if x.mode == invalid { 48 return 49 } 50 } 51 // x.typ is typed 52 53 // spec: "If a left-hand side is the blank identifier, any typed or 54 // non-constant value except for the predeclared identifier nil may 55 // be assigned to it." 56 if T == nil { 57 return 58 } 59 60 if reason := ""; !x.assignableTo(check.conf, T, &reason) { 61 if reason != "" { 62 check.errorf(x.pos(), "cannot use %s as %s value in %s: %s", x, T, context, reason) 63 } else { 64 check.errorf(x.pos(), "cannot use %s as %s value in %s", x, T, context) 65 } 66 x.mode = invalid 67 } 68 } 69 70 func (check *Checker) initConst(lhs *Const, x *operand) { 71 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { 72 if lhs.typ == nil { 73 lhs.typ = Typ[Invalid] 74 } 75 return 76 } 77 78 // rhs must be a constant 79 if x.mode != constant_ { 80 check.errorf(x.pos(), "%s is not constant", x) 81 if lhs.typ == nil { 82 lhs.typ = Typ[Invalid] 83 } 84 return 85 } 86 assert(isConstType(x.typ)) 87 88 // If the lhs doesn't have a type yet, use the type of x. 89 if lhs.typ == nil { 90 lhs.typ = x.typ 91 } 92 93 check.assignment(x, lhs.typ, "constant declaration") 94 if x.mode == invalid { 95 return 96 } 97 98 lhs.val = x.val 99 } 100 101 func (check *Checker) initVar(lhs *Var, x *operand, context string) Type { 102 if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { 103 if lhs.typ == nil { 104 lhs.typ = Typ[Invalid] 105 } 106 return nil 107 } 108 109 // If the lhs doesn't have a type yet, use the type of x. 110 if lhs.typ == nil { 111 typ := x.typ 112 if isUntyped(typ) { 113 // convert untyped types to default types 114 if typ == Typ[UntypedNil] { 115 check.errorf(x.pos(), "use of untyped nil in %s", context) 116 lhs.typ = Typ[Invalid] 117 return nil 118 } 119 typ = Default(typ) 120 } 121 lhs.typ = typ 122 } 123 124 check.assignment(x, lhs.typ, context) 125 if x.mode == invalid { 126 return nil 127 } 128 129 return x.typ 130 } 131 132 func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type { 133 if x.mode == invalid || x.typ == Typ[Invalid] { 134 return nil 135 } 136 137 // Determine if the lhs is a (possibly parenthesized) identifier. 138 ident, _ := unparen(lhs).(*ast.Ident) 139 140 // Don't evaluate lhs if it is the blank identifier. 141 if ident != nil && ident.Name == "_" { 142 check.recordDef(ident, nil) 143 check.assignment(x, nil, "assignment to _ identifier") 144 if x.mode == invalid { 145 return nil 146 } 147 return x.typ 148 } 149 150 // If the lhs is an identifier denoting a variable v, this assignment 151 // is not a 'use' of v. Remember current value of v.used and restore 152 // after evaluating the lhs via check.expr. 153 var v *Var 154 var v_used bool 155 if ident != nil { 156 if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil { 157 // It's ok to mark non-local variables, but ignore variables 158 // from other packages to avoid potential race conditions with 159 // dot-imported variables. 160 if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg { 161 v = w 162 v_used = v.used 163 } 164 } 165 } 166 167 var z operand 168 check.expr(&z, lhs) 169 if v != nil { 170 v.used = v_used // restore v.used 171 } 172 173 if z.mode == invalid || z.typ == Typ[Invalid] { 174 return nil 175 } 176 177 // spec: "Each left-hand side operand must be addressable, a map index 178 // expression, or the blank identifier. Operands may be parenthesized." 179 switch z.mode { 180 case invalid: 181 return nil 182 case variable, mapindex: 183 // ok 184 default: 185 if sel, ok := z.expr.(*ast.SelectorExpr); ok { 186 var op operand 187 check.expr(&op, sel.X) 188 if op.mode == mapindex { 189 check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr)) 190 return nil 191 } 192 } 193 check.errorf(z.pos(), "cannot assign to %s", &z) 194 return nil 195 } 196 197 check.assignment(x, z.typ, "assignment") 198 if x.mode == invalid { 199 return nil 200 } 201 202 return x.typ 203 } 204 205 // If returnPos is valid, initVars is called to type-check the assignment of 206 // return expressions, and returnPos is the position of the return statement. 207 func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) { 208 l := len(lhs) 209 get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid()) 210 if get == nil || l != r { 211 // invalidate lhs and use rhs 212 for _, obj := range lhs { 213 if obj.typ == nil { 214 obj.typ = Typ[Invalid] 215 } 216 } 217 if get == nil { 218 return // error reported by unpack 219 } 220 check.useGetter(get, r) 221 if returnPos.IsValid() { 222 check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r) 223 return 224 } 225 check.errorf(rhs[0].Pos(), "cannot initialize %d variables with %d values", l, r) 226 return 227 } 228 229 context := "assignment" 230 if returnPos.IsValid() { 231 context = "return statement" 232 } 233 234 var x operand 235 if commaOk { 236 var a [2]Type 237 for i := range a { 238 get(&x, i) 239 a[i] = check.initVar(lhs[i], &x, context) 240 } 241 check.recordCommaOkTypes(rhs[0], a) 242 return 243 } 244 245 for i, lhs := range lhs { 246 get(&x, i) 247 check.initVar(lhs, &x, context) 248 } 249 } 250 251 func (check *Checker) assignVars(lhs, rhs []ast.Expr) { 252 l := len(lhs) 253 get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2) 254 if get == nil { 255 check.useLHS(lhs...) 256 return // error reported by unpack 257 } 258 if l != r { 259 check.useGetter(get, r) 260 check.errorf(rhs[0].Pos(), "cannot assign %d values to %d variables", r, l) 261 return 262 } 263 264 var x operand 265 if commaOk { 266 var a [2]Type 267 for i := range a { 268 get(&x, i) 269 a[i] = check.assignVar(lhs[i], &x) 270 } 271 check.recordCommaOkTypes(rhs[0], a) 272 return 273 } 274 275 for i, lhs := range lhs { 276 get(&x, i) 277 check.assignVar(lhs, &x) 278 } 279 } 280 281 func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) { 282 scope := check.scope 283 284 // collect lhs variables 285 var newVars []*Var 286 var lhsVars = make([]*Var, len(lhs)) 287 for i, lhs := range lhs { 288 var obj *Var 289 if ident, _ := lhs.(*ast.Ident); ident != nil { 290 // Use the correct obj if the ident is redeclared. The 291 // variable's scope starts after the declaration; so we 292 // must use Scope.Lookup here and call Scope.Insert 293 // (via check.declare) later. 294 name := ident.Name 295 if alt := scope.Lookup(name); alt != nil { 296 // redeclared object must be a variable 297 if alt, _ := alt.(*Var); alt != nil { 298 obj = alt 299 } else { 300 check.errorf(lhs.Pos(), "cannot assign to %s", lhs) 301 } 302 check.recordUse(ident, alt) 303 } else { 304 // declare new variable, possibly a blank (_) variable 305 obj = NewVar(ident.Pos(), check.pkg, name, nil) 306 if name != "_" { 307 newVars = append(newVars, obj) 308 } 309 check.recordDef(ident, obj) 310 } 311 } else { 312 check.errorf(lhs.Pos(), "cannot declare %s", lhs) 313 } 314 if obj == nil { 315 obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable 316 } 317 lhsVars[i] = obj 318 } 319 320 check.initVars(lhsVars, rhs, token.NoPos) 321 322 // declare new variables 323 if len(newVars) > 0 { 324 // spec: "The scope of a constant or variable identifier declared inside 325 // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl 326 // for short variable declarations) and ends at the end of the innermost 327 // containing block." 328 scopePos := rhs[len(rhs)-1].End() 329 for _, obj := range newVars { 330 check.declare(scope, nil, obj, scopePos) // recordObject already called 331 } 332 } else { 333 check.softErrorf(pos, "no new variables on left side of :=") 334 } 335 }