Source file src/go/types/operand.go

     1  // Copyright 2012 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 defines operands and associated operations.
     6  
     7  package types
     8  
     9  import (
    10  	"bytes"
    11  	"go/ast"
    12  	"go/constant"
    13  	"go/token"
    14  	. "internal/types/errors"
    15  )
    16  
    17  // An operandMode specifies the (addressing) mode of an operand.
    18  type operandMode byte
    19  
    20  const (
    21  	invalid   operandMode = iota // operand is invalid
    22  	novalue                      // operand represents no value (result of a function call w/o result)
    23  	builtin                      // operand is a built-in function
    24  	typexpr                      // operand is a type
    25  	constant_                    // operand is a constant; the operand's typ is a Basic type
    26  	variable                     // operand is an addressable variable
    27  	mapindex                     // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
    28  	value                        // operand is a computed value
    29  	commaok                      // like value, but operand may be used in a comma,ok expression
    30  	commaerr                     // like commaok, but second value is error, not boolean
    31  	cgofunc                      // operand is a cgo function
    32  )
    33  
    34  var operandModeString = [...]string{
    35  	invalid:   "invalid operand",
    36  	novalue:   "no value",
    37  	builtin:   "built-in",
    38  	typexpr:   "type",
    39  	constant_: "constant",
    40  	variable:  "variable",
    41  	mapindex:  "map index expression",
    42  	value:     "value",
    43  	commaok:   "comma, ok expression",
    44  	commaerr:  "comma, error expression",
    45  	cgofunc:   "cgo function",
    46  }
    47  
    48  // An operand represents an intermediate value during type checking.
    49  // Operands have an (addressing) mode, the expression evaluating to
    50  // the operand, the operand's type, a value for constants, and an id
    51  // for built-in functions.
    52  // The zero value of operand is a ready to use invalid operand.
    53  type operand struct {
    54  	mode operandMode
    55  	expr ast.Expr
    56  	typ  Type
    57  	val  constant.Value
    58  	id   builtinId
    59  }
    60  
    61  // Pos returns the position of the expression corresponding to x.
    62  // If x is invalid the position is nopos.
    63  func (x *operand) Pos() token.Pos {
    64  	// x.expr may not be set if x is invalid
    65  	if x.expr == nil {
    66  		return nopos
    67  	}
    68  	return x.expr.Pos()
    69  }
    70  
    71  // Operand string formats
    72  // (not all "untyped" cases can appear due to the type system,
    73  // but they fall out naturally here)
    74  //
    75  // mode       format
    76  //
    77  // invalid    <expr> (               <mode>                    )
    78  // novalue    <expr> (               <mode>                    )
    79  // builtin    <expr> (               <mode>                    )
    80  // typexpr    <expr> (               <mode>                    )
    81  //
    82  // constant   <expr> (<untyped kind> <mode>                    )
    83  // constant   <expr> (               <mode>       of type <typ>)
    84  // constant   <expr> (<untyped kind> <mode> <val>              )
    85  // constant   <expr> (               <mode> <val> of type <typ>)
    86  //
    87  // variable   <expr> (<untyped kind> <mode>                    )
    88  // variable   <expr> (               <mode>       of type <typ>)
    89  //
    90  // mapindex   <expr> (<untyped kind> <mode>                    )
    91  // mapindex   <expr> (               <mode>       of type <typ>)
    92  //
    93  // value      <expr> (<untyped kind> <mode>                    )
    94  // value      <expr> (               <mode>       of type <typ>)
    95  //
    96  // commaok    <expr> (<untyped kind> <mode>                    )
    97  // commaok    <expr> (               <mode>       of type <typ>)
    98  //
    99  // commaerr   <expr> (<untyped kind> <mode>                    )
   100  // commaerr   <expr> (               <mode>       of type <typ>)
   101  //
   102  // cgofunc    <expr> (<untyped kind> <mode>                    )
   103  // cgofunc    <expr> (               <mode>       of type <typ>)
   104  func operandString(x *operand, qf Qualifier) string {
   105  	// special-case nil
   106  	if x.mode == value && x.typ == Typ[UntypedNil] {
   107  		return "nil"
   108  	}
   109  
   110  	var buf bytes.Buffer
   111  
   112  	var expr string
   113  	if x.expr != nil {
   114  		expr = ExprString(x.expr)
   115  	} else {
   116  		switch x.mode {
   117  		case builtin:
   118  			expr = predeclaredFuncs[x.id].name
   119  		case typexpr:
   120  			expr = TypeString(x.typ, qf)
   121  		case constant_:
   122  			expr = x.val.String()
   123  		}
   124  	}
   125  
   126  	// <expr> (
   127  	if expr != "" {
   128  		buf.WriteString(expr)
   129  		buf.WriteString(" (")
   130  	}
   131  
   132  	// <untyped kind>
   133  	hasType := false
   134  	switch x.mode {
   135  	case invalid, novalue, builtin, typexpr:
   136  		// no type
   137  	default:
   138  		// should have a type, but be cautious (don't crash during printing)
   139  		if x.typ != nil {
   140  			if isUntyped(x.typ) {
   141  				buf.WriteString(x.typ.(*Basic).name)
   142  				buf.WriteByte(' ')
   143  				break
   144  			}
   145  			hasType = true
   146  		}
   147  	}
   148  
   149  	// <mode>
   150  	buf.WriteString(operandModeString[x.mode])
   151  
   152  	// <val>
   153  	if x.mode == constant_ {
   154  		if s := x.val.String(); s != expr {
   155  			buf.WriteByte(' ')
   156  			buf.WriteString(s)
   157  		}
   158  	}
   159  
   160  	// <typ>
   161  	if hasType {
   162  		if isValid(x.typ) {
   163  			var intro string
   164  			if isGeneric(x.typ) {
   165  				intro = " of generic type "
   166  			} else {
   167  				intro = " of type "
   168  			}
   169  			buf.WriteString(intro)
   170  			WriteType(&buf, x.typ, qf)
   171  			if tpar, _ := x.typ.(*TypeParam); tpar != nil {
   172  				buf.WriteString(" constrained by ")
   173  				WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here
   174  				// If we have the type set and it's empty, say so for better error messages.
   175  				if hasEmptyTypeset(tpar) {
   176  					buf.WriteString(" with empty type set")
   177  				}
   178  			}
   179  		} else {
   180  			buf.WriteString(" with invalid type")
   181  		}
   182  	}
   183  
   184  	// )
   185  	if expr != "" {
   186  		buf.WriteByte(')')
   187  	}
   188  
   189  	return buf.String()
   190  }
   191  
   192  func (x *operand) String() string {
   193  	return operandString(x, nil)
   194  }
   195  
   196  // setConst sets x to the untyped constant for literal lit.
   197  func (x *operand) setConst(tok token.Token, lit string) {
   198  	var kind BasicKind
   199  	switch tok {
   200  	case token.INT:
   201  		kind = UntypedInt
   202  	case token.FLOAT:
   203  		kind = UntypedFloat
   204  	case token.IMAG:
   205  		kind = UntypedComplex
   206  	case token.CHAR:
   207  		kind = UntypedRune
   208  	case token.STRING:
   209  		kind = UntypedString
   210  	default:
   211  		unreachable()
   212  	}
   213  
   214  	val := constant.MakeFromLiteral(lit, tok, 0)
   215  	if val.Kind() == constant.Unknown {
   216  		x.mode = invalid
   217  		x.typ = Typ[Invalid]
   218  		return
   219  	}
   220  	x.mode = constant_
   221  	x.typ = Typ[kind]
   222  	x.val = val
   223  }
   224  
   225  // isNil reports whether x is the (untyped) nil value.
   226  func (x *operand) isNil() bool { return x.mode == value && x.typ == Typ[UntypedNil] }
   227  
   228  // assignableTo reports whether x is assignable to a variable of type T. If the
   229  // result is false and a non-nil cause is provided, it may be set to a more
   230  // detailed explanation of the failure (result != ""). The returned error code
   231  // is only valid if the (first) result is false. The check parameter may be nil
   232  // if assignableTo is invoked through an exported API call, i.e., when all
   233  // methods have been type-checked.
   234  func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Code) {
   235  	if x.mode == invalid || !isValid(T) {
   236  		return true, 0 // avoid spurious errors
   237  	}
   238  
   239  	V := x.typ
   240  
   241  	// x's type is identical to T
   242  	if Identical(V, T) {
   243  		return true, 0
   244  	}
   245  
   246  	Vu := under(V)
   247  	Tu := under(T)
   248  	Vp, _ := V.(*TypeParam)
   249  	Tp, _ := T.(*TypeParam)
   250  
   251  	// x is an untyped value representable by a value of type T.
   252  	if isUntyped(Vu) {
   253  		assert(Vp == nil)
   254  		if Tp != nil {
   255  			// T is a type parameter: x is assignable to T if it is
   256  			// representable by each specific type in the type set of T.
   257  			return Tp.is(func(t *term) bool {
   258  				if t == nil {
   259  					return false
   260  				}
   261  				// A term may be a tilde term but the underlying
   262  				// type of an untyped value doesn't change so we
   263  				// don't need to do anything special.
   264  				newType, _, _ := check.implicitTypeAndValue(x, t.typ)
   265  				return newType != nil
   266  			}), IncompatibleAssign
   267  		}
   268  		newType, _, _ := check.implicitTypeAndValue(x, T)
   269  		return newType != nil, IncompatibleAssign
   270  	}
   271  	// Vu is typed
   272  
   273  	// x's type V and T have identical underlying types
   274  	// and at least one of V or T is not a named type
   275  	// and neither V nor T is a type parameter.
   276  	if Identical(Vu, Tu) && (!hasName(V) || !hasName(T)) && Vp == nil && Tp == nil {
   277  		return true, 0
   278  	}
   279  
   280  	// T is an interface type, but not a type parameter, and V implements T.
   281  	// Also handle the case where T is a pointer to an interface so that we get
   282  	// the Checker.implements error cause.
   283  	if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
   284  		if check.implements(x.Pos(), V, T, false, cause) {
   285  			return true, 0
   286  		}
   287  		// V doesn't implement T but V may still be assignable to T if V
   288  		// is a type parameter; do not report an error in that case yet.
   289  		if Vp == nil {
   290  			return false, InvalidIfaceAssign
   291  		}
   292  		if cause != nil {
   293  			*cause = ""
   294  		}
   295  	}
   296  
   297  	// If V is an interface, check if a missing type assertion is the problem.
   298  	if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
   299  		if check.implements(x.Pos(), T, V, false, nil) {
   300  			// T implements V, so give hint about type assertion.
   301  			if cause != nil {
   302  				*cause = "need type assertion"
   303  			}
   304  			return false, IncompatibleAssign
   305  		}
   306  	}
   307  
   308  	// x is a bidirectional channel value, T is a channel
   309  	// type, x's type V and T have identical element types,
   310  	// and at least one of V or T is not a named type.
   311  	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
   312  		if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
   313  			return !hasName(V) || !hasName(T), InvalidChanAssign
   314  		}
   315  	}
   316  
   317  	// optimization: if we don't have type parameters, we're done
   318  	if Vp == nil && Tp == nil {
   319  		return false, IncompatibleAssign
   320  	}
   321  
   322  	errorf := func(format string, args ...any) {
   323  		if check != nil && cause != nil {
   324  			msg := check.sprintf(format, args...)
   325  			if *cause != "" {
   326  				msg += "\n\t" + *cause
   327  			}
   328  			*cause = msg
   329  		}
   330  	}
   331  
   332  	// x's type V is not a named type and T is a type parameter, and
   333  	// x is assignable to each specific type in T's type set.
   334  	if !hasName(V) && Tp != nil {
   335  		ok := false
   336  		code := IncompatibleAssign
   337  		Tp.is(func(T *term) bool {
   338  			if T == nil {
   339  				return false // no specific types
   340  			}
   341  			ok, code = x.assignableTo(check, T.typ, cause)
   342  			if !ok {
   343  				errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
   344  				return false
   345  			}
   346  			return true
   347  		})
   348  		return ok, code
   349  	}
   350  
   351  	// x's type V is a type parameter and T is not a named type,
   352  	// and values x' of each specific type in V's type set are
   353  	// assignable to T.
   354  	if Vp != nil && !hasName(T) {
   355  		x := *x // don't clobber outer x
   356  		ok := false
   357  		code := IncompatibleAssign
   358  		Vp.is(func(V *term) bool {
   359  			if V == nil {
   360  				return false // no specific types
   361  			}
   362  			x.typ = V.typ
   363  			ok, code = x.assignableTo(check, T, cause)
   364  			if !ok {
   365  				errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T)
   366  				return false
   367  			}
   368  			return true
   369  		})
   370  		return ok, code
   371  	}
   372  
   373  	return false, IncompatibleAssign
   374  }
   375  

View as plain text