diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index ce395ade0c..00d337ac85 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -457,7 +457,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } else if node.left !in [ast.Ident, ast.SelectorExpr, ast.ComptimeSelector] && (left_type.has_flag(.option) || right_type.has_flag(.option)) { opt_comp_pos := if left_type.has_flag(.option) { left_pos } else { right_pos } - c.error('unwrapped option cannot be compared in an infix expression', + c.error('unwrapped Option cannot be compared in an infix expression', opt_comp_pos) } } @@ -471,6 +471,11 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { if !node.is_stmt { c.error('array append cannot be used in an expression', node.pos) } + if left_type.has_flag(.option) && node.left is ast.Ident + && (node.left as ast.Ident).or_expr.kind == .absent { + c.error('unwrapped Option cannot be used in an infix expression', + node.pos) + } // `array << elm` c.check_expr_opt_call(node.right, right_type) node.auto_locked, _ = c.fail_if_immutable(node.left) @@ -695,7 +700,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { opt_infix_pos := if left_is_option { left_pos } else { right_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) + c.error('unwrapped Option cannot be used in an infix expression', opt_infix_pos) } } @@ -703,7 +708,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { right_is_result := right_type.has_flag(.result) if left_is_result || right_is_result { opt_infix_pos := if left_is_result { left_pos } else { right_pos } - c.error('unwrapped result cannot be used in an infix expression', opt_infix_pos) + c.error('unwrapped Result cannot be used in an infix expression', opt_infix_pos) } // Dual sides check (compatibility check) diff --git a/vlib/v/checker/tests/infix_compare_option_err.out b/vlib/v/checker/tests/infix_compare_option_err.out index ec5c4be16d..ecaa3f6ddc 100644 --- a/vlib/v/checker/tests/infix_compare_option_err.out +++ b/vlib/v/checker/tests/infix_compare_option_err.out @@ -1,7 +1,7 @@ -vlib/v/checker/tests/infix_compare_option_err.vv:6:5: error: unwrapped option cannot be compared in an infix expression - 4 | +vlib/v/checker/tests/infix_compare_option_err.vv:6:5: error: unwrapped Option cannot be compared in an infix expression + 4 | 5 | fn main() { 6 | if foo() > foo() { | ~~~~~ 7 | } - 8 | } \ No newline at end of file + 8 | } diff --git a/vlib/v/checker/tests/infix_err.out b/vlib/v/checker/tests/infix_err.out index f3573fe03c..9e05ae3e44 100644 --- a/vlib/v/checker/tests/infix_err.out +++ b/vlib/v/checker/tests/infix_err.out @@ -17,17 +17,17 @@ vlib/v/checker/tests/infix_err.vv:9:9: error: `+` cannot be used with `?string` 8 | _ = f() + '' 9 | _ = f() + f() | ^ - 10 | + 10 | 11 | _ = 4 + g() vlib/v/checker/tests/infix_err.vv:11:7: error: `+` cannot be used with `?int` 9 | _ = f() + f() - 10 | + 10 | 11 | _ = 4 + g() | ^ 12 | _ = int(0) + g() // FIXME not detected 13 | _ = g() + int(3) -vlib/v/checker/tests/infix_err.vv:12:14: error: unwrapped option cannot be used in an infix expression - 10 | +vlib/v/checker/tests/infix_err.vv:12:14: error: unwrapped Option cannot be used in an infix expression + 10 | 11 | _ = 4 + g() 12 | _ = int(0) + g() // FIXME not detected | ~~~ @@ -45,10 +45,10 @@ vlib/v/checker/tests/infix_err.vv:14:9: error: `+` cannot be used with `?int` 13 | _ = g() + int(3) 14 | _ = g() + 3 | ^ - 15 | + 15 | 16 | // binary operands vlib/v/checker/tests/infix_err.vv:17:5: error: left operand for `&&` is not a boolean - 15 | + 15 | 16 | // binary operands 17 | _ = 1 && 2 | ^ @@ -59,10 +59,10 @@ vlib/v/checker/tests/infix_err.vv:18:13: error: right operand for `||` is not a 17 | _ = 1 && 2 18 | _ = true || 2 | ^ - 19 | + 19 | 20 | // boolean expressions vlib/v/checker/tests/infix_err.vv:21:22: error: ambiguous boolean expression. use `()` to ensure correct order of operations - 19 | + 19 | 20 | // boolean expressions 21 | _ = 1 == 1 && 2 == 2 || 3 == 3 | ~~ @@ -78,4 +78,4 @@ vlib/v/checker/tests/infix_err.vv:24:2: error: ambiguous boolean expression. use 22 | _ = 1 == 1 23 | && 2 == 2 || 3 == 3 24 | && 4 == 4 - | ~~ \ No newline at end of file + | ~~ diff --git a/vlib/v/checker/tests/option_wrapped_cmp_op_err.out b/vlib/v/checker/tests/option_wrapped_cmp_op_err.out index 56d4a42393..265f2e11fe 100644 --- a/vlib/v/checker/tests/option_wrapped_cmp_op_err.out +++ b/vlib/v/checker/tests/option_wrapped_cmp_op_err.out @@ -1,25 +1,25 @@ -vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:3:10: error: unwrapped option cannot be used in an infix expression +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 +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 +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 +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) diff --git a/vlib/v/checker/tests/unwrapped_option_infix.out b/vlib/v/checker/tests/unwrapped_option_infix.out index ece51059b6..e3841c2c2a 100644 --- a/vlib/v/checker/tests/unwrapped_option_infix.out +++ b/vlib/v/checker/tests/unwrapped_option_infix.out @@ -1,5 +1,5 @@ -vlib/v/checker/tests/unwrapped_option_infix.vv:5:9: error: unwrapped option cannot be used in an infix expression +vlib/v/checker/tests/unwrapped_option_infix.vv:5:9: error: unwrapped Option cannot be used in an infix expression 3 | } - 4 | + 4 | 5 | println(test() == '') - | ~~~~~~ \ No newline at end of file + | ~~~~~~ diff --git a/vlib/v/checker/tests/unwrapped_result_infix_err.out b/vlib/v/checker/tests/unwrapped_result_infix_err.out index 69de1f98dd..7ef97c8df3 100644 --- a/vlib/v/checker/tests/unwrapped_result_infix_err.out +++ b/vlib/v/checker/tests/unwrapped_result_infix_err.out @@ -1,8 +1,7 @@ -vlib/v/checker/tests/unwrapped_result_infix_err.vv:7:9: error: unwrapped result cannot be used in an infix expression +vlib/v/checker/tests/unwrapped_result_infix_err.vv:7:9: error: unwrapped Result cannot be used in an infix expression 5 | fn g() ! { 6 | assert f('1')! == true 7 | assert f('1') == true | ~~~~~~ 8 | } 9 | - diff --git a/vlib/v/checker/tests/wrong_shift_left_option_err.out b/vlib/v/checker/tests/wrong_shift_left_option_err.out new file mode 100644 index 0000000000..7f6595d2bb --- /dev/null +++ b/vlib/v/checker/tests/wrong_shift_left_option_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/wrong_shift_left_option_err.vv:7:4: error: unwrapped Option cannot be used in an infix expression + 5 | fn main() { + 6 | mut a := ?[]SomeStruct([SomeStruct{}, SomeStruct{}]) // struct type + 7 | a << []SomeStruct{len: 20} + | ~~ + 8 | mut b := ?[]int([2, 8]) // primitive type + 9 | b << [1, 3, 4] +vlib/v/checker/tests/wrong_shift_left_option_err.vv:9:4: error: unwrapped Option cannot be used in an infix expression + 7 | a << []SomeStruct{len: 20} + 8 | mut b := ?[]int([2, 8]) // primitive type + 9 | b << [1, 3, 4] + | ~~ + 10 | dump(a?.len) + 11 | dump(b) diff --git a/vlib/v/checker/tests/wrong_shift_left_option_err.vv b/vlib/v/checker/tests/wrong_shift_left_option_err.vv new file mode 100644 index 0000000000..be7fdbc8d1 --- /dev/null +++ b/vlib/v/checker/tests/wrong_shift_left_option_err.vv @@ -0,0 +1,12 @@ +pub struct SomeStruct { + i int +} + +fn main() { + mut a := ?[]SomeStruct([SomeStruct{}, SomeStruct{}]) // struct type + a << []SomeStruct{len: 20} + mut b := ?[]int([2, 8]) // primitive type + b << [1, 3, 4] + dump(a?.len) + dump(b) +}