cgen: fix optional void return error

pull/5476/head
yuyi 2020-06-24 18:45:15 +08:00 committed by GitHub
parent d4f0fe12ab
commit 514ee9d396
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 37 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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}')
}
}

View File

@ -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 {}

View File

@ -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
}