mirror of
https://github.com/golang/go
synced 2024-11-18 19:44:46 -07: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:
parent
1f28df4b6c
commit
bc1f724aa4
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ func (f *Function) finishBody() {
|
||||
}
|
||||
|
||||
if f.Prog.mode&SanityCheckFunctions != 0 {
|
||||
MustSanityCheck(f, nil)
|
||||
mustSanityCheck(f, nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()),
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
55
ssa/ssa.go
55
ssa/ssa.go
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user