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