compiler: support ... variadic calls

This commit is contained in:
Evgenii Stratonikov 2020-06-27 10:39:30 +03:00
parent b9171eda14
commit 057e1e2806
2 changed files with 18 additions and 5 deletions

View file

@ -758,8 +758,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
} }
// Do not swap for builtin functions. // Do not swap for builtin functions.
if !isBuiltin { if !isBuiltin {
if typ, ok := c.typeOf(n.Fun).(*types.Signature); ok && typ.Variadic() { typ, ok := c.typeOf(n.Fun).(*types.Signature)
// pack variadic args into an array 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 varSize := len(n.Args) - typ.Params().Len() + 1
c.emitReverse(varSize) c.emitReverse(varSize)
emit.Int(c.prog.BinWriter, int64(varSize)) emit.Int(c.prog.BinWriter, int64(varSize))

View file

@ -186,7 +186,7 @@ func TestLocalsCount(t *testing.T) {
} }
func TestVariadic(t *testing.T) { func TestVariadic(t *testing.T) {
src := `package foo srcTmpl := `package foo
func someFunc(a int, b ...int) int { func someFunc(a int, b ...int) int {
sum := a sum := a
for i := range b { for i := range b {
@ -195,9 +195,21 @@ func TestVariadic(t *testing.T) {
return sum return sum
} }
func Main() int { func Main() int {
return someFunc(10, 1, 2, 3) %s
return someFunc(10, %s)
}` }`
eval(t, src, big.NewInt(4)) t.Run("Elements", func(t *testing.T) {
src := fmt.Sprintf(srcTmpl, "", "1, 2, 3")
eval(t, src, big.NewInt(4))
})
t.Run("Slice", func(t *testing.T) {
src := fmt.Sprintf(srcTmpl, "a := []int{1, 2, 3}", "a...")
eval(t, src, big.NewInt(4))
})
t.Run("Literal", func(t *testing.T) {
src := fmt.Sprintf(srcTmpl, "", "[]int{1, 2, 3}...")
eval(t, src, big.NewInt(4))
})
} }
func TestVariadicMethod(t *testing.T) { func TestVariadicMethod(t *testing.T) {