go.tools/ssa: SSA fixes for *types.Builtin becoming an object (CL 13813043)
R=gri CC=golang-dev https://golang.org/cl/13848043
This commit is contained in:
parent
a05da76c7b
commit
318b83e376
|
@ -41,8 +41,10 @@ func callees(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
|||
}
|
||||
|
||||
// Reject calls to built-ins.
|
||||
if b, ok := qpos.info.TypeOf(call.Fun).(*types.Builtin); ok {
|
||||
return nil, o.errorf(call, "this is a call to the built-in '%s' operator", b.Name())
|
||||
if id, ok := unparen(call.Fun).(*ast.Ident); ok {
|
||||
if b, ok := qpos.info.ObjectOf(id).(*types.Builtin); ok {
|
||||
return nil, o.errorf(call, "this is a call to the built-in '%s' operator", b.Name())
|
||||
}
|
||||
}
|
||||
|
||||
buildSSA(o)
|
||||
|
|
|
@ -265,15 +265,15 @@ func (b *builder) exprN(fn *Function, e ast.Expr) Value {
|
|||
}
|
||||
|
||||
// builtin emits to fn SSA instructions to implement a call to the
|
||||
// built-in function called name with the specified arguments
|
||||
// built-in function obj with the specified arguments
|
||||
// and return type. It returns the value defined by the result.
|
||||
//
|
||||
// The result is nil if no special handling was required; in this case
|
||||
// the caller should treat this like an ordinary library function
|
||||
// call.
|
||||
//
|
||||
func (b *builder) builtin(fn *Function, name string, args []ast.Expr, typ types.Type, pos token.Pos) Value {
|
||||
switch name {
|
||||
func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ types.Type, pos token.Pos) Value {
|
||||
switch obj.Name() {
|
||||
case "make":
|
||||
switch typ.Underlying().(type) {
|
||||
case *types.Slice:
|
||||
|
@ -554,9 +554,8 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||
}
|
||||
// Call to "intrinsic" built-ins, e.g. new, make, panic.
|
||||
if id, ok := e.Fun.(*ast.Ident); ok {
|
||||
obj := fn.Pkg.objectOf(id)
|
||||
if _, ok := fn.Prog.builtins[obj]; ok {
|
||||
if v := b.builtin(fn, id.Name, e.Args, typ, e.Lparen); v != nil {
|
||||
if obj, ok := fn.Pkg.objectOf(id).(*types.Builtin); ok {
|
||||
if v := b.builtin(fn, obj, e.Args, typ, e.Lparen); v != nil {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
@ -639,7 +638,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
|||
case *ast.Ident:
|
||||
obj := fn.Pkg.objectOf(e)
|
||||
// Universal built-in?
|
||||
if obj.Pkg() == nil {
|
||||
if obj, ok := obj.(*types.Builtin); ok {
|
||||
return fn.Prog.builtins[obj]
|
||||
}
|
||||
// Package-level func or var?
|
||||
|
@ -1750,7 +1749,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type) (k, v Value
|
|||
} else {
|
||||
// length = len(x).
|
||||
var c Call
|
||||
c.Call.Value = fn.Prog.builtins[types.Universe.Lookup("len")]
|
||||
c.Call.Value = fn.Prog.builtins[types.Universe.Lookup("len").(*types.Builtin)]
|
||||
c.Call.Args = []Value{x}
|
||||
c.setType(tInt)
|
||||
length = fn.emit(&c)
|
||||
|
|
|
@ -43,7 +43,7 @@ func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
|
|||
Fset: fset,
|
||||
imported: make(map[string]*Package),
|
||||
packages: make(map[*types.Package]*Package),
|
||||
builtins: make(map[types.Object]*Builtin),
|
||||
builtins: make(map[*types.Builtin]*Builtin),
|
||||
boundMethodWrappers: make(map[*types.Func]*Function),
|
||||
ifaceMethodWrappers: make(map[*types.Func]*Function),
|
||||
mode: mode,
|
||||
|
@ -51,7 +51,7 @@ func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
|
|||
|
||||
// Create Values for built-in functions.
|
||||
for _, name := range types.Universe.Names() {
|
||||
if obj, ok := types.Universe.Lookup(name).(*types.Func); ok {
|
||||
if obj, ok := types.Universe.Lookup(name).(*types.Builtin); ok {
|
||||
prog.builtins[obj] = &Builtin{obj}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,18 +178,13 @@ func (prog *Program) packageLevelValue(obj types.Object) Value {
|
|||
return nil
|
||||
}
|
||||
|
||||
// FuncValue returns the SSA Value denoted by the source-level named
|
||||
// function obj. The result may be a *Function or a *Builtin, or nil
|
||||
// if not found.
|
||||
// FuncValue returns the Function denoted by the source-level named
|
||||
// function obj.
|
||||
//
|
||||
func (prog *Program) FuncValue(obj *types.Func) Value {
|
||||
// Universal built-in?
|
||||
if v, ok := prog.builtins[obj]; ok {
|
||||
return v
|
||||
}
|
||||
func (prog *Program) FuncValue(obj *types.Func) *Function {
|
||||
// Package-level function or declared method?
|
||||
if v := prog.packageLevelValue(obj); v != nil {
|
||||
return v
|
||||
return v.(*Function)
|
||||
}
|
||||
// Interface method wrapper?
|
||||
meth := recvType(obj).MethodSet().Lookup(obj.Pkg(), obj.Name())
|
||||
|
|
|
@ -103,28 +103,19 @@ func TestObjValueLookup(t *testing.T) {
|
|||
}
|
||||
|
||||
func checkFuncValue(t *testing.T, prog *ssa.Program, obj *types.Func) {
|
||||
v := prog.FuncValue(obj)
|
||||
// fmt.Printf("FuncValue(%s) = %s\n", obj, v) // debugging
|
||||
if v == nil {
|
||||
fn := prog.FuncValue(obj)
|
||||
// fmt.Printf("FuncValue(%s) = %s\n", obj, fn) // debugging
|
||||
if fn == nil {
|
||||
t.Errorf("FuncValue(%s) == nil", obj)
|
||||
return
|
||||
}
|
||||
// v must be an *ssa.Function or *ssa.Builtin.
|
||||
v2, _ := v.(interface {
|
||||
Object() types.Object
|
||||
})
|
||||
if v2 == nil {
|
||||
t.Errorf("FuncValue(%s) = %s %T; has no Object() method",
|
||||
obj, v.Name(), v)
|
||||
return
|
||||
}
|
||||
if vobj := v2.Object(); vobj != obj {
|
||||
if fnobj := fn.Object(); fnobj != obj {
|
||||
t.Errorf("FuncValue(%s).Object() == %s; value was %s",
|
||||
obj, vobj, v.Name())
|
||||
obj, fnobj, fn.Name())
|
||||
return
|
||||
}
|
||||
if !types.IsIdentical(v.Type(), obj.Type()) {
|
||||
t.Errorf("FuncValue(%s).Type() == %s", obj, v.Type())
|
||||
if !types.IsIdentical(fn.Type(), obj.Type()) {
|
||||
t.Errorf("FuncValue(%s).Type() == %s", obj, fn.Type())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
12
ssa/ssa.go
12
ssa/ssa.go
|
@ -25,7 +25,7 @@ type Program struct {
|
|||
Fset *token.FileSet // position information for the files of this Program
|
||||
imported map[string]*Package // all importable Packages, keyed by import path
|
||||
packages map[*types.Package]*Package // all loaded Packages, keyed by object
|
||||
builtins map[types.Object]*Builtin // all built-in functions, keyed by typechecker objects.
|
||||
builtins map[*types.Builtin]*Builtin // all built-in functions, keyed by typechecker objects.
|
||||
mode BuilderMode // set of mode bits for SSA construction
|
||||
|
||||
methodsMu sync.Mutex // guards the following maps:
|
||||
|
@ -401,12 +401,14 @@ type Global struct {
|
|||
// Builtins are immutable values. Builtins do not have addresses.
|
||||
// Builtins can only appear in CallCommon.Func.
|
||||
//
|
||||
// Type() returns a *types.Builtin.
|
||||
// Built-in functions may have polymorphic or variadic types that are
|
||||
// not expressible in Go's type system.
|
||||
// Object() returns a *types.Builtin.
|
||||
//
|
||||
// Type() returns types.Typ[types.Invalid], since built-in functions
|
||||
// may have polymorphic or variadic types that are not expressible in
|
||||
// Go's type system.
|
||||
//
|
||||
type Builtin struct {
|
||||
object *types.Func // canonical types.Universe object for this built-in
|
||||
object *types.Builtin // canonical types.Universe object for this built-in
|
||||
}
|
||||
|
||||
// Value-defining instructions ----------------------------------------
|
||||
|
|
Loading…
Reference in New Issue