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

View as plain text