go.tools/ssa: remove position info from Literals.
R=gri CC=golang-dev https://golang.org/cl/11292043
This commit is contained in:
parent
55d678e697
commit
a399e26e0e
|
|
@ -57,8 +57,8 @@ var (
|
|||
// SSA Value constants.
|
||||
vZero = intLiteral(0)
|
||||
vOne = intLiteral(1)
|
||||
vTrue = NewLiteral(exact.MakeBool(true), tBool, token.NoPos)
|
||||
vFalse = NewLiteral(exact.MakeBool(false), tBool, token.NoPos)
|
||||
vTrue = NewLiteral(exact.MakeBool(true), tBool)
|
||||
vFalse = NewLiteral(exact.MakeBool(false), tBool)
|
||||
)
|
||||
|
||||
// builder holds state associated with the package currently being built.
|
||||
|
|
@ -547,12 +547,7 @@ func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) {
|
|||
//
|
||||
func (b *builder) expr(fn *Function, e ast.Expr) Value {
|
||||
if v := fn.Pkg.info.ValueOf(e); v != nil {
|
||||
// TODO(adonovan): if e is an ident referring to a named
|
||||
// Const, should we share the Constant's literal?
|
||||
// Then it won't have a position within the function.
|
||||
// Do we want it to have the position of the Ident or
|
||||
// the definition of the const expression?
|
||||
lit := NewLiteral(v, fn.Pkg.typeOf(e), CanonicalPos(e))
|
||||
lit := NewLiteral(v, fn.Pkg.typeOf(e))
|
||||
if id, ok := unparen(e).(*ast.Ident); ok {
|
||||
emitDebugRef(fn, id, lit)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
|||
case *types.Const:
|
||||
c := &Constant{
|
||||
object: obj,
|
||||
Value: NewLiteral(obj.Val(), obj.Type(), obj.Pos()),
|
||||
Value: NewLiteral(obj.Val(), obj.Type()),
|
||||
}
|
||||
pkg.values[obj] = c.Value
|
||||
pkg.Members[name] = c
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
|
|||
// change yet; this defers the point at which the number of
|
||||
// possible representations explodes.
|
||||
if l, ok := val.(*Literal); ok {
|
||||
return NewLiteral(l.Value, typ, l.Pos())
|
||||
return NewLiteral(l.Value, typ)
|
||||
}
|
||||
|
||||
// A representation-changing conversion.
|
||||
|
|
|
|||
|
|
@ -159,6 +159,10 @@ func zero(t types.Type) value {
|
|||
panic("untyped nil has no zero value")
|
||||
}
|
||||
if t.Info()&types.IsUntyped != 0 {
|
||||
// TODO(adonovan): make it an invariant that
|
||||
// this is unreachable. Currently some
|
||||
// literals have 'untyped' types when they
|
||||
// should be defaulted by the typechecker.
|
||||
t = ssa.DefaultType(t).(*types.Basic)
|
||||
}
|
||||
switch t.Kind() {
|
||||
|
|
|
|||
|
|
@ -11,23 +11,23 @@ import (
|
|||
"code.google.com/p/go.tools/go/types"
|
||||
)
|
||||
|
||||
// NewLiteral returns a new literal of the specified value, type and position.
|
||||
// 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, pos token.Pos) *Literal {
|
||||
return &Literal{typ, val, pos}
|
||||
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], token.NoPos)
|
||||
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, token.NoPos)
|
||||
return NewLiteral(exact.MakeNil(), typ)
|
||||
}
|
||||
|
||||
// zeroLiteral returns a new "zero" literal of the specified type,
|
||||
|
|
@ -39,11 +39,11 @@ func zeroLiteral(t types.Type) *Literal {
|
|||
case *types.Basic:
|
||||
switch {
|
||||
case t.Info()&types.IsBoolean != 0:
|
||||
return NewLiteral(exact.MakeBool(false), t, token.NoPos)
|
||||
return NewLiteral(exact.MakeBool(false), t)
|
||||
case t.Info()&types.IsNumeric != 0:
|
||||
return NewLiteral(exact.MakeInt64(0), t, token.NoPos)
|
||||
return NewLiteral(exact.MakeInt64(0), t)
|
||||
case t.Info()&types.IsString != 0:
|
||||
return NewLiteral(exact.MakeString(""), t, token.NoPos)
|
||||
return NewLiteral(exact.MakeString(""), t)
|
||||
case t.Kind() == types.UnsafePointer:
|
||||
fallthrough
|
||||
case t.Kind() == types.UntypedNil:
|
||||
|
|
@ -54,7 +54,7 @@ func zeroLiteral(t types.Type) *Literal {
|
|||
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)
|
||||
return NewLiteral(zeroLiteral(t.Underlying()).Value, t)
|
||||
case *types.Array, *types.Struct:
|
||||
panic(fmt.Sprint("zeroLiteral applied to aggregate:", t))
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ func (l *Literal) Referrers() *[]Instruction {
|
|||
}
|
||||
|
||||
func (l *Literal) Pos() token.Pos {
|
||||
return l.pos
|
||||
return token.NoPos
|
||||
}
|
||||
|
||||
// IsNil returns true if this literal represents a typed or untyped nil value.
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ func (prog *Program) PathEnclosingInterval(imp *importer.Importer, start, end to
|
|||
continue
|
||||
}
|
||||
if path, exact := PathEnclosingInterval(f, start, end); path != nil {
|
||||
// TODO(adonovan): return the
|
||||
// importPath; remove Prog as a
|
||||
// parameter.
|
||||
// TODO(adonovan): return info in lieu
|
||||
// of pkg; remove Prog as a parameter;
|
||||
// move to importer.
|
||||
return prog.PackagesByPath[importPath], path, exact
|
||||
}
|
||||
}
|
||||
|
|
@ -171,24 +171,21 @@ func CanonicalPos(n ast.Node) token.Pos {
|
|||
return CanonicalPos(n.X)
|
||||
|
||||
case *ast.CallExpr:
|
||||
// f(x): *Call, *Go, *Defer, *Literal (e.g. len)
|
||||
// T(x): *ChangeType, *Convert, *MakeInterface, *ChangeInterface, *Literal.
|
||||
// f(x): *Call, *Go, *Defer.
|
||||
// T(x): *ChangeType, *Convert, *MakeInterface, *ChangeInterface.
|
||||
// make(): *MakeMap, *MakeChan, *MakeSlice.
|
||||
// new(): *Alloc.
|
||||
// panic(): *Panic.
|
||||
return n.Lparen
|
||||
|
||||
case *ast.BasicLit:
|
||||
return n.ValuePos // *Literal
|
||||
|
||||
case *ast.Ident:
|
||||
return n.NamePos // *Parameter, *Alloc, *Capture, *Literal
|
||||
return n.NamePos // *Parameter, *Alloc, *Capture
|
||||
|
||||
case *ast.TypeAssertExpr:
|
||||
return n.Lparen // *ChangeInterface or *TypeAssertExpr
|
||||
|
||||
case *ast.SelectorExpr:
|
||||
return n.Sel.NamePos // *MakeClosure, *Field, *FieldAddr, *Literal
|
||||
return n.Sel.NamePos // *MakeClosure, *Field, *FieldAddr
|
||||
|
||||
case *ast.FuncLit:
|
||||
return n.Type.Func // *Function or *MakeClosure
|
||||
|
|
@ -197,10 +194,10 @@ func CanonicalPos(n ast.Node) token.Pos {
|
|||
return n.Lbrace // *Alloc or *Slice
|
||||
|
||||
case *ast.BinaryExpr:
|
||||
return n.OpPos // *Phi, *BinOp or *Literal
|
||||
return n.OpPos // *Phi or *BinOp
|
||||
|
||||
case *ast.UnaryExpr:
|
||||
return n.OpPos // *Phi, *UnOp, or *Literal
|
||||
return n.OpPos // *Phi or *UnOp
|
||||
|
||||
case *ast.IndexExpr:
|
||||
return n.Lbrack // *Index or *IndexAddr
|
||||
|
|
@ -277,25 +274,18 @@ func (prog *Program) FuncValue(obj *types.Func) Value {
|
|||
// constant obj. The result may be a *Literal, or nil if not found.
|
||||
//
|
||||
func (prog *Program) ConstValue(obj *types.Const) *Literal {
|
||||
// TODO(adonovan): opt: share (don't reallocate)
|
||||
// Literals for const objects.
|
||||
|
||||
// Universal constant? {true,false,nil}
|
||||
if obj.Parent() == types.Universe {
|
||||
// TODO(adonovan): opt: share, don't reallocate.
|
||||
return NewLiteral(obj.Val(), obj.Type(), obj.Pos())
|
||||
return NewLiteral(obj.Val(), obj.Type())
|
||||
}
|
||||
// Package-level named constant?
|
||||
if v := prog.packageLevelValue(obj); v != nil {
|
||||
return v.(*Literal)
|
||||
}
|
||||
// TODO(adonovan): need a per-function const object map. For
|
||||
// now, just return a new literal.
|
||||
//
|
||||
// Design question: should literal (constant) values even have
|
||||
// a position? Is their identity important? Should two
|
||||
// different references to Math.pi be distinguishable in any
|
||||
// way? From an analytical perspective, their type and value
|
||||
// tell you all you need to know; they're interchangeable.
|
||||
// Experiment with removing Literal.Pos().
|
||||
return NewLiteral(obj.Val(), obj.Type(), obj.Pos())
|
||||
return NewLiteral(obj.Val(), obj.Type())
|
||||
}
|
||||
|
||||
// VarValue returns the SSA Value that corresponds to a specific
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package ssa
|
|||
|
||||
// It has no dependencies on ssa or go/types.
|
||||
// TODO(adonovan): move it somewhere more general,
|
||||
// e.g. go.tools/astutil?
|
||||
// e.g. go.tools/importer?
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
|
|||
|
|
@ -299,7 +299,6 @@ func TestObjValueLookup(t *testing.T) {
|
|||
for _, c := range f.Comments {
|
||||
text := c.Text()
|
||||
pos := imp.Fset.Position(c.Pos())
|
||||
fmt.Println(pos.Line, text)
|
||||
for _, m := range re.FindAllStringSubmatch(text, -1) {
|
||||
key := fmt.Sprintf("%s:%d", m[2], pos.Line)
|
||||
value := m[1] + m[3]
|
||||
|
|
|
|||
|
|
@ -377,8 +377,7 @@ type Parameter struct {
|
|||
// Type(), using the same representation as package go/exact uses for
|
||||
// constants.
|
||||
//
|
||||
// Pos() returns the canonical position (see CanonicalPos) of the
|
||||
// originating constant expression, if explicit in the source.
|
||||
// Pos() returns token.NoPos.
|
||||
//
|
||||
// Example printed form:
|
||||
// 42:int
|
||||
|
|
@ -388,7 +387,6 @@ type Parameter struct {
|
|||
type Literal struct {
|
||||
typ types.Type
|
||||
Value exact.Value
|
||||
pos token.Pos
|
||||
}
|
||||
|
||||
// A Global is a named Value holding the address of a package-level
|
||||
|
|
@ -1165,7 +1163,7 @@ type DebugRef struct {
|
|||
// Register is a mix-in embedded by all SSA values that are also
|
||||
// instructions, i.e. virtual registers, and provides implementations
|
||||
// of the Value interface's Name() and Type() methods: the name is
|
||||
// simply a numbered register (e.g. "t0") and the type is the Type_
|
||||
// simply a numbered register (e.g. "t0") and the type is the typ
|
||||
// field.
|
||||
//
|
||||
// Temporary names are automatically assigned to each Register on
|
||||
|
|
|
|||
Loading…
Reference in New Issue