Commit d84569895c

Vexu <git@vexu.eu>
2020-01-16 08:04:11
turn panics into compile errors, require at least 1 field in non-exhaustive enum
1 parent 02e5cb1
doc/langref.html.in
@@ -2903,11 +2903,8 @@ test "switch using enum literals" {
       {#link|@intToEnum#} on a non-exhaustive enum cannot fail.
       </p>
       <p>
-      A switch on a non-exhaustive enum can include a '_' prong with the following properties:
-      <ul>
-        <li>makes it a compile error if all the known tag names are not handled by the switch</li>
-        <li>allows omitting {#syntax#}else{#endsyntax#}</li>
-      </ul>
+      A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong
+      with the difference being that it makes it a compile error if all the known tag names are not handled by the switch.
       </p>
       {#code_begin|test#}
 const std = @import("std");
src/analyze.cpp
@@ -2560,7 +2560,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
 
     assert(!enum_type->data.enumeration.fields);
     uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
-    if (field_count == 0) {
+    if (field_count == 0 || (field_count == 1 &&
+        buf_eql_str(decl_node->data.container_decl.fields.at(0)->data.struct_field.name, "_"))) {
         add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
 
         enum_type->data.enumeration.src_field_count = field_count;
src/codegen.cpp
@@ -5065,8 +5065,11 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
 {
     ZigType *enum_type = instruction->target->value->type;
     assert(enum_type->id == ZigTypeIdEnum);
-    if (enum_type->data.enumeration.non_exhaustive)
-        zig_panic("TODO @tagName on non-exhaustive enum");
+    if (enum_type->data.enumeration.non_exhaustive) {
+        add_node_error(g, instruction->base.source_node,
+            buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
+        codegen_report_errors_and_exit(g);
+    }
 
     LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
 
src/ir.cpp
@@ -8183,13 +8183,6 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
                     return irb->codegen->invalid_instruction;
                 }
                 else_prong = prong_node;
-                if (underscore_prong) {
-                    ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
-                            buf_sprintf("else and '_' prong in switch expression"));
-                    add_error_note(irb->codegen, msg, underscore_prong,
-                            buf_sprintf("'_' prong is here"));
-                    return irb->codegen->invalid_instruction;
-                }
             } else if (prong_item_count == 1 && 
                     prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol &&
                     buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) {
@@ -8201,16 +8194,20 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
                     return irb->codegen->invalid_instruction;
                 }
                 underscore_prong = prong_node;
-                if (else_prong) {
-                    ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
-                            buf_sprintf("else and '_' prong in switch expression"));
-                    add_error_note(irb->codegen, msg, else_prong,
-                            buf_sprintf("else prong is here"));
-                    return irb->codegen->invalid_instruction;
-                }
             } else {
                 continue;
             }
+           if (underscore_prong && else_prong) {
+                ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+                        buf_sprintf("else and '_' prong in switch expression"));
+                if (underscore_prong == prong_node)
+                    add_error_note(irb->codegen, msg, else_prong,
+                            buf_sprintf("else prong is here"));
+                else
+                    add_error_note(irb->codegen, msg, underscore_prong,
+                            buf_sprintf("'_' prong is here"));
+                return irb->codegen->invalid_instruction;
+            }
             ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
 
             IrBasicBlock *prev_block = irb->current_basic_block;
@@ -22357,8 +22354,11 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
     if (instr_is_comptime(target)) {
         if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
             return ira->codegen->invalid_instruction;
-        if (target->value->type->data.enumeration.non_exhaustive)
-            zig_panic("TODO @tagName on non-exhaustive enum");
+        if (target->value->type->data.enumeration.non_exhaustive) {
+            add_node_error(ira->codegen, instruction->base.source_node,
+                buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
+            return ira->codegen->invalid_instruction;
+        }
         TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
         ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
         IrInstruction *result = ir_const(ira, &instruction->base, nullptr);