Skip to content

Commit 32d7e0e

Browse files
committed
fix(checker): correct variadic method arg type
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 <ville@vesilehto.fi>
1 parent d472286 commit 32d7e0e

File tree

4 files changed

+47
-1
lines changed

4 files changed

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

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)