...

Source file src/go/types/assignments.go

     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, 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.lookup(ident.Name); 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		top := len(check.delayed)
   283		scope := check.scope
   284	
   285		// collect lhs variables
   286		var newVars []*Var
   287		var lhsVars = make([]*Var, len(lhs))
   288		for i, lhs := range lhs {
   289			var obj *Var
   290			if ident, _ := lhs.(*ast.Ident); ident != nil {
   291				// Use the correct obj if the ident is redeclared. The
   292				// variable's scope starts after the declaration; so we
   293				// must use Scope.Lookup here and call Scope.Insert
   294				// (via check.declare) later.
   295				name := ident.Name
   296				if alt := scope.Lookup(name); alt != nil {
   297					// redeclared object must be a variable
   298					if alt, _ := alt.(*Var); alt != nil {
   299						obj = alt
   300					} else {
   301						check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
   302					}
   303					check.recordUse(ident, alt)
   304				} else {
   305					// declare new variable, possibly a blank (_) variable
   306					obj = NewVar(ident.Pos(), check.pkg, name, nil)
   307					if name != "_" {
   308						newVars = append(newVars, obj)
   309					}
   310					check.recordDef(ident, obj)
   311				}
   312			} else {
   313				check.useLHS(lhs)
   314				check.errorf(lhs.Pos(), "cannot declare %s", lhs)
   315			}
   316			if obj == nil {
   317				obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
   318			}
   319			lhsVars[i] = obj
   320		}
   321	
   322		check.initVars(lhsVars, rhs, token.NoPos)
   323	
   324		// process function literals in rhs expressions before scope changes
   325		check.processDelayed(top)
   326	
   327		// declare new variables
   328		if len(newVars) > 0 {
   329			// spec: "The scope of a constant or variable identifier declared inside
   330			// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
   331			// for short variable declarations) and ends at the end of the innermost
   332			// containing block."
   333			scopePos := rhs[len(rhs)-1].End()
   334			for _, obj := range newVars {
   335				check.declare(scope, nil, obj, scopePos) // recordObject already called
   336			}
   337		} else {
   338			check.softErrorf(pos, "no new variables on left side of :=")
   339		}
   340	}
   341	

View as plain text