diff --git a/ssa/builder.go b/ssa/builder.go index 6eea7e69..286c006b 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -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) } diff --git a/ssa/create.go b/ssa/create.go index 3e9a7af4..fd62c806 100644 --- a/ssa/create.go +++ b/ssa/create.go @@ -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 diff --git a/ssa/emit.go b/ssa/emit.go index 530351f5..9aa0037d 100644 --- a/ssa/emit.go +++ b/ssa/emit.go @@ -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. diff --git a/ssa/interp/ops.go b/ssa/interp/ops.go index 0e86cabf..0d8c2e5b 100644 --- a/ssa/interp/ops.go +++ b/ssa/interp/ops.go @@ -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() { diff --git a/ssa/literal.go b/ssa/literal.go index 138b7faf..bbb68b2b 100644 --- a/ssa/literal.go +++ b/ssa/literal.go @@ -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. diff --git a/ssa/source.go b/ssa/source.go index ed3f1dd4..d97ecd58 100644 --- a/ssa/source.go +++ b/ssa/source.go @@ -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 diff --git a/ssa/source_ast.go b/ssa/source_ast.go index fa21d065..0d946f1e 100644 --- a/ssa/source_ast.go +++ b/ssa/source_ast.go @@ -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" diff --git a/ssa/source_test.go b/ssa/source_test.go index 0abc62a6..552bad31 100644 --- a/ssa/source_test.go +++ b/ssa/source_test.go @@ -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] diff --git a/ssa/ssa.go b/ssa/ssa.go index bdf57b93..4592e6a2 100644 --- a/ssa/ssa.go +++ b/ssa/ssa.go @@ -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