Skip to content

Commit 29337c9

Browse files
committed
Pass nil slice when variadic arguments are omitted after regular args.
Previously we would pass an empty slice, which is against the Go spec: > If f is invoked with no actual arguments for p, the value passed to p > is nil. Source: https://go.dev/ref/spec#Passing_arguments_to_..._parameters Fixes #1147
1 parent 480cd60 commit 29337c9

File tree

2 files changed

+50
-18
lines changed

2 files changed

+50
-18
lines changed

compiler/utils.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,15 @@ func (fc *funcContext) translateArgs(sig *types.Signature, argExprs []ast.Expr,
140140
// If variadic arguments were passed in as individual elements, regroup them
141141
// into a slice and pass it as a single argument.
142142
if sig.Variadic() && !ellipsis {
143-
return append(args[:sigTypes.RequiredParams()],
144-
fmt.Sprintf("new %s([%s])", fc.typeName(sigTypes.VariadicType()), strings.Join(args[sigTypes.RequiredParams():], ", ")))
143+
required := args[:sigTypes.RequiredParams()]
144+
var variadic string
145+
if len(args) == sigTypes.RequiredParams() {
146+
// If no variadic parameters were passed, the slice value defaults to nil.
147+
variadic = fmt.Sprintf("%s.nil", fc.typeName(sigTypes.VariadicType()))
148+
} else {
149+
variadic = fmt.Sprintf("new %s([%s])", fc.typeName(sigTypes.VariadicType()), strings.Join(args[sigTypes.RequiredParams():], ", "))
150+
}
151+
return append(required, variadic)
145152
}
146153
return args
147154
}

tests/compiler_test.go

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,50 @@ import (
55
)
66

77
func TestVariadicNil(t *testing.T) {
8-
printVari := func(strs ...string) []string {
9-
return strs
10-
}
8+
t.Run("only variadic", func(t *testing.T) {
9+
printVari := func(strs ...string) []string {
10+
return strs
11+
}
12+
13+
if got := printVari(); got != nil {
14+
t.Errorf("printVari(): got: %#v; want %#v.", got, nil)
15+
}
16+
17+
{
18+
var want []string
19+
if got := printVari(want...); got != nil {
20+
t.Errorf("printVari(want...): got: %#v; want %#v.", got, nil)
21+
}
22+
}
1123

12-
if got := printVari(); got != nil {
13-
t.Errorf("printVari(): got: %#v; want %#v.", got, nil)
14-
}
24+
{
25+
want := []string{}
26+
if got := printVari(want...); got == nil || len(got) != len(want) {
27+
t.Errorf("printVari(want...): got: %#v; want %#v.", got, want)
28+
}
29+
}
30+
})
31+
t.Run("mixed", func(t *testing.T) {
32+
printVari := func(_ int, strs ...string) []string {
33+
return strs
34+
}
35+
36+
if got := printVari(0); got != nil {
37+
t.Errorf("printVari(): got: %#v; want %#v.", got, nil)
38+
}
1539

16-
{
17-
var want []string
18-
if got := printVari(want...); got != nil {
19-
t.Errorf("printVari(want...): got: %#v; want %#v.", got, nil)
40+
{
41+
var want []string
42+
if got := printVari(0, want...); got != nil {
43+
t.Errorf("printVari(want...): got: %#v; want %#v.", got, nil)
44+
}
2045
}
21-
}
2246

23-
{
24-
want := []string{}
25-
if got := printVari(want...); got == nil || len(got) != len(want) {
26-
t.Errorf("printVari(want...): got: %#v; want %#v.", got, want)
47+
{
48+
want := []string{}
49+
if got := printVari(0, want...); got == nil || len(got) != len(want) {
50+
t.Errorf("printVari(want...): got: %#v; want %#v.", got, want)
51+
}
2752
}
28-
}
53+
})
2954
}

0 commit comments

Comments
 (0)