authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-09-14 16:43:49+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-14 16:43:49+03:00
logd073836894df8b9fb56f24f577a51dd09a85a932
tree920723ea7cbe577934f0fb9670332f40dc7fd94a
parentc49435f76b07cbf3fdd6a10303a1a0ee4290e59a
parentacdf1f0bde9a07cae2fbe33739f5f4aee7989f7b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6172 from tadeokondrak/@Type(.Union)

Implement @Type for Union

11 files changed, 437 insertions(+), 155 deletions(-)

lib/std/builtin.zig-1
......@@ -317,7 +317,6 @@ pub const TypeInfo = union(enum) {
317317 /// therefore must be kept in sync with the compiler implementation.
318318 pub const UnionField = struct {
319319 name: []const u8,
320 enum_field: ?EnumField,
321320 field_type: type,
322321 };
323322
lib/std/fmt.zig+1-1
......@@ -399,7 +399,7 @@ pub fn formatType(
399399 try writer.writeAll(@tagName(@as(UnionTagType, value)));
400400 try writer.writeAll(" = ");
401401 inline for (info.fields) |u_field| {
402 if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
402 if (value == @field(UnionTagType, u_field.name)) {
403403 try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1);
404404 }
405405 }
lib/std/hash/auto_hash.zig+2-3
......@@ -139,9 +139,8 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
139139 const tag = meta.activeTag(key);
140140 const s = hash(hasher, tag, strat);
141141 inline for (info.fields) |field| {
142 const enum_field = field.enum_field.?;
143 if (enum_field.value == @enumToInt(tag)) {
144 hash(hasher, @field(key, enum_field.name), strat);
142 if (@field(tag_type, field.name) == tag) {
143 hash(hasher, @field(key, field.name), strat);
145144 // TODO use a labelled break when it does not crash the compiler. cf #2908
146145 // break :blk;
147146 return;
lib/std/io/serialization.zig+2-2
......@@ -156,7 +156,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing,
156156 const tag = try self.deserializeInt(TagInt);
157157
158158 inline for (info.fields) |field_info| {
159 if (field_info.enum_field.?.value == tag) {
159 if (@enumToInt(@field(TagType, field_info.name)) == tag) {
160160 const name = field_info.name;
161161 const FieldType = field_info.field_type;
162162 ptr.* = @unionInit(C, name, undefined);
......@@ -320,7 +320,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co
320320 // value, but @field requires a comptime value. Our alternative
321321 // is to check each field for a match
322322 inline for (info.fields) |field_info| {
323 if (field_info.enum_field.?.value == @enumToInt(active_tag)) {
323 if (@field(TagType, field_info.name) == active_tag) {
324324 const name = field_info.name;
325325 const FieldType = field_info.field_type;
326326 try self.serialize(@field(value, name));
lib/std/json.zig+2-2
......@@ -1613,7 +1613,7 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {
16131613 .Union => |unionInfo| {
16141614 if (unionInfo.tag_type) |UnionTagType| {
16151615 inline for (unionInfo.fields) |u_field| {
1616 if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
1616 if (value == @field(UnionTagType, u_field.name)) {
16171617 parseFree(u_field.field_type, @field(value, u_field.name), options);
16181618 break;
16191619 }
......@@ -2458,7 +2458,7 @@ pub fn stringify(
24582458 const info = @typeInfo(T).Union;
24592459 if (info.tag_type) |UnionTagType| {
24602460 inline for (info.fields) |u_field| {
2461 if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
2461 if (value == @field(UnionTagType, u_field.name)) {
24622462 return try stringify(@field(value, u_field.name), options, out_stream);
24632463 }
24642464 }
lib/std/meta.zig+7-5
......@@ -465,10 +465,13 @@ pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type {
465465 testing.expect(trait.is(.Union)(U));
466466
467467 const info = @typeInfo(U).Union;
468 const tag_info = @typeInfo(@TagType(U)).Enum;
468469
469470 inline for (info.fields) |field_info| {
470 if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type;
471 if (comptime mem.eql(u8, field_info.name, @tagName(tag)))
472 return field_info.field_type;
471473 }
474
472475 unreachable;
473476}
474477
......@@ -504,15 +507,14 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool {
504507 }
505508 },
506509 .Union => |info| {
507 if (info.tag_type) |_| {
510 if (info.tag_type) |Tag| {
508511 const tag_a = activeTag(a);
509512 const tag_b = activeTag(b);
510513 if (tag_a != tag_b) return false;
511514
512515 inline for (info.fields) |field_info| {
513 const enum_field = field_info.enum_field.?;
514 if (enum_field.value == @enumToInt(tag_a)) {
515 return eql(@field(a, enum_field.name), @field(b, enum_field.name));
516 if (@field(Tag, field_info.name) == tag_a) {
517 return eql(@field(a, field_info.name), @field(b, field_info.name));
516518 }
517519 }
518520 return false;
src/analyze.cpp+147-116
......@@ -2373,7 +2373,10 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) {
23732373 if (field->gen_index == UINT32_MAX)
23742374 continue;
23752375
2376 AstNode *align_expr = field->decl_node->data.struct_field.align_expr;
2376 AstNode *align_expr = nullptr;
2377 if (union_type->data.unionation.decl_node->type == NodeTypeContainerDecl) {
2378 align_expr = field->decl_node->data.struct_field.align_expr;
2379 }
23772380 if (align_expr != nullptr) {
23782381 if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr,
23792382 &field->align))
......@@ -2469,9 +2472,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
24692472
24702473 AstNode *decl_node = union_type->data.unionation.decl_node;
24712474
2472
2473 assert(decl_node->type == NodeTypeContainerDecl);
2474
24752475 uint32_t field_count = union_type->data.unionation.src_field_count;
24762476 TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member;
24772477
......@@ -2604,16 +2604,16 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
26042604 if (decl_node->type == NodeTypeContainerDecl) {
26052605 assert(!enum_type->data.enumeration.fields);
26062606 field_count = (uint32_t)decl_node->data.container_decl.fields.length;
2607 if (field_count == 0) {
2608 add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
2609
2610 enum_type->data.enumeration.src_field_count = field_count;
2611 enum_type->data.enumeration.fields = nullptr;
2612 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2613 return ErrorSemanticAnalyzeFail;
2614 }
26152607 } else {
2616 field_count = enum_type->data.enumeration.src_field_count;
2608 field_count = enum_type->data.enumeration.src_field_count + enum_type->data.enumeration.non_exhaustive;
2609 }
2610
2611 if (field_count == 0) {
2612 add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
2613 enum_type->data.enumeration.src_field_count = field_count;
2614 enum_type->data.enumeration.fields = nullptr;
2615 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2616 return ErrorSemanticAnalyzeFail;
26172617 }
26182618
26192619 Scope *scope = &enum_type->data.enumeration.decls_scope->base;
......@@ -3056,7 +3056,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
30563056 return ErrorNone;
30573057
30583058 AstNode *decl_node = union_type->data.unionation.decl_node;
3059 assert(decl_node->type == NodeTypeContainerDecl);
30603059
30613060 if (union_type->data.unionation.resolve_loop_flag_zero_bits) {
30623061 if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) {
......@@ -3070,30 +3069,51 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
30703069
30713070 union_type->data.unionation.resolve_loop_flag_zero_bits = true;
30723071
3073 assert(union_type->data.unionation.fields == nullptr);
3074 uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
3072 uint32_t field_count;
3073 if (decl_node->type == NodeTypeContainerDecl) {
3074 assert(union_type->data.unionation.fields == nullptr);
3075 field_count = (uint32_t)decl_node->data.container_decl.fields.length;
3076 union_type->data.unionation.src_field_count = field_count;
3077 union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count);
3078 union_type->data.unionation.fields_by_name.init(field_count);
3079 } else {
3080 field_count = union_type->data.unionation.src_field_count;
3081 assert(field_count == 0 || union_type->data.unionation.fields != nullptr);
3082 }
3083
30753084 if (field_count == 0) {
30763085 add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields"));
30773086 union_type->data.unionation.src_field_count = field_count;
30783087 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
30793088 return ErrorSemanticAnalyzeFail;
30803089 }
3081 union_type->data.unionation.src_field_count = field_count;
3082 union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count);
3083 union_type->data.unionation.fields_by_name.init(field_count);
30843090
30853091 Scope *scope = &union_type->data.unionation.decls_scope->base;
30863092
30873093 HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
30883094
3089 AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
3090 union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum ||
3091 enum_type_node != nullptr;
3092 bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
3093 bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
3095 bool is_auto_enum; // union(enum) or union(enum(expr))
3096 bool is_explicit_enum; // union(expr)
3097 AstNode *enum_type_node; // expr in union(enum(expr)) or union(expr)
3098 if (decl_node->type == NodeTypeContainerDecl) {
3099 is_auto_enum = decl_node->data.container_decl.auto_enum;
3100 is_explicit_enum = decl_node->data.container_decl.init_arg_expr != nullptr;
3101 enum_type_node = decl_node->data.container_decl.init_arg_expr;
3102 } else {
3103 is_auto_enum = false;
3104 is_explicit_enum = union_type->data.unionation.tag_type != nullptr;
3105 enum_type_node = nullptr;
3106 }
3107 union_type->data.unionation.have_explicit_tag_type = is_auto_enum || is_explicit_enum;
3108
3109 bool is_auto_layout = union_type->data.unionation.layout == ContainerLayoutAuto;
3110 bool want_safety = (field_count >= 2)
3111 && (is_auto_layout || is_explicit_enum)
3112 && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
30943113 ZigType *tag_type;
3095 bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
3114 bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety);
30963115 bool *covered_enum_fields;
3116 bool *is_zero_bits = heap::c_allocator.allocate<bool>(field_count);
30973117 ZigLLVMDIEnumerator **di_enumerators;
30983118 if (create_enum_type) {
30993119 occupied_tag_values.init(field_count);
......@@ -3151,71 +3171,81 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
31513171 return err;
31523172 }
31533173 tag_type = enum_type;
3154 covered_enum_fields = heap::c_allocator.allocate<bool>(enum_type->data.enumeration.src_field_count);
31553174 } else {
3156 tag_type = nullptr;
3175 if (decl_node->type == NodeTypeContainerDecl) {
3176 tag_type = nullptr;
3177 } else {
3178 tag_type = union_type->data.unionation.tag_type;
3179 }
3180 }
3181 if (tag_type != nullptr) {
3182 covered_enum_fields = heap::c_allocator.allocate<bool>(tag_type->data.enumeration.src_field_count);
31573183 }
31583184 union_type->data.unionation.tag_type = tag_type;
31593185
3160 uint32_t gen_field_index = 0;
31613186 for (uint32_t i = 0; i < field_count; i += 1) {
3162 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
3163 Buf *field_name = field_node->data.struct_field.name;
31643187 TypeUnionField *union_field = &union_type->data.unionation.fields[i];
3165 union_field->name = field_node->data.struct_field.name;
3166 union_field->decl_node = field_node;
3167 union_field->gen_index = UINT32_MAX;
3168
3169 auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
3170 if (field_entry != nullptr) {
3171 ErrorMsg *msg = add_node_error(g, field_node,
3172 buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
3173 add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
3174 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
3175 return ErrorSemanticAnalyzeFail;
3176 }
3188 if (decl_node->type == NodeTypeContainerDecl) {
3189 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
3190 union_field->name = field_node->data.struct_field.name;
3191 union_field->decl_node = field_node;
3192 union_field->gen_index = UINT32_MAX;
3193 is_zero_bits[i] = false;
31773194
3178 bool field_is_zero_bits;
3179 if (field_node->data.struct_field.type == nullptr) {
3180 if (decl_node->data.container_decl.auto_enum ||
3181 decl_node->data.container_decl.init_arg_expr != nullptr)
3182 {
3183 union_field->type_entry = g->builtin_types.entry_void;
3184 field_is_zero_bits = true;
3185 } else {
3186 add_node_error(g, field_node, buf_sprintf("union field missing type"));
3195 auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
3196 if (field_entry != nullptr) {
3197 ErrorMsg *msg = add_node_error(g, union_field->decl_node,
3198 buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
3199 add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
31873200 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
31883201 return ErrorSemanticAnalyzeFail;
31893202 }
3190 } else {
3191 ZigValue *field_type_val = analyze_const_value(g, scope,
3192 field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef);
3193 if (type_is_invalid(field_type_val->type)) {
3194 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
3195 return ErrorSemanticAnalyzeFail;
3203
3204 if (field_node->data.struct_field.type == nullptr) {
3205 if (is_auto_enum || is_explicit_enum) {
3206 union_field->type_entry = g->builtin_types.entry_void;
3207 is_zero_bits[i] = true;
3208 } else {
3209 add_node_error(g, field_node, buf_sprintf("union field missing type"));
3210 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
3211 return ErrorSemanticAnalyzeFail;
3212 }
3213 } else {
3214 ZigValue *field_type_val = analyze_const_value(g, scope,
3215 field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef);
3216 if (type_is_invalid(field_type_val->type)) {
3217 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
3218 return ErrorSemanticAnalyzeFail;
3219 }
3220 assert(field_type_val->special != ConstValSpecialRuntime);
3221 union_field->type_val = field_type_val;
31963222 }
3197 assert(field_type_val->special != ConstValSpecialRuntime);
3198 union_field->type_val = field_type_val;
3199 if (union_type->data.unionation.resolve_status == ResolveStatusInvalid)
3200 return ErrorSemanticAnalyzeFail;
32013223
3224 if (field_node->data.struct_field.value != nullptr && !is_auto_enum) {
3225 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
3226 buf_create_from_str("untagged union field assignment"));
3227 add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here"));
3228 }
3229 }
3230
3231 if (union_field->type_val != nullptr) {
32023232 bool field_is_opaque_type;
3203 if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) {
3233 if ((err = type_val_resolve_is_opaque_type(g, union_field->type_val, &field_is_opaque_type))) {
32043234 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
32053235 return ErrorSemanticAnalyzeFail;
32063236 }
32073237 if (field_is_opaque_type) {
3208 add_node_error(g, field_node,
3238 add_node_error(g, union_field->decl_node,
32093239 buf_create_from_str(
32103240 "opaque types have unknown size and therefore cannot be directly embedded in unions"));
32113241 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
32123242 return ErrorSemanticAnalyzeFail;
32133243 }
32143244
3215 switch (type_val_resolve_requires_comptime(g, field_type_val)) {
3245 switch (type_val_resolve_requires_comptime(g, union_field->type_val)) {
32163246 case ReqCompTimeInvalid:
32173247 if (g->trace_err != nullptr) {
3218 g->trace_err = add_error_note(g, g->trace_err, field_node,
3248 g->trace_err = add_error_note(g, g->trace_err, union_field->decl_node,
32193249 buf_create_from_str("while checking this field"));
32203250 }
32213251 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
......@@ -3227,29 +3257,25 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
32273257 break;
32283258 }
32293259
3230 if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) {
3260 if ((err = type_val_resolve_zero_bits(g, union_field->type_val, union_type, nullptr, &is_zero_bits[i]))) {
32313261 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
32323262 return ErrorSemanticAnalyzeFail;
32333263 }
32343264 }
32353265
3236 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
3237 ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
3238 buf_create_from_str("untagged union field assignment"));
3239 add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here"));
3240 }
3241
32423266 if (create_enum_type) {
3243 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
3267 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i);
32443268 union_field->enum_field = &tag_type->data.enumeration.fields[i];
3245 union_field->enum_field->name = field_name;
3269 union_field->enum_field->name = union_field->name;
32463270 union_field->enum_field->decl_index = i;
3247 union_field->enum_field->decl_node = field_node;
3271 union_field->enum_field->decl_node = union_field->decl_node;
32483272
32493273 auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field);
32503274 assert(prev_entry == nullptr); // caught by union de-duplicator above
32513275
3252 AstNode *tag_value = field_node->data.struct_field.value;
3276 AstNode *tag_value = decl_node->type == NodeTypeContainerDecl
3277 ? union_field->decl_node->data.struct_field.value : nullptr;
3278
32533279 // In this first pass we resolve explicit tag values.
32543280 // In a second pass we will fill in the unspecified ones.
32553281 if (tag_value != nullptr) {
......@@ -3277,11 +3303,11 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
32773303 return ErrorSemanticAnalyzeFail;
32783304 }
32793305 }
3280 } else if (enum_type_node != nullptr) {
3281 union_field->enum_field = find_enum_type_field(tag_type, field_name);
3306 } else if (tag_type != nullptr) {
3307 union_field->enum_field = find_enum_type_field(tag_type, union_field->name);
32823308 if (union_field->enum_field == nullptr) {
3283 ErrorMsg *msg = add_node_error(g, field_node,
3284 buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
3309 ErrorMsg *msg = add_node_error(g, union_field->decl_node,
3310 buf_sprintf("enum field not found: '%s'", buf_ptr(union_field->name)));
32853311 add_error_note(g, msg, tag_type->data.enumeration.decl_node,
32863312 buf_sprintf("enum declared here"));
32873313 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
......@@ -3290,21 +3316,23 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
32903316 covered_enum_fields[union_field->enum_field->decl_index] = true;
32913317 } else {
32923318 union_field->enum_field = heap::c_allocator.create<TypeEnumField>();
3293 union_field->enum_field->name = field_name;
3319 union_field->enum_field->name = union_field->name;
32943320 union_field->enum_field->decl_index = i;
32953321 bigint_init_unsigned(&union_field->enum_field->value, i);
32963322 }
32973323 assert(union_field->enum_field != nullptr);
3324 }
32983325
3299 if (field_is_zero_bits)
3300 continue;
3301
3302 union_field->gen_index = gen_field_index;
3303 gen_field_index += 1;
3326 uint32_t gen_field_index = 0;
3327 for (uint32_t i = 0; i < field_count; i += 1) {
3328 TypeUnionField *union_field = &union_type->data.unionation.fields[i];
3329 if (!is_zero_bits[i]) {
3330 union_field->gen_index = gen_field_index;
3331 gen_field_index += 1;
3332 }
33043333 }
33053334
3306 bool src_have_tag = decl_node->data.container_decl.auto_enum ||
3307 decl_node->data.container_decl.init_arg_expr != nullptr;
3335 bool src_have_tag = is_auto_enum || is_explicit_enum;
33083336
33093337 if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) {
33103338 const char *qual_str;
......@@ -3318,8 +3346,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
33183346 qual_str = "extern";
33193347 break;
33203348 }
3321 AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ?
3322 decl_node->data.container_decl.init_arg_expr : decl_node;
3349 AstNode *source_node = enum_type_node != nullptr ? enum_type_node : decl_node;
33233350 add_node_error(g, source_node,
33243351 buf_sprintf("%s union does not support enum tag type", qual_str));
33253352 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
......@@ -3327,43 +3354,47 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
33273354 }
33283355
33293356 if (create_enum_type) {
3330 // Now iterate again and populate the unspecified tag values
3331 uint32_t next_maybe_unoccupied_index = 0;
3357 if (decl_node->type == NodeTypeContainerDecl) {
3358 // Now iterate again and populate the unspecified tag values
3359 uint32_t next_maybe_unoccupied_index = 0;
33323360
3333 for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
3334 AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
3335 TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
3336 AstNode *tag_value = field_node->data.struct_field.value;
3361 for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
3362 AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
3363 TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
3364 AstNode *tag_value = field_node->data.struct_field.value;
33373365
3338 if (tag_value == nullptr) {
3339 if (occupied_tag_values.size() == 0) {
3340 bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
3341 next_maybe_unoccupied_index += 1;
3342 } else {
3343 BigInt proposed_value;
3344 for (;;) {
3345 bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
3366 if (tag_value == nullptr) {
3367 if (occupied_tag_values.size() == 0) {
3368 bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
33463369 next_maybe_unoccupied_index += 1;
3347 auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
3348 if (entry != nullptr) {
3349 continue;
3370 } else {
3371 BigInt proposed_value;
3372 for (;;) {
3373 bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
3374 next_maybe_unoccupied_index += 1;
3375 auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
3376 if (entry != nullptr) {
3377 continue;
3378 }
3379 break;
33503380 }
3351 break;
3381 bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
33523382 }
3353 bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
33543383 }
33553384 }
33563385 }
3357 } else if (enum_type_node != nullptr) {
3386 } else if (tag_type != nullptr) {
33583387 for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
33593388 TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
33603389 if (!covered_enum_fields[i]) {
3361 AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
3362 AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
33633390 ErrorMsg *msg = add_node_error(g, decl_node,
33643391 buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
3365 add_error_note(g, msg, field_node,
3366 buf_sprintf("declared here"));
3392 if (decl_node->type == NodeTypeContainerDecl) {
3393 AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
3394 AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
3395 add_error_note(g, msg, field_node,
3396 buf_sprintf("declared here"));
3397 }
33673398 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
33683399 }
33693400 }
......@@ -8351,7 +8382,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
83518382 ZigLLVMDIFile *di_file;
83528383 ZigLLVMDIScope *di_scope;
83538384 unsigned line;
8354 if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) {
8385 if (decl_node != nullptr) {
83558386 Scope *scope = &struct_type->data.structure.decls_scope->base;
83568387 ZigType *import = get_scope_import(scope);
83578388 di_file = import->data.structure.root_struct->di_file;
......@@ -8714,7 +8745,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
87148745
87158746 uint64_t store_size_in_bits = union_field->type_entry->size_in_bits;
87168747 uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align;
8717 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
8748 AstNode *field_node = union_field->decl_node;
87188749 union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
87198750 ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name),
87208751 import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
src/ir.cpp+85-20
......@@ -25424,8 +25424,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2542425424
2542525425 init_const_slice(ira->codegen, fields[2], union_field_array, 0, union_field_count, false);
2542625426
25427 ZigType *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr);
25428
2542925427 for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) {
2543025428 TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index];
2543125429 ZigValue *union_field_val = &union_field_array->data.x_array.data.s_none.elements[union_field_index];
......@@ -25433,20 +25431,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2543325431 union_field_val->special = ConstValSpecialStatic;
2543425432 union_field_val->type = type_info_union_field_type;
2543525433
25436 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3);
25434 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2);
2543725435 inner_fields[1]->special = ConstValSpecialStatic;
25438 inner_fields[1]->type = get_optional_type(ira->codegen, type_info_enum_field_type);
25439
25440 if (fields[1]->data.x_optional == nullptr) {
25441 inner_fields[1]->data.x_optional = nullptr;
25442 } else {
25443 inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create<ZigValue>();
25444 make_enum_field_val(ira, inner_fields[1]->data.x_optional, union_field->enum_field, type_info_enum_field_type);
25445 }
25446
25447 inner_fields[2]->special = ConstValSpecialStatic;
25448 inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
25449 inner_fields[2]->data.x_type = union_field->type_entry;
25436 inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
25437 inner_fields[1]->data.x_type = union_field->type_entry;
2545025438
2545125439 ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee;
2545225440 init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true);
......@@ -26102,7 +26090,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2610226090 entry->data.structure.layout = layout;
2610326091 entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone;
2610426092 entry->data.structure.created_by_at_type = true;
26105 entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name);
26093 entry->data.structure.decls_scope = create_decls_scope(
26094 ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name);
2610626095
2610726096 assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
2610826097 assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0);
......@@ -26226,13 +26215,89 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2622626215 return ira->codegen->invalid_inst_gen->value->type;
2622726216 field->value = *field_int_value;
2622826217 }
26218 return entry;
26219 }
26220 case ZigTypeIdUnion: {
26221 assert(payload->special == ConstValSpecialStatic);
26222 assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr));
2622926223
26224 ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0);
26225 if (layout_value == nullptr)
26226 return ira->codegen->invalid_inst_gen->value->type;
26227 assert(layout_value->special == ConstValSpecialStatic);
26228 assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
26229 ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);
26230
26231 ZigType *tag_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "tag_type", 1);
26232 if (tag_type != nullptr && type_is_invalid(tag_type)) {
26233 return ira->codegen->invalid_inst_gen->value->type;
26234 }
26235 if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) {
26236 ir_add_error(ira, source_instr, buf_sprintf(
26237 "expected enum type, found '%s'", type_id_name(tag_type->id)));
26238 return ira->codegen->invalid_inst_gen->value->type;
26239 }
26240
26241 ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 2);
26242 if (fields_value == nullptr)
26243 return ira->codegen->invalid_inst_gen->value->type;
26244
26245 assert(fields_value->special == ConstValSpecialStatic);
26246 assert(is_slice(fields_value->type));
26247 ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index];
26248 ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
26249 size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint);
26250
26251 ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 3);
26252 if (decls_value == nullptr)
26253 return ira->codegen->invalid_inst_gen->value->type;
26254
26255 assert(decls_value->special == ConstValSpecialStatic);
26256 assert(is_slice(decls_value->type));
26257 ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
26258 size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
26259 if (decls_len != 0) {
26260 ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Union.decls must be empty for @Type"));
26261 return ira->codegen->invalid_inst_gen->value->type;
26262 }
26263
26264 ZigType *entry = new_type_table_entry(ZigTypeIdUnion);
26265 buf_init_from_buf(&entry->name,
26266 get_anon_type_name(ira->codegen, ira->old_irb.exec, "union", source_instr->scope, source_instr->source_node, &entry->name));
26267 entry->data.unionation.decl_node = source_instr->source_node;
26268 entry->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(fields_len);
26269 entry->data.unionation.fields_by_name.init(fields_len);
26270 entry->data.unionation.decls_scope = create_decls_scope(
26271 ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name);
26272 entry->data.unionation.tag_type = tag_type;
26273 entry->data.unionation.src_field_count = fields_len;
26274 entry->data.unionation.layout = layout;
26275
26276 assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
26277 assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0);
26278 ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val;
26279 assert(fields_arr->special == ConstValSpecialStatic);
26280 assert(fields_arr->data.x_array.special == ConstArraySpecialNone);
26281 for (size_t i = 0; i < fields_len; i++) {
26282 ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i];
26283 assert(field_value->type == ir_type_info_get_type(ira, "UnionField", nullptr));
26284 TypeUnionField *field = &entry->data.unionation.fields[i];
26285 field->name = buf_alloc();
26286 if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name)))
26287 return ira->codegen->invalid_inst_gen->value->type;
26288 if (entry->data.unionation.fields_by_name.put_unique(field->name, field) != nullptr) {
26289 ir_add_error(ira, source_instr, buf_sprintf("duplicate union field '%s'", buf_ptr(field->name)));
26290 return ira->codegen->invalid_inst_gen->value->type;
26291 }
26292 field->decl_node = source_instr->source_node;
26293 ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1);
26294 if (type_value == nullptr)
26295 return ira->codegen->invalid_inst_gen->value->type;
26296 field->type_val = type_value;
26297 field->type_entry = type_value->data.x_type;
26298 }
2623026299 return entry;
2623126300 }
26232 case ZigTypeIdUnion:
26233 ir_add_error(ira, source_instr, buf_sprintf(
26234 "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
26235 return ira->codegen->invalid_inst_gen->value->type;
2623626301 case ZigTypeIdFn:
2623726302 case ZigTypeIdBoundFn:
2623826303 ir_add_error(ira, source_instr, buf_sprintf(
test/compile_errors.zig+130-1
......@@ -10,6 +10,135 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1010 "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
1111 });
1212
13 cases.add("@Type for union with opaque field",
14 \\const TypeInfo = @import("builtin").TypeInfo;
15 \\const Untagged = @Type(.{
16 \\ .Union = .{
17 \\ .layout = .Auto,
18 \\ .tag_type = null,
19 \\ .fields = &[_]TypeInfo.UnionField{
20 \\ .{ .name = "foo", .field_type = @Type(.Opaque) },
21 \\ },
22 \\ .decls = &[_]TypeInfo.Declaration{},
23 \\ },
24 \\});
25 \\export fn entry() void {
26 \\ _ = Untagged{};
27 \\}
28 , &[_][]const u8{
29 "tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
30 "tmp.zig:13:17: note: referenced here",
31 });
32
33 cases.add("@Type for union with zero fields",
34 \\const TypeInfo = @import("builtin").TypeInfo;
35 \\const Untagged = @Type(.{
36 \\ .Union = .{
37 \\ .layout = .Auto,
38 \\ .tag_type = null,
39 \\ .fields = &[_]TypeInfo.UnionField{},
40 \\ .decls = &[_]TypeInfo.Declaration{},
41 \\ },
42 \\});
43 \\export fn entry() void {
44 \\ _ = Untagged{};
45 \\}
46 , &[_][]const u8{
47 "tmp.zig:2:25: error: unions must have 1 or more fields",
48 "tmp.zig:11:17: note: referenced here",
49 });
50
51 cases.add("@Type for exhaustive enum with zero fields",
52 \\const TypeInfo = @import("builtin").TypeInfo;
53 \\const Tag = @Type(.{
54 \\ .Enum = .{
55 \\ .layout = .Auto,
56 \\ .tag_type = u1,
57 \\ .fields = &[_]TypeInfo.EnumField{},
58 \\ .decls = &[_]TypeInfo.Declaration{},
59 \\ .is_exhaustive = true,
60 \\ },
61 \\});
62 \\export fn entry() void {
63 \\ _ = @intToEnum(Tag, 0);
64 \\}
65 , &[_][]const u8{
66 "tmp.zig:2:20: error: enums must have 1 or more fields",
67 "tmp.zig:12:9: note: referenced here",
68 });
69
70 cases.add("@Type for tagged union with extra union field",
71 \\const TypeInfo = @import("builtin").TypeInfo;
72 \\const Tag = @Type(.{
73 \\ .Enum = .{
74 \\ .layout = .Auto,
75 \\ .tag_type = u1,
76 \\ .fields = &[_]TypeInfo.EnumField{
77 \\ .{ .name = "signed", .value = 0 },
78 \\ .{ .name = "unsigned", .value = 1 },
79 \\ },
80 \\ .decls = &[_]TypeInfo.Declaration{},
81 \\ .is_exhaustive = true,
82 \\ },
83 \\});
84 \\const Tagged = @Type(.{
85 \\ .Union = .{
86 \\ .layout = .Auto,
87 \\ .tag_type = Tag,
88 \\ .fields = &[_]TypeInfo.UnionField{
89 \\ .{ .name = "signed", .field_type = i32 },
90 \\ .{ .name = "unsigned", .field_type = u32 },
91 \\ .{ .name = "arst", .field_type = f32 },
92 \\ },
93 \\ .decls = &[_]TypeInfo.Declaration{},
94 \\ },
95 \\});
96 \\export fn entry() void {
97 \\ var tagged = Tagged{ .signed = -1 };
98 \\ tagged = .{ .unsigned = 1 };
99 \\}
100 , &[_][]const u8{
101 "tmp.zig:14:23: error: enum field not found: 'arst'",
102 "tmp.zig:2:20: note: enum declared here",
103 "tmp.zig:27:24: note: referenced here",
104 });
105
106 cases.add("@Type for tagged union with extra enum field",
107 \\const TypeInfo = @import("builtin").TypeInfo;
108 \\const Tag = @Type(.{
109 \\ .Enum = .{
110 \\ .layout = .Auto,
111 \\ .tag_type = u2,
112 \\ .fields = &[_]TypeInfo.EnumField{
113 \\ .{ .name = "signed", .value = 0 },
114 \\ .{ .name = "unsigned", .value = 1 },
115 \\ .{ .name = "arst", .field_type = 2 },
116 \\ },
117 \\ .decls = &[_]TypeInfo.Declaration{},
118 \\ .is_exhaustive = true,
119 \\ },
120 \\});
121 \\const Tagged = @Type(.{
122 \\ .Union = .{
123 \\ .layout = .Auto,
124 \\ .tag_type = Tag,
125 \\ .fields = &[_]TypeInfo.UnionField{
126 \\ .{ .name = "signed", .field_type = i32 },
127 \\ .{ .name = "unsigned", .field_type = u32 },
128 \\ },
129 \\ .decls = &[_]TypeInfo.Declaration{},
130 \\ },
131 \\});
132 \\export fn entry() void {
133 \\ var tagged = Tagged{ .signed = -1 };
134 \\ tagged = .{ .unsigned = 1 };
135 \\}
136 , &[_][]const u8{
137 "tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'",
138 "tmp.zig:18:21: note: referenced here",
139 "tmp.zig:27:18: note: referenced here",
140 });
141
13142 cases.add("@Type with undefined",
14143 \\comptime {
15144 \\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } });
......@@ -7419,7 +7548,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
74197548 });
74207549
74217550 cases.add( // fixed bug #2032
7422 "compile diagnostic string for top level decl type",
7551 "compile diagnostic string for top level decl type",
74237552 \\export fn entry() void {
74247553 \\ var foo: u32 = @This(){};
74257554 \\}
test/stage1/behavior/type.zig+61
......@@ -313,3 +313,64 @@ test "Type.Enum" {
313313 testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b));
314314 testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6)));
315315}
316
317test "Type.Union" {
318 const Untagged = @Type(.{
319 .Union = .{
320 .layout = .Auto,
321 .tag_type = null,
322 .fields = &[_]TypeInfo.UnionField{
323 .{ .name = "int", .field_type = i32 },
324 .{ .name = "float", .field_type = f32 },
325 },
326 .decls = &[_]TypeInfo.Declaration{},
327 },
328 });
329 var untagged = Untagged{ .int = 1 };
330 untagged.float = 2.0;
331 untagged.int = 3;
332 testing.expectEqual(@as(i32, 3), untagged.int);
333
334 const PackedUntagged = @Type(.{
335 .Union = .{
336 .layout = .Packed,
337 .tag_type = null,
338 .fields = &[_]TypeInfo.UnionField{
339 .{ .name = "signed", .field_type = i32 },
340 .{ .name = "unsigned", .field_type = u32 },
341 },
342 .decls = &[_]TypeInfo.Declaration{},
343 },
344 });
345 var packed_untagged = PackedUntagged{ .signed = -1 };
346 testing.expectEqual(@as(i32, -1), packed_untagged.signed);
347 testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned);
348
349 const Tag = @Type(.{
350 .Enum = .{
351 .layout = .Auto,
352 .tag_type = u1,
353 .fields = &[_]TypeInfo.EnumField{
354 .{ .name = "signed", .value = 0 },
355 .{ .name = "unsigned", .value = 1 },
356 },
357 .decls = &[_]TypeInfo.Declaration{},
358 .is_exhaustive = true,
359 },
360 });
361 const Tagged = @Type(.{
362 .Union = .{
363 .layout = .Auto,
364 .tag_type = Tag,
365 .fields = &[_]TypeInfo.UnionField{
366 .{ .name = "signed", .field_type = i32 },
367 .{ .name = "unsigned", .field_type = u32 },
368 },
369 .decls = &[_]TypeInfo.Declaration{},
370 },
371 });
372 var tagged = Tagged{ .signed = -1 };
373 testing.expectEqual(Tag.signed, tagged);
374 tagged = .{ .unsigned = 1 };
375 testing.expectEqual(Tag.unsigned, tagged);
376}
test/stage1/behavior/type_info.zig-4
......@@ -198,8 +198,6 @@ fn testUnion() void {
198198 expect(typeinfo_info.Union.layout == .Auto);
199199 expect(typeinfo_info.Union.tag_type.? == TypeId);
200200 expect(typeinfo_info.Union.fields.len == 25);
201 expect(typeinfo_info.Union.fields[4].enum_field != null);
202 expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
203201 expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
204202 expect(typeinfo_info.Union.decls.len == 21);
205203
......@@ -213,7 +211,6 @@ fn testUnion() void {
213211 expect(notag_union_info.Union.tag_type == null);
214212 expect(notag_union_info.Union.layout == .Auto);
215213 expect(notag_union_info.Union.fields.len == 2);
216 expect(notag_union_info.Union.fields[0].enum_field == null);
217214 expect(notag_union_info.Union.fields[1].field_type == u32);
218215
219216 const TestExternUnion = extern union {
......@@ -223,7 +220,6 @@ fn testUnion() void {
223220 const extern_union_info = @typeInfo(TestExternUnion);
224221 expect(extern_union_info.Union.layout == .Extern);
225222 expect(extern_union_info.Union.tag_type == null);
226 expect(extern_union_info.Union.fields[0].enum_field == null);
227223 expect(extern_union_info.Union.fields[0].field_type == *c_void);
228224}
229225