Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expr.WithContext requires expr.Env? #753

Open
swdunlop opened this issue Feb 8, 2025 · 2 comments
Open

expr.WithContext requires expr.Env? #753

swdunlop opened this issue Feb 8, 2025 · 2 comments

Comments

@swdunlop
Copy link

swdunlop commented Feb 8, 2025

When using the expr.WithContext option, the named variable must also be provided at compilation time using expr.Env, otherwise the patch seems to fail to correctly update calls to functions that require a context. (I'm not exactly sure why this happens, but if it's necessary, perhaps we should document it?)

Reproduction:

env := map[string]any{
	`cancelled`: func(ctx context.Context) bool {
		return ctx.Err() != nil
	},
	`ctx`: context.Background(),
}
program, err := expr.Compile(`cancelled()`,
	expr.WithContext(`ctx`),
	// expr.Env(env),
)
if err != nil {
	panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
	panic(err)
}
fmt.Println(output)

With the expr.Env line commented out, this will fail (see playground), and with it uncommented, it succeeds (see playground). The error produced at runtime is:

reflect: Call with too few input arguments (1:1)
	 | cancelled()
	 | ^
@swdunlop swdunlop changed the title expr.WithContext Requires expr.Env expr.WithContext requires expr.Env? Feb 8, 2025
@swdunlop
Copy link
Author

swdunlop commented Feb 8, 2025

Since this error also happens if cancelled is not bound at compilation but is bound at run, playground, I assume the problem is that Patch cannot figure out the argument of the function at compilation time.

@antonmedv
Copy link
Member

Yes, exactly. If patcher is not able to figure out the types, it will not add context arg.

But there is a way without a patcher: https://go.dev/play/p/zKG4Ro4jlo4

package main

import (
	"context"
	"fmt"

	"github.com/expr-lang/expr"
)

type Env struct {
	ctx context.Context
	Var string
}

func (e Env) Fn(s string) (string, error) {
	if e.ctx.Err() != nil {
		return "", e.ctx.Err()
	}
	return s, nil
}

func main() {
	code := `Fn(Var)`

	program, err := expr.Compile(code, expr.Env(Env{}))
	if err != nil {
		panic(err)
	}

	ctx, cancel := context.WithCancel(context.Background())
	env := Env{
		ctx: ctx,
		Var: "foo",
	}
	output, err := expr.Run(program, env)
	if err != nil {
		panic(err)
	}
	fmt.Println(output)

	cancel()
	_, err = expr.Run(program, env)
	if err != nil {
		panic(err)
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants