checker,cgen: unpack multi returns in return statements
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{}
|
mut got_types := []table.Type{}
|
||||||
for expr in return_stmt.exprs {
|
for expr in return_stmt.exprs {
|
||||||
typ := c.expr(expr)
|
typ := c.expr(expr)
|
||||||
got_types << typ
|
|
||||||
|
// 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
|
return_stmt.types = got_types
|
||||||
// allow `none` & `error (Option)` return types for function that returns optional
|
// 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']] {
|
if exp_is_optional && got_types[0].idx() in [table.none_type_idx, c.table.type_idxs['Option']] {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected_types.len > 0 && expected_types.len != got_types.len {
|
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)
|
c.error('wrong number of return arguments', return_stmt.pos)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, exp_type in expected_types {
|
for i, exp_type in expected_types {
|
||||||
got_typ := got_types[i]
|
got_typ := got_types[i]
|
||||||
is_generic := exp_type == table.t_type
|
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) {
|
fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
g.write('return ')
|
g.write('return ')
|
||||||
if g.fn_decl.name == 'main' {
|
if g.fn_decl.name == 'main' {
|
||||||
|
@ -2226,18 +2239,57 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
} else {
|
} else {
|
||||||
styp = g.typ(g.fn_decl.return_type)
|
styp = g.typ(g.fn_decl.return_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use this to keep the tmp assignments in order
|
||||||
|
mut multi_unpack := ''
|
||||||
|
|
||||||
|
|
||||||
g.write('($styp){')
|
g.write('($styp){')
|
||||||
|
|
||||||
|
mut arg_idx := 0
|
||||||
for i, expr in node.exprs {
|
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)
|
g.expr(expr)
|
||||||
|
arg_idx++
|
||||||
if i < node.exprs.len - 1 {
|
if i < node.exprs.len - 1 {
|
||||||
g.write(',')
|
g.write(',')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write('}')
|
g.write('}')
|
||||||
|
|
||||||
if fn_return_is_optional {
|
if fn_return_is_optional {
|
||||||
g.write(' }, sizeof($styp))')
|
g.write(' }, sizeof($styp))')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure to add our unpacks
|
||||||
|
g.insert_before_stmt(multi_unpack)
|
||||||
} else if node.exprs.len >= 1 {
|
} else if node.exprs.len >= 1 {
|
||||||
// normal return
|
// normal return
|
||||||
return_sym := g.table.get_type_symbol(node.types[0])
|
return_sym := g.table.get_type_symbol(node.types[0])
|
||||||
|
|
Loading…
Reference in New Issue