Browse Source

Fix returns of tuple

Ginger Bill 9 years ago
parent
commit
db6abb9706
3 changed files with 62 additions and 18 deletions
  1. 11 0
      code/demo.odin
  2. 19 15
      src/checker/stmt.cpp
  3. 32 3
      src/codegen/ssa.cpp

+ 11 - 0
code/demo.odin

@@ -2,7 +2,18 @@
 #import "os.odin"
 #import "os.odin"
 #import "mem.odin"
 #import "mem.odin"
 
 
+
 main :: proc() {
 main :: proc() {
+	x :: proc() -> (int, int) {
+		return 1, 2
+	}
+	y :: proc() -> (int, int) {
+		return x()
+	}
+
+	fmt.println(y())
+
+
 
 
 	arena: mem.Arena
 	arena: mem.Arena
 	mem.init_arena_from_context(^arena, 1000)
 	mem.init_arena_from_context(^arena, 1000)

+ 19 - 15
src/checker/stmt.cpp

@@ -146,6 +146,13 @@ b32 check_is_terminating(AstNode *node) {
 		}
 		}
 		return has_default;
 		return has_default;
 	case_end;
 	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;
 	return false;
@@ -160,15 +167,13 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 	AstNode *node = unparen_expr(lhs);
 	AstNode *node = unparen_expr(lhs);
 
 
 	// NOTE(bill): Ignore assignments to `_`
 	// 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;
 	Entity *e = NULL;
@@ -989,17 +994,14 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 			break;
 			break;
 		}
 		}
 
 
+
 		Type *proc_type = c->proc_stack[gb_array_count(c->proc_stack)-1];
 		Type *proc_type = c->proc_stack[gb_array_count(c->proc_stack)-1];
 		isize result_count = 0;
 		isize result_count = 0;
 		if (proc_type->Proc.results) {
 		if (proc_type->Proc.results) {
 			result_count = proc_type->Proc.results->Tuple.variable_count;
 			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;
 			Entity **variables = NULL;
 			if (proc_type->Proc.results != NULL) {
 			if (proc_type->Proc.results != NULL) {
 				auto *tuple = &proc_type->Proc.results->Tuple;
 				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,
 			check_init_variables(c, variables, result_count,
 			                     rs->results, make_string("return statement"));
 			                     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;
 	case_end;
 
 

+ 32 - 3
src/codegen/ssa.cpp

@@ -3366,8 +3366,38 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		ssaValue *v = NULL;
 		ssaValue *v = NULL;
 		auto *return_type_tuple  = &proc->type->Proc.results->Tuple;
 		auto *return_type_tuple  = &proc->type->Proc.results->Tuple;
 		isize return_count = proc->type->Proc.result_count;
 		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) {
 		} else if (return_count == 1) {
 			Entity *e = return_type_tuple->variables[0];
 			Entity *e = return_type_tuple->variables[0];
 			v = ssa_emit_conv(proc, ssa_build_expr(proc, rs->results[0]), e->type);
 			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_build_stmt(proc, pa->body);
 		ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL);
 		ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL);
-
 	case_end;
 	case_end;