1
0
mirror of https://github.com/golang/go synced 2024-11-18 17:14:45 -07:00

go.tools/ssa: add debug info for x.f where Selection.Kind()==FieldVal.

Also:
- Implement Program.FuncValue for interface methods (+ test).
- go/types.Object.String(): don't package-qualify names unless
  they are package level objects---otherwise you see "main.x" for
  locals, struct fields, etc.
- go/types.Func.String(): don't assume Type() is *Signature;
  it could be *Builtin.

R=gri
CC=golang-dev
https://golang.org/cl/12058045
This commit is contained in:
Alan Donovan 2013-07-29 17:10:11 -04:00
parent 90aa993096
commit 0ba53b54bd
6 changed files with 47 additions and 30 deletions

View File

@ -76,13 +76,15 @@ func (obj *object) Name() string { return obj.name }
func (obj *object) Type() Type { return obj.typ }
func (obj *object) IsExported() bool { return ast.IsExported(obj.name) }
func (obj *object) Id() string { return Id(obj.pkg, obj.name) }
func (obj *object) String() string { panic("abstract") }
func (obj *object) toString(kind string, typ Type) string {
var buf bytes.Buffer
buf.WriteString(kind)
buf.WriteByte(' ')
if obj.pkg != nil {
// For package-level objects, package-qualify the name.
if obj.pkg != nil && obj.pkg.scope.Lookup(obj.name) == obj {
buf.WriteString(obj.pkg.name)
buf.WriteByte('.')
}
@ -205,7 +207,7 @@ func (obj *Func) FullName() string {
}
func (obj *Func) fullname(buf *bytes.Buffer) {
sig := obj.typ.(*Signature)
if sig, _ := obj.typ.(*Signature); sig != nil { // may be a *Builtin
if recv := sig.Recv(); recv != nil {
buf.WriteByte('(')
if _, ok := recv.Type().(*Interface); ok {
@ -223,6 +225,7 @@ func (obj *Func) fullname(buf *bytes.Buffer) {
buf.WriteString(obj.pkg.name)
buf.WriteByte('.')
}
}
buf.WriteString(obj.name)
}
@ -230,7 +233,9 @@ func (obj *Func) String() string {
var buf bytes.Buffer
buf.WriteString("func ")
obj.fullname(&buf)
writeSignature(&buf, obj.typ.(*Signature))
if sig, _ := obj.typ.(*Signature); sig != nil {
writeSignature(&buf, sig)
}
return buf.String()
}

View File

@ -391,7 +391,11 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
wantAddr := true
v := b.receiver(fn, e.X, wantAddr, escaping, sel)
last := len(sel.Index()) - 1
return &address{addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos())}
return &address{
addr: emitFieldSelection(fn, v, sel.Index()[last], true, e.Sel.Pos()),
id: e.Sel,
object: sel.Obj(),
}
}
case *ast.IndexExpr:
@ -651,7 +655,9 @@ func (b *builder) expr(fn *Function, e ast.Expr) Value {
last := len(indices) - 1
v := b.expr(fn, e.X)
v = emitImplicitSelections(fn, v, indices[:last])
return emitFieldSelection(fn, v, indices[last], false, e.Sel.Pos())
v = emitFieldSelection(fn, v, indices[last], false, e.Sel.Pos())
emitDebugRef(fn, e.Sel, v)
return v
}
panic("unexpected expression-relative selector")

View File

@ -182,7 +182,6 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
// Conversion to, or construction of a value of, an interface type?
if _, ok := ut_dst.(*types.Interface); ok {
// Assignment from one interface type to another?
if _, ok := ut_src.(*types.Interface); ok {
c := &ChangeInterface{X: val}

View File

@ -224,8 +224,9 @@ func (prog *Program) FuncValue(obj *types.Func) Value {
if v := prog.packageLevelValue(obj); v != nil {
return v
}
// TODO(adonovan): interface method wrappers? other wrappers?
return nil
// Interface method wrapper?
sel := types.NewSelection(types.MethodExpr, recvType(obj), obj, nil, false)
return prog.LookupMethod(sel)
}
// ConstValue returns the SSA Value denoted by the source-level named

View File

@ -70,9 +70,6 @@ func TestObjValueLookup(t *testing.T) {
for obj := range objs {
switch obj := obj.(type) {
case *types.Func:
if obj.Name() == "interfaceMethod" {
continue // TODO(adonovan): not yet implemented.
}
checkFuncValue(t, prog, obj)
case *types.Const:

View File

@ -12,7 +12,8 @@ package main
// its value (x) or its address (&x).
//
// For const and func objects, the results don't vary by reference and
// are always values not addresses, so no annotations are needed.
// are always values not addresses, so no annotations are needed. The
// declaration is enough.
import "fmt"
@ -27,7 +28,7 @@ var globalVar int // &globalVar::Global
func globalFunc() {}
type I interface {
interfaceMethod() // TODO(adonovan): unimplemented (blacklisted in source_test)
interfaceMethod()
}
type S struct {
@ -73,7 +74,8 @@ func main() {
print(v6) // v6::Const
var v7 S // v7::UnOp (load from Alloc)
v7.x = 1 // &v7::Alloc x::nil TODO(adonovan): do better for x
v7.x = 1 // &v7::Alloc x::Const
print(v7.x) // v7::UnOp x::Field
var v8 [1]int // v8::UnOp (load from Alloc)
v8[0] = 0 // &v8::Alloc
@ -94,6 +96,13 @@ func main() {
var v12 J // v12::UnOp (load from Alloc)
v12.method() // &v12::Alloc (implicitly address-taken)
// NB, in the following, 'method' resolves to the *types.Func
// of (*J).method, so it doesn't help us locate the specific
// ssa.Values here: a bound-method closure and a promotion
// wrapper.
_ = v11.method // v11::Const
_ = (*struct{ J }).method
// These vars are optimised away.
if false {
v13 := 0 // v13::nil