Skip to content

Commit d17f6f6

Browse files
authored
checker: fix missing check for unwrapped shift operation (#18451)
1 parent 84cf448 commit d17f6f6

8 files changed

+54
-24
lines changed

vlib/v/checker/infix.v

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
457457
} else if node.left !in [ast.Ident, ast.SelectorExpr, ast.ComptimeSelector]
458458
&& (left_type.has_flag(.option) || right_type.has_flag(.option)) {
459459
opt_comp_pos := if left_type.has_flag(.option) { left_pos } else { right_pos }
460-
c.error('unwrapped option cannot be compared in an infix expression',
460+
c.error('unwrapped Option cannot be compared in an infix expression',
461461
opt_comp_pos)
462462
}
463463
}
@@ -471,6 +471,11 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
471471
if !node.is_stmt {
472472
c.error('array append cannot be used in an expression', node.pos)
473473
}
474+
if left_type.has_flag(.option) && node.left is ast.Ident
475+
&& (node.left as ast.Ident).or_expr.kind == .absent {
476+
c.error('unwrapped Option cannot be used in an infix expression',
477+
node.pos)
478+
}
474479
// `array << elm`
475480
c.check_expr_opt_call(node.right, right_type)
476481
node.auto_locked, _ = c.fail_if_immutable(node.left)
@@ -695,15 +700,15 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
695700
opt_infix_pos := if left_is_option { left_pos } else { right_pos }
696701
if (node.left !in [ast.Ident, ast.SelectorExpr, ast.ComptimeSelector]
697702
|| node.op in [.eq, .ne, .lt, .gt, .le, .ge]) && right_sym.kind != .none_ {
698-
c.error('unwrapped option cannot be used in an infix expression', opt_infix_pos)
703+
c.error('unwrapped Option cannot be used in an infix expression', opt_infix_pos)
699704
}
700705
}
701706

702707
left_is_result := left_type.has_flag(.result)
703708
right_is_result := right_type.has_flag(.result)
704709
if left_is_result || right_is_result {
705710
opt_infix_pos := if left_is_result { left_pos } else { right_pos }
706-
c.error('unwrapped result cannot be used in an infix expression', opt_infix_pos)
711+
c.error('unwrapped Result cannot be used in an infix expression', opt_infix_pos)
707712
}
708713

709714
// Dual sides check (compatibility check)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
vlib/v/checker/tests/infix_compare_option_err.vv:6:5: error: unwrapped option cannot be compared in an infix expression
2-
4 |
1+
vlib/v/checker/tests/infix_compare_option_err.vv:6:5: error: unwrapped Option cannot be compared in an infix expression
2+
4 |
33
5 | fn main() {
44
6 | if foo() > foo() {
55
| ~~~~~
66
7 | }
7-
8 | }
7+
8 | }

vlib/v/checker/tests/infix_err.out

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ vlib/v/checker/tests/infix_err.vv:9:9: error: `+` cannot be used with `?string`
1717
8 | _ = f() + ''
1818
9 | _ = f() + f()
1919
| ^
20-
10 |
20+
10 |
2121
11 | _ = 4 + g()
2222
vlib/v/checker/tests/infix_err.vv:11:7: error: `+` cannot be used with `?int`
2323
9 | _ = f() + f()
24-
10 |
24+
10 |
2525
11 | _ = 4 + g()
2626
| ^
2727
12 | _ = int(0) + g() // FIXME not detected
2828
13 | _ = g() + int(3)
29-
vlib/v/checker/tests/infix_err.vv:12:14: error: unwrapped option cannot be used in an infix expression
30-
10 |
29+
vlib/v/checker/tests/infix_err.vv:12:14: error: unwrapped Option cannot be used in an infix expression
30+
10 |
3131
11 | _ = 4 + g()
3232
12 | _ = int(0) + g() // FIXME not detected
3333
| ~~~
@@ -45,10 +45,10 @@ vlib/v/checker/tests/infix_err.vv:14:9: error: `+` cannot be used with `?int`
4545
13 | _ = g() + int(3)
4646
14 | _ = g() + 3
4747
| ^
48-
15 |
48+
15 |
4949
16 | // binary operands
5050
vlib/v/checker/tests/infix_err.vv:17:5: error: left operand for `&&` is not a boolean
51-
15 |
51+
15 |
5252
16 | // binary operands
5353
17 | _ = 1 && 2
5454
| ^
@@ -59,10 +59,10 @@ vlib/v/checker/tests/infix_err.vv:18:13: error: right operand for `||` is not a
5959
17 | _ = 1 && 2
6060
18 | _ = true || 2
6161
| ^
62-
19 |
62+
19 |
6363
20 | // boolean expressions
6464
vlib/v/checker/tests/infix_err.vv:21:22: error: ambiguous boolean expression. use `()` to ensure correct order of operations
65-
19 |
65+
19 |
6666
20 | // boolean expressions
6767
21 | _ = 1 == 1 && 2 == 2 || 3 == 3
6868
| ~~
@@ -78,4 +78,4 @@ vlib/v/checker/tests/infix_err.vv:24:2: error: ambiguous boolean expression. use
7878
22 | _ = 1 == 1
7979
23 | && 2 == 2 || 3 == 3
8080
24 | && 4 == 4
81-
| ~~
81+
| ~~

