mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker,cgen: unpack multi returns in return statements
This commit is contained in:
parent
72ed673566
commit
0b64e2190f
@ -1167,17 +1167,28 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
||||
mut got_types := []table.Type{}
|
||||
for expr in return_stmt.exprs {
|
||||
typ := c.expr(expr)
|
||||
|
||||
// Unpack multi return types
|
||||
sym := c.table.get_type_symbol(typ)
|
||||
if sym.kind == .multi_return {
|
||||
for t in sym.mr_info().types {
|
||||
got_types << t
|
||||
}
|
||||
} else {
|
||||
got_types << typ
|
||||
}
|
||||
}
|
||||
return_stmt.types = got_types
|
||||
// allow `none` & `error (Option)` return types for function that returns optional
|
||||
if exp_is_optional && got_types[0].idx() in [table.none_type_idx, c.table.type_idxs['Option']] {
|
||||
return
|
||||
}
|
||||
|
||||
if expected_types.len > 0 && expected_types.len != got_types.len {
|
||||
// c.error('wrong number of return arguments:\n\texpected: $expected_table.str()\n\tgot: $got_types.str()', return_stmt.pos)
|
||||
c.error('wrong number of return arguments', return_stmt.pos)
|
||||
return
|
||||
}
|
||||
|
||||
for i, exp_type in expected_types {
|
||||
got_typ := got_types[i]
|
||||
is_generic := exp_type == table.t_type
|
||||
|
@ -2191,6 +2191,19 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
||||
match expr {
|
||||
ast.CallExpr {
|
||||
return g.table.get_type_symbol(it.return_type).kind == .multi_return
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn (mut g Gen) return_statement(node ast.Return) {
|
||||
g.write('return ')
|
||||
if g.fn_decl.name == 'main' {
|
||||
@ -2226,18 +2239,57 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||
} else {
|
||||
styp = g.typ(g.fn_decl.return_type)
|
||||
}
|
||||
|
||||
// Use this to keep the tmp assignments in order
|
||||
mut multi_unpack := ''
|
||||
|
||||
|
||||
g.write('($styp){')
|
||||
|
||||
mut arg_idx := 0
|
||||
for i, expr in node.exprs {
|
||||
g.write('.arg$i=')
|
||||
// Check if we are dealing with a multi return and handle it seperately
|
||||
if g.expr_is_multi_return_call(expr) {
|
||||
c := expr as ast.CallExpr
|
||||
expr_sym := g.table.get_type_symbol(c.return_type)
|
||||
|
||||
// Create a tmp for this call
|
||||
tmp := g.new_tmp_var()
|
||||
s := g.go_before_stmt(0)
|
||||
expr_styp := g.typ(c.return_type)
|
||||
g.write('$expr_styp $tmp=')
|
||||
g.expr(expr)
|
||||
g.writeln(';')
|
||||
multi_unpack += g.go_before_stmt(0)
|
||||
g.write(s)
|
||||
|
||||
expr_types := expr_sym.mr_info().types
|
||||
for j, _ in expr_types {
|
||||
g.write('.arg$arg_idx=${tmp}.arg$j')
|
||||
if j < expr_types.len || i < node.exprs.len - 1 {
|
||||
g.write(',')
|
||||
}
|
||||
arg_idx++
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
g.write('.arg$arg_idx=')
|
||||
g.expr(expr)
|
||||
arg_idx++
|
||||
if i < node.exprs.len - 1 {
|
||||
g.write(',')
|
||||
}
|
||||
}
|
||||
g.write('}')
|
||||
|
||||
if fn_return_is_optional {
|
||||
g.write(' }, sizeof($styp))')
|
||||
}
|
||||
|
||||
// Make sure to add our unpacks
|
||||
g.insert_before_stmt(multi_unpack)
|
||||
} else if node.exprs.len >= 1 {
|
||||
// normal return
|
||||
return_sym := g.table.get_type_symbol(node.types[0])
|
||||
|
Loading…
Reference in New Issue
Block a user