| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- // Copyright 2013 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package ssa
- // This file defines the Const SSA value type.
- import (
- "fmt"
- "go/constant"
- "go/token"
- "go/types"
- "strconv"
- )
- // NewConst returns a new constant of the specified value and type.
- // val must be valid according to the specification of Const.Value.
- //
- func NewConst(val constant.Value, typ types.Type) *Const {
- return &Const{typ, val}
- }
- // intConst returns an 'int' constant that evaluates to i.
- // (i is an int64 in case the host is narrower than the target.)
- func intConst(i int64) *Const {
- return NewConst(constant.MakeInt64(i), tInt)
- }
- // nilConst returns a nil constant of the specified type, which may
- // be any reference type, including interfaces.
- //
- func nilConst(typ types.Type) *Const {
- return NewConst(nil, typ)
- }
- // stringConst returns a 'string' constant that evaluates to s.
- func stringConst(s string) *Const {
- return NewConst(constant.MakeString(s), tString)
- }
- // zeroConst returns a new "zero" constant of the specified type,
- // which must not be an array or struct type: the zero values of
- // aggregates are well-defined but cannot be represented by Const.
- //
- func zeroConst(t types.Type) *Const {
- switch t := t.(type) {
- case *types.Basic:
- switch {
- case t.Info()&types.IsBoolean != 0:
- return NewConst(constant.MakeBool(false), t)
- case t.Info()&types.IsNumeric != 0:
- return NewConst(constant.MakeInt64(0), t)
- case t.Info()&types.IsString != 0:
- return NewConst(constant.MakeString(""), t)
- case t.Kind() == types.UnsafePointer:
- fallthrough
- case t.Kind() == types.UntypedNil:
- return nilConst(t)
- default:
- panic(fmt.Sprint("zeroConst for unexpected type:", t))
- }
- case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
- return nilConst(t)
- case *types.Named:
- return NewConst(zeroConst(t.Underlying()).Value, t)
- case *types.Array, *types.Struct, *types.Tuple:
- panic(fmt.Sprint("zeroConst applied to aggregate:", t))
- }
- panic(fmt.Sprint("zeroConst: unexpected ", t))
- }
- func (c *Const) RelString(from *types.Package) string {
- var s string
- if c.Value == nil {
- s = "nil"
- } else if c.Value.Kind() == constant.String {
- s = constant.StringVal(c.Value)
- const max = 20
- // TODO(adonovan): don't cut a rune in half.
- if len(s) > max {
- s = s[:max-3] + "..." // abbreviate
- }
- s = strconv.Quote(s)
- } else {
- s = c.Value.String()
- }
- return s + ":" + relType(c.Type(), from)
- }
- func (c *Const) Name() string {
- return c.RelString(nil)
- }
- func (c *Const) String() string {
- return c.Name()
- }
- func (c *Const) Type() types.Type {
- return c.typ
- }
- func (c *Const) Referrers() *[]Instruction {
- return nil
- }
- func (c *Const) Parent() *Function { return nil }
- func (c *Const) Pos() token.Pos {
- return token.NoPos
- }
- // IsNil returns true if this constant represents a typed or untyped nil value.
- func (c *Const) IsNil() bool {
- return c.Value == nil
- }
- // TODO(adonovan): move everything below into honnef.co/go/tools/ssa/interp.
- // Int64 returns the numeric value of this constant truncated to fit
- // a signed 64-bit integer.
- //
- func (c *Const) Int64() int64 {
- switch x := constant.ToInt(c.Value); x.Kind() {
- case constant.Int:
- if i, ok := constant.Int64Val(x); ok {
- return i
- }
- return 0
- case constant.Float:
- f, _ := constant.Float64Val(x)
- return int64(f)
- }
- panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
- }
- // Uint64 returns the numeric value of this constant truncated to fit
- // an unsigned 64-bit integer.
- //
- func (c *Const) Uint64() uint64 {
- switch x := constant.ToInt(c.Value); x.Kind() {
- case constant.Int:
- if u, ok := constant.Uint64Val(x); ok {
- return u
- }
- return 0
- case constant.Float:
- f, _ := constant.Float64Val(x)
- return uint64(f)
- }
- panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
- }
- // Float64 returns the numeric value of this constant truncated to fit
- // a float64.
- //
- func (c *Const) Float64() float64 {
- f, _ := constant.Float64Val(c.Value)
- return f
- }
- // Complex128 returns the complex value of this constant truncated to
- // fit a complex128.
- //
- func (c *Const) Complex128() complex128 {
- re, _ := constant.Float64Val(constant.Real(c.Value))
- im, _ := constant.Float64Val(constant.Imag(c.Value))
- return complex(re, im)
- }
|