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