From 01c358d5eb221201013d8b85f230960e2b5dd019 Mon Sep 17 00:00:00 2001 From: Anton Medvedev Date: Wed, 6 Sep 2023 10:36:40 +0200 Subject: [PATCH] Fix type checker for "in" operator Fixes #426 --- checker/checker.go | 13 ++----------- checker/checker_test.go | 5 +++++ checker/types.go | 15 +++++++++++++++ expr_test.go | 8 ++++++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/checker/checker.go b/checker/checker.go index 287164b64..3e787fa4f 100644 --- a/checker/checker.go +++ b/checker/checker.go @@ -242,16 +242,7 @@ func (v *checker) BinaryNode(node *ast.BinaryNode) (reflect.Type, info) { switch node.Operator { case "==", "!=": - if isNumber(l) && isNumber(r) { - return boolType, info{} - } - if l == nil || r == nil { // It is possible to compare with nil. - return boolType, info{} - } - if l.Kind() == r.Kind() { - return boolType, info{} - } - if isAny(l) || isAny(r) { + if isComparable(l, r) { return boolType, info{} } @@ -357,7 +348,7 @@ func (v *checker) BinaryNode(node *ast.BinaryNode) (reflect.Type, info) { if l == nil { // It is possible to compare with nil. return boolType, info{} } - if !isAny(l) && !l.AssignableTo(r.Elem()) && !(isInteger(l) && isInteger(r.Elem())) { + if !isComparable(l, r.Elem()) { return v.error(node, "cannot use %v as type %v in array", l, r.Elem()) } return boolType, info{} diff --git a/checker/checker_test.go b/checker/checker_test.go index 69c0a8e76..7528f1da9 100644 --- a/checker/checker_test.go +++ b/checker/checker_test.go @@ -513,6 +513,11 @@ cannot use float64 as type int in map key (1:5) | 1/2 in MapIntAny | ....^ +0.5 in ArrayOfFoo +cannot use float64 as type *mock.Foo in array (1:5) + | 0.5 in ArrayOfFoo + | ....^ + repeat("0", 1/0) cannot use float64 as argument (type int) to call repeat (1:14) | repeat("0", 1/0) diff --git a/checker/types.go b/checker/types.go index 1665527f0..890d74a5f 100644 --- a/checker/types.go +++ b/checker/types.go @@ -227,3 +227,18 @@ func kind(t reflect.Type) reflect.Kind { } return t.Kind() } + +func isComparable(l, r reflect.Type) bool { + if l == nil || r == nil { + return true + } + switch { + case l.Kind() == r.Kind(): + return true + case isNumber(l) && isNumber(r): + return true + case isAny(l) || isAny(r): + return true + } + return false +} diff --git a/expr_test.go b/expr_test.go index 84d31bf9e..1857403ec 100644 --- a/expr_test.go +++ b/expr_test.go @@ -1084,6 +1084,14 @@ func TestExpr(t *testing.T) { `4/2 == 2`, true, }, + { + `.5 in 0..1`, + false, + }, + { + `.5 in ArrayOfInt`, + false, + }, } for _, tt := range tests {