Commit 2962be8135

Tadeo Kondrak <me@tadeo.ca>
2020-09-16 11:29:38
stage1: fix @Type(.Union) not resolving its tag type
Fixes https://github.com/ziglang/zig/issues/6339
1 parent 281fc10
Changed files (2)
src
test
stage1
behavior
src/analyze.cpp
@@ -3155,30 +3155,29 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
         tag_type->data.enumeration.fields_by_name.init(field_count);
         tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
     } else if (enum_type_node != nullptr) {
-        ZigType *enum_type = analyze_type_expr(g, scope, enum_type_node);
-        if (type_is_invalid(enum_type)) {
+        tag_type = analyze_type_expr(g, scope, enum_type_node);
+    } else {
+        if (decl_node->type == NodeTypeContainerDecl) {
+            tag_type = nullptr;
+        } else {
+            tag_type = union_type->data.unionation.tag_type;
+        }
+    }
+    if (tag_type != nullptr) {
+        if (type_is_invalid(tag_type)) {
             union_type->data.unionation.resolve_status = ResolveStatusInvalid;
             return ErrorSemanticAnalyzeFail;
         }
-        if (enum_type->id != ZigTypeIdEnum) {
+        if (tag_type->id != ZigTypeIdEnum) {
             union_type->data.unionation.resolve_status = ResolveStatusInvalid;
-            add_node_error(g, enum_type_node,
-                buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
+            add_node_error(g, enum_type_node != nullptr ? enum_type_node : decl_node,
+                buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&tag_type->name)));
             return ErrorSemanticAnalyzeFail;
         }
-        if ((err = type_resolve(g, enum_type, ResolveStatusAlignmentKnown))) {
+        if ((err = type_resolve(g, tag_type, ResolveStatusAlignmentKnown))) {
             assert(g->errors.length != 0);
             return err;
         }
-        tag_type = enum_type;
-    } else {
-        if (decl_node->type == NodeTypeContainerDecl) {
-            tag_type = nullptr;
-        } else {
-            tag_type = union_type->data.unionation.tag_type;
-        }
-    }
-    if (tag_type != nullptr) {
         covered_enum_fields = heap::c_allocator.allocate<bool>(tag_type->data.enumeration.src_field_count);
     }
     union_type->data.unionation.tag_type = tag_type;
test/stage1/behavior/type.zig
@@ -374,3 +374,45 @@ test "Type.Union" {
     tagged = .{ .unsigned = 1 };
     testing.expectEqual(Tag.unsigned, tagged);
 }
+
+test "Type.Union from Type.Enum" {
+    const Tag = @Type(.{
+        .Enum = .{
+            .layout = .Auto,
+            .tag_type = u0,
+            .fields = &[_]TypeInfo.EnumField{
+                .{ .name = "working_as_expected", .value = 0 },
+            },
+            .decls = &[_]TypeInfo.Declaration{},
+            .is_exhaustive = true,
+        },
+    });
+    const T = @Type(.{
+        .Union = .{
+            .layout = .Auto,
+            .tag_type = Tag,
+            .fields = &[_]TypeInfo.UnionField{
+                .{ .name = "working_as_expected", .field_type = u32 },
+            },
+            .decls = &[_]TypeInfo.Declaration{},
+        },
+    });
+    _ = T;
+    _ = @typeInfo(T).Union;
+}
+
+test "Type.Union from regular enum" {
+    const E = enum { working_as_expected = 0 };
+    const T = @Type(.{
+        .Union = .{
+            .layout = .Auto,
+            .tag_type = E,
+            .fields = &[_]TypeInfo.UnionField{
+                .{ .name = "working_as_expected", .field_type = u32 },
+            },
+            .decls = &[_]TypeInfo.Declaration{},
+        },
+    });
+    _ = T;
+    _ = @typeInfo(T).Union;
+}