authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-22 15:42:09-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-22 15:45:59-07:00
log60d8c4739de14823c407245f01c9b7483f3b6e7f
tree8321a331d269b3ce4af0fdd88e99a6421f2a3b5d
parent593130ce0a4b06185fcb4806f8330857a1da9f92

Sema: introduce a mechanism in Value to resolve types

This commit adds a new optional argument to several Value methods which provides the ability to resolve types if it comes to it. This prevents having duplicated logic inside both Sema and Value. With this commit, the "struct contains slice of itself" test is passing by exploiting the new lazy_align Value Tag.

5 files changed, 167 insertions(+), 54 deletions(-)

src/Module.zig+6
......@@ -177,6 +177,12 @@ const MonomorphedFuncsContext = struct {
177177 }
178178};
179179
180pub const WipAnalysis = struct {
181 sema: *Sema,
182 block: *Sema.Block,
183 src: Module.LazySrcLoc,
184};
185
180186pub const MemoizedCallSet = std.HashMapUnmanaged(
181187 MemoizedCall.Key,
182188 MemoizedCall.Result,
src/Sema.zig+32-16
......@@ -1591,7 +1591,7 @@ fn resolveInt(
15911591 const coerced = try sema.coerce(block, dest_ty, air_inst, src);
15921592 const val = try sema.resolveConstValue(block, src, coerced);
15931593 const target = sema.mod.getTarget();
1594 return val.toUnsignedInt(target);
1594 return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;
15951595}
15961596
15971597// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
......@@ -9926,7 +9926,7 @@ fn analyzePtrArithmetic(
99269926 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target));
99279927 // TODO I tried to put this check earlier but it the LLVM backend generate invalid instructinons
99289928 if (offset_int == 0) return ptr;
9929 if (ptr_val.getUnsignedInt(target)) |addr| {
9929 if (try ptr_val.getUnsignedIntAdvanced(target, sema.kit(block, ptr_src))) |addr| {
99309930 const ptr_child_ty = ptr_ty.childType();
99319931 const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array)
99329932 ptr_child_ty.childType()
......@@ -11863,6 +11863,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1186311863 const elem_ty_src: LazySrcLoc = .unneeded;
1186411864 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
1186511865 const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
11866 const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type);
11867 const target = sema.mod.getTarget();
1186611868
1186711869 var extra_i = extra.end;
1186811870
......@@ -11872,10 +11874,19 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1187211874 break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;
1187311875 } else null;
1187411876
11875 const abi_align = if (inst_data.flags.has_align) blk: {
11877 const abi_align: u32 = if (inst_data.flags.has_align) blk: {
1187611878 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
1187711879 extra_i += 1;
11878 const abi_align = try sema.resolveInt(block, .unneeded, ref, Type.u32);
11880 const coerced = try sema.coerce(block, Type.u32, sema.resolveInst(ref), src);
11881 const val = try sema.resolveConstValue(block, src, coerced);
11882 // Check if this happens to be the lazy alignment of our element type, in
11883 // which case we can make this 0 without resolving it.
11884 if (val.castTag(.lazy_align)) |payload| {
11885 if (payload.data.eql(unresolved_elem_ty, target)) {
11886 break :blk 0;
11887 }
11888 }
11889 const abi_align = (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;
1187911890 break :blk @intCast(u32, abi_align);
1188011891 } else 0;
1188111892
......@@ -11903,7 +11914,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1190311914 return sema.fail(block, src, "bit offset starts after end of host integer", .{});
1190411915 }
1190511916
11906 const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type);
1190711917 const elem_ty = if (abi_align == 0)
1190811918 unresolved_elem_ty
1190911919 else t: {
......@@ -11911,7 +11921,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1191111921 try sema.resolveTypeLayout(block, elem_ty_src, elem_ty);
1191211922 break :t elem_ty;
1191311923 };
11914 const target = sema.mod.getTarget();
1191511924 const ty = try Type.ptr(sema.arena, target, .{
1191611925 .pointee_type = elem_ty,
1191711926 .sentinel = sentinel,
......@@ -18390,15 +18399,15 @@ fn storePtrVal(
1839018399 operand_val: Value,
1839118400 operand_ty: Type,
1839218401) !void {
18393 var kit = try beginComptimePtrMutation(sema, block, src, ptr_val);
18394 try sema.checkComptimeVarStore(block, src, kit.decl_ref_mut);
18402 var mut_kit = try beginComptimePtrMutation(sema, block, src, ptr_val);
18403 try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut);
1839518404
18396 const bitcasted_val = try sema.bitCastVal(block, src, operand_val, operand_ty, kit.ty, 0);
18405 const bitcasted_val = try sema.bitCastVal(block, src, operand_val, operand_ty, mut_kit.ty, 0);
1839718406
18398 const arena = kit.beginArena(sema.gpa);
18399 defer kit.finishArena();
18407 const arena = mut_kit.beginArena(sema.gpa);
18408 defer mut_kit.finishArena();
1840018409
18401 kit.val.* = try bitcasted_val.copy(arena);
18410 mut_kit.val.* = try bitcasted_val.copy(arena);
1840218411}
1840318412
1840418413const ComptimePtrMutationKit = struct {
......@@ -19891,7 +19900,7 @@ fn cmpNumeric(
1989119900 return Air.Inst.Ref.bool_false;
1989219901 }
1989319902 }
19894 if (Value.compareHetero(lhs_val, op, rhs_val, target)) {
19903 if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, target, sema.kit(block, src))) {
1989519904 return Air.Inst.Ref.bool_true;
1989619905 } else {
1989719906 return Air.Inst.Ref.bool_false;
......@@ -20758,7 +20767,7 @@ pub fn resolveFnTypes(
2075820767 }
2075920768}
2076020769
20761fn resolveTypeLayout(
20770pub fn resolveTypeLayout(
2076220771 sema: *Sema,
2076320772 block: *Block,
2076420773 src: LazySrcLoc,
......@@ -20929,7 +20938,7 @@ fn resolveUnionFully(
2092920938 union_obj.status = .fully_resolved;
2093020939}
2093120940
20932fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
20941pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
2093320942 switch (ty.tag()) {
2093420943 .@"struct" => {
2093520944 const struct_obj = ty.castTag(.@"struct").?.data;
......@@ -22209,7 +22218,9 @@ fn typePtrOrOptionalPtrTy(
2220922218/// This function returns false negatives when structs and unions are having their
2221022219/// field types resolved.
2221122220/// TODO assert the return value matches `ty.comptimeOnly`
22212fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
22221/// TODO merge these implementations together with the "advanced"/sema_kit pattern seen
22222/// elsewhere in value.zig
22223pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
2221322224 return switch (ty.tag()) {
2221422225 .u1,
2221522226 .u8,
......@@ -22415,6 +22426,7 @@ fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 {
2241522426 return ty.abiSize(target);
2241622427}
2241722428
22429/// TODO merge with Type.abiAlignmentAdvanced
2241822430fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32 {
2241922431 try sema.resolveTypeLayout(block, src, ty);
2242022432 const target = sema.mod.getTarget();
......@@ -22498,3 +22510,7 @@ fn anonStructFieldIndex(
2249822510 struct_ty.fmt(target), field_name,
2249922511 });
2250022512}
22513
22514fn kit(sema: *Sema, block: *Block, src: LazySrcLoc) Module.WipAnalysis {
22515 return .{ .sema = sema, .block = block, .src = src };
22516}
src/type.zig+65-30
......@@ -1483,20 +1483,29 @@ pub const Type = extern union {
14831483 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
14841484 }
14851485
1486 pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(TypedValue.format) {
1487 var ty_payload: Value.Payload.Ty = .{
1488 .base = .{ .tag = .ty },
1489 .data = ty,
1490 };
1486 pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(format2) {
14911487 return .{ .data = .{
1492 .tv = .{
1493 .ty = Type.type,
1494 .val = Value.initPayload(&ty_payload.base),
1495 },
1488 .ty = ty,
14961489 .target = target,
14971490 } };
14981491 }
14991492
1493 const FormatContext = struct {
1494 ty: Type,
1495 target: Target,
1496 };
1497
1498 fn format2(
1499 ctx: FormatContext,
1500 comptime unused_format_string: []const u8,
1501 options: std.fmt.FormatOptions,
1502 writer: anytype,
1503 ) !void {
1504 comptime assert(unused_format_string.len == 0);
1505 _ = options;
1506 return print(ctx.ty, writer, ctx.target);
1507 }
1508
15001509 pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {
15011510 return .{ .data = ty };
15021511 }
......@@ -2241,8 +2250,12 @@ pub const Type = extern union {
22412250 /// * the type has only one possible value, making its ABI size 0.
22422251 /// When `ignore_comptime_only` is true, then types that are comptime only
22432252 /// may return false positives.
2244 pub fn hasRuntimeBitsAdvanced(ty: Type, ignore_comptime_only: bool) bool {
2245 return switch (ty.tag()) {
2253 pub fn hasRuntimeBitsAdvanced(
2254 ty: Type,
2255 ignore_comptime_only: bool,
2256 sema_kit: ?Module.WipAnalysis,
2257 ) Module.CompileError!bool {
2258 switch (ty.tag()) {
22462259 .u1,
22472260 .u8,
22482261 .i8,
......@@ -2296,7 +2309,7 @@ pub const Type = extern union {
22962309 .@"anyframe",
22972310 .anyopaque,
22982311 .@"opaque",
2299 => true,
2312 => return true,
23002313
23012314 // These are false because they are comptime-only types.
23022315 .single_const_pointer_to_comptime_int,
......@@ -2320,7 +2333,7 @@ pub const Type = extern union {
23202333 .fn_void_no_args,
23212334 .fn_naked_noreturn_no_args,
23222335 .fn_ccc_void_no_args,
2323 => false,
2336 => return false,
23242337
23252338 // These types have more than one possible value, so the result is the same as
23262339 // asking whether they are comptime-only types.
......@@ -2337,20 +2350,34 @@ pub const Type = extern union {
23372350 .const_slice,
23382351 .mut_slice,
23392352 .pointer,
2340 => if (ignore_comptime_only) true else !comptimeOnly(ty),
2353 => {
2354 if (ignore_comptime_only) {
2355 return true;
2356 } else if (sema_kit) |sk| {
2357 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
2358 } else {
2359 return !comptimeOnly(ty);
2360 }
2361 },
23412362
23422363 .@"struct" => {
23432364 const struct_obj = ty.castTag(.@"struct").?.data;
2365 if (sema_kit) |sk| {
2366 _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty);
2367 }
23442368 switch (struct_obj.requires_comptime) {
23452369 .wip => unreachable,
23462370 .yes => return false,
23472371 .no => if (struct_obj.known_non_opv) return true,
23482372 .unknown => {},
23492373 }
2374 if (sema_kit) |sk| {
2375 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2376 }
23502377 assert(struct_obj.haveFieldTypes());
23512378 for (struct_obj.fields.values()) |value| {
23522379 if (value.is_comptime) continue;
2353 if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))
2380 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
23542381 return true;
23552382 } else {
23562383 return false;
......@@ -2368,14 +2395,17 @@ pub const Type = extern union {
23682395 .enum_numbered, .enum_nonexhaustive => {
23692396 var buffer: Payload.Bits = undefined;
23702397 const int_tag_ty = ty.intTagType(&buffer);
2371 return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only);
2398 return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit);
23722399 },
23732400
23742401 .@"union" => {
23752402 const union_obj = ty.castTag(.@"union").?.data;
2403 if (sema_kit) |sk| {
2404 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2405 }
23762406 assert(union_obj.haveFieldTypes());
23772407 for (union_obj.fields.values()) |value| {
2378 if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))
2408 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
23792409 return true;
23802410 } else {
23812411 return false;
......@@ -2383,29 +2413,32 @@ pub const Type = extern union {
23832413 },
23842414 .union_tagged => {
23852415 const union_obj = ty.castTag(.union_tagged).?.data;
2386 if (union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) {
2416 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
23872417 return true;
23882418 }
2419 if (sema_kit) |sk| {
2420 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2421 }
23892422 assert(union_obj.haveFieldTypes());
23902423 for (union_obj.fields.values()) |value| {
2391 if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))
2424 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
23922425 return true;
23932426 } else {
23942427 return false;
23952428 }
23962429 },
23972430
2398 .array, .vector => ty.arrayLen() != 0 and
2399 ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only),
2400 .array_u8 => ty.arrayLen() != 0,
2401 .array_sentinel => ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only),
2431 .array, .vector => return ty.arrayLen() != 0 and
2432 try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit),
2433 .array_u8 => return ty.arrayLen() != 0,
2434 .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit),
24022435
2403 .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0,
2436 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,
24042437
24052438 .error_union => {
24062439 const payload = ty.castTag(.error_union).?.data;
2407 return payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only) or
2408 payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only);
2440 return (try payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) or
2441 (try payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit));
24092442 },
24102443
24112444 .tuple, .anon_struct => {
......@@ -2413,7 +2446,7 @@ pub const Type = extern union {
24132446 for (tuple.types) |field_ty, i| {
24142447 const val = tuple.values[i];
24152448 if (val.tag() != .unreachable_value) continue; // comptime field
2416 if (field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) return true;
2449 if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) return true;
24172450 }
24182451 return false;
24192452 },
......@@ -2422,7 +2455,7 @@ pub const Type = extern union {
24222455 .inferred_alloc_mut => unreachable,
24232456 .var_args_param => unreachable,
24242457 .generic_poison => unreachable,
2425 };
2458 }
24262459 }
24272460
24282461 /// true if and only if the type has a well-defined memory layout
......@@ -2548,11 +2581,11 @@ pub const Type = extern union {
25482581 }
25492582
25502583 pub fn hasRuntimeBits(ty: Type) bool {
2551 return hasRuntimeBitsAdvanced(ty, false);
2584 return hasRuntimeBitsAdvanced(ty, false, null) catch unreachable;
25522585 }
25532586
25542587 pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {
2555 return hasRuntimeBitsAdvanced(ty, true);
2588 return hasRuntimeBitsAdvanced(ty, true, null) catch unreachable;
25562589 }
25572590
25582591 pub fn isFnOrHasRuntimeBits(ty: Type) bool {
......@@ -4538,6 +4571,8 @@ pub const Type = extern union {
45384571
45394572 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
45404573 /// resolves field types rather than asserting they are already resolved.
4574 /// TODO merge these implementations together with the "advanced" pattern seen
4575 /// elsewhere in this file.
45414576 pub fn comptimeOnly(ty: Type) bool {
45424577 return switch (ty.tag()) {
45434578 .u1,
src/value.zig+55-8
......@@ -9,6 +9,7 @@ const Allocator = std.mem.Allocator;
99const Module = @import("Module.zig");
1010const Air = @import("Air.zig");
1111const TypedValue = @import("TypedValue.zig");
12const Sema = @import("Sema.zig");
1213
1314/// This is the raw data, with no bookkeeping, no memory awareness,
1415/// no de-duplication, and no type system awareness.
......@@ -990,6 +991,16 @@ pub const Value = extern union {
990991
991992 /// Asserts the value is an integer.
992993 pub fn toBigInt(val: Value, space: *BigIntSpace, target: Target) BigIntConst {
994 return val.toBigIntAdvanced(space, target, null) catch unreachable;
995 }
996
997 /// Asserts the value is an integer.
998 pub fn toBigIntAdvanced(
999 val: Value,
1000 space: *BigIntSpace,
1001 target: Target,
1002 sema_kit: ?Module.WipAnalysis,
1003 ) !BigIntConst {
9931004 switch (val.tag()) {
9941005 .zero,
9951006 .bool_false,
......@@ -1008,7 +1019,11 @@ pub const Value = extern union {
10081019 .undef => unreachable,
10091020
10101021 .lazy_align => {
1011 const x = val.castTag(.lazy_align).?.data.abiAlignment(target);
1022 const ty = val.castTag(.lazy_align).?.data;
1023 if (sema_kit) |sk| {
1024 try sk.sema.resolveTypeLayout(sk.block, sk.src, ty);
1025 }
1026 const x = ty.abiAlignment(target);
10121027 return BigIntMutable.init(&space.limbs, x).toConst();
10131028 },
10141029
......@@ -1019,6 +1034,12 @@ pub const Value = extern union {
10191034 /// If the value fits in a u64, return it, otherwise null.
10201035 /// Asserts not undefined.
10211036 pub fn getUnsignedInt(val: Value, target: Target) ?u64 {
1037 return getUnsignedIntAdvanced(val, target, null) catch unreachable;
1038 }
1039
1040 /// If the value fits in a u64, return it, otherwise null.
1041 /// Asserts not undefined.
1042 pub fn getUnsignedIntAdvanced(val: Value, target: Target, sema_kit: ?Module.WipAnalysis) !?u64 {
10221043 switch (val.tag()) {
10231044 .zero,
10241045 .bool_false,
......@@ -1036,7 +1057,13 @@ pub const Value = extern union {
10361057
10371058 .undef => unreachable,
10381059
1039 .lazy_align => return val.castTag(.lazy_align).?.data.abiAlignment(target),
1060 .lazy_align => {
1061 const ty = val.castTag(.lazy_align).?.data;
1062 if (sema_kit) |sk| {
1063 try sk.sema.resolveTypeLayout(sk.block, sk.src, ty);
1064 }
1065 return ty.abiAlignment(target);
1066 },
10401067
10411068 else => return null,
10421069 }
......@@ -1777,6 +1804,10 @@ pub const Value = extern union {
17771804 }
17781805
17791806 pub fn orderAgainstZero(lhs: Value) std.math.Order {
1807 return orderAgainstZeroAdvanced(lhs, null) catch unreachable;
1808 }
1809
1810 pub fn orderAgainstZeroAdvanced(lhs: Value, sema_kit: ?Module.WipAnalysis) !std.math.Order {
17801811 return switch (lhs.tag()) {
17811812 .zero,
17821813 .bool_false,
......@@ -1799,7 +1830,7 @@ pub const Value = extern union {
17991830
18001831 .lazy_align => {
18011832 const ty = lhs.castTag(.lazy_align).?.data;
1802 if (ty.hasRuntimeBitsIgnoreComptime()) {
1833 if (try ty.hasRuntimeBitsAdvanced(false, sema_kit)) {
18031834 return .gt;
18041835 } else {
18051836 return .eq;
......@@ -1818,10 +1849,16 @@ pub const Value = extern union {
18181849
18191850 /// Asserts the value is comparable.
18201851 pub fn order(lhs: Value, rhs: Value, target: Target) std.math.Order {
1852 return orderAdvanced(lhs, rhs, target, null) catch unreachable;
1853 }
1854
1855 /// Asserts the value is comparable.
1856 /// If sema_kit is null then this function asserts things are resolved and cannot fail.
1857 pub fn orderAdvanced(lhs: Value, rhs: Value, target: Target, sema_kit: ?Module.WipAnalysis) !std.math.Order {
18211858 const lhs_tag = lhs.tag();
18221859 const rhs_tag = rhs.tag();
1823 const lhs_against_zero = lhs.orderAgainstZero();
1824 const rhs_against_zero = rhs.orderAgainstZero();
1860 const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(sema_kit);
1861 const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(sema_kit);
18251862 switch (lhs_against_zero) {
18261863 .lt => if (rhs_against_zero != .lt) return .lt,
18271864 .eq => return rhs_against_zero.invert(),
......@@ -1855,14 +1892,24 @@ pub const Value = extern union {
18551892
18561893 var lhs_bigint_space: BigIntSpace = undefined;
18571894 var rhs_bigint_space: BigIntSpace = undefined;
1858 const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, target);
1859 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, target);
1895 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, target, sema_kit);
1896 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, target, sema_kit);
18601897 return lhs_bigint.order(rhs_bigint);
18611898 }
18621899
18631900 /// Asserts the value is comparable. Does not take a type parameter because it supports
18641901 /// comparisons between heterogeneous types.
18651902 pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, target: Target) bool {
1903 return compareHeteroAdvanced(lhs, op, rhs, target, null) catch unreachable;
1904 }
1905
1906 pub fn compareHeteroAdvanced(
1907 lhs: Value,
1908 op: std.math.CompareOperator,
1909 rhs: Value,
1910 target: Target,
1911 sema_kit: ?Module.WipAnalysis,
1912 ) !bool {
18661913 if (lhs.pointerDecl()) |lhs_decl| {
18671914 if (rhs.pointerDecl()) |rhs_decl| {
18681915 switch (op) {
......@@ -1884,7 +1931,7 @@ pub const Value = extern union {
18841931 else => {},
18851932 }
18861933 }
1887 return order(lhs, rhs, target).compare(op);
1934 return (try orderAdvanced(lhs, rhs, target, sema_kit)).compare(op);
18881935 }
18891936
18901937 /// Asserts the values are comparable. Both operands have type `ty`.
test/behavior/struct_contains_slice_of_itself.zig+9
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const expect = @import("std").testing.expect;
23
34const Node = struct {
......@@ -11,6 +12,10 @@ const NodeAligned = struct {
1112};
1213
1314test "struct contains slice of itself" {
15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18
1419 var other_nodes = [_]Node{
1520 Node{
1621 .payload = 31,
......@@ -48,6 +53,10 @@ test "struct contains slice of itself" {
4853}
4954
5055test "struct contains aligned slice of itself" {
56 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
59
5160 var other_nodes = [_]NodeAligned{
5261 NodeAligned{
5362 .payload = 31,