go.tools/ssa: display named types package-qualified using types.TypeString.

Details:
- use relative (non-qualified) names in more places
- Member interface now has Package(), RelString() methods.
- (*Function).DumpTo: add "# Package: " header.
- Added sanity checks for String functions.

R=gri, gri
CC=golang-dev
https://golang.org/cl/26380043
diff --git a/ssa/const.go b/ssa/const.go
index 6c9ee30..5083d99 100644
--- a/ssa/const.go
+++ b/ssa/const.go
@@ -65,21 +65,27 @@
 	panic(fmt.Sprint("zeroConst: unexpected ", t))
 }
 
-func (c *Const) Name() string {
-	var s string
+func (c *Const) valstring() string {
 	if c.Value == nil {
-		s = "nil"
+		return "nil"
 	} else if c.Value.Kind() == exact.String {
-		s = exact.StringVal(c.Value)
+		s := exact.StringVal(c.Value)
 		const max = 20
 		if len(s) > max {
 			s = s[:max-3] + "..." // abbreviate
 		}
-		s = strconv.Quote(s)
+		return strconv.Quote(s)
 	} else {
-		s = c.Value.String()
+		return c.Value.String()
 	}
-	return s + ":" + c.typ.String()
+}
+
+func (c *Const) Name() string {
+	return fmt.Sprintf("%s:%s", c.valstring(), c.typ)
+}
+
+func (v *Const) String() string {
+	return v.Name()
 }
 
 func (c *Const) Type() types.Type {
diff --git a/ssa/create.go b/ssa/create.go
index 40e1ae0..6067751 100644
--- a/ssa/create.go
+++ b/ssa/create.go
@@ -71,12 +71,16 @@
 	switch obj := obj.(type) {
 	case *types.TypeName:
 		pkg.values[obj] = nil // for needMethods
-		pkg.Members[name] = &Type{object: obj}
+		pkg.Members[name] = &Type{
+			object: obj,
+			pkg:    pkg,
+		}
 
 	case *types.Const:
 		c := &NamedConst{
 			object: obj,
 			Value:  NewConst(obj.Val(), obj.Type()),
+			pkg:    pkg,
 		}
 		pkg.values[obj] = c.Value
 		pkg.Members[name] = c
diff --git a/ssa/example_test.go b/ssa/example_test.go
index 64f0edf..520f47d 100644
--- a/ssa/example_test.go
+++ b/ssa/example_test.go
@@ -82,6 +82,7 @@
 	//   const message    message = "Hello, World!":untyped string
 	//
 	// # Name: main.init
+	// # Package: main
 	// # Synthetic: package initializer
 	// func init():
 	// .0.entry:                                                               P:0 S:2
@@ -95,6 +96,7 @@
 	// 	return
 	//
 	// # Name: main.main
+	// # Package: main
 	// # Location: hello.go:8:6
 	// func main():
 	// .0.entry:                                                               P:0 S:0
diff --git a/ssa/func.go b/ssa/func.go
index cf1aa65..b2059ef 100644
--- a/ssa/func.go
+++ b/ssa/func.go
@@ -444,7 +444,7 @@
 	return f.currentBlock.emit(instr)
 }
 
-// FullName returns the full name of this function, qualified by
+// RelString returns the full name of this function, qualified by
 // package name, receiver type, etc.
 //
 // The specific formatting rules are not guaranteed and may change.
@@ -453,13 +453,13 @@
 //      "math.IsNaN"                // a package-level function
 //      "IsNaN"                     // intra-package reference to same
 //      "(*sync.WaitGroup).Add"     // a declared method
-//      "(*exp/ssa.Return).Block"      // a promotion wrapper method
-//      "(ssa.Instruction).Block"   // an interface method wrapper
+//      "(*Return).Block"           // a promotion wrapper method (intra-package ref)
+//      "(Instruction).Block"       // an interface method wrapper (intra-package ref)
 //      "func@5.32"                 // an anonymous function
 //      "bound$(*T).f"              // a bound method wrapper
 //
 // If from==f.Pkg, suppress package qualification.
-func (f *Function) fullName(from *Package) string {
+func (f *Function) RelString(from *types.Package) string {
 	// TODO(adonovan): expose less fragile case discrimination
 	// using f.method.
 
@@ -490,8 +490,8 @@
 
 	// Package-level function.
 	// Prefix with package name for cross-package references only.
-	if from != f.Pkg {
-		return fmt.Sprintf("%s.%s", f.Pkg.Object.Path(), f.name)
+	if p := f.pkgobj(); p != from {
+		return fmt.Sprintf("%s.%s", p.Path(), f.name)
 	}
 	return f.name
 }
@@ -499,7 +499,7 @@
 // writeSignature writes to w the signature sig in declaration syntax.
 // Derived from types.Signature.String().
 //
-func writeSignature(w io.Writer, pkg *Package, name string, sig *types.Signature, params []*Parameter) {
+func writeSignature(w io.Writer, pkg *types.Package, name string, sig *types.Signature, params []*Parameter) {
 	io.WriteString(w, "func ")
 	if recv := sig.Recv(); recv != nil {
 		io.WriteString(w, "(")
@@ -533,16 +533,26 @@
 		if n == 1 && r.At(0).Name() == "" {
 			io.WriteString(w, relType(r.At(0).Type(), pkg))
 		} else {
-			io.WriteString(w, r.String()) // TODO(adonovan): use relType
+			io.WriteString(w, relType(r, pkg))
 		}
 	}
 }
 
+func (f *Function) pkgobj() *types.Package {
+	if f.Pkg != nil {
+		return f.Pkg.Object
+	}
+	return nil
+}
+
 // DumpTo prints to w a human readable "disassembly" of the SSA code of
 // all basic blocks of function f.
 //
 func (f *Function) DumpTo(w io.Writer) {
 	fmt.Fprintf(w, "# Name: %s\n", f.String())
+	if f.Pkg != nil {
+		fmt.Fprintf(w, "# Package: %s\n", f.Pkg.Object.Path())
+	}
 	if syn := f.Synthetic; syn != "" {
 		fmt.Fprintln(w, "# Synthetic:", syn)
 	}
@@ -558,21 +568,22 @@
 		fmt.Fprintf(w, "# Recover: %s\n", f.Recover)
 	}
 
+	pkgobj := f.pkgobj()
+
 	if f.FreeVars != nil {
 		io.WriteString(w, "# Free variables:\n")
 		for i, fv := range f.FreeVars {
-			fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), f.Pkg))
+			fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), pkgobj))
 		}
 	}
 
 	if len(f.Locals) > 0 {
 		io.WriteString(w, "# Locals:\n")
 		for i, l := range f.Locals {
-			fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), f.Pkg))
+			fmt.Fprintf(w, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), pkgobj))
 		}
 	}
