authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-14 19:11:37-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-14 19:11:37-04:00
loge93a05b6e4a6e66012a24d61d7653e7002e62196
tree5aac024772b68682954b78a5a41037e8b61b6e14
parentc08c222d5e8881631a4e3c56a9bda909c25e6c0b
signaturelock-open Commit is signed but in an unrecognized format.

switching on error sets makes new error set for capture values

closes #769

4 files changed, 95 insertions(+), 21 deletions(-)

src/all_types.hpp+2-1
......@@ -2370,7 +2370,8 @@ struct IrInstructionSwitchVar {
23702370 IrInstruction base;
23712371
23722372 IrInstruction *target_value_ptr;
2373 IrInstruction *prong_value;
2373 IrInstruction **prongs_ptr;
2374 size_t prongs_len;
23742375};
23752376
23762377struct IrInstructionSwitchElseVar {
src/ir.cpp+57-18
......@@ -1834,14 +1834,17 @@ static IrInstruction *ir_build_switch_target(IrBuilder *irb, Scope *scope, AstNo
18341834}
18351835
18361836static 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)
18381838{
18391839 IrInstructionSwitchVar *instruction = ir_build_instruction<IrInstructionSwitchVar>(irb, scope, source_node);
18401840 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;
18421843
18431844 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 }
18451848
18461849 return &instruction->base;
18471850}
......@@ -6309,7 +6312,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
63096312
63106313static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,
63116314 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,
63136316 ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values,
63146317 IrInstructionSwitchElseVar **out_switch_else_var)
63156318{
......@@ -6336,8 +6339,9 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
63366339 *out_switch_else_var = switch_else_var;
63376340 IrInstruction *var_ptr_value = &switch_else_var->base;
63386341 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) {
6340 IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
6342 } else if (prong_values != nullptr) {
6343 IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr,
6344 prong_values, prong_values_len);
63416345 var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value);
63426346 } else {
63436347 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 *
64106414 IrBasicBlock *prev_block = irb->current_basic_block;
64116415 ir_set_cursor_at_end_and_append_block(irb, else_block);
64126416 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,
64146418 &switch_else_var))
64156419 {
64166420 return irb->codegen->invalid_instruction;
......@@ -6478,7 +6482,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
64786482
64796483 ir_set_cursor_at_end_and_append_block(irb, range_block_yes);
64806484 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))
64826487 {
64836488 return irb->codegen->invalid_instruction;
64846489 }
......@@ -6497,7 +6502,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
64976502 continue;
64986503
64996504 IrBasicBlock *prong_block = ir_create_basic_block(irb, scope, "SwitchProng");
6500 IrInstruction *last_item_value = nullptr;
6505 IrInstruction **items = allocate<IrInstruction *>(prong_item_count);
65016506
65026507 for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) {
65036508 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 *
65156520 this_case->value = item_value;
65166521 this_case->block = prong_block;
65176522
6518 last_item_value = item_value;
6523 items[item_i] = item_value;
65196524 }
6520 IrInstruction *only_item_value = (prong_item_count == 1) ? last_item_value : nullptr;
65216525
65226526 IrBasicBlock *prev_block = irb->current_basic_block;
65236527 ir_set_cursor_at_end_and_append_block(irb, prong_block);
65246528 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,
6526 nullptr))
6529 is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count,
6530 &incoming_blocks, &incoming_values, nullptr))
65276531 {
65286532 return irb->codegen->invalid_instruction;
65296533 }
......@@ -17423,17 +17427,22 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1742317427 if (type_is_invalid(target_value_ptr->value.type))
1742417428 return ira->codegen->invalid_instruction;
1742517429
17426 IrInstruction *prong_value = instruction->prong_value->child;
17427 if (type_is_invalid(prong_value->value.type))
17428 return ira->codegen->invalid_instruction;
17429
17430 assert(target_value_ptr->value.type->id == ZigTypeIdPointer);
17430 ZigType *ref_type = target_value_ptr->value.type;
17431 assert(ref_type->id == ZigTypeIdPointer);
1743117432 ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type;
1743217433 if (target_type->id == ZigTypeIdUnion) {
1743317434 ZigType *enum_type = target_type->data.unionation.tag_type;
1743417435 assert(enum_type != nullptr);
1743517436 assert(enum_type->id == ZigTypeIdEnum);
1743617437
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
1743717446 IrInstruction *casted_prong_value = ir_implicit_cast(ira, prong_value, enum_type);
1743817447 if (type_is_invalid(casted_prong_value->value.type))
1743917448 return ira->codegen->invalid_instruction;
......@@ -17468,6 +17477,36 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1746817477 result->value.type = get_pointer_to_type(ira->codegen, field->type_entry,
1746917478 target_value_ptr->value.type->data.pointer.is_const);
1747017479 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);
1747117510 } else {
1747217511 ir_add_error(ira, &instruction->base,
1747317512 buf_sprintf("switch on type '%s' provides no expression parameter", buf_ptr(&target_type->name)));
src/ir_print.cpp+4-2
......@@ -542,8 +542,10 @@ static void ir_print_switch_br(IrPrint *irp, IrInstructionSwitchBr *instruction)
542542static void ir_print_switch_var(IrPrint *irp, IrInstructionSwitchVar *instruction) {
543543 fprintf(irp->f, "switchvar ");
544544 ir_print_other_instruction(irp, instruction->target_value_ptr);
545 fprintf(irp->f, ", ");
546 ir_print_other_instruction(irp, instruction->prong_value);
545 for (size_t i = 0; i < instruction->prongs_len; i += 1) {
546 fprintf(irp->f, ", ");
547 ir_print_other_instruction(irp, instruction->prongs_ptr[i]);
548 }
547549}
548550
549551static void ir_print_switch_else_var(IrPrint *irp, IrInstructionSwitchElseVar *instruction) {
test/stage1/behavior/switch.zig+32
......@@ -328,3 +328,35 @@ test "else prong of switch on error set excludes other cases" {
328328 S.doTheTest();
329329 comptime S.doTheTest();
330330}
331
332test "switch prongs with error set cases make a new error set type for capture value" {
333 const S = struct {
334 fn doTheTest() void {
335 expectError(error.B, bar());
336 }
337 const E = E1 || E2;
338
339 const E1 = error{
340 A,
341 B,
342 };
343
344 const E2 = error{
345 C,
346 D,
347 };
348
349 fn foo() E!void {
350 return error.B;
351 }
352
353 fn bar() E1!void {
354 foo() catch |err| switch (err) {
355 error.A, error.B => |e| return e,
356 else => {},
357 };
358 }
359 };
360 S.doTheTest();
361 comptime S.doTheTest();
362}