1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: fix multi return with option type (#17489)

This commit is contained in:
Felipe Pena 2023-03-05 07:41:19 -03:00 committed by GitHub
parent c1f249af6c
commit 7de3485bd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 7 deletions

View File

@ -1191,7 +1191,11 @@ pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int {
for i, mr_typ in mr_typs {
mr_type_sym := t.sym(mktyp(mr_typ))
ref, cref := if mr_typ.is_ptr() { '&', 'ref_' } else { '', '' }
name += if mr_typ.has_flag(.option) { '?' } else { '' }
name += if mr_typ.has_flag(.result) { '!' } else { '' }
name += '${ref}${mr_type_sym.name}'
cname += if mr_typ.has_flag(.option) { '_option' } else { '' }
cname += if mr_typ.has_flag(.result) { '_result' } else { '' }
cname += '_${cref}${mr_type_sym.cname}'
if i < mr_typs.len - 1 {
name += ', '

View File

@ -652,7 +652,12 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ
// multi return
// TODO Handle in if_expr
mr_var_name := 'mr_${node.pos.pos}'
mr_styp := g.typ(return_type.clear_flag(.option).clear_flag(.result))
mut is_option := return_type.has_flag(.option)
mut mr_styp := g.typ(return_type.clear_flag(.result))
if node.right[0] is ast.CallExpr && (node.right[0] as ast.CallExpr).or_block.kind != .absent {
is_option = false
mr_styp = g.typ(return_type.clear_flag(.option).clear_flag(.result))
}
g.write('${mr_styp} ${mr_var_name} = ')
g.expr(node.right[0])
g.writeln(';')
@ -682,12 +687,16 @@ fn (mut g Gen) gen_multi_return_assign(node &ast.AssignStmt, return_type ast.Typ
if g.is_arraymap_set {
if is_auto_heap {
g.writeln('HEAP${noscan}(${styp}, ${mr_var_name}.arg${i}) });')
} else if is_option {
g.writeln('(*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i} });')
} else {
g.writeln('${mr_var_name}.arg${i} });')
}
} else {
if is_auto_heap {
g.writeln(' = HEAP${noscan}(${styp}, ${mr_var_name}.arg${i});')
} else if is_option {
g.writeln(' = (*((${g.base_type(return_type)}*)${mr_var_name}.data)).arg${i};')
} else {
g.writeln(' = ${mr_var_name}.arg${i};')
}

View File

@ -4563,6 +4563,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
ret_typ := g.typ(g.unwrap_generic(fn_ret_type))
mut use_tmp_var := g.defer_stmts.len > 0 || g.defer_profile_code.len > 0
|| g.cur_lock.lockeds.len > 0
|| (fn_return_is_multi && node.exprs.len >= 1 && fn_return_is_option)
// handle promoting none/error/function returning _option'
if fn_return_is_option {
option_none := node.exprs[0] is ast.None
@ -4586,6 +4587,17 @@ fn (mut g Gen) return_stmt(node ast.Return) {
g.gen_option_error(fn_ret_type, node.exprs[0])
g.writeln(';')
if use_tmp_var {
// handle options when returning `none` for `?(int, ?int)`
if fn_return_is_multi && node.exprs.len >= 1 {
mr_info := sym.info as ast.MultiReturn
for i in 0 .. mr_info.types.len {
if mr_info.types[i].has_flag(.option) {
g.write('(*(${g.base_type(fn_ret_type)}*)${tmpvar}.data).arg${i} = ')
g.gen_option_error(mr_info.types[i], ast.None{})
g.writeln(';')
}
}
}
g.write_defer_stmts_when_needed()
g.writeln('return ${tmpvar};')
}
@ -4631,8 +4643,7 @@ fn (mut g Gen) return_stmt(node ast.Return) {
g.writeln('return ${tmpvar};')
return
}
typ_sym := g.table.sym(g.fn_decl.return_type)
mr_info := typ_sym.info as ast.MultiReturn
mr_info := sym.info as ast.MultiReturn
mut styp := ''
if fn_return_is_option {
g.writeln('${ret_typ} ${tmpvar};')
@ -4699,10 +4710,11 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} else {
g.expr(expr)
}
arg_idx++
if i < node.exprs.len - 1 {
g.write(', ')
}
arg_idx++
}
g.write('}')
if fn_return_is_option {

View File

@ -1,10 +1,61 @@
struct MmapRangeLocal {}
fn addr2range() ?(&MmapRangeLocal, ?u64, u64) {
return none
}
fn foo(val ?int) (?int, ?int) {
return val, none
}
fn test_multi_return() {
a, b := foo(100)
assert a == 100
assert b == none
}
fn tuple() ?(int, int) {
return 1, 2
}
fn test_option_multi_return() {
println(tuple()?)
a, b := tuple()?
fn tuple2() ?(string, int) {
return '', 2
}
fn tuple3() ?(?int, ?int) {
return none, none
}
fn tuple4() ?(?int, ?int) {
return none
}
fn test_tuple_1() {
a, b := tuple()
assert a == 1
assert b == 2
}
fn test_tuple_2() {
a, b := tuple2()
assert a == ''
assert b == 2
}
fn test_tuple_3() {
a, b := tuple3()
assert a == none
assert b == none
}
fn test_tuple_4() {
a, b := tuple4()
assert a == none
assert b == none
}
fn test_none_ret() {
_, b, c := addr2range()
assert b == none
assert c == 0
}