expr-lang / expr

Expression language and expression evaluation for Go
https://expr-lang.org
MIT License
6.31k stars 405 forks source link

Can't compile function with slice as a parameter #725

Open MEZk opened 1 week ago

MEZk commented 1 week ago

The following code results in compilation error: cannot use []interface {} as argument (type []string) to call HasPhones (1:18)

package main

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

type client struct {
}

func (c *client) HasPhones(phones []string) bool {
    return false
}

type env struct {
    Client *client
}

func main() {
    _, err := expr.Compile("Client.HasPhones([\"7\"])", expr.Env(env{}))
    if err != nil {
        panic(err)
    }
}

go 1.22.5 github.com/expr-lang/expr v1.16.9

I expect that the code can be compiled without errors.

MEZk commented 1 week ago

I think the problem is in checker.go checkFunc:

if !t.AssignableTo(in) && t.Kind() != reflect.Interface {
  return v.error(arg, "cannot use %v as argument (type %v) to call %v ", t, in, name)
}

If t is an array (slice) of non interface types checker should check that all elements have the same type,

MEZk commented 1 week ago

By the way, expr.Eval works OK:

func main() {
    _, err := expr.Eval("Client.HasPhones([\"7\"])", env{})
    if err != nil {
        panic(err)
    }
}

Same is for expr.Run – no problems:

func main() {
    p, err := expr.Compile("Client.HasPhones([\"7\"])")
    if err != nil {
        panic(err)
    }

    _, err = expr.Run(p, env{})
    if err != nil {
        panic(err)
    }
}
MEZk commented 1 week ago

Test case to prove problem https://github.com/MEZk/expr/commit/527303c94dfe331fe74383af7d39c4bd559b960c . Possible fix https://github.com/MEZk/expr/commit/413d52da08a3443ad9641b30570f1873e5be9d0a (but I'm not sure, needs further investigation).

Concerns:

So if we know that argNature is an array and all elements of the array have the same type (see checker.ArrayNode) we can get the type of the array and compare the type with the first argument of the function – in to check the validity of arguments.