Skip to content

Commit

Permalink
Add type checks for 42 in ["a"] as invalid
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmedv committed Sep 20, 2023
1 parent 89ddc14 commit 5916dc2
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 19 deletions.
28 changes: 25 additions & 3 deletions checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ type varScope struct {
type info struct {
method bool
fn *ast.Function

// elem is element type of array or map.
// Arrays created with type []any, but
// we would like to detect expressions
// like `42 in ["a"]` as invalid.
elem reflect.Type
}

func (v *checker) visit(node ast.Node) (reflect.Type, info) {
Expand Down Expand Up @@ -227,7 +233,7 @@ func (v *checker) UnaryNode(node *ast.UnaryNode) (reflect.Type, info) {

func (v *checker) BinaryNode(node *ast.BinaryNode) (reflect.Type, info) {
l, _ := v.visit(node.Left)
r, _ := v.visit(node.Right)
r, ri := v.visit(node.Right)

l = deref(l)
r = deref(r)
Expand Down Expand Up @@ -351,6 +357,9 @@ func (v *checker) BinaryNode(node *ast.BinaryNode) (reflect.Type, info) {
if !isComparable(l, r.Elem()) {
return v.error(node, "cannot use %v as type %v in array", l, r.Elem())
}
if !isComparable(l, ri.elem) {
return v.error(node, "cannot use %v as type %v in array", l, ri.elem)
}
return boolType, info{}
}
if isAny(l) && anyOf(r, isString, isArray, isMap) {
Expand Down Expand Up @@ -1067,8 +1076,21 @@ func (v *checker) ConditionalNode(node *ast.ConditionalNode) (reflect.Type, info
}

func (v *checker) ArrayNode(node *ast.ArrayNode) (reflect.Type, info) {
for _, node := range node.Nodes {
v.visit(node)
var prev reflect.Type
allElementsAreSameType := true
for i, node := range node.Nodes {
curr, _ := v.visit(node)
if i > 0 {
if curr == nil || prev == nil {
allElementsAreSameType = false
} else if curr.Kind() != prev.Kind() {
allElementsAreSameType = false
}
}
prev = curr
}
if allElementsAreSameType && prev != nil {
return arrayType, info{elem: prev}
}
return arrayType, info{}
}
Expand Down
10 changes: 8 additions & 2 deletions checker/checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/antonmedv/expr"
"github.com/antonmedv/expr/ast"
"github.com/antonmedv/expr/checker"
"github.com/antonmedv/expr/conf"
"github.com/antonmedv/expr/parser"
"github.com/antonmedv/expr/test/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCheck(t *testing.T) {
Expand Down Expand Up @@ -547,6 +548,11 @@ map(1..9, #unknown)
unknown pointer #unknown (1:11)
| map(1..9, #unknown)
| ..........^
42 in ["a", "b", "c"]
cannot use int as type string in array (1:4)
| 42 in ["a", "b", "c"]
| ...^
`

func TestCheck_error(t *testing.T) {
Expand Down
7 changes: 4 additions & 3 deletions expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/antonmedv/expr"
"github.com/antonmedv/expr/ast"
"github.com/antonmedv/expr/file"
"github.com/antonmedv/expr/test/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func ExampleEval() {
Expand Down Expand Up @@ -1997,4 +1998,4 @@ func TestIssue432(t *testing.T) {
out, err := expr.Run(program, env)
assert.NoError(t, err)
assert.Equal(t, float64(10), out)
}
}
3 changes: 0 additions & 3 deletions test/fuzz/fuzz_corpus.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2711,7 +2711,6 @@ add == score != true
add == score and i32 >= 1
add == score or 0.5 < 1
add in [div]
add not in [f64]
add not in sort(array)
add(1, 1) ** i
add(1, 1) ^ i
Expand Down Expand Up @@ -3113,7 +3112,6 @@ array == map(array, add)
array == nil != nil
array == nil != true ? 0.5 : 0.5
array == nil && (false || ok)
array in [i]
array[-1]
array[-i32]
array[-i64]
Expand Down Expand Up @@ -6102,7 +6100,6 @@ foo == foo ? i : score
foo == last(list)
foo == nil == nil
foo == nil || ok
foo in [half]
foo in filter(list, false)
foo in list
foo in list ? nil : i32
Expand Down
Binary file modified test/fuzz/fuzz_expr_seed_corpus.zip
Binary file not shown.
3 changes: 0 additions & 3 deletions testdata/examples.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2711,7 +2711,6 @@ add == score != true
add == score and i32 >= 1
add == score or 0.5 < 1
add in [div]
add not in [f64]
add not in sort(array)
add(1, 1) ** i
add(1, 1) ^ i
Expand Down Expand Up @@ -3113,7 +3112,6 @@ array == map(array, add)
array == nil != nil
array == nil != true ? 0.5 : 0.5
array == nil && (false || ok)
array in [i]
array[-1]
array[-i32]
array[-i64]
Expand Down Expand Up @@ -6102,7 +6100,6 @@ foo == foo ? i : score
foo == last(list)
foo == nil == nil
foo == nil || ok
foo in [half]
foo in filter(list, false)
foo in list
foo in list ? nil : i32
Expand Down
6 changes: 1 addition & 5 deletions vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,7 @@ func In(needle any, array any) bool {
if needle == nil {
value = v.MapIndex(reflect.Zero(v.Type().Key()))
} else {
n := reflect.ValueOf(needle)
if !n.IsValid() {
panic(fmt.Sprintf("cannot use %T as index to %T", needle, array))
}
value = v.MapIndex(n)
value = v.MapIndex(reflect.ValueOf(needle))
}
if value.IsValid() {
return true
Expand Down

0 comments on commit 5916dc2

Please sign in to comment.