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

View as plain text