From f9bbc119aa3d4dd02090879c2730eda5728b1d00 Mon Sep 17 00:00:00 2001 From: zakuro Date: Sun, 21 Mar 2021 01:27:16 +0900 Subject: [PATCH] checker: make optional arguments in func call an error (#9362) --- vlib/v/checker/checker.v | 8 +- vlib/v/checker/tests/optional_fn_err.out | 122 +++++++++++++++++++---- vlib/v/checker/tests/optional_fn_err.vv | 39 +++++++- 3 files changed, 143 insertions(+), 26 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index ebbdbcd80b..67fcbf4d3f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) diff --git a/vlib/v/checker/tests/optional_fn_err.out b/vlib/v/checker/tests/optional_fn_err.out index f493ce1b82..0f7652ed6c 100644 --- a/vlib/v/checker/tests/optional_fn_err.out +++ b/vlib/v/checker/tests/optional_fn_err.out @@ -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 | } diff --git a/vlib/v/checker/tests/optional_fn_err.vv b/vlib/v/checker/tests/optional_fn_err.vv index 716e65d5c8..390b47b627 100644 --- a/vlib/v/checker/tests/optional_fn_err.vv +++ b/vlib/v/checker/tests/optional_fn_err.vv @@ -2,14 +2,47 @@ fn foo() ? { println('foo is called') } -fn bar() ?int { +fn bar(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))) }