...

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/typeparams"
    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(typeSetOf(typ), func(t types.Type) bool {
    49  		var c types.BasicInfo
    50  		if t, ok := t.(*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 = zeroString(c.typ, 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  // zeroString returns the string representation of the "zero" value of the type t.
    97  func zeroString(t types.Type, from *types.Package) string {
    98  	switch t := t.(type) {
    99  	case *types.Basic:
   100  		switch {
   101  		case t.Info()&types.IsBoolean != 0:
   102  			return "false"
   103  		case t.Info()&types.IsNumeric != 0:
   104  			return "0"
   105  		case t.Info()&types.IsString != 0:
   106  			return `""`
   107  		case t.Kind() == types.UnsafePointer:
   108  			fallthrough
   109  		case t.Kind() == types.UntypedNil:
   110  			return "nil"
   111  		default:
   112  			panic(fmt.Sprint("zeroString for unexpected type:", t))
   113  		}
   114  	case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
   115  		return "nil"
   116  	case *types.Named:
   117  		return zeroString(t.Underlying(), from)
   118  	case *types.Array, *types.Struct:
   119  		return relType(t, from) + "{}"
   120  	case *types.Tuple:
   121  		// Tuples are not normal values.
   122  		// We are currently format as "(t[0], ..., t[n])". Could be something else.
   123  		components := make([]string, t.Len())
   124  		for i := 0; i < t.Len(); i++ {
   125  			components[i] = zeroString(t.At(i).Type(), from)
   126  		}
   127  		return "(" + strings.Join(components, ", ") + ")"
   128  	case *typeparams.TypeParam:
   129  		return "*new(" + relType(t, from) + ")"
   130  	}
   131  	panic(fmt.Sprint("zeroString: unexpected ", t))
   132  }
   133  
   134  func (c *Const) Name() string {
   135  	return c.RelString(nil)
   136  }
   137  
   138  func (c *Const) String() string {
   139  	return c.Name()
   140  }
   141  
   142  func (c *Const) Type() types.Type {
   143  	return c.typ
   144  }
   145  
   146  func (c *Const) Referrers() *[]Instruction {
   147  	return nil
   148  }
   149  
   150  func (c *Const) Parent() *Function { return nil }
   151  
   152  func (c *Const) Pos() token.Pos {
   153  	return token.NoPos
   154  }
   155  
   156  // IsNil returns true if this constant represents a typed or untyped nil value
   157  // with an underlying reference type: pointer, slice, chan, map, function, or
   158  // *basic* interface.
   159  //
   160  // Note: a type parameter whose underlying type is a basic interface is
   161  // considered a reference type.
   162  func (c *Const) IsNil() bool {
   163  	return c.Value == nil && nillable(c.typ)
   164  }
   165  
   166  // nillable reports whether *new(T) == nil is legal for type T.
   167  func nillable(t types.Type) bool {
   168  	switch t := t.Underlying().(type) {
   169  	case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
   170  		return true
   171  	case *types.Interface:
   172  		return typeSetOf(t).Len() == 0 // basic interface.
   173  	default:
   174  		return false
   175  	}
   176  }
   177  
   178  // TODO(adonovan): move everything below into golang.org/x/tools/go/ssa/interp.
   179  
   180  // Int64 returns the numeric value of this constant truncated to fit
   181  // a signed 64-bit integer.
   182  func (c *Const) Int64() int64 {
   183  	switch x := constant.ToInt(c.Value); x.Kind() {
   184  	case constant.Int:
   185  		if i, ok := constant.Int64Val(x); ok {
   186  			return i
   187  		}
   188  		return 0
   189  	case constant.Float:
   190  		f, _ := constant.Float64Val(x)
   191  		return int64(f)
   192  	}
   193  	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
   194  }
   195  
   196  // Uint64 returns the numeric value of this constant truncated to fit
   197  // an unsigned 64-bit integer.
   198  func (c *Const) Uint64() uint64 {
   199  	switch x := constant.ToInt(c.Value); x.Kind() {
   200  	case constant.Int:
   201  		if u, ok := constant.Uint64Val(x); ok {
   202  			return u
   203  		}
   204  		return 0
   205  	case constant.Float:
   206  		f, _ := constant.Float64Val(x)
   207  		return uint64(f)
   208  	}
   209  	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
   210  }
   211  
   212  // Float64 returns the numeric value of this constant truncated to fit
   213  // a float64.
   214  func (c *Const) Float64() float64 {
   215  	x := constant.ToFloat(c.Value) // (c.Value == nil) => x.Kind() == Unknown
   216  	f, _ := constant.Float64Val(x)
   217  	return f
   218  }
   219  
   220  // Complex128 returns the complex value of this constant truncated to
   221  // fit a complex128.
   222  func (c *Const) Complex128() complex128 {
   223  	x := constant.ToComplex(c.Value) // (c.Value == nil) => x.Kind() == Unknown
   224  	re, _ := constant.Float64Val(constant.Real(x))
   225  	im, _ := constant.Float64Val(constant.Imag(x))
   226  	return complex(re, im)
   227  }
   228  

View as plain text