github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/go/types/operand.go (about)

     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  		// has type
   126  		if isUntyped(x.typ) {
   127  			buf.WriteString(x.typ.(*Basic).name)
   128  			buf.WriteByte(' ')
   129  			break
   130  		}
   131  		hasType = true
   132  	}
   133  
   134  	// <mode>
   135  	buf.WriteString(operandModeString[x.mode])
   136  
   137  	// <val>
   138  	if x.mode == constant_ {
   139  		if s := x.val.String(); s != expr {
   140  			buf.WriteByte(' ')
   141  			buf.WriteString(s)
   142  		}
   143  	}
   144  
   145  	// <typ>
   146  	if hasType {
   147  		if x.typ != Typ[Invalid] {
   148  			buf.WriteString(" of type ")
   149  			WriteType(&buf, x.typ, qf)
   150  		} else {
   151  			buf.WriteString(" with invalid type")
   152  		}
   153  	}
   154  
   155  	// )
   156  	if expr != "" {
   157  		buf.WriteByte(')')
   158  	}
   159  
   160  	return buf.String()
   161  }
   162  
   163  func (x *operand) String() string {
   164  	return operandString(x, nil)
   165  }
   166  
   167  // setConst sets x to the untyped constant for literal lit.
   168  func (x *operand) setConst(tok token.Token, lit string) {
   169  	val := constant.MakeFromLiteral(lit, tok, 0)
   170  	if val == nil {
   171  		// TODO(gri) Should we make it an unknown constant instead?
   172  		x.mode = invalid
   173  		return
   174  	}
   175  
   176  	var kind BasicKind
   177  	switch tok {
   178  	case token.INT:
   179  		kind = UntypedInt
   180  	case token.FLOAT:
   181  		kind = UntypedFloat
   182  	case token.IMAG:
   183  		kind = UntypedComplex
   184  	case token.CHAR:
   185  		kind = UntypedRune
   186  	case token.STRING:
   187  		kind = UntypedString
   188  	}
   189  
   190  	x.mode = constant_
   191  	x.typ = Typ[kind]
   192  	x.val = val
   193  }
   194  
   195  // isNil reports whether x is the nil value.
   196  func (x *operand) isNil() bool {
   197  	return x.mode == value && x.typ == Typ[UntypedNil]
   198  }
   199  
   200  // TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
   201  //           checker.representable, and checker.assignment are
   202  //           overlapping in functionality. Need to simplify and clean up.
   203  
   204  // assignableTo reports whether x is assignable to a variable of type T.
   205  // If the result is false and a non-nil reason is provided, it may be set
   206  // to a more detailed explanation of the failure (result != "").
   207  func (x *operand) assignableTo(conf *Config, T Type, reason *string) bool {
   208  	if x.mode == invalid || T == Typ[Invalid] {
   209  		return true // avoid spurious errors
   210  	}
   211  
   212  	V := x.typ
   213  
   214  	// x's type is identical to T
   215  	if Identical(V, T) {
   216  		return true
   217  	}
   218  
   219  	Vu := V.Underlying()
   220  	Tu := T.Underlying()
   221  
   222  	// x is an untyped value representable by a value of type T
   223  	// TODO(gri) This is borrowing from checker.convertUntyped and
   224  	//           checker.representable. Need to clean up.
   225  	if isUntyped(Vu) {
   226  		switch t := Tu.(type) {
   227  		case *Basic:
   228  			if x.isNil() && t.kind == UnsafePointer {
   229  				return true
   230  			}
   231  			if x.mode == constant_ {
   232  				return representableConst(x.val, conf, t.kind, nil)
   233  			}
   234  			// The result of a comparison is an untyped boolean,
   235  			// but may not be a constant.
   236  			if Vb, _ := Vu.(*Basic); Vb != nil {
   237  				return Vb.kind == UntypedBool && isBoolean(Tu)
   238  			}
   239  		case *Interface:
   240  			return x.isNil() || t.Empty()
   241  		case *Pointer, *Signature, *Slice, *Map, *Chan:
   242  			return x.isNil()
   243  		}
   244  	}
   245  	// Vu is typed
   246  
   247  	// x's type V and T have identical underlying types
   248  	// and at least one of V or T is not a named type
   249  	if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
   250  		return true
   251  	}
   252  
   253  	// T is an interface type and x implements T
   254  	if Ti, ok := Tu.(*Interface); ok {
   255  		if m, wrongType := MissingMethod(x.typ, Ti, true); m != nil /* Implements(x.typ, Ti) */ {
   256  			if reason != nil {
   257  				if wrongType {
   258  					*reason = "wrong type for method " + m.Name()
   259  				} else {
   260  					*reason = "missing method " + m.Name()
   261  				}
   262  			}
   263  			return false
   264  		}
   265  		return true
   266  	}
   267  
   268  	// x is a bidirectional channel value, T is a channel
   269  	// type, x's type V and T have identical element types,
   270  	// and at least one of V or T is not a named type
   271  	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
   272  		if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
   273  			return !isNamed(V) || !isNamed(T)
   274  		}
   275  	}
   276  
   277  	return false
   278  }
   279  
   280  // isInteger reports whether x is value of integer type
   281  // or an untyped constant representable as an integer.
   282  func (x *operand) isInteger() bool {
   283  	return x.mode == invalid ||
   284  		isInteger(x.typ) ||
   285  		isUntyped(x.typ) && x.mode == constant_ && representableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt
   286  }