authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-16 15:46:43+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-20 20:25:11+02:00
loge5a3eb9777ff165d936b0811f3825eabb8bcd6a4
tree15b67ec852dc6b41d1b54a1039bcdd6581aa0449
parent44f8714dfb69fac2e8c7a6a35ad9f2abe7c4513a

Type: make `hasRuntimeBitsAdvanced` take `AbiAlignmentAdvancedStrat`

I wasn't able to create a reduced test case for this but the reasoning can be seen in `abiAlignmentAdvancedUnion` where if `strat` was lazy `hasRuntimeBitsAdvanced` would be given `null` instead of `sema` which would cause eager evaluation when it is not valid or desired.

4 files changed, 81 insertions(+), 37 deletions(-)

src/Sema.zig+5-2
......@@ -128,7 +128,7 @@ pub const Block = struct {
128128 /// Shared among all child blocks.
129129 sema: *Sema,
130130 /// The namespace to use for lookups from this source block
131 /// When analyzing fields, this is different from src_decl.src_namepsace.
131 /// When analyzing fields, this is different from src_decl.src_namespace.
132132 namespace: *Namespace,
133133 /// The AIR instructions generated for this block.
134134 instructions: std.ArrayListUnmanaged(Air.Inst.Index),
......@@ -31298,7 +31298,10 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3129831298}
3129931299
3130031300pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
31301 return ty.hasRuntimeBitsAdvanced(false, sema);
31301 return ty.hasRuntimeBitsAdvanced(false, .{ .sema = sema }) catch |err| switch (err) {
31302 error.NeedLazy => unreachable,
31303 else => |e| return e,
31304 };
3130231305}
3130331306
3130431307fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
src/print_zir.zig+17-1
......@@ -262,9 +262,10 @@ const Writer = struct {
262262 => try self.writeBreak(stream, inst),
263263 .array_init,
264264 .array_init_ref,
265 => try self.writeArrayInit(stream, inst),
265266 .array_init_anon,
266267 .array_init_anon_ref,
267 => try self.writeArrayInit(stream, inst),
268 => try self.writeArrayInitAnon(stream, inst),
268269
269270 .slice_start => try self.writeSliceStart(stream, inst),
270271 .slice_end => try self.writeSliceEnd(stream, inst),
......@@ -2316,6 +2317,21 @@ const Writer = struct {
23162317 try self.writeSrc(stream, inst_data.src());
23172318 }
23182319
2320 fn writeArrayInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2321 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2322
2323 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
2324 const args = self.code.refSlice(extra.end, extra.data.operands_len);
2325
2326 try stream.writeAll("{");
2327 for (args) |arg, i| {
2328 if (i != 0) try stream.writeAll(", ");
2329 try self.writeInstRef(stream, arg);
2330 }
2331 try stream.writeAll("}) ");
2332 try self.writeSrc(stream, inst_data.src());
2333 }
2334
23192335 fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
23202336 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
23212337
src/type.zig+49-32
......@@ -2312,6 +2312,8 @@ pub const Type = extern union {
23122312 }
23132313 }
23142314
2315 const RuntimeBitsError = Module.CompileError || error{NeedLazy};
2316
23152317 /// true if and only if the type takes up space in memory at runtime.
23162318 /// There are two reasons a type will return false:
23172319 /// * the type is a comptime-only type. For example, the type `type` itself.
......@@ -2326,8 +2328,8 @@ pub const Type = extern union {
23262328 pub fn hasRuntimeBitsAdvanced(
23272329 ty: Type,
23282330 ignore_comptime_only: bool,
2329 opt_sema: ?*Sema,
2330 ) Module.CompileError!bool {
2331 strat: AbiAlignmentAdvancedStrat,
2332 ) RuntimeBitsError!bool {
23312333 switch (ty.tag()) {
23322334 .u1,
23332335 .u8,
......@@ -2406,8 +2408,8 @@ pub const Type = extern union {
24062408 return true;
24072409 } else if (ty.childType().zigTypeTag() == .Fn) {
24082410 return !ty.childType().fnInfo().is_generic;
2409 } else if (opt_sema) |sema| {
2410 return !(try sema.typeRequiresComptime(ty));
2411 } else if (strat == .sema) {
2412 return !(try strat.sema.typeRequiresComptime(ty));
24112413 } else {
24122414 return !comptimeOnly(ty);
24132415 }
......@@ -2445,8 +2447,8 @@ pub const Type = extern union {
24452447 }
24462448 if (ignore_comptime_only) {
24472449 return true;
2448 } else if (opt_sema) |sema| {
2449 return !(try sema.typeRequiresComptime(child_ty));
2450 } else if (strat == .sema) {
2451 return !(try strat.sema.typeRequiresComptime(child_ty));
24502452 } else {
24512453 return !comptimeOnly(child_ty);
24522454 }
......@@ -2459,13 +2461,14 @@ pub const Type = extern union {
24592461 // and then later if our guess was incorrect, we emit a compile error.
24602462 return true;
24612463 }
2462 if (opt_sema) |sema| {
2463 _ = try sema.resolveTypeFields(ty);
2464 switch (strat) {
2465 .sema => |sema| _ = try sema.resolveTypeFields(ty),
2466 .eager => assert(struct_obj.haveFieldTypes()),
2467 .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy,
24642468 }
2465 assert(struct_obj.haveFieldTypes());
24662469 for (struct_obj.fields.values()) |field| {
24672470 if (field.is_comptime) continue;
2468 if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))
2471 if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
24692472 return true;
24702473 } else {
24712474 return false;
......@@ -2474,7 +2477,7 @@ pub const Type = extern union {
24742477
24752478 .enum_full => {
24762479 const enum_full = ty.castTag(.enum_full).?.data;
2477 return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema);
2480 return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat);
24782481 },
24792482 .enum_simple => {
24802483 const enum_simple = ty.castTag(.enum_simple).?.data;
......@@ -2483,17 +2486,18 @@ pub const Type = extern union {
24832486 .enum_numbered, .enum_nonexhaustive => {
24842487 var buffer: Payload.Bits = undefined;
24852488 const int_tag_ty = ty.intTagType(&buffer);
2486 return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema);
2489 return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat);
24872490 },
24882491
24892492 .@"union" => {
24902493 const union_obj = ty.castTag(.@"union").?.data;
2491 if (opt_sema) |sema| {
2492 _ = try sema.resolveTypeFields(ty);
2494 switch (strat) {
2495 .sema => |sema| _ = try sema.resolveTypeFields(ty),
2496 .eager => assert(union_obj.haveFieldTypes()),
2497 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
24932498 }
2494 assert(union_obj.haveFieldTypes());
24952499 for (union_obj.fields.values()) |value| {
2496 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))
2500 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
24972501 return true;
24982502 } else {
24992503 return false;
......@@ -2501,16 +2505,17 @@ pub const Type = extern union {
25012505 },
25022506 .union_safety_tagged, .union_tagged => {
25032507 const union_obj = ty.cast(Payload.Union).?.data;
2504 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) {
2508 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) {
25052509 return true;
25062510 }
25072511
2508 if (opt_sema) |sema| {
2509 _ = try sema.resolveTypeFields(ty);
2512 switch (strat) {
2513 .sema => |sema| _ = try sema.resolveTypeFields(ty),
2514 .eager => assert(union_obj.haveFieldTypes()),
2515 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
25102516 }
2511 assert(union_obj.haveFieldTypes());
25122517 for (union_obj.fields.values()) |value| {
2513 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))
2518 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
25142519 return true;
25152520 } else {
25162521 return false;
......@@ -2518,9 +2523,9 @@ pub const Type = extern union {
25182523 },
25192524
25202525 .array, .vector => return ty.arrayLen() != 0 and
2521 try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema),
2526 try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat),
25222527 .array_u8 => return ty.arrayLen() != 0,
2523 .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema),
2528 .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat),
25242529
25252530 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,
25262531
......@@ -2529,7 +2534,7 @@ pub const Type = extern union {
25292534 for (tuple.types) |field_ty, i| {
25302535 const val = tuple.values[i];
25312536 if (val.tag() != .unreachable_value) continue; // comptime field
2532 if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) return true;
2537 if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true;
25332538 }
25342539 return false;
25352540 },
......@@ -2665,11 +2670,11 @@ pub const Type = extern union {
26652670 }
26662671
26672672 pub fn hasRuntimeBits(ty: Type) bool {
2668 return hasRuntimeBitsAdvanced(ty, false, null) catch unreachable;
2673 return hasRuntimeBitsAdvanced(ty, false, .eager) catch unreachable;
26692674 }
26702675
26712676 pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {
2672 return hasRuntimeBitsAdvanced(ty, true, null) catch unreachable;
2677 return hasRuntimeBitsAdvanced(ty, true, .eager) catch unreachable;
26732678 }
26742679
26752680 pub fn isFnOrHasRuntimeBits(ty: Type) bool {
......@@ -2812,12 +2817,12 @@ pub const Type = extern union {
28122817 }
28132818 }
28142819
2815 const AbiAlignmentAdvanced = union(enum) {
2820 pub const AbiAlignmentAdvanced = union(enum) {
28162821 scalar: u32,
28172822 val: Value,
28182823 };
28192824
2820 const AbiAlignmentAdvancedStrat = union(enum) {
2825 pub const AbiAlignmentAdvancedStrat = union(enum) {
28212826 eager,
28222827 lazy: Allocator,
28232828 sema: *Sema,
......@@ -2971,7 +2976,10 @@ pub const Type = extern union {
29712976
29722977 switch (strat) {
29732978 .eager, .sema => {
2974 if (!(try child_type.hasRuntimeBitsAdvanced(false, opt_sema))) {
2979 if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
2980 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
2981 else => |e| return e,
2982 })) {
29752983 return AbiAlignmentAdvanced{ .scalar = 1 };
29762984 }
29772985 return child_type.abiAlignmentAdvanced(target, strat);
......@@ -2990,7 +2998,10 @@ pub const Type = extern union {
29902998 const code_align = abiAlignment(Type.anyerror, target);
29912999 switch (strat) {
29923000 .eager, .sema => {
2993 if (!(try data.payload.hasRuntimeBitsAdvanced(false, opt_sema))) {
3001 if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
3002 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
3003 else => |e| return e,
3004 })) {
29943005 return AbiAlignmentAdvanced{ .scalar = code_align };
29953006 }
29963007 return AbiAlignmentAdvanced{ .scalar = @max(
......@@ -3044,7 +3055,10 @@ pub const Type = extern union {
30443055 const fields = ty.structFields();
30453056 var big_align: u32 = 0;
30463057 for (fields.values()) |field| {
3047 if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue;
3058 if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
3059 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
3060 else => |e| return e,
3061 })) continue;
30483062
30493063 const field_align = if (field.abi_align != 0)
30503064 field.abi_align
......@@ -3161,7 +3175,10 @@ pub const Type = extern union {
31613175 var max_align: u32 = 0;
31623176 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
31633177 for (union_obj.fields.values()) |field| {
3164 if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue;
3178 if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
3179 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
3180 else => |e| return e,
3181 })) continue;
31653182
31663183 const field_align = if (field.abi_align != 0)
31673184 field.abi_align
src/value.zig+10-2
......@@ -1911,7 +1911,11 @@ pub const Value = extern union {
19111911
19121912 .lazy_align => {
19131913 const ty = lhs.castTag(.lazy_align).?.data;
1914 if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) {
1914 const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
1915 if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
1916 error.NeedLazy => unreachable,
1917 else => |e| return e,
1918 }) {
19151919 return .gt;
19161920 } else {
19171921 return .eq;
......@@ -1919,7 +1923,11 @@ pub const Value = extern union {
19191923 },
19201924 .lazy_size => {
19211925 const ty = lhs.castTag(.lazy_size).?.data;
1922 if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) {
1926 const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
1927 if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
1928 error.NeedLazy => unreachable,
1929 else => |e| return e,
1930 }) {
19231931 return .gt;
19241932 } else {
19251933 return .eq;