authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-01-15 20:23:49+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-01-15 20:24:59+02:00
log6fd0dddf186f6435f422f2992f44ec9a35e09f20
tree4b285418ef2d5f47262247fa21040a7b0fb01c86
parent8d9d4a065820bfce0395465834cb9b7e01509a12
signature Commit is signed but in an unrecognized format.

implement non-exhaustive enums


4 files changed, 97 insertions(+), 35 deletions(-)

src/all_types.hpp+2
...@@ -1383,6 +1383,7 @@ struct ZigTypeEnum {...@@ -1383,6 +1383,7 @@ struct ZigTypeEnum {
1383 ContainerLayout layout;1383 ContainerLayout layout;
1384 ResolveStatus resolve_status;1384 ResolveStatus resolve_status;
13851385
1386 bool non_exhaustive;
1386 bool resolve_loop_flag;1387 bool resolve_loop_flag;
1387};1388};
13881389
...@@ -3665,6 +3666,7 @@ struct IrInstructionCheckSwitchProngs {...@@ -3665,6 +3666,7 @@ struct IrInstructionCheckSwitchProngs {
3665 IrInstructionCheckSwitchProngsRange *ranges;3666 IrInstructionCheckSwitchProngsRange *ranges;
3666 size_t range_count;3667 size_t range_count;
3667 bool have_else_prong;3668 bool have_else_prong;
3669 bool have_underscore_prong;
3668};3670};
36693671
3670struct IrInstructionCheckStatementIsVoid {3672struct IrInstructionCheckStatementIsVoid {
src/analyze.cpp+16-2
...@@ -2572,6 +2572,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2572,6 +2572,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2572 enum_type->data.enumeration.src_field_count = field_count;2572 enum_type->data.enumeration.src_field_count = field_count;
2573 enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);2573 enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
2574 enum_type->data.enumeration.fields_by_name.init(field_count);2574 enum_type->data.enumeration.fields_by_name.init(field_count);
2575 enum_type->data.enumeration.non_exhaustive = false;
25752576
2576 Scope *scope = &enum_type->data.enumeration.decls_scope->base;2577 Scope *scope = &enum_type->data.enumeration.decls_scope->base;
25772578
...@@ -2648,6 +2649,21 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2648,6 +2649,21 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2648 buf_sprintf("consider 'union(enum)' here"));2649 buf_sprintf("consider 'union(enum)' here"));
2649 }2650 }
26502651
2652 AstNode *tag_value = field_node->data.struct_field.value;
2653
2654 if (buf_eql_str(type_enum_field->name, "_")) {
2655 if (field_i != field_count - 1) {
2656 add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
2657 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2658 }
2659 if (tag_value != nullptr) {
2660 add_node_error(g, field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum"));
2661 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2662 }
2663 enum_type->data.enumeration.non_exhaustive = true;
2664 continue;
2665 }
2666
2651 auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);2667 auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);
2652 if (field_entry != nullptr) {2668 if (field_entry != nullptr) {
2653 ErrorMsg *msg = add_node_error(g, field_node,2669 ErrorMsg *msg = add_node_error(g, field_node,
...@@ -2657,8 +2673,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2657,8 +2673,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2657 continue;2673 continue;
2658 }2674 }
26592675
2660 AstNode *tag_value = field_node->data.struct_field.value;
2661
2662 if (tag_value != nullptr) {2676 if (tag_value != nullptr) {
2663 // A user-specified value is available2677 // A user-specified value is available
2664 ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type,2678 ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type,
src/codegen.cpp+1-1
...@@ -3356,7 +3356,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,...@@ -3356,7 +3356,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
3356 LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),3356 LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
3357 instruction->target->value->type, tag_int_type, target_val);3357 instruction->target->value->type, tag_int_type, target_val);
33583358
3359 if (ir_want_runtime_safety(g, &instruction->base) && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {3359 if (ir_want_runtime_safety(g, &instruction->base) && !wanted_type->data.enumeration.non_exhaustive) {
3360 LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");3360 LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
3361 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");3361 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
3362 size_t field_count = wanted_type->data.enumeration.src_field_count;3362 size_t field_count = wanted_type->data.enumeration.src_field_count;
src/ir.cpp+78-32
...@@ -3451,7 +3451,7 @@ static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode...@@ -3451,7 +3451,7 @@ static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode
34513451
3452static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,3452static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,
3453 IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count,3453 IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count,
3454 bool have_else_prong)3454 bool have_else_prong, bool have_underscore_prong)
3455{3455{
3456 IrInstructionCheckSwitchProngs *instruction = ir_build_instruction<IrInstructionCheckSwitchProngs>(3456 IrInstructionCheckSwitchProngs *instruction = ir_build_instruction<IrInstructionCheckSwitchProngs>(
3457 irb, scope, source_node);3457 irb, scope, source_node);
...@@ -3459,6 +3459,7 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,...@@ -3459,6 +3459,7 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,
3459 instruction->ranges = ranges;3459 instruction->ranges = ranges;
3460 instruction->range_count = range_count;3460 instruction->range_count = range_count;
3461 instruction->have_else_prong = have_else_prong;3461 instruction->have_else_prong = have_else_prong;
3462 instruction->have_underscore_prong = have_underscore_prong;
34623463
3463 ir_ref_instruction(target_value, irb->current_basic_block);3464 ir_ref_instruction(target_value, irb->current_basic_block);
3464 for (size_t i = 0; i < range_count; i += 1) {3465 for (size_t i = 0; i < range_count; i += 1) {
...@@ -8090,34 +8091,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -8090,34 +8091,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
8090 Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);8091 Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
8091 Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);8092 Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
8092 AstNode *else_prong = nullptr;8093 AstNode *else_prong = nullptr;
8094 AstNode *underscore_prong = nullptr;
8093 for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {8095 for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
8094 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);8096 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
8095 size_t prong_item_count = prong_node->data.switch_prong.items.length;8097 size_t prong_item_count = prong_node->data.switch_prong.items.length;
8096 if (prong_item_count == 0) {8098 if (prong_node->data.switch_prong.any_items_are_range) {
8097 ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
8098 if (else_prong) {
8099 ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
8100 buf_sprintf("multiple else prongs in switch expression"));
8101 add_error_note(irb->codegen, msg, else_prong,
8102 buf_sprintf("previous else prong is here"));
8103 return irb->codegen->invalid_instruction;
8104 }
8105 else_prong = prong_node;
8106
8107 IrBasicBlock *prev_block = irb->current_basic_block;
8108 if (peer_parent->peers.length > 0) {
8109 peer_parent->peers.last()->next_bb = else_block;
8110 }
8111 peer_parent->peers.append(this_peer_result_loc);
8112 ir_set_cursor_at_end_and_append_block(irb, else_block);
8113 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
8114 is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
8115 &switch_else_var, LValNone, &this_peer_result_loc->base))
8116 {
8117 return irb->codegen->invalid_instruction;
8118 }
8119 ir_set_cursor_at_end(irb, prev_block);
8120 } else if (prong_node->data.switch_prong.any_items_are_range) {
8121 ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);8099 ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
81228100
8123 IrInstruction *ok_bit = nullptr;8101 IrInstruction *ok_bit = nullptr;
...@@ -8195,6 +8173,59 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -8195,6 +8173,59 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
8195 }8173 }
81968174
8197 ir_set_cursor_at_end_and_append_block(irb, range_block_no);8175 ir_set_cursor_at_end_and_append_block(irb, range_block_no);
8176 } else {
8177 if (prong_item_count == 0) {
8178 if (else_prong) {
8179 ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
8180 buf_sprintf("multiple else prongs in switch expression"));
8181 add_error_note(irb->codegen, msg, else_prong,
8182 buf_sprintf("previous else prong is here"));
8183 return irb->codegen->invalid_instruction;
8184 }
8185 else_prong = prong_node;
8186 if (underscore_prong) {
8187 ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
8188 buf_sprintf("else and '_' prong in switch expression"));
8189 add_error_note(irb->codegen, msg, underscore_prong,
8190 buf_sprintf("'_' prong is here"));
8191 return irb->codegen->invalid_instruction;
8192 }
8193 } else if (prong_item_count == 1 &&
8194 prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol &&
8195 buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) {
8196 if (underscore_prong) {
8197 ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
8198 buf_sprintf("multiple '_' prongs in switch expression"));
8199 add_error_note(irb->codegen, msg, underscore_prong,
8200 buf_sprintf("previous '_' prong is here"));
8201 return irb->codegen->invalid_instruction;
8202 }
8203 underscore_prong = prong_node;
8204 if (else_prong) {
8205 ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
8206 buf_sprintf("else and '_' prong in switch expression"));
8207 add_error_note(irb->codegen, msg, else_prong,
8208 buf_sprintf("else prong is here"));
8209 return irb->codegen->invalid_instruction;
8210 }
8211 } else {
8212 continue;
8213 }
8214 ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
8215
8216 IrBasicBlock *prev_block = irb->current_basic_block;
8217 if (peer_parent->peers.length > 0) {
8218 peer_parent->peers.last()->next_bb = else_block;
8219 }
8220 peer_parent->peers.append(this_peer_result_loc);
8221 ir_set_cursor_at_end_and_append_block(irb, else_block);
8222 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
8223 is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
8224 &switch_else_var, LValNone, &this_peer_result_loc->base))
8225 {
8226 return irb->codegen->invalid_instruction;
8227 }
8228 ir_set_cursor_at_end(irb, prev_block);
8198 }8229 }
8199 }8230 }
82008231
...@@ -8206,6 +8237,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -8206,6 +8237,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
8206 continue;8237 continue;
8207 if (prong_node->data.switch_prong.any_items_are_range)8238 if (prong_node->data.switch_prong.any_items_are_range)
8208 continue;8239 continue;
8240 if (underscore_prong == prong_node)
8241 continue;
82098242
8210 ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);8243 ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
82118244
...@@ -8249,7 +8282,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -8249,7 +8282,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
8249 }8282 }
82508283
8251 IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,8284 IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,
8252 check_ranges.items, check_ranges.length, else_prong != nullptr);8285 check_ranges.items, check_ranges.length, else_prong != nullptr, underscore_prong != nullptr);
82538286
8254 IrInstruction *br_instruction;8287 IrInstruction *br_instruction;
8255 if (cases.length == 0) {8288 if (cases.length == 0) {
...@@ -8269,7 +8302,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -8269,7 +8302,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
8269 peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction;8302 peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction;
8270 }8303 }
82718304
8272 if (!else_prong) {8305 if (!else_prong && !underscore_prong) {
8273 if (peer_parent->peers.length != 0) {8306 if (peer_parent->peers.length != 0) {
8274 peer_parent->peers.last()->next_bb = else_block;8307 peer_parent->peers.last()->next_bb = else_block;
8275 }8308 }
...@@ -12790,7 +12823,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour...@@ -12790,7 +12823,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
12790 return ira->codegen->invalid_instruction;12823 return ira->codegen->invalid_instruction;
1279112824
12792 TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);12825 TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
12793 if (field == nullptr && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {12826 if (field == nullptr && !wanted_type->data.enumeration.non_exhaustive) {
12794 Buf *val_buf = buf_alloc();12827 Buf *val_buf = buf_alloc();
12795 bigint_append_buf(val_buf, &val->data.x_bigint, 10);12828 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
12796 ErrorMsg *msg = ir_add_error(ira, source_instr,12829 ErrorMsg *msg = ir_add_error(ira, source_instr,
...@@ -26433,10 +26466,23 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -26433,10 +26466,23 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
26433 bigint_incr(&field_index);26466 bigint_incr(&field_index);
26434 }26467 }
26435 }26468 }
26436 if (!instruction->have_else_prong) {26469 if (switch_type->data.enumeration.non_exhaustive && instruction->have_underscore_prong) {
26437 if (switch_type->data.enumeration.layout == ContainerLayoutExtern) {26470 for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
26471 TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
26472 if (buf_eql_str(enum_field->name, "_"))
26473 continue;
26474
26475 auto entry = field_prev_uses.maybe_get(enum_field->value);
26476 if (!entry) {
26477 ir_add_error(ira, &instruction->base,
26478 buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name),
26479 buf_ptr(enum_field->name)));
26480 }
26481 }
26482 } else if (!instruction->have_else_prong) {
26483 if (switch_type->data.enumeration.non_exhaustive) {
26438 ir_add_error(ira, &instruction->base,26484 ir_add_error(ira, &instruction->base,
26439 buf_sprintf("switch on an extern enum must have an else prong"));26485 buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong"));
26440 }26486 }
26441 for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {26487 for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
26442 TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];26488 TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];