Skip to content

Commit f4519c5

Browse files
committed
support self-referential struct through a slice of optional
by making optionals even more lazy closes #1805
1 parent c1fd7ed commit f4519c5

File tree

5 files changed

+210
-98
lines changed

5 files changed

+210
-98
lines changed

src/all_types.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ struct LazyValueSliceType {
329329
LazyValue base;
330330

331331
IrAnalyze *ira;
332-
ZigType *elem_type;
332+
IrInstruction *elem_type;
333333
IrInstruction *align_inst; // can be null
334334

335335
bool is_const;
@@ -1222,6 +1222,7 @@ struct ZigTypeStruct {
12221222

12231223
struct ZigTypeOptional {
12241224
ZigType *child_type;
1225+
ResolveStatus resolve_status;
12251226
};
12261227

12271228
struct ZigTypeErrorUnion {

src/analyze.cpp

Lines changed: 134 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
566566
}
567567

568568
entry->data.maybe.child_type = child_type;
569+
entry->data.maybe.resolve_status = ResolveStatusSizeKnown;
569570

570571
child_type->optional_parent = entry;
571572
return entry;
@@ -1055,9 +1056,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
10551056
zig_unreachable();
10561057
case LazyValueIdSliceType: {
10571058
LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy);
1058-
if (type_is_invalid(lazy_slice_type->elem_type))
1059-
return ReqCompTimeInvalid;
1060-
return type_requires_comptime(g, lazy_slice_type->elem_type);
1059+
return type_val_resolve_requires_comptime(g, &lazy_slice_type->elem_type->value);
10611060
}
10621061
case LazyValueIdPtrType: {
10631062
LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy);
@@ -1099,6 +1098,42 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue
10991098
zig_unreachable();
11001099
}
11011100

1101+
static Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val,
1102+
size_t *abi_size, size_t *size_in_bits)
1103+
{
1104+
Error err;
1105+
if (type_val->data.x_lazy->id == LazyValueIdOptType) {
1106+
if ((err = ir_resolve_lazy(g, source_node, type_val)))
1107+
return err;
1108+
}
1109+
if (type_val->special != ConstValSpecialLazy) {
1110+
assert(type_val->special == ConstValSpecialStatic);
1111+
ZigType *ty = type_val->data.x_type;
1112+
if ((err = type_resolve(g, ty, ResolveStatusSizeKnown)))
1113+
return err;
1114+
*abi_size = ty->abi_size;
1115+
*size_in_bits = ty->size_in_bits;
1116+
return ErrorNone;
1117+
}
1118+
switch (type_val->data.x_lazy->id) {
1119+
case LazyValueIdInvalid:
1120+
case LazyValueIdAlignOf:
1121+
zig_unreachable();
1122+
case LazyValueIdSliceType:
1123+
*abi_size = g->builtin_types.entry_usize->abi_size * 2;
1124+
*size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2;
1125+
return ErrorNone;
1126+
case LazyValueIdPtrType:
1127+
case LazyValueIdFnType:
1128+
*abi_size = g->builtin_types.entry_usize->abi_size;
1129+
*size_in_bits = g->builtin_types.entry_usize->size_in_bits;
1130+
return ErrorNone;
1131+
case LazyValueIdOptType:
1132+
zig_unreachable();
1133+
}
1134+
zig_unreachable();
1135+
}
1136+
11021137
Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align) {
11031138
Error err;
11041139
if (type_val->special != ConstValSpecialLazy) {
@@ -1767,6 +1802,17 @@ static size_t get_abi_size_bytes(size_t size_in_bits, size_t pointer_size_bytes)
17671802
return align_forward(store_size_bytes, abi_align);
17681803
}
17691804

1805+
ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field) {
1806+
Error err;
1807+
if (struct_field->type_entry == nullptr) {
1808+
if ((err = ir_resolve_lazy(g, struct_field->decl_node, struct_field->type_val))) {
1809+
return nullptr;
1810+
}
1811+
struct_field->type_entry = struct_field->type_val->data.x_type;
1812+
}
1813+
return struct_field->type_entry;
1814+
}
1815+
17701816
static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
17711817
assert(struct_type->id == ZigTypeIdStruct);
17721818

@@ -1801,40 +1847,6 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
18011847

18021848
uint32_t *host_int_bytes = packed ? allocate<uint32_t>(struct_type->data.structure.gen_field_count) : nullptr;
18031849

