github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/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 "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 = defaultType(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 = defaultType(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 v, _ = obj.(*Var) 158 if v != nil { 159 v_used = v.used 160 } 161 } 162 } 163 164 var z operand 165 check.expr(&z, lhs) 166 if v != nil { 167 v.used = v_used // restore v.used 168 } 169 170 if z.mode == invalid || z.typ == Typ[Invalid] { 171 return nil 172 } 173 174 // spec: "Each left-hand side operand must be addressable, a map index 175 // expression, or the blank identifier. Operands may be parenthesized." 176 switch z.mode { 177 case invalid: 178 return nil 179 case variable, mapindex: 180 // ok 181 default: 182 if sel, ok := z.expr.(*ast.SelectorExpr); ok { 183 var op operand 184 check.expr(&op, sel.X) 185 if op.mode == mapindex { 186 check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr)) 187 return nil 188 } 189 } 190 check.errorf(z.pos(), "cannot assign to %s", &z) 191 return nil 192 } 193 194 check.assignment(x, z.typ, "assignment") 195 if x.mode == invalid { 196 return nil 197 } 198 199 return x.typ 200 } 201 202 // If returnPos is valid, initVars is called to type-check the assignment of 203 // return expressions, and returnPos is the position of the return statement. 204 func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) { 205 l := len(lhs) 206 get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid()) 207 if get == nil || l != r { 208 // invalidate lhs and use rhs 209 for _, obj := range lhs { 210 if obj.typ == nil { 211 obj.typ = Typ[Invalid] 212 } 213 } 214 if get == nil { 215 return // error reported by unpack 216 } 217 check.useGetter(get, r) 218 if returnPos.IsValid() { 219 check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r) 220 return 221 } 222 check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r) 223 return 224 } 225 226 context := "assignment" 227 if returnPos.IsValid() { 228 context = "return statement" 229 } 230 231 var x operand 232 if commaOk { 233 var a [2]Type 234 for i := range a { 235 get(&x, i) 236 a[i] = check.initVar(lhs[i], &x, context) 237 } 238 check.recordCommaOkTypes(rhs[0], a) 239 return 240 } 241 242 for i, lhs := range lhs { 243 get(&x, i) 244 check.initVar(lhs, &x, context) 245 } 246 } 247 248 func (check *Checker) assignVars(lhs, rhs []ast.Expr) { 249 l := len(lhs) 250 get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2) 251 if get == nil { 252 return // error reported by unpack 253 } 254 if l != r { 255 check.useGetter(get, r) 256 check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r) 257 return 258 } 259 260 var x operand 261 if commaOk { 262 var a [2]Type 263 for i := range a { 264 get(&x, i) 265 a[i] = check.assignVar(lhs[i], &x) 266 } 267 check.recordCommaOkTypes(rhs[0], a) 268 return 269 } 270 271 for i, lhs := range lhs { 272 get(&x, i) 273 check.assignVar(lhs, &x) 274 } 275 } 276 277 func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) { 278 scope := check.scope 279 280 // collect lhs variables 281 var newVars []*Var 282 var lhsVars = make([]*Var, len(lhs)) 283 for i, lhs := range lhs { 284 var obj *Var 285 if ident, _ := lhs.(*ast.Ident); ident != nil { 286 // Use the correct obj if the ident is redeclared. The 287 // variable's scope starts after the declaration; so we 288 // must use Scope.Lookup here and call Scope.Insert 289 // (via check.declare) later. 290 name := ident.Name 291 if alt := scope.Lookup(name); alt != nil { 292 // redeclared object must be a variable 293 if alt, _ := alt.(*Var); alt != nil { 294 obj = alt 295 } else { 296 check.errorf(lhs.Pos(), "cannot assign to %s", lhs) 297 } 298 check.recordUse(ident, alt) 299 } else { 300 // declare new variable, possibly a blank (_) variable 301 obj = NewVar(ident.Pos(), check.pkg, name, nil) 302 if name != "_" { 303 newVars = append(newVars, obj) 304 } 305 check.recordDef(ident, obj) 306 } 307 } else { 308 check.errorf(lhs.Pos(), "cannot declare %s", lhs) 309 } 310 if obj == nil { 311 obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable 312 } 313 lhsVars[i] = obj 314 } 315 316 check.initVars(lhsVars, rhs, token.NoPos) 317 318 // declare new variables 319 if len(newVars) > 0 { 320 // spec: "The scope of a constant or variable identifier declared inside 321 // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl 322 // for short variable declarations) and ends at the end of the innermost 323 // containing block." 324 scopePos := rhs[len(rhs)-1].End() 325 for _, obj := range newVars { 326 check.declare(scope, nil, obj, scopePos) // recordObject already called 327 } 328 } else { 329 check.softErrorf(pos, "no new variables on left side of :=") 330 } 331 }