From 48a03a487406b93b04bc99428c0f8e0c984add5b Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Sat, 11 Mar 2023 14:46:12 +0530 Subject: [PATCH] checker: check wrapped Option types before comparison (#17590) --- vlib/v/checker/infix.v | 8 +++--- .../tests/option_wrapped_cmp_op_err.out | 27 +++++++++++++++++++ .../tests/option_wrapped_cmp_op_err.vv | 7 +++++ vlib/v/tests/option_multi_return_test.v | 2 +- 4 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 vlib/v/checker/tests/option_wrapped_cmp_op_err.out create mode 100644 vlib/v/checker/tests/option_wrapped_cmp_op_err.vv diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index 97ca41a12b..1b46d47fb8 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -669,10 +669,12 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { // TODO move this to symmetric_check? Right now it would break `return 0` for `fn()?int ` left_is_option := left_type.has_flag(.option) right_is_option := right_type.has_flag(.option) - if node.left !in [ast.Ident, ast.SelectorExpr, ast.ComptimeSelector] - && (left_is_option || right_is_option) { + if left_is_option || right_is_option { opt_infix_pos := if left_is_option { left_pos } else { right_pos } - c.error('unwrapped option cannot be used in an infix expression', opt_infix_pos) + if (node.left !in [ast.Ident, ast.SelectorExpr, ast.ComptimeSelector] + || node.op in [.eq, .ne, .lt, .gt, .le, .ge]) && right_sym.kind != .none_ { + c.error('unwrapped option cannot be used in an infix expression', opt_infix_pos) + } } left_is_result := left_type.has_flag(.result) diff --git a/vlib/v/checker/tests/option_wrapped_cmp_op_err.out b/vlib/v/checker/tests/option_wrapped_cmp_op_err.out new file mode 100644 index 0000000000..56d4a42393 --- /dev/null +++ b/vlib/v/checker/tests/option_wrapped_cmp_op_err.out @@ -0,0 +1,27 @@ +vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:3:10: error: unwrapped option cannot be used in an infix expression + 1 | fn main() { + 2 | a := ?string("hi") + 3 | println(a == 'hi') + | ^ + 4 | println('hi' == a) + 5 | println(a != 'hi') +vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:4:18: error: unwrapped option cannot be used in an infix expression + 2 | a := ?string("hi") + 3 | println(a == 'hi') + 4 | println('hi' == a) + | ^ + 5 | println(a != 'hi') + 6 | println('hi' != a) +vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:5:10: error: unwrapped option cannot be used in an infix expression + 3 | println(a == 'hi') + 4 | println('hi' == a) + 5 | println(a != 'hi') + | ^ + 6 | println('hi' != a) + 7 | } +vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:6:18: error: unwrapped option cannot be used in an infix expression + 4 | println('hi' == a) + 5 | println(a != 'hi') + 6 | println('hi' != a) + | ^ + 7 | } diff --git a/vlib/v/checker/tests/option_wrapped_cmp_op_err.vv b/vlib/v/checker/tests/option_wrapped_cmp_op_err.vv new file mode 100644 index 0000000000..8d66a00a13 --- /dev/null +++ b/vlib/v/checker/tests/option_wrapped_cmp_op_err.vv @@ -0,0 +1,7 @@ +fn main() { + a := ?string("hi") + println(a == 'hi') + println('hi' == a) + println(a != 'hi') + println('hi' != a) +} diff --git a/vlib/v/tests/option_multi_return_test.v b/vlib/v/tests/option_multi_return_test.v index 0c31a2fa73..5c3ef8e7ea 100644 --- a/vlib/v/tests/option_multi_return_test.v +++ b/vlib/v/tests/option_multi_return_test.v @@ -10,7 +10,7 @@ fn foo(val ?int) (?int, ?int) { fn test_multi_return() { a, b := foo(100) - assert a == 100 + assert a? == 100 assert b == none }