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:
parent
90aa993096
commit
0ba53b54bd
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
15
ssa/testdata/objlookup.go
vendored
15
ssa/testdata/objlookup.go
vendored
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user