Skip to content

Commit cda16c2

Browse files
committed
Fix type checker to visit all arguments of func even in args count mismatch
1 parent 71bc9f9 commit cda16c2

File tree

4 files changed

+45
-9
lines changed

4 files changed

+45
-9
lines changed

checker/checker.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -906,28 +906,38 @@ func (v *checker) checkArguments(
906906
fnInOffset = 1
907907
}
908908

909+
var err *file.Error
909910
if fn.IsVariadic() {
910911
if len(arguments) < fnNumIn-1 {
911-
return anyType, &file.Error{
912+
err = &file.Error{
912913
Location: node.Location(),
913914
Message: fmt.Sprintf("not enough arguments to call %v", name),
914915
}
915916
}
916917
} else {
917918
if len(arguments) > fnNumIn {
918-
return anyType, &file.Error{
919+
err = &file.Error{
919920
Location: node.Location(),
920921
Message: fmt.Sprintf("too many arguments to call %v", name),
921922
}
922923
}
923924
if len(arguments) < fnNumIn {
924-
return anyType, &file.Error{
925+
err = &file.Error{
925926
Location: node.Location(),
926927
Message: fmt.Sprintf("not enough arguments to call %v", name),
927928
}
928929
}
929930
}
930931

932+
if err != nil {
933+
// If we have an error, we should still visit all arguments to
934+
// type check them, as a patch can fix the error later.
935+
for _, arg := range arguments {
936+
_, _ = v.visit(arg)
937+
}
938+
return fn.Out(0), err
939+
}
940+
931941
for i, arg := range arguments {
932942
t, _ := v.visit(arg)
933943

checker/checker_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ type mock.Foo has no field bar (1:4)
170170
| Foo['bar']
171171
| ...^
172172
173-
Foo.Method(Not)
173+
Foo.Method(42)
174174
too many arguments to call Method (1:5)
175-
| Foo.Method(Not)
175+
| Foo.Method(42)
176176
| ....^
177177
178178
Foo.Bar()
@@ -210,9 +210,9 @@ array elements can only be selected using an integer (got string) (1:12)
210210
| ArrayOfFoo.Not
211211
| ...........^
212212
213-
FuncParam(Not)
213+
FuncParam(true)
214214
not enough arguments to call FuncParam (1:1)
215-
| FuncParam(Not)
215+
| FuncParam(true)
216216
| ^
217217
218218
MapOfFoo['str'].Not

patcher/with_context.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ type WithContext struct {
1313

1414
// Visit adds WithContext.Name argument to all functions calls with a context.Context argument.
1515
func (w WithContext) Visit(node *ast.Node) {
16-
switch (*node).(type) {
16+
switch call := (*node).(type) {
1717
case *ast.CallNode:
18-
call := (*node).(*ast.CallNode)
1918
fn := call.Callee.Type()
19+
if fn == nil {
20+
return
21+
}
2022
if fn.Kind() != reflect.Func {
2123
return
2224
}

patcher/with_context_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,27 @@ func TestWithContext_with_env_method_chain(t *testing.T) {
104104
require.NoError(t, err)
105105
require.Equal(t, int64(42), output)
106106
}
107+
108+
func TestWithContext_issue529(t *testing.T) {
109+
env := map[string]any{
110+
"ctx": context.Background(),
111+
"foo": func(ctx context.Context, n int) int {
112+
if ctx == nil {
113+
panic("wanted a context")
114+
}
115+
return n + 1
116+
},
117+
}
118+
options := []expr.Option{
119+
expr.Env(env),
120+
expr.WithContext("ctx"),
121+
}
122+
123+
code := "foo(0) | foo()"
124+
program, err := expr.Compile(code, options...)
125+
require.NoError(t, err)
126+
127+
out, err := expr.Run(program, env)
128+
require.NoError(t, err)
129+
require.Equal(t, 2, out)
130+
}

0 commit comments

Comments
 (0)