1804-
// Resolve types for fields and then resolve sizes of all the field types.
1805-
// This is done before the offset loop because the offset loop has to look ahead.
1806-
for (size_t i = 0; i < field_count; i += 1) {
1807-
AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
1808-
TypeStructField *field = &struct_type->data.structure.fields[i];
1809-
1810-
if ((err = ir_resolve_lazy(g, field_source_node, field->type_val))) {
1811-
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1812-
return err;
1813-
}
1814-
field->type_entry = field->type_val->data.x_type;
1815-
1816-
if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) {
1817-
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1818-
return err;
1819-
}
1820-
1821-
if (struct_type->data.structure.layout == ContainerLayoutExtern &&
1822-
!type_allowed_in_extern(g, field->type_entry))
1823-
{
1824-
add_node_error(g, field_source_node,
1825-
buf_sprintf("extern structs cannot contain fields of type '%s'",
1826-
buf_ptr(&field->type_entry->name)));
1827-
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1828-
return ErrorSemanticAnalyzeFail;
1829-
} else if (packed) {
1830-
if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field->type_entry, field_source_node))) {
1831-
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1832-
return err;
1833-
}
1834-
}
1835-
1836-
}
1837-
18381850
size_t packed_bits_offset = 0;
18391851
size_t next_offset = 0;
18401852
size_t first_packed_bits_offset_misalign = SIZE_MAX;
@@ -1847,13 +1859,25 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
18471859
TypeStructField *field = &struct_type->data.structure.fields[i];
18481860
if (field->gen_index == SIZE_MAX)
18491861
continue;
1850-
ZigType *field_type = field->type_entry;
1851-
assert(field_type != nullptr);
18521862

18531863
field->gen_index = gen_field_index;
18541864
field->offset = next_offset;
18551865

18561866
if (packed) {
1867+
ZigType *field_type = resolve_struct_field_type(g, field);
1868+
if (field_type == nullptr) {
1869+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1870+
return err;
1871+
}
1872+
if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) {
1873+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1874+
return err;
1875+
}
1876+
if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field->type_entry, field->decl_node))) {
1877+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1878+
return err;
1879+
}
1880+
18571881
size_t field_size_in_bits = type_size_bits(g, field_type);
18581882
size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;
18591883

@@ -1889,6 +1913,15 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
18891913
}
18901914
packed_bits_offset = next_packed_bits_offset;
18911915
} else {
1916+
size_t field_abi_size;
1917+
size_t field_size_in_bits;
1918+
if ((err = type_val_resolve_abi_size(g, field->decl_node, field->type_val,
1919+
&field_abi_size, &field_size_in_bits)))
1920+
{
1921+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1922+
return err;
1923+
}
1924+
18921925
gen_field_index += 1;
18931926
size_t next_src_field_index = i + 1;
18941927
for (; next_src_field_index < field_count; next_src_field_index += 1) {
@@ -1898,7 +1931,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
18981931
}
18991932
size_t next_align = (next_src_field_index == field_count) ?
19001933
abi_align : struct_type->data.structure.fields[next_src_field_index].align;
1901-
next_offset = next_field_offset(next_offset, abi_align, field_type->abi_size, next_align);
1934+
next_offset = next_field_offset(next_offset, abi_align, field_abi_size, next_align);
19021935
size_in_bits = next_offset * 8;
19031936
}
19041937
}
@@ -1917,6 +1950,36 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
19171950
struct_type->data.structure.resolve_loop_flag_other = false;
19181951
struct_type->data.structure.host_int_bytes = host_int_bytes;
19191952

1953+
1954+
// Resolve types for fields
1955+
if (!packed) {
1956+
for (size_t i = 0; i < field_count; i += 1) {
1957+
TypeStructField *field = &struct_type->data.structure.fields[i];
1958+
ZigType *field_type = resolve_struct_field_type(g, field);
1959+
if (field_type == nullptr) {
1960+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1961+
return err;
1962+
}
1963+
1964+
if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) {
1965+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1966+
return err;
1967+
}
1968+
1969+
if (struct_type->data.structure.layout == ContainerLayoutExtern &&
1970+
!type_allowed_in_extern(g, field_type))
1971+
{
1972+
add_node_error(g, field->decl_node,
1973+
buf_sprintf("extern structs cannot contain fields of type '%s'",
1974+
buf_ptr(&field_type->name)));
1975+
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
1976+
return ErrorSemanticAnalyzeFail;
1977+
}
1978+
1979+
}
1980+
}
1981+
1982+
19201983
return ErrorNone;
19211984
}
19221985

@@ -7669,8 +7732,11 @@ static void resolve_llvm_types_integer(CodeGen *g, ZigType *type) {
76697732
type->llvm_type = LLVMIntType(type->size_in_bits);
76707733
}
76717734

7672-
static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) {
7673-
if (type->llvm_di_type != nullptr) return;
7735+
static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
7736+
assert(type->id == ZigTypeIdOptional);
7737+
assert(type->data.maybe.resolve_status != ResolveStatusInvalid);
7738+
assert(type->data.maybe.resolve_status >= ResolveStatusSizeKnown);
7739+
if (type->data.maybe.resolve_status >= wanted_resolve_status) return;
76747740

76757741
LLVMTypeRef bool_llvm_type = get_llvm_type(g, g->builtin_types.entry_bool);
76767742
ZigLLVMDIType *bool_llvm_di_type = get_llvm_di_type(g, g->builtin_types.entry_bool);
@@ -7679,30 +7745,41 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) {
76797745
if (!type_has_bits(child_type)) {
76807746
type->llvm_type = bool_llvm_type;
76817747
type->llvm_di_type = bool_llvm_di_type;
7748+
type->data.maybe.resolve_status = ResolveStatusLLVMFull;
76827749
return;
76837750
}
76847751

7685-
LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type);
7686-
ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type);
7687-
76887752
if (type_is_nonnull_ptr(child_type) || child_type->id == ZigTypeIdErrorSet) {
7689-
type->llvm_type = child_llvm_type;
7690-
type->llvm_di_type = child_llvm_di_type;
7753+
type->llvm_type = get_llvm_type(g, child_type);
7754+
type->llvm_di_type = get_llvm_di_type(g, child_type);
7755+
type->data.maybe.resolve_status = ResolveStatusLLVMFull;
76917756
return;
76927757
}
76937758

7759+
ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7760+
ZigLLVMDIFile *di_file = nullptr;
7761+
unsigned line = 0;
7762+
7763+
if (type->data.maybe.resolve_status < ResolveStatusLLVMFwdDecl) {
7764+
type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&type->name));
7765+
unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
7766+
type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
7767+
dwarf_kind, buf_ptr(&type->name),
7768+
compile_unit_scope, di_file, line);
7769+
7770+
type->data.maybe.resolve_status = ResolveStatusLLVMFwdDecl;
7771+
if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return;
7772+
}
7773+
7774+
LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type);
7775+
ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type);
7776+
if (type->data.maybe.resolve_status >= wanted_resolve_status) return;
7777+
76947778
LLVMTypeRef elem_types[] = {
76957779
get_llvm_type(g, child_type),
76967780
LLVMInt1Type(),
76977781
};
7698-
type->llvm_type = LLVMStructType(elem_types, 2, false);
7699-
7700-
ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit);
7701-
ZigLLVMDIFile *di_file = nullptr;
7702-
unsigned line = 0;
7703-
type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
7704-
ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name),
7705-
compile_unit_scope, di_file, line);
7782+
LLVMStructSetBody(type->llvm_type, elem_types, 2, false);
77067783

77077784
uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type);
77087785
uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_llvm_type);
@@ -7737,6 +7814,7 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) {
77377814

77387815
ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type);
77397816
type->llvm_di_type = replacement_di_type;
7817+
type->data.maybe.resolve_status = ResolveStatusLLVMFull;
77407818
}
77417819

77427820
static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) {
@@ -8180,7 +8258,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r
81808258
case ZigTypeIdInt:
81818259
return resolve_llvm_types_integer(g, type);
81828260
case ZigTypeIdOptional:
8183-
return resolve_llvm_types_optional(g, type);
8261+
return resolve_llvm_types_optional(g, type, wanted_resolve_status);
81848262
case ZigTypeIdErrorUnion:
81858263
return resolve_llvm_types_error_union(g, type);
81868264
case ZigTypeIdArray:

src/analyze.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,5 +248,6 @@ bool fn_is_async(ZigFn *fn);
248248

249249
Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align);
250250
ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field);
251+
ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field);
251252

252253
#endif

0 commit comments

Comments
 (0)