...
Run Format

Source file src/go/types/assignments.go

Documentation: go/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.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