support switching on error union type

closes #23
This commit is contained in:
Andrew Kelley
2016-04-25 21:51:04 -07:00
parent d1b65c6f46
commit d0378057d1
5 changed files with 143 additions and 15 deletions

View File

@@ -2627,12 +2627,6 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
}
zig_unreachable();
/* TODO delete
FnTableEntry *fn_entry = node->data.symbol_expr.fn_entry;
assert(fn_entry);
return fn_entry->fn_value;
*/
}
static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
@@ -2653,6 +2647,10 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
add_debug_source_node(g, node);
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, "");
target_value = LLVMBuildLoad(g->builder, tag_field_ptr, "");
} else if (target_type->id == TypeTableEntryIdErrorUnion) {
add_debug_source_node(g, node);
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, "");
target_value = LLVMBuildLoad(g->builder, tag_field_ptr, "");
} else {
zig_unreachable();
}
@@ -2696,12 +2694,23 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
assert(item_node->type != NodeTypeSwitchRange);
LLVMValueRef val;
if (target_type->id == TypeTableEntryIdEnum) {
if (target_type->id == TypeTableEntryIdEnum ||
target_type->id == TypeTableEntryIdErrorUnion)
{
assert(item_node->type == NodeTypeSymbol);
TypeEnumField *enum_field = item_node->data.symbol_expr.enum_field;
assert(enum_field);
val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref,
enum_field->value, false);
TypeEnumField *enum_field = nullptr;
uint32_t err_value = 0;
if (target_type->id == TypeTableEntryIdEnum) {
enum_field = item_node->data.symbol_expr.enum_field;
assert(enum_field);
val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref,
enum_field->value, false);
} else if (target_type->id == TypeTableEntryIdErrorUnion) {
err_value = item_node->data.symbol_expr.err_value;
val = LLVMConstInt(g->err_tag_type->type_ref, err_value, false);
} else {
zig_unreachable();
}
if (prong_var && type_has_bits(prong_var->type)) {
LLVMBasicBlockRef item_block;
@@ -2721,6 +2730,7 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
gen_assign_raw(g, var_node, BinOpTypeAssign,
prong_var->value_ref, target_value, prong_var->type, target_type);
} else if (target_type->id == TypeTableEntryIdEnum) {
assert(enum_field);
assert(type_has_bits(enum_field->type_entry));
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle,
1, "");
@@ -2731,6 +2741,25 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
gen_assign_raw(g, var_node, BinOpTypeAssign,
prong_var->value_ref, handle_val, prong_var->type, enum_field->type_entry);
} else if (target_type->id == TypeTableEntryIdErrorUnion) {
if (err_value == 0) {
// variable is the payload
LLVMValueRef err_payload_ptr = LLVMBuildStructGEP(g->builder,
target_value_handle, 1, "");
LLVMValueRef handle_val = get_handle_value(g, var_node,
err_payload_ptr, prong_var->type);
gen_assign_raw(g, var_node, BinOpTypeAssign,
prong_var->value_ref, handle_val, prong_var->type, prong_var->type);
} else {
// variable is the pure error value
LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder,
target_value_handle, 0, "");
LLVMValueRef handle_val = LLVMBuildLoad(g->builder, err_tag_ptr, "");
gen_assign_raw(g, var_node, BinOpTypeAssign,
prong_var->value_ref, handle_val, prong_var->type, g->err_tag_type);
}
} else {
zig_unreachable();
}
if (make_item_blocks) {
LLVMBuildBr(g->builder, prong_block);