cgen: fix optional void return error
parent
d4f0fe12ab
commit
514ee9d396
|
@ -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',
|
c.error('too many arguments to return, current function does not return anything',
|
||||||
return_stmt.pos)
|
return_stmt.pos)
|
||||||
return
|
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)
|
c.error('too few arguments to return', return_stmt.pos)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,12 +375,12 @@ fn (g &Gen) optional_type_text(styp, base string) string {
|
||||||
// replace void with something else
|
// replace void with something else
|
||||||
size := if base == 'void' { 'int' } else { base }
|
size := if base == 'void' { 'int' } else { base }
|
||||||
ret := 'struct $x {
|
ret := 'struct $x {
|
||||||
bool ok;
|
bool ok;
|
||||||
bool is_none;
|
bool is_none;
|
||||||
string v_error;
|
string v_error;
|
||||||
int ecode;
|
int ecode;
|
||||||
byte data[sizeof($size)];
|
byte data[sizeof($size)];
|
||||||
} '
|
}'
|
||||||
return ret
|
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)
|
sym := g.table.get_type_symbol(g.fn_decl.return_type)
|
||||||
fn_return_is_multi := sym.kind == .multi_return
|
fn_return_is_multi := sym.kind == .multi_return
|
||||||
fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional)
|
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'
|
// handle promoting none/error/function returning 'Option'
|
||||||
if fn_return_is_optional {
|
if fn_return_is_optional {
|
||||||
optional_none := node.exprs[0] is ast.None
|
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()
|
tmp := g.new_tmp_var()
|
||||||
g.write('/*opt promotion*/ Option $tmp = ')
|
g.write('/*opt promotion*/ Option $tmp = ')
|
||||||
g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
|
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)
|
styp := g.typ(g.fn_decl.return_type)
|
||||||
g.writeln('return *($styp*)&$tmp;')
|
g.writeln('return *($styp*)&$tmp;')
|
||||||
return
|
return
|
||||||
|
|
|
@ -330,7 +330,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
if gen_or {
|
if gen_or {
|
||||||
g.or_block(tmp_opt, node.or_block, node.return_type)
|
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}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
fn test_optional_val_with_empty_or() {
|
||||||
ret_none() or {}
|
ret_none() or {}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue