authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-14 18:06:02-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-14 18:06:57-04:00
logdf4f77024e93dc3b60dd1d76d64e3c5ffa5ebd84
tree59d5026be2d5840255bf48b8d48a94840c26e0cf
parent6536b409df053165ed704148de6ecf5b72e27282
signaturelock-open Commit is signed but in an unrecognized format.

else value when switching on error set has

optional capture value which is subset. see #769

5 files changed, 207 insertions(+), 23 deletions(-)

src/all_types.hpp+8
......@@ -2149,6 +2149,7 @@ enum IrInstructionId {
21492149 IrInstructionIdCondBr,
21502150 IrInstructionIdSwitchBr,
21512151 IrInstructionIdSwitchVar,
2152 IrInstructionIdSwitchElseVar,
21522153 IrInstructionIdSwitchTarget,
21532154 IrInstructionIdPhi,
21542155 IrInstructionIdUnOp,
......@@ -2372,6 +2373,13 @@ struct IrInstructionSwitchVar {
23722373 IrInstruction *prong_value;
23732374};
23742375
2376struct IrInstructionSwitchElseVar {
2377 IrInstruction base;
2378
2379 IrInstruction *target_value_ptr;
2380 IrInstructionSwitchBr *switch_br;
2381};
2382
23752383struct IrInstructionSwitchTarget {
23762384 IrInstruction base;
23772385
src/codegen.cpp+1
......@@ -5572,6 +5572,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
55725572 case IrInstructionIdTypeName:
55735573 case IrInstructionIdDeclRef:
55745574 case IrInstructionIdSwitchVar:
5575 case IrInstructionIdSwitchElseVar:
55755576 case IrInstructionIdByteOffsetOf:
55765577 case IrInstructionIdBitOffsetOf:
55775578 case IrInstructionIdTypeInfo:
src/ir.cpp+157-22
......@@ -419,6 +419,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchVar *) {
419419 return IrInstructionIdSwitchVar;
420420}
421421
422static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchElseVar *) {
423 return IrInstructionIdSwitchElseVar;
424}
425
422426static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchTarget *) {
423427 return IrInstructionIdSwitchTarget;
424428}
......@@ -1791,7 +1795,7 @@ static IrInstruction *ir_build_pop_count(IrBuilder *irb, Scope *scope, AstNode *
17911795 return &instruction->base;
17921796}
17931797
1794static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,
1798static IrInstructionSwitchBr *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,
17951799 IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
17961800 IrInstruction *switch_prongs_void)
17971801{
......@@ -1815,7 +1819,7 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *
18151819 ir_ref_bb(cases[i].block);
18161820 }
18171821
1818 return &instruction->base;
1822 return instruction;
18191823}
18201824
18211825static IrInstruction *ir_build_switch_target(IrBuilder *irb, Scope *scope, AstNode *source_node,
......@@ -1842,6 +1846,18 @@ static IrInstruction *ir_build_switch_var(IrBuilder *irb, Scope *scope, AstNode
18421846 return &instruction->base;
18431847}
18441848
1849// For this instruction the switch_br must be set later.
1850static IrInstructionSwitchElseVar *ir_build_switch_else_var(IrBuilder *irb, Scope *scope, AstNode *source_node,
1851 IrInstruction *target_value_ptr)
1852{
1853 IrInstructionSwitchElseVar *instruction = ir_build_instruction<IrInstructionSwitchElseVar>(irb, scope, source_node);
1854 instruction->target_value_ptr = target_value_ptr;
1855
1856 ir_ref_instruction(target_value_ptr, irb->current_basic_block);
1857
1858 return instruction;
1859}
1860
18451861static IrInstruction *ir_build_union_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
18461862 IrInstructionUnionTag *instruction = ir_build_instruction<IrInstructionUnionTag>(irb, scope, source_node);
18471863 instruction->value = value;
......@@ -6294,7 +6310,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
62946310static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,
62956311 IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime,
62966312 IrInstruction *target_value_ptr, IrInstruction *prong_value,
6297 ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values)
6313 ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values,
6314 IrInstructionSwitchElseVar **out_switch_else_var)
62986315{
62996316 assert(switch_node->type == NodeTypeSwitchExpr);
63006317 assert(prong_node->type == NodeTypeSwitchProng);
......@@ -6312,13 +6329,17 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
63126329 ZigVar *var = ir_create_var(irb, var_symbol_node, scope,
63136330 var_name, is_const, is_const, is_shadowable, var_is_comptime);
63146331 child_scope = var->child_scope;
6315 IrInstruction *var_value;
6316 if (prong_value) {
6317 IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
6318 var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value);
6332 IrInstruction *var_ptr_value;
6333 if (prong_value != nullptr) {
6334 var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
63196335 } else {
6320 var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
6336 IrInstructionSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node,
6337 target_value_ptr);
6338 *out_switch_else_var = switch_else_var;
6339 var_ptr_value = &switch_else_var->base;
63216340 }
6341 IrInstruction *var_value = var_is_ptr ?
6342 var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value);
63226343 IrInstruction *var_type = nullptr; // infer the type
63236344 ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
63246345 } else {
......@@ -6364,6 +6385,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
63646385 ZigList<IrBasicBlock *> incoming_blocks = {0};
63656386 ZigList<IrInstructionCheckSwitchProngsRange> check_ranges = {0};
63666387
6388 IrInstructionSwitchElseVar *switch_else_var = nullptr;
6389
63676390 // First do the else and the ranges
63686391 Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
63696392 Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
......@@ -6384,7 +6407,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
63846407 IrBasicBlock *prev_block = irb->current_basic_block;
63856408 ir_set_cursor_at_end_and_append_block(irb, else_block);
63866409 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
6387 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
6410 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values,
6411 &switch_else_var))
63886412 {
63896413 return irb->codegen->invalid_instruction;
63906414 }
......@@ -6451,7 +6475,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
64516475
64526476 ir_set_cursor_at_end_and_append_block(irb, range_block_yes);
64536477 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
6454 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
6478 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values, nullptr))
64556479 {
64566480 return irb->codegen->invalid_instruction;
64576481 }
......@@ -6495,7 +6519,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
64956519 IrBasicBlock *prev_block = irb->current_basic_block;
64966520 ir_set_cursor_at_end_and_append_block(irb, prong_block);
64976521 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
6498 is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))
6522 is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values,
6523 nullptr))
64996524 {
65006525 return irb->codegen->invalid_instruction;
65016526 }
......@@ -6510,7 +6535,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
65106535 if (cases.length == 0) {
65116536 ir_build_br(irb, scope, node, else_block, is_comptime);
65126537 } else {
6513 ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime, switch_prongs_void);
6538 IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, scope, node, target_value, else_block,
6539 cases.length, cases.items, is_comptime, switch_prongs_void);
6540 if (switch_else_var != nullptr) {
6541 switch_else_var->switch_br = switch_br;
6542 }
65146543 }
65156544
65166545 if (!else_prong) {
......@@ -7474,8 +7503,9 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
74747503 cases[0].block = resume_block;
74757504 cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
74767505 cases[1].block = canceled_block;
7477 ir_mark_gen(ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
7478 2, cases, const_bool_false, nullptr));
7506 IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, parent_scope, node, suspend_code,
7507 irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
7508 ir_mark_gen(&switch_br->base);
74797509
74807510 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
74817511 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
......@@ -8972,6 +9002,15 @@ static bool slice_is_const(ZigType *type) {
89729002 return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
89739003}
89749004
9005static void populate_error_set_table(ErrorTableEntry **errors, ZigType *set) {
9006 assert(set->id == ZigTypeIdErrorSet);
9007 for (uint32_t i = 0; i < set->data.error_set.err_count; i += 1) {
9008 ErrorTableEntry *error_entry = set->data.error_set.errors[i];
9009 assert(errors[error_entry->value] == nullptr);
9010 errors[error_entry->value] = error_entry;
9011 }
9012}
9013
89759014static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigType *set2,
89769015 AstNode *source_node)
89779016{
......@@ -8991,11 +9030,7 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
89919030 return set1;
89929031 }
89939032 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
8994 for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
8995 ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
8996 assert(errors[error_entry->value] == nullptr);
8997 errors[error_entry->value] = error_entry;
8998 }
9033 populate_error_set_table(errors, set1);
89999034 ZigList<ErrorTableEntry *> intersection_list = {};
90009035
90019036 ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
......@@ -10410,6 +10445,24 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
1041010445 return ir_exec_const_result(codegen, analyzed_executable);
1041110446}
1041210447
10448static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_value) {
10449 if (type_is_invalid(err_value->value.type))
10450 return nullptr;
10451
10452 if (err_value->value.type->id != ZigTypeIdErrorSet) {
10453 ir_add_error(ira, err_value,
10454 buf_sprintf("expected error, found '%s'", buf_ptr(&err_value->value.type->name)));
10455 return nullptr;
10456 }
10457
10458 ConstExprValue *const_val = ir_resolve_const(ira, err_value, UndefBad);
10459 if (!const_val)
10460 return nullptr;
10461
10462 assert(const_val->data.x_err_set != nullptr);
10463 return const_val->data.x_err_set;
10464}
10465
1041310466static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
1041410467 if (type_is_invalid(type_value->value.type))
1041510468 return ira->codegen->builtin_types.entry_invalid;
......@@ -17229,11 +17282,11 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
1722917282 }
1723017283
1723117284 IrBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block, &switch_br_instruction->base);
17232 IrInstruction *result = ir_build_switch_br(&ira->new_irb,
17285 IrInstructionSwitchBr *switch_br = ir_build_switch_br(&ira->new_irb,
1723317286 switch_br_instruction->base.scope, switch_br_instruction->base.source_node,
1723417287 target_value, new_else_block, case_count, cases, nullptr, nullptr);
17235 result->value.type = ira->codegen->builtin_types.entry_unreachable;
17236 return ir_finish_anal(ira, result);
17288 switch_br->base.value.type = ira->codegen->builtin_types.entry_unreachable;
17289 return ir_finish_anal(ira, &switch_br->base);
1723717290}
1723817291
1723917292static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
......@@ -17419,6 +17472,85 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1741917472 }
1742017473}
1742117474
17475static IrInstruction *ir_analyze_instruction_switch_else_var(IrAnalyze *ira,
17476 IrInstructionSwitchElseVar *instruction)
17477{
17478 IrInstruction *target_value_ptr = instruction->target_value_ptr->child;
17479 if (type_is_invalid(target_value_ptr->value.type))
17480 return ira->codegen->invalid_instruction;
17481
17482 ZigType *ref_type = target_value_ptr->value.type;
17483 assert(ref_type->id == ZigTypeIdPointer);
17484 ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type;
17485 if (target_type->id == ZigTypeIdErrorSet) {
17486 // make a new set that has the other cases removed
17487 if (!resolve_inferred_error_set(ira->codegen, target_type, instruction->base.source_node)) {
17488 return ira->codegen->invalid_instruction;
17489 }
17490 if (type_is_global_error_set(target_type)) {
17491 // the type of the else capture variable still has to be the global error set.
17492 // once the runtime hint system is more sophisticated, we could add some hint information here.
17493 return target_value_ptr;
17494 }
17495 // Make note of the errors handled by other cases
17496 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
17497 for (size_t case_i = 0; case_i < instruction->switch_br->case_count; case_i += 1) {
17498 IrInstructionSwitchBrCase *br_case = &instruction->switch_br->cases[case_i];
17499 IrInstruction *case_expr = br_case->value->child;
17500 if (case_expr->value.type->id == ZigTypeIdErrorSet) {
17501 ErrorTableEntry *err = ir_resolve_error(ira, case_expr);
17502 if (err == nullptr)
17503 return ira->codegen->invalid_instruction;
17504 errors[err->value] = err;
17505 } else if (case_expr->value.type->id == ZigTypeIdMetaType) {
17506 ZigType *err_set_type = ir_resolve_type(ira, case_expr);
17507 if (type_is_invalid(err_set_type))
17508 return ira->codegen->invalid_instruction;
17509 populate_error_set_table(errors, err_set_type);
17510 } else {
17511 zig_unreachable();
17512 }
17513 }
17514 ZigList<ErrorTableEntry *> result_list = {};
17515
17516 ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet);
17517 buf_resize(&err_set_type->name, 0);
17518 buf_appendf(&err_set_type->name, "error{");
17519
17520 // Look at all the errors in the type switched on and add them to the result_list
17521 // if they are not handled by cases.
17522 for (uint32_t i = 0; i < target_type->data.error_set.err_count; i += 1) {
17523 ErrorTableEntry *error_entry = target_type->data.error_set.errors[i];
17524 ErrorTableEntry *existing_entry = errors[error_entry->value];
17525 if (existing_entry == nullptr) {
17526 result_list.append(error_entry);
17527 buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name));
17528 }
17529 }
17530 free(errors);
17531
17532 err_set_type->data.error_set.err_count = result_list.length;
17533 err_set_type->data.error_set.errors = result_list.items;
17534 err_set_type->size_in_bits = ira->codegen->builtin_types.entry_global_error_set->size_in_bits;
17535 err_set_type->abi_align = ira->codegen->builtin_types.entry_global_error_set->abi_align;
17536 err_set_type->abi_size = ira->codegen->builtin_types.entry_global_error_set->abi_size;
17537
17538 buf_appendf(&err_set_type->name, "}");
17539
17540 ZigType *new_target_value_ptr_type = get_pointer_to_type_extra(ira->codegen,
17541 err_set_type,
17542 ref_type->data.pointer.is_const, ref_type->data.pointer.is_volatile,
17543 ref_type->data.pointer.ptr_len,
17544 ref_type->data.pointer.explicit_alignment,
17545 ref_type->data.pointer.bit_offset_in_host, ref_type->data.pointer.host_int_bytes,
17546 ref_type->data.pointer.allow_zero);
17547 return ir_analyze_ptr_cast(ira, &instruction->base, target_value_ptr, new_target_value_ptr_type,
17548 &instruction->base, false);
17549 }
17550
17551 return target_value_ptr;
17552}
17553
1742217554static IrInstruction *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUnionTag *instruction) {
1742317555 IrInstruction *value = instruction->value->child;
1742417556 return ir_analyze_union_tag(ira, &instruction->base, value);
......@@ -23094,6 +23226,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
2309423226 return ir_analyze_instruction_switch_target(ira, (IrInstructionSwitchTarget *)instruction);
2309523227 case IrInstructionIdSwitchVar:
2309623228 return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction);
23229 case IrInstructionIdSwitchElseVar:
23230 return ir_analyze_instruction_switch_else_var(ira, (IrInstructionSwitchElseVar *)instruction);
2309723231 case IrInstructionIdUnionTag:
2309823232 return ir_analyze_instruction_union_tag(ira, (IrInstructionUnionTag *)instruction);
2309923233 case IrInstructionIdImport:
......@@ -23457,6 +23591,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2345723591 case IrInstructionIdCtz:
2345823592 case IrInstructionIdPopCount:
2345923593 case IrInstructionIdSwitchVar:
23594 case IrInstructionIdSwitchElseVar:
2346023595 case IrInstructionIdSwitchTarget:
2346123596 case IrInstructionIdUnionTag:
2346223597 case IrInstructionIdRef:
src/ir_print.cpp+8
......@@ -546,6 +546,11 @@ static void ir_print_switch_var(IrPrint *irp, IrInstructionSwitchVar *instructio
546546 ir_print_other_instruction(irp, instruction->prong_value);
547547}
548548
549static void ir_print_switch_else_var(IrPrint *irp, IrInstructionSwitchElseVar *instruction) {
550 fprintf(irp->f, "switchelsevar ");
551 ir_print_other_instruction(irp, &instruction->switch_br->base);
552}
553
549554static void ir_print_switch_target(IrPrint *irp, IrInstructionSwitchTarget *instruction) {
550555 fprintf(irp->f, "switchtarget ");
551556 ir_print_other_instruction(irp, instruction->target_value_ptr);
......@@ -1559,6 +1564,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15591564 case IrInstructionIdSwitchVar:
15601565 ir_print_switch_var(irp, (IrInstructionSwitchVar *)instruction);
15611566 break;
1567 case IrInstructionIdSwitchElseVar:
1568 ir_print_switch_else_var(irp, (IrInstructionSwitchElseVar *)instruction);
1569 break;
15621570 case IrInstructionIdSwitchTarget:
15631571 ir_print_switch_target(irp, (IrInstructionSwitchTarget *)instruction);
15641572 break;
test/stage1/behavior/switch.zig+33-1
......@@ -1,4 +1,6 @@
1const expect = @import("std").testing.expect;
1const std = @import("std");
2const expect = std.testing.expect;
3const expectError = std.testing.expectError;
24
35test "switch with numbers" {
46 testSwitchWithNumbers(13);
......@@ -296,3 +298,33 @@ test "anon enum literal used in switch on union enum" {
296298 },
297299 }
298300}
301
302test "else prong of switch on error set excludes other cases" {
303 const S = struct {
304 fn doTheTest() void {
305 expectError(error.C, bar());
306 }
307 const E = error{
308 A,
309 B,
310 } || E2;
311
312 const E2 = error{
313 C,
314 D,
315 };
316
317 fn foo() E!void {
318 return error.C;
319 }
320
321 fn bar() E2!void {
322 foo() catch |err| switch (err) {
323 error.A, error.B => {},
324 else => |e| return e,
325 };
326 }
327 };
328 S.doTheTest();
329 comptime S.doTheTest();
330}