src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

const.go (5274B)


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