1
0
mirror of https://github.com/golang/go synced 2024-11-18 23:05:06 -07:00
go/ssa/literal.go
Alan Donovan 8097dad724 go.tools/ssa: Select now returns received values by tuple, not interface.
Before, all values received on some channel by Select would
flow to an empty interface, creating a spurious confluence for
flow analyses.  Now, the tuple returned by Select has one
component for each 'receive' case.

Also, fixes:
- Removed workarounds for now-fixed typechecker bug in FuncLit+TypeAssert.
- sanity check that all Value Instructions have non-nil Type().
- Convert: document and sanity-check that at least one of the types is basic.

Also, other things to help clients:
- Define CallInstruction interface: common parts of Call, Go, Defer.
- Add CallCommon.Signature() method.
- Literal.Pos() is now populated.

R=gri
CC=golang-dev
https://golang.org/cl/10505043
2013-06-24 14:15:13 -04:00

146 lines
3.7 KiB
Go

package ssa
// This file defines the Literal SSA value type.
import (
"fmt"
"go/token"
"strconv"
"code.google.com/p/go.tools/go/exact"
"code.google.com/p/go.tools/go/types"
)
// NewLiteral returns a new literal of the specified value, type and position.
// val must be valid according to the specification of Literal.Value.
//
func NewLiteral(val exact.Value, typ types.Type, pos token.Pos) *Literal {
return &Literal{typ, val, pos}
}
// intLiteral returns an untyped integer literal that evaluates to i.
func intLiteral(i int64) *Literal {
return NewLiteral(exact.MakeInt64(i), types.Typ[types.UntypedInt], token.NoPos)
}
// nilLiteral returns a nil literal of the specified type, which may
// be any reference type, including interfaces.
//
func nilLiteral(typ types.Type) *Literal {
return NewLiteral(exact.MakeNil(), typ, token.NoPos)
}
// zeroLiteral returns a new "zero" literal 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 Literal.
//
func zeroLiteral(t types.Type) *Literal {
switch t := t.(type) {
case *types.Basic:
switch {
case t.Info()&types.IsBoolean != 0:
return NewLiteral(exact.MakeBool(false), t, token.NoPos)
case t.Info()&types.IsNumeric != 0:
return NewLiteral(exact.MakeInt64(0), t, token.NoPos)
case t.Info()&types.IsString != 0:
return NewLiteral(exact.MakeString(""), t, token.NoPos)
case t.Kind() == types.UnsafePointer:
fallthrough
case t.Kind() == types.UntypedNil:
return nilLiteral(t)
default:
panic(fmt.Sprint("zeroLiteral for unexpected type:", t))
}
case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
return nilLiteral(t)
case *types.Named:
return NewLiteral(zeroLiteral(t.Underlying()).Value, t, token.NoPos)
case *types.Array, *types.Struct:
panic(fmt.Sprint("zeroLiteral applied to aggregate:", t))
}
panic(fmt.Sprint("zeroLiteral: unexpected ", t))
}
func (l *Literal) Name() string {
var s string
if l.Value.Kind() == exact.String {
s = exact.StringVal(l.Value)
const maxLit = 20
if len(s) > maxLit {
s = s[:maxLit-3] + "..." // abbreviate
}
s = strconv.Quote(s)
} else {
s = l.Value.String()
}
return s + ":" + l.typ.String()
}
func (l *Literal) Type() types.Type {
return l.typ
}
func (l *Literal) Referrers() *[]Instruction {
return nil
}
func (l *Literal) Pos() token.Pos {
return l.pos
}
// IsNil returns true if this literal represents a typed or untyped nil value.
func (l *Literal) IsNil() bool {
return l.Value.Kind() == exact.Nil
}
// Int64 returns the numeric value of this literal truncated to fit
// a signed 64-bit integer.
//
func (l *Literal) Int64() int64 {
switch x := l.Value; x.Kind() {
case exact.Int:
if i, ok := exact.Int64Val(x); ok {
return i
}
return 0
case exact.Float:
f, _ := exact.Float64Val(x)
return int64(f)
}
panic(fmt.Sprintf("unexpected literal value: %T", l.Value))
}
// Uint64 returns the numeric value of this literal truncated to fit
// an unsigned 64-bit integer.
//
func (l *Literal) Uint64() uint64 {
switch x := l.Value; x.Kind() {
case exact.Int:
if u, ok := exact.Uint64Val(x); ok {
return u
}
return 0
case exact.Float:
f, _ := exact.Float64Val(x)
return uint64(f)
}
panic(fmt.Sprintf("unexpected literal value: %T", l.Value))
}
// Float64 returns the numeric value of this literal truncated to fit
// a float64.
//
func (l *Literal) Float64() float64 {
f, _ := exact.Float64Val(l.Value)
return f
}
// Complex128 returns the complex value of this literal truncated to
// fit a complex128.
//
func (l *Literal) Complex128() complex128 {
re, _ := exact.Float64Val(exact.Real(l.Value))
im, _ := exact.Float64Val(exact.Imag(l.Value))
return complex(re, im)
}