vlib/v/checker/tests/option_wrapped_cmp_op_err.out

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:3:10: error: unwrapped option cannot be used in an infix expression
1+
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:3:10: error: unwrapped Option cannot be used in an infix expression
22
1 | fn main() {
33
2 | a := ?string("hi")
44
3 | println(a == 'hi')
55
| ^
66
4 | println('hi' == a)
77
5 | println(a != 'hi')
8-
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:4:18: error: unwrapped option cannot be used in an infix expression
8+
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:4:18: error: unwrapped Option cannot be used in an infix expression
99
2 | a := ?string("hi")
1010
3 | println(a == 'hi')
1111
4 | println('hi' == a)
1212
| ^
1313
5 | println(a != 'hi')
1414
6 | println('hi' != a)
15-
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:5:10: error: unwrapped option cannot be used in an infix expression
15+
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:5:10: error: unwrapped Option cannot be used in an infix expression
1616
3 | println(a == 'hi')
1717
4 | println('hi' == a)
1818
5 | println(a != 'hi')
1919
| ^
2020
6 | println('hi' != a)
2121
7 | }
22-
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:6:18: error: unwrapped option cannot be used in an infix expression
22+
vlib/v/checker/tests/option_wrapped_cmp_op_err.vv:6:18: error: unwrapped Option cannot be used in an infix expression
2323
4 | println('hi' == a)
2424
5 | println(a != 'hi')
2525
6 | println('hi' != a)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
vlib/v/checker/tests/unwrapped_option_infix.vv:5:9: error: unwrapped option cannot be used in an infix expression
1+
vlib/v/checker/tests/unwrapped_option_infix.vv:5:9: error: unwrapped Option cannot be used in an infix expression
22
3 | }
3-
4 |
3+
4 |
44
5 | println(test() == '')
5-
| ~~~~~~
5+
| ~~~~~~
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
vlib/v/checker/tests/unwrapped_result_infix_err.vv:7:9: error: unwrapped result cannot be used in an infix expression
1+
vlib/v/checker/tests/unwrapped_result_infix_err.vv:7:9: error: unwrapped Result cannot be used in an infix expression
22
5 | fn g() ! {
33
6 | assert f('1')! == true
44
7 | assert f('1') == true
55
| ~~~~~~
66
8 | }
77
9 |
8-
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
vlib/v/checker/tests/wrong_shift_left_option_err.vv:7:4: error: unwrapped Option cannot be used in an infix expression
2+
5 | fn main() {
3+
6 | mut a := ?[]SomeStruct([SomeStruct{}, SomeStruct{}]) // struct type
4+
7 | a << []SomeStruct{len: 20}
5+
| ~~
6+
8 | mut b := ?[]int([2, 8]) // primitive type
7+
9 | b << [1, 3, 4]
8+
vlib/v/checker/tests/wrong_shift_left_option_err.vv:9:4: error: unwrapped Option cannot be used in an infix expression
9+
7 | a << []SomeStruct{len: 20}
10+
8 | mut b := ?[]int([2, 8]) // primitive type
11+
9 | b << [1, 3, 4]
12+
| ~~
13+
10 | dump(a?.len)
14+
11 | dump(b)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
pub struct SomeStruct {
2+
i int
3+
}
4+
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]
10+
dump(a?.len)
11+
dump(b)
12+
}

0 commit comments

Comments
 (0)