Skip to content

Commit 98d79a9

Browse files
committed
Fix type any type propagation with patcher relationship
1 parent 6691bc8 commit 98d79a9

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

checker/checker.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -539,9 +539,22 @@ func (v *checker) SliceNode(node *ast.SliceNode) (reflect.Type, info) {
539539

540540
func (v *checker) CallNode(node *ast.CallNode) (reflect.Type, info) {
541541
t, i := v.functionReturnType(node)
542-
if node.Type() != nil {
542+
543+
// Check if type was set on node (for example, by patcher)
544+
// and use node type instead of function return type.
545+
//
546+
// If node type is anyType, then we should use function
547+
// return type. For example, on error we return anyType
548+
// for a call `errCall().Method()` and method will be
549+
// evaluated on `anyType.Method()`, so return type will
550+
// be anyType `anyType.Method(): anyType`. Patcher can
551+
// fix `errCall()` to return proper type, so on second
552+
// checker pass we should replace anyType on method node
553+
// with new correct function return type.
554+
if node.Type() != nil && node.Type() != anyType {
543555
return node.Type(), i
544556
}
557+
545558
return t, i
546559
}
547560

patcher/with_context_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,46 @@ func TestWithContext_with_env_Function(t *testing.T) {
6161
require.NoError(t, err)
6262
require.Equal(t, 42, output)
6363
}
64+
65+
type TestFoo struct {
66+
contextValue int
67+
}
68+
69+
func (f *TestFoo) GetValue(a int) int64 {
70+
return int64(f.contextValue + a)
71+
}
72+
73+
func TestWithContext_with_env_method_chain(t *testing.T) {
74+
env := map[string]any{
75+
"ctx": context.TODO(),
76+
}
77+
78+
fn := expr.Function("fn",
79+
func(params ...any) (any, error) {
80+
ctx := params[0].(context.Context)
81+
82+
contextValue := ctx.Value("value").(int)
83+
84+
return &TestFoo{
85+
contextValue: contextValue,
86+
}, nil
87+
},
88+
new(func(context.Context) *TestFoo),
89+
)
90+
91+
program, err := expr.Compile(
92+
`fn().GetValue(40)`,
93+
expr.Env(env),
94+
expr.WithContext("ctx"),
95+
fn,
96+
expr.AsInt64(),
97+
)
98+
require.NoError(t, err)
99+
100+
ctx := context.WithValue(context.Background(), "value", 2)
101+
env["ctx"] = ctx
102+
103+
output, err := expr.Run(program, env)
104+
require.NoError(t, err)
105+
require.Equal(t, int64(42), output)
106+
}

0 commit comments

Comments
 (0)