| ... | @@ -1834,14 +1834,17 @@ static IrInstruction *ir_build_switch_target(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -1834,14 +1834,17 @@ static IrInstruction *ir_build_switch_target(IrBuilder *irb, Scope *scope, AstNo |
| 1834 | } | 1834 | } |
| 1835 | | 1835 | |
| 1836 | static IrInstruction *ir_build_switch_var(IrBuilder *irb, Scope *scope, AstNode *source_node, | 1836 | static IrInstruction *ir_build_switch_var(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1837 | IrInstruction *target_value_ptr, IrInstruction *prong_value) | 1837 | IrInstruction *target_value_ptr, IrInstruction **prongs_ptr, size_t prongs_len) |
| 1838 | { | 1838 | { |
| 1839 | IrInstructionSwitchVar *instruction = ir_build_instruction<IrInstructionSwitchVar>(irb, scope, source_node); | 1839 | IrInstructionSwitchVar *instruction = ir_build_instruction<IrInstructionSwitchVar>(irb, scope, source_node); |
| 1840 | instruction->target_value_ptr = target_value_ptr; | 1840 | instruction->target_value_ptr = target_value_ptr; |
| 1841 | instruction->prong_value = prong_value; | 1841 | instruction->prongs_ptr = prongs_ptr; |
| | 1842 | instruction->prongs_len = prongs_len; |
| 1842 | | 1843 | |
| 1843 | ir_ref_instruction(target_value_ptr, irb->current_basic_block); | 1844 | ir_ref_instruction(target_value_ptr, irb->current_basic_block); |
| 1844 | ir_ref_instruction(prong_value, irb->current_basic_block); | 1845 | for (size_t i = 0; i < prongs_len; i += 1) { |
| | 1846 | ir_ref_instruction(prongs_ptr[i], irb->current_basic_block); |
| | 1847 | } |
| 1845 | | 1848 | |
| 1846 | return &instruction->base; | 1849 | return &instruction->base; |
| 1847 | } | 1850 | } |
| ... | @@ -6309,7 +6312,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6309,7 +6312,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6309 | | 6312 | |
| 6310 | static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, | 6313 | static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, |
| 6311 | IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime, | 6314 | IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime, |
| 6312 | IrInstruction *target_value_ptr, IrInstruction *prong_value, | 6315 | IrInstruction *target_value_ptr, IrInstruction **prong_values, size_t prong_values_len, |
| 6313 | ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values, | 6316 | ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values, |
| 6314 | IrInstructionSwitchElseVar **out_switch_else_var) | 6317 | IrInstructionSwitchElseVar **out_switch_else_var) |
| 6315 | { | 6318 | { |
| ... | @@ -6336,8 +6339,9 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit | ... | @@ -6336,8 +6339,9 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit |
| 6336 | *out_switch_else_var = switch_else_var; | 6339 | *out_switch_else_var = switch_else_var; |
| 6337 | IrInstruction *var_ptr_value = &switch_else_var->base; | 6340 | IrInstruction *var_ptr_value = &switch_else_var->base; |
| 6338 | var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); | 6341 | var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); |
| 6339 | } else if (prong_value != nullptr) { | 6342 | } else if (prong_values != nullptr) { |
| 6340 | IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value); | 6343 | IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, |
| | 6344 | prong_values, prong_values_len); |
| 6341 | var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); | 6345 | var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); |
| 6342 | } else { | 6346 | } else { |
| 6343 | var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, | 6347 | var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, |
| ... | @@ -6410,7 +6414,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6410,7 +6414,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6410 | IrBasicBlock *prev_block = irb->current_basic_block; | 6414 | IrBasicBlock *prev_block = irb->current_basic_block; |
| 6411 | ir_set_cursor_at_end_and_append_block(irb, else_block); | 6415 | ir_set_cursor_at_end_and_append_block(irb, else_block); |
| 6412 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, | 6416 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6413 | is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values, | 6417 | is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, |
| 6414 | &switch_else_var)) | 6418 | &switch_else_var)) |
| 6415 | { | 6419 | { |
| 6416 | return irb->codegen->invalid_instruction; | 6420 | return irb->codegen->invalid_instruction; |
| ... | @@ -6478,7 +6482,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6478,7 +6482,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6478 | | 6482 | |
| 6479 | ir_set_cursor_at_end_and_append_block(irb, range_block_yes); | 6483 | ir_set_cursor_at_end_and_append_block(irb, range_block_yes); |
| 6480 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, | 6484 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6481 | is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values, nullptr)) | 6485 | is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, |
| | 6486 | &incoming_blocks, &incoming_values, nullptr)) |
| 6482 | { | 6487 | { |
| 6483 | return irb->codegen->invalid_instruction; | 6488 | return irb->codegen->invalid_instruction; |
| 6484 | } | 6489 | } |
| ... | @@ -6497,7 +6502,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6497,7 +6502,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6497 | continue; | 6502 | continue; |
| 6498 | | 6503 | |
| 6499 | IrBasicBlock *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); | 6504 | IrBasicBlock *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); |
| 6500 | IrInstruction *last_item_value = nullptr; | 6505 | IrInstruction **items = allocate<IrInstruction *>(prong_item_count); |
| 6501 | | 6506 | |
| 6502 | for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { | 6507 | for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { |
| 6503 | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); | 6508 | AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); |
| ... | @@ -6515,15 +6520,14 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -6515,15 +6520,14 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * |
| 6515 | this_case->value = item_value; | 6520 | this_case->value = item_value; |
| 6516 | this_case->block = prong_block; | 6521 | this_case->block = prong_block; |
| 6517 | | 6522 | |
| 6518 | last_item_value = item_value; | 6523 | items[item_i] = item_value; |
| 6519 | } | 6524 | } |
| 6520 | IrInstruction *only_item_value = (prong_item_count == 1) ? last_item_value : nullptr; | | |
| 6521 | | 6525 | |
| 6522 | IrBasicBlock *prev_block = irb->current_basic_block; | 6526 | IrBasicBlock *prev_block = irb->current_basic_block; |
| 6523 | ir_set_cursor_at_end_and_append_block(irb, prong_block); | 6527 | ir_set_cursor_at_end_and_append_block(irb, prong_block); |
| 6524 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, | 6528 | if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, |
| 6525 | is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values, | 6529 | is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, |
| 6526 | nullptr)) | 6530 | &incoming_blocks, &incoming_values, nullptr)) |
| 6527 | { | 6531 | { |
| 6528 | return irb->codegen->invalid_instruction; | 6532 | return irb->codegen->invalid_instruction; |
| 6529 | } | 6533 | } |
| ... | @@ -17423,17 +17427,22 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru | ... | @@ -17423,17 +17427,22 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru |
| 17423 | if (type_is_invalid(target_value_ptr->value.type)) | 17427 | if (type_is_invalid(target_value_ptr->value.type)) |
| 17424 | return ira->codegen->invalid_instruction; | 17428 | return ira->codegen->invalid_instruction; |
| 17425 | | 17429 | |
| 17426 | IrInstruction *prong_value = instruction->prong_value->child; | 17430 | ZigType *ref_type = target_value_ptr->value.type; |
| 17427 | if (type_is_invalid(prong_value->value.type)) | 17431 | assert(ref_type->id == ZigTypeIdPointer); |
| 17428 | return ira->codegen->invalid_instruction; | | |
| 17429 | | | |
| 17430 | assert(target_value_ptr->value.type->id == ZigTypeIdPointer); | | |
| 17431 | ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type; | 17432 | ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type; |
| 17432 | if (target_type->id == ZigTypeIdUnion) { | 17433 | if (target_type->id == ZigTypeIdUnion) { |
| 17433 | ZigType *enum_type = target_type->data.unionation.tag_type; | 17434 | ZigType *enum_type = target_type->data.unionation.tag_type; |
| 17434 | assert(enum_type != nullptr); | 17435 | assert(enum_type != nullptr); |
| 17435 | assert(enum_type->id == ZigTypeIdEnum); | 17436 | assert(enum_type->id == ZigTypeIdEnum); |
| 17436 | | 17437 | |
| | 17438 | if (instruction->prongs_len != 1) { |
| | 17439 | return target_value_ptr; |
| | 17440 | } |
| | 17441 | |
| | 17442 | IrInstruction *prong_value = instruction->prongs_ptr[0]->child; |
| | 17443 | if (type_is_invalid(prong_value->value.type)) |
| | 17444 | return ira->codegen->invalid_instruction; |
| | 17445 | |
| 17437 | IrInstruction *casted_prong_value = ir_implicit_cast(ira, prong_value, enum_type); | 17446 | IrInstruction *casted_prong_value = ir_implicit_cast(ira, prong_value, enum_type); |
| 17438 | if (type_is_invalid(casted_prong_value->value.type)) | 17447 | if (type_is_invalid(casted_prong_value->value.type)) |
| 17439 | return ira->codegen->invalid_instruction; | 17448 | return ira->codegen->invalid_instruction; |
| ... | @@ -17468,6 +17477,36 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru | ... | @@ -17468,6 +17477,36 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru |
| 17468 | result->value.type = get_pointer_to_type(ira->codegen, field->type_entry, | 17477 | result->value.type = get_pointer_to_type(ira->codegen, field->type_entry, |
| 17469 | target_value_ptr->value.type->data.pointer.is_const); | 17478 | target_value_ptr->value.type->data.pointer.is_const); |
| 17470 | return result; | 17479 | return result; |
| | 17480 | } else if (target_type->id == ZigTypeIdErrorSet) { |
| | 17481 | // construct an error set from the prong values |
| | 17482 | ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); |
| | 17483 | err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits; |
| | 17484 | err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align; |
| | 17485 | err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size; |
| | 17486 | ZigList<ErrorTableEntry *> error_list = {}; |
| | 17487 | buf_resize(&err_set_type->name, 0); |
| | 17488 | buf_appendf(&err_set_type->name, "error{"); |
| | 17489 | for (size_t i = 0; i < instruction->prongs_len; i += 1) { |
| | 17490 | ErrorTableEntry *err = ir_resolve_error(ira, instruction->prongs_ptr[i]->child); |
| | 17491 | if (err == nullptr) |
| | 17492 | return ira->codegen->invalid_instruction; |
| | 17493 | error_list.append(err); |
| | 17494 | buf_appendf(&err_set_type->name, "%s,", buf_ptr(&err->name)); |
| | 17495 | } |
| | 17496 | err_set_type->data.error_set.errors = error_list.items; |
| | 17497 | err_set_type->data.error_set.err_count = error_list.length; |
| | 17498 | buf_appendf(&err_set_type->name, "}"); |
| | 17499 | |
| | 17500 | |
| | 17501 | ZigType *new_target_value_ptr_type = get_pointer_to_type_extra(ira->codegen, |
| | 17502 | err_set_type, |
| | 17503 | ref_type->data.pointer.is_const, ref_type->data.pointer.is_volatile, |
| | 17504 | ref_type->data.pointer.ptr_len, |
| | 17505 | ref_type->data.pointer.explicit_alignment, |
| | 17506 | ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes, |
| | 17507 | ref_type->data.pointer.allow_zero); |
| | 17508 | return ir_analyze_ptr_cast(ira, &instruction->base, target_value_ptr, new_target_value_ptr_type, |
| | 17509 | &instruction->base, false); |
| 17471 | } else { | 17510 | } else { |
| 17472 | ir_add_error(ira, &instruction->base, | 17511 | ir_add_error(ira, &instruction->base, |
| 17473 | buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name))); | 17512 | buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name))); |