go.tools/ssa: Member.Object() returns typechecker object for package members.

Also:
- {Must,}SanityCheck un-exported.  Added sanityCheckPackage.

R=gri
CC=golang-dev
https://golang.org/cl/11174043
This commit is contained in:
Alan Donovan 2013-07-11 14:12:30 -04:00
parent 1f28df4b6c
commit bc1f724aa4
6 changed files with 87 additions and 39 deletions

View File

@ -147,7 +147,7 @@ func optimizeBlocks(f *Function) {
if debugBlockOpt { if debugBlockOpt {
f.DumpTo(os.Stderr) f.DumpTo(os.Stderr)
MustSanityCheck(f, nil) mustSanityCheck(f, nil)
} }
for _, b := range f.Blocks { for _, b := range f.Blocks {

View File

@ -85,23 +85,23 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
name := obj.Name() name := obj.Name()
switch obj := obj.(type) { switch obj := obj.(type) {
case *types.TypeName: case *types.TypeName:
pkg.Members[name] = &Type{Object: obj} pkg.Members[name] = &Type{object: obj}
case *types.Const: case *types.Const:
pkg.Members[name] = &Constant{ pkg.Members[name] = &Constant{
name: name, object: obj,
Value: NewLiteral(obj.Val(), obj.Type(), obj.Pos()), Value: NewLiteral(obj.Val(), obj.Type(), obj.Pos()),
pos: obj.Pos(),
} }
case *types.Var: case *types.Var:
spec, _ := syntax.(*ast.ValueSpec) spec, _ := syntax.(*ast.ValueSpec)
g := &Global{ g := &Global{
Pkg: pkg, Pkg: pkg,
name: name, name: name,
typ: pointer(obj.Type()), // address object: obj,
pos: obj.Pos(), typ: pointer(obj.Type()), // address
spec: spec, pos: obj.Pos(),
spec: spec,
} }
pkg.values[obj] = g pkg.values[obj] = g
pkg.Members[name] = g pkg.Members[name] = g
@ -121,6 +121,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
sig := obj.Type().(*types.Signature) sig := obj.Type().(*types.Signature)
fn := &Function{ fn := &Function{
name: name, name: name,
object: obj,
Signature: sig, Signature: sig,
Synthetic: synthetic, Synthetic: synthetic,
pos: obj.Pos(), // (iff syntax) pos: obj.Pos(), // (iff syntax)
@ -264,4 +265,8 @@ func createPackage(prog *Program, importPath string, info *importer.PackageInfo)
prog.PackagesByPath[importPath] = p prog.PackagesByPath[importPath] = p
prog.packages[p.Object] = p prog.packages[p.Object] = p
if prog.mode&SanityCheckFunctions != 0 {
sanityCheckPackage(p)
}
} }

View File

@ -350,7 +350,7 @@ func (f *Function) finishBody() {
} }
if f.Prog.mode&SanityCheckFunctions != 0 { if f.Prog.mode&SanityCheckFunctions != 0 {
MustSanityCheck(f, nil) mustSanityCheck(f, nil)
} }
} }

View File

@ -285,6 +285,7 @@ func promotionWrapper(prog *Program, typ types.Type, cand *candidate) *Function
if prog.mode&LogSource != 0 { if prog.mode&LogSource != 0 {
defer logStack("promotionWrapper (%s)%s, type %s", typ, cand, sig)() defer logStack("promotionWrapper (%s)%s, type %s", typ, cand, sig)()
} }
// TODO(adonovan): is there a *types.Func for this function?
fn := &Function{ fn := &Function{
name: cand.method.Name(), name: cand.method.Name(),
Signature: sig, Signature: sig,
@ -395,6 +396,7 @@ func interfaceMethodWrapper(prog *Program, typ types.Type, id Id) *Function {
} }
fn = &Function{ fn = &Function{
name: meth.Name(), name: meth.Name(),
object: meth,
Signature: meth.Type().(*types.Signature), Signature: meth.Type().(*types.Signature),
Synthetic: fmt.Sprintf("interface method wrapper for %s.%s", typ, id), Synthetic: fmt.Sprintf("interface method wrapper for %s.%s", typ, id),
pos: meth.Pos(), pos: meth.Pos(),
@ -495,6 +497,7 @@ func indirectionWrapper(meth *Function) *Function {
s := meth.Signature s := meth.Signature
recv := types.NewVar(token.NoPos, meth.Pkg.Object, "recv", recv := types.NewVar(token.NoPos, meth.Pkg.Object, "recv",
types.NewPointer(s.Recv().Type())) types.NewPointer(s.Recv().Type()))
// TODO(adonovan): is there a *types.Func for this method?
fn = &Function{ fn = &Function{
name: meth.Name(), name: meth.Name(),
Signature: types.NewSignature(recv, s.Params(), s.Results(), s.IsVariadic()), Signature: types.NewSignature(recv, s.Params(), s.Results(), s.IsVariadic()),

View File

@ -17,26 +17,26 @@ type sanity struct {
insane bool insane bool
} }
// SanityCheck performs integrity checking of the SSA representation // sanityCheck performs integrity checking of the SSA representation
// of the function fn and returns true if it was valid. Diagnostics // of the function fn and returns true if it was valid. Diagnostics
// are written to reporter if non-nil, os.Stderr otherwise. Some // are written to reporter if non-nil, os.Stderr otherwise. Some
// diagnostics are only warnings and do not imply a negative result. // diagnostics are only warnings and do not imply a negative result.
// //
// Sanity checking is intended to facilitate the debugging of code // Sanity-checking is intended to facilitate the debugging of code
// transformation passes. // transformation passes.
// //
func SanityCheck(fn *Function, reporter io.Writer) bool { func sanityCheck(fn *Function, reporter io.Writer) bool {
if reporter == nil { if reporter == nil {
reporter = os.Stderr reporter = os.Stderr
} }
return (&sanity{reporter: reporter}).checkFunction(fn) return (&sanity{reporter: reporter}).checkFunction(fn)
} }
// MustSanityCheck is like SanityCheck but panics instead of returning // mustSanityCheck is like sanityCheck but panics instead of returning
// a negative result. // a negative result.
// //
func MustSanityCheck(fn *Function, reporter io.Writer) { func mustSanityCheck(fn *Function, reporter io.Writer) {
if !SanityCheck(fn, reporter) { if !sanityCheck(fn, reporter) {
panic("SanityCheck failed") panic("SanityCheck failed")
} }
} }
@ -344,3 +344,32 @@ func (s *sanity) checkFunction(fn *Function) bool {
s.fn = nil s.fn = nil
return !s.insane return !s.insane
} }
// sanityCheckPackage checks invariants of packages upon creation.
// It does not require that the package is built.
// Unlike sanityCheck (for functions), it just panics at the first error.
func sanityCheckPackage(pkg *Package) {
for name, mem := range pkg.Members {
if name != mem.Name() {
panic(fmt.Sprintf("%s: %T.Name() = %s, want %s",
pkg.Object.Path(), mem, mem.Name(), name))
}
obj := mem.Object()
if obj == nil {
// This check is sound because fields
// {Global,Function}.object have type
// types.Object. (If they were declared as
// *types.{Var,Func}, we'd have a non-empty
// interface containing a nil pointer.)
continue // not all members have typechecker objects
}
if obj.Name() != name {
panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s",
pkg.Object.Path(), mem, obj.Name(), name))
}
if obj.Pos() != mem.Pos() {
panic(fmt.Sprintf("%s Pos=%d obj.Pos=%d", mem, mem.Pos(), obj.Pos()))
}
}
}

View File

@ -55,11 +55,12 @@ type Package struct {
// const, var, func and type declarations respectively. // const, var, func and type declarations respectively.
// //
type Member interface { type Member interface {
Name() string // the declared name of the package member Name() string // declared name of the package member
String() string // human-readable information about the value String() string // package-qualified name of the package member
Pos() token.Pos // position of member's declaration, if known Object() types.Object // typechecker's object for this member, if any
Type() types.Type // the type of the package member Pos() token.Pos // position of member's declaration, if known
Token() token.Token // token.{VAR,FUNC,CONST,TYPE} Type() types.Type // type of the package member
Token() token.Token // token.{VAR,FUNC,CONST,TYPE}
} }
// An Id identifies the name of a field of a struct type, or the name // An Id identifies the name of a field of a struct type, or the name
@ -96,7 +97,7 @@ type MethodSet map[Id]*Function
// Type() returns a *types.Named. // Type() returns a *types.Named.
// //
type Type struct { type Type struct {
Object *types.TypeName object *types.TypeName
} }
// A Constant is a Member of Package representing a package-level // A Constant is a Member of Package representing a package-level
@ -109,9 +110,9 @@ type Type struct {
// it augments with the name and position of its 'const' declaration. // it augments with the name and position of its 'const' declaration.
// //
type Constant struct { type Constant struct {
name string object *types.Const
Value *Literal Value *Literal
pos token.Pos pos token.Pos
} }
// An SSA value that can be referenced by an instruction. // An SSA value that can be referenced by an instruction.
@ -266,6 +267,7 @@ type Instruction interface {
// //
type Function struct { type Function struct {
name string name string
object types.Object // a *types.Func; may be nil for init, wrappers, etc.
Signature *types.Signature Signature *types.Signature
pos token.Pos pos token.Pos
@ -395,9 +397,10 @@ type Literal struct {
// identifier. // identifier.
// //
type Global struct { type Global struct {
name string name string
typ types.Type object types.Object // a *types.Var; may be nil for synthetics e.g. init$guard
pos token.Pos typ types.Type
pos token.Pos
Pkg *Package Pkg *Package
@ -1315,12 +1318,14 @@ func (v *Global) Name() string { return v.name }
func (v *Global) Pos() token.Pos { return v.pos } func (v *Global) Pos() token.Pos { return v.pos }
func (*Global) Referrers() *[]Instruction { return nil } func (*Global) Referrers() *[]Instruction { return nil }
func (v *Global) Token() token.Token { return token.VAR } func (v *Global) Token() token.Token { return token.VAR }
func (v *Global) Object() types.Object { return v.object }
func (v *Function) Name() string { return v.name } func (v *Function) Name() string { return v.name }
func (v *Function) Type() types.Type { return v.Signature } func (v *Function) Type() types.Type { return v.Signature }
func (v *Function) Pos() token.Pos { return v.pos } func (v *Function) Pos() token.Pos { return v.pos }
func (*Function) Referrers() *[]Instruction { return nil } func (*Function) Referrers() *[]Instruction { return nil }
func (v *Function) Token() token.Token { return token.FUNC } func (v *Function) Token() token.Token { return token.FUNC }
func (v *Function) Object() types.Object { return v.object }
func (v *Parameter) Type() types.Type { return v.typ } func (v *Parameter) Type() types.Type { return v.typ }
func (v *Parameter) Name() string { return v.name } func (v *Parameter) Name() string { return v.name }
@ -1346,17 +1351,23 @@ func (v *anInstruction) Parent() *Function { return v.block.parent }
func (v *anInstruction) Block() *BasicBlock { return v.block } func (v *anInstruction) Block() *BasicBlock { return v.block }
func (v *anInstruction) SetBlock(block *BasicBlock) { v.block = block } func (v *anInstruction) SetBlock(block *BasicBlock) { v.block = block }
func (t *Type) Name() string { return 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) Pos() token.Pos { return t.object.Pos() }
func (t *Type) String() string { return t.Name() } func (t *Type) Type() types.Type { return t.object.Type() }
func (t *Type) Type() types.Type { return t.Object.Type() } func (t *Type) Token() token.Token { return token.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 (c *Constant) Name() string { return c.name } func (c *Constant) Name() string { return c.object.Name() }
func (c *Constant) Pos() token.Pos { return c.pos } func (c *Constant) Pos() token.Pos { return c.object.Pos() }
func (c *Constant) String() string { return c.Name() } func (c *Constant) String() string {
func (c *Constant) Type() types.Type { return c.Value.Type() } return fmt.Sprintf("%s.%s", c.object.Pkg().Path(), c.object.Name())
func (c *Constant) Token() token.Token { return token.CONST } }
func (c *Constant) Type() types.Type { return c.object.Type() }
func (c *Constant) Token() token.Token { return token.CONST }
func (c *Constant) Object() types.Object { return c.object }
// Func returns the package-level function of the specified name, // Func returns the package-level function of the specified name,
// or nil if not found. // or nil if not found.