...

Source file src/go/types/operand.go

Documentation: go/types

		 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  	"fmt"
		12  	"go/ast"
		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  	commaok											// like value, but operand may be used in a comma,ok expression
		30  	commaerr										 // like commaok, but second value is error, not boolean
		31  	cgofunc											// operand is a cgo function
		32  )
		33  
		34  var operandModeString = [...]string{
		35  	invalid:	 "invalid operand",
		36  	novalue:	 "no value",
		37  	builtin:	 "built-in",
		38  	typexpr:	 "type",
		39  	constant_: "constant",
		40  	variable:	"variable",
		41  	mapindex:	"map index expression",
		42  	value:		 "value",
		43  	commaok:	 "comma, ok expression",
		44  	commaerr:	"comma, error expression",
		45  	cgofunc:	 "cgo function",
		46  }
		47  
		48  // An operand represents an intermediate value during type checking.
		49  // Operands have an (addressing) mode, the expression evaluating to
		50  // the operand, the operand's type, a value for constants, and an id
		51  // for built-in functions.
		52  // The zero value of operand is a ready to use invalid operand.
		53  //
		54  type operand struct {
		55  	mode operandMode
		56  	expr ast.Expr
		57  	typ	Type
		58  	val	constant.Value
		59  	id	 builtinId
		60  }
		61  
		62  // Pos returns the position of the expression corresponding to x.
		63  // If x is invalid the position is token.NoPos.
		64  //
		65  func (x *operand) Pos() token.Pos {
		66  	// x.expr may not be set if x is invalid
		67  	if x.expr == nil {
		68  		return token.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  // commaok		<expr> (<untyped kind> <mode>										)
		99  // commaok		<expr> (							 <mode>			 of type <typ>)
	 100  //
	 101  // commaerr	 <expr> (<untyped kind> <mode>										)
	 102  // commaerr	 <expr> (							 <mode>			 of type <typ>)
	 103  //
	 104  // cgofunc		<expr> (<untyped kind> <mode>										)
	 105  // cgofunc		<expr> (							 <mode>			 of type <typ>)
	 106  //
	 107  func operandString(x *operand, qf Qualifier) string {
	 108  	var buf bytes.Buffer
	 109  
	 110  	var expr string
	 111  	if x.expr != nil {
	 112  		expr = ExprString(x.expr)
	 113  	} else {
	 114  		switch x.mode {
	 115  		case builtin:
	 116  			expr = predeclaredFuncs[x.id].name
	 117  		case typexpr:
	 118  			expr = TypeString(x.typ, qf)
	 119  		case constant_:
	 120  			expr = x.val.String()
	 121  		}
	 122  	}
	 123  
	 124  	// <expr> (
	 125  	if expr != "" {
	 126  		buf.WriteString(expr)
	 127  		buf.WriteString(" (")
	 128  	}
	 129  
	 130  	// <untyped kind>
	 131  	hasType := false
	 132  	switch x.mode {
	 133  	case invalid, novalue, builtin, typexpr:
	 134  		// no type
	 135  	default:
	 136  		// should have a type, but be cautious (don't crash during printing)
	 137  		if x.typ != nil {
	 138  			if isUntyped(x.typ) {
	 139  				buf.WriteString(x.typ.(*Basic).name)
	 140  				buf.WriteByte(' ')
	 141  				break
	 142  			}
	 143  			hasType = true
	 144  		}
	 145  	}
	 146  
	 147  	// <mode>
	 148  	buf.WriteString(operandModeString[x.mode])
	 149  
	 150  	// <val>
	 151  	if x.mode == constant_ {
	 152  		if s := x.val.String(); s != expr {
	 153  			buf.WriteByte(' ')
	 154  			buf.WriteString(s)
	 155  		}
	 156  	}
	 157  
	 158  	// <typ>
	 159  	if hasType {
	 160  		if x.typ != Typ[Invalid] {
	 161  			var intro string
	 162  			switch {
	 163  			case isGeneric(x.typ):
	 164  				intro = " of generic type "
	 165  			case asTypeParam(x.typ) != nil:
	 166  				intro = " of type parameter type "
	 167  			default:
	 168  				intro = " of type "
	 169  			}
	 170  			buf.WriteString(intro)
	 171  			WriteType(&buf, x.typ, qf)
	 172  		} else {
	 173  			buf.WriteString(" with invalid type")
	 174  		}
	 175  	}
	 176  
	 177  	// )
	 178  	if expr != "" {
	 179  		buf.WriteByte(')')
	 180  	}
	 181  
	 182  	return buf.String()
	 183  }
	 184  
	 185  func (x *operand) String() string {
	 186  	return operandString(x, nil)
	 187  }
	 188  
	 189  // setConst sets x to the untyped constant for literal lit.
	 190  func (x *operand) setConst(tok token.Token, lit string) {
	 191  	var kind BasicKind
	 192  	switch tok {
	 193  	case token.INT:
	 194  		kind = UntypedInt
	 195  	case token.FLOAT:
	 196  		kind = UntypedFloat
	 197  	case token.IMAG:
	 198  		kind = UntypedComplex
	 199  	case token.CHAR:
	 200  		kind = UntypedRune
	 201  	case token.STRING:
	 202  		kind = UntypedString
	 203  	default:
	 204  		unreachable()
	 205  	}
	 206  
	 207  	val := constant.MakeFromLiteral(lit, tok, 0)
	 208  	if val.Kind() == constant.Unknown {
	 209  		x.mode = invalid
	 210  		x.typ = Typ[Invalid]
	 211  		return
	 212  	}
	 213  	x.mode = constant_
	 214  	x.typ = Typ[kind]
	 215  	x.val = val
	 216  }
	 217  
	 218  // isNil reports whether x is the nil value.
	 219  func (x *operand) isNil() bool {
	 220  	return x.mode == value && x.typ == Typ[UntypedNil]
	 221  }
	 222  
	 223  // assignableTo reports whether x is assignable to a variable of type T. If the
	 224  // result is false and a non-nil reason is provided, it may be set to a more
	 225  // detailed explanation of the failure (result != ""). The returned error code
	 226  // is only valid if the (first) result is false. The check parameter may be nil
	 227  // if assignableTo is invoked through an exported API call, i.e., when all
	 228  // methods have been type-checked.
	 229  func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
	 230  	if x.mode == invalid || T == Typ[Invalid] {
	 231  		return true, 0 // avoid spurious errors
	 232  	}
	 233  
	 234  	V := x.typ
	 235  
	 236  	// x's type is identical to T
	 237  	if check.identical(V, T) {
	 238  		return true, 0
	 239  	}
	 240  
	 241  	Vu := optype(V)
	 242  	Tu := optype(T)
	 243  
	 244  	// x is an untyped value representable by a value of type T.
	 245  	if isUntyped(Vu) {
	 246  		if t, ok := Tu.(*_Sum); ok {
	 247  			return t.is(func(t Type) bool {
	 248  				// TODO(gri) this could probably be more efficient
	 249  				ok, _ := x.assignableTo(check, t, reason)
	 250  				return ok
	 251  			}), _IncompatibleAssign
	 252  		}
	 253  		newType, _, _ := check.implicitTypeAndValue(x, Tu)
	 254  		return newType != nil, _IncompatibleAssign
	 255  	}
	 256  	// Vu is typed
	 257  
	 258  	// x's type V and T have identical underlying types
	 259  	// and at least one of V or T is not a named type
	 260  	if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
	 261  		return true, 0
	 262  	}
	 263  
	 264  	// T is an interface type and x implements T
	 265  	if Ti, ok := Tu.(*Interface); ok {
	 266  		if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
	 267  			if reason != nil {
	 268  				if wrongType != nil {
	 269  					if check.identical(m.typ, wrongType.typ) {
	 270  						*reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
	 271  					} else {
	 272  						*reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
	 273  					}
	 274  
	 275  				} else {
	 276  					*reason = "missing method " + m.Name()
	 277  				}
	 278  			}
	 279  			return false, _InvalidIfaceAssign
	 280  		}
	 281  		return true, 0
	 282  	}
	 283  
	 284  	// x is a bidirectional channel value, T is a channel
	 285  	// type, x's type V and T have identical element types,
	 286  	// and at least one of V or T is not a named type
	 287  	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
	 288  		if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) {
	 289  			return !isNamed(V) || !isNamed(T), _InvalidChanAssign
	 290  		}
	 291  	}
	 292  
	 293  	return false, _IncompatibleAssign
	 294  }
	 295  

View as plain text