checker: check opt call in more places (#9538)
parent
1a76cb1c36
commit
0d1714cb0d
|
@ -414,7 +414,10 @@ pub fn (mut c Checker) struct_decl(mut decl ast.StructDecl) {
|
|||
}
|
||||
if field.has_default_expr {
|
||||
c.expected_type = field.typ
|
||||
field_expr_type := c.expr(field.default_expr)
|
||||
mut field_expr_type := c.expr(field.default_expr)
|
||||
if !field.typ.has_flag(.optional) {
|
||||
c.check_expr_opt_call(field.default_expr, field_expr_type)
|
||||
}
|
||||
struct_sym.info.fields[i].default_expr_typ = field_expr_type
|
||||
c.check_expected(field_expr_type, field.typ) or {
|
||||
if !(sym.kind == .interface_
|
||||
|
@ -611,7 +614,10 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
|||
inited_fields << field_name
|
||||
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||
c.expected_type = info_field.typ
|
||||
expr_type := c.expr(field.expr)
|
||||
mut expr_type := c.expr(field.expr)
|
||||
if !info_field.typ.has_flag(.optional) {
|
||||
expr_type = c.check_expr_opt_call(field.expr, expr_type)
|
||||
}
|
||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||
if field_type_sym.kind == .interface_ {
|
||||
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 {
|
|||
c.error('array append cannot be used in an expression', infix_expr.pos)
|
||||
}
|
||||
// `array << elm`
|
||||
c.check_expr_opt_call(infix_expr.right, right_type)
|
||||
infix_expr.auto_locked, _ = c.fail_if_immutable(infix_expr.left)
|
||||
left_value_type := c.table.value_type(left_type)
|
||||
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
|
|||
|
||||
pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type, expr_return_type table.Type) {
|
||||
if or_expr.kind == .propagate {
|
||||
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main' {
|
||||
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main'
|
||||
&& !c.inside_const {
|
||||
c.error('to propagate the optional call, `$c.cur_fn.name` must return an optional',
|
||||
or_expr.pos)
|
||||
}
|
||||
|
@ -2697,12 +2705,7 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
|
|||
for i, field in node.fields {
|
||||
c.const_decl = field.name
|
||||
c.const_deps << field.name
|
||||
mut typ := c.expr(field.expr)
|
||||
if field.expr is ast.CallExpr {
|
||||
if field.expr.or_block.kind != .absent {
|
||||
typ = typ.clear_flag(.optional)
|
||||
}
|
||||
}
|
||||
typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
|
||||
node.fields[i].typ = c.table.mktyp(typ)
|
||||
for cd in c.const_deps {
|
||||
for j, f in node.fields {
|
||||
|
@ -3207,9 +3210,10 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
|
|||
}
|
||||
}
|
||||
if array_init.has_default {
|
||||
default_typ := c.expr(array_init.default_expr)
|
||||
default_expr := array_init.default_expr
|
||||
default_typ := c.check_expr_opt_call(default_expr, c.expr(default_expr))
|
||||
c.check_expected(default_typ, array_init.elem_type) or {
|
||||
c.error(err.msg, array_init.default_expr.position())
|
||||
c.error(err.msg, default_expr.position())
|
||||
}
|
||||
}
|
||||
if array_init.has_len {
|
||||
|
@ -3513,7 +3517,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
|
||||
fn (mut c Checker) assert_stmt(node ast.AssertStmt) {
|
||||
cur_exp_typ := c.expected_type
|
||||
assert_type := c.expr(node.expr)
|
||||
assert_type := c.check_expr_opt_call(node.expr, c.expr(node.expr))
|
||||
if assert_type != table.bool_type_idx {
|
||||
atype_name := c.table.get_type_symbol(assert_type).name
|
||||
c.error('assert can be used only with `bool` expressions, but found `$atype_name` instead',
|
||||
|
|
|
@ -1,104 +1,160 @@
|
|||
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
|
||||
23 | fn main() {
|
||||
24 | // Calling foo() without ? or an or block, should be an error.
|
||||
25 | foo()
|
||||
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
|
||||
11 |
|
||||
12 | const (
|
||||
13 | const_value = bar(0)
|
||||
| ~~~~~~
|
||||
14 | )
|
||||
15 |
|
||||
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
|
||||
17 | f fn (int)
|
||||
18 | mut:
|
||||
19 | value int = bar(0)
|
||||
| ~~~~~~
|
||||
20 | opt ?int = bar(0)
|
||||
21 | }
|
||||
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
|
||||
31 | fn main() {
|
||||
32 | // call fn
|
||||
33 | foo()
|
||||
| ~~~~~
|
||||
26 |
|
||||
27 | _ := bar(0)
|
||||
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
|
||||
25 | foo()
|
||||
26 |
|
||||
27 | _ := bar(0)
|
||||
34 | _ := bar(0)
|
||||
35 | println(twice(bar(0)))
|
||||
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
|
||||
32 | // call fn
|
||||
33 | foo()
|
||||
34 | _ := bar(0)
|
||||
| ~~~~~~
|
||||
28 | _ := [bar(0)]
|
||||
29 |
|
||||
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
|
||||
26 |
|
||||
27 | _ := bar(0)
|
||||
28 | _ := [bar(0)]
|
||||
35 | println(twice(bar(0)))
|
||||
36 |
|
||||
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
|
||||
33 | foo()
|
||||
34 | _ := bar(0)
|
||||
35 | println(twice(bar(0)))
|
||||
| ~~~~~~
|
||||
29 |
|
||||
30 | // Calling fn with optional argument
|
||||
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
|
||||
29 |
|
||||
30 | // Calling fn with optional argument
|
||||
31 | println(twice(bar(0)))
|
||||
36 |
|
||||
37 | // anon fn
|
||||
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
|
||||
36 |
|
||||
37 | // anon fn
|
||||
38 | fn (_ int) {}(bar(0))
|
||||
| ~~~~~~
|
||||
32 | // method and fn field
|
||||
33 | mut v := Data{fn (_ int) {}, 1}
|
||||
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
|
||||
32 | // method and fn field
|
||||
33 | mut v := Data{fn (_ int) {}, 1}
|
||||
34 | v.add(bar(0))
|
||||
| ~~~~~~
|
||||
35 | v.f(bar(0))
|
||||
36 | // anon fn
|
||||
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
|
||||
33 | mut v := Data{fn (_ int) {}, 1}
|
||||
34 | v.add(bar(0))
|
||||
35 | v.f(bar(0))
|
||||
| ~~~~~~
|
||||
36 | // anon fn
|
||||
37 | fn (_ int) {}(bar(0))
|
||||
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
|
||||
35 | v.f(bar(0))
|
||||
36 | // anon fn
|
||||
37 | fn (_ int) {}(bar(0))
|
||||
| ~~~~~~
|
||||
38 | // array builtin methods
|
||||
39 | mut arr := [1, 2]
|
||||
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
|
||||
38 | // array builtin methods
|
||||
39 | mut arr := [1, 2]
|
||||
40 | arr.insert(0, bar(0))
|
||||
| ~~~~~~
|
||||
41 | arr.prepend(bar(0))
|
||||
42 | arr.contains(bar(0))
|
||||
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
|
||||
39 | mut arr := [1, 2]
|
||||
40 | arr.insert(0, bar(0))
|
||||
41 | arr.prepend(bar(0))
|
||||
| ~~~~~~
|
||||
42 | arr.contains(bar(0))
|
||||
43 | arr.index(bar(0))
|
||||
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
|
||||
40 | arr.insert(0, bar(0))
|
||||
41 | arr.prepend(bar(0))
|
||||
42 | arr.contains(bar(0))
|
||||
| ~~~~~~
|
||||
43 | arr.index(bar(0))
|
||||
44 | println(arr.map(bar(0)))
|
||||
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
|
||||
41 | arr.prepend(bar(0))
|
||||
42 | arr.contains(bar(0))
|
||||
43 | arr.index(bar(0))
|
||||
| ~~~~~~
|
||||
44 | println(arr.map(bar(0)))
|
||||
45 | println(arr.filter(bar(true)))
|
||||
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
|
||||
42 | arr.contains(bar(0))
|
||||
43 | arr.index(bar(0))
|
||||
44 | println(arr.map(bar(0)))
|
||||
| ~~~~~~
|
||||
45 | println(arr.filter(bar(true)))
|
||||
46 | println(arr.any(bar(true)))
|
||||
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
|
||||
43 | arr.index(bar(0))
|
||||
44 | println(arr.map(bar(0)))
|
||||
45 | println(arr.filter(bar(true)))
|
||||
39 |
|
||||
40 | // assert
|
||||
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
|
||||
39 |
|
||||
40 | // assert
|
||||
41 | assert bar(true)
|
||||
| ~~~~~~~~~
|
||||
46 | println(arr.any(bar(true)))
|
||||
47 | println(arr.all(bar(true)))
|
||||
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
|
||||
44 | println(arr.map(bar(0)))
|
||||
45 | println(arr.filter(bar(true)))
|
||||
46 | println(arr.any(bar(true)))
|
||||
| ~~~~~~~~~
|
||||
47 | println(arr.all(bar(true)))
|
||||
42 |
|
||||
43 | // struct
|
||||
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
|
||||
44 | mut v := Data{
|
||||
45 | f: fn (_ int) {},
|
||||
46 | value: bar(0),
|
||||
| ~~~~~~
|
||||
47 | opt: bar(0),
|
||||
48 | }
|
||||
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
|
||||
45 | println(arr.filter(bar(true)))
|
||||
46 | println(arr.any(bar(true)))
|
||||
47 | println(arr.all(bar(true)))
|
||||
| ~~~~~~~~~
|
||||
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
|
||||
47 | opt: bar(0),
|
||||
48 | }
|
||||
49 | v.add(bar(0)) // call method
|
||||
| ~~~~~~
|
||||
50 | v.f(bar(0)) // call fn field
|
||||
51 |
|
||||
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
|
||||
48 | }
|
||||
49 | v.add(bar(0)) // call method
|
||||
50 | v.f(bar(0)) // call fn field
|
||||
| ~~~~~~
|
||||
51 |
|
||||
52 | // array
|
||||
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
|
||||
52 | // array
|
||||
53 | mut arr := [1, 2]
|
||||
54 | arr << bar(0)
|
||||
| ~~~~~~
|
||||
55 | // init
|
||||
56 | _ := [bar(0)]
|
||||
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
|
||||
54 | arr << bar(0)
|
||||
55 | // init
|
||||
56 | _ := [bar(0)]
|
||||
| ~~~~~~
|
||||
57 | _ := []int{init: bar(0)}
|
||||
58 | _ := [bar(0)]!
|
||||
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
|
||||
55 | // init
|
||||
56 | _ := [bar(0)]
|
||||
57 | _ := []int{init: bar(0)}
|
||||
| ~~~~~~
|
||||
58 | _ := [bar(0)]!
|
||||
59 | _ := [1]int{init: bar(0)}
|
||||
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
|
||||
56 | _ := [bar(0)]
|
||||
57 | _ := []int{init: bar(0)}
|
||||
58 | _ := [bar(0)]!
|
||||
| ~~~~~~
|
||||
59 | _ := [1]int{init: bar(0)}
|
||||
60 | // index
|
||||
vlib/v/checker/tests/optional_fn_err.vv:61:13: error: cannot use optional as index (array type `[]int`)
|
||||
59 | _ := [1]int{init: bar(0)}
|
||||
60 | // index
|
||||
61 | println(arr[bar(0)])
|
||||
| ~~~~~~~~
|
||||
62 | // array builtin methods
|
||||
63 | arr.insert(0, bar(0))
|
||||
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
|
||||
61 | println(arr[bar(0)])
|
||||
62 | // array builtin methods
|
||||
63 | arr.insert(0, bar(0))
|
||||
| ~~~~~~
|
||||
64 | arr.prepend(bar(0))
|
||||
65 | arr.contains(bar(0))
|
||||
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
|
||||
62 | // array builtin methods
|
||||
63 | arr.insert(0, bar(0))
|
||||
64 | arr.prepend(bar(0))
|
||||
| ~~~~~~
|
||||
65 | arr.contains(bar(0))
|
||||
66 | arr.index(bar(0))
|
||||
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
|
||||
63 | arr.insert(0, bar(0))
|
||||
64 | arr.prepend(bar(0))
|
||||
65 | arr.contains(bar(0))
|
||||
| ~~~~~~
|
||||
66 | arr.index(bar(0))
|
||||
67 | println(arr.map(bar(0)))
|
||||
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
|
||||
64 | arr.prepend(bar(0))
|
||||
65 | arr.contains(bar(0))
|
||||
66 | arr.index(bar(0))
|
||||
| ~~~~~~
|
||||
67 | println(arr.map(bar(0)))
|
||||
68 | println(arr.filter(bar(true)))
|
||||
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
|
||||
65 | arr.contains(bar(0))
|
||||
66 | arr.index(bar(0))
|
||||
67 | println(arr.map(bar(0)))
|
||||
| ~~~~~~
|
||||
68 | println(arr.filter(bar(true)))
|
||||
69 | println(arr.any(bar(true)))
|
||||
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
|
||||
66 | arr.index(bar(0))
|
||||
67 | println(arr.map(bar(0)))
|
||||
68 | println(arr.filter(bar(true)))
|
||||
| ~~~~~~~~~
|
||||
69 | println(arr.any(bar(true)))
|
||||
70 | println(arr.all(bar(true)))
|
||||
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
|
||||
67 | println(arr.map(bar(0)))
|
||||
68 | println(arr.filter(bar(true)))
|
||||
69 | println(arr.any(bar(true)))
|
||||
| ~~~~~~~~~
|
||||
70 | println(arr.all(bar(true)))
|
||||
71 | }
|
||||
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
|
||||
68 | println(arr.filter(bar(true)))
|
||||
69 | println(arr.any(bar(true)))
|
||||
70 | println(arr.all(bar(true)))
|
||||
| ~~~~~~~~~
|
||||
71 | }
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
// use optional without ? or an or block in places where it is not allowed
|
||||
|
||||
fn foo() ? {
|
||||
println('foo is called')
|
||||
}
|
||||
|
@ -6,10 +9,15 @@ fn bar<T>(v T) ?T {
|
|||
return none
|
||||
}
|
||||
|
||||
const (
|
||||
const_value = bar(0)
|
||||
)
|
||||
|
||||
struct Data {
|
||||
f fn (int)
|
||||
mut:
|
||||
value int
|
||||
value int = bar(0)
|
||||
opt ?int = bar(0)
|
||||
}
|
||||
|
||||
fn (mut v Data) add(n int) {
|
||||
|
@ -21,22 +29,37 @@ fn twice(n int) int {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
// Calling foo() without ? or an or block, should be an error.
|
||||
// call fn
|
||||
foo()
|
||||
|
||||
_ := bar(0)
|
||||
_ := [bar(0)]
|
||||
|
||||
// Calling fn with optional argument
|
||||
println(twice(bar(0)))
|
||||
// method and fn field
|
||||
mut v := Data{fn (_ int) {}, 1}
|
||||
v.add(bar(0))
|
||||
v.f(bar(0))
|
||||
|
||||
// anon fn
|
||||
fn (_ int) {}(bar(0))
|
||||
// array builtin methods
|
||||
|
||||
// assert
|
||||
assert bar(true)
|
||||
|
||||
// struct
|
||||
mut v := Data{
|
||||
f: fn (_ int) {},
|
||||
value: bar(0),
|
||||
opt: bar(0),
|
||||
}
|
||||
v.add(bar(0)) // call method
|
||||
v.f(bar(0)) // call fn field
|
||||
|
||||
// array
|
||||
mut arr := [1, 2]
|
||||
arr << bar(0)
|
||||
// init
|
||||
_ := [bar(0)]
|
||||
_ := []int{init: bar(0)}
|
||||
_ := [bar(0)]!
|
||||
_ := [1]int{init: bar(0)}
|
||||
// index
|
||||
println(arr[bar(0)])
|
||||
// array builtin methods
|
||||
arr.insert(0, bar(0))
|
||||
arr.prepend(bar(0))
|
||||
arr.contains(bar(0))
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
vlib/v/checker/tests/optional_index_err.vv:3:14: error: cannot use optional as index (type `string`)
|
||||
1 | fn main() {
|
||||
2 | v := 'hello'
|
||||
3 | println(v[v.last_index('l')])
|
||||
| ~~~~~~~~~~~~~~~~~~~
|
||||
4 | }
|
|
@ -1,4 +0,0 @@
|
|||
fn main() {
|
||||
v := 'hello'
|
||||
println(v[v.last_index('l')])
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
vlib/v/checker/tests/optional_method_err.vv:17:10: error: inc_to_limit() returns an option, so it should have either an `or {}` block, or `?` at the end
|
||||
15 | mut a := Abc{}
|
||||
16 | for _ in 0 .. 4 {
|
||||
17 | _ := a.inc_to_limit(2)
|
||||
| ~~~~~~~~~~~~~~~
|
||||
18 | eprintln('a: $a')
|
||||
19 | }
|
|
@ -1,20 +0,0 @@
|
|||
struct Abc {
|
||||
mut:
|
||||
x int
|
||||
}
|
||||
|
||||
fn (mut a Abc) inc_to_limit(max int) ?int {
|
||||
if a.x >= max {
|
||||
return error('x is already $max')
|
||||
}
|
||||
a.x++
|
||||
return a.x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut a := Abc{}
|
||||
for _ in 0 .. 4 {
|
||||
_ := a.inc_to_limit(2)
|
||||
eprintln('a: $a')
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue