compiler: allow to inline var arg functions
This commit is contained in:
parent
339187a56d
commit
6e560c6c9f
4 changed files with 57 additions and 4 deletions
|
@ -892,10 +892,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
typ, ok := c.typeOf(n.Fun).(*types.Signature)
|
||||
if ok && typ.Variadic() && !n.Ellipsis.IsValid() {
|
||||
// pack variadic args into an array only if last argument is not of form `...`
|
||||
varSize := len(n.Args) - typ.Params().Len() + 1
|
||||
c.emitReverse(varSize)
|
||||
emit.Int(c.prog.BinWriter, int64(varSize))
|
||||
emit.Opcodes(c.prog.BinWriter, opcode.PACK)
|
||||
varSize := c.packVarArgs(n, typ)
|
||||
numArgs -= varSize - 1
|
||||
}
|
||||
c.emitReverse(numArgs)
|
||||
|
@ -1232,6 +1229,16 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
return c
|
||||
}
|
||||
|
||||
// packVarArgs packs variadic arguments into an array
|
||||
// and returns amount of arguments packed.
|
||||
func (c *codegen) packVarArgs(n *ast.CallExpr, typ *types.Signature) int {
|
||||
varSize := len(n.Args) - typ.Params().Len() + 1
|
||||
c.emitReverse(varSize)
|
||||
emit.Int(c.prog.BinWriter, int64(varSize))
|
||||
emit.Opcodes(c.prog.BinWriter, opcode.PACK)
|
||||
return varSize
|
||||
}
|
||||
|
||||
// processDefers emits code for `defer` statements.
|
||||
// TRY-related opcodes handle exception as follows:
|
||||
// 1. CATCH block is executed only if exception has occurred.
|
||||
|
|
|
@ -25,8 +25,16 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
|
|||
c.scope.vars.newScope()
|
||||
newScope := c.scope.vars.locals
|
||||
defer c.scope.vars.dropScope()
|
||||
|
||||
hasVarArgs := !n.Ellipsis.IsValid()
|
||||
needPack := sig.Variadic() && hasVarArgs
|
||||
for i := range n.Args {
|
||||
c.scope.vars.locals = oldScope
|
||||
// true if normal arg or var arg is `slice...`
|
||||
needStore := i < sig.Params().Len()-1 || !sig.Variadic() || !hasVarArgs
|
||||
if !needStore {
|
||||
break
|
||||
}
|
||||
name := sig.Params().At(i).Name()
|
||||
if tv := c.typeAndValueOf(n.Args[i]); tv.Value != nil {
|
||||
c.scope.vars.locals = newScope
|
||||
|
@ -53,6 +61,20 @@ func (c *codegen) inlineCall(f *funcScope, n *ast.CallExpr) {
|
|||
c.emitStoreVar("", name)
|
||||
}
|
||||
|
||||
if needPack {
|
||||
// traverse variadic args and pack them
|
||||
// if they are provided directly i.e. without `...`
|
||||
c.scope.vars.locals = oldScope
|
||||
for i := sig.Params().Len() - 1; i < len(n.Args); i++ {
|
||||
ast.Walk(c, n.Args[i])
|
||||
}
|
||||
c.scope.vars.locals = newScope
|
||||
c.packVarArgs(n, sig)
|
||||
name := sig.Params().At(sig.Params().Len() - 1).Name()
|
||||
c.scope.newLocal(name)
|
||||
c.emitStoreVar("", name)
|
||||
}
|
||||
|
||||
c.pkgInfoInline = append(c.pkgInfoInline, pkg)
|
||||
oldMap := c.importMap
|
||||
c.fillImportMap(f.file, pkg.Pkg)
|
||||
|
|
|
@ -91,6 +91,22 @@ func TestInline(t *testing.T) {
|
|||
checkCallCount(t, src, 1, 2)
|
||||
eval(t, src, big.NewInt(51))
|
||||
})
|
||||
t.Run("var args, empty", func(t *testing.T) {
|
||||
src := fmt.Sprintf(srcTmpl, `return inline.VarSum(11)`)
|
||||
checkCallCount(t, src, 0, 1)
|
||||
eval(t, src, big.NewInt(11))
|
||||
})
|
||||
t.Run("var args, direct", func(t *testing.T) {
|
||||
src := fmt.Sprintf(srcTmpl, `return inline.VarSum(11, 14, 17)`)
|
||||
checkCallCount(t, src, 0, 1)
|
||||
eval(t, src, big.NewInt(42))
|
||||
})
|
||||
t.Run("var args, array", func(t *testing.T) {
|
||||
src := fmt.Sprintf(srcTmpl, `arr := []int{14, 17}
|
||||
return inline.VarSum(11, arr...)`)
|
||||
checkCallCount(t, src, 0, 1)
|
||||
eval(t, src, big.NewInt(42))
|
||||
})
|
||||
}
|
||||
|
||||
func TestInlineConversion(t *testing.T) {
|
||||
|
|
8
pkg/compiler/testdata/inline/inline.go
vendored
8
pkg/compiler/testdata/inline/inline.go
vendored
|
@ -30,3 +30,11 @@ func DropInsideInline() int {
|
|||
sum(3, 4)
|
||||
return 7
|
||||
}
|
||||
|
||||
func VarSum(a int, b ...int) int {
|
||||
sum := a
|
||||
for i := range b {
|
||||
sum += b[i]
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue