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) 16 17// NewConst returns a new constant of the specified value and type. 18// val must be valid according to the specification of Const.Value. 19// 20func NewConst(val constant.Value, typ types.Type) *Const { 21 return &Const{typ, val} 22} 23 24// intConst returns an 'int' constant that evaluates to i. 25// (i is an int64 in case the host is narrower than the target.) 26func intConst(i int64) *Const { 27 return NewConst(constant.MakeInt64(i), tInt) 28} 29 30// nilConst returns a nil constant of the specified type, which may 31// be any reference type, including interfaces. 32// 33func nilConst(typ types.Type) *Const { 34 return NewConst(nil, typ) 35} 36 37// stringConst returns a 'string' constant that evaluates to s. 38func stringConst(s string) *Const { 39 return NewConst(constant.MakeString(s), tString) 40} 41 42// zeroConst returns a new "zero" constant of the specified type, 43// which must not be an array or struct type: the zero values of 44// aggregates are well-defined but cannot be represented by Const. 45// 46func zeroConst(t types.Type) *Const { 47 switch t := t.(type) { 48 case *types.Basic: 49 switch { 50 case t.Info()&types.IsBoolean != 0: 51 return NewConst(constant.MakeBool(false), t) 52 case t.Info()&types.IsNumeric != 0: 53 return NewConst(constant.MakeInt64(0), t) 54 case t.Info()&types.IsString != 0: 55 return NewConst(constant.MakeString(""), t) 56 case t.Kind() == types.UnsafePointer: 57 fallthrough 58 case t.Kind() == types.UntypedNil: 59 return nilConst(t) 60 default: 61 panic(fmt.Sprint("zeroConst for unexpected type:", t)) 62 } 63 case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: 64 return nilConst(t) 65 case *types.Named: 66 return NewConst(zeroConst(t.Underlying()).Value, t) 67 case *types.Array, *types.Struct, *types.Tuple: 68 panic(fmt.Sprint("zeroConst applied to aggregate:", t)) 69 } 70 panic(fmt.Sprint("zeroConst: unexpected ", t)) 71} 72 73func (c *Const) RelString(from *types.Package) string { 74 var s string 75 if c.Value == nil { 76 s = "nil" 77 } else if c.Value.Kind() == constant.String { 78 s = constant.StringVal(c.Value) 79 const max = 20 80 // TODO(adonovan): don't cut a rune in half. 81 if len(s) > max { 82 s = s[:max-3] + "..." // abbreviate 83 } 84 s = strconv.Quote(s) 85 } else { 86 s = c.Value.String() 87 } 88 return s + ":" + relType(c.Type(), from) 89} 90 91func (c *Const) Name() string { 92 return c.RelString(nil) 93} 94 95func (c *Const) String() string { 96 return c.Name() 97} 98 99func (c *Const) Type() types.Type { 100 return c.typ 101} 102 103func (c *Const) Referrers() *[]Instruction { 104 return nil 105} 106 107func (c *Const) Parent() *Function { return nil } 108 109func (c *Const) Pos() token.Pos { 110 return token.NoPos 111} 112 113// IsNil returns true if this constant represents a typed or untyped nil value. 114func (c *Const) IsNil() bool { 115 return c.Value == nil 116} 117 118// TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp. 119 120// Int64 returns the numeric value of this constant truncated to fit 121// a signed 64-bit integer. 122// 123func (c *Const) Int64() int64 { 124 switch x := constant.ToInt(c.Value); x.Kind() { 125 case constant.Int: 126 if i, ok := constant.Int64Val(x); ok { 127 return i 128 } 129 return 0 130 case constant.Float: 131 f, _ := constant.Float64Val(x) 132 return int64(f) 133 } 134 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 135} 136 137// Uint64 returns the numeric value of this constant truncated to fit 138// an unsigned 64-bit integer. 139// 140func (c *Const) Uint64() uint64 { 141 switch x := constant.ToInt(c.Value); x.Kind() { 142 case constant.Int: 143 if u, ok := constant.Uint64Val(x); ok { 144 return u 145 } 146 return 0 147 case constant.Float: 148 f, _ := constant.Float64Val(x) 149 return uint64(f) 150 } 151 panic(fmt.Sprintf("unexpected constant value: %T", c.Value)) 152} 153 154// Float64 returns the numeric value of this constant truncated to fit 155// a float64. 156// 157func (c *Const) Float64() float64 { 158 f, _ := constant.Float64Val(c.Value) 159 return f 160} 161 162// Complex128 returns the complex value of this constant truncated to 163// fit a complex128. 164// 165func (c *Const) Complex128() complex128 { 166 re, _ := constant.Float64Val(constant.Real(c.Value)) 167 im, _ := constant.Float64Val(constant.Imag(c.Value)) 168 return complex(re, im) 169} 170