aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2016-09-23 20:40:42 +0100
committerGinger Bill <bill@gingerbill.org>2016-09-23 20:40:42 +0100
commitdb6abb97066e24c90d0048e6d2b2bc4c08041cf5 (patch)
treeb36f77569d2c54da9de5db21c934c9e63f9258d6
parentfa7d7938e1faeed446d22cdc65bb072620b8d35a (diff)
Fix returns of tuple
-rw-r--r--code/demo.odin11
-rw-r--r--src/checker/stmt.cpp34
-rw-r--r--src/codegen/ssa.cpp35
3 files changed, 62 insertions, 18 deletions
diff --git a/code/demo.odin b/code/demo.odin
index 10d0009f8..7e4e5eed7 100644
--- a/code/demo.odin
+++ b/code/demo.odin
@@ -2,7 +2,18 @@
#import "os.odin"
#import "mem.odin"
+
main :: proc() {
+ x :: proc() -> (int, int) {
+ return 1, 2
+ }
+ y :: proc() -> (int, int) {
+ return x()
+ }
+
+ fmt.println(y())
+
+
arena: mem.Arena
mem.init_arena_from_context(^arena, 1000)
diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp
index 04df70ffb..20d4bb904 100644
--- a/src/checker/stmt.cpp
+++ b/src/checker/stmt.cpp
@@ -146,6 +146,13 @@ b32 check_is_terminating(AstNode *node) {
}
return has_default;
case_end;
+
+ case_ast_node(pa, PushAllocator, node);
+ return check_is_terminating(pa->body);
+ case_end;
+ case_ast_node(pc, PushContext, node);
+ return check_is_terminating(pc->body);
+ case_end;
}
return false;
@@ -160,15 +167,13 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
AstNode *node = unparen_expr(lhs);
// NOTE(bill): Ignore assignments to `_`
- if (node->kind == AstNode_Ident) {
- ast_node(i, Ident, node);
- if (i->string == make_string("_")) {
- add_entity_definition(&c->info, node, NULL);
- check_assignment(c, op_a, NULL, make_string("assignment to `_` identifier"));
- if (op_a->mode == Addressing_Invalid)
- return NULL;
- return op_a->type;
- }
+ if (node->kind == AstNode_Ident &&
+ node->Ident.string == make_string("_")) {
+ add_entity_definition(&c->info, node, NULL);
+ check_assignment(c, op_a, NULL, make_string("assignment to `_` identifier"));
+ if (op_a->mode == Addressing_Invalid)
+ return NULL;
+ return op_a->type;
}
Entity *e = NULL;
@@ -989,17 +994,14 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
break;
}
+
Type *proc_type = c->proc_stack[gb_array_count(c->proc_stack)-1];
isize result_count = 0;
if (proc_type->Proc.results) {
result_count = proc_type->Proc.results->Tuple.variable_count;
}
- if (result_count != gb_array_count(rs->results)) {
- error(rs->token, "Expected %td return %s, got %td",
- result_count,
- (result_count != 1 ? "values" : "value"),
- gb_array_count(rs->results));
- } else if (result_count > 0) {
+
+ if (result_count > 0) {
Entity **variables = NULL;
if (proc_type->Proc.results != NULL) {
auto *tuple = &proc_type->Proc.results->Tuple;
@@ -1007,6 +1009,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
}
check_init_variables(c, variables, result_count,
rs->results, make_string("return statement"));
+ } else if (gb_array_count(rs->results) > 0) {
+ error(ast_node_token(rs->results[0]), "No result values expected");
}
case_end;
diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp
index aeb7d0de6..6226424dd 100644
--- a/src/codegen/ssa.cpp
+++ b/src/codegen/ssa.cpp
@@ -3366,8 +3366,38 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
ssaValue *v = NULL;
auto *return_type_tuple = &proc->type->Proc.results->Tuple;
isize return_count = proc->type->Proc.result_count;
- if (gb_array_count(rs->results) == 1 && return_count > 1) {
- GB_PANIC("ReturnStmt tuple return statement");
+ if (gb_array_count(rs->results) < return_count) {
+ gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&proc->module->tmp_arena);
+ defer (gb_temp_arena_memory_end(tmp));
+
+ gbArray(ssaValue *) results;
+ gb_array_init_reserve(results, proc->module->tmp_allocator, return_count);
+
+ gb_for_array(res_index, rs->results) {
+ ssaValue *res = ssa_build_expr(proc, rs->results[res_index]);
+ Type *t = ssa_type(res);
+ if (t->kind == Type_Tuple) {
+ for (isize i = 0; i < t->Tuple.variable_count; i++) {
+ Entity *e = t->Tuple.variables[i];
+ ssaValue *v = ssa_emit_struct_ev(proc, res, i, e->type);
+ gb_array_append(results, v);
+ }
+ } else {
+ gb_array_append(results, res);
+ }
+ }
+
+ Type *ret_type = proc->type->Proc.results;
+ v = ssa_add_local_generated(proc, ret_type);
+ gb_for_array(i, results) {
+ Type *t = return_type_tuple->variables[i]->type;
+ ssaValue *e = ssa_emit_conv(proc, results[i], t);
+ ssaValue *gep = ssa_emit_struct_gep(proc, v, i, make_type_pointer(proc->module->allocator, t));
+ ssa_emit_store(proc, gep, e);
+ }
+
+ v = ssa_emit_load(proc, v);
+
} else if (return_count == 1) {
Entity *e = return_type_tuple->variables[0];
v = ssa_emit_conv(proc, ssa_build_expr(proc, rs->results[0]), e->type);
@@ -3732,7 +3762,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
ssa_build_stmt(proc, pa->body);
ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL);
-
case_end;