github.com/bir3/gocompiler@v0.3.205/src/go/types/assignments.go (about)

     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  	"fmt"
    11  	"github.com/bir3/gocompiler/src/go/ast"
    12  	"github.com/bir3/gocompiler/src/go/token"
    13  	. "github.com/bir3/gocompiler/src/internal/types/errors"
    14  	"strings"
    15  )
    16  
    17  // assignment reports whether x can be assigned to a variable of type T,
    18  // if necessary by attempting to convert untyped values to the appropriate
    19  // type. context describes the context in which the assignment takes place.
    20  // Use T == nil to indicate assignment to an untyped blank identifier.
    21  // x.mode is set to invalid if the assignment failed.
    22  func (check *Checker) assignment(x *operand, T Type, context string) {
    23  	check.singleValue(x)
    24  
    25  	switch x.mode {
    26  	case invalid:
    27  		return // error reported before
    28  	case constant_, variable, mapindex, value, commaok, commaerr:
    29  		// ok
    30  	default:
    31  		// we may get here because of other problems (issue #39634, crash 12)
    32  		// TODO(gri) do we need a new "generic" error code here?
    33  		check.errorf(x, IncompatibleAssign, "cannot assign %s to %s in %s", x, T, context)
    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 T == nil || isNonTypeParamInterface(T) {
    45  			if T == nil && x.typ == Typ[UntypedNil] {
    46  				check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
    47  				x.mode = invalid
    48  				return
    49  			}
    50  			target = Default(x.typ)
    51  		}
    52  		newType, val, code := check.implicitTypeAndValue(x, target)
    53  		if code != 0 {
    54  			msg := check.sprintf("cannot use %s as %s value in %s", x, target, context)
    55  			switch code {
    56  			case TruncatedFloat:
    57  				msg += " (truncated)"
    58  			case NumericOverflow:
    59  				msg += " (overflows)"
    60  			default:
    61  				code = IncompatibleAssign
    62  			}
    63  			check.error(x, code, msg)
    64  			x.mode = invalid
    65  			return
    66  		}
    67  		if val != nil {
    68  			x.val = val
    69  			check.updateExprVal(x.expr, val)
    70  		}
    71  		if newType != x.typ {
    72  			x.typ = newType
    73  			check.updateExprType(x.expr, newType, false)
    74  		}
    75  	}
    76  
    77  	// A generic (non-instantiated) function value cannot be assigned to a variable.
    78  	if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
    79  		check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
    80  	}
    81  
    82  	// spec: "If a left-hand side is the blank identifier, any typed or
    83  	// non-constant value except for the predeclared identifier nil may
    84  	// be assigned to it."
    85  	if T == nil {
    86  		return
    87  	}
    88  
    89  	cause := ""
    90  	if ok, code := x.assignableTo(check, T, &cause); !ok {
    91  		if cause != "" {
    92  			check.errorf(x, code, "cannot use %s as %s value in %s: %s", x, T, context, cause)
    93  		} else {
    94  			check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
    95  		}
    96  		x.mode = invalid
    97  	}
    98  }
    99  
   100  func (check *Checker) initConst(lhs *Const, x *operand) {
   101  	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
   102  		if lhs.typ == nil {
   103  			lhs.typ = Typ[Invalid]
   104  		}
   105  		return
   106  	}
   107  
   108  	// rhs must be a constant
   109  	if x.mode != constant_ {
   110  		check.errorf(x, InvalidConstInit, "%s is not constant", x)
   111  		if lhs.typ == nil {
   112  			lhs.typ = Typ[Invalid]
   113  		}
   114  		return
   115  	}
   116  	assert(isConstType(x.typ))
   117  
   118  	// If the lhs doesn't have a type yet, use the type of x.
   119  	if lhs.typ == nil {
   120  		lhs.typ = x.typ
   121  	}
   122  
   123  	check.assignment(x, lhs.typ, "constant declaration")
   124  	if x.mode == invalid {
   125  		return
   126  	}
   127  
   128  	lhs.val = x.val
   129  }
   130  
   131  func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
   132  	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
   133  		if lhs.typ == nil {
   134  			lhs.typ = Typ[Invalid]
   135  		}
   136  		return nil
   137  	}
   138  
   139  	// If the lhs doesn't have a type yet, use the type of x.
   140  	if lhs.typ == nil {
   141  		typ := x.typ
   142  		if isUntyped(typ) {
   143  			// convert untyped types to default types
   144  			if typ == Typ[UntypedNil] {
   145  				check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
   146  				lhs.typ = Typ[Invalid]
   147  				return nil
   148  			}
   149  			typ = Default(typ)
   150  		}
   151  		lhs.typ = typ
   152  	}
   153  
   154  	check.assignment(x, lhs.typ, context)
   155  	if x.mode == invalid {
   156  		return nil
   157  	}
   158  
   159  	return x.typ
   160  }
   161  
   162  func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
   163  	if x.mode == invalid || x.typ == Typ[Invalid] {
   164  		check.useLHS(lhs)
   165  		return nil
   166  	}
   167  
   168  	// Determine if the lhs is a (possibly parenthesized) identifier.
   169  	ident, _ := unparen(lhs).(*ast.Ident)
   170  
   171  	// Don't evaluate lhs if it is the blank identifier.
   172  	if ident != nil && ident.Name == "_" {
   173  		check.recordDef(ident, nil)
   174  		check.assignment(x, nil, "assignment to _ identifier")
   175  		if x.mode == invalid {
   176  			return nil
   177  		}
   178  		return x.typ
   179  	}
   180  
   181  	// If the lhs is an identifier denoting a variable v, this assignment
   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.Name); 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 z operand
   199  	check.expr(&z, lhs)
   200  	if v != nil {
   201  		v.used = v_used // restore v.used
   202  	}
   203  
   204  	if z.mode == invalid || z.typ == Typ[Invalid] {
   205  		return nil
   206  	}
   207  
   208  	// spec: "Each left-hand side operand must be addressable, a map index
   209  	// expression, or the blank identifier. Operands may be parenthesized."
   210  	switch z.mode {
   211  	case invalid:
   212  		return nil
   213  	case variable, mapindex:
   214  		// ok
   215  	default:
   216  		if sel, ok := z.expr.(*ast.SelectorExpr); ok {
   217  			var op operand
   218  			check.expr(&op, sel.X)
   219  			if op.mode == mapindex {
   220  				check.errorf(&z, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(z.expr))
   221  				return nil
   222  			}
   223  		}
   224  		check.errorf(&z, UnassignableOperand, "cannot assign to %s", &z)
   225  		return nil
   226  	}
   227  
   228  	check.assignment(x, z.typ, "assignment")
   229  	if x.mode == invalid {
   230  		return nil
   231  	}
   232  
   233  	return x.typ
   234  }
   235  
   236  // operandTypes returns the list of types for the given operands.
   237  func operandTypes(list []*operand) (res []Type) {
   238  	for _, x := range list {
   239  		res = append(res, x.typ)
   240  	}
   241  	return res
   242  }
   243  
   244  // varTypes returns the list of types for the given variables.
   245  func varTypes(list []*Var) (res []Type) {
   246  	for _, x := range list {
   247  		res = append(res, x.typ)
   248  	}
   249  	return res
   250  }
   251  
   252  // typesSummary returns a string of the form "(t1, t2, ...)" where the
   253  // ti's are user-friendly string representations for the given types.
   254  // If variadic is set and the last type is a slice, its string is of
   255  // the form "...E" where E is the slice's element type.
   256  func (check *Checker) typesSummary(list []Type, variadic bool) string {
   257  	var res []string
   258  	for i, t := range list {
   259  		var s string
   260  		switch {
   261  		case t == nil:
   262  			fallthrough // should not happen but be cautious
   263  		case t == Typ[Invalid]:
   264  			s = "<T>"
   265  		case isUntyped(t):
   266  			if isNumeric(t) {
   267  				// Do not imply a specific type requirement:
   268  				// "have number, want float64" is better than
   269  				// "have untyped int, want float64" or
   270  				// "have int, want float64".
   271  				s = "number"
   272  			} else {
   273  				// If we don't have a number, omit the "untyped" qualifier
   274  				// for compactness.
   275  				s = strings.Replace(t.(*Basic).name, "untyped ", "", -1)
   276  			}
   277  		case variadic && i == len(list)-1:
   278  			s = check.sprintf("...%s", t.(*Slice).elem)
   279  		}
   280  		if s == "" {
   281  			s = check.sprintf("%s", t)
   282  		}
   283  		res = append(res, s)
   284  	}
   285  	return "(" + strings.Join(res, ", ") + ")"
   286  }
   287  
   288  func measure(x int, unit string) string {
   289  	if x != 1 {
   290  		unit += "s"
   291  	}
   292  	return fmt.Sprintf("%d %s", x, unit)
   293  }
   294  
   295  func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
   296  	vars := measure(nvars, "variable")
   297  	vals := measure(nvals, "value")
   298  	rhs0 := rhs[0]
   299  
   300  	if len(rhs) == 1 {
   301  		if call, _ := unparen(rhs0).(*ast.CallExpr); call != nil {
   302  			check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals)
   303  			return
   304  		}
   305  	}
   306  	check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s", vars, vals)
   307  }
   308  
   309  // If returnStmt != nil, initVars is called to type-check the assignment
   310  // of return expressions, and returnStmt is the return statement.
   311  func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnStmt ast.Stmt) {
   312  	rhs, commaOk := check.exprList(origRHS, len(lhs) == 2 && returnStmt == nil)
   313  
   314  	if len(lhs) != len(rhs) {
   315  		// invalidate lhs
   316  		for _, obj := range lhs {
   317  			obj.used = true // avoid declared and not used errors
   318  			if obj.typ == nil {
   319  				obj.typ = Typ[Invalid]
   320  			}
   321  		}
   322  		// don't report an error if we already reported one
   323  		for _, x := range rhs {
   324  			if x.mode == invalid {
   325  				return
   326  			}
   327  		}
   328  		if returnStmt != nil {
   329  			var at positioner = returnStmt
   330  			qualifier := "not enough"
   331  			if len(rhs) > len(lhs) {
   332  				at = rhs[len(lhs)].expr // report at first extra value
   333  				qualifier = "too many"
   334  			} else if len(rhs) > 0 {
   335  				at = rhs[len(rhs)-1].expr // report at last value
   336  			}
   337  			err := newErrorf(at, WrongResultCount, "%s return values", qualifier)
   338  			err.errorf(token.NoPos, "have %s", check.typesSummary(operandTypes(rhs), false))
   339  			err.errorf(token.NoPos, "want %s", check.typesSummary(varTypes(lhs), false))
   340  			check.report(err)
   341  			return
   342  		}
   343  		check.assignError(origRHS, len(lhs), len(rhs))
   344  		return
   345  	}
   346  
   347  	context := "assignment"
   348  	if returnStmt != nil {
   349  		context = "return statement"
   350  	}
   351  
   352  	if commaOk {
   353  		var a [2]Type
   354  		for i := range a {
   355  			a[i] = check.initVar(lhs[i], rhs[i], context)
   356  		}
   357  		check.recordCommaOkTypes(origRHS[0], a)
   358  		return
   359  	}
   360  
   361  	for i, lhs := range lhs {
   362  		check.initVar(lhs, rhs[i], context)
   363  	}
   364  }
   365  
   366  func (check *Checker) assignVars(lhs, origRHS []ast.Expr) {
   367  	rhs, commaOk := check.exprList(origRHS, len(lhs) == 2)
   368  
   369  	if len(lhs) != len(rhs) {
   370  		check.useLHS(lhs...)
   371  		// don't report an error if we already reported one
   372  		for _, x := range rhs {
   373  			if x.mode == invalid {
   374  				return
   375  			}
   376  		}
   377  		check.assignError(origRHS, len(lhs), len(rhs))
   378  		return
   379  	}
   380  
   381  	if commaOk {
   382  		var a [2]Type
   383  		for i := range a {
   384  			a[i] = check.assignVar(lhs[i], rhs[i])
   385  		}
   386  		check.recordCommaOkTypes(origRHS[0], a)
   387  		return
   388  	}
   389  
   390  	for i, lhs := range lhs {
   391  		check.assignVar(lhs, rhs[i])
   392  	}
   393  }
   394  
   395  func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
   396  	top := len(check.delayed)
   397  	scope := check.scope
   398  
   399  	// collect lhs variables
   400  	seen := make(map[string]bool, len(lhs))
   401  	lhsVars := make([]*Var, len(lhs))
   402  	newVars := make([]*Var, 0, len(lhs))
   403  	hasErr := false
   404  	for i, lhs := range lhs {
   405  		ident, _ := lhs.(*ast.Ident)
   406  		if ident == nil {
   407  			check.useLHS(lhs)
   408  			// TODO(rFindley) this is redundant with a parser error. Consider omitting?
   409  			check.errorf(lhs, BadDecl, "non-name %s on left side of :=", lhs)
   410  			hasErr = true
   411  			continue
   412  		}
   413  
   414  		name := ident.Name
   415  		if name != "_" {
   416  			if seen[name] {
   417  				check.errorf(lhs, RepeatedDecl, "%s repeated on left side of :=", lhs)
   418  				hasErr = true
   419  				continue
   420  			}
   421  			seen[name] = true
   422  		}
   423  
   424  		// Use the correct obj if the ident is redeclared. The
   425  		// variable's scope starts after the declaration; so we
   426  		// must use Scope.Lookup here and call Scope.Insert
   427  		// (via check.declare) later.
   428  		if alt := scope.Lookup(name); alt != nil {
   429  			check.recordUse(ident, alt)
   430  			// redeclared object must be a variable
   431  			if obj, _ := alt.(*Var); obj != nil {
   432  				lhsVars[i] = obj
   433  			} else {
   434  				check.errorf(lhs, UnassignableOperand, "cannot assign to %s", lhs)
   435  				hasErr = true
   436  			}
   437  			continue
   438  		}
   439  
   440  		// declare new variable
   441  		obj := NewVar(ident.Pos(), check.pkg, name, nil)
   442  		lhsVars[i] = obj
   443  		if name != "_" {
   444  			newVars = append(newVars, obj)
   445  		}
   446  		check.recordDef(ident, obj)
   447  	}
   448  
   449  	// create dummy variables where the lhs is invalid
   450  	for i, obj := range lhsVars {
   451  		if obj == nil {
   452  			lhsVars[i] = NewVar(lhs[i].Pos(), check.pkg, "_", nil)
   453  		}
   454  	}
   455  
   456  	check.initVars(lhsVars, rhs, nil)
   457  
   458  	// process function literals in rhs expressions before scope changes
   459  	check.processDelayed(top)
   460  
   461  	if len(newVars) == 0 && !hasErr {
   462  		check.softErrorf(pos, NoNewVar, "no new variables on left side of :=")
   463  		return
   464  	}
   465  
   466  	// declare new variables
   467  	// spec: "The scope of a constant or variable identifier declared inside
   468  	// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
   469  	// for short variable declarations) and ends at the end of the innermost
   470  	// containing block."
   471  	scopePos := rhs[len(rhs)-1].End()
   472  	for _, obj := range newVars {
   473  		check.declare(scope, nil, obj, scopePos) // id = nil: recordDef already called
   474  	}
   475  }