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 {...@@ -1125,6 +1125,8 @@ pub const Union = struct {
1125 abi_align: Value,1125 abi_align: Value,
11261126
1127 /// Returns the field alignment, assuming the union is not packed.1127 /// 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.
1128 pub fn normalAlignment(field: Field, target: Target) u32 {1130 pub fn normalAlignment(field: Field, target: Target) u32 {
1129 if (field.abi_align.tag() == .abi_align_default) {1131 if (field.abi_align.tag() == .abi_align_default) {
1130 return field.ty.abiAlignment(target);1132 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...@@ -10402,7 +10402,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1040210402
10403 const union_field_fields = try fields_anon_decl.arena().create([3]Value);10403 const union_field_fields = try fields_anon_decl.arena().create([3]Value);
10404 const alignment = switch (layout) {10404 const alignment = switch (layout) {
10405 .Auto, .Extern => field.normalAlignment(target),10405 .Auto, .Extern => try sema.unionFieldAlignment(block, src, field),
10406 .Packed => 0,10406 .Packed => 0,
10407 };10407 };
1040810408
...@@ -17713,6 +17713,10 @@ fn resolveTypeLayout(...@@ -17713,6 +17713,10 @@ fn resolveTypeLayout(
17713 .Optional => {17713 .Optional => {
17714 var buf: Type.Payload.ElemType = undefined;17714 var buf: Type.Payload.ElemType = undefined;
17715 const payload_ty = ty.optionalChild(&buf);17715 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);
17716 return sema.resolveTypeLayout(block, src, payload_ty);17720 return sema.resolveTypeLayout(block, src, payload_ty);
17717 },17721 },
17718 .ErrorUnion => {17722 .ErrorUnion => {
...@@ -17744,6 +17748,13 @@ fn resolveStructLayout(...@@ -17744,6 +17748,13 @@ fn resolveStructLayout(
17744 try sema.resolveTypeLayout(block, src, field.ty);17748 try sema.resolveTypeLayout(block, src, field.ty);
17745 }17749 }
17746 struct_obj.status = .have_layout;17750 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 }
17747 }17758 }
17748 // otherwise it's a tuple; no need to resolve anything17759 // otherwise it's a tuple; no need to resolve anything
17749}17760}
...@@ -19297,6 +19308,21 @@ fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32...@@ -19297,6 +19308,21 @@ fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32
19297 return ty.abiAlignment(target);19308 return ty.abiAlignment(target);
19298}19309}
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
19300/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.19326/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
19301pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {19327pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
19302 const fn_info = ty.fnInfo();19328 const fn_info = ty.fnInfo();
src/type.zig+6-12
...@@ -1619,10 +1619,6 @@ pub const Type = extern union {...@@ -1619,10 +1619,6 @@ pub const Type = extern union {
16191619
1620 // These types have more than one possible value, so the result is the same as1620 // These types have more than one possible value, so the result is the same as
1621 // asking whether they are comptime-only types.1621 // 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
1626 .anyframe_T,1622 .anyframe_T,
1627 .optional,1623 .optional,
1628 .optional_single_mut_pointer,1624 .optional_single_mut_pointer,
...@@ -1636,7 +1632,7 @@ pub const Type = extern union {...@@ -1636,7 +1632,7 @@ pub const Type = extern union {
1636 .const_slice,1632 .const_slice,
1637 .mut_slice,1633 .mut_slice,
1638 .pointer,1634 .pointer,
1639 => !(ty.comptimeOnly() catch return true),1635 => !ty.comptimeOnly(),
16401636
1641 .@"struct" => {1637 .@"struct" => {
1642 const struct_obj = ty.castTag(.@"struct").?.data;1638 const struct_obj = ty.castTag(.@"struct").?.data;
...@@ -1732,7 +1728,7 @@ pub const Type = extern union {...@@ -1732,7 +1728,7 @@ pub const Type = extern union {
1732 .Inline => return false,1728 .Inline => return false,
1733 else => {},1729 else => {},
1734 }1730 }
1735 if (fn_info.return_type.comptimeOnly() catch unreachable) return false;1731 if (fn_info.return_type.comptimeOnly()) return false;
1736 return true;1732 return true;
1737 },1733 },
1738 else => return ty.hasRuntimeBits(),1734 else => return ty.hasRuntimeBits(),
...@@ -3614,7 +3610,7 @@ pub const Type = extern union {...@@ -3614,7 +3610,7 @@ pub const Type = extern union {
36143610
3615 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which3611 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
3616 /// resolves field types rather than asserting they are already resolved.3612 /// 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 {
3618 return switch (ty.tag()) {3614 return switch (ty.tag()) {
3619 .u1,3615 .u1,
3620 .u8,3616 .u8,
...@@ -3735,7 +3731,7 @@ pub const Type = extern union {...@@ -3735,7 +3731,7 @@ pub const Type = extern union {
3735 .tuple => {3731 .tuple => {
3736 const tuple = ty.castTag(.tuple).?.data;3732 const tuple = ty.castTag(.tuple).?.data;
3737 for (tuple.types) |field_ty| {3733 for (tuple.types) |field_ty| {
3738 if (try field_ty.comptimeOnly()) return true;3734 if (field_ty.comptimeOnly()) return true;
3739 }3735 }
3740 return false;3736 return false;
3741 },3737 },
...@@ -3743,20 +3739,18 @@ pub const Type = extern union {...@@ -3743,20 +3739,18 @@ pub const Type = extern union {
3743 .@"struct" => {3739 .@"struct" => {
3744 const struct_obj = ty.castTag(.@"struct").?.data;3740 const struct_obj = ty.castTag(.@"struct").?.data;
3745 switch (struct_obj.requires_comptime) {3741 switch (struct_obj.requires_comptime) {
3746 .wip => unreachable,3742 .wip, .unknown => unreachable, // This function asserts types already resolved.
3747 .no => return false,3743 .no => return false,
3748 .yes => return true,3744 .yes => return true,
3749 .unknown => return error.StatusNotResolved,
3750 }3745 }
3751 },3746 },
37523747
3753 .@"union", .union_tagged => {3748 .@"union", .union_tagged => {
3754 const union_obj = ty.cast(Type.Payload.Union).?.data;3749 const union_obj = ty.cast(Type.Payload.Union).?.data;
3755 switch (union_obj.requires_comptime) {3750 switch (union_obj.requires_comptime) {
3756 .wip => unreachable,3751 .wip, .unknown => unreachable, // This function asserts types already resolved.
3757 .no => return false,3752 .no => return false,
3758 .yes => return true,3753 .yes => return true,
3759 .unknown => return error.StatusNotResolved,
3760 }3754 }
3761 },3755 },
37623756