Skip to content

Commit c020e95

Browse files
authored
fix(checker): correct variadic method arg type (#889)
When checking arguments for variadic methods, the index passed to InElem used "fnNumIn-1", but fnNumIn had already been decremented to exclude the receiver. This caused InElem to access the receiver type (index 0) instead of the variadic parameter type, causing a type error ("cannot use string as argument"). Add "fnInOffset" to the index calculation to correctly reference the variadic parameter. Regression tests included. Signed-off-by: Ville Vesilehto <[email protected]>
1 parent d472286 commit c020e95

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

checker/checker.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,7 @@ func (v *Checker) checkArguments(
11121112
if isVariadic && i >= fnNumIn-1 {
11131113
// For variadic arguments fn(xs ...int), go replaces type of xs (int) with ([]int).
11141114
// As we compare arguments one by one, we need underling type.
1115-
in = fn.InElem(&v.config.NtCache, fnNumIn-1)
1115+
in = fn.InElem(&v.config.NtCache, fnNumIn-1+fnInOffset)
11161116
} else {
11171117
in = fn.In(&v.config.NtCache, i+fnInOffset)
11181118
}

checker/checker_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ func TestCheck(t *testing.T) {
135135
{"let foo = 1; foo == 1"},
136136
{"(Embed).EmbedPointerEmbedInt > 0"},
137137
{"(true ? [1] : [[1]])[0][0] == 1"},
138+
{"Foo.VariadicMethod('a', 'b', 'c')"},
138139
}
139140

140141
c := new(checker.Checker)

test/issues/888/issue_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/expr-lang/expr"
7+
"github.com/expr-lang/expr/internal/testify/require"
8+
)
9+
10+
type Container struct {
11+
ID string
12+
List []string
13+
}
14+
15+
func (c Container) IncludesAny(s ...string) bool {
16+
for _, l := range c.List {
17+
// Note: original issue used "slices.Contains" but
18+
// it is not available in the minimum Go version of expr (1.18).
19+
for _, v := range s {
20+
if v == l {
21+
return true
22+
}
23+
}
24+
}
25+
return false
26+
}
27+
28+
func TestIssue888(t *testing.T) {
29+
env := map[string]any{
30+
"Container": Container{
31+
ID: "id",
32+
List: []string{"foo", "bar", "baz"},
33+
},
34+
}
35+
36+
code := `Container.IncludesAny("nope", "nope again", "bar")`
37+
38+
program, err := expr.Compile(code, expr.Env(env))
39+
require.NoError(t, err)
40+
41+
output, err := expr.Run(program, env)
42+
require.NoError(t, err)
43+
require.Equal(t, true, output)
44+
}

test/mock/mock.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ func (Foo) String() string {
186186
return "Foo.String"
187187
}
188188

189+
func (Foo) VariadicMethod(_ ...string) bool {
190+
return true
191+
}
192+
189193
type Bar struct {
190194
Baz string
191195
}

0 commit comments

Comments
 (0)