go.tools/ssa: remove position info from Literals.

R=gri
CC=golang-dev
https://golang.org/cl/11292043
This commit is contained in:
Alan Donovan 2013-07-15 16:10:08 -04:00
parent 55d678e697
commit a399e26e0e
9 changed files with 36 additions and 50 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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.

View File

@ -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() {

View File

@ -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.

View File

@ -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

View File

@ -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"

View File

@ -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]

View File

@ -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