authorgravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2022-01-07 18:58:40+01:00
committergravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2022-01-07 22:10:36+01:00
log9d6bef49a5fc2a5387734fa8d8cc698f0da8d5fa
tree86304781ddc0b37b2b7881b54f72fb789660c7eb
parentd5093b6c1395d4a60a923e1911321784ce368bda

Add two more resolution status' to Struct and Union

resolveTypeForCodegen is called when we needed to resolve a type fully, even through pointer. This commit fully implements this, even through pointer fields on structs and unions. The function has now also been renamed to resolveTypeFully

3 files changed, 116 insertions(+), 19 deletions(-)

src/Module.zig+41-1
......@@ -831,6 +831,10 @@ pub const Struct = struct {
831831 have_field_types,
832832 layout_wip,
833833 have_layout,
834 fully_resolved_wip,
835 // The types and all its fields have had their layout resolved. Even through pointer,
836 // which `have_layout` does not ensure.
837 fully_resolved,
834838 },
835839 /// If true, definitely nonzero size at runtime. If false, resolving the fields
836840 /// is necessary to determine whether it has bits at runtime.
......@@ -889,6 +893,22 @@ pub const Struct = struct {
889893 .have_field_types,
890894 .layout_wip,
891895 .have_layout,
896 .fully_resolved_wip,
897 .fully_resolved,
898 => true,
899 };
900 }
901
902 pub fn haveLayout(s: Struct) bool {
903 return switch (s.status) {
904 .none,
905 .field_types_wip,
906 .have_field_types,
907 .layout_wip,
908 => false,
909 .have_layout,
910 .fully_resolved_wip,
911 .fully_resolved,
892912 => true,
893913 };
894914 }
......@@ -1003,6 +1023,10 @@ pub const Union = struct {
10031023 have_field_types,
10041024 layout_wip,
10051025 have_layout,
1026 fully_resolved_wip,
1027 // The types and all its fields have had their layout resolved. Even through pointer,
1028 // which `have_layout` does not ensure.
1029 fully_resolved,
10061030 },
10071031
10081032 pub const Field = struct {
......@@ -1033,6 +1057,8 @@ pub const Union = struct {
10331057 .have_field_types,
10341058 .layout_wip,
10351059 .have_layout,
1060 .fully_resolved_wip,
1061 .fully_resolved,
10361062 => true,
10371063 };
10381064 }
......@@ -1102,8 +1128,22 @@ pub const Union = struct {
11021128 tag_size: u64,
11031129 };
11041130
1131 pub fn haveLayout(u: Union) bool {
1132 return switch (u.status) {
1133 .none,
1134 .field_types_wip,
1135 .have_field_types,
1136 .layout_wip,
1137 => false,
1138 .have_layout,
1139 .fully_resolved_wip,
1140 .fully_resolved,
1141 => true,
1142 };
1143 }
1144
11051145 pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout {
1106 assert(u.status == .have_layout);
1146 assert(u.haveLayout());
11071147 var most_aligned_field: u32 = undefined;
11081148 var most_aligned_field_size: u64 = undefined;
11091149 var biggest_field: u32 = undefined;
src/Sema.zig+72-15
......@@ -4503,14 +4503,14 @@ fn analyzeCall(
45034503 const arg_src = call_src; // TODO: better source location
45044504 if (i < fn_params_len) {
45054505 const param_ty = func_ty.fnParamType(i);
4506 try sema.resolveTypeForCodegen(block, arg_src, param_ty);
4506 try sema.resolveTypeFully(block, arg_src, param_ty);
45074507 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
45084508 } else {
45094509 args[i] = uncasted_arg;
45104510 }
45114511 }
45124512
4513 try sema.resolveTypeForCodegen(block, call_src, func_ty_info.return_type);
4513 try sema.resolveTypeFully(block, call_src, func_ty_info.return_type);
45144514
45154515 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
45164516 args.len);
......@@ -4580,7 +4580,7 @@ fn finishGenericCall(
45804580 const param_ty = new_fn_ty.fnParamType(runtime_i);
45814581 const arg_src = call_src; // TODO: better source location
45824582 const uncasted_arg = uncasted_args[total_i];
4583 try sema.resolveTypeForCodegen(block, arg_src, param_ty);
4583 try sema.resolveTypeFully(block, arg_src, param_ty);
45844584 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
45854585 runtime_args[runtime_i] = casted_arg;
45864586 runtime_i += 1;
......@@ -4588,7 +4588,7 @@ fn finishGenericCall(
45884588 total_i += 1;
45894589 }
45904590
4591 try sema.resolveTypeForCodegen(block, call_src, new_fn_ty.fnReturnType());
4591 try sema.resolveTypeFully(block, call_src, new_fn_ty.fnReturnType());
45924592 }
45934593 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
45944594 runtime_args_len);
......@@ -15228,7 +15228,7 @@ fn resolveStructLayout(
1522815228 .field_types_wip, .layout_wip => {
1522915229 return sema.fail(block, src, "struct {} depends on itself", .{ty});
1523015230 },
15231 .have_layout => return,
15231 .have_layout, .fully_resolved_wip, .fully_resolved => return,
1523215232 }
1523315233 struct_obj.status = .layout_wip;
1523415234 for (struct_obj.fields.values()) |field| {
......@@ -15250,7 +15250,7 @@ fn resolveUnionLayout(
1525015250 .field_types_wip, .layout_wip => {
1525115251 return sema.fail(block, src, "union {} depends on itself", .{ty});
1525215252 },
15253 .have_layout => return,
15253 .have_layout, .fully_resolved_wip, .fully_resolved => return,
1525415254 }
1525515255 union_obj.status = .layout_wip;
1525615256 for (union_obj.fields.values()) |field| {
......@@ -15259,7 +15259,7 @@ fn resolveUnionLayout(
1525915259 union_obj.status = .have_layout;
1526015260}
1526115261
15262fn resolveTypeForCodegen(
15262fn resolveTypeFully(
1526315263 sema: *Sema,
1526415264 block: *Block,
1526515265 src: LazySrcLoc,
......@@ -15268,20 +15268,67 @@ fn resolveTypeForCodegen(
1526815268 switch (ty.zigTypeTag()) {
1526915269 .Pointer => {
1527015270 const child_ty = try sema.resolveTypeFields(block, src, ty.childType());
15271 return resolveTypeForCodegen(sema, block, src, child_ty);
15271 return resolveTypeFully(sema, block, src, child_ty);
1527215272 },
15273 .Struct => return resolveStructLayout(sema, block, src, ty),
15274 .Union => return resolveUnionLayout(sema, block, src, ty),
15275 .Array => return resolveTypeForCodegen(sema, block, src, ty.childType()),
15273 .Struct => return resolveStructFully(sema, block, src, ty),
15274 .Union => return resolveUnionFully(sema, block, src, ty),
15275 .Array => return resolveTypeFully(sema, block, src, ty.childType()),
1527615276 .Optional => {
1527715277 var buf: Type.Payload.ElemType = undefined;
15278 return resolveTypeForCodegen(sema, block, src, ty.optionalChild(&buf));
15278 return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));
1527915279 },
15280 .ErrorUnion => return resolveTypeForCodegen(sema, block, src, ty.errorUnionPayload()),
15280 .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()),
1528115281 else => {},
1528215282 }
1528315283}
1528415284
15285fn resolveStructFully(
15286 sema: *Sema,
15287 block: *Block,
15288 src: LazySrcLoc,
15289 ty: Type,
15290) CompileError!void {
15291 try resolveStructLayout(sema, block, src, ty);
15292
15293 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15294 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
15295 switch (struct_obj.status) {
15296 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
15297 .fully_resolved_wip, .fully_resolved => return,
15298 }
15299
15300 // After we have resolve struct layout we have to go over the fields again to
15301 // make sure pointer fields get their child types resolved as well
15302 struct_obj.status = .fully_resolved_wip;
15303 for (struct_obj.fields.values()) |field| {
15304 try sema.resolveTypeFully(block, src, field.ty);
15305 }
15306 struct_obj.status = .fully_resolved;
15307}
15308
15309fn resolveUnionFully(
15310 sema: *Sema,
15311 block: *Block,
15312 src: LazySrcLoc,
15313 ty: Type,
15314) CompileError!void {
15315 try resolveUnionLayout(sema, block, src, ty);
15316
15317 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15318 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
15319 switch (union_obj.status) {
15320 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
15321 .fully_resolved_wip, .fully_resolved => return,
15322 }
15323
15324 // Same goes for unions (see comment about structs)
15325 union_obj.status = .fully_resolved_wip;
15326 for (union_obj.fields.values()) |field| {
15327 try sema.resolveTypeFully(block, src, field.ty);
15328 }
15329 union_obj.status = .fully_resolved;
15330}
15331
1528515332fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
1528615333 switch (ty.tag()) {
1528715334 .@"struct" => {
......@@ -15291,7 +15338,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
1529115338 .field_types_wip => {
1529215339 return sema.fail(block, src, "struct {} depends on itself", .{ty});
1529315340 },
15294 .have_field_types, .have_layout, .layout_wip => return ty,
15341 .have_field_types,
15342 .have_layout,
15343 .layout_wip,
15344 .fully_resolved_wip,
15345 .fully_resolved,
15346 => return ty,
1529515347 }
1529615348
1529715349 struct_obj.status = .field_types_wip;
......@@ -15324,7 +15376,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
1532415376 .field_types_wip => {
1532515377 return sema.fail(block, src, "union {} depends on itself", .{ty});
1532615378 },
15327 .have_field_types, .have_layout, .layout_wip => return ty,
15379 .have_field_types,
15380 .have_layout,
15381 .layout_wip,
15382 .fully_resolved_wip,
15383 .fully_resolved,
15384 => return ty,
1532815385 }
1532915386
1533015387 union_obj.status = .field_types_wip;
src/type.zig+3-3
......@@ -1916,7 +1916,7 @@ pub const Type = extern union {
19161916 const fields = self.structFields();
19171917 const is_packed = if (self.castTag(.@"struct")) |payload| p: {
19181918 const struct_obj = payload.data;
1919 assert(struct_obj.status == .have_layout);
1919 assert(struct_obj.haveLayout());
19201920 break :p struct_obj.layout == .Packed;
19211921 } else false;
19221922
......@@ -2220,7 +2220,7 @@ pub const Type = extern union {
22202220 if (field_count == 0) return 0;
22212221
22222222 const struct_obj = ty.castTag(.@"struct").?.data;
2223 assert(struct_obj.status == .have_layout);
2223 assert(struct_obj.haveLayout());
22242224
22252225 var total: u64 = 0;
22262226 for (struct_obj.fields.values()) |field| {
......@@ -3771,7 +3771,7 @@ pub const Type = extern union {
37713771 switch (ty.tag()) {
37723772 .@"struct" => {
37733773 const struct_obj = ty.castTag(.@"struct").?.data;
3774 assert(struct_obj.status == .have_layout);
3774 assert(struct_obj.haveLayout());
37753775 const is_packed = struct_obj.layout == .Packed;
37763776 if (!is_packed) {
37773777 var offset: u64 = 0;