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.
|
// SSA Value constants.
|
||||||
vZero = intLiteral(0)
|
vZero = intLiteral(0)
|
||||||
vOne = intLiteral(1)
|
vOne = intLiteral(1)
|
||||||
vTrue = NewLiteral(exact.MakeBool(true), tBool, token.NoPos)
|
vTrue = NewLiteral(exact.MakeBool(true), tBool)
|
||||||
vFalse = NewLiteral(exact.MakeBool(false), tBool, token.NoPos)
|
vFalse = NewLiteral(exact.MakeBool(false), tBool)
|
||||||
)
|
)
|
||||||
|
|
||||||
// builder holds state associated with the package currently being built.
|
// 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 {
|
func (b *builder) expr(fn *Function, e ast.Expr) Value {
|
||||||
if v := fn.Pkg.info.ValueOf(e); v != nil {
|
if v := fn.Pkg.info.ValueOf(e); v != nil {
|
||||||
// TODO(adonovan): if e is an ident referring to a named
|
lit := NewLiteral(v, fn.Pkg.typeOf(e))
|
||||||
// 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))
|
|
||||||
if id, ok := unparen(e).(*ast.Ident); ok {
|
if id, ok := unparen(e).(*ast.Ident); ok {
|
||||||
emitDebugRef(fn, id, lit)
|
emitDebugRef(fn, id, lit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
||||||
case *types.Const:
|
case *types.Const:
|
||||||
c := &Constant{
|
c := &Constant{
|
||||||
object: obj,
|
object: obj,
|
||||||
Value: NewLiteral(obj.Val(), obj.Type(), obj.Pos()),
|
Value: NewLiteral(obj.Val(), obj.Type()),
|
||||||
}
|
}
|
||||||
pkg.values[obj] = c.Value
|
pkg.values[obj] = c.Value
|
||||||
pkg.Members[name] = c
|
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
|
// change yet; this defers the point at which the number of
|
||||||
// possible representations explodes.
|
// possible representations explodes.
|
||||||
if l, ok := val.(*Literal); ok {
|
if l, ok := val.(*Literal); ok {
|
||||||
return NewLiteral(l.Value, typ, l.Pos())
|
return NewLiteral(l.Value, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A representation-changing conversion.
|
// A representation-changing conversion.
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,10 @@ func zero(t types.Type) value {
|
||||||
panic("untyped nil has no zero value")
|
panic("untyped nil has no zero value")
|
||||||
}
|
}
|
||||||
if t.Info()&types.IsUntyped != 0 {
|
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)
|
t = ssa.DefaultType(t).(*types.Basic)
|
||||||
}
|
}
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
|
|
|
||||||
|
|
@ -11,23 +11,23 @@ import (
|
||||||
"code.google.com/p/go.tools/go/types"
|
"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.
|
// val must be valid according to the specification of Literal.Value.
|
||||||
//
|
//
|
||||||
func NewLiteral(val exact.Value, typ types.Type, pos token.Pos) *Literal {
|
func NewLiteral(val exact.Value, typ types.Type) *Literal {
|
||||||
return &Literal{typ, val, pos}
|
return &Literal{typ, val}
|
||||||
}
|
}
|
||||||
|
|
||||||
// intLiteral returns an untyped integer literal that evaluates to i.
|
// intLiteral returns an untyped integer literal that evaluates to i.
|
||||||
func intLiteral(i int64) *Literal {
|
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
|
// nilLiteral returns a nil literal of the specified type, which may
|
||||||
// be any reference type, including interfaces.
|
// be any reference type, including interfaces.
|
||||||
//
|
//
|
||||||
func nilLiteral(typ types.Type) *Literal {
|
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,
|
// zeroLiteral returns a new "zero" literal of the specified type,
|
||||||
|
|
@ -39,11 +39,11 @@ func zeroLiteral(t types.Type) *Literal {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
switch {
|
switch {
|
||||||
case t.Info()&types.IsBoolean != 0:
|
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:
|
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:
|
case t.Info()&types.IsString != 0:
|
||||||
return NewLiteral(exact.MakeString(""), t, token.NoPos)
|
return NewLiteral(exact.MakeString(""), t)
|
||||||
case t.Kind() == types.UnsafePointer:
|
case t.Kind() == types.UnsafePointer:
|
||||||
fallthrough
|
fallthrough
|
||||||
case t.Kind() == types.UntypedNil:
|
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:
|
case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
|
||||||
return nilLiteral(t)
|
return nilLiteral(t)
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
return NewLiteral(zeroLiteral(t.Underlying()).Value, t, token.NoPos)
|
return NewLiteral(zeroLiteral(t.Underlying()).Value, t)
|
||||||
case *types.Array, *types.Struct:
|
case *types.Array, *types.Struct:
|
||||||
panic(fmt.Sprint("zeroLiteral applied to aggregate:", t))
|
panic(fmt.Sprint("zeroLiteral applied to aggregate:", t))
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ func (l *Literal) Referrers() *[]Instruction {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Literal) Pos() token.Pos {
|
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.
|
// 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
|
continue
|
||||||
}
|
}
|
||||||
if path, exact := PathEnclosingInterval(f, start, end); path != nil {
|
if path, exact := PathEnclosingInterval(f, start, end); path != nil {
|
||||||
// TODO(adonovan): return the
|
// TODO(adonovan): return info in lieu
|
||||||
// importPath; remove Prog as a
|
// of pkg; remove Prog as a parameter;
|
||||||
// parameter.
|
// move to importer.
|
||||||
return prog.PackagesByPath[importPath], path, exact
|
return prog.PackagesByPath[importPath], path, exact
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,24 +171,21 @@ func CanonicalPos(n ast.Node) token.Pos {
|
||||||
return CanonicalPos(n.X)
|
return CanonicalPos(n.X)
|
||||||
|
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
// f(x): *Call, *Go, *Defer, *Literal (e.g. len)
|
// f(x): *Call, *Go, *Defer.
|
||||||
// T(x): *ChangeType, *Convert, *MakeInterface, *ChangeInterface, *Literal.
|
// T(x): *ChangeType, *Convert, *MakeInterface, *ChangeInterface.
|
||||||
// make(): *MakeMap, *MakeChan, *MakeSlice.
|
// make(): *MakeMap, *MakeChan, *MakeSlice.
|
||||||
// new(): *Alloc.
|
// new(): *Alloc.
|
||||||
// panic(): *Panic.
|
// panic(): *Panic.
|
||||||
return n.Lparen
|
return n.Lparen
|
||||||
|
|
||||||
case *ast.BasicLit:
|
|
||||||
return n.ValuePos // *Literal
|
|
||||||
|
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
return n.NamePos // *Parameter, *Alloc, *Capture, *Literal
|
return n.NamePos // *Parameter, *Alloc, *Capture
|
||||||
|
|
||||||
case *ast.TypeAssertExpr:
|
case *ast.TypeAssertExpr:
|
||||||
return n.Lparen // *ChangeInterface or *TypeAssertExpr
|
return n.Lparen // *ChangeInterface or *TypeAssertExpr
|
||||||
|
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
return n.Sel.NamePos // *MakeClosure, *Field, *FieldAddr, *Literal
|
return n.Sel.NamePos // *MakeClosure, *Field, *FieldAddr
|
||||||
|
|
||||||
case *ast.FuncLit:
|
case *ast.FuncLit:
|
||||||
return n.Type.Func // *Function or *MakeClosure
|
return n.Type.Func // *Function or *MakeClosure
|
||||||
|
|
@ -197,10 +194,10 @@ func CanonicalPos(n ast.Node) token.Pos {
|
||||||
return n.Lbrace // *Alloc or *Slice
|
return n.Lbrace // *Alloc or *Slice
|
||||||
|
|
||||||
case *ast.BinaryExpr:
|
case *ast.BinaryExpr:
|
||||||
return n.OpPos // *Phi, *BinOp or *Literal
|
return n.OpPos // *Phi or *BinOp
|
||||||
|
|
||||||
case *ast.UnaryExpr:
|
case *ast.UnaryExpr:
|
||||||
return n.OpPos // *Phi, *UnOp, or *Literal
|
return n.OpPos // *Phi or *UnOp
|
||||||
|
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
return n.Lbrack // *Index or *IndexAddr
|
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.
|
// constant obj. The result may be a *Literal, or nil if not found.
|
||||||
//
|
//
|
||||||
func (prog *Program) ConstValue(obj *types.Const) *Literal {
|
func (prog *Program) ConstValue(obj *types.Const) *Literal {
|
||||||
|
// TODO(adonovan): opt: share (don't reallocate)
|
||||||
|
// Literals for const objects.
|
||||||
|
|
||||||
// Universal constant? {true,false,nil}
|
// Universal constant? {true,false,nil}
|
||||||
if obj.Parent() == types.Universe {
|
if obj.Parent() == types.Universe {
|
||||||
// TODO(adonovan): opt: share, don't reallocate.
|
return NewLiteral(obj.Val(), obj.Type())
|
||||||
return NewLiteral(obj.Val(), obj.Type(), obj.Pos())
|
|
||||||
}
|
}
|
||||||
// Package-level named constant?
|
// Package-level named constant?
|
||||||
if v := prog.packageLevelValue(obj); v != nil {
|
if v := prog.packageLevelValue(obj); v != nil {
|
||||||
return v.(*Literal)
|
return v.(*Literal)
|
||||||
}
|
}
|
||||||
// TODO(adonovan): need a per-function const object map. For
|
return NewLiteral(obj.Val(), obj.Type())
|
||||||
// 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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VarValue returns the SSA Value that corresponds to a specific
|
// 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.
|
// It has no dependencies on ssa or go/types.
|
||||||
// TODO(adonovan): move it somewhere more general,
|
// TODO(adonovan): move it somewhere more general,
|
||||||
// e.g. go.tools/astutil?
|
// e.g. go.tools/importer?
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,6 @@ func TestObjValueLookup(t *testing.T) {
|
||||||
for _, c := range f.Comments {
|
for _, c := range f.Comments {
|
||||||
text := c.Text()
|
text := c.Text()
|
||||||
pos := imp.Fset.Position(c.Pos())
|
pos := imp.Fset.Position(c.Pos())
|
||||||
fmt.Println(pos.Line, text)
|
|
||||||
for _, m := range re.FindAllStringSubmatch(text, -1) {
|
for _, m := range re.FindAllStringSubmatch(text, -1) {
|
||||||
key := fmt.Sprintf("%s:%d", m[2], pos.Line)
|
key := fmt.Sprintf("%s:%d", m[2], pos.Line)
|
||||||
value := m[1] + m[3]
|
value := m[1] + m[3]
|
||||||
|
|
|
||||||
|
|
@ -377,8 +377,7 @@ type Parameter struct {
|
||||||
// Type(), using the same representation as package go/exact uses for
|
// Type(), using the same representation as package go/exact uses for
|
||||||
// constants.
|
// constants.
|
||||||
//
|
//
|
||||||
// Pos() returns the canonical position (see CanonicalPos) of the
|
// Pos() returns token.NoPos.
|
||||||
// originating constant expression, if explicit in the source.
|
|
||||||
//
|
//
|
||||||
// Example printed form:
|
// Example printed form:
|
||||||
// 42:int
|
// 42:int
|
||||||
|
|
@ -388,7 +387,6 @@ type Parameter struct {
|
||||||
type Literal struct {
|
type Literal struct {
|
||||||
typ types.Type
|
typ types.Type
|
||||||
Value exact.Value
|
Value exact.Value
|
||||||
pos token.Pos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Global is a named Value holding the address of a package-level
|
// 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
|
// Register is a mix-in embedded by all SSA values that are also
|
||||||
// instructions, i.e. virtual registers, and provides implementations
|
// instructions, i.e. virtual registers, and provides implementations
|
||||||
// of the Value interface's Name() and Type() methods: the name is
|
// 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.
|
// field.
|
||||||
//
|
//
|
||||||
// Temporary names are automatically assigned to each Register on
|
// Temporary names are automatically assigned to each Register on
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue