mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Implement @Type for Union
This removes TypeInfo.UnionField.enum_field, which is redundant with TypeInfo.Union.tag_type.
This commit is contained in:
parent
d7268cbb24
commit
ff2ed966bb
@ -317,7 +317,6 @@ pub const TypeInfo = union(enum) {
|
|||||||
/// therefore must be kept in sync with the compiler implementation.
|
/// therefore must be kept in sync with the compiler implementation.
|
||||||
pub const UnionField = struct {
|
pub const UnionField = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
enum_field: ?EnumField,
|
|
||||||
field_type: type,
|
field_type: type,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
120
src/analyze.cpp
120
src/analyze.cpp
@ -2372,7 +2372,10 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) {
|
|||||||
if (field->gen_index == UINT32_MAX)
|
if (field->gen_index == UINT32_MAX)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
AstNode *align_expr = field->decl_node->data.struct_field.align_expr;
|
AstNode *align_expr = nullptr;
|
||||||
|
if (union_type->data.unionation.decl_node->type == NodeTypeContainerDecl) {
|
||||||
|
align_expr = field->decl_node->data.struct_field.align_expr;
|
||||||
|
}
|
||||||
if (align_expr != nullptr) {
|
if (align_expr != nullptr) {
|
||||||
if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr,
|
if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr,
|
||||||
&field->align))
|
&field->align))
|
||||||
@ -2468,9 +2471,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
|
|||||||
|
|
||||||
AstNode *decl_node = union_type->data.unionation.decl_node;
|
AstNode *decl_node = union_type->data.unionation.decl_node;
|
||||||
|
|
||||||
|
|
||||||
assert(decl_node->type == NodeTypeContainerDecl);
|
|
||||||
|
|
||||||
uint32_t field_count = union_type->data.unionation.src_field_count;
|
uint32_t field_count = union_type->data.unionation.src_field_count;
|
||||||
TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member;
|
TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member;
|
||||||
|
|
||||||
@ -3055,7 +3055,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
return ErrorNone;
|
return ErrorNone;
|
||||||
|
|
||||||
AstNode *decl_node = union_type->data.unionation.decl_node;
|
AstNode *decl_node = union_type->data.unionation.decl_node;
|
||||||
assert(decl_node->type == NodeTypeContainerDecl);
|
|
||||||
|
|
||||||
if (union_type->data.unionation.resolve_loop_flag_zero_bits) {
|
if (union_type->data.unionation.resolve_loop_flag_zero_bits) {
|
||||||
if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) {
|
if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) {
|
||||||
@ -3069,8 +3068,10 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
|
|
||||||
union_type->data.unionation.resolve_loop_flag_zero_bits = true;
|
union_type->data.unionation.resolve_loop_flag_zero_bits = true;
|
||||||
|
|
||||||
|
uint32_t field_count;
|
||||||
|
if (decl_node->type == NodeTypeContainerDecl) {
|
||||||
assert(union_type->data.unionation.fields == nullptr);
|
assert(union_type->data.unionation.fields == nullptr);
|
||||||
uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
|
field_count = (uint32_t)decl_node->data.container_decl.fields.length;
|
||||||
if (field_count == 0) {
|
if (field_count == 0) {
|
||||||
add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields"));
|
add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields"));
|
||||||
union_type->data.unionation.src_field_count = field_count;
|
union_type->data.unionation.src_field_count = field_count;
|
||||||
@ -3080,19 +3081,37 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
union_type->data.unionation.src_field_count = field_count;
|
union_type->data.unionation.src_field_count = field_count;
|
||||||
union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count);
|
union_type->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(field_count);
|
||||||
union_type->data.unionation.fields_by_name.init(field_count);
|
union_type->data.unionation.fields_by_name.init(field_count);
|
||||||
|
} else {
|
||||||
|
assert(union_type->data.unionation.fields != nullptr);
|
||||||
|
field_count = union_type->data.unionation.src_field_count;
|
||||||
|
}
|
||||||
|
|
||||||
Scope *scope = &union_type->data.unionation.decls_scope->base;
|
Scope *scope = &union_type->data.unionation.decls_scope->base;
|
||||||
|
|
||||||
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
||||||
|
|
||||||
AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
|
bool is_auto_enum; // union(enum) or union(enum(expr))
|
||||||
union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum ||
|
bool is_explicit_enum; // union(expr)
|
||||||
enum_type_node != nullptr;
|
AstNode *enum_type_node; // expr in union(enum(expr)) or union(expr)
|
||||||
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
|
if (decl_node->type == NodeTypeContainerDecl) {
|
||||||
bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
|
is_auto_enum = decl_node->data.container_decl.auto_enum;
|
||||||
|
is_explicit_enum = decl_node->data.container_decl.init_arg_expr != nullptr;
|
||||||
|
enum_type_node = decl_node->data.container_decl.init_arg_expr;
|
||||||
|
} else {
|
||||||
|
is_auto_enum = false;
|
||||||
|
is_explicit_enum = union_type->data.unionation.tag_type != nullptr;
|
||||||
|
enum_type_node = nullptr;
|
||||||
|
}
|
||||||
|
union_type->data.unionation.have_explicit_tag_type = is_auto_enum || is_explicit_enum;
|
||||||
|
|
||||||
|
bool is_auto_layout = union_type->data.unionation.layout == ContainerLayoutAuto;
|
||||||
|
bool want_safety = (field_count >= 2)
|
||||||
|
&& (is_auto_layout || is_explicit_enum)
|
||||||
|
&& !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
|
||||||
ZigType *tag_type;
|
ZigType *tag_type;
|
||||||
bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
|
bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety);
|
||||||
bool *covered_enum_fields;
|
bool *covered_enum_fields;
|
||||||
|
bool *is_zero_bits = heap::c_allocator.allocate<bool>(field_count);
|
||||||
ZigLLVMDIEnumerator **di_enumerators;
|
ZigLLVMDIEnumerator **di_enumerators;
|
||||||
if (create_enum_type) {
|
if (create_enum_type) {
|
||||||
occupied_tag_values.init(field_count);
|
occupied_tag_values.init(field_count);
|
||||||
@ -3150,37 +3169,40 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
tag_type = enum_type;
|
tag_type = enum_type;
|
||||||
covered_enum_fields = heap::c_allocator.allocate<bool>(enum_type->data.enumeration.src_field_count);
|
|
||||||
} else {
|
} else {
|
||||||
|
if (decl_node->type == NodeTypeContainerDecl) {
|
||||||
tag_type = nullptr;
|
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;
|
union_type->data.unionation.tag_type = tag_type;
|
||||||
|
|
||||||
uint32_t gen_field_index = 0;
|
|
||||||
for (uint32_t i = 0; i < field_count; i += 1) {
|
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||||
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
|
|
||||||
Buf *field_name = field_node->data.struct_field.name;
|
|
||||||
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
|
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
|
||||||
|
if (decl_node->type == NodeTypeContainerDecl) {
|
||||||
|
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
|
||||||
union_field->name = field_node->data.struct_field.name;
|
union_field->name = field_node->data.struct_field.name;
|
||||||
union_field->decl_node = field_node;
|
union_field->decl_node = field_node;
|
||||||
union_field->gen_index = UINT32_MAX;
|
union_field->gen_index = UINT32_MAX;
|
||||||
|
is_zero_bits[i] = false;
|
||||||
|
|
||||||
auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
|
auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field);
|
||||||
if (field_entry != nullptr) {
|
if (field_entry != nullptr) {
|
||||||
ErrorMsg *msg = add_node_error(g, field_node,
|
ErrorMsg *msg = add_node_error(g, union_field->decl_node,
|
||||||
buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
|
buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name)));
|
||||||
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
|
add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here"));
|
||||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||||
return ErrorSemanticAnalyzeFail;
|
return ErrorSemanticAnalyzeFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool field_is_zero_bits;
|
|
||||||
if (field_node->data.struct_field.type == nullptr) {
|
if (field_node->data.struct_field.type == nullptr) {
|
||||||
if (decl_node->data.container_decl.auto_enum ||
|
if (is_auto_enum || is_explicit_enum) {
|
||||||
decl_node->data.container_decl.init_arg_expr != nullptr)
|
|
||||||
{
|
|
||||||
union_field->type_entry = g->builtin_types.entry_void;
|
union_field->type_entry = g->builtin_types.entry_void;
|
||||||
field_is_zero_bits = true;
|
is_zero_bits[i] = true;
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, field_node, buf_sprintf("union field missing type"));
|
add_node_error(g, field_node, buf_sprintf("union field missing type"));
|
||||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||||
@ -3226,29 +3248,32 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) {
|
if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &is_zero_bits[i]))) {
|
||||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||||
return ErrorSemanticAnalyzeFail;
|
return ErrorSemanticAnalyzeFail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
|
if (field_node->data.struct_field.value != nullptr && !is_auto_enum) {
|
||||||
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
|
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
|
||||||
buf_create_from_str("untagged union field assignment"));
|
buf_create_from_str("untagged union field assignment"));
|
||||||
add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here"));
|
add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (create_enum_type) {
|
if (create_enum_type) {
|
||||||
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
|
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i);
|
||||||
union_field->enum_field = &tag_type->data.enumeration.fields[i];
|
union_field->enum_field = &tag_type->data.enumeration.fields[i];
|
||||||
union_field->enum_field->name = field_name;
|
union_field->enum_field->name = union_field->name;
|
||||||
union_field->enum_field->decl_index = i;
|
union_field->enum_field->decl_index = i;
|
||||||
union_field->enum_field->decl_node = field_node;
|
union_field->enum_field->decl_node = union_field->decl_node;
|
||||||
|
|
||||||
auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field);
|
auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field);
|
||||||
assert(prev_entry == nullptr); // caught by union de-duplicator above
|
assert(prev_entry == nullptr); // caught by union de-duplicator above
|
||||||
|
|
||||||
AstNode *tag_value = field_node->data.struct_field.value;
|
AstNode *tag_value = decl_node->type == NodeTypeContainerDecl
|
||||||
|
? union_field->decl_node->data.struct_field.value : nullptr;
|
||||||
|
|
||||||
// In this first pass we resolve explicit tag values.
|
// In this first pass we resolve explicit tag values.
|
||||||
// In a second pass we will fill in the unspecified ones.
|
// In a second pass we will fill in the unspecified ones.
|
||||||
if (tag_value != nullptr) {
|
if (tag_value != nullptr) {
|
||||||
@ -3276,11 +3301,11 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
return ErrorSemanticAnalyzeFail;
|
return ErrorSemanticAnalyzeFail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (enum_type_node != nullptr) {
|
} else if (tag_type != nullptr) {
|
||||||
union_field->enum_field = find_enum_type_field(tag_type, field_name);
|
union_field->enum_field = find_enum_type_field(tag_type, union_field->name);
|
||||||
if (union_field->enum_field == nullptr) {
|
if (union_field->enum_field == nullptr) {
|
||||||
ErrorMsg *msg = add_node_error(g, field_node,
|
ErrorMsg *msg = add_node_error(g, union_field->decl_node,
|
||||||
buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
|
buf_sprintf("enum field not found: '%s'", buf_ptr(union_field->name)));
|
||||||
add_error_note(g, msg, tag_type->data.enumeration.decl_node,
|
add_error_note(g, msg, tag_type->data.enumeration.decl_node,
|
||||||
buf_sprintf("enum declared here"));
|
buf_sprintf("enum declared here"));
|
||||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||||
@ -3289,21 +3314,23 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
covered_enum_fields[union_field->enum_field->decl_index] = true;
|
covered_enum_fields[union_field->enum_field->decl_index] = true;
|
||||||
} else {
|
} else {
|
||||||
union_field->enum_field = heap::c_allocator.create<TypeEnumField>();
|
union_field->enum_field = heap::c_allocator.create<TypeEnumField>();
|
||||||
union_field->enum_field->name = field_name;
|
union_field->enum_field->name = union_field->name;
|
||||||
union_field->enum_field->decl_index = i;
|
union_field->enum_field->decl_index = i;
|
||||||
bigint_init_unsigned(&union_field->enum_field->value, i);
|
bigint_init_unsigned(&union_field->enum_field->value, i);
|
||||||
}
|
}
|
||||||
assert(union_field->enum_field != nullptr);
|
assert(union_field->enum_field != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (field_is_zero_bits)
|
uint32_t gen_field_index = 0;
|
||||||
continue;
|
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||||
|
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
|
||||||
|
if (!is_zero_bits[i]) {
|
||||||
union_field->gen_index = gen_field_index;
|
union_field->gen_index = gen_field_index;
|
||||||
gen_field_index += 1;
|
gen_field_index += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool src_have_tag = decl_node->data.container_decl.auto_enum ||
|
bool src_have_tag = is_auto_enum || is_explicit_enum;
|
||||||
decl_node->data.container_decl.init_arg_expr != nullptr;
|
|
||||||
|
|
||||||
if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) {
|
if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) {
|
||||||
const char *qual_str;
|
const char *qual_str;
|
||||||
@ -3317,8 +3344,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
qual_str = "extern";
|
qual_str = "extern";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ?
|
AstNode *source_node = enum_type_node != nullptr ? enum_type_node : decl_node;
|
||||||
decl_node->data.container_decl.init_arg_expr : decl_node;
|
|
||||||
add_node_error(g, source_node,
|
add_node_error(g, source_node,
|
||||||
buf_sprintf("%s union does not support enum tag type", qual_str));
|
buf_sprintf("%s union does not support enum tag type", qual_str));
|
||||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||||
@ -3326,6 +3352,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (create_enum_type) {
|
if (create_enum_type) {
|
||||||
|
if (decl_node->type == NodeTypeContainerDecl) {
|
||||||
// Now iterate again and populate the unspecified tag values
|
// Now iterate again and populate the unspecified tag values
|
||||||
uint32_t next_maybe_unoccupied_index = 0;
|
uint32_t next_maybe_unoccupied_index = 0;
|
||||||
|
|
||||||
@ -3353,16 +3380,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (enum_type_node != nullptr) {
|
}
|
||||||
|
} else if (tag_type != nullptr) {
|
||||||
for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
|
for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
|
||||||
TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
|
TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
|
||||||
if (!covered_enum_fields[i]) {
|
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,
|
ErrorMsg *msg = add_node_error(g, decl_node,
|
||||||
buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
|
buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
|
||||||
|
if (decl_node->type == NodeTypeContainerDecl) {
|
||||||
|
AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
|
||||||
|
AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
|
||||||
add_error_note(g, msg, field_node,
|
add_error_note(g, msg, field_node,
|
||||||
buf_sprintf("declared here"));
|
buf_sprintf("declared here"));
|
||||||
|
}
|
||||||
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8350,7 +8380,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
|
|||||||
ZigLLVMDIFile *di_file;
|
ZigLLVMDIFile *di_file;
|
||||||
ZigLLVMDIScope *di_scope;
|
ZigLLVMDIScope *di_scope;
|
||||||
unsigned line;
|
unsigned line;
|
||||||
if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) {
|
if (decl_node != nullptr) {
|
||||||
Scope *scope = &struct_type->data.structure.decls_scope->base;
|
Scope *scope = &struct_type->data.structure.decls_scope->base;
|
||||||
ZigType *import = get_scope_import(scope);
|
ZigType *import = get_scope_import(scope);
|
||||||
di_file = import->data.structure.root_struct->di_file;
|
di_file = import->data.structure.root_struct->di_file;
|
||||||
@ -8713,7 +8743,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
|
|||||||
|
|
||||||
uint64_t store_size_in_bits = union_field->type_entry->size_in_bits;
|
uint64_t store_size_in_bits = union_field->type_entry->size_in_bits;
|
||||||
uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align;
|
uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align;
|
||||||
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
|
AstNode *field_node = union_field->decl_node;
|
||||||
union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||||
ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name),
|
ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name),
|
||||||
import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
|
import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1),
|
||||||
|
|||||||
98
src/ir.cpp
98
src/ir.cpp
@ -25424,8 +25424,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
|
|||||||
|
|
||||||
init_const_slice(ira->codegen, fields[2], union_field_array, 0, union_field_count, false);
|
init_const_slice(ira->codegen, fields[2], union_field_array, 0, union_field_count, false);
|
||||||
|
|
||||||
ZigType *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr);
|
|
||||||
|
|
||||||
for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) {
|
for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) {
|
||||||
TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index];
|
TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index];
|
||||||
ZigValue *union_field_val = &union_field_array->data.x_array.data.s_none.elements[union_field_index];
|
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
|
|||||||
union_field_val->special = ConstValSpecialStatic;
|
union_field_val->special = ConstValSpecialStatic;
|
||||||
union_field_val->type = type_info_union_field_type;
|
union_field_val->type = type_info_union_field_type;
|
||||||
|
|
||||||
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3);
|
ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2);
|
||||||
inner_fields[1]->special = ConstValSpecialStatic;
|
inner_fields[1]->special = ConstValSpecialStatic;
|
||||||
inner_fields[1]->type = get_optional_type(ira->codegen, type_info_enum_field_type);
|
inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
|
||||||
|
inner_fields[1]->data.x_type = union_field->type_entry;
|
||||||
if (fields[1]->data.x_optional == nullptr) {
|
|
||||||
inner_fields[1]->data.x_optional = nullptr;
|
|
||||||
} else {
|
|
||||||
inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create<ZigValue>();
|
|
||||||
make_enum_field_val(ira, inner_fields[1]->data.x_optional, union_field->enum_field, type_info_enum_field_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
inner_fields[2]->special = ConstValSpecialStatic;
|
|
||||||
inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
|
|
||||||
inner_fields[2]->data.x_type = union_field->type_entry;
|
|
||||||
|
|
||||||
ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee;
|
ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee;
|
||||||
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true);
|
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
|
|||||||
entry->data.structure.layout = layout;
|
entry->data.structure.layout = layout;
|
||||||
entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone;
|
entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone;
|
||||||
entry->data.structure.created_by_at_type = true;
|
entry->data.structure.created_by_at_type = true;
|
||||||
entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name);
|
entry->data.structure.decls_scope = create_decls_scope(
|
||||||
|
ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name);
|
||||||
|
|
||||||
assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
|
assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
|
||||||
assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0);
|
assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0);
|
||||||
@ -26226,13 +26215,84 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
|
|||||||
return ira->codegen->invalid_inst_gen->value->type;
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
field->value = *field_int_value;
|
field->value = *field_int_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
case ZigTypeIdUnion:
|
case ZigTypeIdUnion: {
|
||||||
|
assert(payload->special == ConstValSpecialStatic);
|
||||||
|
assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr));
|
||||||
|
|
||||||
|
ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0);
|
||||||
|
assert(layout_value->special == ConstValSpecialStatic);
|
||||||
|
assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
|
||||||
|
ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);
|
||||||
|
|
||||||
|
ZigType *tag_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "tag_type", 1);
|
||||||
|
if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) {
|
||||||
ir_add_error(ira, source_instr, buf_sprintf(
|
ir_add_error(ira, source_instr, buf_sprintf(
|
||||||
"TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId)));
|
"union tag type must be an enum, not %s", type_id_name(tag_type->id)));
|
||||||
return ira->codegen->invalid_inst_gen->value->type;
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 2);
|
||||||
|
if (fields_value == nullptr)
|
||||||
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
|
|
||||||
|
assert(fields_value->special == ConstValSpecialStatic);
|
||||||
|
assert(is_slice(fields_value->type));
|
||||||
|
ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index];
|
||||||
|
ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
|
||||||
|
size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint);
|
||||||
|
|
||||||
|
ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 3);
|
||||||
|
if (decls_value == nullptr)
|
||||||
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
|
|
||||||
|
assert(decls_value->special == ConstValSpecialStatic);
|
||||||
|
assert(is_slice(decls_value->type));
|
||||||
|
ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
|
||||||
|
size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
|
||||||
|
if (decls_len != 0) {
|
||||||
|
ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Union.decls must be empty for @Type"));
|
||||||
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZigType *entry = new_type_table_entry(ZigTypeIdUnion);
|
||||||
|
buf_init_from_buf(&entry->name,
|
||||||
|
get_anon_type_name(ira->codegen, ira->old_irb.exec, "union", source_instr->scope, source_instr->source_node, &entry->name));
|
||||||
|
entry->data.unionation.decl_node = source_instr->source_node;
|
||||||
|
entry->data.unionation.fields = heap::c_allocator.allocate<TypeUnionField>(fields_len);
|
||||||
|
entry->data.unionation.fields_by_name.init(fields_len);
|
||||||
|
entry->data.unionation.decls_scope = create_decls_scope(
|
||||||
|
ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name);
|
||||||
|
entry->data.unionation.tag_type = tag_type;
|
||||||
|
entry->data.unionation.src_field_count = fields_len;
|
||||||
|
entry->data.unionation.layout = layout;
|
||||||
|
|
||||||
|
assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
|
||||||
|
assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0);
|
||||||
|
ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val;
|
||||||
|
assert(fields_arr->special == ConstValSpecialStatic);
|
||||||
|
assert(fields_arr->data.x_array.special == ConstArraySpecialNone);
|
||||||
|
for (size_t i = 0; i < fields_len; i++) {
|
||||||
|
ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i];
|
||||||
|
assert(field_value->type == ir_type_info_get_type(ira, "UnionField", nullptr));
|
||||||
|
TypeUnionField *field = &entry->data.unionation.fields[i];
|
||||||
|
field->name = buf_alloc();
|
||||||
|
if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name)))
|
||||||
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
|
if (entry->data.unionation.fields_by_name.put_unique(field->name, field) != nullptr) {
|
||||||
|
ir_add_error(ira, source_instr, buf_sprintf("duplicate union field '%s'", buf_ptr(field->name)));
|
||||||
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
|
}
|
||||||
|
field->decl_node = source_instr->source_node;
|
||||||
|
ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1);
|
||||||
|
if (type_value == nullptr)
|
||||||
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
|
field->type_val = type_value;
|
||||||
|
field->type_entry = type_value->data.x_type;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
case ZigTypeIdFn:
|
case ZigTypeIdFn:
|
||||||
case ZigTypeIdBoundFn:
|
case ZigTypeIdBoundFn:
|
||||||
ir_add_error(ira, source_instr, buf_sprintf(
|
ir_add_error(ira, source_instr, buf_sprintf(
|
||||||
|
|||||||
@ -10,6 +10,78 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
"tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
|
"tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cases.add("@Type for tagged union with extra union field",
|
||||||
|
\\const TypeInfo = @import("builtin").TypeInfo;
|
||||||
|
\\const Tag = @Type(.{
|
||||||
|
\\ .Enum = .{
|
||||||
|
\\ .layout = .Auto,
|
||||||
|
\\ .tag_type = u1,
|
||||||
|
\\ .fields = &[_]TypeInfo.EnumField{
|
||||||
|
\\ .{ .name = "signed", .value = 0 },
|
||||||
|
\\ .{ .name = "unsigned", .value = 1 },
|
||||||
|
\\ },
|
||||||
|
\\ .decls = &[_]TypeInfo.Declaration{},
|
||||||
|
\\ .is_exhaustive = true,
|
||||||
|
\\ },
|
||||||
|
\\});
|
||||||
|
\\const Tagged = @Type(.{
|
||||||
|
\\ .Union = .{
|
||||||
|
\\ .layout = .Auto,
|
||||||
|
\\ .tag_type = Tag,
|
||||||
|
\\ .fields = &[_]TypeInfo.UnionField{
|
||||||
|
\\ .{ .name = "signed", .field_type = i32 },
|
||||||
|
\\ .{ .name = "unsigned", .field_type = u32 },
|
||||||
|
\\ .{ .name = "arst", .field_type = f32 },
|
||||||
|
\\ },
|
||||||
|
\\ .decls = &[_]TypeInfo.Declaration{},
|
||||||
|
\\ },
|
||||||
|
\\});
|
||||||
|
\\export fn entry() void {
|
||||||
|
\\ var tagged = Tagged{ .signed = -1 };
|
||||||
|
\\ tagged = .{ .unsigned = 1 };
|
||||||
|
\\}
|
||||||
|
, &[_][]const u8{
|
||||||
|
"tmp.zig:14:23: error: enum field not found: 'arst'",
|
||||||
|
"tmp.zig:2:20: note: enum declared here",
|
||||||
|
"tmp.zig:27:24: note: referenced here",
|
||||||
|
});
|
||||||
|
|
||||||
|
cases.add("@Type for tagged union with extra enum field",
|
||||||
|
\\const TypeInfo = @import("builtin").TypeInfo;
|
||||||
|
\\const Tag = @Type(.{
|
||||||
|
\\ .Enum = .{
|
||||||
|
\\ .layout = .Auto,
|
||||||
|
\\ .tag_type = u2,
|
||||||
|
\\ .fields = &[_]TypeInfo.EnumField{
|
||||||
|
\\ .{ .name = "signed", .value = 0 },
|
||||||
|
\\ .{ .name = "unsigned", .value = 1 },
|
||||||
|
\\ .{ .name = "arst", .field_type = 2 },
|
||||||
|
\\ },
|
||||||
|
\\ .decls = &[_]TypeInfo.Declaration{},
|
||||||
|
\\ .is_exhaustive = true,
|
||||||
|
\\ },
|
||||||
|
\\});
|
||||||
|
\\const Tagged = @Type(.{
|
||||||
|
\\ .Union = .{
|
||||||
|
\\ .layout = .Auto,
|
||||||
|
\\ .tag_type = Tag,
|
||||||
|
\\ .fields = &[_]TypeInfo.UnionField{
|
||||||
|
\\ .{ .name = "signed", .field_type = i32 },
|
||||||
|
\\ .{ .name = "unsigned", .field_type = u32 },
|
||||||
|
\\ },
|
||||||
|
\\ .decls = &[_]TypeInfo.Declaration{},
|
||||||
|
\\ },
|
||||||
|
\\});
|
||||||
|
\\export fn entry() void {
|
||||||
|
\\ var tagged = Tagged{ .signed = -1 };
|
||||||
|
\\ tagged = .{ .unsigned = 1 };
|
||||||
|
\\}
|
||||||
|
, &[_][]const u8{
|
||||||
|
"tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'",
|
||||||
|
"tmp.zig:18:21: note: referenced here",
|
||||||
|
"tmp.zig:27:18: note: referenced here",
|
||||||
|
});
|
||||||
|
|
||||||
cases.add("@Type with undefined",
|
cases.add("@Type with undefined",
|
||||||
\\comptime {
|
\\comptime {
|
||||||
\\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } });
|
\\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } });
|
||||||
|
|||||||
@ -313,3 +313,64 @@ test "Type.Enum" {
|
|||||||
testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b));
|
testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b));
|
||||||
testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6)));
|
testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Type.Union" {
|
||||||
|
const Untagged = @Type(.{
|
||||||
|
.Union = .{
|
||||||
|
.layout = .Auto,
|
||||||
|
.tag_type = null,
|
||||||
|
.fields = &[_]TypeInfo.UnionField{
|
||||||
|
.{ .name = "int", .field_type = i32 },
|
||||||
|
.{ .name = "float", .field_type = f32 },
|
||||||
|
},
|
||||||
|
.decls = &[_]TypeInfo.Declaration{},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
var untagged = Untagged{ .int = 1 };
|
||||||
|
untagged.float = 2.0;
|
||||||
|
untagged.int = 3;
|
||||||
|
testing.expectEqual(@as(i32, 3), untagged.int);
|
||||||
|
|
||||||
|
const PackedUntagged = @Type(.{
|
||||||
|
.Union = .{
|
||||||
|
.layout = .Packed,
|
||||||
|
.tag_type = null,
|
||||||
|
.fields = &[_]TypeInfo.UnionField{
|
||||||
|
.{ .name = "signed", .field_type = i32 },
|
||||||
|
.{ .name = "unsigned", .field_type = u32 },
|
||||||
|
},
|
||||||
|
.decls = &[_]TypeInfo.Declaration{},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
var packed_untagged = PackedUntagged{ .signed = -1 };
|
||||||
|
testing.expectEqual(@as(i32, -1), packed_untagged.signed);
|
||||||
|
testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned);
|
||||||
|
|
||||||
|
const Tag = @Type(.{
|
||||||
|
.Enum = .{
|
||||||
|
.layout = .Auto,
|
||||||
|
.tag_type = u1,
|
||||||
|
.fields = &[_]TypeInfo.EnumField{
|
||||||
|
.{ .name = "signed", .value = 0 },
|
||||||
|
.{ .name = "unsigned", .value = 1 },
|
||||||
|
},
|
||||||
|
.decls = &[_]TypeInfo.Declaration{},
|
||||||
|
.is_exhaustive = true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const Tagged = @Type(.{
|
||||||
|
.Union = .{
|
||||||
|
.layout = .Auto,
|
||||||
|
.tag_type = Tag,
|
||||||
|
.fields = &[_]TypeInfo.UnionField{
|
||||||
|
.{ .name = "signed", .field_type = i32 },
|
||||||
|
.{ .name = "unsigned", .field_type = u32 },
|
||||||
|
},
|
||||||
|
.decls = &[_]TypeInfo.Declaration{},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
var tagged = Tagged{ .signed = -1 };
|
||||||
|
testing.expectEqual(Tag.signed, tagged);
|
||||||
|
tagged = .{ .unsigned = 1 };
|
||||||
|
testing.expectEqual(Tag.unsigned, tagged);
|
||||||
|
}
|
||||||
|
|||||||
@ -198,8 +198,6 @@ fn testUnion() void {
|
|||||||
expect(typeinfo_info.Union.layout == .Auto);
|
expect(typeinfo_info.Union.layout == .Auto);
|
||||||
expect(typeinfo_info.Union.tag_type.? == TypeId);
|
expect(typeinfo_info.Union.tag_type.? == TypeId);
|
||||||
expect(typeinfo_info.Union.fields.len == 25);
|
expect(typeinfo_info.Union.fields.len == 25);
|
||||||
expect(typeinfo_info.Union.fields[4].enum_field != null);
|
|
||||||
expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
|
|
||||||
expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
|
expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
|
||||||
expect(typeinfo_info.Union.decls.len == 21);
|
expect(typeinfo_info.Union.decls.len == 21);
|
||||||
|
|
||||||
@ -213,7 +211,6 @@ fn testUnion() void {
|
|||||||
expect(notag_union_info.Union.tag_type == null);
|
expect(notag_union_info.Union.tag_type == null);
|
||||||
expect(notag_union_info.Union.layout == .Auto);
|
expect(notag_union_info.Union.layout == .Auto);
|
||||||
expect(notag_union_info.Union.fields.len == 2);
|
expect(notag_union_info.Union.fields.len == 2);
|
||||||
expect(notag_union_info.Union.fields[0].enum_field == null);
|
|
||||||
expect(notag_union_info.Union.fields[1].field_type == u32);
|
expect(notag_union_info.Union.fields[1].field_type == u32);
|
||||||
|
|
||||||
const TestExternUnion = extern union {
|
const TestExternUnion = extern union {
|
||||||
@ -223,7 +220,6 @@ fn testUnion() void {
|
|||||||
const extern_union_info = @typeInfo(TestExternUnion);
|
const extern_union_info = @typeInfo(TestExternUnion);
|
||||||
expect(extern_union_info.Union.layout == .Extern);
|
expect(extern_union_info.Union.layout == .Extern);
|
||||||
expect(extern_union_info.Union.tag_type == null);
|
expect(extern_union_info.Union.tag_type == null);
|
||||||
expect(extern_union_info.Union.fields[0].enum_field == null);
|
|
||||||
expect(extern_union_info.Union.fields[0].field_type == *c_void);
|
expect(extern_union_info.Union.fields[0].field_type == *c_void);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user