...

Source file src/golang.org/x/tools/go/ssa/const.go

Documentation: golang.org/x/tools/go/ssa

     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  	"strings"
    16  
    17  	"golang.org/x/tools/internal/aliases"
    18  	"golang.org/x/tools/internal/typeparams"
    19  )
    20  
    21  // NewConst returns a new constant of the specified value and type.
    22  // val must be valid according to the specification of Const.Value.
    23  func NewConst(val constant.Value, typ types.Type) *Const {
    24  	if val == nil {
    25  		switch soleTypeKind(typ) {
    26  		case types.IsBoolean:
    27  			val = constant.MakeBool(false)
    28  		case types.IsInteger:
    29  			val = constant.MakeInt64(0)
    30  		case types.IsString:
    31  			val = constant.MakeString("")
    32  		}
    33  	}
    34  	return &Const{typ, val}
    35  }
    36  
    37  // soleTypeKind returns a BasicInfo for which constant.Value can
    38  // represent all zero values for the types in the type set.
    39  //
    40  //	types.IsBoolean for false is a representative.
    41  //	types.IsInteger for 0
    42  //	types.IsString for ""
    43  //	0 otherwise.
    44  func soleTypeKind(typ types.Type) types.BasicInfo {
    45  	// State records the set of possible zero values (false, 0, "").
    46  	// Candidates (perhaps all) are eliminated during the type-set
    47  	// iteration, which executes at least once.
    48  	state := types.IsBoolean | types.IsInteger | types.IsString
    49  	underIs(typeSetOf(typ), func(ut types.Type) bool {
    50  		var c types.BasicInfo
    51  		if t, ok := ut.(*types.Basic); ok {
    52  			c = t.Info()
    53  		}
    54  		if c&types.IsNumeric != 0 { // int/float/complex
    55  			c = types.IsInteger
    56  		}
    57  		state = state & c
    58  		return state != 0
    59  	})
    60  	return state
    61  }
    62  
    63  // intConst returns an 'int' constant that evaluates to i.
    64  // (i is an int64 in case the host is narrower than the target.)
    65  func intConst(i int64) *Const {
    66  	return NewConst(constant.MakeInt64(i), tInt)
    67  }
    68  
    69  // stringConst returns a 'string' constant that evaluates to s.
    70  func stringConst(s string) *Const {
    71  	return NewConst(constant.MakeString(s), tString)
    72  }
    73  
    74  // zeroConst returns a new "zero" constant of the specified type.
    75  func zeroConst(t types.Type) *Const {
    76  	return NewConst(nil, t)
    77  }
    78  
    79  func (c *Const) RelString(from *types.Package) string {
    80  	var s string
    81  	if c.Value == nil {
    82  		s = zeroString(c.typ, from)
    83  	} else if c.Value.Kind() == constant.String {
    84  		s = constant.StringVal(c.Value)
    85  		const max = 20
    86  		// TODO(adonovan): don't cut a rune in half.
    87  		if len(s) > max {
    88  			s = s[:max-3] + "..." // abbreviate
    89  		}
    90  		s = strconv.Quote(s)
    91  	} else {
    92  		s = c.Value.String()
    93  	}
    94  	return s + ":" + relType(c.Type(), from)
    95  }
    96  
    97  // zeroString returns the string representation of the "zero" value of the type t.
    98  func zeroString(t types.Type, from *types.Package) string {
    99  	switch t := t.(type) {
   100  	case *types.Basic:
   101  		switch {
   102  		case t.Info()&types.IsBoolean != 0:
   103  			return "false"
   104  		case t.Info()&types.IsNumeric != 0:
   105  			return "0"
   106  		case t.Info()&types.IsString != 0:
   107  			return `""`
   108  		case t.Kind() == types.UnsafePointer:
   109  			fallthrough
   110  		case t.Kind() == types.UntypedNil:
   111  			return "nil"
   112  		default:
   113  			panic(fmt.Sprint("zeroString for unexpected type:", t))
   114  		}
   115  	case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
   116  		return "nil"
   117  	case *types.Named, *aliases.Alias:
   118  		return zeroString(t.Underlying(), from)
   119  	case *types.Array, *types.Struct:
   120  		return relType(t, from) + "{}"
   121  	case *types.Tuple:
   122  		// Tuples are not normal values.
   123  		// We are currently format as "(t[0], ..., t[n])". Could be something else.
   124  		components := make([]string, t.Len())
   125  		for i := 0; i < t.Len(); i++ {
   126  			components[i] = zeroString(t.At(i).Type(), from)
   127  		}
   128  		return "(" + strings.Join(components, ", ") + ")"
   129  	case *types.TypeParam:
   130  		return "*new(" + relType(t, from) + ")"
   131  	}
   132  	panic(fmt.Sprint("zeroString: unexpected ", t))
   133  }
   134  
   135  func (c *Const) Name() string {
   136  	return c.RelString(nil)
   137  }
   138  
   139  func (c *Const) String() string {
   140  	return c.Name()
   141  }
   142  
   143  func (c *Const) Type() types.Type {
   144  	return c.typ
   145  }
   146  
   147  func (c *Const) Referrers() *[]Instruction {
   148  	return nil
   149  }
   150  
   151  func (c *Const) Parent() *Function { return nil }
   152  
   153  func (c *Const) Pos() token.Pos {
   154  	return token.NoPos
   155  }
   156  
   157  // IsNil returns true if this constant is a nil value of
   158  // a nillable reference type (pointer, slice, channel, map, or function),
   159  // a basic interface type, or
   160  // a type parameter all of whose possible instantiations are themselves nillable.
   161  func (c *Const) IsNil() bool {
   162  	return c.Value == nil && nillable(c.typ)
   163  }
   164  
   165  // nillable reports whether *new(T) == nil is legal for type T.
   166  func nillable(t types.Type) bool {
   167  	if typeparams.IsTypeParam(t) {
   168  		return underIs(typeSetOf(t), func(u types.Type) bool {
   169  			// empty type set (u==nil) => any underlying types => not nillable
   170  			return u != nil && nillable(u)
   171  		})
   172  	}
   173  	switch t.Underlying().(type) {
   174  	case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
   175  		return true
   176  	case *types.Interface:
   177  		return true // basic interface.
   178  	default:
   179  		return false
   180  	}
   181  }
   182  
   183  // TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp.
   184  
   185  // Int64 returns the numeric value of this constant truncated to fit
   186  // a signed 64-bit integer.
   187  func (c *Const) Int64() int64 {
   188  	switch x := constant.ToInt(c.Value); x.Kind() {
   189  	case constant.Int:
   190  		if i, ok := constant.Int64Val(x); ok {
   191  			return i
   192  		}
   193  		return 0
   194  	case constant.Float:
   195  		f, _ := constant.Float64Val(x)
   196  		return int64(f)
   197  	}
   198  	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
   199  }
   200  
   201  // Uint64 returns the numeric value of this constant truncated to fit
   202  // an unsigned 64-bit integer.
   203  func (c *Const) Uint64() uint64 {
   204  	switch x := constant.ToInt(c.Value); x.Kind() {
   205  	case constant.Int:
   206  		if u, ok := constant.Uint64Val(x); ok {
   207  			return u
   208  		}
   209  		return 0
   210  	case constant.Float:
   211  		f, _ := constant.Float64Val(x)
   212  		return uint64(f)
   213  	}
   214  	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
   215  }
   216  
   217  // Float64 returns the numeric value of this constant truncated to fit
   218  // a float64.
   219  func (c *Const) Float64() float64 {
   220  	x := constant.ToFloat(c.Value) // (c.Value == nil) => x.Kind() == Unknown
   221  	f, _ := constant.Float64Val(x)
   222  	return f
   223  }
   224  
   225  // Complex128 returns the complex value of this constant truncated to
   226  // fit a complex128.
   227  func (c *Const) Complex128() complex128 {
   228  	x := constant.ToComplex(c.Value) // (c.Value == nil) => x.Kind() == Unknown
   229  	re, _ := constant.Float64Val(constant.Real(x))
   230  	im, _ := constant.Float64Val(constant.Imag(x))
   231  	return complex(re, im)
   232  }
   233  

View as plain text