Black Lives Matter. Support the Equal Justice Initiative.

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  	"errors"
    11  	"go/ast"
    12  	"go/token"
    13  )
    14  
    15  // assignment reports whether x can be assigned to a variable of type T,
    16  // if necessary by attempting to convert untyped values to the appropriate
    17  // type. context describes the context in which the assignment takes place.
    18  // Use T == nil to indicate assignment to an untyped blank identifier.
    19  // x.mode is set to invalid if the assignment failed.
    20  func (check *Checker) assignment(x *operand, T Type, context string) {
    21  	check.singleValue(x)
    22  
    23  	switch x.mode {
    24  	case invalid:
    25  		return // error reported before
    26  	case constant_, variable, mapindex, value, commaok, commaerr:
    27  		// ok
    28  	default:
    29  		unreachable()
    30  	}
    31  
    32  	if isUntyped(x.typ) {
    33  		target := T
    34  		// spec: "If an untyped constant is assigned to a variable of interface
    35  		// type or the blank identifier, the constant is first converted to type
    36  		// bool, rune, int, float64, complex128 or string respectively, depending
    37  		// on whether the value is a boolean, rune, integer, floating-point,
    38  		// complex, or string constant."
    39  		if T == nil || IsInterface(T) {
    40  			if T == nil && x.typ == Typ[UntypedNil] {
    41  				check.errorf(x, _UntypedNil, "use of untyped nil in %s", context)
    42  				x.mode = invalid
    43  				return
    44  			}
    45  			target = Default(x.typ)
    46  		}
    47  		if err := check.canConvertUntyped(x, target); err != nil {
    48  			msg := check.sprintf("cannot use %s as %s value in %s", x, target, context)
    49  			code := _IncompatibleAssign
    50  			var ierr Error
    51  			if errors.As(err, &ierr) {
    52  				// Preserve these inner errors, as they are informative.
    53  				switch ierr.go116code {
    54  				case _TruncatedFloat:
    55  					msg += " (truncated)"
    56  					code = ierr.go116code
    57  				case _NumericOverflow:
    58  					msg += " (overflows)"
    59  					code = ierr.go116code
    60  				}
    61  			}
    62  			check.error(x, code, msg)
    63  			x.mode = invalid
    64  			return
    65  		}
    66  	}
    67  	// x.typ is typed
    68  
    69  	// spec: "If a left-hand side is the blank identifier, any typed or
    70  	// non-constant value except for the predeclared identifier nil may
    71  	// be assigned to it."
    72  	if T == nil {
    73  		return
    74  	}
    75  
    76  	reason := ""
    77  	if ok, code := x.assignableTo(check, T, &reason); !ok {
    78  		if reason != "" {
    79  			check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, reason)
    80  		} else {
    81  			check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
    82  		}
    83  		x.mode = invalid
    84  	}
    85  }
    86  
    87  func (check *Checker) initConst(lhs *Const, x *operand) {
    88  	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
    89  		if lhs.typ == nil {
    90  			lhs.typ = Typ[Invalid]
    91  		}
    92  		return
    93  	}
    94  
    95  	// rhs must be a constant
    96  	if x.mode != constant_ {
    97  		check.errorf(x, _InvalidConstInit, "%s is not constant", x)
    98  		if lhs.typ == nil {
    99  			lhs.typ = Typ[Invalid]
   100  		}
   101  		return
   102  	}
   103  	assert(isConstType(x.typ))
   104  
   105  	// If the lhs doesn't have a type yet, use the type of x.
   106  	if lhs.typ == nil {
   107  		lhs.typ = x.typ
   108  	}
   109  
   110  	check.assignment(x, lhs.typ, "constant declaration")
   111  	if x.mode == invalid {
   112  		return
   113  	}
   114  
   115  	lhs.val = x.val
   116  }
   117  
   118  func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
   119  	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
   120  		if lhs.typ == nil {
   121  			lhs.typ = Typ[Invalid]
   122  		}
   123  		return nil
   124  	}
   125  
   126  	// If the lhs doesn't have a type yet, use the type of x.
   127  	if lhs.typ == nil {
   128  		typ := x.typ
   129  		if isUntyped(typ) {
   130  			// convert untyped types to default types
   131  			if typ == Typ[UntypedNil] {
   132  				check.errorf(x, _UntypedNil, "use of untyped nil in %s", context)
   133  				lhs.typ = Typ[Invalid]
   134  				return nil
   135  			}
   136  			typ = Default(typ)
   137  		}
   138  		lhs.typ = typ
   139  	}
   140  
   141  	check.assignment(x, lhs.typ, context)
   142  	if x.mode == invalid {
   143  		return nil
   144  	}
   145  
   146  	return x.typ
   147  }
   148  
   149  func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
   150  	if x.mode == invalid || x.typ == Typ[Invalid] {
   151  		return nil
   152  	}
   153  
   154  	// Determine if the lhs is a (possibly parenthesized) identifier.
   155  	ident, _ := unparen(lhs).(*ast.Ident)
   156  
   157  	// Don't evaluate lhs if it is the blank identifier.
   158  	if ident != nil && ident.Name == "_" {
   159  		check.recordDef(ident, nil)
   160  		check.assignment(x, nil, "assignment to _ identifier")
   161  		if x.mode == invalid {
   162  			return nil
   163  		}
   164  		return x.typ
   165  	}
   166  
   167  	// If the lhs is an identifier denoting a variable v, this assignment
   168  	// is not a 'use' of v. Remember current value of v.used and restore
   169  	// after evaluating the lhs via check.expr.
   170  	var v *Var
   171  	var v_used bool
   172  	if ident != nil {
   173  		if obj := check.lookup(ident.Name); obj != nil {
   174  			// It's ok to mark non-local variables, but ignore variables
   175  			// from other packages to avoid potential race conditions with
   176  			// dot-imported variables.
   177  			if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
   178  				v = w
   179  				v_used = v.used
   180  			}
   181  		}
   182  	}
   183  
   184  	var z operand
   185  	check.expr(&z, lhs)
   186  	if v != nil {
   187  		v.used = v_used // restore v.used
   188  	}
   189  
   190  	if z.mode == invalid || z.typ == Typ[Invalid] {
   191  		return nil
   192  	}
   193  
   194  	// spec: "Each left-hand side operand must be addressable, a map index
   195  	// expression, or the blank identifier. Operands may be parenthesized."
   196  	switch z.mode {
   197  	case invalid:
   198  		return nil
   199  	case variable, mapindex:
   200  		// ok
   201  	default:
   202  		if sel, ok := z.expr.(*ast.SelectorExpr); ok {
   203  			var op operand
   204  			check.expr(&op, sel.X)
   205  			if op.mode == mapindex {
   206  				check.errorf(&z, _UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(z.expr))
   207  				return nil
   208  			}
   209  		}
   210  		check.errorf(&z, _UnassignableOperand, "cannot assign to %s", &z)
   211  		return nil
   212  	}
   213  
   214  	check.assignment(x, z.typ, "assignment")
   215  	if x.mode == invalid {
   216  		return nil
   217  	}
   218  
   219  	return x.typ
   220  }
   221  
   222  // If returnPos is valid, initVars is called to type-check the assignment of
   223  // return expressions, and returnPos is the position of the return statement.
   224  func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
   225  	l := len(lhs)
   226  	get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
   227  	if get == nil || l != r {
   228  		// invalidate lhs and use rhs
   229  		for _, obj := range lhs {
   230  			if obj.typ == nil {
   231  				obj.typ = Typ[Invalid]
   232  			}
   233  		}
   234  		if get == nil {
   235  			return // error reported by unpack
   236  		}
   237  		check.useGetter(get, r)
   238  		if returnPos.IsValid() {
   239  			check.errorf(atPos(returnPos), _WrongResultCount, "wrong number of return values (want %d, got %d)", l, r)
   240  			return
   241  		}
   242  		check.errorf(rhs[0], _WrongAssignCount, "cannot initialize %d variables with %d values", l, r)
   243  		return
   244  	}
   245  
   246  	context := "assignment"
   247  	if returnPos.IsValid() {
   248  		context = "return statement"
   249  	}
   250  
   251  	var x operand
   252  	if commaOk {
   253  		var a [2]Type
   254  		for i := range a {
   255  			get(&x, i)
   256  			a[i] = check.initVar(lhs[i], &x, context)
   257  		}
   258  		check.recordCommaOkTypes(rhs[0], a)
   259  		return
   260  	}
   261  
   262  	for i, lhs := range lhs {
   263  		get(&x, i)
   264  		check.initVar(lhs, &x, context)
   265  	}
   266  }
   267  
   268  func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
   269  	l := len(lhs)
   270  	get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
   271  	if get == nil {
   272  		check.useLHS(lhs...)
   273  		return // error reported by unpack
   274  	}
   275  	if l != r {
   276  		check.useGetter(get, r)
   277  		check.errorf(rhs[0], _WrongAssignCount, "cannot assign %d values to %d variables", r, l)
   278  		return
   279  	}
   280  
   281  	var x operand
   282  	if commaOk {
   283  		var a [2]Type
   284  		for i := range a {
   285  			get(&x, i)
   286  			a[i] = check.assignVar(lhs[i], &x)
   287  		}
   288  		check.recordCommaOkTypes(rhs[0], a)
   289  		return
   290  	}
   291  
   292  	for i, lhs := range lhs {
   293  		get(&x, i)
   294  		check.assignVar(lhs, &x)
   295  	}
   296  }
   297  
   298  func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
   299  	top := len(check.delayed)
   300  	scope := check.scope
   301  
   302  	// collect lhs variables
   303  	var newVars []*Var
   304  	var lhsVars = make([]*Var, len(lhs))
   305  	for i, lhs := range lhs {
   306  		var obj *Var
   307  		if ident, _ := lhs.(*ast.Ident); ident != nil {
   308  			// Use the correct obj if the ident is redeclared. The
   309  			// variable's scope starts after the declaration; so we
   310  			// must use Scope.Lookup here and call Scope.Insert
   311  			// (via check.declare) later.
   312  			name := ident.Name
   313  			if alt := scope.Lookup(name); alt != nil {
   314  				// redeclared object must be a variable
   315  				if alt, _ := alt.(*Var); alt != nil {
   316  					obj = alt
   317  				} else {
   318  					check.errorf(lhs, _UnassignableOperand, "cannot assign to %s", lhs)
   319  				}
   320  				check.recordUse(ident, alt)
   321  			} else {
   322  				// declare new variable, possibly a blank (_) variable
   323  				obj = NewVar(ident.Pos(), check.pkg, name, nil)
   324  				if name != "_" {
   325  					newVars = append(newVars, obj)
   326  				}
   327  				check.recordDef(ident, obj)
   328  			}
   329  		} else {
   330  			check.useLHS(lhs)
   331  			check.invalidAST(lhs, "cannot declare %s", lhs)
   332  		}
   333  		if obj == nil {
   334  			obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
   335  		}
   336  		lhsVars[i] = obj
   337  	}
   338  
   339  	check.initVars(lhsVars, rhs, token.NoPos)
   340  
   341  	// process function literals in rhs expressions before scope changes
   342  	check.processDelayed(top)
   343  
   344  	// declare new variables
   345  	if len(newVars) > 0 {
   346  		// spec: "The scope of a constant or variable identifier declared inside
   347  		// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
   348  		// for short variable declarations) and ends at the end of the innermost
   349  		// containing block."
   350  		scopePos := rhs[len(rhs)-1].End()
   351  		for _, obj := range newVars {
   352  			check.declare(scope, nil, obj, scopePos) // recordObject already called
   353  		}
   354  	} else {
   355  		check.softErrorf(pos, _NoNewVar, "no new variables on left side of :=")
   356  	}
   357  }
   358  

View as plain text