mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
Sema: resolve necessary information ahead of time
Do the fallible logic in Sema where we have access to error reporting mechanisms, rather than in Type/Value. We can't just do the best guess when resolving queries of "is this type comptime only?" or "what is the ABI alignment of this field?". The result needs to be accurate. So we need to keep the assertions that the data is available active, and instead compute the necessary information before such functions get called. Unfortunately we are stuck with two versions of such functions because the various backends need to be able to ask such queries of Types and Values while assuming the result has already been computed and validated by Sema.
This commit is contained in:
parent
71aa5084ed
commit
9d4cfd9048
@ -1125,6 +1125,8 @@ pub const Union = struct {
|
||||
abi_align: Value,
|
||||
|
||||
/// Returns the field alignment, assuming the union is not packed.
|
||||
/// Keep implementation in sync with `Sema.unionFieldAlignment`.
|
||||
/// Prefer to call that function instead of this one during Sema.
|
||||
pub fn normalAlignment(field: Field, target: Target) u32 {
|
||||
if (field.abi_align.tag() == .abi_align_default) {
|
||||
return field.ty.abiAlignment(target);
|
||||
|
||||
28
src/Sema.zig
28
src/Sema.zig
@ -10402,7 +10402,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
|
||||
const union_field_fields = try fields_anon_decl.arena().create([3]Value);
|
||||
const alignment = switch (layout) {
|
||||
.Auto, .Extern => field.normalAlignment(target),
|
||||
.Auto, .Extern => try sema.unionFieldAlignment(block, src, field),
|
||||
.Packed => 0,
|
||||
};
|
||||
|
||||
@ -17713,6 +17713,10 @@ fn resolveTypeLayout(
|
||||
.Optional => {
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
const payload_ty = ty.optionalChild(&buf);
|
||||
// In case of querying the ABI alignment of this optional, we will ask
|
||||
// for hasRuntimeBits() of the payload type, so we need "requires comptime"
|
||||
// to be known already before this function returns.
|
||||
_ = try sema.typeRequiresComptime(block, src, payload_ty);
|
||||
return sema.resolveTypeLayout(block, src, payload_ty);
|
||||
},
|
||||
.ErrorUnion => {
|
||||
@ -17744,6 +17748,13 @@ fn resolveStructLayout(
|
||||
try sema.resolveTypeLayout(block, src, field.ty);
|
||||
}
|
||||
struct_obj.status = .have_layout;
|
||||
|
||||
// In case of querying the ABI alignment of this struct, we will ask
|
||||
// for hasRuntimeBits() of each field, so we need "requires comptime"
|
||||
// to be known already before this function returns.
|
||||
for (struct_obj.fields.values()) |field| {
|
||||
_ = try sema.typeRequiresComptime(block, src, field.ty);
|
||||
}
|
||||
}
|
||||
// otherwise it's a tuple; no need to resolve anything
|
||||
}
|
||||
@ -19297,6 +19308,21 @@ fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32
|
||||
return ty.abiAlignment(target);
|
||||
}
|
||||
|
||||
/// Not valid to call for packed unions.
|
||||
/// Keep implementation in sync with `Module.Union.Field.normalAlignment`.
|
||||
fn unionFieldAlignment(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
field: Module.Union.Field,
|
||||
) !u32 {
|
||||
if (field.abi_align.tag() == .abi_align_default) {
|
||||
return sema.typeAbiAlignment(block, src, field.ty);
|
||||
} else {
|
||||
return @intCast(u32, field.abi_align.toUnsignedInt());
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
|
||||
pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
|
||||
const fn_info = ty.fnInfo();
|
||||
|
||||
18
src/type.zig
18
src/type.zig
@ -1619,10 +1619,6 @@ pub const Type = extern union {
|
||||
|
||||
// These types have more than one possible value, so the result is the same as
|
||||
// asking whether they are comptime-only types.
|
||||
//
|
||||
// If we get an error that the comptimeOnly status hasn't been
|
||||
// resolved yet, then we assume that there are runtime bits,
|
||||
// just like we do for structs below
|
||||
.anyframe_T,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
@ -1636,7 +1632,7 @@ pub const Type = extern union {
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
.pointer,
|
||||
=> !(ty.comptimeOnly() catch return true),
|
||||
=> !ty.comptimeOnly(),
|
||||
|
||||
.@"struct" => {
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
@ -1732,7 +1728,7 @@ pub const Type = extern union {
|
||||
.Inline => return false,
|
||||
else => {},
|
||||
}
|
||||
if (fn_info.return_type.comptimeOnly() catch unreachable) return false;
|
||||
if (fn_info.return_type.comptimeOnly()) return false;
|
||||
return true;
|
||||
},
|
||||
else => return ty.hasRuntimeBits(),
|
||||
@ -3614,7 +3610,7 @@ pub const Type = extern union {
|
||||
|
||||
/// During semantic analysis, instead call `Sema.typeRequiresComptime` which
|
||||
/// resolves field types rather than asserting they are already resolved.
|
||||
pub fn comptimeOnly(ty: Type) error{StatusNotResolved}!bool {
|
||||
pub fn comptimeOnly(ty: Type) bool {
|
||||
return switch (ty.tag()) {
|
||||
.u1,
|
||||
.u8,
|
||||
@ -3735,7 +3731,7 @@ pub const Type = extern union {
|
||||
.tuple => {
|
||||
const tuple = ty.castTag(.tuple).?.data;
|
||||
for (tuple.types) |field_ty| {
|
||||
if (try field_ty.comptimeOnly()) return true;
|
||||
if (field_ty.comptimeOnly()) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
@ -3743,20 +3739,18 @@ pub const Type = extern union {
|
||||
.@"struct" => {
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
switch (struct_obj.requires_comptime) {
|
||||
.wip => unreachable,
|
||||
.wip, .unknown => unreachable, // This function asserts types already resolved.
|
||||
.no => return false,
|
||||
.yes => return true,
|
||||
.unknown => return error.StatusNotResolved,
|
||||
}
|
||||
},
|
||||
|
||||
.@"union", .union_tagged => {
|
||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
||||
switch (union_obj.requires_comptime) {
|
||||
.wip => unreachable,
|
||||
.wip, .unknown => unreachable, // This function asserts types already resolved.
|
||||
.no => return false,
|
||||
.yes => return true,
|
||||
.unknown => return error.StatusNotResolved,
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user