...

Source file src/go/types/assignments.go

Documentation: go/types

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

View as plain text