aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Module.zig42
-rw-r--r--src/Sema.zig87
-rw-r--r--src/type.zig6
3 files changed, 116 insertions, 19 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 0cbf75c735..8c14f080d2 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -831,6 +831,10 @@ pub const Struct = struct {
have_field_types,
layout_wip,
have_layout,
+ fully_resolved_wip,
+ // The types and all its fields have had their layout resolved. Even through pointer,
+ // which `have_layout` does not ensure.
+ fully_resolved,
},
/// If true, definitely nonzero size at runtime. If false, resolving the fields
/// is necessary to determine whether it has bits at runtime.
@@ -889,6 +893,22 @@ pub const Struct = struct {
.have_field_types,
.layout_wip,
.have_layout,
+ .fully_resolved_wip,
+ .fully_resolved,
+ => true,
+ };
+ }
+
+ pub fn haveLayout(s: Struct) bool {
+ return switch (s.status) {
+ .none,
+ .field_types_wip,
+ .have_field_types,
+ .layout_wip,
+ => false,
+ .have_layout,
+ .fully_resolved_wip,
+ .fully_resolved,
=> true,
};
}
@@ -1003,6 +1023,10 @@ pub const Union = struct {
have_field_types,
layout_wip,
have_layout,
+ fully_resolved_wip,
+ // The types and all its fields have had their layout resolved. Even through pointer,
+ // which `have_layout` does not ensure.
+ fully_resolved,
},
pub const Field = struct {
@@ -1033,6 +1057,8 @@ pub const Union = struct {
.have_field_types,
.layout_wip,
.have_layout,
+ .fully_resolved_wip,
+ .fully_resolved,
=> true,
};
}
@@ -1102,8 +1128,22 @@ pub const Union = struct {
tag_size: u64,
};
+ pub fn haveLayout(u: Union) bool {
+ return switch (u.status) {
+ .none,
+ .field_types_wip,
+ .have_field_types,
+ .layout_wip,
+ => false,
+ .have_layout,
+ .fully_resolved_wip,
+ .fully_resolved,
+ => true,
+ };
+ }
+
pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout {
- assert(u.status == .have_layout);
+ assert(u.haveLayout());
var most_aligned_field: u32 = undefined;
var most_aligned_field_size: u64 = undefined;
var biggest_field: u32 = undefined;
diff --git a/src/Sema.zig b/src/Sema.zig
index 8389eed6d5..9ecac34c77 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -4503,14 +4503,14 @@ fn analyzeCall(
const arg_src = call_src; // TODO: better source location
if (i < fn_params_len) {
const param_ty = func_ty.fnParamType(i);
- try sema.resolveTypeForCodegen(block, arg_src, param_ty);
+ try sema.resolveTypeFully(block, arg_src, param_ty);
args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
} else {
args[i] = uncasted_arg;
}
}
- try sema.resolveTypeForCodegen(block, call_src, func_ty_info.return_type);
+ try sema.resolveTypeFully(block, call_src, func_ty_info.return_type);
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
args.len);
@@ -4580,7 +4580,7 @@ fn finishGenericCall(
const param_ty = new_fn_ty.fnParamType(runtime_i);
const arg_src = call_src; // TODO: better source location
const uncasted_arg = uncasted_args[total_i];
- try sema.resolveTypeForCodegen(block, arg_src, param_ty);
+ try sema.resolveTypeFully(block, arg_src, param_ty);
const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
runtime_args[runtime_i] = casted_arg;
runtime_i += 1;
@@ -4588,7 +4588,7 @@ fn finishGenericCall(
total_i += 1;
}
- try sema.resolveTypeForCodegen(block, call_src, new_fn_ty.fnReturnType());
+ try sema.resolveTypeFully(block, call_src, new_fn_ty.fnReturnType());
}
try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
runtime_args_len);
@@ -15228,7 +15228,7 @@ fn resolveStructLayout(
.field_types_wip, .layout_wip => {
return sema.fail(block, src, "struct {} depends on itself", .{ty});
},
- .have_layout => return,
+ .have_layout, .fully_resolved_wip, .fully_resolved => return,
}
struct_obj.status = .layout_wip;
for (struct_obj.fields.values()) |field| {
@@ -15250,7 +15250,7 @@ fn resolveUnionLayout(
.field_types_wip, .layout_wip => {
return sema.fail(block, src, "union {} depends on itself", .{ty});
},
- .have_layout => return,
+ .have_layout, .fully_resolved_wip, .fully_resolved => return,
}
union_obj.status = .layout_wip;
for (union_obj.fields.values()) |field| {
@@ -15259,7 +15259,7 @@ fn resolveUnionLayout(
union_obj.status = .have_layout;
}
-fn resolveTypeForCodegen(
+fn resolveTypeFully(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
@@ -15268,20 +15268,67 @@ fn resolveTypeForCodegen(
switch (ty.zigTypeTag()) {
.Pointer => {
const child_ty = try sema.resolveTypeFields(block, src, ty.childType());
- return resolveTypeForCodegen(sema, block, src, child_ty);
+ return resolveTypeFully(sema, block, src, child_ty);
},
- .Struct => return resolveStructLayout(sema, block, src, ty),
- .Union => return resolveUnionLayout(sema, block, src, ty),
- .Array => return resolveTypeForCodegen(sema, block, src, ty.childType()),
+ .Struct => return resolveStructFully(sema, block, src, ty),
+ .Union => return resolveUnionFully(sema, block, src, ty),
+ .Array => return resolveTypeFully(sema, block, src, ty.childType()),
.Optional => {
var buf: Type.Payload.ElemType = undefined;
- return resolveTypeForCodegen(sema, block, src, ty.optionalChild(&buf));
+ return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));
},
- .ErrorUnion => return resolveTypeForCodegen(sema, block, src, ty.errorUnionPayload()),
+ .ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()),
else => {},
}
}
+fn resolveStructFully(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ ty: Type,
+) CompileError!void {
+ try resolveStructLayout(sema, block, src, ty);
+
+ const resolved_ty = try sema.resolveTypeFields(block, src, ty);
+ const struct_obj = resolved_ty.castTag(.@"struct").?.data;
+ switch (struct_obj.status) {
+ .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
+ .fully_resolved_wip, .fully_resolved => return,
+ }
+
+ // After we have resolve struct layout we have to go over the fields again to
+ // make sure pointer fields get their child types resolved as well
+ struct_obj.status = .fully_resolved_wip;
+ for (struct_obj.fields.values()) |field| {
+ try sema.resolveTypeFully(block, src, field.ty);
+ }
+ struct_obj.status = .fully_resolved;
+}
+
+fn resolveUnionFully(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ ty: Type,
+) CompileError!void {
+ try resolveUnionLayout(sema, block, src, ty);
+
+ const resolved_ty = try sema.resolveTypeFields(block, src, ty);
+ const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
+ switch (union_obj.status) {
+ .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
+ .fully_resolved_wip, .fully_resolved => return,
+ }
+
+ // Same goes for unions (see comment about structs)
+ union_obj.status = .fully_resolved_wip;
+ for (union_obj.fields.values()) |field| {
+ try sema.resolveTypeFully(block, src, field.ty);
+ }
+ union_obj.status = .fully_resolved;
+}
+
fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
switch (ty.tag()) {
.@"struct" => {
@@ -15291,7 +15338,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
.field_types_wip => {
return sema.fail(block, src, "struct {} depends on itself", .{ty});
},
- .have_field_types, .have_layout, .layout_wip => return ty,
+ .have_field_types,
+ .have_layout,
+ .layout_wip,
+ .fully_resolved_wip,
+ .fully_resolved,
+ => return ty,
}
struct_obj.status = .field_types_wip;
@@ -15324,7 +15376,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
.field_types_wip => {
return sema.fail(block, src, "union {} depends on itself", .{ty});
},
- .have_field_types, .have_layout, .layout_wip => return ty,
+ .have_field_types,
+ .have_layout,
+ .layout_wip,
+ .fully_resolved_wip,
+ .fully_resolved,
+ => return ty,
}
union_obj.status = .field_types_wip;
diff --git a/src/type.zig b/src/type.zig
index 4ad15f2399..f4561769e2 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -1916,7 +1916,7 @@ pub const Type = extern union {
const fields = self.structFields();
const is_packed = if (self.castTag(.@"struct")) |payload| p: {
const struct_obj = payload.data;
- assert(struct_obj.status == .have_layout);
+ assert(struct_obj.haveLayout());
break :p struct_obj.layout == .Packed;
} else false;
@@ -2220,7 +2220,7 @@ pub const Type = extern union {
if (field_count == 0) return 0;
const struct_obj = ty.castTag(.@"struct").?.data;
- assert(struct_obj.status == .have_layout);
+ assert(struct_obj.haveLayout());
var total: u64 = 0;
for (struct_obj.fields.values()) |field| {
@@ -3771,7 +3771,7 @@ pub const Type = extern union {
switch (ty.tag()) {
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
- assert(struct_obj.status == .have_layout);
+ assert(struct_obj.haveLayout());
const is_packed = struct_obj.layout == .Packed;
if (!is_packed) {
var offset: u64 = 0;