checker: make optional arguments in func call an error (#9362)

pull/9393/head
zakuro 2021-03-21 01:27:16 +09:00 committed by GitHub
parent c8416f9a54
commit f9bbc119aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 143 additions and 26 deletions

View File

@ -1499,7 +1499,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
}
exp_arg_sym := c.table.get_type_symbol(exp_arg_typ)
c.expected_type = exp_arg_typ
got_arg_typ := c.expr(arg.expr)
got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
call_expr.args[i].typ = got_arg_typ
if method.is_variadic && got_arg_typ.has_flag(.variadic) && call_expr.args.len - 1 > i {
c.error('when forwarding a variadic variable, it must be the final argument',
@ -1634,7 +1634,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
call_expr.return_type = info.func.return_type
mut earg_types := []table.Type{}
for mut arg in call_expr.args {
targ := c.expr(arg.expr)
targ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
arg.typ = targ
earg_types << targ
}
@ -1732,7 +1732,7 @@ fn (mut c Checker) call_array_builtin_method(mut call_expr ast.CallExpr, left_ty
// map/filter are supposed to have 1 arg only
mut arg_type := left_type
for arg in call_expr.args {
arg_type = c.expr(arg.expr)
arg_type = c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
}
if method_name == 'map' {
// check fn
@ -2024,7 +2024,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
}
}
c.expected_type = arg.typ
typ := c.expr(call_arg.expr)
typ := c.check_expr_opt_call(call_arg.expr, c.expr(call_arg.expr))
call_expr.args[i].typ = typ
typ_sym := c.table.get_type_symbol(typ)
arg_typ_sym := c.table.get_type_symbol(arg.typ)

View File

@ -1,20 +1,104 @@
vlib/v/checker/tests/optional_fn_err.vv:11:2: error: foo() returns an option, so it should have either an `or {}` block, or `?` at the end
9 | fn main() {
10 | // Calling foo() without ? or an or block, should be an error.
11 | foo()
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()
| ~~~~~
12 |
13 | _ := bar()
vlib/v/checker/tests/optional_fn_err.vv:13:7: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
11 | foo()
12 |
13 | _ := bar()
| ~~~~~
14 | _ := [bar()]
15 | }
vlib/v/checker/tests/optional_fn_err.vv:14:8: error: bar() returns an option, so it should have either an `or {}` block, or `?` at the end
12 |
13 | _ := bar()
14 | _ := [bar()]
| ~~~~~
15 | }
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)
| ~~~~~~
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)]
| ~~~~~~
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)))
| ~~~~~~
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)))
| ~~~~~~~~~
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)))
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)))
| ~~~~~~~~~
48 | }

View File

@ -2,14 +2,47 @@ fn foo() ? {
println('foo is called')
}
fn bar() ?int {
fn bar<T>(v T) ?T {
return none
}
struct Data {
f fn (int)
mut:
value int
}
fn (mut v Data) add(n int) {
v.value += n
}
fn twice(n int) int {
return n * 2
}
fn main() {
// Calling foo() without ? or an or block, should be an error.
foo()
_ := bar()
_ := [bar()]
_ := 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
mut arr := [1, 2]
arr.insert(0, bar(0))
arr.prepend(bar(0))
arr.contains(bar(0))
arr.index(bar(0))
println(arr.map(bar(0)))
println(arr.filter(bar(true)))
println(arr.any(bar(true)))
println(arr.all(bar(true)))
}