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