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.
5 // This file defines operands and associated operations.
16 // An operandMode specifies the (addressing) mode of an operand.
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
31 var operandModeString
= [...]string{
32 invalid
: "invalid operand",
36 constant_
: "constant",
38 mapindex
: "map index expression",
40 commaok
: "comma, ok expression",
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.
57 // pos returns the position of the expression corresponding to x.
58 // If x is invalid the position is token.NoPos.
60 func (x
*operand
) pos() token
.Pos
{
61 // x.expr may not be set if x is invalid
68 // Operand string formats
69 // (not all "untyped" cases can appear due to the type system,
70 // but they fall out naturally here)
74 // invalid <expr> ( <mode> )
75 // novalue <expr> ( <mode> )
76 // builtin <expr> ( <mode> )
77 // typexpr <expr> ( <mode> )
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>)
84 // variable <expr> (<untyped kind> <mode> )
85 // variable <expr> ( <mode> of type <typ>)
87 // mapindex <expr> (<untyped kind> <mode> )
88 // mapindex <expr> ( <mode> of type <typ>)
90 // value <expr> (<untyped kind> <mode> )
91 // value <expr> ( <mode> of type <typ>)
93 // commaok <expr> (<untyped kind> <mode> )
94 // commaok <expr> ( <mode> of type <typ>)
96 func operandString(x
*operand
, qf Qualifier
) string {
101 expr
= ExprString(x
.expr
)
105 expr
= predeclaredFuncs
[x
.id
].name
107 expr
= TypeString(x
.typ
, qf
)
109 expr
= x
.val
.String()
115 buf
.WriteString(expr
)
116 buf
.WriteString(" (")
122 case invalid
, novalue
, builtin
, typexpr
:
125 // should have a type, but be cautious (don't crash during printing)
127 if isUntyped(x
.typ
) {
128 buf
.WriteString(x
.typ
.(*Basic
).name
)
137 buf
.WriteString(operandModeString
[x
.mode
])
140 if x
.mode
== constant_
{
141 if s
:= x
.val
.String(); s
!= expr
{
149 if x
.typ
!= Typ
[Invalid
] {
150 buf
.WriteString(" of type ")
151 WriteType(&buf
, x
.typ
, qf
)
153 buf
.WriteString(" with invalid type")
165 func (x
*operand
) String() string {
166 return operandString(x
, nil)
169 // setConst sets x to the untyped constant for literal lit.
170 func (x
*operand
) setConst(tok token
.Token
, lit
string) {
178 kind
= UntypedComplex
189 x
.val
= constant
.MakeFromLiteral(lit
, tok
, 0)
192 // isNil reports whether x is the nil value.
193 func (x
*operand
) isNil() bool {
194 return x
.mode
== value
&& x
.typ
== Typ
[UntypedNil
]
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.
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 func (x
*operand
) assignableTo(conf
*Config
, T Type
, reason
*string) bool {
205 if x
.mode
== invalid || T
== Typ
[Invalid
] {
206 return true // avoid spurious errors
211 // x's type is identical to T
219 // x is an untyped value representable by a value of type T
220 // TODO(gri) This is borrowing from checker.convertUntyped and
221 // checker.representable. Need to clean up.
223 switch t
:= Tu
.(type) {
225 if x
.isNil() && t
.kind
== UnsafePointer
{
228 if x
.mode
== constant_
{
229 return representableConst(x
.val
, conf
, t
, nil)
231 // The result of a comparison is an untyped boolean,
232 // but may not be a constant.
233 if Vb
, _
:= Vu
.(*Basic
); Vb
!= nil {
234 return Vb
.kind
== UntypedBool
&& isBoolean(Tu
)
237 return x
.isNil() || t
.Empty()
238 case *Pointer
, *Signature
, *Slice
, *Map
, *Chan
:
244 // x's type V and T have identical underlying types
245 // and at least one of V or T is not a named type
246 if Identical(Vu
, Tu
) && (!isNamed(V
) ||
!isNamed(T
)) {
250 // T is an interface type and x implements T
251 if Ti
, ok
:= Tu
.(*Interface
); ok
{
252 if m
, wrongType
:= MissingMethod(x
.typ
, Ti
, true); m
!= nil /* Implements(x.typ, Ti) */ {
255 *reason
= "wrong type for method " + m
.Name()
257 *reason
= "missing method " + m
.Name()
265 // x is a bidirectional channel value, T is a channel
266 // type, x's type V and T have identical element types,
267 // and at least one of V or T is not a named type
268 if Vc
, ok
:= Vu
.(*Chan
); ok
&& Vc
.dir
== SendRecv
{
269 if Tc
, ok
:= Tu
.(*Chan
); ok
&& Identical(Vc
.elem
, Tc
.elem
) {
270 return !isNamed(V
) ||
!isNamed(T
)