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 }