mirror of
https://github.com/ziglang/zig.git
synced 2026-01-29 10:47:40 +00:00
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
This commit is contained in:
parent
d5093b6c13
commit
9d6bef49a5
@ -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;
|
||||
|
||||
87
src/Sema.zig
87
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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user