...

Source file src/cmd/compile/internal/types2/operand.go

Documentation: cmd/compile/internal/types2

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

View as plain text