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.Underlying().(type) {
135 case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
136 return true
137 case *types.Interface:
138 return true // basic interface.
139 default:
140 return false
141 }
142 }
143 144 // TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp.
145 146 // Int64 returns the numeric value of this constant truncated to fit
147 // a signed 64-bit integer.
148 func (c *Const) Int64() int64 {
149 switch x := constant.ToInt(c.Value); x.Kind() {
150 case constant.Int:
151 if i, ok := constant.Int64Val(x); ok {
152 return i
153 }
154 return 0
155 case constant.Float:
156 f, _ := constant.Float64Val(x)
157 return int64(f)
158 }
159 panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
160 }
161 162 // Uint64 returns the numeric value of this constant truncated to fit
163 // an unsigned 64-bit integer.
164 func (c *Const) Uint64() uint64 {
165 switch x := constant.ToInt(c.Value); x.Kind() {
166 case constant.Int:
167 if u, ok := constant.Uint64Val(x); ok {
168 return u
169 }
170 return 0
171 case constant.Float:
172 f, _ := constant.Float64Val(x)
173 return uint64(f)
174 }
175 panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
176 }
177 178 // Float64 returns the numeric value of this constant truncated to fit
179 // a float64.
180 func (c *Const) Float64() float64 {
181 x := constant.ToFloat(c.Value) // (c.Value == nil) => x.Kind() == Unknown
182 f, _ := constant.Float64Val(x)
183 return f
184 }
185 186 // Complex128 returns the complex value of this constant truncated to
187 // fit a complex128.
188 func (c *Const) Complex128() complex128 {
189 x := constant.ToComplex(c.Value) // (c.Value == nil) => x.Kind() == Unknown
190 re, _ := constant.Float64Val(constant.Real(x))
191 im, _ := constant.Float64Val(constant.Imag(x))
192 return complex(re, im)
193 }
194