From 514ee9d396d669c24c52e01a061a6397b64dd5e0 Mon Sep 17 00:00:00 2001 From: yuyi Date: Wed, 24 Jun 2020 18:45:15 +0800 Subject: [PATCH] cgen: fix optional void return error --- vlib/v/checker/checker.v | 3 +- vlib/v/gen/cgen.v | 27 +++++++++++++----- vlib/v/gen/fn.v | 2 +- vlib/v/tests/option_test.v | 28 ------------------ vlib/v/tests/option_void_test.v | 50 +++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 37 deletions(-) create mode 100644 vlib/v/tests/option_void_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 9c7715a16a..73ae3eacf3 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1259,7 +1259,8 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { c.error('too many arguments to return, current function does not return anything', return_stmt.pos) return - } else if return_stmt.exprs.len == 0 && c.expected_type != table.void_type { + } else if return_stmt.exprs.len == 0 && !(c.expected_type == table.void_type || + c.table.get_type_symbol(c.expected_type).kind == .void) { c.error('too few arguments to return', return_stmt.pos) return } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 7ba144ca4b..2e2ff78a13 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -375,12 +375,12 @@ fn (g &Gen) optional_type_text(styp, base string) string { // replace void with something else size := if base == 'void' { 'int' } else { base } ret := 'struct $x { - bool ok; - bool is_none; - string v_error; - int ecode; - byte data[sizeof($size)]; -} ' + bool ok; + bool is_none; + string v_error; + int ecode; + byte data[sizeof($size)]; +}' return ret } @@ -2309,6 +2309,19 @@ fn (mut g Gen) return_statement(node ast.Return) { sym := g.table.get_type_symbol(g.fn_decl.return_type) fn_return_is_multi := sym.kind == .multi_return fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional) + + if node.exprs.len == 0 { + if fn_return_is_optional { + tmp := g.new_tmp_var() + styp := g.typ(g.fn_decl.return_type) + g.writeln('$styp $tmp;') + g.writeln('${tmp}.ok = true;') + g.writeln('return $tmp;') + } else { + g.writeln('return;') + } + return + } // handle promoting none/error/function returning 'Option' if fn_return_is_optional { optional_none := node.exprs[0] is ast.None @@ -2317,7 +2330,7 @@ fn (mut g Gen) return_statement(node ast.Return) { tmp := g.new_tmp_var() g.write('/*opt promotion*/ Option $tmp = ') g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type) - g.write(';') + g.writeln(';') styp := g.typ(g.fn_decl.return_type) g.writeln('return *($styp*)&$tmp;') return diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index cd23e14017..ef0c6ede54 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -330,7 +330,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { } if gen_or { g.or_block(tmp_opt, node.or_block, node.return_type) - g.write('\n${cur_line}${tmp_opt}') + g.write('\n\t${cur_line}${tmp_opt}') } } diff --git a/vlib/v/tests/option_test.v b/vlib/v/tests/option_test.v index 5b0e834c4a..8a221244a7 100644 --- a/vlib/v/tests/option_test.v +++ b/vlib/v/tests/option_test.v @@ -274,34 +274,6 @@ fn test_multi_return_opt() { } } */ -fn foo() ? { - return error('something') -} - -fn test_optional_void() { - foo() or { - println(err) - assert err == 'something' - return - } -} - -fn bar() ? { - return error('bar error') -} - -fn test_optional_void_only_question() { - bar() or { - println(err) - assert err == 'bar error' - return - } -} - -fn test_optional_void_with_empty_or() { - foo() or {} - assert true -} fn test_optional_val_with_empty_or() { ret_none() or {} diff --git a/vlib/v/tests/option_void_test.v b/vlib/v/tests/option_void_test.v new file mode 100644 index 0000000000..9fccb6ba0f --- /dev/null +++ b/vlib/v/tests/option_void_test.v @@ -0,0 +1,50 @@ +fn foo() ? { + return error('something') +} + +fn test_optional_void() { + foo() or { + println(err) + assert err == 'something' + return + } +} + +fn bar() ? { + return error('bar error') +} + +fn test_optional_void_only_question() { + bar() or { + println(err) + assert err == 'bar error' + return + } +} + +fn test_optional_void_with_empty_or() { + foo() or {} + assert true +} + +fn option_void(a int) ? { + if a != 0 { + return + } else { + return error('zero error') + } +} + +fn test_optional_void_with_return() { + option_void(0) or { + println(err) + assert err == 'zero error' + return + } + option_void(-1) or { + println(err) + assert err == 'zero error' + return + } + assert true +}