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  }