mirror of
https://github.com/golang/go
synced 2024-11-18 10:14:45 -07:00
go.tools/go/loader: use new types.TypeAndValue mode predicates.
PackageInfo: - deleted IsType - inlined + deleted: ValueOf, TypeCaseVar, ImportSpecPkg - on failure, TypeOf accessor now returns nil (was: panic) go/ssa: avoid extra map lookups by using Uses or Defs directly when safe to do so, and keeping the TypeAndValue around in expr0(). LGTM=gri R=gri, pcc CC=golang-codereviews https://golang.org/cl/107650043
This commit is contained in:
parent
961ab3ca8d
commit
f2db24a319
@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"code.google.com/p/go.tools/go/exact"
|
|
||||||
"code.google.com/p/go.tools/go/types"
|
"code.google.com/p/go.tools/go/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,90 +31,29 @@ func (info *PackageInfo) String() string {
|
|||||||
return fmt.Sprintf("PackageInfo(%s)", info.Pkg.Path())
|
return fmt.Sprintf("PackageInfo(%s)", info.Pkg.Path())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeOf returns the type of expression e.
|
// TODO(gri): move the methods below to types.Info.
|
||||||
// Precondition: e belongs to the package's ASTs.
|
|
||||||
//
|
// TypeOf returns the type of expression e, or nil if not found.
|
||||||
func (info *PackageInfo) TypeOf(e ast.Expr) types.Type {
|
func (info *PackageInfo) TypeOf(e ast.Expr) types.Type {
|
||||||
if t, ok := info.Types[e]; ok {
|
if t, ok := info.Types[e]; ok {
|
||||||
return t.Type
|
return t.Type
|
||||||
}
|
}
|
||||||
// Defining ast.Idents (id := expr) get only Ident callbacks
|
// Idents appear only in Defs/Uses, not Types.
|
||||||
// but not Expr callbacks.
|
|
||||||
if id, ok := e.(*ast.Ident); ok {
|
if id, ok := e.(*ast.Ident); ok {
|
||||||
return info.ObjectOf(id).Type()
|
return info.ObjectOf(id).Type()
|
||||||
}
|
}
|
||||||
panic("no type for expression")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValueOf returns the value of expression e if it is a constant, nil
|
// ObjectOf returns the type-checker object denoted by the specified
|
||||||
// otherwise.
|
// id, or nil if not found.
|
||||||
// Precondition: e belongs to the package's ASTs.
|
|
||||||
//
|
//
|
||||||
func (info *PackageInfo) ValueOf(e ast.Expr) exact.Value {
|
// If id is an anonymous struct field, ObjectOf returns the field
|
||||||
return info.Types[e].Value
|
// (*types.Var) it uses, not the type (*types.TypeName) it defines.
|
||||||
}
|
|
||||||
|
|
||||||
// ObjectOf returns the typechecker object denoted by the specified id.
|
|
||||||
//
|
|
||||||
// If id is an anonymous struct field, the field (*types.Var) is
|
|
||||||
// returned, not the type (*types.TypeName).
|
|
||||||
//
|
|
||||||
// Precondition: id belongs to the package's ASTs.
|
|
||||||
//
|
//
|
||||||
func (info *PackageInfo) ObjectOf(id *ast.Ident) types.Object {
|
func (info *PackageInfo) ObjectOf(id *ast.Ident) types.Object {
|
||||||
obj, ok := info.Defs[id]
|
if obj, ok := info.Defs[id]; ok {
|
||||||
if ok {
|
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
return info.Uses[id]
|
return info.Uses[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsType returns true iff expression e denotes a type.
|
|
||||||
// Precondition: e belongs to the package's ASTs.
|
|
||||||
//
|
|
||||||
// TODO(gri): move this into go/types.
|
|
||||||
//
|
|
||||||
func (info *PackageInfo) IsType(e ast.Expr) bool {
|
|
||||||
switch e := e.(type) {
|
|
||||||
case *ast.SelectorExpr: // pkg.Type
|
|
||||||
if _, ok := info.Selections[e]; !ok {
|
|
||||||
// qualified identifier
|
|
||||||
_, isType := info.Uses[e.Sel].(*types.TypeName)
|
|
||||||
return isType
|
|
||||||
}
|
|
||||||
case *ast.StarExpr: // *T
|
|
||||||
return info.IsType(e.X)
|
|
||||||
case *ast.Ident:
|
|
||||||
_, isType := info.ObjectOf(e).(*types.TypeName)
|
|
||||||
return isType
|
|
||||||
case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
|
|
||||||
return true
|
|
||||||
case *ast.ParenExpr:
|
|
||||||
return info.IsType(e.X)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeCaseVar returns the implicit variable created by a single-type
|
|
||||||
// case clause in a type switch, or nil if not found.
|
|
||||||
//
|
|
||||||
func (info *PackageInfo) TypeCaseVar(cc *ast.CaseClause) *types.Var {
|
|
||||||
if v := info.Implicits[cc]; v != nil {
|
|
||||||
return v.(*types.Var)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImportSpecPkg returns the PkgName for a given ImportSpec, possibly
|
|
||||||
// an implicit one for a dot-import or an import-without-rename.
|
|
||||||
// It returns nil if not found.
|
|
||||||
//
|
|
||||||
func (info *PackageInfo) ImportSpecPkg(spec *ast.ImportSpec) *types.PkgName {
|
|
||||||
if spec.Name != nil {
|
|
||||||
return info.ObjectOf(spec.Name).(*types.PkgName)
|
|
||||||
}
|
|
||||||
if p := info.Implicits[spec]; p != nil {
|
|
||||||
return p.(*types.PkgName)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -446,19 +446,23 @@ func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr, isZero bool)
|
|||||||
// to fn and returning the Value defined by the expression.
|
// to fn and returning the Value defined by the expression.
|
||||||
//
|
//
|
||||||
func (b *builder) expr(fn *Function, e ast.Expr) Value {
|
func (b *builder) expr(fn *Function, e ast.Expr) Value {
|
||||||
// Is expression a constant?
|
|
||||||
if v := fn.Pkg.info.ValueOf(e); v != nil {
|
|
||||||
return NewConst(v, fn.Pkg.typeOf(e))
|
|
||||||
}
|
|
||||||
e = unparen(e)
|
e = unparen(e)
|
||||||
v := b.expr0(fn, e)
|
|
||||||
|
tv := fn.Pkg.info.Types[e]
|
||||||
|
|
||||||
|
// Is expression a constant?
|
||||||
|
if tv.Value != nil {
|
||||||
|
return NewConst(tv.Value, tv.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
v := b.expr0(fn, e, tv)
|
||||||
if fn.debugInfo() {
|
if fn.debugInfo() {
|
||||||
emitDebugRef(fn, e, v, false)
|
emitDebugRef(fn, e, v, false)
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
|
||||||
switch e := e.(type) {
|
switch e := e.(type) {
|
||||||
case *ast.BasicLit:
|
case *ast.BasicLit:
|
||||||
panic("non-constant BasicLit") // unreachable
|
panic("non-constant BasicLit") // unreachable
|
||||||
@ -479,7 +483,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
return fn2
|
return fn2
|
||||||
}
|
}
|
||||||
v := &MakeClosure{Fn: fn2}
|
v := &MakeClosure{Fn: fn2}
|
||||||
v.setType(fn.Pkg.typeOf(e))
|
v.setType(tv.Type)
|
||||||
for _, fv := range fn2.FreeVars {
|
for _, fv := range fn2.FreeVars {
|
||||||
v.Bindings = append(v.Bindings, fv.outer)
|
v.Bindings = append(v.Bindings, fv.outer)
|
||||||
fv.outer = nil
|
fv.outer = nil
|
||||||
@ -487,14 +491,13 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
return fn.emit(v)
|
return fn.emit(v)
|
||||||
|
|
||||||
case *ast.TypeAssertExpr: // single-result form only
|
case *ast.TypeAssertExpr: // single-result form only
|
||||||
return emitTypeAssert(fn, b.expr(fn, e.X), fn.Pkg.typeOf(e), e.Lparen)
|
return emitTypeAssert(fn, b.expr(fn, e.X), tv.Type, e.Lparen)
|
||||||
|
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
typ := fn.Pkg.typeOf(e)
|
if fn.Pkg.info.Types[e.Fun].IsType() {
|
||||||
if fn.Pkg.info.IsType(e.Fun) {
|
|
||||||
// Explicit type conversion, e.g. string(x) or big.Int(x)
|
// Explicit type conversion, e.g. string(x) or big.Int(x)
|
||||||
x := b.expr(fn, e.Args[0])
|
x := b.expr(fn, e.Args[0])
|
||||||
y := emitConv(fn, x, typ)
|
y := emitConv(fn, x, tv.Type)
|
||||||
if y != x {
|
if y != x {
|
||||||
switch y := y.(type) {
|
switch y := y.(type) {
|
||||||
case *Convert:
|
case *Convert:
|
||||||
@ -509,8 +512,8 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
}
|
}
|
||||||
// Call to "intrinsic" built-ins, e.g. new, make, panic.
|
// Call to "intrinsic" built-ins, e.g. new, make, panic.
|
||||||
if id, ok := unparen(e.Fun).(*ast.Ident); ok {
|
if id, ok := unparen(e.Fun).(*ast.Ident); ok {
|
||||||
if obj, ok := fn.Pkg.objectOf(id).(*types.Builtin); ok {
|
if obj, ok := fn.Pkg.info.Uses[id].(*types.Builtin); ok {
|
||||||
if v := b.builtin(fn, obj, e.Args, typ, e.Lparen); v != nil {
|
if v := b.builtin(fn, obj, e.Args, tv.Type, e.Lparen); v != nil {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,7 +521,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
// Regular function call.
|
// Regular function call.
|
||||||
var v Call
|
var v Call
|
||||||
b.setCall(fn, e, &v.Call)
|
b.setCall(fn, e, &v.Call)
|
||||||
v.setType(typ)
|
v.setType(tv.Type)
|
||||||
return fn.emit(&v)
|
return fn.emit(&v)
|
||||||
|
|
||||||
case *ast.UnaryExpr:
|
case *ast.UnaryExpr:
|
||||||
@ -541,7 +544,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
X: b.expr(fn, e.X),
|
X: b.expr(fn, e.X),
|
||||||
}
|
}
|
||||||
v.setPos(e.OpPos)
|
v.setPos(e.OpPos)
|
||||||
v.setType(fn.Pkg.typeOf(e))
|
v.setType(tv.Type)
|
||||||
return fn.emit(v)
|
return fn.emit(v)
|
||||||
default:
|
default:
|
||||||
panic(e.Op)
|
panic(e.Op)
|
||||||
@ -554,12 +557,12 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
case token.SHL, token.SHR:
|
case token.SHL, token.SHR:
|
||||||
fallthrough
|
fallthrough
|
||||||
case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
|
case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
|
||||||
return emitArith(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), fn.Pkg.typeOf(e), e.OpPos)
|
return emitArith(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), tv.Type, e.OpPos)
|
||||||
|
|
||||||
case token.EQL, token.NEQ, token.GTR, token.LSS, token.LEQ, token.GEQ:
|
case token.EQL, token.NEQ, token.GTR, token.LSS, token.LEQ, token.GEQ:
|
||||||
cmp := emitCompare(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), e.OpPos)
|
cmp := emitCompare(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), e.OpPos)
|
||||||
// The type of x==y may be UntypedBool.
|
// The type of x==y may be UntypedBool.
|
||||||
return emitConv(fn, cmp, DefaultType(fn.Pkg.typeOf(e)))
|
return emitConv(fn, cmp, DefaultType(tv.Type))
|
||||||
default:
|
default:
|
||||||
panic("illegal op in BinaryExpr: " + e.Op.String())
|
panic("illegal op in BinaryExpr: " + e.Op.String())
|
||||||
}
|
}
|
||||||
@ -592,17 +595,17 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
Max: max,
|
Max: max,
|
||||||
}
|
}
|
||||||
v.setPos(e.Lbrack)
|
v.setPos(e.Lbrack)
|
||||||
v.setType(fn.Pkg.typeOf(e))
|
v.setType(tv.Type)
|
||||||
return fn.emit(v)
|
return fn.emit(v)
|
||||||
|
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
obj := fn.Pkg.objectOf(e)
|
obj := fn.Pkg.info.Uses[e]
|
||||||
// Universal built-in or nil?
|
// Universal built-in or nil?
|
||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *types.Builtin:
|
case *types.Builtin:
|
||||||
return &Builtin{name: obj.Name(), sig: fn.Pkg.typeOf(e).(*types.Signature)}
|
return &Builtin{name: obj.Name(), sig: tv.Type.(*types.Signature)}
|
||||||
case *types.Nil:
|
case *types.Nil:
|
||||||
return nilConst(fn.Pkg.typeOf(e))
|
return nilConst(tv.Type)
|
||||||
}
|
}
|
||||||
// Package-level func or var?
|
// Package-level func or var?
|
||||||
if v := fn.Prog.packageLevelValue(obj); v != nil {
|
if v := fn.Prog.packageLevelValue(obj); v != nil {
|
||||||
@ -624,7 +627,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
case types.MethodExpr:
|
case types.MethodExpr:
|
||||||
// (*T).f or T.f, the method f from the method-set of type T.
|
// (*T).f or T.f, the method f from the method-set of type T.
|
||||||
// The result is a "thunk".
|
// The result is a "thunk".
|
||||||
return emitConv(fn, makeThunk(fn.Prog, sel), fn.Pkg.typeOf(e))
|
return emitConv(fn, makeThunk(fn.Prog, sel), tv.Type)
|
||||||
|
|
||||||
case types.MethodVal:
|
case types.MethodVal:
|
||||||
// e.f where e is an expression and f is a method.
|
// e.f where e is an expression and f is a method.
|
||||||
@ -645,7 +648,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||||||
Bindings: []Value{v},
|
Bindings: []Value{v},
|
||||||
}
|
}
|
||||||
c.setPos(e.Sel.Pos())
|
c.setPos(e.Sel.Pos())
|
||||||
c.setType(fn.Pkg.typeOf(e))
|
c.setType(tv.Type)
|
||||||
return fn.emit(c)
|
return fn.emit(c)
|
||||||
|
|
||||||
case types.FieldVal:
|
case types.FieldVal:
|
||||||
@ -952,10 +955,7 @@ func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) {
|
|||||||
var lval lvalue = blank{}
|
var lval lvalue = blank{}
|
||||||
if !isBlankIdent(lhs) {
|
if !isBlankIdent(lhs) {
|
||||||
if isDef {
|
if isDef {
|
||||||
// Local may be "redeclared" in the same
|
if obj := fn.Pkg.info.Defs[lhs.(*ast.Ident)]; obj != nil {
|
||||||
// scope, so don't blindly create anew.
|
|
||||||
obj := fn.Pkg.objectOf(lhs.(*ast.Ident))
|
|
||||||
if _, ok := fn.objects[obj]; !ok {
|
|
||||||
fn.addNamedLocal(obj)
|
fn.addNamedLocal(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1310,7 +1310,7 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *BasicBlock) {
|
func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *BasicBlock) {
|
||||||
if obj := fn.Pkg.info.TypeCaseVar(cc); obj != nil {
|
if obj := fn.Pkg.info.Implicits[cc]; obj != nil {
|
||||||
// In a switch y := x.(type), each case clause
|
// In a switch y := x.(type), each case clause
|
||||||
// implicitly declares a distinct object y.
|
// implicitly declares a distinct object y.
|
||||||
// In a single-type case, y has that type.
|
// In a single-type case, y has that type.
|
||||||
@ -2115,7 +2115,7 @@ func (b *builder) buildFuncDecl(pkg *Package, decl *ast.FuncDecl) {
|
|||||||
v.setType(types.NewTuple())
|
v.setType(types.NewTuple())
|
||||||
pkg.init.emit(&v)
|
pkg.init.emit(&v)
|
||||||
} else {
|
} else {
|
||||||
fn = pkg.values[pkg.objectOf(id)].(*Function)
|
fn = pkg.values[pkg.info.Defs[id]].(*Function)
|
||||||
}
|
}
|
||||||
b.buildFunction(fn)
|
b.buildFunction(fn)
|
||||||
}
|
}
|
||||||
@ -2250,6 +2250,7 @@ func (p *Package) Build() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Like ObjectOf, but panics instead of returning nil.
|
||||||
// Only valid during p's create and build phases.
|
// Only valid during p's create and build phases.
|
||||||
func (p *Package) objectOf(id *ast.Ident) types.Object {
|
func (p *Package) objectOf(id *ast.Ident) types.Object {
|
||||||
if o := p.info.ObjectOf(id); o != nil {
|
if o := p.info.ObjectOf(id); o != nil {
|
||||||
@ -2259,9 +2260,14 @@ func (p *Package) objectOf(id *ast.Ident) types.Object {
|
|||||||
id.Name, p.Prog.Fset.Position(id.Pos())))
|
id.Name, p.Prog.Fset.Position(id.Pos())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Like TypeOf, but panics instead of returning nil.
|
||||||
// Only valid during p's create and build phases.
|
// Only valid during p's create and build phases.
|
||||||
func (p *Package) typeOf(e ast.Expr) types.Type {
|
func (p *Package) typeOf(e ast.Expr) types.Type {
|
||||||
return p.info.TypeOf(e)
|
if T := p.info.TypeOf(e); T != nil {
|
||||||
|
return T
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("no type for %T @ %s",
|
||||||
|
e, p.Prog.Fset.Position(e.Pos())))
|
||||||
}
|
}
|
||||||
|
|
||||||
// needMethodsOf ensures that runtime type information (including the
|
// needMethodsOf ensures that runtime type information (including the
|
||||||
|
@ -131,7 +131,7 @@ func membersFromDecl(pkg *Package, decl ast.Decl) {
|
|||||||
for _, spec := range decl.Specs {
|
for _, spec := range decl.Specs {
|
||||||
for _, id := range spec.(*ast.ValueSpec).Names {
|
for _, id := range spec.(*ast.ValueSpec).Names {
|
||||||
if !isBlankIdent(id) {
|
if !isBlankIdent(id) {
|
||||||
memberFromObject(pkg, pkg.objectOf(id), nil)
|
memberFromObject(pkg, pkg.info.Defs[id], nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ func membersFromDecl(pkg *Package, decl ast.Decl) {
|
|||||||
for _, spec := range decl.Specs {
|
for _, spec := range decl.Specs {
|
||||||
for _, id := range spec.(*ast.ValueSpec).Names {
|
for _, id := range spec.(*ast.ValueSpec).Names {
|
||||||
if !isBlankIdent(id) {
|
if !isBlankIdent(id) {
|
||||||
memberFromObject(pkg, pkg.objectOf(id), spec)
|
memberFromObject(pkg, pkg.info.Defs[id], spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ func membersFromDecl(pkg *Package, decl ast.Decl) {
|
|||||||
for _, spec := range decl.Specs {
|
for _, spec := range decl.Specs {
|
||||||
id := spec.(*ast.TypeSpec).Name
|
id := spec.(*ast.TypeSpec).Name
|
||||||
if !isBlankIdent(id) {
|
if !isBlankIdent(id) {
|
||||||
memberFromObject(pkg, pkg.objectOf(id), nil)
|
memberFromObject(pkg, pkg.info.Defs[id], nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ func membersFromDecl(pkg *Package, decl ast.Decl) {
|
|||||||
return // no object
|
return // no object
|
||||||
}
|
}
|
||||||
if !isBlankIdent(id) {
|
if !isBlankIdent(id) {
|
||||||
memberFromObject(pkg, pkg.objectOf(id), decl)
|
memberFromObject(pkg, pkg.info.Defs[id], decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
|
|||||||
if recv != nil {
|
if recv != nil {
|
||||||
for _, field := range recv.List {
|
for _, field := range recv.List {
|
||||||
for _, n := range field.Names {
|
for _, n := range field.Names {
|
||||||
f.addSpilledParam(f.Pkg.objectOf(n))
|
f.addSpilledParam(f.Pkg.info.Defs[n])
|
||||||
}
|
}
|
||||||
// Anonymous receiver? No need to spill.
|
// Anonymous receiver? No need to spill.
|
||||||
if field.Names == nil {
|
if field.Names == nil {
|
||||||
@ -238,7 +238,7 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
|
|||||||
n := len(f.Params) // 1 if has recv, 0 otherwise
|
n := len(f.Params) // 1 if has recv, 0 otherwise
|
||||||
for _, field := range functype.Params.List {
|
for _, field := range functype.Params.List {
|
||||||
for _, n := range field.Names {
|
for _, n := range field.Names {
|
||||||
f.addSpilledParam(f.Pkg.objectOf(n))
|
f.addSpilledParam(f.Pkg.info.Defs[n])
|
||||||
}
|
}
|
||||||
// Anonymous parameter? No need to spill.
|
// Anonymous parameter? No need to spill.
|
||||||
if field.Names == nil {
|
if field.Names == nil {
|
||||||
@ -307,7 +307,7 @@ func (f *Function) finishBody() {
|
|||||||
f.syntax = extentNode{n.Pos(), n.End()}
|
f.syntax = extentNode{n.Pos(), n.End()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any f.Locals that are now heap-allocated.
|
// Remove from f.Locals any Allocs that escape to the heap.
|
||||||
j := 0
|
j := 0
|
||||||
for _, l := range f.Locals {
|
for _, l := range f.Locals {
|
||||||
if !l.Heap {
|
if !l.Heap {
|
||||||
@ -393,7 +393,7 @@ func (f *Function) addNamedLocal(obj types.Object) *Alloc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
|
func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
|
||||||
return f.addNamedLocal(f.Pkg.objectOf(id))
|
return f.addNamedLocal(f.Pkg.info.Defs[id])
|
||||||
}
|
}
|
||||||
|
|
||||||
// addLocal creates an anonymous local variable of type typ, adds it
|
// addLocal creates an anonymous local variable of type typ, adds it
|
||||||
|
@ -298,14 +298,14 @@ type Function struct {
|
|||||||
Signature *types.Signature
|
Signature *types.Signature
|
||||||
pos token.Pos
|
pos token.Pos
|
||||||
|
|
||||||
Synthetic string // provenance of synthetic function; "" for true source functions
|
Synthetic string // provenance of synthetic function; "" for true source functions
|
||||||
syntax ast.Node // *ast.Func{Decl,Lit}; replaced with simple ast.Node after build, unless debug mode
|
syntax ast.Node // *ast.Func{Decl,Lit}; replaced with simple ast.Node after build, unless debug mode
|
||||||
parent *Function // enclosing function if anon; nil if global
|
parent *Function // enclosing function if anon; nil if global
|
||||||
Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
|
Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
|
||||||
Prog *Program // enclosing program
|
Prog *Program // enclosing program
|
||||||
Params []*Parameter // function parameters; for methods, includes receiver
|
Params []*Parameter // function parameters; for methods, includes receiver
|
||||||
FreeVars []*FreeVar // free variables whose values must be supplied by closure
|
FreeVars []*FreeVar // free variables whose values must be supplied by closure
|
||||||
Locals []*Alloc
|
Locals []*Alloc // local variables of this function
|
||||||
Blocks []*BasicBlock // basic blocks of the function; nil => external
|
Blocks []*BasicBlock // basic blocks of the function; nil => external
|
||||||
Recover *BasicBlock // optional; control transfers here after recovered panic
|
Recover *BasicBlock // optional; control transfers here after recovered panic
|
||||||
AnonFuncs []*Function // anonymous functions directly beneath this one
|
AnonFuncs []*Function // anonymous functions directly beneath this one
|
||||||
|
@ -38,13 +38,13 @@ func callees(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
|||||||
// not what the user intended.
|
// not what the user intended.
|
||||||
|
|
||||||
// Reject type conversions.
|
// Reject type conversions.
|
||||||
if qpos.info.IsType(e.Fun) {
|
if qpos.info.Types[e.Fun].IsType() {
|
||||||
return nil, fmt.Errorf("this is a type conversion, not a function call")
|
return nil, fmt.Errorf("this is a type conversion, not a function call")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject calls to built-ins.
|
// Reject calls to built-ins.
|
||||||
if id, ok := unparen(e.Fun).(*ast.Ident); ok {
|
if id, ok := unparen(e.Fun).(*ast.Ident); ok {
|
||||||
if b, ok := qpos.info.ObjectOf(id).(*types.Builtin); ok {
|
if b, ok := qpos.info.Uses[id].(*types.Builtin); ok {
|
||||||
return nil, fmt.Errorf("this is a call to the built-in '%s' operator", b.Name())
|
return nil, fmt.Errorf("this is a call to the built-in '%s' operator", b.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -180,7 +181,8 @@ func findInterestingNode(pkginfo *loader.PackageInfo, path []ast.Node) ([]ast.No
|
|||||||
return path, actionExpr
|
return path, actionExpr
|
||||||
|
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
if pkginfo.ObjectOf(n.Sel) == nil {
|
// TODO(adonovan): use Selections info directly.
|
||||||
|
if pkginfo.Uses[n.Sel] == nil {
|
||||||
// TODO(adonovan): is this reachable?
|
// TODO(adonovan): is this reachable?
|
||||||
return path, actionUnknown
|
return path, actionUnknown
|
||||||
}
|
}
|
||||||
@ -267,15 +269,15 @@ func findInterestingNode(pkginfo *loader.PackageInfo, path []ast.Node) ([]ast.No
|
|||||||
return path[1:], actionPackage
|
return path[1:], actionPackage
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// e.g. blank identifier (go/types bug?)
|
// e.g. blank identifier
|
||||||
// or y in "switch y := x.(type)" (go/types bug?)
|
// or y in "switch y := x.(type)"
|
||||||
// or code in a _test.go file that's not part of the package.
|
// or code in a _test.go file that's not part of the package.
|
||||||
fmt.Printf("unknown reference %s in %T\n", n, path[1])
|
log.Printf("unknown reference %s in %T\n", n, path[1])
|
||||||
return path, actionUnknown
|
return path, actionUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.StarExpr:
|
case *ast.StarExpr:
|
||||||
if pkginfo.IsType(n) {
|
if pkginfo.Types[n].IsType() {
|
||||||
return path, actionType
|
return path, actionType
|
||||||
}
|
}
|
||||||
return path, actionExpr
|
return path, actionExpr
|
||||||
@ -311,7 +313,7 @@ func describeValue(o *Oracle, qpos *QueryPos, path []ast.Node) (*describeValueRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
typ := qpos.info.TypeOf(expr)
|
typ := qpos.info.TypeOf(expr)
|
||||||
constVal := qpos.info.ValueOf(expr)
|
constVal := qpos.info.Types[expr].Value
|
||||||
|
|
||||||
return &describeValueResult{
|
return &describeValueResult{
|
||||||
qpos: qpos,
|
qpos: qpos,
|
||||||
@ -497,7 +499,12 @@ func describePackage(o *Oracle, qpos *QueryPos, path []ast.Node) (*describePacka
|
|||||||
var pkg *types.Package
|
var pkg *types.Package
|
||||||
switch n := path[0].(type) {
|
switch n := path[0].(type) {
|
||||||
case *ast.ImportSpec:
|
case *ast.ImportSpec:
|
||||||
pkgname := qpos.info.ImportSpecPkg(n)
|
var pkgname *types.PkgName
|
||||||
|
if n.Name != nil {
|
||||||
|
pkgname = qpos.info.Defs[n.Name].(*types.PkgName)
|
||||||
|
} else if p := qpos.info.Implicits[n]; p != nil {
|
||||||
|
pkgname = p.(*types.PkgName)
|
||||||
|
}
|
||||||
description = fmt.Sprintf("import of package %q", pkgname.Pkg().Path())
|
description = fmt.Sprintf("import of package %q", pkgname.Pkg().Path())
|
||||||
pkg = pkgname.Pkg()
|
pkg = pkgname.Pkg()
|
||||||
|
|
||||||
@ -507,7 +514,7 @@ func describePackage(o *Oracle, qpos *QueryPos, path []ast.Node) (*describePacka
|
|||||||
pkg = qpos.info.Pkg
|
pkg = qpos.info.Pkg
|
||||||
description = fmt.Sprintf("definition of package %q", pkg.Path())
|
description = fmt.Sprintf("definition of package %q", pkg.Path())
|
||||||
} else {
|
} else {
|
||||||
// e.g. import id
|
// e.g. import id "..."
|
||||||
// or id.F()
|
// or id.F()
|
||||||
pkg = qpos.info.ObjectOf(n).Pkg()
|
pkg = qpos.info.ObjectOf(n).Pkg()
|
||||||
description = fmt.Sprintf("reference to package %q", pkg.Path())
|
description = fmt.Sprintf("reference to package %q", pkg.Path())
|
||||||
@ -662,7 +669,7 @@ func describeStmt(o *Oracle, qpos *QueryPos, path []ast.Node) (*describeStmtResu
|
|||||||
var description string
|
var description string
|
||||||
switch n := path[0].(type) {
|
switch n := path[0].(type) {
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
if qpos.info.ObjectOf(n).Pos() == n.Pos() {
|
if qpos.info.Defs[n] != nil {
|
||||||
description = "labelled statement"
|
description = "labelled statement"
|
||||||
} else {
|
} else {
|
||||||
description = "reference to labelled statement"
|
description = "reference to labelled statement"
|
||||||
|
@ -51,17 +51,13 @@ func freevars(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
id = func(n *ast.Ident) types.Object {
|
id = func(n *ast.Ident) types.Object {
|
||||||
obj := qpos.info.ObjectOf(n)
|
obj := qpos.info.Uses[n]
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return nil // TODO(adonovan): fix: this fails for *types.Label.
|
return nil // not a reference
|
||||||
panic("no types.Object for ast.Ident")
|
|
||||||
}
|
}
|
||||||
if _, ok := obj.(*types.PkgName); ok {
|
if _, ok := obj.(*types.PkgName); ok {
|
||||||
return nil // imported package
|
return nil // imported package
|
||||||
}
|
}
|
||||||
if n.Pos() == obj.Pos() {
|
|
||||||
return nil // this ident is the definition, not a reference
|
|
||||||
}
|
|
||||||
if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
|
if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
|
||||||
return nil // not defined in this file
|
return nil // not defined in this file
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ Dot imports are forbidden in the template.
|
|||||||
// TODO(adonovan): expand upon the above documentation as an HTML page.
|
// TODO(adonovan): expand upon the above documentation as an HTML page.
|
||||||
|
|
||||||
// TODO(adonovan): eliminate dependency on loader.PackageInfo.
|
// TODO(adonovan): eliminate dependency on loader.PackageInfo.
|
||||||
// Move its ObjectOf/IsType/TypeOf methods into go/types.
|
// Move its TypeOf method into go/types.
|
||||||
|
|
||||||
// A Transformer represents a single example-based transformation.
|
// A Transformer represents a single example-based transformation.
|
||||||
type Transformer struct {
|
type Transformer struct {
|
||||||
|
@ -105,7 +105,7 @@ func (tr *Transformer) matchExpr(x, y ast.Expr) bool {
|
|||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
y := y.(*ast.CallExpr)
|
y := y.(*ast.CallExpr)
|
||||||
match := tr.matchExpr // function call
|
match := tr.matchExpr // function call
|
||||||
if tr.info.IsType(x.Fun) {
|
if tr.info.Types[x.Fun].IsType() {
|
||||||
match = tr.matchType // type conversion
|
match = tr.matchType // type conversion
|
||||||
}
|
}
|
||||||
return x.Ellipsis.IsValid() == y.Ellipsis.IsValid() &&
|
return x.Ellipsis.IsValid() == y.Ellipsis.IsValid() &&
|
||||||
|
Loading…
Reference in New Issue
Block a user