GoPLS Viewer

Home|gopls/go/ssa/const.go
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
5package ssa
6
7// This file defines the Const SSA value type.
8
9import (
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.
22func NewConst(val constant.Valuetyp 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{typval}
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.
43func soleTypeKind(typ types.Typetypes.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.Typebool {
49        var c types.BasicInfo
50        if tok := 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.)
64func intConst(i int64) *Const {
65    return NewConst(constant.MakeInt64(i), tInt)
66}
67
68// stringConst returns a 'string' constant that evaluates to s.
69func stringConst(s string) *Const {
70    return NewConst(constant.MakeString(s), tString)
71}
72
73// zeroConst returns a new "zero" constant of the specified type.
74func zeroConst(t types.Type) *Const {
75    return NewConst(nilt)
76}
77
78func (c *ConstRelString(from *types.Packagestring {
79    var s string
80    if c.Value == nil {
81        s = zeroString(c.typfrom)
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.
97func zeroString(t types.Typefrom *types.Packagestring {
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(tfrom) + "{}"
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([]stringt.Len())
124        for i := 0i < 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(tfrom) + ")"
130    }
131    panic(fmt.Sprint("zeroString: unexpected "t))
132}
133
134func (c *ConstName() string {
135    return c.RelString(nil)
136}
137
138func (c *ConstString() string {
139    return c.Name()
140}
141
142func (c *ConstType() types.Type {
143    return c.typ
144}
145
146func (c *ConstReferrers() *[]Instruction {
147    return nil
148}
149
150func (c *ConstParent() *Function { return nil }
151
152func (c *ConstPos() token.Pos {
153    return token.NoPos
154}
155
156// IsNil returns true if this constant represents a typed or untyped nil value
157// with an underlying reference type: pointer, slice, chan, map, function, or
158// *basic* interface.
159//
160// Note: a type parameter whose underlying type is a basic interface is
161// considered a reference type.
162func (c *ConstIsNil() bool {
163    return c.Value == nil && nillable(c.typ)
164}
165
166// nillable reports whether *new(T) == nil is legal for type T.
167func nillable(t types.Typebool {
168    switch t := t.Underlying().(type) {
169    case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
170        return true
171    case *types.Interface:
172        return typeSetOf(t).Len() == 0 // basic interface.
173    default:
174        return false
175    }
176}
177
178// TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp.
179
180// Int64 returns the numeric value of this constant truncated to fit
181// a signed 64-bit integer.
182func (c *ConstInt64() int64 {
183    switch x := constant.ToInt(c.Value); x.Kind() {
184    case constant.Int:
185        if iok := constant.Int64Val(x); ok {
186            return i
187        }
188        return 0
189    case constant.Float:
190        f_ := constant.Float64Val(x)
191        return int64(f)
192    }
193    panic(fmt.Sprintf("unexpected constant value: %T"c.Value))
194}
195
196// Uint64 returns the numeric value of this constant truncated to fit
197// an unsigned 64-bit integer.
198func (c *ConstUint64() uint64 {
199    switch x := constant.ToInt(c.Value); x.Kind() {
200    case constant.Int:
201        if uok := constant.Uint64Val(x); ok {
202            return u
203        }
204        return 0
205    case constant.Float:
206        f_ := constant.Float64Val(x)
207        return uint64(f)
208    }
209    panic(fmt.Sprintf("unexpected constant value: %T"c.Value))
210}
211
212// Float64 returns the numeric value of this constant truncated to fit
213// a float64.
214func (c *ConstFloat64() float64 {
215    x := constant.ToFloat(c.Value// (c.Value == nil) => x.Kind() == Unknown
216    f_ := constant.Float64Val(x)
217    return f
218}
219
220// Complex128 returns the complex value of this constant truncated to
221// fit a complex128.
222func (c *ConstComplex128() complex128 {
223    x := constant.ToComplex(c.Value// (c.Value == nil) => x.Kind() == Unknown
224    re_ := constant.Float64Val(constant.Real(x))
225    im_ := constant.Float64Val(constant.Imag(x))
226    return complex(reim)
227}
228
MembersX
soleTypeKind.BlockStmt.c
Const.RelString.c
Const.IsNil
Const.Uint64.BlockStmt.u
Const.Int64
NewConst
soleTypeKind
zeroConst.t
Const.RelString.from
zeroString
Const.RelString.s
Const.Int64.BlockStmt._
Const.Uint64.BlockStmt._
strconv
Const.RelString.BlockStmt.max
Const.IsNil.c
nillable
Const.Int64.c
zeroString.from
Const.Parent.c
Const.Float64.x
stringConst.s
zeroConst
zeroString.BlockStmt.components
Const.Complex128._
NewConst.val
Const.RelString
Const.Type
Const.Uint64.c
Const.Uint64
intConst.i
Const.Pos.c
Const.Float64.c
Const.Complex128
Const.Referrers.c
Const.Int64.x
Const.Int64.BlockStmt.ok
Const.Int64.BlockStmt.f
Const.Float64
Const.String
Const.Pos
Const.Uint64.BlockStmt.f
Const.Name.c
Const.Name
Const.Referrers
Const.Float64.f
Const.Complex128.x
Const.Int64.BlockStmt.i
Const.Uint64.x
Const.Float64._
Const.Complex128.c
NewConst.typ
stringConst
Const.Parent
soleTypeKind.typ
intConst
Const.Uint64.BlockStmt.ok
Const.Complex128.re
Const.Complex128.im
zeroString.t
zeroString.BlockStmt.i
Const.String.c
Const.Type.c
nillable.t
Members
X