libgo: update to go1.9
[official-gcc.git] / libgo / go / go / types / operand.go
blob07247bd6f58831a3f4ba3b4854a6de2e644bc21d
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.
7 package types
9 import (
10 "bytes"
11 "go/ast"
12 "go/constant"
13 "go/token"
16 // An operandMode specifies the (addressing) mode of an operand.
17 type operandMode byte
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
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",
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.
49 type operand struct {
50 mode operandMode
51 expr ast.Expr
52 typ Type
53 val constant.Value
54 id builtinId
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
62 if x.expr == nil {
63 return token.NoPos
65 return x.expr.Pos()
68 // Operand string formats
69 // (not all "untyped" cases can appear due to the type system,
70 // but they fall out naturally here)
72 // mode format
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 {
97 var buf bytes.Buffer
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()
113 // <expr> (
114 if expr != "" {
115 buf.WriteString(expr)
116 buf.WriteString(" (")
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
132 hasType = true
136 // <mode>
137 buf.WriteString(operandModeString[x.mode])
139 // <val>
140 if x.mode == constant_ {
141 if s := x.val.String(); s != expr {
142 buf.WriteByte(' ')
143 buf.WriteString(s)
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")
157 // )
158 if expr != "" {
159 buf.WriteByte(')')
162 return buf.String()
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) {
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()
187 x.mode = constant_
188 x.typ = Typ[kind]
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
209 V := x.typ
211 // x's type is identical to T
212 if Identical(V, T) {
213 return true
216 Vu := V.Underlying()
217 Tu := T.Underlying()
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.
222 if isUntyped(Vu) {
223 switch t := Tu.(type) {
224 case *Basic:
225 if x.isNil() && t.kind == UnsafePointer {
226 return true
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)
236 case *Interface:
237 return x.isNil() || t.Empty()
238 case *Pointer, *Signature, *Slice, *Map, *Chan:
239 return x.isNil()
242 // Vu is typed
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)) {
247 return true
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) */ {
253 if reason != nil {
254 if wrongType {
255 *reason = "wrong type for method " + m.Name()
256 } else {
257 *reason = "missing method " + m.Name()
260 return false
262 return true
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)
274 return false