const.go (5274B)
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 "go/constant" 12 "go/token" 13 "go/types" 14 "strconv" 15 16 "golang.org/x/tools/internal/typeparams" 17 "golang.org/x/tools/internal/typesinternal" 18 ) 19 20 // NewConst returns a new constant of the specified value and type. 21 // val must be valid according to the specification of Const.Value. 22 func NewConst(val constant.Value, typ types.Type) *Const { 23 if val == nil { 24 switch soleTypeKind(typ) { 25 case types.IsBoolean: 26 val = constant.MakeBool(false) 27 case types.IsInteger: 28 val = constant.MakeInt64(0) 29 case types.IsString: 30 val = constant.MakeString("") 31 } 32 } 33 return &Const{typ, val} 34 } 35 36 // soleTypeKind returns a BasicInfo for which constant.Value can 37 // represent all zero values for the types in the type set. 38 // 39 // types.IsBoolean for false is a representative. 40 // types.IsInteger for 0 41 // types.IsString for "" 42 // 0 otherwise. 43 func soleTypeKind(typ types.Type) types.BasicInfo { 44 // State records the set of possible zero values (false, 0, ""). 45 // Candidates (perhaps all) are eliminated during the type-set 46 // iteration, which executes at least once. 47 state := types.IsBoolean | types.IsInteger | types.IsString 48 underIs(typ, func(ut types.Type) bool { 49 var c types.BasicInfo 50 if t, ok := ut.(*types.Basic); ok { 51 c = t.Info() 52 } 53 if c&types.IsNumeric != 0 { // int/float/complex 54 c = types.IsInteger 55 } 56 state = state & c 57 return state != 0 58 }) 59 return state 60 } 61 62 // intConst returns an 'int' constant that evaluates to i. 63 // (i is an int64 in case the host is narrower than the target.) 64 func intConst(i int64) *Const { 65 return NewConst(constant.MakeInt64(i), tInt) 66 } 67 68 // stringConst returns a 'string' constant that evaluates to s. 69 func stringConst(s string) *Const { 70 return NewConst(constant.MakeString(s), tString) 71 } 72 73 // zeroConst returns a new "zero" constant of the specified type. 74 func zeroConst(t types.Type) *Const { 75 return NewConst(nil, t) 76 } 77 78 func (c *Const) RelString(from *types.Package) string { 79 var s string 80 if c.Value == nil { 81 s, _ = typesinternal.ZeroString(c.typ, types.RelativeTo(from)) 82 } else if c.Value.Kind() == constant.String { 83 s = constant.StringVal(c.Value) 84 const max = 20 85 // TODO(adonovan): don't cut a rune in half. 86 if len(s) > max { 87 s = s[:max-3] + "..." // abbreviate 88 } 89 s = strconv.Quote(s) 90 } else { 91 s = c.Value.String() 92 } 93 return s + ":" + relType(c.Type(), from) 94 } 95 96 func (c *Const) Name() string { 97 return c.RelString(nil) 98 } 99 100 func (c *Const) String() string { 101 return c.Name() 102 } 103 104 func (c *Const) Type() types.Type { 105 return c.typ 106 } 107 108 func (c *Const) Referrers() *[]Instruction { 109 return nil 110 } 111 112 func (c *Const) Parent() *Function { return nil } 113 114 func (c *Const) Pos() token.Pos { 115 return token.NoPos 116 } 117 118 // IsNil returns true if this constant is a nil value of 119 // a nillable reference type (pointer, slice, channel, map, or function), 120 // a basic interface type, or 121 // a type parameter all of whose possible instantiations are themselves nillable. 122 func (c *Const) IsNil() bool { 123 return c.Value == nil && nillable(c.typ) 124 } 125 126 // nillable reports whether *new(T) == nil is legal for type T. 127 func nillable(t types.Type) bool { 128 if typeparams.IsTypeParam(t) { 129 return underIs(t, func(u types.Type) bool { 130 // empty type set (u==nil) => any underlying types => not nillable 131 return u != nil && nillable(u) 132 }) 133 } 134 switch t := t.Underlying().(type) { 135 case *types.Basic: 136 return t.Kind() == types.UnsafePointer 137 case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature: 138 return true 139 case *types.Interface: 140 return true // basic interface. 141 default: 142 return false 143 } 144 } 145 146 // TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp. 147 148 // Int64 returns the numeric value of this constant truncated to fit 149 // a signed 64-bit integer. 150 func (c *Const) Int64() int64 { 151 switch x := constant.ToInt(c.Value); x.Kind() { 152 case constant.Int: 153 if i, ok := constant.Int64Val(x); ok { 154 return i 155 } 156 return 0 157 case constant.Float: 158 f, _ := constant.Float64Val(x) 159 return int64(f) 160 } 161 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 162 } 163 164 // Uint64 returns the numeric value of this constant truncated to fit 165 // an unsigned 64-bit integer. 166 func (c *Const) Uint64() uint64 { 167 switch x := constant.ToInt(c.Value); x.Kind() { 168 case constant.Int: 169 if u, ok := constant.Uint64Val(x); ok { 170 return u 171 } 172 return 0 173 case constant.Float: 174 f, _ := constant.Float64Val(x) 175 return uint64(f) 176 } 177 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 178 } 179 180 // Float64 returns the numeric value of this constant truncated to fit 181 // a float64. 182 func (c *Const) Float64() float64 { 183 x := constant.ToFloat(c.Value) // (c.Value == nil) => x.Kind() == Unknown 184 f, _ := constant.Float64Val(x) 185 return f 186 } 187 188 // Complex128 returns the complex value of this constant truncated to 189 // fit a complex128. 190 func (c *Const) Complex128() complex128 { 191 x := constant.ToComplex(c.Value) // (c.Value == nil) => x.Kind() == Unknown 192 re, _ := constant.Float64Val(constant.Real(x)) 193 im, _ := constant.Float64Val(constant.Imag(x)) 194 return complex(re, im) 195 }