mirror of
https://github.com/golang/go
synced 2024-10-01 20:38:32 -06:00
341a07a3aa
Method sets: - Simplify CallCommon. Avoid the implicit copy when calling a T method on a *T receiver. This simplifies clients. Instead we generate "indirection wrapper" functions that do this (like gc does). New invariant: m's receiver type is exactly T for all m in MethodSet(T) - MakeInterface no longer holds the concrete type's MethodSet. We can defer its computation this way. - ssa.Type now just wraps a types.TypeName object. MethodSets are computed as needed, not eagerly. Position info: - new CanonicalPos utility maps ast.Expr to canonical token.Pos, as returned by {Instruction,Value}.Pos() methods. - Don't set posn for implicit operations (e.g. varargs array alloc) - Set position info for ChangeInterface and Slice instructions. Cosmetic: - add Member.Token() method - simplify isPointer - Omit words "interface", "slice" when printing MakeInterface, MakeSlice; the type is enough. - Comments on PathEnclosingInterval. - Remove Function.FullName() where implicit String() suffices. Also: - Exposed NewLiteral to clients. - Added ssa.Instruction.Parent() *Function Added ssa.BasicBlock.Parent() *Function. Added Sanity checks for above. R=golang-dev, gri CC=golang-dev https://golang.org/cl/10166045
147 lines
3.7 KiB
Go
147 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 and type.
|
|
// val must be valid according to the specification of Literal.Value.
|
|
//
|
|
func NewLiteral(val exact.Value, typ types.Type) *Literal {
|
|
return &Literal{typ, val}
|
|
}
|
|
|
|
// intLiteral returns an untyped integer literal that evaluates to i.
|
|
func intLiteral(i int64) *Literal {
|
|
return NewLiteral(exact.MakeInt64(i), types.Typ[types.UntypedInt])
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
// 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)
|
|
case t.Info()&types.IsNumeric != 0:
|
|
return NewLiteral(exact.MakeInt64(0), t)
|
|
case t.Info()&types.IsString != 0:
|
|
return NewLiteral(exact.MakeString(""), t)
|
|
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)
|
|
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 {
|
|
// TODO(adonovan): Literals don't have positions. Should they?
|
|
return token.NoPos
|
|
}
|
|
|
|
// 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)
|
|
}
|