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

View as plain text