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

View as plain text