-
-	writeSignature(w, f.Pkg, f.Name(), f.Signature, f.Params)
+	writeSignature(w, pkgobj, f.Name(), f.Signature, f.Params)
 	io.WriteString(w, ":\n")
 
 	if f.Blocks == nil {
@@ -608,7 +619,7 @@
 				l -= n
 				// Right-align the type.
 				if t := v.Type(); t != nil {
-					fmt.Fprintf(w, " %*s", l-10, relType(t, f.Pkg))
+					fmt.Fprintf(w, " %*s", l-10, relType(t, pkgobj))
 				}
 			case nil:
 				// Be robust against bad transforms.
diff --git a/ssa/print.go b/ssa/print.go
index c8fcb96..e75caf3 100644
--- a/ssa/print.go
+++ b/ssa/print.go
@@ -14,57 +14,41 @@
 	"io"
 	"reflect"
 	"sort"
-	"strings"
 
 	"code.google.com/p/go.tools/go/types"
 )
 
 // relName returns the name of v relative to i.
-// In most cases, this is identical to v.Name(), but for references to
-// Functions (including methods) and Globals, the FullName is used
-// instead, explicitly package-qualified for cross-package references.
+// In most cases, this is identical to v.Name(), but references to
+// Functions (including methods) and Globals use RelString and
+// all types are displayed with relType, so that only cross-package
+// references are package-qualified.
 //
 func relName(v Value, i Instruction) string {
+	var from *types.Package
+	if i != nil {
+		from = i.Parent().pkgobj()
+	}
 	switch v := v.(type) {
-	case *Global:
-		if i != nil && v.Pkg == i.Parent().Pkg {
-			return v.Name()
-		}
-		return v.FullName()
-	case *Function:
-		var pkg *Package
-		if i != nil {
-			pkg = i.Parent().Pkg
-		}
-		return v.fullName(pkg)
+	case Member: // *Function or *Global
+		return v.RelString(from)
+	case *Const:
+		return v.valstring() + ":" + relType(v.Type(), from)
 	}
 	return v.Name()
 }
 
