1
0
mirror of https://github.com/golang/go synced 2024-10-01 01:18:32 -06:00

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 {
f.DumpTo(os.Stderr)
MustSanityCheck(f, nil)
mustSanityCheck(f, nil)
}
for _, b := range f.Blocks {

View File

@ -85,23 +85,23 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
name := obj.Name()
switch obj := obj.(type) {
case *types.TypeName:
pkg.Members[name] = &Type{Object: obj}
pkg.Members[name] = &Type{object: obj}
case *types.Const:
pkg.Members[name] = &Constant{
name: name,
Value: NewLiteral(obj.Val(), obj.Type(), obj.Pos()),
pos: obj.Pos(),
object: obj,
Value: NewLiteral(obj.Val(), obj.Type(), obj.Pos()),
}
case *types.Var:
spec, _ := syntax.(*ast.ValueSpec)
g := &Global{
Pkg: pkg,
name: name,
typ: pointer(obj.Type()), // address
pos: obj.Pos(),
spec: spec,
Pkg: pkg,
name: name,
object: obj,
typ: pointer(obj.Type()), // address
pos: obj.Pos(),
spec: spec,
}
pkg.values[obj] = g
pkg.Members[name] = g
@ -121,6 +121,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
sig := obj.Type().(*types.Signature)
fn := &Function{
name: name,
object: obj,
Signature: sig,
Synthetic: synthetic,
pos: obj.Pos(), // (iff syntax)
@ -264,4 +265,8 @@ func createPackage(prog *Program, importPath string, info *importer.PackageInfo)
prog.PackagesByPath[importPath] = 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 {
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 {
defer logStack("promotionWrapper (%s)%s, type %s", typ, cand, sig)()
}
// TODO(adonovan): is there a *types.Func for this function?
fn := &Function{
name: cand.method.Name(),
Signature: sig,
@ -395,6 +396,7 @@ func interfaceMethodWrapper(prog *Program, typ types.Type, id Id) *Function {
}
fn = &Function{
name: meth.Name(),
object: meth,
Signature: meth.Type().(*types.Signature),
Synthetic: fmt.Sprintf("interface method wrapper for %s.%s", typ, id),
pos: meth.Pos(),
@ -495,6 +497,7 @@ func indirectionWrapper(meth *Function) *Function {
s := meth.Signature
recv := types.NewVar(token.NoPos, meth.Pkg.Object, "recv",
types.NewPointer(s.Recv().Type()))
// TODO(adonovan): is there a *types.Func for this method?
fn = &Function{
name: meth.Name(),
Signature: types.NewSignature(recv, s.Params(), s.Results(), s.IsVariadic()),

View File

@ -17,26 +17,26 @@ type sanity struct {
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
// are written to reporter if non-nil, os.Stderr otherwise. Some
// 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.
//
func SanityCheck(fn *Function, reporter io.Writer) bool {
func sanityCheck(fn *Function, reporter io.Writer) bool {
if reporter == nil {
reporter = os.Stderr
}
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.
//
func MustSanityCheck(fn *Function, reporter io.Writer) {
if !SanityCheck(fn, reporter) {
func mustSanityCheck(fn *Function, reporter io.Writer) {
if !sanityCheck(fn, reporter) {
panic("SanityCheck failed")
}
}
@ -344,3 +344,32 @@ func (s *sanity) checkFunction(fn *Function) bool {
s.fn = nil
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.
//
type Member interface {
Name() string // the declared name of the package member
String() string // human-readable information about the value
Pos() token.Pos // position of member's declaration, if known
Type() types.Type // the 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
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}
}
// 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 Type struct {
Object *types.TypeName
object *types.TypeName
}
// 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.
//
type Constant struct {
name string
Value *Literal
pos token.Pos
object *types.Const
Value *Literal
pos token.Pos
}
// An SSA value that can be referenced by an instruction.
@ -266,6 +267,7 @@ type Instruction interface {
//
type Function struct {
name string
object types.Object // a *types.Func; may be nil for init, wrappers, etc.
Signature *types.Signature
pos token.Pos
@ -395,9 +397,10 @@ type Literal struct {
// identifier.
//
type Global struct {
name string
typ types.Type
pos token.Pos
name string
object types.Object // a *types.Var; may be nil for synthetics e.g. init$guard
typ types.Type
pos token.Pos
Pkg *Package
@ -1315,12 +1318,14 @@ 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 *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 (*Function) Referrers() *[]Instruction { return nil }
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) 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) 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) String() string { return t.Name() }
func (t *Type) Type() types.Type { return t.Object.Type() }
func (t *Type) Token() token.Token { return token.TYPE }
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 (c *Constant) Name() string { return c.name }
func (c *Constant) Pos() token.Pos { return c.pos }
func (c *Constant) String() string { return c.Name() }
func (c *Constant) Type() types.Type { return c.Value.Type() }
func (c *Constant) Token() token.Token { return token.CONST }
func (c *Constant) Name() string { return c.object.Name() }
func (c *Constant) Pos() token.Pos { return c.object.Pos() }
func (c *Constant) String() string {
return fmt.Sprintf("%s.%s", c.object.Pkg().Path(), c.object.Name())
}
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,
// or nil if not found.