Commit 6c8f01dcde

Vexu <git@vexu.eu>
2020-01-16 21:48:01
correct field count
1 parent 6450736
Changed files (3)
src
test
src/analyze.cpp
@@ -2569,16 +2569,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
         return ErrorSemanticAnalyzeFail;
     }
 
-    enum_type->data.enumeration.src_field_count = field_count;
-    enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-    enum_type->data.enumeration.fields_by_name.init(field_count);
-    enum_type->data.enumeration.non_exhaustive = false;
-
     Scope *scope = &enum_type->data.enumeration.decls_scope->base;
 
-    HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
-    occupied_tag_values.init(field_count);
-
     ZigType *tag_int_type;
     if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
         tag_int_type = get_c_int_type(g, CIntTypeInt);
@@ -2620,6 +2612,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
         }
     }
 
+    enum_type->data.enumeration.non_exhaustive = false;
     enum_type->data.enumeration.tag_int_type = tag_int_type;
     enum_type->size_in_bits = tag_int_type->size_in_bits;
     enum_type->abi_size = tag_int_type->abi_size;
@@ -2628,6 +2621,31 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
     BigInt bi_one;
     bigint_init_unsigned(&bi_one, 1);
 
+    AstNode *last_field_node = decl_node->data.container_decl.fields.at(field_count - 1);
+    if (buf_eql_str(last_field_node->data.struct_field.name, "_")) {
+        field_count -= 1;
+        if (field_count > 1 && log2_u64(field_count) == enum_type->size_in_bits) {
+            add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum specifies every value"));
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+        }
+        if (decl_node->data.container_decl.init_arg_expr == nullptr) {
+            add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum must specify size"));
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+        }
+        if (last_field_node->data.struct_field.value != nullptr) {
+            add_node_error(g, last_field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum"));
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+        }
+        enum_type->data.enumeration.non_exhaustive = true;
+    }
+
+    enum_type->data.enumeration.src_field_count = field_count;
+    enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
+    enum_type->data.enumeration.fields_by_name.init(field_count);
+
+    HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
+    occupied_tag_values.init(field_count);
+
     TypeEnumField *last_enum_field = nullptr;
 
     for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
@@ -2649,27 +2667,9 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
                     buf_sprintf("consider 'union(enum)' here"));
         }
 
-        AstNode *tag_value = field_node->data.struct_field.value;
-
         if (buf_eql_str(type_enum_field->name, "_")) {
-            if (decl_node->data.container_decl.init_arg_expr == nullptr) {
-                add_node_error(g, field_node, buf_sprintf("non-exhaustive enum must specify size"));
-                enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
-            }
-            if (field_count > 1 && log2_u64(field_count - 1) == enum_type->size_in_bits) {
-                add_node_error(g, field_node, buf_sprintf("non-exhaustive enum specifies every value"));
-                enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
-            }
-            if (field_i != field_count - 1) {
-                add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
-                enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
-            }
-            if (tag_value != nullptr) {
-                add_node_error(g, field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum"));
-                enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
-            }
-            enum_type->data.enumeration.non_exhaustive = true;
-            continue;
+            add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
+            enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
         }
 
         auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);
@@ -2681,6 +2681,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
             continue;
         }
 
+        AstNode *tag_value = field_node->data.struct_field.value;
+
         if (tag_value != nullptr) {
             // A user-specified value is available
             ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type,
@@ -3293,7 +3295,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
     } else if (enum_type_node != nullptr) {
         for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
             TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
-            if (!covered_enum_fields[i] && !buf_eql_str(enum_field->name, "_")) {
+            if (!covered_enum_fields[i]) {
                 AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
                 AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
                 ErrorMsg *msg = add_node_error(g, decl_node,
test/stage1/behavior/enum.zig
@@ -41,6 +41,7 @@ test "non-exhaustive enum" {
                 .b => {},
                 else => {},
             }
+            expect(@typeInfo(E).Enum.fields.len == 2);
             expect(@enumToInt(e) == 1);
             e = @intToEnum(E, 12);
             expect(@enumToInt(e) == 12);
test/compile_errors.zig
@@ -13,9 +13,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    _,
         \\    b,
         \\};
+        \\const C = enum(u1) {
+        \\    a,
+        \\    b,
+        \\    _,
+        \\};
         \\pub export fn entry() void {
         \\    _ = A;
         \\    _ = B;
+        \\    _ = C;
         \\}
     , &[_][]const u8{
         "tmp.zig:4:5: error: non-exhaustive enum must specify size",