-// relType is like t.String(), but if t is a Named type belonging to
-// package from, optionally wrapped by one or more Pointer
-// constructors, package qualification is suppressed.
-//
-// TODO(gri): provide this functionality in go/types (using a
-// *types.Package, obviously).
-//
-func relType(t types.Type, from *Package) string {
-	if from != nil {
-		t2 := t
-		var nptr int // number of Pointers stripped off
-		for {
-			ptr, ok := t2.(*types.Pointer)
-			if !ok {
-				break
-			}
-			t2 = ptr.Elem()
-			nptr++
-		}
-		if n, ok := t2.(*types.Named); ok && n.Obj().Pkg() == from.Object {
-			return strings.Repeat("*", nptr) + n.Obj().Name()
-		}
+func relType(t types.Type, from *types.Package) string {
+	return types.TypeString(from, t)
+}
+
+func relString(m Member, from *types.Package) string {
+	// NB: not all globals have an Object (e.g. init$guard),
+	// so use Package().Object not Object.Package().
+	if obj := m.Package().Object; obj != nil && obj != from {
+		return fmt.Sprintf("%s.%s", obj.Path(), m.Name())
 	}
-	return t.String()
+	return m.Name()
 }
 
 // Value.String()
@@ -72,10 +56,6 @@
 // This method is provided only for debugging.
 // It never appears in disassembly, which uses Value.Name().
 
-func (v *Const) String() string {
-	return v.Name()
-}
-
 func (v *Parameter) String() string {
 	return fmt.Sprintf("parameter %s : %s", v.Name(), v.Type())
 }
@@ -84,23 +64,10 @@
 	return fmt.Sprintf("capture %s : %s", v.Name(), v.Type())
 }
 
-func (v *Global) String() string {
-	return v.FullName()
-}
-
 func (v *Builtin) String() string {
 	return fmt.Sprintf("builtin %s", v.Name())
 }
 
-func (v *Function) String() string {
-	return v.fullName(nil)
-}
-
-// FullName returns g's package-qualified name.
-func (g *Global) FullName() string {
-	return fmt.Sprintf("%s.%s", g.Pkg.Object.Path(), g.name)
-}
-
 // Instruction.String()
 
 func (v *Alloc) String() string {
@@ -108,7 +75,7 @@
 	if v.Heap {
 		op = "new"
 	}
-	return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), v.Parent().Pkg), v.Comment)
+	return fmt.Sprintf("%s %s (%s)", op, relType(deref(v.Type()), v.Parent().pkgobj()), v.Comment)
 }
 
 func (v *Phi) String() string {
@@ -170,7 +137,7 @@
 }
 
 func (v *ChangeType) String() string {
-	return fmt.Sprintf("changetype %s <- %s (%s)", relType(v.Type(), v.Parent().Pkg), v.X.Type(), relName(v.X, v))
+	return fmt.Sprintf("changetype %s <- %s (%s)", relType(v.Type(), v.Parent().pkgobj()), v.X.Type(), relName(v.X, v))
 }
 
 func (v *BinOp) String() string {
@@ -182,7 +149,7 @@
 }
 
 func (v *Convert) String() string {
-	return fmt.Sprintf("convert %s <- %s (%s)", relType(v.Type(), v.Parent().Pkg), v.X.Type(), relName(v.X, v))
+	return fmt.Sprintf("convert %s <- %s (%s)", relType(v.Type(), v.Parent().pkgobj()), v.X.Type(), relName(v.X, v))
 }
 
 func (v *ChangeInterface) String() string {
@@ -190,7 +157,7 @@
 }
 
 func (v *MakeInterface) String() string {
-	return fmt.Sprintf("make %s <- %s (%s)", relType(v.Type(), v.Parent().Pkg), relType(v.X.Type(), v.Parent().Pkg), relName(v.X, v))
+	return fmt.Sprintf("make %s <- %s (%s)", relType(v.Type(), v.Parent().pkgobj()), relType(v.X.Type(), v.Parent().pkgobj()), relName(v.X, v))
 }
 
 func (v *MakeClosure) String() string {
@@ -289,7 +256,7 @@
 }
 
 func (v *TypeAssert) String() string {
-	return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), v.AssertedType)
+	return fmt.Sprintf("typeassert%s %s.(%s)", commaOk(v.CommaOk), relName(v.X, v), relType(v.AssertedType, v.Parent().pkgobj()))
 }
 
 func (v *Extract) String() string {
diff --git a/ssa/sanity.go b/ssa/sanity.go
index f6afb06..9b5bb68 100644
--- a/ssa/sanity.go
+++ b/ssa/sanity.go
@@ -367,6 +367,10 @@
 	if fn.Prog == nil {
 		s.errorf("nil Prog")
 	}
+
+	fn.String()               // must not crash
+	fn.RelString(fn.pkgobj()) // must not crash
+
 	// All functions have a package, except wrappers (which are
 	// shared across packages, or duplicated as weak symbols in a
 	// separate-compilation model), and error.Error.
@@ -430,6 +434,11 @@
 // It does not require that the package is built.
 // Unlike sanityCheck (for functions), it just panics at the first error.
 func sanityCheckPackage(pkg *Package) {
+	if pkg.Object == nil {
+		panic(fmt.Sprintf("Package %s has no Object", pkg))
+	}
+	pkg.String() // must not crash
+
 	for name, mem := range pkg.Members {
 		if name != mem.Name() {
 			panic(fmt.Sprintf("%s: %T.Name() = %s, want %s",
diff --git a/ssa/ssa.go b/ssa/ssa.go
index a4f968e..c7b550e 100644
--- a/ssa/ssa.go
+++ b/ssa/ssa.go
@@ -61,12 +61,14 @@
 // const, var, func and type declarations respectively.
 //
 type Member interface {
-	Name() string         // declared name of the package member
-	String() string       // package-qualified name of the package member
-	Object() types.Object // typechecker's object for this member, if any
-	Pos() token.Pos       // position of member's declaration, if known
-	Type() types.Type     // type of the package member
-	Token() token.Token   // token.{VAR,FUNC,CONST,TYPE}
+	Name() string                    // declared name of the package member
+	String() string                  // package-qualified name of the package member
+	RelString(*types.Package) string // like String, but relative refs are unqualified
+	Object() types.Object            // typechecker's object for this member, if any
+	Pos() token.Pos                  // position of member's declaration, if known
+	Type() types.Type                // type of the package member
+	Token() token.Token              // token.{VAR,FUNC,CONST,TYPE}
+	Package() *Package               // returns the containing package. (TODO: rename Pkg)
 }
 
 // A Type is a Member of a Package representing a package-level named type.
@@ -75,6 +77,7 @@
 //
 type Type struct {
 	object *types.TypeName
+	pkg    *Package
 }
 
 // A NamedConst is a Member of Package representing a package-level
@@ -90,6 +93,7 @@
 	object *types.Const
 	Value  *Const
 	pos    token.Pos
+	pkg    *Package
 }
 
 // An SSA value that can be referenced by an instruction.
@@ -1149,7 +1153,7 @@
 }
 
 // A DebugRef instruction maps a source-level expression Expr to the
-// SSA value that represents the value (!IsAddr) or address (IsAddr)
+// SSA value X that represents the value (!IsAddr) or address (IsAddr)
 // of that expression.
 //
 // DebugRef is a pseudo-instruction: it has no dynamic effect.
@@ -1361,18 +1365,23 @@
 func (v *Capture) Pos() token.Pos            { return v.pos }
 func (v *Capture) Parent() *Function         { return v.parent }
 
-func (v *Global) Type() types.Type        { return v.typ }
-func (v *Global) Name() string            { return v.name }
-func (v *Global) Pos() token.Pos          { return v.pos }
-func (*Global) Referrers() *[]Instruction { return nil }
-func (v *Global) Token() token.Token      { return token.VAR }
-func (v *Global) Object() types.Object    { return v.object }
+func (v *Global) Type() types.Type                     { return v.typ }
+func (v *Global) Name() string                         { return v.name }
+func (v *Global) Pos() token.Pos                       { return v.pos }
+func (v *Global) Referrers() *[]Instruction            { return nil }
+func (v *Global) Token() token.Token                   { return token.VAR }
+func (v *Global) Object() types.Object                 { return v.object }
+func (v *Global) String() string                       { return v.RelString(nil) }
+func (v *Global) Package() *Package                    { return v.Pkg }
+func (v *Global) RelString(from *types.Package) string { return relString(v, from) }
 
 func (v *Function) Name() string         { return v.name }
 func (v *Function) Type() types.Type     { return v.Signature }
 func (v *Function) Pos() token.Pos       { return v.pos }
 func (v *Function) Token() token.Token   { return token.FUNC }
 func (v *Function) Object() types.Object { return v.object }
+func (v *Function) String() string       { return v.RelString(nil) }
+func (v *Function) Package() *Package    { return v.Pkg }
 func (v *Function) Referrers() *[]Instruction {
 	if v.Enclosing != nil {
 		return &v.referrers
@@ -1403,23 +1412,23 @@
 func (v *anInstruction) Block() *BasicBlock         { return v.block }
 func (v *anInstruction) setBlock(block *BasicBlock) { v.block = block }
 
-func (t *Type) Name() string         { return t.object.Name() }
-func (t *Type) Pos() token.Pos       { return t.object.Pos() }
-func (t *Type) Type() types.Type     { return t.object.Type() }
-func (t *Type) Token() token.Token   { return token.TYPE }
-func (t *Type) Object() types.Object { return t.object }
-func (t *Type) String() string {
-	return fmt.Sprintf("%s.%s", t.object.Pkg().Path(), t.object.Name())
-}
+func (t *Type) Name() string                         { return t.object.Name() }
+func (t *Type) Pos() token.Pos                       { return t.object.Pos() }
+func (t *Type) Type() types.Type                     { return t.object.Type() }
+func (t *Type) Token() token.Token                   { return token.TYPE }
+func (t *Type) Object() types.Object                 { return t.object }
+func (t *Type) String() string                       { return t.RelString(nil) }
+func (t *Type) Package() *Package                    { return t.pkg }
+func (t *Type) RelString(from *types.Package) string { return relString(t, from) }
 
-func (c *NamedConst) Name() string   { return c.object.Name() }
-func (c *NamedConst) Pos() token.Pos { return c.object.Pos() }
-func (c *NamedConst) String() string {
-	return fmt.Sprintf("%s.%s", c.object.Pkg().Path(), c.object.Name())
-}
-func (c *NamedConst) Type() types.Type     { return c.object.Type() }
-func (c *NamedConst) Token() token.Token   { return token.CONST }
-func (c *NamedConst) Object() types.Object { return c.object }
+func (c *NamedConst) Name() string                         { return c.object.Name() }
+func (c *NamedConst) Pos() token.Pos                       { return c.object.Pos() }
+func (c *NamedConst) String() string                       { return c.RelString(nil) }
+func (c *NamedConst) Type() types.Type                     { return c.object.Type() }
+func (c *NamedConst) Token() token.Token                   { return token.CONST }
+func (c *NamedConst) Object() types.Object                 { return c.object }
+func (c *NamedConst) Package() *Package                    { return c.pkg }
+func (c *NamedConst) RelString(from *types.Package) string { return relString(c, from) }
 
 // Func returns the package-level function of the specified name,
 // or nil if not found.