...

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	)
    15	
    16	// An operandMode specifies the (addressing) mode of an operand.
    17	type operandMode byte
    18	
    19	const (
    20		invalid   operandMode = iota // operand is invalid
    21		novalue                      // operand represents no value (result of a function call w/o result)
    22		builtin                      // operand is a built-in function
    23		typexpr                      // operand is a type
    24		constant_                    // operand is a constant; the operand's typ is a Basic type
    25		variable                     // operand is an addressable variable
    26		mapindex                     // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
    27		value                        // operand is a computed value
    28		commaok                      // like value, but operand may be used in a comma,ok expression
    29	)
    30	
    31	var operandModeString = [...]string{
    32		invalid:   "invalid operand",
    33		novalue:   "no value",
    34		builtin:   "built-in",
    35		typexpr:   "type",
    36		constant_: "constant",
    37		variable:  "variable",
    38		mapindex:  "map index expression",
    39		value:     "value",
    40		commaok:   "comma, ok expression",
    41	}
    42	
    43	// An operand represents an intermediate value during type checking.
    44	// Operands have an (addressing) mode, the expression evaluating to
    45	// the operand, the operand's type, a value for constants, and an id
    46	// for built-in functions.
    47	// The zero value of operand is a ready to use invalid operand.
    48	//
    49	type operand struct {
    50		mode operandMode
    51		expr ast.Expr
    52		typ  Type
    53		val  constant.Value
    54		id   builtinId
    55	}
    56	
    57	// pos returns the position of the expression corresponding to x.
    58	// If x is invalid the position is token.NoPos.
    59	//
    60	func (x *operand) pos() token.Pos {
    61		// x.expr may not be set if x is invalid
    62		if x.expr == nil {
    63			return token.NoPos
    64		}
    65		return x.expr.Pos()
    66	}
    67	
    68	// Operand string formats
    69	// (not all "untyped" cases can appear due to the type system,
    70	// but they fall out naturally here)
    71	//
    72	// mode       format
    73	//
    74	// invalid    <expr> (               <mode>                    )
    75	// novalue    <expr> (               <mode>                    )
    76	// builtin    <expr> (               <mode>                    )
    77	// typexpr    <expr> (               <mode>                    )
    78	//
    79	// constant   <expr> (<untyped kind> <mode>                    )
    80	// constant   <expr> (               <mode>       of type <typ>)
    81	// constant   <expr> (<untyped kind> <mode> <val>              )
    82	// constant   <expr> (               <mode> <val> of type <typ>)
    83	//
    84	// variable   <expr> (<untyped kind> <mode>                    )
    85	// variable   <expr> (               <mode>       of type <typ>)
    86	//
    87	// mapindex   <expr> (<untyped kind> <mode>                    )
    88	// mapindex   <expr> (               <mode>       of type <typ>)
    89	//
    90	// value      <expr> (<untyped kind> <mode>                    )
    91	// value      <expr> (               <mode>       of type <typ>)
    92	//
    93	// commaok    <expr> (<untyped kind> <mode>                    )
    94	// commaok    <expr> (               <mode>       of type <typ>)
    95	//
    96	func operandString(x *operand, qf Qualifier) string {
    97		var buf bytes.Buffer
    98	
    99		var expr string
   100		if x.expr != nil {
   101			expr = ExprString(x.expr)
   102		} else {
   103			switch x.mode {
   104			case builtin:
   105				expr = predeclaredFuncs[x.id].name
   106			case typexpr:
   107				expr = TypeString(x.typ, qf)
   108			case constant_:
   109				expr = x.val.String()
   110			}
   111		}
   112	
   113		// <expr> (
   114		if expr != "" {
   115			buf.WriteString(expr)
   116			buf.WriteString(" (")
   117		}
   118	
   119		// <untyped kind>
   120		hasType := false
   121		switch x.mode {
   122		case invalid, novalue, builtin, typexpr:
   123			// no type
   124		default:
   125			// should have a type, but be cautious (don't crash during printing)
   126			if x.typ != nil {
   127				if isUntyped(x.typ) {
   128					buf.WriteString(x.typ.(*Basic).name)
   129					buf.WriteByte(' ')
   130					break
   131				}
   132				hasType = true
   133			}
   134		}
   135	
   136		// <mode>
   137		buf.WriteString(operandModeString[x.mode])
   138	
   139		// <val>
   140		if x.mode == constant_ {
   141			if s := x.val.String(); s != expr {
   142				buf.WriteByte(' ')
   143				buf.WriteString(s)
   144			}
   145		}
   146	
   147		// <typ>
   148		if hasType {
   149			if x.typ != Typ[Invalid] {
   150				buf.WriteString(" of type ")
   151				WriteType(&buf, x.typ, qf)
   152			} else {
   153				buf.WriteString(" with invalid type")
   154			}
   155		}
   156	
   157		// )
   158		if expr != "" {
   159			buf.WriteByte(')')
   160		}
   161	
   162		return buf.String()
   163	}
   164	
   165	func (x *operand) String() string {
   166		return operandString(x, nil)
   167	}
   168	
   169	// setConst sets x to the untyped constant for literal lit.
   170	func (x *operand) setConst(tok token.Token, lit string) {
   171		var kind BasicKind
   172		switch tok {
   173		case token.INT:
   174			kind = UntypedInt
   175		case token.FLOAT:
   176			kind = UntypedFloat
   177		case token.IMAG:
   178			kind = UntypedComplex
   179		case token.CHAR:
   180			kind = UntypedRune
   181		case token.STRING:
   182			kind = UntypedString
   183		default:
   184			unreachable()
   185		}
   186	
   187		x.mode = constant_
   188		x.typ = Typ[kind]
   189		x.val = constant.MakeFromLiteral(lit, tok, 0)
   190	}
   191	
   192	// isNil reports whether x is the nil value.
   193	func (x *operand) isNil() bool {
   194		return x.mode == value && x.typ == Typ[UntypedNil]
   195	}
   196	
   197	// TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
   198	//           checker.representable, and checker.assignment are
   199	//           overlapping in functionality. Need to simplify and clean up.
   200	
   201	// assignableTo reports whether x is assignable to a variable of type T.
   202	// If the result is false and a non-nil reason is provided, it may be set
   203	// to a more detailed explanation of the failure (result != "").
   204	// The check parameter may be nil if assignableTo is invoked through
   205	// an exported API call, i.e., when all methods have been type-checked.
   206	func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
   207		if x.mode == invalid || T == Typ[Invalid] {
   208			return true // avoid spurious errors
   209		}
   210	
   211		V := x.typ
   212	
   213		// x's type is identical to T
   214		if Identical(V, T) {
   215			return true
   216		}
   217	
   218		Vu := V.Underlying()
   219		Tu := T.Underlying()
   220	
   221		// x is an untyped value representable by a value of type T
   222		// TODO(gri) This is borrowing from checker.convertUntyped and
   223		//           checker.representable. Need to clean up.
   224		if isUntyped(Vu) {
   225			switch t := Tu.(type) {
   226			case *Basic:
   227				if x.isNil() && t.kind == UnsafePointer {
   228					return true
   229				}
   230				if x.mode == constant_ {
   231					return representableConst(x.val, check, t, nil)
   232				}
   233				// The result of a comparison is an untyped boolean,
   234				// but may not be a constant.
   235				if Vb, _ := Vu.(*Basic); Vb != nil {
   236					return Vb.kind == UntypedBool && isBoolean(Tu)
   237				}
   238			case *Interface:
   239				return x.isNil() || t.Empty()
   240			case *Pointer, *Signature, *Slice, *Map, *Chan:
   241				return x.isNil()
   242			}
   243		}
   244		// Vu is typed
   245	
   246		// x's type V and T have identical underlying types
   247		// and at least one of V or T is not a named type
   248		if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
   249			return true
   250		}
   251	
   252		// T is an interface type and x implements T
   253		if Ti, ok := Tu.(*Interface); ok {
   254			if m, wrongType := check.missingMethod(x.typ, Ti, true); m != nil /* Implements(x.typ, Ti) */ {
   255				if reason != nil {
   256					if wrongType {
   257						*reason = "wrong type for method " + m.Name()
   258					} else {
   259						*reason = "missing method " + m.Name()
   260					}
   261				}
   262				return false
   263			}
   264			return true
   265		}
   266	
   267		// x is a bidirectional channel value, T is a channel
   268		// type, x's type V and T have identical element types,
   269		// and at least one of V or T is not a named type
   270		if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
   271			if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
   272				return !isNamed(V) || !isNamed(T)
   273			}
   274		}
   275	
   276		return false
   277	}
   278	

View as plain text