authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-27 16:51:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-27 16:51:33-07:00
log9d4cfd9048d71d7519d759b9849914ce154d1877
treee28008bbb3ff86babf48fbe4b80d078e9217c2f3
parent71aa5084edd1d3fba5bf8db87c4cf0d03667a566

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.

3 files changed, 35 insertions(+), 13 deletions(-)

src/Module.zig+2
......@@ -1125,6 +1125,8 @@ pub const Union = struct {
11251125 abi_align: Value,
11261126
11271127 /// Returns the field alignment, assuming the union is not packed.
1128 /// Keep implementation in sync with `Sema.unionFieldAlignment`.
1129 /// Prefer to call that function instead of this one during Sema.
11281130 pub fn normalAlignment(field: Field, target: Target) u32 {
11291131 if (field.abi_align.tag() == .abi_align_default) {
11301132 return field.ty.abiAlignment(target);
src/Sema.zig+27-1
......@@ -10402,7 +10402,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1040210402
1040310403 const union_field_fields = try fields_anon_decl.arena().create([3]Value);
1040410404 const alignment = switch (layout) {
10405 .Auto, .Extern => field.normalAlignment(target),
10405 .Auto, .Extern => try sema.unionFieldAlignment(block, src, field),
1040610406 .Packed => 0,
1040710407 };
1040810408
......@@ -17713,6 +17713,10 @@ fn resolveTypeLayout(
1771317713 .Optional => {
1771417714 var buf: Type.Payload.ElemType = undefined;
1771517715 const payload_ty = ty.optionalChild(&buf);
17716 // In case of querying the ABI alignment of this optional, we will ask
17717 // for hasRuntimeBits() of the payload type, so we need "requires comptime"
17718 // to be known already before this function returns.
17719 _ = try sema.typeRequiresComptime(block, src, payload_ty);
1771617720 return sema.resolveTypeLayout(block, src, payload_ty);
1771717721 },
1771817722 .ErrorUnion => {
......@@ -17744,6 +17748,13 @@ fn resolveStructLayout(
1774417748 try sema.resolveTypeLayout(block, src, field.ty);
1774517749 }
1774617750 struct_obj.status = .have_layout;
17751
17752 // In case of querying the ABI alignment of this struct, we will ask
17753 // for hasRuntimeBits() of each field, so we need "requires comptime"
17754 // to be known already before this function returns.
17755 for (struct_obj.fields.values()) |field| {
17756 _ = try sema.typeRequiresComptime(block, src, field.ty);
17757 }
1774717758 }
1774817759 // otherwise it's a tuple; no need to resolve anything
1774917760}
......@@ -19297,6 +19308,21 @@ fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32
1929719308 return ty.abiAlignment(target);
1929819309}
1929919310
19311/// Not valid to call for packed unions.
19312/// Keep implementation in sync with `Module.Union.Field.normalAlignment`.
19313fn unionFieldAlignment(
19314 sema: *Sema,
19315 block: *Block,
19316 src: LazySrcLoc,
19317 field: Module.Union.Field,
19318) !u32 {
19319 if (field.abi_align.tag() == .abi_align_default) {
19320 return sema.typeAbiAlignment(block, src, field.ty);
19321 } else {
19322 return @intCast(u32, field.abi_align.toUnsignedInt());
19323 }
19324}
19325
1930019326/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
1930119327pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
1930219328 const fn_info = ty.fnInfo();
src/type.zig+6-12
......@@ -1619,10 +1619,6 @@ pub const Type = extern union {
16191619
16201620 // These types have more than one possible value, so the result is the same as
16211621 // asking whether they are comptime-only types.
1622 //
1623 // If we get an error that the comptimeOnly status hasn't been
1624 // resolved yet, then we assume that there are runtime bits,
1625 // just like we do for structs below
16261622 .anyframe_T,
16271623 .optional,
16281624 .optional_single_mut_pointer,
......@@ -1636,7 +1632,7 @@ pub const Type = extern union {
16361632 .const_slice,
16371633 .mut_slice,
16381634 .pointer,
1639 => !(ty.comptimeOnly() catch return true),
1635 => !ty.comptimeOnly(),
16401636
16411637 .@"struct" => {
16421638 const struct_obj = ty.castTag(.@"struct").?.data;
......@@ -1732,7 +1728,7 @@ pub const Type = extern union {
17321728 .Inline => return false,
17331729 else => {},
17341730 }
1735 if (fn_info.return_type.comptimeOnly() catch unreachable) return false;
1731 if (fn_info.return_type.comptimeOnly()) return false;
17361732 return true;
17371733 },
17381734 else => return ty.hasRuntimeBits(),
......@@ -3614,7 +3610,7 @@ pub const Type = extern union {
36143610
36153611 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
36163612 /// resolves field types rather than asserting they are already resolved.
3617 pub fn comptimeOnly(ty: Type) error{StatusNotResolved}!bool {
3613 pub fn comptimeOnly(ty: Type) bool {
36183614 return switch (ty.tag()) {
36193615 .u1,
36203616 .u8,
......@@ -3735,7 +3731,7 @@ pub const Type = extern union {
37353731 .tuple => {
37363732 const tuple = ty.castTag(.tuple).?.data;
37373733 for (tuple.types) |field_ty| {
3738 if (try field_ty.comptimeOnly()) return true;
3734 if (field_ty.comptimeOnly()) return true;
37393735 }
37403736 return false;
37413737 },
......@@ -3743,20 +3739,18 @@ pub const Type = extern union {
37433739 .@"struct" => {
37443740 const struct_obj = ty.castTag(.@"struct").?.data;
37453741 switch (struct_obj.requires_comptime) {
3746 .wip => unreachable,
3742 .wip, .unknown => unreachable, // This function asserts types already resolved.
37473743 .no => return false,
37483744 .yes => return true,
3749 .unknown => return error.StatusNotResolved,
37503745 }
37513746 },
37523747
37533748 .@"union", .union_tagged => {
37543749 const union_obj = ty.cast(Type.Payload.Union).?.data;
37553750 switch (union_obj.requires_comptime) {
3756 .wip => unreachable,
3751 .wip, .unknown => unreachable, // This function asserts types already resolved.
37573752 .no => return false,
37583753 .yes => return true,
3759 .unknown => return error.StatusNotResolved,
37603754 }
37613755 },
37623756