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:
parent
c1f249af6c
commit
7de3485bd2
@ -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 += ', '
|
||||
|
@ -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};')
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user