github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/ssa/const.go (about) 1 // Copyright 2013 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 package ssa 6 7 // This file defines the Const SSA value type. 8 9 import ( 10 "fmt" 11 exact "go/constant" 12 "go/token" 13 "go/types" 14 "strconv" 15 ) 16 17 // NewConst returns a new constant of the specified value and type. 18 // val must be valid according to the specification of Const.Value. 19 // 20 func NewConst(val exact.Value, typ types.Type) *Const { 21 return &Const{typ, val} 22 } 23 24 // intConst returns an 'int' constant that evaluates to i. 25 // (i is an int64 in case the host is narrower than the target.) 26 func intConst(i int64) *Const { 27 return NewConst(exact.MakeInt64(i), tInt) 28 } 29 30 // nilConst returns a nil constant of the specified type, which may 31 // be any reference type, including interfaces. 32 // 33 func nilConst(typ types.Type) *Const { 34 return NewConst(nil, typ) 35 } 36 37 // stringConst returns a 'string' constant that evaluates to s. 38 func stringConst(s string) *Const { 39 return NewConst(exact.MakeString(s), tString) 40 } 41 42 // zeroConst returns a new "zero" constant of the specified type, 43 // which must not be an array or struct type: the zero values of 44 // aggregates are well-defined but cannot be represented by Const. 45 // 46 func zeroConst(t types.Type) *Const { 47 switch t := t.(type) { 48 case *types.Basic: 49 switch { 50 case t.Info()&types.IsBoolean != 0: 51 return NewConst(exact.MakeBool(false), t) 52 case t.Info()&types.IsNumeric != 0: 53 return NewConst(exact.MakeInt64(0), t) 54 case t.Info()&types.IsString != 0: 55 return NewConst(exact.MakeString(""), t) 56 case t.Kind() == types.UnsafePointer: 57 fallthrough 58 case t.Kind() == types.UntypedNil: 59 return nilConst(t) 60 default: 61 panic(fmt.Sprint("zeroConst for unexpected type:", t)) 62 } 63 case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: 64 return nilConst(t) 65 case *types.Named: 66 return NewConst(zeroConst(t.Underlying()).Value, t) 67 case *types.Array, *types.Struct, *types.Tuple: 68 panic(fmt.Sprint("zeroConst applied to aggregate:", t)) 69 } 70 panic(fmt.Sprint("zeroConst: unexpected ", t)) 71 } 72 73 func (c *Const) RelString(from *types.Package) string { 74 var s string 75 if c.Value == nil { 76 s = "nil" 77 } else if c.Value.Kind() == exact.String { 78 s = exact.StringVal(c.Value) 79 const max = 20 80 // TODO(adonovan): don't cut a rune in half. 81 if len(s) > max { 82 s = s[:max-3] + "..." // abbreviate 83 } 84 s = strconv.Quote(s) 85 } else { 86 s = c.Value.String() 87 } 88 return s + ":" + relType(c.Type(), from) 89 } 90 91 func (c *Const) Name() string { 92 return c.RelString(nil) 93 } 94 95 func (c *Const) String() string { 96 return c.Name() 97 } 98 99 func (c *Const) Type() types.Type { 100 return c.typ 101 } 102 103 func (c *Const) Referrers() *[]Instruction { 104 return nil 105 } 106 107 func (c *Const) Parent() *Function { return nil } 108 109 func (c *Const) Pos() token.Pos { 110 return token.NoPos 111 } 112 113 // IsNil returns true if this constant represents a typed or untyped nil value. 114 func (c *Const) IsNil() bool { 115 return c.Value == nil 116 } 117 118 // TODO(adonovan): move everything below into github.com/golangci/go-tools/ssa/interp. 119 120 // Int64 returns the numeric value of this constant truncated to fit 121 // a signed 64-bit integer. 122 // 123 func (c *Const) Int64() int64 { 124 switch x := exact.ToInt(c.Value); x.Kind() { 125 case exact.Int: 126 if i, ok := exact.Int64Val(x); ok { 127 return i 128 } 129 return 0 130 case exact.Float: 131 f, _ := exact.Float64Val(x) 132 return int64(f) 133 } 134 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 135 } 136 137 // Uint64 returns the numeric value of this constant truncated to fit 138 // an unsigned 64-bit integer. 139 // 140 func (c *Const) Uint64() uint64 { 141 switch x := exact.ToInt(c.Value); x.Kind() { 142 case exact.Int: 143 if u, ok := exact.Uint64Val(x); ok { 144 return u 145 } 146 return 0 147 case exact.Float: 148 f, _ := exact.Float64Val(x) 149 return uint64(f) 150 } 151 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 152 } 153 154 // Float64 returns the numeric value of this constant truncated to fit 155 // a float64. 156 // 157 func (c *Const) Float64() float64 { 158 f, _ := exact.Float64Val(c.Value) 159 return f 160 } 161 162 // Complex128 returns the complex value of this constant truncated to 163 // fit a complex128. 164 // 165 func (c *Const) Complex128() complex128 { 166 re, _ := exact.Float64Val(exact.Real(c.Value)) 167 im, _ := exact.Float64Val(exact.Imag(c.Value)) 168 return complex(re, im) 169 }