Source file src/cmd/compile/internal/types2/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 types2
     8  
     9  import (
    10  	"cmd/compile/internal/syntax"
    11  	"fmt"
    12  	. "internal/types/errors"
    13  	"strings"
    14  )
    15  
    16  // assignment reports whether x can be assigned to a variable of type T,
    17  // if necessary by attempting to convert untyped values to the appropriate
    18  // type. context describes the context in which the assignment takes place.
    19  // Use T == nil to indicate assignment to an untyped blank identifier.
    20  // If the assignment check fails, x.mode is set to invalid.
    21  func (check *Checker) assignment(x *operand, T Type, context string) {
    22  	check.singleValue(x)
    23  
    24  	switch x.mode {
    25  	case invalid:
    26  		return // error reported before
    27  	case constant_, variable, mapindex, value, nilvalue, commaok, commaerr:
    28  		// ok
    29  	default:
    30  		// we may get here because of other problems (go.dev/issue/39634, crash 12)
    31  		// TODO(gri) do we need a new "generic" error code here?
    32  		check.errorf(x, IncompatibleAssign, "cannot assign %s to %s in %s", x, T, context)
    33  		x.mode = invalid
    34  		return
    35  	}
    36  
    37  	if isUntyped(x.typ) {
    38  		target := T
    39  		// spec: "If an untyped constant is assigned to a variable of interface
    40  		// type or the blank identifier, the constant is first converted to type
    41  		// bool, rune, int, float64, complex128 or string respectively, depending
    42  		// on whether the value is a boolean, rune, integer, floating-point,
    43  		// complex, or string constant."
    44  		if x.isNil() {
    45  			if T == nil {
    46  				check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
    47  				x.mode = invalid
    48  				return
    49  			}
    50  		} else if T == nil || isNonTypeParamInterface(T) {
    51  			target = Default(x.typ)
    52  		}
    53  		newType, val, code := check.implicitTypeAndValue(x, target)
    54  		if code != 0 {
    55  			msg := check.sprintf("cannot use %s as %s value in %s", x, target, context)
    56  			switch code {
    57  			case TruncatedFloat:
    58  				msg += " (truncated)"
    59  			case NumericOverflow:
    60  				msg += " (overflows)"
    61  			default:
    62  				code = IncompatibleAssign
    63  			}
    64  			check.error(x, code, msg)
    65  			x.mode = invalid
    66  			return
    67  		}
    68  		if val != nil {
    69  			x.val = val
    70  			check.updateExprVal(x.expr, val)
    71  		}
    72  		if newType != x.typ {
    73  			x.typ = newType
    74  			check.updateExprType(x.expr, newType, false)
    75  		}
    76  	}
    77  	// x.typ is typed
    78  
    79  	// A generic (non-instantiated) function value cannot be assigned to a variable.
    80  	if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
    81  		check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
    82  		x.mode = invalid
    83  		return
    84  	}
    85  
    86  	// spec: "If a left-hand side is the blank identifier, any typed or
    87  	// non-constant value except for the predeclared identifier nil may
    88  	// be assigned to it."
    89  	if T == nil {
    90  		return
    91  	}
    92  
    93  	cause := ""
    94  	if ok, code := x.assignableTo(check, T, &cause); !ok {
    95  		if cause != "" {
    96  			check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, cause)
    97  		} else {
    98  			check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
    99  		}
   100  		x.mode = invalid
   101  	}
   102  }
   103  
   104  func (check *Checker) initConst(lhs *Const, x *operand) {
   105  	if x.mode == invalid || !isValid(x.typ) || !isValid(lhs.typ) {
   106  		if lhs.typ == nil {
   107  			lhs.typ = Typ[Invalid]
   108  		}
   109  		return
   110  	}
   111  
   112  	// rhs must be a constant
   113  	if x.mode != constant_ {
   114  		check.errorf(x, InvalidConstInit, "%s is not constant", x)
   115  		if lhs.typ == nil {
   116  			lhs.typ = Typ[Invalid]
   117  		}
   118  		return
   119  	}
   120  	assert(isConstType(x.typ))
   121  
   122  	// If the lhs doesn't have a type yet, use the type of x.
   123  	if lhs.typ == nil {
   124  		lhs.typ = x.typ
   125  	}
   126  
   127  	check.assignment(x, lhs.typ, "constant declaration")
   128  	if x.mode == invalid {
   129  		return
   130  	}
   131  
   132  	lhs.val = x.val
   133  }
   134  
   135  // initVar checks the initialization lhs = x in a variable declaration.
   136  // If lhs doesn't have a type yet, it is given the type of x,
   137  // or Typ[Invalid] in case of an error.
   138  // If the initialization check fails, x.mode is set to invalid.
   139  func (check *Checker) initVar(lhs *Var, x *operand, context string) {
   140  	if x.mode == invalid || !isValid(x.typ) || !isValid(lhs.typ) {
   141  		if lhs.typ == nil {
   142  			lhs.typ = Typ[Invalid]
   143  		}
   144  		x.mode = invalid
   145  		return
   146  	}
   147  
   148  	// If lhs doesn't have a type yet, use the type of x.
   149  	if lhs.typ == nil {
   150  		typ := x.typ
   151  		if isUntyped(typ) {
   152  			// convert untyped types to default types
   153  			if typ == Typ[UntypedNil] {
   154  				check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
   155  				lhs.typ = Typ[Invalid]
   156  				x.mode = invalid
   157  				return
   158  			}
   159  			typ = Default(typ)
   160  		}
   161  		lhs.typ = typ
   162  	}
   163  
   164  	check.assignment(x, lhs.typ, context)
   165  }
   166  
   167  // lhsVar checks a lhs variable in an assignment and returns its type.
   168  // lhsVar takes care of not counting a lhs identifier as a "use" of
   169  // that identifier. The result is nil if it is the blank identifier,
   170  // and Typ[Invalid] if it is an invalid lhs expression.
   171  func (check *Checker) lhsVar(lhs syntax.Expr) Type {
   172  	// Determine if the lhs is a (possibly parenthesized) identifier.
   173  	ident, _ := syntax.Unparen(lhs).(*syntax.Name)
   174  
   175  	// Don't evaluate lhs if it is the blank identifier.
   176  	if ident != nil && ident.Value == "_" {
   177  		check.recordDef(ident, nil)
   178  		return nil
   179  	}
   180  
   181  	// If the lhs is an identifier denoting a variable v, this reference
   182  	// is not a 'use' of v. Remember current value of v.used and restore
   183  	// after evaluating the lhs via check.expr.
   184  	var v *Var
   185  	var v_used bool
   186  	if ident != nil {
   187  		if obj := check.lookup(ident.Value); obj != nil {
   188  			// It's ok to mark non-local variables, but ignore variables
   189  			// from other packages to avoid potential race conditions with
   190  			// dot-imported variables.
   191  			if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
   192  				v = w
   193  				v_used = v.used
   194  			}
   195  		}
   196  	}
   197  
   198  	var x operand
   199  	check.expr(nil, &x, lhs)
   200  
   201  	if v != nil {
   202  		v.used = v_used // restore v.used
   203  	}
   204  
   205  	if x.mode == invalid || !isValid(x.typ) {
   206  		return Typ[Invalid]
   207  	}
   208  
   209  	// spec: "Each left-hand side operand must be addressable, a map index
   210  	// expression, or the blank identifier. Operands may be parenthesized."
   211  	switch x.mode {
   212  	case invalid:
   213  		return Typ[Invalid]
   214  	case variable, mapindex:
   215  		// ok
   216  	default:
   217  		if sel, ok := x.expr.(*syntax.SelectorExpr); ok {
   218  			var op operand
   219  			check.expr(nil, &op, sel.X)
   220  			if op.mode == mapindex {
   221  				check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", syntax.String(x.expr))
   222  				return Typ[Invalid]
   223  			}
   224  		}
   225  		check.errorf(&x, UnassignableOperand, "cannot assign to %s (neither addressable nor a map index expression)", x.expr)
   226  		return Typ[Invalid]
   227  	}
   228  
   229  	return x.typ
   230  }
   231  
   232  // assignVar checks the assignment lhs = rhs (if x == nil), or lhs = x (if x != nil).
   233  // If x != nil, it must be the evaluation of rhs (and rhs will be ignored).
   234  // If the assignment check fails and x != nil, x.mode is set to invalid.
   235  func (check *Checker) assignVar(lhs, rhs syntax.Expr, x *operand, context string) {
   236  	T := check.lhsVar(lhs) // nil if lhs is _
   237  	if !isValid(T) {
   238  		if x != nil {
   239  			x.mode = invalid
   240  		} else {
   241  			check.use(rhs)
   242  		}
   243  		return
   244  	}
   245  
   246  	if x == nil {
   247  		var target *target
   248  		// avoid calling syntax.String if not needed
   249  		if T != nil {
   250  			if _, ok := under(T).(*Signature); ok {
   251  				target = newTarget(T, syntax.String(lhs))
   252  			}
   253  		}
   254  		x = new(operand)
   255  		check.expr(target, x, rhs)
   256  	}
   257  
   258  	if T == nil && context == "assignment" {
   259  		context = "assignment to _ identifier"
   260  	}
   261  	check.assignment(x, T, context)
   262  }
   263  
   264  // operandTypes returns the list of types for the given operands.
   265  func operandTypes(list []*operand) (res []Type) {
   266  	for _, x := range list {
   267  		res = append(res, x.typ)
   268  	}
   269  	return res
   270  }
   271  
   272  // varTypes returns the list of types for the given variables.
   273  func varTypes(list []*Var) (res []Type) {
   274  	for _, x := range list {
   275  		res = append(res, x.typ)
   276  	}
   277  	return res
   278  }
   279  
   280  // typesSummary returns a string of the form "(t1, t2, ...)" where the
   281  // ti's are user-friendly string representations for the given types.
   282  // If variadic is set and the last type is a slice, its string is of
   283  // the form "...E" where E is the slice's element type.
   284  func (check *Checker) typesSummary(list []Type, variadic bool) string {
   285  	var res []string
   286  	for i, t := range list {
   287  		var s string
   288  		switch {
   289  		case t == nil:
   290  			fallthrough // should not happen but be cautious
   291  		case !isValid(t):
   292  			s = "unknown type"
   293  		case isUntyped(t):
   294  			if isNumeric(t) {
   295  				// Do not imply a specific type requirement:
   296  				// "have number, want float64" is better than
   297  				// "have untyped int, want float64" or
   298  				// "have int, want float64".
   299  				s = "number"
   300  			} else {
   301  				// If we don't have a number, omit the "untyped" qualifier
   302  				// for compactness.
   303  				s = strings.Replace(t.(*Basic).name, "untyped ", "", -1)
   304  			}
   305  		case variadic && i == len(list)-1:
   306  			s = check.sprintf("...%s", t.(*Slice).elem)
   307  		}
   308  		if s == "" {
   309  			s = check.sprintf("%s", t)
   310  		}
   311  		res = append(res, s)
   312  	}
   313  	return "(" + strings.Join(res, ", ") + ")"
   314  }
   315  
   316  func measure(x int, unit string) string {
   317  	if x != 1 {
   318  		unit += "s"
   319  	}
   320  	return fmt.Sprintf("%d %s", x, unit)
   321  }
   322  
   323  func (check *Checker) assignError(rhs []syntax.Expr, l, r int) {
   324  	vars := measure(l, "variable")
   325  	vals := measure(r, "value")
   326  	rhs0 := rhs[0]
   327  
   328  	if len(rhs) == 1 {
   329  		if call, _ := syntax.Unparen(rhs0).(*syntax.CallExpr); call != nil {
   330  			check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals)
   331  			return
   332  		}
   333  	}
   334  	check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s", vars, vals)
   335  }
   336  
   337  func (check *Checker) returnError(at poser, lhs []*Var, rhs []*operand) {
   338  	l, r := len(lhs), len(rhs)
   339  	qualifier := "not enough"
   340  	if r > l {
   341  		at = rhs[l] // report at first extra value
   342  		qualifier = "too many"
   343  	} else if r > 0 {
   344  		at = rhs[r-1] // report at last value
   345  	}
   346  	var err error_
   347  	err.code = WrongResultCount
   348  	err.errorf(at, "%s return values", qualifier)
   349  	err.errorf(nopos, "have %s", check.typesSummary(operandTypes(rhs), false))
   350  	err.errorf(nopos, "want %s", check.typesSummary(varTypes(lhs), false))
   351  	check.report(&err)
   352  }
   353  
   354  // initVars type-checks assignments of initialization expressions orig_rhs
   355  // to variables lhs.
   356  // If returnStmt is non-nil, initVars type-checks the implicit assignment
   357  // of result expressions orig_rhs to function result parameters lhs.
   358  func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt syntax.Stmt) {
   359  	context := "assignment"
   360  	if returnStmt != nil {
   361  		context = "return statement"
   362  	}
   363  
   364  	l, r := len(lhs), len(orig_rhs)
   365  
   366  	// If l == 1 and the rhs is a single call, for a better
   367  	// error message don't handle it as n:n mapping below.
   368  	isCall := false
   369  	if r == 1 {
   370  		_, isCall = syntax.Unparen(orig_rhs[0]).(*syntax.CallExpr)
   371  	}
   372  
   373  	// If we have a n:n mapping from lhs variable to rhs expression,
   374  	// each value can be assigned to its corresponding variable.
   375  	if l == r && !isCall {
   376  		var x operand
   377  		for i, lhs := range lhs {
   378  			desc := lhs.name
   379  			if returnStmt != nil && desc == "" {
   380  				desc = "result variable"
   381  			}
   382  			check.expr(newTarget(lhs.typ, desc), &x, orig_rhs[i])
   383  			check.initVar(lhs, &x, context)
   384  		}
   385  		return
   386  	}
   387  
   388  	// If we don't have an n:n mapping, the rhs must be a single expression
   389  	// resulting in 2 or more values; otherwise we have an assignment mismatch.
   390  	if r != 1 {
   391  		// Only report a mismatch error if there are no other errors on the rhs.
   392  		if check.use(orig_rhs...) {
   393  			if returnStmt != nil {
   394  				rhs := check.exprList(orig_rhs)
   395  				check.returnError(returnStmt, lhs, rhs)
   396  			} else {
   397  				check.assignError(orig_rhs, l, r)
   398  			}
   399  		}
   400  		// ensure that LHS variables have a type
   401  		for _, v := range lhs {
   402  			if v.typ == nil {
   403  				v.typ = Typ[Invalid]
   404  			}
   405  		}
   406  		return
   407  	}
   408  
   409  	rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2 && returnStmt == nil)
   410  	r = len(rhs)
   411  	if l == r {
   412  		for i, lhs := range lhs {
   413  			check.initVar(lhs, rhs[i], context)
   414  		}
   415  		// Only record comma-ok expression if both initializations succeeded
   416  		// (go.dev/issue/59371).
   417  		if commaOk && rhs[0].mode != invalid && rhs[1].mode != invalid {
   418  			check.recordCommaOkTypes(orig_rhs[0], rhs)
   419  		}
   420  		return
   421  	}
   422  
   423  	// In all other cases we have an assignment mismatch.
   424  	// Only report a mismatch error if there are no other errors on the rhs.
   425  	if rhs[0].mode != invalid {
   426  		if returnStmt != nil {
   427  			check.returnError(returnStmt, lhs, rhs)
   428  		} else {
   429  			check.assignError(orig_rhs, l, r)
   430  		}
   431  	}
   432  	// ensure that LHS variables have a type
   433  	for _, v := range lhs {
   434  		if v.typ == nil {
   435  			v.typ = Typ[Invalid]
   436  		}
   437  	}
   438  	// orig_rhs[0] was already evaluated
   439  }
   440  
   441  // assignVars type-checks assignments of expressions orig_rhs to variables lhs.
   442  func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
   443  	l, r := len(lhs), len(orig_rhs)
   444  
   445  	// If l == 1 and the rhs is a single call, for a better
   446  	// error message don't handle it as n:n mapping below.
   447  	isCall := false
   448  	if r == 1 {
   449  		_, isCall = syntax.Unparen(orig_rhs[0]).(*syntax.CallExpr)
   450  	}
   451  
   452  	// If we have a n:n mapping from lhs variable to rhs expression,
   453  	// each value can be assigned to its corresponding variable.
   454  	if l == r && !isCall {
   455  		for i, lhs := range lhs {
   456  			check.assignVar(lhs, orig_rhs[i], nil, "assignment")
   457  		}
   458  		return
   459  	}
   460  
   461  	// If we don't have an n:n mapping, the rhs must be a single expression
   462  	// resulting in 2 or more values; otherwise we have an assignment mismatch.
   463  	if r != 1 {
   464  		// Only report a mismatch error if there are no other errors on the lhs or rhs.
   465  		okLHS := check.useLHS(lhs...)
   466  		okRHS := check.use(orig_rhs...)
   467  		if okLHS && okRHS {
   468  			check.assignError(orig_rhs, l, r)
   469  		}
   470  		return
   471  	}
   472  
   473  	rhs, commaOk := check.multiExpr(orig_rhs[0], l == 2)
   474  	r = len(rhs)
   475  	if l == r {
   476  		for i, lhs := range lhs {
   477  			check.assignVar(lhs, nil, rhs[i], "assignment")
   478  		}
   479  		// Only record comma-ok expression if both assignments succeeded
   480  		// (go.dev/issue/59371).
   481  		if commaOk && rhs[0].mode != invalid && rhs[1].mode != invalid {
   482  			check.recordCommaOkTypes(orig_rhs[0], rhs)
   483  		}
   484  		return
   485  	}
   486  
   487  	// In all other cases we have an assignment mismatch.
   488  	// Only report a mismatch error if there are no other errors on the rhs.
   489  	if rhs[0].mode != invalid {
   490  		check.assignError(orig_rhs, l, r)
   491  	}
   492  	check.useLHS(lhs...)
   493  	// orig_rhs[0] was already evaluated
   494  }
   495  
   496  func (check *Checker) shortVarDecl(pos syntax.Pos, lhs, rhs []syntax.Expr) {
   497  	top := len(check.delayed)
   498  	scope := check.scope
   499  
   500  	// collect lhs variables
   501  	seen := make(map[string]bool, len(lhs))
   502  	lhsVars := make([]*Var, len(lhs))
   503  	newVars := make([]*Var, 0, len(lhs))
   504  	hasErr := false
   505  	for i, lhs := range lhs {
   506  		ident, _ := lhs.(*syntax.Name)
   507  		if ident == nil {
   508  			check.useLHS(lhs)
   509  			check.errorf(lhs, BadDecl, "non-name %s on left side of :=", lhs)
   510  			hasErr = true
   511  			continue
   512  		}
   513  
   514  		name := ident.Value
   515  		if name != "_" {
   516  			if seen[name] {
   517  				check.errorf(lhs, RepeatedDecl, "%s repeated on left side of :=", lhs)
   518  				hasErr = true
   519  				continue
   520  			}
   521  			seen[name] = true
   522  		}
   523  
   524  		// Use the correct obj if the ident is redeclared. The
   525  		// variable's scope starts after the declaration; so we
   526  		// must use Scope.Lookup here and call Scope.Insert
   527  		// (via check.declare) later.
   528  		if alt := scope.Lookup(name); alt != nil {
   529  			check.recordUse(ident, alt)
   530  			// redeclared object must be a variable
   531  			if obj, _ := alt.(*Var); obj != nil {
   532  				lhsVars[i] = obj
   533  			} else {
   534  				check.errorf(lhs, UnassignableOperand, "cannot assign to %s", lhs)
   535  				hasErr = true
   536  			}
   537  			continue
   538  		}
   539  
   540  		// declare new variable
   541  		obj := NewVar(ident.Pos(), check.pkg, name, nil)
   542  		lhsVars[i] = obj
   543  		if name != "_" {
   544  			newVars = append(newVars, obj)
   545  		}
   546  		check.recordDef(ident, obj)
   547  	}
   548  
   549  	// create dummy variables where the lhs is invalid
   550  	for i, obj := range lhsVars {
   551  		if obj == nil {
   552  			lhsVars[i] = NewVar(lhs[i].Pos(), check.pkg, "_", nil)
   553  		}
   554  	}
   555  
   556  	check.initVars(lhsVars, rhs, nil)
   557  
   558  	// process function literals in rhs expressions before scope changes
   559  	check.processDelayed(top)
   560  
   561  	if len(newVars) == 0 && !hasErr {
   562  		check.softErrorf(pos, NoNewVar, "no new variables on left side of :=")
   563  		return
   564  	}
   565  
   566  	// declare new variables
   567  	// spec: "The scope of a constant or variable identifier declared inside
   568  	// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
   569  	// for short variable declarations) and ends at the end of the innermost
   570  	// containing block."
   571  	scopePos := syntax.EndPos(rhs[len(rhs)-1])
   572  	for _, obj := range newVars {
   573  		check.declare(scope, nil, obj, scopePos) // id = nil: recordDef already called
   574  	}
   575  }
   576  

View as plain text