github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/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 "go/constant" 12 "go/token" 13 "go/types" 14 "strconv" 15 "strings" 16 17 "golang.org/x/tools/internal/typeparams" 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(typeSetOf(typ), func(t types.Type) bool { 49 var c types.BasicInfo 50 if t, ok := t.(*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 = zeroString(c.typ, 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 // zeroString returns the string representation of the "zero" value of the type t. 97 func zeroString(t types.Type, from *types.Package) string { 98 switch t := t.(type) { 99 case *types.Basic: 100 switch { 101 case t.Info()&types.IsBoolean != 0: 102 return "false" 103 case t.Info()&types.IsNumeric != 0: 104 return "0" 105 case t.Info()&types.IsString != 0: 106 return `""` 107 case t.Kind() == types.UnsafePointer: 108 fallthrough 109 case t.Kind() == types.UntypedNil: 110 return "nil" 111 default: 112 panic(fmt.Sprint("zeroString for unexpected type:", t)) 113 } 114 case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: 115 return "nil" 116 case *types.Named: 117 return zeroString(t.Underlying(), from) 118 case *types.Array, *types.Struct: 119 return relType(t, from) + "{}" 120 case *types.Tuple: 121 // Tuples are not normal values. 122 // We are currently format as "(t[0], ..., t[n])". Could be something else. 123 components := make([]string, t.Len()) 124 for i := 0; i < t.Len(); i++ { 125 components[i] = zeroString(t.At(i).Type(), from) 126 } 127 return "(" + strings.Join(components, ", ") + ")" 128 case *typeparams.TypeParam: 129 return "*new(" + relType(t, from) + ")" 130 } 131 panic(fmt.Sprint("zeroString: unexpected ", t)) 132 } 133 134 func (c *Const) Name() string { 135 return c.RelString(nil) 136 } 137 138 func (c *Const) String() string { 139 return c.Name() 140 } 141 142 func (c *Const) Type() types.Type { 143 return c.typ 144 } 145 146 func (c *Const) Referrers() *[]Instruction { 147 return nil 148 } 149 150 func (c *Const) Parent() *Function { return nil } 151 152 func (c *Const) Pos() token.Pos { 153 return token.NoPos 154 } 155 156 // IsNil returns true if this constant is a nil value of 157 // a nillable reference type (pointer, slice, channel, map, or function), 158 // a basic interface type, or 159 // a type parameter all of whose possible instantiations are themselves nillable. 160 func (c *Const) IsNil() bool { 161 return c.Value == nil && nillable(c.typ) 162 } 163 164 // nillable reports whether *new(T) == nil is legal for type T. 165 func nillable(t types.Type) bool { 166 if typeparams.IsTypeParam(t) { 167 return underIs(typeSetOf(t), func(u types.Type) bool { 168 // empty type set (u==nil) => any underlying types => not nillable 169 return u != nil && nillable(u) 170 }) 171 } 172 switch t.Underlying().(type) { 173 case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature: 174 return true 175 case *types.Interface: 176 return true // basic interface. 177 default: 178 return false 179 } 180 } 181 182 // TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp. 183 184 // Int64 returns the numeric value of this constant truncated to fit 185 // a signed 64-bit integer. 186 func (c *Const) Int64() int64 { 187 switch x := constant.ToInt(c.Value); x.Kind() { 188 case constant.Int: 189 if i, ok := constant.Int64Val(x); ok { 190 return i 191 } 192 return 0 193 case constant.Float: 194 f, _ := constant.Float64Val(x) 195 return int64(f) 196 } 197 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 198 } 199 200 // Uint64 returns the numeric value of this constant truncated to fit 201 // an unsigned 64-bit integer. 202 func (c *Const) Uint64() uint64 { 203 switch x := constant.ToInt(c.Value); x.Kind() { 204 case constant.Int: 205 if u, ok := constant.Uint64Val(x); ok { 206 return u 207 } 208 return 0 209 case constant.Float: 210 f, _ := constant.Float64Val(x) 211 return uint64(f) 212 } 213 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 214 } 215 216 // Float64 returns the numeric value of this constant truncated to fit 217 // a float64. 218 func (c *Const) Float64() float64 { 219 x := constant.ToFloat(c.Value) // (c.Value == nil) => x.Kind() == Unknown 220 f, _ := constant.Float64Val(x) 221 return f 222 } 223 224 // Complex128 returns the complex value of this constant truncated to 225 // fit a complex128. 226 func (c *Const) Complex128() complex128 { 227 x := constant.ToComplex(c.Value) // (c.Value == nil) => x.Kind() == Unknown 228 re, _ := constant.Float64Val(constant.Real(x)) 229 im, _ := constant.Float64Val(constant.Imag(x)) 230 return complex(re, im) 231 }