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 {...@@ -177,6 +177,12 @@ const MonomorphedFuncsContext = struct {
177 }177 }
178};178};
179179
180pub const WipAnalysis = struct {
181 sema: *Sema,
182 block: *Sema.Block,
183 src: Module.LazySrcLoc,
184};
185
180pub const MemoizedCallSet = std.HashMapUnmanaged(186pub const MemoizedCallSet = std.HashMapUnmanaged(
181 MemoizedCall.Key,187 MemoizedCall.Key,
182 MemoizedCall.Result,188 MemoizedCall.Result,
src/Sema.zig+32-16
...@@ -1591,7 +1591,7 @@ fn resolveInt(...@@ -1591,7 +1591,7 @@ fn resolveInt(
1591 const coerced = try sema.coerce(block, dest_ty, air_inst, src);1591 const coerced = try sema.coerce(block, dest_ty, air_inst, src);
1592 const val = try sema.resolveConstValue(block, src, coerced);1592 const val = try sema.resolveConstValue(block, src, coerced);
1593 const target = sema.mod.getTarget();1593 const target = sema.mod.getTarget();
1594 return val.toUnsignedInt(target);1594 return (try val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?;
1595}1595}
15961596
1597// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for1597// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
...@@ -9926,7 +9926,7 @@ fn analyzePtrArithmetic(...@@ -9926,7 +9926,7 @@ fn analyzePtrArithmetic(
9926 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target));9926 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target));
9927 // TODO I tried to put this check earlier but it the LLVM backend generate invalid instructinons9927 // TODO I tried to put this check earlier but it the LLVM backend generate invalid instructinons
9928 if (offset_int == 0) return ptr;9928 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| {
9930 const ptr_child_ty = ptr_ty.childType();9930 const ptr_child_ty = ptr_ty.childType();
9931 const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array)9931 const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array)
9932 ptr_child_ty.childType()9932 ptr_child_ty.childType()
...@@ -11863,6 +11863,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -11863,6 +11863,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
11863 const elem_ty_src: LazySrcLoc = .unneeded;11863 const elem_ty_src: LazySrcLoc = .unneeded;
11864 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;11864 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
11865 const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);11865 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
11867 var extra_i = extra.end;11869 var extra_i = extra.end;
1186811870
...@@ -11872,10 +11874,19 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -11872,10 +11874,19 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
11872 break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;11874 break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;
11873 } else null;11875 } 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: {
11876 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);11878 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
11877 extra_i += 1;11879 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))).?;
11879 break :blk @intCast(u32, abi_align);11890 break :blk @intCast(u32, abi_align);
11880 } else 0;11891 } else 0;
1188111892
...@@ -11903,7 +11914,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -11903,7 +11914,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
11903 return sema.fail(block, src, "bit offset starts after end of host integer", .{});11914 return sema.fail(block, src, "bit offset starts after end of host integer", .{});
11904 }11915 }
1190511916
11906 const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type);
11907 const elem_ty = if (abi_align == 0)11917 const elem_ty = if (abi_align == 0)
11908 unresolved_elem_ty11918 unresolved_elem_ty
11909 else t: {11919 else t: {
...@@ -11911,7 +11921,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -11911,7 +11921,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
11911 try sema.resolveTypeLayout(block, elem_ty_src, elem_ty);11921 try sema.resolveTypeLayout(block, elem_ty_src, elem_ty);
11912 break :t elem_ty;11922 break :t elem_ty;
11913 };11923 };
11914 const target = sema.mod.getTarget();
11915 const ty = try Type.ptr(sema.arena, target, .{11924 const ty = try Type.ptr(sema.arena, target, .{
11916 .pointee_type = elem_ty,11925 .pointee_type = elem_ty,
11917 .sentinel = sentinel,11926 .sentinel = sentinel,
...@@ -18390,15 +18399,15 @@ fn storePtrVal(...@@ -18390,15 +18399,15 @@ fn storePtrVal(
18390 operand_val: Value,18399 operand_val: Value,
18391 operand_ty: Type,18400 operand_ty: Type,
18392) !void {18401) !void {
18393 var kit = try beginComptimePtrMutation(sema, block, src, ptr_val);18402 var mut_kit = try beginComptimePtrMutation(sema, block, src, ptr_val);
18394 try sema.checkComptimeVarStore(block, src, kit.decl_ref_mut);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);18407 const arena = mut_kit.beginArena(sema.gpa);
18399 defer kit.finishArena();18408 defer mut_kit.finishArena();
1840018409
18401 kit.val.* = try bitcasted_val.copy(arena);18410 mut_kit.val.* = try bitcasted_val.copy(arena);
18402}18411}
1840318412
18404const ComptimePtrMutationKit = struct {18413const ComptimePtrMutationKit = struct {
...@@ -19891,7 +19900,7 @@ fn cmpNumeric(...@@ -19891,7 +19900,7 @@ fn cmpNumeric(
19891 return Air.Inst.Ref.bool_false;19900 return Air.Inst.Ref.bool_false;
19892 }19901 }
19893 }19902 }
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))) {
19895 return Air.Inst.Ref.bool_true;19904 return Air.Inst.Ref.bool_true;
19896 } else {19905 } else {
19897 return Air.Inst.Ref.bool_false;19906 return Air.Inst.Ref.bool_false;
...@@ -20758,7 +20767,7 @@ pub fn resolveFnTypes(...@@ -20758,7 +20767,7 @@ pub fn resolveFnTypes(
20758 }20767 }
20759}20768}
2076020769
20761fn resolveTypeLayout(20770pub fn resolveTypeLayout(
20762 sema: *Sema,20771 sema: *Sema,
20763 block: *Block,20772 block: *Block,
20764 src: LazySrcLoc,20773 src: LazySrcLoc,
...@@ -20929,7 +20938,7 @@ fn resolveUnionFully(...@@ -20929,7 +20938,7 @@ fn resolveUnionFully(
20929 union_obj.status = .fully_resolved;20938 union_obj.status = .fully_resolved;
20930}20939}
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 {
20933 switch (ty.tag()) {20942 switch (ty.tag()) {
20934 .@"struct" => {20943 .@"struct" => {
20935 const struct_obj = ty.castTag(.@"struct").?.data;20944 const struct_obj = ty.castTag(.@"struct").?.data;
...@@ -22209,7 +22218,9 @@ fn typePtrOrOptionalPtrTy(...@@ -22209,7 +22218,9 @@ fn typePtrOrOptionalPtrTy(
22209/// This function returns false negatives when structs and unions are having their22218/// This function returns false negatives when structs and unions are having their
22210/// field types resolved.22219/// field types resolved.
22211/// TODO assert the return value matches `ty.comptimeOnly`22220/// 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 {
22213 return switch (ty.tag()) {22224 return switch (ty.tag()) {
22214 .u1,22225 .u1,
22215 .u8,22226 .u8,
...@@ -22415,6 +22426,7 @@ fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 {...@@ -22415,6 +22426,7 @@ fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 {
22415 return ty.abiSize(target);22426 return ty.abiSize(target);
22416}22427}
2241722428
22429/// TODO merge with Type.abiAlignmentAdvanced
22418fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32 {22430fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32 {
22419 try sema.resolveTypeLayout(block, src, ty);22431 try sema.resolveTypeLayout(block, src, ty);
22420 const target = sema.mod.getTarget();22432 const target = sema.mod.getTarget();
...@@ -22498,3 +22510,7 @@ fn anonStructFieldIndex(...@@ -22498,3 +22510,7 @@ fn anonStructFieldIndex(
22498 struct_ty.fmt(target), field_name,22510 struct_ty.fmt(target), field_name,
22499 });22511 });
22500}22512}
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 {...@@ -1483,20 +1483,29 @@ pub const Type = extern union {
1483 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");1483 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
1484 }1484 }
14851485
1486 pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(TypedValue.format) {1486 pub fn fmt(ty: Type, target: Target) std.fmt.Formatter(format2) {
1487 var ty_payload: Value.Payload.Ty = .{
1488 .base = .{ .tag = .ty },
1489 .data = ty,
1490 };
1491 return .{ .data = .{1487 return .{ .data = .{
1492 .tv = .{1488 .ty = ty,
1493 .ty = Type.type,
1494 .val = Value.initPayload(&ty_payload.base),
1495 },
1496 .target = target,1489 .target = target,
1497 } };1490 } };
1498 }1491 }
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
1500 pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {1509 pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {
1501 return .{ .data = ty };1510 return .{ .data = ty };
1502 }1511 }
...@@ -2241,8 +2250,12 @@ pub const Type = extern union {...@@ -2241,8 +2250,12 @@ pub const Type = extern union {
2241 /// * the type has only one possible value, making its ABI size 0.2250 /// * the type has only one possible value, making its ABI size 0.
2242 /// When `ignore_comptime_only` is true, then types that are comptime only2251 /// When `ignore_comptime_only` is true, then types that are comptime only
2243 /// may return false positives.2252 /// may return false positives.
2244 pub fn hasRuntimeBitsAdvanced(ty: Type, ignore_comptime_only: bool) bool {2253 pub fn hasRuntimeBitsAdvanced(
2245 return switch (ty.tag()) {2254 ty: Type,
2255 ignore_comptime_only: bool,
2256 sema_kit: ?Module.WipAnalysis,
2257 ) Module.CompileError!bool {
2258 switch (ty.tag()) {
2246 .u1,2259 .u1,
2247 .u8,2260 .u8,
2248 .i8,2261 .i8,
...@@ -2296,7 +2309,7 @@ pub const Type = extern union {...@@ -2296,7 +2309,7 @@ pub const Type = extern union {
2296 .@"anyframe",2309 .@"anyframe",
2297 .anyopaque,2310 .anyopaque,
2298 .@"opaque",2311 .@"opaque",
2299 => true,2312 => return true,
23002313
2301 // These are false because they are comptime-only types.2314 // These are false because they are comptime-only types.
2302 .single_const_pointer_to_comptime_int,2315 .single_const_pointer_to_comptime_int,
...@@ -2320,7 +2333,7 @@ pub const Type = extern union {...@@ -2320,7 +2333,7 @@ pub const Type = extern union {
2320 .fn_void_no_args,2333 .fn_void_no_args,
2321 .fn_naked_noreturn_no_args,2334 .fn_naked_noreturn_no_args,
2322 .fn_ccc_void_no_args,2335 .fn_ccc_void_no_args,
2323 => false,2336 => return false,
23242337
2325 // These types have more than one possible value, so the result is the same as2338 // These types have more than one possible value, so the result is the same as
2326 // asking whether they are comptime-only types.2339 // asking whether they are comptime-only types.
...@@ -2337,20 +2350,34 @@ pub const Type = extern union {...@@ -2337,20 +2350,34 @@ pub const Type = extern union {
2337 .const_slice,2350 .const_slice,
2338 .mut_slice,2351 .mut_slice,
2339 .pointer,2352 .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
2342 .@"struct" => {2363 .@"struct" => {
2343 const struct_obj = ty.castTag(.@"struct").?.data;2364 const struct_obj = ty.castTag(.@"struct").?.data;
2365 if (sema_kit) |sk| {
2366 _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty);
2367 }
2344 switch (struct_obj.requires_comptime) {2368 switch (struct_obj.requires_comptime) {
2345 .wip => unreachable,2369 .wip => unreachable,
2346 .yes => return false,2370 .yes => return false,
2347 .no => if (struct_obj.known_non_opv) return true,2371 .no => if (struct_obj.known_non_opv) return true,
2348 .unknown => {},2372 .unknown => {},
2349 }2373 }
2374 if (sema_kit) |sk| {
2375 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2376 }
2350 assert(struct_obj.haveFieldTypes());2377 assert(struct_obj.haveFieldTypes());
2351 for (struct_obj.fields.values()) |value| {2378 for (struct_obj.fields.values()) |value| {
2352 if (value.is_comptime) continue;2379 if (value.is_comptime) continue;
2353 if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))2380 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
2354 return true;2381 return true;
2355 } else {2382 } else {
2356 return false;2383 return false;
...@@ -2368,14 +2395,17 @@ pub const Type = extern union {...@@ -2368,14 +2395,17 @@ pub const Type = extern union {
2368 .enum_numbered, .enum_nonexhaustive => {2395 .enum_numbered, .enum_nonexhaustive => {
2369 var buffer: Payload.Bits = undefined;2396 var buffer: Payload.Bits = undefined;
2370 const int_tag_ty = ty.intTagType(&buffer);2397 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);
2372 },2399 },
23732400
2374 .@"union" => {2401 .@"union" => {
2375 const union_obj = ty.castTag(.@"union").?.data;2402 const union_obj = ty.castTag(.@"union").?.data;
2403 if (sema_kit) |sk| {
2404 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2405 }
2376 assert(union_obj.haveFieldTypes());2406 assert(union_obj.haveFieldTypes());
2377 for (union_obj.fields.values()) |value| {2407 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))
2379 return true;2409 return true;
2380 } else {2410 } else {
2381 return false;2411 return false;
...@@ -2383,29 +2413,32 @@ pub const Type = extern union {...@@ -2383,29 +2413,32 @@ pub const Type = extern union {
2383 },2413 },
2384 .union_tagged => {2414 .union_tagged => {
2385 const union_obj = ty.castTag(.union_tagged).?.data;2415 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)) {
2387 return true;2417 return true;
2388 }2418 }
2419 if (sema_kit) |sk| {
2420 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2421 }
2389 assert(union_obj.haveFieldTypes());2422 assert(union_obj.haveFieldTypes());
2390 for (union_obj.fields.values()) |value| {2423 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))
2392 return true;2425 return true;
2393 } else {2426 } else {
2394 return false;2427 return false;
2395 }2428 }
2396 },2429 },
23972430
2398 .array, .vector => ty.arrayLen() != 0 and2431 .array, .vector => return ty.arrayLen() != 0 and
2399 ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only),2432 try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit),
2400 .array_u8 => ty.arrayLen() != 0,2433 .array_u8 => return ty.arrayLen() != 0,
2401 .array_sentinel => ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only),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
2405 .error_union => {2438 .error_union => {
2406 const payload = ty.castTag(.error_union).?.data;2439 const payload = ty.castTag(.error_union).?.data;
2407 return payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only) or2440 return (try payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) or
2408 payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only);2441 (try payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit));
2409 },2442 },
24102443
2411 .tuple, .anon_struct => {2444 .tuple, .anon_struct => {
...@@ -2413,7 +2446,7 @@ pub const Type = extern union {...@@ -2413,7 +2446,7 @@ pub const Type = extern union {
2413 for (tuple.types) |field_ty, i| {2446 for (tuple.types) |field_ty, i| {
2414 const val = tuple.values[i];2447 const val = tuple.values[i];
2415 if (val.tag() != .unreachable_value) continue; // comptime field2448 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;
2417 }2450 }
2418 return false;2451 return false;
2419 },2452 },
...@@ -2422,7 +2455,7 @@ pub const Type = extern union {...@@ -2422,7 +2455,7 @@ pub const Type = extern union {
2422 .inferred_alloc_mut => unreachable,2455 .inferred_alloc_mut => unreachable,
2423 .var_args_param => unreachable,2456 .var_args_param => unreachable,
2424 .generic_poison => unreachable,2457 .generic_poison => unreachable,
2425 };2458 }
2426 }2459 }
24272460
2428 /// true if and only if the type has a well-defined memory layout2461 /// true if and only if the type has a well-defined memory layout
...@@ -2548,11 +2581,11 @@ pub const Type = extern union {...@@ -2548,11 +2581,11 @@ pub const Type = extern union {
2548 }2581 }
25492582
2550 pub fn hasRuntimeBits(ty: Type) bool {2583 pub fn hasRuntimeBits(ty: Type) bool {
2551 return hasRuntimeBitsAdvanced(ty, false);2584 return hasRuntimeBitsAdvanced(ty, false, null) catch unreachable;
2552 }2585 }
25532586
2554 pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {2587 pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {
2555 return hasRuntimeBitsAdvanced(ty, true);2588 return hasRuntimeBitsAdvanced(ty, true, null) catch unreachable;
2556 }2589 }
25572590
2558 pub fn isFnOrHasRuntimeBits(ty: Type) bool {2591 pub fn isFnOrHasRuntimeBits(ty: Type) bool {
...@@ -4538,6 +4571,8 @@ pub const Type = extern union {...@@ -4538,6 +4571,8 @@ pub const Type = extern union {
45384571
4539 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which4572 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
4540 /// resolves field types rather than asserting they are already resolved.4573 /// 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.
4541 pub fn comptimeOnly(ty: Type) bool {4576 pub fn comptimeOnly(ty: Type) bool {
4542 return switch (ty.tag()) {4577 return switch (ty.tag()) {
4543 .u1,4578 .u1,
src/value.zig+55-8
...@@ -9,6 +9,7 @@ const Allocator = std.mem.Allocator;...@@ -9,6 +9,7 @@ const Allocator = std.mem.Allocator;
9const Module = @import("Module.zig");9const Module = @import("Module.zig");
10const Air = @import("Air.zig");10const Air = @import("Air.zig");
11const TypedValue = @import("TypedValue.zig");11const TypedValue = @import("TypedValue.zig");
12const Sema = @import("Sema.zig");
1213
13/// This is the raw data, with no bookkeeping, no memory awareness,14/// This is the raw data, with no bookkeeping, no memory awareness,
14/// no de-duplication, and no type system awareness.15/// no de-duplication, and no type system awareness.
...@@ -990,6 +991,16 @@ pub const Value = extern union {...@@ -990,6 +991,16 @@ pub const Value = extern union {
990991
991 /// Asserts the value is an integer.992 /// Asserts the value is an integer.
992 pub fn toBigInt(val: Value, space: *BigIntSpace, target: Target) BigIntConst {993 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 {
993 switch (val.tag()) {1004 switch (val.tag()) {
994 .zero,1005 .zero,
995 .bool_false,1006 .bool_false,
...@@ -1008,7 +1019,11 @@ pub const Value = extern union {...@@ -1008,7 +1019,11 @@ pub const Value = extern union {
1008 .undef => unreachable,1019 .undef => unreachable,
10091020
1010 .lazy_align => {1021 .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);
1012 return BigIntMutable.init(&space.limbs, x).toConst();1027 return BigIntMutable.init(&space.limbs, x).toConst();
1013 },1028 },
10141029
...@@ -1019,6 +1034,12 @@ pub const Value = extern union {...@@ -1019,6 +1034,12 @@ pub const Value = extern union {
1019 /// If the value fits in a u64, return it, otherwise null.1034 /// If the value fits in a u64, return it, otherwise null.
1020 /// Asserts not undefined.1035 /// Asserts not undefined.
1021 pub fn getUnsignedInt(val: Value, target: Target) ?u64 {1036 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 {
1022 switch (val.tag()) {1043 switch (val.tag()) {
1023 .zero,1044 .zero,
1024 .bool_false,1045 .bool_false,
...@@ -1036,7 +1057,13 @@ pub const Value = extern union {...@@ -1036,7 +1057,13 @@ pub const Value = extern union {
10361057
1037 .undef => unreachable,1058 .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
1041 else => return null,1068 else => return null,
1042 }1069 }
...@@ -1777,6 +1804,10 @@ pub const Value = extern union {...@@ -1777,6 +1804,10 @@ pub const Value = extern union {
1777 }1804 }
17781805
1779 pub fn orderAgainstZero(lhs: Value) std.math.Order {1806 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 {
1780 return switch (lhs.tag()) {1811 return switch (lhs.tag()) {
1781 .zero,1812 .zero,
1782 .bool_false,1813 .bool_false,
...@@ -1799,7 +1830,7 @@ pub const Value = extern union {...@@ -1799,7 +1830,7 @@ pub const Value = extern union {
17991830
1800 .lazy_align => {1831 .lazy_align => {
1801 const ty = lhs.castTag(.lazy_align).?.data;1832 const ty = lhs.castTag(.lazy_align).?.data;
1802 if (ty.hasRuntimeBitsIgnoreComptime()) {1833 if (try ty.hasRuntimeBitsAdvanced(false, sema_kit)) {
1803 return .gt;1834 return .gt;
1804 } else {1835 } else {
1805 return .eq;1836 return .eq;
...@@ -1818,10 +1849,16 @@ pub const Value = extern union {...@@ -1818,10 +1849,16 @@ pub const Value = extern union {
18181849
1819 /// Asserts the value is comparable.1850 /// Asserts the value is comparable.
1820 pub fn order(lhs: Value, rhs: Value, target: Target) std.math.Order {1851 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 {
1821 const lhs_tag = lhs.tag();1858 const lhs_tag = lhs.tag();
1822 const rhs_tag = rhs.tag();1859 const rhs_tag = rhs.tag();
1823 const lhs_against_zero = lhs.orderAgainstZero();1860 const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(sema_kit);
1824 const rhs_against_zero = rhs.orderAgainstZero();1861 const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(sema_kit);
1825 switch (lhs_against_zero) {1862 switch (lhs_against_zero) {
1826 .lt => if (rhs_against_zero != .lt) return .lt,1863 .lt => if (rhs_against_zero != .lt) return .lt,
1827 .eq => return rhs_against_zero.invert(),1864 .eq => return rhs_against_zero.invert(),
...@@ -1855,14 +1892,24 @@ pub const Value = extern union {...@@ -1855,14 +1892,24 @@ pub const Value = extern union {
18551892
1856 var lhs_bigint_space: BigIntSpace = undefined;1893 var lhs_bigint_space: BigIntSpace = undefined;
1857 var rhs_bigint_space: BigIntSpace = undefined;1894 var rhs_bigint_space: BigIntSpace = undefined;
1858 const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, target);1895 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, target, sema_kit);
1859 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, target);1896 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, target, sema_kit);
1860 return lhs_bigint.order(rhs_bigint);1897 return lhs_bigint.order(rhs_bigint);
1861 }1898 }
18621899
1863 /// Asserts the value is comparable. Does not take a type parameter because it supports1900 /// Asserts the value is comparable. Does not take a type parameter because it supports
1864 /// comparisons between heterogeneous types.1901 /// comparisons between heterogeneous types.
1865 pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, target: Target) bool {1902 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 {
1866 if (lhs.pointerDecl()) |lhs_decl| {1913 if (lhs.pointerDecl()) |lhs_decl| {
1867 if (rhs.pointerDecl()) |rhs_decl| {1914 if (rhs.pointerDecl()) |rhs_decl| {
1868 switch (op) {1915 switch (op) {
...@@ -1884,7 +1931,7 @@ pub const Value = extern union {...@@ -1884,7 +1931,7 @@ pub const Value = extern union {
1884 else => {},1931 else => {},
1885 }1932 }
1886 }1933 }
1887 return order(lhs, rhs, target).compare(op);1934 return (try orderAdvanced(lhs, rhs, target, sema_kit)).compare(op);
1888 }1935 }
18891936
1890 /// Asserts the values are comparable. Both operands have type `ty`.1937 /// Asserts the values are comparable. Both operands have type `ty`.
test/behavior/struct_contains_slice_of_itself.zig+9
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const expect = @import("std").testing.expect;2const expect = @import("std").testing.expect;
23
3const Node = struct {4const Node = struct {
...@@ -11,6 +12,10 @@ const NodeAligned = struct {...@@ -11,6 +12,10 @@ const NodeAligned = struct {
11};12};
1213
13test "struct contains slice of itself" {14test "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
14 var other_nodes = [_]Node{19 var other_nodes = [_]Node{
15 Node{20 Node{
16 .payload = 31,21 .payload = 31,
...@@ -48,6 +53,10 @@ test "struct contains slice of itself" {...@@ -48,6 +53,10 @@ test "struct contains slice of itself" {
48}53}
4954
50test "struct contains aligned slice of itself" {55test "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
51 var other_nodes = [_]NodeAligned{60 var other_nodes = [_]NodeAligned{
52 NodeAligned{61 NodeAligned{
53 .payload = 31,62 .payload = 31,