Home | History | Annotate | Download | only in types
      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 }
    336