...
1
2
3
4
5 package ssa
6
7
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/aliases"
18 "golang.org/x/tools/internal/typeparams"
19 )
20
21
22
23 func NewConst(val constant.Value, typ types.Type) *Const {
24 if val == nil {
25 switch soleTypeKind(typ) {
26 case types.IsBoolean:
27 val = constant.MakeBool(false)
28 case types.IsInteger:
29 val = constant.MakeInt64(0)
30 case types.IsString:
31 val = constant.MakeString("")
32 }
33 }
34 return &Const{typ, val}
35 }
36
37
38
39
40
41
42
43
44 func soleTypeKind(typ types.Type) types.BasicInfo {
45
46
47
48 state := types.IsBoolean | types.IsInteger | types.IsString
49 underIs(typeSetOf(typ), func(ut types.Type) bool {
50 var c types.BasicInfo
51 if t, ok := ut.(*types.Basic); ok {
52 c = t.Info()
53 }
54 if c&types.IsNumeric != 0 {
55 c = types.IsInteger
56 }
57 state = state & c
58 return state != 0
59 })
60 return state
61 }
62
63
64
65 func intConst(i int64) *Const {
66 return NewConst(constant.MakeInt64(i), tInt)
67 }
68
69
70 func stringConst(s string) *Const {
71 return NewConst(constant.MakeString(s), tString)
72 }
73
74
75 func zeroConst(t types.Type) *Const {
76 return NewConst(nil, t)
77 }
78
79 func (c *Const) RelString(from *types.Package) string {
80 var s string
81 if c.Value == nil {
82 s = zeroString(c.typ, from)
83 } else if c.Value.Kind() == constant.String {
84 s = constant.StringVal(c.Value)
85 const max = 20
86
87 if len(s) > max {
88 s = s[:max-3] + "..."
89 }
90 s = strconv.Quote(s)
91 } else {
92 s = c.Value.String()
93 }
94 return s + ":" + relType(c.Type(), from)
95 }
96
97
98 func zeroString(t types.Type, from *types.Package) string {
99 switch t := t.(type) {
100 case *types.Basic:
101 switch {
102 case t.Info()&types.IsBoolean != 0:
103 return "false"
104 case t.Info()&types.IsNumeric != 0:
105 return "0"
106 case t.Info()&types.IsString != 0:
107 return `""`
108 case t.Kind() == types.UnsafePointer:
109 fallthrough
110 case t.Kind() == types.UntypedNil:
111 return "nil"
112 default:
113 panic(fmt.Sprint("zeroString for unexpected type:", t))
114 }
115 case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
116 return "nil"
117 case *types.Named, *aliases.Alias:
118 return zeroString(t.Underlying(), from)
119 case *types.Array, *types.Struct:
120 return relType(t, from) + "{}"
121 case *types.Tuple:
122
123
124 components := make([]string, t.Len())
125 for i := 0; i < t.Len(); i++ {
126 components[i] = zeroString(t.At(i).Type(), from)
127 }
128 return "(" + strings.Join(components, ", ") + ")"
129 case *types.TypeParam:
130 return "*new(" + relType(t, from) + ")"
131 }
132 panic(fmt.Sprint("zeroString: unexpected ", t))
133 }
134
135 func (c *Const) Name() string {
136 return c.RelString(nil)
137 }
138
139 func (c *Const) String() string {
140 return c.Name()
141 }
142
143 func (c *Const) Type() types.Type {
144 return c.typ
145 }
146
147 func (c *Const) Referrers() *[]Instruction {
148 return nil
149 }
150
151 func (c *Const) Parent() *Function { return nil }
152
153 func (c *Const) Pos() token.Pos {
154 return token.NoPos
155 }
156
157
158
159
160
161 func (c *Const) IsNil() bool {
162 return c.Value == nil && nillable(c.typ)
163 }
164
165
166 func nillable(t types.Type) bool {
167 if typeparams.IsTypeParam(t) {
168 return underIs(typeSetOf(t), func(u types.Type) bool {
169
170 return u != nil && nillable(u)
171 })
172 }
173 switch t.Underlying().(type) {
174 case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
175 return true
176 case *types.Interface:
177 return true
178 default:
179 return false
180 }
181 }
182
183
184
185
186
187 func (c *Const) Int64() int64 {
188 switch x := constant.ToInt(c.Value); x.Kind() {
189 case constant.Int:
190 if i, ok := constant.Int64Val(x); ok {
191 return i
192 }
193 return 0
194 case constant.Float:
195 f, _ := constant.Float64Val(x)
196 return int64(f)
197 }
198 panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
199 }
200
201
202
203 func (c *Const) Uint64() uint64 {
204 switch x := constant.ToInt(c.Value); x.Kind() {
205 case constant.Int:
206 if u, ok := constant.Uint64Val(x); ok {
207 return u
208 }
209 return 0
210 case constant.Float:
211 f, _ := constant.Float64Val(x)
212 return uint64(f)
213 }
214 panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
215 }
216
217
218
219 func (c *Const) Float64() float64 {
220 x := constant.ToFloat(c.Value)
221 f, _ := constant.Float64Val(x)
222 return f
223 }
224
225
226
227 func (c *Const) Complex128() complex128 {
228 x := constant.ToComplex(c.Value)
229 re, _ := constant.Float64Val(constant.Real(x))
230 im, _ := constant.Float64Val(constant.Imag(x))
231 return complex(re, im)
232 }
233
View as plain text