diff options
Diffstat (limited to 'vendor/golang.org/x/tools/go/ssa/const.go')
-rw-r--r-- | vendor/golang.org/x/tools/go/ssa/const.go | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/vendor/golang.org/x/tools/go/ssa/const.go b/vendor/golang.org/x/tools/go/ssa/const.go new file mode 100644 index 0000000..2a4e0dd --- /dev/null +++ b/vendor/golang.org/x/tools/go/ssa/const.go @@ -0,0 +1,232 @@ +// 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" + "strings" + + "golang.org/x/tools/internal/aliases" + "golang.org/x/tools/internal/typeparams" +) + +// 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 { + if val == nil { + switch soleTypeKind(typ) { + case types.IsBoolean: + val = constant.MakeBool(false) + case types.IsInteger: + val = constant.MakeInt64(0) + case types.IsString: + val = constant.MakeString("") + } + } + return &Const{typ, val} +} + +// soleTypeKind returns a BasicInfo for which constant.Value can +// represent all zero values for the types in the type set. +// +// types.IsBoolean for false is a representative. +// types.IsInteger for 0 +// types.IsString for "" +// 0 otherwise. +func soleTypeKind(typ types.Type) types.BasicInfo { + // State records the set of possible zero values (false, 0, ""). + // Candidates (perhaps all) are eliminated during the type-set + // iteration, which executes at least once. + state := types.IsBoolean | types.IsInteger | types.IsString + underIs(typeSetOf(typ), func(ut types.Type) bool { + var c types.BasicInfo + if t, ok := ut.(*types.Basic); ok { + c = t.Info() + } + if c&types.IsNumeric != 0 { // int/float/complex + c = types.IsInteger + } + state = state & c + return state != 0 + }) + return state +} + +// 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) +} + +// 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. +func zeroConst(t types.Type) *Const { + return NewConst(nil, t) +} + +func (c *Const) RelString(from *types.Package) string { + var s string + if c.Value == nil { + s = zeroString(c.typ, from) + } 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) +} + +// zeroString returns the string representation of the "zero" value of the type t. +func zeroString(t types.Type, from *types.Package) string { + switch t := t.(type) { + case *types.Basic: + switch { + case t.Info()&types.IsBoolean != 0: + return "false" + case t.Info()&types.IsNumeric != 0: + return "0" + case t.Info()&types.IsString != 0: + return `""` + case t.Kind() == types.UnsafePointer: + fallthrough + case t.Kind() == types.UntypedNil: + return "nil" + default: + panic(fmt.Sprint("zeroString for unexpected type:", t)) + } + case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: + return "nil" + case *types.Named, *aliases.Alias: + return zeroString(t.Underlying(), from) + case *types.Array, *types.Struct: + return relType(t, from) + "{}" + case *types.Tuple: + // Tuples are not normal values. + // We are currently format as "(t[0], ..., t[n])". Could be something else. + components := make([]string, t.Len()) + for i := 0; i < t.Len(); i++ { + components[i] = zeroString(t.At(i).Type(), from) + } + return "(" + strings.Join(components, ", ") + ")" + case *types.TypeParam: + return "*new(" + relType(t, from) + ")" + } + panic(fmt.Sprint("zeroString: unexpected ", t)) +} + +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 is a nil value of +// a nillable reference type (pointer, slice, channel, map, or function), +// a basic interface type, or +// a type parameter all of whose possible instantiations are themselves nillable. +func (c *Const) IsNil() bool { + return c.Value == nil && nillable(c.typ) +} + +// nillable reports whether *new(T) == nil is legal for type T. +func nillable(t types.Type) bool { + if typeparams.IsTypeParam(t) { + return underIs(typeSetOf(t), func(u types.Type) bool { + // empty type set (u==nil) => any underlying types => not nillable + return u != nil && nillable(u) + }) + } + switch t.Underlying().(type) { + case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature: + return true + case *types.Interface: + return true // basic interface. + default: + return false + } +} + +// TODO(adonovan): move everything below into golang.org/x/tools/go/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 { + x := constant.ToFloat(c.Value) // (c.Value == nil) => x.Kind() == Unknown + f, _ := constant.Float64Val(x) + return f +} + +// Complex128 returns the complex value of this constant truncated to +// fit a complex128. +func (c *Const) Complex128() complex128 { + x := constant.ToComplex(c.Value) // (c.Value == nil) => x.Kind() == Unknown + re, _ := constant.Float64Val(constant.Real(x)) + im, _ := constant.Float64Val(constant.Imag(x)) + return complex(re, im) +} |