Skip to content

Commit 0d1714c

Browse files
authored
checker: check opt call in more places (#9538)
1 parent 1a76cb1 commit 0d1714c

File tree

7 files changed

+197
-151
lines changed

7 files changed

+197
-151
lines changed

vlib/v/checker/checker.v

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,10 @@ pub fn (mut c Checker) struct_decl(mut decl ast.StructDecl) {
414414
}
415415
if field.has_default_expr {
416416
c.expected_type = field.typ
417-
field_expr_type := c.expr(field.default_expr)
417+
mut field_expr_type := c.expr(field.default_expr)
418+
if !field.typ.has_flag(.optional) {
419+
c.check_expr_opt_call(field.default_expr, field_expr_type)
420+
}
418421
struct_sym.info.fields[i].default_expr_typ = field_expr_type
419422
c.check_expected(field_expr_type, field.typ) or {
420423
if !(sym.kind == .interface_
@@ -611,7 +614,10 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
611614
inited_fields << field_name
612615
field_type_sym := c.table.get_type_symbol(info_field.typ)
613616
c.expected_type = info_field.typ
614-
expr_type := c.expr(field.expr)
617+
mut expr_type := c.expr(field.expr)
618+
if !info_field.typ.has_flag(.optional) {
619+
expr_type = c.check_expr_opt_call(field.expr, expr_type)
620+
}
615621
expr_type_sym := c.table.get_type_symbol(expr_type)
616622
if field_type_sym.kind == .interface_ {
617623
c.type_implements(expr_type, info_field.typ, field.pos)
@@ -948,6 +954,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
948954
c.error('array append cannot be used in an expression', infix_expr.pos)
949955
}
950956
// `array << elm`
957+
c.check_expr_opt_call(infix_expr.right, right_type)
951958
infix_expr.auto_locked, _ = c.fail_if_immutable(infix_expr.left)
952959
left_value_type := c.table.value_type(left_type)
953960
left_value_sym := c.table.get_type_symbol(left_value_type)
@@ -2340,7 +2347,8 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
23402347

23412348
pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type, expr_return_type table.Type) {
23422349
if or_expr.kind == .propagate {
2343-
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main' {
2350+
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main'
2351+
&& !c.inside_const {
23442352
c.error('to propagate the optional call, `$c.cur_fn.name` must return an optional',
23452353
or_expr.pos)
23462354
}
@@ -2697,12 +2705,7 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
26972705
for i, field in node.fields {
26982706
c.const_decl = field.name
26992707
c.const_deps << field.name
2700-
mut typ := c.expr(field.expr)
2701-
if field.expr is ast.CallExpr {
2702-
if field.expr.or_block.kind != .absent {
2703-
typ = typ.clear_flag(.optional)
2704-
}
2705-
}
2708+
typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
27062709
node.fields[i].typ = c.table.mktyp(typ)
27072710
for cd in c.const_deps {
27082711
for j, f in node.fields {
@@ -3207,9 +3210,10 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
32073210
}
32083211
}
32093212
if array_init.has_default {
3210-
default_typ := c.expr(array_init.default_expr)
3213+
default_expr := array_init.default_expr
3214+
default_typ := c.check_expr_opt_call(default_expr, c.expr(default_expr))
32113215
c.check_expected(default_typ, array_init.elem_type) or {
3212-
c.error(err.msg, array_init.default_expr.position())
3216+
c.error(err.msg, default_expr.position())
32133217
}
32143218
}
32153219
if array_init.has_len {
@@ -3513,7 +3517,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
35133517

35143518
fn (mut c Checker) assert_stmt(node ast.AssertStmt) {
35153519
cur_exp_typ := c.expected_type
3516-
assert_type := c.expr(node.expr)
3520+
assert_type := c.check_expr_opt_call(node.expr, c.expr(node.expr))
35173521
if assert_type != table.bool_type_idx {
35183522
atype_name := c.table.get_type_symbol(assert_type).name
35193523
c.error('assert can be used only with `bool` expressions, but found `$atype_name` instead',
Lines changed: 147 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,160 @@
1-
vlib/v/checker/tests/optional_fn_err.vv:25:2: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
2-
23 | fn main() {
3-
24 | // Calling foo() without ? or an or block, should be an error.
4-
25 | foo()
1+
vlib/v/checker/tests/optional_fn_err.vv:13:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
2+
11 |
3+
12 | const (
4+
13 | const_value = bar(0)
5+
| ~~~~~~
6+
14 | )
7+
15 |
8+
vlib/v/checker/tests/optional_fn_err.vv:19:14: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
9+
17 | f fn (int)
10+
18 | mut:
11+
19 | value int = bar(0)
12+
| ~~~~~~
13+
20 | opt ?int = bar(0)
14+
21 | }
15+
vlib/v/checker/tests/optional_fn_err.vv:33:2: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
16+
31 | fn main() {
17+
32 | // call fn
18+
33 | foo()
519
| ~~~~~
6-
26 |
7-
27 | _ := bar(0)
8-
vlib/v/checker/tests/optional_fn_err.vv:27:7: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
9-
25 | foo()
10-
26 |
11-
27 | _ := bar(0)
20+
34 | _ := bar(0)
21+
35 | println(twice(bar(0)))
22+
vlib/v/checker/tests/optional_fn_err.vv:34:7: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
23+
32 | // call fn
24+
33 | foo()
25+
34 | _ := bar(0)
1226
| ~~~~~~
13-
28 | _ := [bar(0)]
14-
29 |
15-
vlib/v/checker/tests/optional_fn_err.vv:28:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
16-
26 |
17-
27 | _ := bar(0)
18-
28 | _ := [bar(0)]
19-
| ~~~~~~
20-
29 |
21-
30 | // Calling fn with optional argument
22-
vlib/v/checker/tests/optional_fn_err.vv:31:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
23-
29 |
24-
30 | // Calling fn with optional argument
25-
31 | println(twice(bar(0)))
27+
35 | println(twice(bar(0)))
28+
36 |
29+
vlib/v/checker/tests/optional_fn_err.vv:35:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
30+
33 | foo()
31+
34 | _ := bar(0)
32+
35 | println(twice(bar(0)))
33+
| ~~~~~~
34+
36 |
35+
37 | // anon fn
36+
vlib/v/checker/tests/optional_fn_err.vv:38:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
37+
36 |
38+
37 | // anon fn
39+
38 | fn (_ int) {}(bar(0))
2640
| ~~~~~~
27-
32 | // method and fn field
28-
33 | mut v := Data{fn (_ int) {}, 1}
29-
vlib/v/checker/tests/optional_fn_err.vv:34:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
30-
32 | // method and fn field
31-
33 | mut v := Data{fn (_ int) {}, 1}
32-
34 | v.add(bar(0))
41+
39 |
42+
40 | // assert
43+
vlib/v/checker/tests/optional_fn_err.vv:41:9: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
44+
39 |
45+
40 | // assert
46+
41 | assert bar(true)
47+
| ~~~~~~~~~
48+
42 |
49+
43 | // struct
50+
vlib/v/checker/tests/optional_fn_err.vv:46:10: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
51+
44 | mut v := Data{
52+
45 | f: fn (_ int) {},
53+
46 | value: bar(0),
54+
| ~~~~~~
55+
47 | opt: bar(0),
56+
48 | }
57+
vlib/v/checker/tests/optional_fn_err.vv:49:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
58+
47 | opt: bar(0),
59+
48 | }
60+
49 | v.add(bar(0)) // call method
3361
| ~~~~~~
34-
35 | v.f(bar(0))
35-
36 | // anon fn
36-
vlib/v/checker/tests/optional_fn_err.vv:35:6: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
37-
33 | mut v := Data{fn (_ int) {}, 1}
38-
34 | v.add(bar(0))
39-
35 | v.f(bar(0))
62+
50 | v.f(bar(0)) // call fn field
63+
51 |
64+
vlib/v/checker/tests/optional_fn_err.vv:50:6: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
65+
48 | }
66+
49 | v.add(bar(0)) // call method
67+
50 | v.f(bar(0)) // call fn field
4068
| ~~~~~~
41-
36 | // anon fn
42-
37 | fn (_ int) {}(bar(0))
43-
vlib/v/checker/tests/optional_fn_err.vv:37:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
44-
35 | v.f(bar(0))
45-
36 | // anon fn
46-
37 | fn (_ int) {}(bar(0))
47-
| ~~~~~~
48-
38 | // array builtin methods
49-
39 | mut arr := [1, 2]
50-
vlib/v/checker/tests/optional_fn_err.vv:40:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
51-
38 | // array builtin methods
52-
39 | mut arr := [1, 2]
53-
40 | arr.insert(0, bar(0))
69+
51 |
70+
52 | // array
71+
vlib/v/checker/tests/optional_fn_err.vv:54:9: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
72+
52 | // array
73+
53 | mut arr := [1, 2]
74+
54 | arr << bar(0)
75+
| ~~~~~~
76+
55 | // init
77+
56 | _ := [bar(0)]
78+
vlib/v/checker/tests/optional_fn_err.vv:56:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
79+
54 | arr << bar(0)
80+
55 | // init
81+
56 | _ := [bar(0)]
82+
| ~~~~~~
83+
57 | _ := []int{init: bar(0)}
84+
58 | _ := [bar(0)]!
85+
vlib/v/checker/tests/optional_fn_err.vv:57:19: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
86+
55 | // init
87+
56 | _ := [bar(0)]
88+
57 | _ := []int{init: bar(0)}
89+
| ~~~~~~
90+
58 | _ := [bar(0)]!
91+
59 | _ := [1]int{init: bar(0)}
92+
vlib/v/checker/tests/optional_fn_err.vv:58:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
93+
56 | _ := [bar(0)]
94+
57 | _ := []int{init: bar(0)}
95+
58 | _ := [bar(0)]!
96+
| ~~~~~~
97+
59 | _ := [1]int{init: bar(0)}
98+
60 | // index
99+
vlib/v/checker/tests/optional_fn_err.vv:61:13: error: cannot use optional as index (array type `[]int`)
100+
59 | _ := [1]int{init: bar(0)}
101+
60 | // index
102+
61 | println(arr[bar(0)])
103+
| ~~~~~~~~
104+
62 | // array builtin methods
105+
63 | arr.insert(0, bar(0))
106+
vlib/v/checker/tests/optional_fn_err.vv:63:16: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
107+
61 | println(arr[bar(0)])
108+
62 | // array builtin methods
109+
63 | arr.insert(0, bar(0))
54110
| ~~~~~~
55-
41 | arr.prepend(bar(0))
56-
42 | arr.contains(bar(0))
57-
vlib/v/checker/tests/optional_fn_err.vv:41:14: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
58-
39 | mut arr := [1, 2]
59-
40 | arr.insert(0, bar(0))
60-
41 | arr.prepend(bar(0))
111+
64 | arr.prepend(bar(0))
112+
65 | arr.contains(bar(0))
113+
vlib/v/checker/tests/optional_fn_err.vv:64:14: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
114+
62 | // array builtin methods
115+
63 | arr.insert(0, bar(0))
116+
64 | arr.prepend(bar(0))
61117
| ~~~~~~
62-
42 | arr.contains(bar(0))
63-
43 | arr.index(bar(0))
64-
vlib/v/checker/tests/optional_fn_err.vv:42:15: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
65-
40 | arr.insert(0, bar(0))
66-
41 | arr.prepend(bar(0))
67-
42 | arr.contains(bar(0))
118+
65 | arr.contains(bar(0))
119+
66 | arr.index(bar(0))
120+
vlib/v/checker/tests/optional_fn_err.vv:65:15: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
121+
63 | arr.insert(0, bar(0))
122+
64 | arr.prepend(bar(0))
123+
65 | arr.contains(bar(0))
68124
| ~~~~~~
69-
43 | arr.index(bar(0))
70-
44 | println(arr.map(bar(0)))
71-
vlib/v/checker/tests/optional_fn_err.vv:43:12: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
72-
41 | arr.prepend(bar(0))
73-
42 | arr.contains(bar(0))
74-
43 | arr.index(bar(0))
125+
66 | arr.index(bar(0))
126+
67 | println(arr.map(bar(0)))
127+
vlib/v/checker/tests/optional_fn_err.vv:66:12: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
128+
64 | arr.prepend(bar(0))
129+
65 | arr.contains(bar(0))
130+
66 | arr.index(bar(0))
75131
| ~~~~~~
76-
44 | println(arr.map(bar(0)))
77-
45 | println(arr.filter(bar(true)))
78-
vlib/v/checker/tests/optional_fn_err.vv:44:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
79-
42 | arr.contains(bar(0))
80-
43 | arr.index(bar(0))
81-
44 | println(arr.map(bar(0)))
132+
67 | println(arr.map(bar(0)))
133+
68 | println(arr.filter(bar(true)))
134+
vlib/v/checker/tests/optional_fn_err.vv:67:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
135+
65 | arr.contains(bar(0))
136+
66 | arr.index(bar(0))
137+
67 | println(arr.map(bar(0)))
82138
| ~~~~~~
83-
45 | println(arr.filter(bar(true)))
84-
46 | println(arr.any(bar(true)))
85-
vlib/v/checker/tests/optional_fn_err.vv:45:21: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
86-
43 | arr.index(bar(0))
87-
44 | println(arr.map(bar(0)))
88-
45 | println(arr.filter(bar(true)))
139+
68 | println(arr.filter(bar(true)))
140+
69 | println(arr.any(bar(true)))
141+
vlib/v/checker/tests/optional_fn_err.vv:68:21: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
142+
66 | arr.index(bar(0))
143+
67 | println(arr.map(bar(0)))
144+
68 | println(arr.filter(bar(true)))
89145
| ~~~~~~~~~
90-
46 | println(arr.any(bar(true)))
91-
47 | println(arr.all(bar(true)))
92-
vlib/v/checker/tests/optional_fn_err.vv:46:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
93-
44 | println(arr.map(bar(0)))
94-
45 | println(arr.filter(bar(true)))
95-
46 | println(arr.any(bar(true)))
146+
69 | println(arr.any(bar(true)))
147+
70 | println(arr.all(bar(true)))
148+
vlib/v/checker/tests/optional_fn_err.vv:69:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
149+
67 | println(arr.map(bar(0)))
150+
68 | println(arr.filter(bar(true)))
151+
69 | println(arr.any(bar(true)))
96152
| ~~~~~~~~~
97-
47 | println(arr.all(bar(true)))
98-
48 | }
99-
vlib/v/checker/tests/optional_fn_err.vv:47:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
100-
45 | println(arr.filter(bar(true)))
101-
46 | println(arr.any(bar(true)))
102-
47 | println(arr.all(bar(true)))
153+
70 | println(arr.all(bar(true)))
154+
71 | }
155+
vlib/v/checker/tests/optional_fn_err.vv:70:18: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
156+
68 | println(arr.filter(bar(true)))
157+
69 | println(arr.any(bar(true)))
158+
70 | println(arr.all(bar(true)))
103159
| ~~~~~~~~~
104-
48 | }
160+
71 | }

0 commit comments

Comments
 (0)