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) exp_arg_sym := c.table.get_type_symbol(exp_arg_typ)
c.expected_type = 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 call_expr.args[i].typ = got_arg_typ
if method.is_variadic && got_arg_typ.has_flag(.variadic) && call_expr.args.len - 1 > i { 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', 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 call_expr.return_type = info.func.return_type
mut earg_types := []table.Type{} mut earg_types := []table.Type{}
for mut arg in call_expr.args { 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 arg.typ = targ
earg_types << 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 // map/filter are supposed to have 1 arg only
mut arg_type := left_type mut arg_type := left_type
for arg in call_expr.args { 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' { if method_name == 'map' {
// check fn // 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 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 call_expr.args[i].typ = typ
typ_sym := c.table.get_type_symbol(typ) typ_sym := c.table.get_type_symbol(typ)
arg_typ_sym := c.table.get_type_symbol(arg.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 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
9 | fn main() { 23 | fn main() {
10 | // Calling foo() without ? or an or block, should be an error. 24 | // Calling foo() without ? or an or block, should be an error.
11 | foo() 25 | foo()
| ~~~~~ | ~~~~~
12 | 26 |
13 | _ := bar() 27 | _ := bar(0)
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 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
11 | foo() 25 | foo()
12 | 26 |
13 | _ := bar() 27 | _ := bar(0)
| ~~~~~ | ~~~~~~
14 | _ := [bar()] 28 | _ := [bar(0)]
15 | } 29 |
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 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
12 | 26 |
13 | _ := bar() 27 | _ := bar(0)
14 | _ := [bar()] 28 | _ := [bar(0)]
| ~~~~~ | ~~~~~~
15 | } 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') println('foo is called')
} }
fn bar() ?int { fn bar<T>(v T) ?T {
return none 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() { fn main() {
// Calling foo() without ? or an or block, should be an error. // Calling foo() without ? or an or block, should be an error.
foo() foo()
_ := bar() _ := bar(0)
_ := [bar()] _ := [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)))
} }