authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-26 03:56:54+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-26 13:48:06+00:00
log152a2ceaf738301cd59165a4f17d915391321bdc
treef2239a36d9d2ce92bfaf34742620ce74ec7defb5
parent884d957b6c291961536c10401f60264da26cba30
signaturelock-open Commit is signed but in an unrecognized format.

compiler: audit uses of `ptr.addr` in the frontend

This commit also performs some refactors to `TypedValue.print` in preparation for improved comptime pointer access logic. Once that logic exists, `TypedValue.print` can use Sema to access pointers for more helpful printing. This commit also implements proposal #19435, because the existing logic there relied on some blatantly incorrect code in `Value.sliceLen`. Resolves: #19435

4 files changed, 406 insertions(+), 467 deletions(-)

src/Sema.zig+112-80
...@@ -1881,10 +1881,10 @@ pub fn toConstString(...@@ -1881,10 +1881,10 @@ pub fn toConstString(
1881 air_inst: Air.Inst.Ref,1881 air_inst: Air.Inst.Ref,
1882 reason: NeededComptimeReason,1882 reason: NeededComptimeReason,
1883) ![]u8 {1883) ![]u8 {
1884 const wanted_type = Type.slice_const_u8;1884 const coerced_inst = try sema.coerce(block, Type.slice_const_u8, air_inst, src);
1885 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);1885 const slice_val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason);
1886 const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason);1886 const arr_val = try sema.derefSliceAsArray(block, src, slice_val, reason);
1887 return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod);1887 return arr_val.toAllocatedBytes(arr_val.typeOf(sema.mod), sema.arena, sema.mod);
1888}1888}
18891889
1890pub fn resolveConstStringIntern(1890pub fn resolveConstStringIntern(
...@@ -14498,12 +14498,16 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14498,12 +14498,16 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14498 else => unreachable,14498 else => unreachable,
14499 }) |rhs_val| {14499 }) |rhs_val| {
14500 const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))14500 const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))
14501 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?14501 try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :rs lhs_src
14502 else if (lhs_ty.isSlice(mod))
14503 try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :rs lhs_src
14502 else14504 else
14503 lhs_val;14505 lhs_val;
1450414506
14505 const rhs_sub_val = if (rhs_ty.isSinglePointer(mod))14507 const rhs_sub_val = if (rhs_ty.isSinglePointer(mod))
14506 (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).?14508 try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty) orelse break :rs rhs_src
14509 else if (rhs_ty.isSlice(mod))
14510 try sema.maybeDerefSliceAsArray(block, rhs_src, rhs_val) orelse break :rs rhs_src
14507 else14511 else
14508 rhs_val;14512 rhs_val;
1450914513
...@@ -14623,10 +14627,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins...@@ -14623,10 +14627,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
14623 .Pointer => {14627 .Pointer => {
14624 const ptr_info = operand_ty.ptrInfo(mod);14628 const ptr_info = operand_ty.ptrInfo(mod);
14625 switch (ptr_info.flags.size) {14629 switch (ptr_info.flags.size) {
14626 // TODO: in the Many case here this should only work if the type14630 .Slice => {
14627 // has a sentinel, and this code should compute the length based
14628 // on the sentinel value.
14629 .Slice, .Many => {
14630 const val = try sema.resolveConstDefinedValue(block, src, operand, .{14631 const val = try sema.resolveConstDefinedValue(block, src, operand, .{
14631 .needed_comptime_reason = "slice value being concatenated must be comptime-known",14632 .needed_comptime_reason = "slice value being concatenated must be comptime-known",
14632 });14633 });
...@@ -14636,7 +14637,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins...@@ -14636,7 +14637,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
14636 .none => null,14637 .none => null,
14637 else => Value.fromInterned(ptr_info.sentinel),14638 else => Value.fromInterned(ptr_info.sentinel),
14638 },14639 },
14639 .len = val.sliceLen(mod),14640 .len = try val.sliceLen(sema),
14640 };14641 };
14641 },14642 },
14642 .One => {14643 .One => {
...@@ -14644,7 +14645,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins...@@ -14644,7 +14645,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
14644 return Type.fromInterned(ptr_info.child).arrayInfo(mod);14645 return Type.fromInterned(ptr_info.child).arrayInfo(mod);
14645 }14646 }
14646 },14647 },
14647 .C => {},14648 .C, .Many => {},
14648 }14649 }
14649 },14650 },
14650 .Struct => {14651 .Struct => {
...@@ -14830,9 +14831,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14830,9 +14831,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14830 const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null;14831 const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null;
14831 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);14832 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
1483214833
14833 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {14834 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| ct: {
14834 const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))14835 const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))
14835 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?14836 try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :ct
14837 else if (lhs_ty.isSlice(mod))
14838 try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :ct
14836 else14839 else
14837 lhs_val;14840 lhs_val;
1483814841
...@@ -14840,7 +14843,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14840,7 +14843,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14840 // Optimization for the common pattern of a single element repeated N times, such14843 // Optimization for the common pattern of a single element repeated N times, such
14841 // as zero-filling a byte array.14844 // as zero-filling a byte array.
14842 if (lhs_len == 1 and lhs_info.sentinel == null) {14845 if (lhs_len == 1 and lhs_info.sentinel == null) {
14843 const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, 0)).?;14846 const elem_val = try lhs_sub_val.elemValue(mod, 0);
14844 break :v try mod.intern(.{ .aggregate = .{14847 break :v try mod.intern(.{ .aggregate = .{
14845 .ty = result_ty.toIntern(),14848 .ty = result_ty.toIntern(),
14846 .storage = .{ .repeated_elem = elem_val.toIntern() },14849 .storage = .{ .repeated_elem = elem_val.toIntern() },
...@@ -14852,7 +14855,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14852,7 +14855,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14852 while (elem_i < result_len) {14855 while (elem_i < result_len) {
14853 var lhs_i: usize = 0;14856 var lhs_i: usize = 0;
14854 while (lhs_i < lhs_len) : (lhs_i += 1) {14857 while (lhs_i < lhs_len) : (lhs_i += 1) {
14855 const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, lhs_i)).?;14858 const elem_val = try lhs_sub_val.elemValue(mod, lhs_i);
14856 element_vals[elem_i] = elem_val.toIntern();14859 element_vals[elem_i] = elem_val.toIntern();
14857 elem_i += 1;14860 elem_i += 1;
14858 }14861 }
...@@ -21124,7 +21127,9 @@ fn zirReify(...@@ -21124,7 +21127,9 @@ fn zirReify(
21124 .needed_comptime_reason = "operand to @Type must be comptime-known",21127 .needed_comptime_reason = "operand to @Type must be comptime-known",
21125 });21128 });
21126 const union_val = ip.indexToKey(val.toIntern()).un;21129 const union_val = ip.indexToKey(val.toIntern()).un;
21127 if (try sema.anyUndef(Value.fromInterned(union_val.val))) return sema.failWithUseOfUndef(block, src);21130 if (try sema.anyUndef(block, operand_src, Value.fromInterned(union_val.val))) {
21131 return sema.failWithUseOfUndef(block, operand_src);
21132 }
21128 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;21133 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;
21129 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {21134 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
21130 .Type => return .type_type,21135 .Type => return .type_type,
...@@ -21365,11 +21370,15 @@ fn zirReify(...@@ -21365,11 +21370,15 @@ fn zirReify(
21365 const payload_val = Value.fromInterned(union_val.val).optionalValue(mod) orelse21370 const payload_val = Value.fromInterned(union_val.val).optionalValue(mod) orelse
21366 return Air.internedToRef(Type.anyerror.toIntern());21371 return Air.internedToRef(Type.anyerror.toIntern());
2136721372
21368 const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod));21373 const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{
21374 .needed_comptime_reason = "error set contents must be comptime-known",
21375 });
21376
21377 const len = try sema.usizeCast(block, src, names_val.typeOf(mod).arrayLen(mod));
21369 var names: InferredErrorSet.NameMap = .{};21378 var names: InferredErrorSet.NameMap = .{};
21370 try names.ensureUnusedCapacity(sema.arena, len);21379 try names.ensureUnusedCapacity(sema.arena, len);
21371 for (0..len) |i| {21380 for (0..len) |i| {
21372 const elem_val = (try payload_val.maybeElemValueFull(sema, mod, i)).?;21381 const elem_val = try names_val.elemValue(mod, i);
21373 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));21382 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
21374 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(21383 const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21375 ip,21384 ip,
...@@ -21417,7 +21426,7 @@ fn zirReify(...@@ -21417,7 +21426,7 @@ fn zirReify(
21417 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);21426 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
2141821427
21419 // Decls21428 // Decls
21420 if (decls_val.sliceLen(mod) > 0) {21429 if (try decls_val.sliceLen(sema) > 0) {
21421 return sema.fail(block, src, "reified structs must have no decls", .{});21430 return sema.fail(block, src, "reified structs must have no decls", .{});
21422 }21431 }
2142321432
...@@ -21425,7 +21434,11 @@ fn zirReify(...@@ -21425,7 +21434,11 @@ fn zirReify(
21425 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});21434 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
21426 }21435 }
2142721436
21428 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());21437 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{
21438 .needed_comptime_reason = "struct fields must be comptime-known",
21439 });
21440
21441 return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy, is_tuple_val.toBool());
21429 },21442 },
21430 .Enum => {21443 .Enum => {
21431 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));21444 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
...@@ -21446,11 +21459,15 @@ fn zirReify(...@@ -21446,11 +21459,15 @@ fn zirReify(
21446 try ip.getOrPutString(gpa, "is_exhaustive"),21459 try ip.getOrPutString(gpa, "is_exhaustive"),
21447 ).?);21460 ).?);
2144821461
21449 if (decls_val.sliceLen(mod) > 0) {21462 if (try decls_val.sliceLen(sema) > 0) {
21450 return sema.fail(block, src, "reified enums must have no decls", .{});21463 return sema.fail(block, src, "reified enums must have no decls", .{});
21451 }21464 }
2145221465
21453 return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_val, name_strategy);21466 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{
21467 .needed_comptime_reason = "enum fields must be comptime-known",
21468 });
21469
21470 return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy);
21454 },21471 },
21455 .Opaque => {21472 .Opaque => {
21456 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));21473 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
...@@ -21460,7 +21477,7 @@ fn zirReify(...@@ -21460,7 +21477,7 @@ fn zirReify(
21460 ).?);21477 ).?);
2146121478
21462 // Decls21479 // Decls
21463 if (decls_val.sliceLen(mod) > 0) {21480 if (try decls_val.sliceLen(sema) > 0) {
21464 return sema.fail(block, src, "reified opaque must have no decls", .{});21481 return sema.fail(block, src, "reified opaque must have no decls", .{});
21465 }21482 }
2146621483
...@@ -21505,12 +21522,16 @@ fn zirReify(...@@ -21505,12 +21522,16 @@ fn zirReify(
21505 try ip.getOrPutString(gpa, "decls"),21522 try ip.getOrPutString(gpa, "decls"),
21506 ).?);21523 ).?);
2150721524
21508 if (decls_val.sliceLen(mod) > 0) {21525 if (try decls_val.sliceLen(sema) > 0) {
21509 return sema.fail(block, src, "reified unions must have no decls", .{});21526 return sema.fail(block, src, "reified unions must have no decls", .{});
21510 }21527 }
21511 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);21528 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
2151221529
21513 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_val, name_strategy);21530 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{
21531 .needed_comptime_reason = "union fields must be comptime-known",
21532 });
21533
21534 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
21514 },21535 },
21515 .Fn => {21536 .Fn => {
21516 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));21537 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
...@@ -21530,7 +21551,7 @@ fn zirReify(...@@ -21530,7 +21551,7 @@ fn zirReify(
21530 ip,21551 ip,
21531 try ip.getOrPutString(gpa, "return_type"),21552 try ip.getOrPutString(gpa, "return_type"),
21532 ).?);21553 ).?);
21533 const params_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21554 const params_slice_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21534 ip,21555 ip,
21535 try ip.getOrPutString(gpa, "params"),21556 try ip.getOrPutString(gpa, "params"),
21536 ).?);21557 ).?);
...@@ -21549,12 +21570,16 @@ fn zirReify(...@@ -21549,12 +21570,16 @@ fn zirReify(
21549 const return_type = return_type_val.optionalValue(mod) orelse21570 const return_type = return_type_val.optionalValue(mod) orelse
21550 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});21571 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
2155121572
21552 const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod));21573 const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{
21574 .needed_comptime_reason = "function parameters must be comptime-known",
21575 });
21576
21577 const args_len = try sema.usizeCast(block, src, params_val.typeOf(mod).arrayLen(mod));
21553 const param_types = try sema.arena.alloc(InternPool.Index, args_len);21578 const param_types = try sema.arena.alloc(InternPool.Index, args_len);
2155421579
21555 var noalias_bits: u32 = 0;21580 var noalias_bits: u32 = 0;
21556 for (param_types, 0..) |*param_type, i| {21581 for (param_types, 0..) |*param_type, i| {
21557 const elem_val = (try params_val.maybeElemValueFull(sema, mod, i)).?;21582 const elem_val = try params_val.elemValue(mod, i);
21558 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));21583 const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
21559 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(21584 const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
21560 ip,21585 ip,
...@@ -21615,7 +21640,7 @@ fn reifyEnum(...@@ -21615,7 +21640,7 @@ fn reifyEnum(
2161521640
21616 // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.21641 // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.
2161721642
21618 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));21643 const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod));
2161921644
21620 // The validation work here is non-trivial, and it's possible the type already exists.21645 // The validation work here is non-trivial, and it's possible the type already exists.
21621 // So in this first pass, let's just construct a hash to optimize for this case. If the21646 // So in this first pass, let's just construct a hash to optimize for this case. If the
...@@ -21629,7 +21654,7 @@ fn reifyEnum(...@@ -21629,7 +21654,7 @@ fn reifyEnum(
21629 std.hash.autoHash(&hasher, fields_len);21654 std.hash.autoHash(&hasher, fields_len);
2163021655
21631 for (0..fields_len) |field_idx| {21656 for (0..fields_len) |field_idx| {
21632 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;21657 const field_info = try fields_val.elemValue(mod, field_idx);
2163321658
21634 const field_name_val = try field_info.fieldValue(mod, 0);21659 const field_name_val = try field_info.fieldValue(mod, 0);
21635 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));21660 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
...@@ -21674,7 +21699,7 @@ fn reifyEnum(...@@ -21674,7 +21699,7 @@ fn reifyEnum(
21674 wip_ty.setTagTy(ip, tag_ty.toIntern());21699 wip_ty.setTagTy(ip, tag_ty.toIntern());
2167521700
21676 for (0..fields_len) |field_idx| {21701 for (0..fields_len) |field_idx| {
21677 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;21702 const field_info = try fields_val.elemValue(mod, field_idx);
2167821703
21679 const field_name_val = try field_info.fieldValue(mod, 0);21704 const field_name_val = try field_info.fieldValue(mod, 0);
21680 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));21705 const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
...@@ -21736,7 +21761,7 @@ fn reifyUnion(...@@ -21736,7 +21761,7 @@ fn reifyUnion(
2173621761
21737 // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`.21762 // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`.
2173821763
21739 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));21764 const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod));
2174021765
21741 // The validation work here is non-trivial, and it's possible the type already exists.21766 // The validation work here is non-trivial, and it's possible the type already exists.
21742 // So in this first pass, let's just construct a hash to optimize for this case. If the21767 // So in this first pass, let's just construct a hash to optimize for this case. If the
...@@ -21752,7 +21777,7 @@ fn reifyUnion(...@@ -21752,7 +21777,7 @@ fn reifyUnion(
21752 var any_aligns = false;21777 var any_aligns = false;
2175321778
21754 for (0..fields_len) |field_idx| {21779 for (0..fields_len) |field_idx| {
21755 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;21780 const field_info = try fields_val.elemValue(mod, field_idx);
2175621781
21757 const field_name_val = try field_info.fieldValue(mod, 0);21782 const field_name_val = try field_info.fieldValue(mod, 0);
21758 const field_type_val = try field_info.fieldValue(mod, 1);21783 const field_type_val = try field_info.fieldValue(mod, 1);
...@@ -21828,7 +21853,7 @@ fn reifyUnion(...@@ -21828,7 +21853,7 @@ fn reifyUnion(
21828 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);21853 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
2182921854
21830 for (field_types, 0..) |*field_ty, field_idx| {21855 for (field_types, 0..) |*field_ty, field_idx| {
21831 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;21856 const field_info = try fields_val.elemValue(mod, field_idx);
2183221857
21833 const field_name_val = try field_info.fieldValue(mod, 0);21858 const field_name_val = try field_info.fieldValue(mod, 0);
21834 const field_type_val = try field_info.fieldValue(mod, 1);21859 const field_type_val = try field_info.fieldValue(mod, 1);
...@@ -21880,7 +21905,7 @@ fn reifyUnion(...@@ -21880,7 +21905,7 @@ fn reifyUnion(
21880 try field_names.ensureTotalCapacity(sema.arena, fields_len);21905 try field_names.ensureTotalCapacity(sema.arena, fields_len);
2188121906
21882 for (field_types, 0..) |*field_ty, field_idx| {21907 for (field_types, 0..) |*field_ty, field_idx| {
21883 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;21908 const field_info = try fields_val.elemValue(mod, field_idx);
2188421909
21885 const field_name_val = try field_info.fieldValue(mod, 0);21910 const field_name_val = try field_info.fieldValue(mod, 0);
21886 const field_type_val = try field_info.fieldValue(mod, 1);21911 const field_type_val = try field_info.fieldValue(mod, 1);
...@@ -21974,7 +21999,7 @@ fn reifyStruct(...@@ -21974,7 +21999,7 @@ fn reifyStruct(
2197421999
21975 // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`.22000 // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`.
2197622001
21977 const fields_len: u32 = @intCast(fields_val.sliceLen(mod));22002 const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod));
2197822003
21979 // The validation work here is non-trivial, and it's possible the type already exists.22004 // The validation work here is non-trivial, and it's possible the type already exists.
21980 // So in this first pass, let's just construct a hash to optimize for this case. If the22005 // So in this first pass, let's just construct a hash to optimize for this case. If the
...@@ -21993,7 +22018,7 @@ fn reifyStruct(...@@ -21993,7 +22018,7 @@ fn reifyStruct(
21993 var any_aligned_fields = false;22018 var any_aligned_fields = false;
2199422019
21995 for (0..fields_len) |field_idx| {22020 for (0..fields_len) |field_idx| {
21996 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;22021 const field_info = try fields_val.elemValue(mod, field_idx);
2199722022
21998 const field_name_val = try field_info.fieldValue(mod, 0);22023 const field_name_val = try field_info.fieldValue(mod, 0);
21999 const field_type_val = try field_info.fieldValue(mod, 1);22024 const field_type_val = try field_info.fieldValue(mod, 1);
...@@ -22071,7 +22096,7 @@ fn reifyStruct(...@@ -22071,7 +22096,7 @@ fn reifyStruct(
22071 const struct_type = ip.loadStructType(wip_ty.index);22096 const struct_type = ip.loadStructType(wip_ty.index);
2207222097
22073 for (0..fields_len) |field_idx| {22098 for (0..fields_len) |field_idx| {
22074 const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?;22099 const field_info = try fields_val.elemValue(mod, field_idx);
2207522100
22076 const field_name_val = try field_info.fieldValue(mod, 0);22101 const field_name_val = try field_info.fieldValue(mod, 0);
22077 const field_type_val = try field_info.fieldValue(mod, 1);22102 const field_type_val = try field_info.fieldValue(mod, 1);
...@@ -23892,11 +23917,9 @@ fn resolveExportOptions(...@@ -23892,11 +23917,9 @@ fn resolveExportOptions(
23892 const visibility_src = sema.maybeOptionsSrc(block, src, "visibility");23917 const visibility_src = sema.maybeOptionsSrc(block, src, "visibility");
2389323918
23894 const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);23919 const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);
23895 const name_val = try sema.resolveConstDefinedValue(block, name_src, name_operand, .{23920 const name = try sema.toConstString(block, name_src, name_operand, .{
23896 .needed_comptime_reason = "name of exported value must be comptime-known",23921 .needed_comptime_reason = "name of exported value must be comptime-known",
23897 });23922 });
23898 const name_ty = Type.slice_const_u8;
23899 const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod);
2390023923
23901 const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src);23924 const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src);
23902 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{23925 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{
...@@ -23908,9 +23931,10 @@ fn resolveExportOptions(...@@ -23908,9 +23931,10 @@ fn resolveExportOptions(
23908 const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{23931 const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{
23909 .needed_comptime_reason = "linksection of exported value must be comptime-known",23932 .needed_comptime_reason = "linksection of exported value must be comptime-known",
23910 });23933 });
23911 const section_ty = Type.slice_const_u8;
23912 const section = if (section_opt_val.optionalValue(mod)) |section_val|23934 const section = if (section_opt_val.optionalValue(mod)) |section_val|
23913 try section_val.toAllocatedBytes(section_ty, sema.arena, mod)23935 try sema.toConstString(block, section_src, Air.internedToRef(section_val.toIntern()), .{
23936 .needed_comptime_reason = "linksection of exported value must be comptime-known",
23937 })
23914 else23938 else
23915 null;23939 null;
2391623940
...@@ -26028,10 +26052,9 @@ fn resolveExternOptions(...@@ -26028,10 +26052,9 @@ fn resolveExternOptions(
26028 const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local");26052 const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local");
2602926053
26030 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);26054 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);
26031 const name_val = try sema.resolveConstDefinedValue(block, name_src, name_ref, .{26055 const name = try sema.toConstString(block, name_src, name_ref, .{
26032 .needed_comptime_reason = "name of the extern symbol must be comptime-known",26056 .needed_comptime_reason = "name of the extern symbol must be comptime-known",
26033 });26057 });
26034 const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);
2603526058
26036 const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src);26059 const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src);
26037 const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{26060 const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{
...@@ -26050,7 +26073,9 @@ fn resolveExternOptions(...@@ -26050,7 +26073,9 @@ fn resolveExternOptions(
26050 });26073 });
2605126074
26052 const library_name = if (library_name_val.optionalValue(mod)) |library_name_payload| library_name: {26075 const library_name = if (library_name_val.optionalValue(mod)) |library_name_payload| library_name: {
26053 const library_name = try library_name_payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);26076 const library_name = try sema.toConstString(block, library_src, Air.internedToRef(library_name_payload.toIntern()), .{
26077 .needed_comptime_reason = "library in which extern symbol is must be comptime-known",
26078 });
26054 if (library_name.len == 0) {26079 if (library_name.len == 0) {
26055 return sema.fail(block, library_src, "library name cannot be empty", .{});26080 return sema.fail(block, library_src, "library name cannot be empty", .{});
26056 }26081 }
...@@ -28564,7 +28589,7 @@ fn elemValSlice(...@@ -28564,7 +28589,7 @@ fn elemValSlice(
2856428589
28565 if (maybe_slice_val) |slice_val| {28590 if (maybe_slice_val) |slice_val| {
28566 runtime_src = elem_index_src;28591 runtime_src = elem_index_src;
28567 const slice_len = slice_val.sliceLen(mod);28592 const slice_len = try slice_val.sliceLen(sema);
28568 const slice_len_s = slice_len + @intFromBool(slice_sent);28593 const slice_len_s = slice_len + @intFromBool(slice_sent);
28569 if (slice_len_s == 0) {28594 if (slice_len_s == 0) {
28570 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});28595 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
...@@ -28589,7 +28614,7 @@ fn elemValSlice(...@@ -28589,7 +28614,7 @@ fn elemValSlice(
28589 try sema.requireRuntimeBlock(block, src, runtime_src);28614 try sema.requireRuntimeBlock(block, src, runtime_src);
28590 if (oob_safety and block.wantSafety()) {28615 if (oob_safety and block.wantSafety()) {
28591 const len_inst = if (maybe_slice_val) |slice_val|28616 const len_inst = if (maybe_slice_val) |slice_val|
28592 try mod.intRef(Type.usize, slice_val.sliceLen(mod))28617 try mod.intRef(Type.usize, try slice_val.sliceLen(sema))
28593 else28618 else
28594 try block.addTyOp(.slice_len, Type.usize, slice);28619 try block.addTyOp(.slice_len, Type.usize, slice);
28595 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;28620 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
...@@ -28626,7 +28651,7 @@ fn elemPtrSlice(...@@ -28626,7 +28651,7 @@ fn elemPtrSlice(
28626 if (slice_val.isUndef(mod)) {28651 if (slice_val.isUndef(mod)) {
28627 return mod.undefRef(elem_ptr_ty);28652 return mod.undefRef(elem_ptr_ty);
28628 }28653 }
28629 const slice_len = slice_val.sliceLen(mod);28654 const slice_len = try slice_val.sliceLen(sema);
28630 const slice_len_s = slice_len + @intFromBool(slice_sent);28655 const slice_len_s = slice_len + @intFromBool(slice_sent);
28631 if (slice_len_s == 0) {28656 if (slice_len_s == 0) {
28632 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});28657 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
...@@ -28649,7 +28674,7 @@ fn elemPtrSlice(...@@ -28649,7 +28674,7 @@ fn elemPtrSlice(
28649 const len_inst = len: {28674 const len_inst = len: {
28650 if (maybe_undef_slice_val) |slice_val|28675 if (maybe_undef_slice_val) |slice_val|
28651 if (!slice_val.isUndef(mod))28676 if (!slice_val.isUndef(mod))
28652 break :len try mod.intRef(Type.usize, slice_val.sliceLen(mod));28677 break :len try mod.intRef(Type.usize, try slice_val.sliceLen(sema));
28653 break :len try block.addTyOp(.slice_len, Type.usize, slice);28678 break :len try block.addTyOp(.slice_len, Type.usize, slice);
28654 };28679 };
28655 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;28680 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
...@@ -31523,16 +31548,11 @@ fn coerceArrayPtrToSlice(...@@ -31523,16 +31548,11 @@ fn coerceArrayPtrToSlice(
31523 if (try sema.resolveValue(inst)) |val| {31548 if (try sema.resolveValue(inst)) |val| {
31524 const ptr_array_ty = sema.typeOf(inst);31549 const ptr_array_ty = sema.typeOf(inst);
31525 const array_ty = ptr_array_ty.childType(mod);31550 const array_ty = ptr_array_ty.childType(mod);
31551 const slice_ptr_ty = dest_ty.slicePtrFieldType(mod);
31552 const slice_ptr = try mod.getCoerced(val, slice_ptr_ty);
31526 const slice_val = try mod.intern(.{ .slice = .{31553 const slice_val = try mod.intern(.{ .slice = .{
31527 .ty = dest_ty.toIntern(),31554 .ty = dest_ty.toIntern(),
31528 .ptr = try mod.intern(.{ .ptr = .{31555 .ptr = slice_ptr.toIntern(),
31529 .ty = dest_ty.slicePtrFieldType(mod).toIntern(),
31530 .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) {
31531 .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) },
31532 .ptr => |ptr| ptr.addr,
31533 else => unreachable,
31534 },
31535 } }),
31536 .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(),31556 .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(),
31537 } });31557 } });
31538 return Air.internedToRef(slice_val);31558 return Air.internedToRef(slice_val);
...@@ -32602,7 +32622,7 @@ fn analyzeSliceLen(...@@ -32602,7 +32622,7 @@ fn analyzeSliceLen(
32602 if (slice_val.isUndef(mod)) {32622 if (slice_val.isUndef(mod)) {
32603 return mod.undefRef(Type.usize);32623 return mod.undefRef(Type.usize);
32604 }32624 }
32605 return mod.intRef(Type.usize, slice_val.sliceLen(sema.mod));32625 return mod.intRef(Type.usize, try slice_val.sliceLen(sema));
32606 }32626 }
32607 try sema.requireRuntimeBlock(block, src, null);32627 try sema.requireRuntimeBlock(block, src, null);
32608 return block.addTyOp(.slice_len, Type.usize, slice_inst);32628 return block.addTyOp(.slice_len, Type.usize, slice_inst);
...@@ -33041,7 +33061,7 @@ fn analyzeSlice(...@@ -33041,7 +33061,7 @@ fn analyzeSlice(
33041 return sema.fail(block, src, "slice of undefined", .{});33061 return sema.fail(block, src, "slice of undefined", .{});
33042 }33062 }
33043 const has_sentinel = slice_ty.sentinel(mod) != null;33063 const has_sentinel = slice_ty.sentinel(mod) != null;
33044 const slice_len = slice_val.sliceLen(mod);33064 const slice_len = try slice_val.sliceLen(sema);
33045 const len_plus_sent = slice_len + @intFromBool(has_sentinel);33065 const len_plus_sent = slice_len + @intFromBool(has_sentinel);
33046 const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent);33066 const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent);
33047 if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) {33067 if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) {
...@@ -33056,7 +33076,7 @@ fn analyzeSlice(...@@ -33056,7 +33076,7 @@ fn analyzeSlice(
33056 "end index {} out of bounds for slice of length {d}{s}",33076 "end index {} out of bounds for slice of length {d}{s}",
33057 .{33077 .{
33058 end_val.fmtValue(Type.usize, mod),33078 end_val.fmtValue(Type.usize, mod),
33059 slice_val.sliceLen(mod),33079 try slice_val.sliceLen(sema),
33060 sentinel_label,33080 sentinel_label,
33061 },33081 },
33062 );33082 );
...@@ -33285,7 +33305,7 @@ fn analyzeSlice(...@@ -33285,7 +33305,7 @@ fn analyzeSlice(
33285 if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {33305 if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
33286 // we don't need to add one for sentinels because the33306 // we don't need to add one for sentinels because the
33287 // underlying value data includes the sentinel33307 // underlying value data includes the sentinel
33288 break :blk try mod.intRef(Type.usize, slice_val.sliceLen(mod));33308 break :blk try mod.intRef(Type.usize, try slice_val.sliceLen(sema));
33289 }33309 }
3329033310
33291 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);33311 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
...@@ -39003,22 +39023,22 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai...@@ -39003,22 +39023,22 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai
39003}39023}
3900439024
39005/// Returns true if any value contained in `val` is undefined.39025/// Returns true if any value contained in `val` is undefined.
39006fn anyUndef(sema: *Sema, val: Value) !bool {39026fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {
39007 const mod = sema.mod;39027 const mod = sema.mod;
39008 return switch (val.toIntern()) {39028 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
39009 .undef => true,39029 .undef => true,
39010 else => switch (mod.intern_pool.indexToKey(val.toIntern())) {39030 .simple_value => |v| v == .undefined,
39011 .undef => true,39031 .slice => {
39012 .simple_value => |v| v == .undefined,39032 // If the slice contents are runtime-known, reification will fail later on with a
39013 .slice => |slice| for (0..@intCast(Value.fromInterned(slice.len).toUnsignedInt(mod))) |idx| {39033 // specific error message.
39014 if (try sema.anyUndef((try val.maybeElemValueFull(sema, mod, idx)).?)) break true;39034 const arr = try sema.maybeDerefSliceAsArray(block, src, val) orelse return false;
39015 } else false,39035 return sema.anyUndef(block, src, arr);
39016 .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| {39036 },
39017 const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i];39037 .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| {
39018 if (try sema.anyUndef(Value.fromInterned(elem))) break true;39038 const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i];
39019 } else false,39039 if (try sema.anyUndef(block, src, Value.fromInterned(elem))) break true;
39020 else => false,39040 } else false,
39021 },39041 else => false,
39022 };39042 };
39023}39043}
3902439044
...@@ -39050,6 +39070,20 @@ fn derefSliceAsArray(...@@ -39050,6 +39070,20 @@ fn derefSliceAsArray(
39050 slice_val: Value,39070 slice_val: Value,
39051 reason: NeededComptimeReason,39071 reason: NeededComptimeReason,
39052) CompileError!Value {39072) CompileError!Value {
39073 return try sema.maybeDerefSliceAsArray(block, src, slice_val) orelse {
39074 return sema.failWithNeededComptime(block, src, reason);
39075 };
39076}
39077
39078/// Given a slice value, attempts to dereference it into a comptime-known array.
39079/// Returns `null` if the contents of the slice are not comptime-known.
39080/// Asserts that `slice_val` is a slice.
39081fn maybeDerefSliceAsArray(
39082 sema: *Sema,
39083 block: *Block,
39084 src: LazySrcLoc,
39085 slice_val: Value,
39086) CompileError!?Value {
39053 const zcu = sema.mod;39087 const zcu = sema.mod;
39054 const ip = &zcu.intern_pool;39088 const ip = &zcu.intern_pool;
39055 assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu));39089 assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu));
...@@ -39072,7 +39106,5 @@ fn derefSliceAsArray(...@@ -39072,7 +39106,5 @@ fn derefSliceAsArray(
39072 break :p p;39106 break :p p;
39073 });39107 });
39074 const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty);39108 const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty);
39075 return try sema.pointerDeref(block, src, casted_ptr, ptr_ty) orelse {39109 return sema.pointerDeref(block, src, casted_ptr, ptr_ty);
39076 return sema.failWithNeededComptime(block, src, reason);
39077 };
39078}39110}
src/TypedValue.zig+250-270
...@@ -1,7 +1,10 @@...@@ -1,7 +1,10 @@
1const std = @import("std");1const std = @import("std");
2const Type = @import("type.zig").Type;2const Type = @import("type.zig").Type;
3const Value = @import("Value.zig");3const Value = @import("Value.zig");
4const Module = @import("Module.zig");4const Zcu = @import("Module.zig");
5const Module = Zcu;
6const Sema = @import("Sema.zig");
7const InternPool = @import("InternPool.zig");
5const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
6const TypedValue = @This();9const TypedValue = @This();
7const Target = std.Target;10const Target = std.Target;
...@@ -61,8 +64,10 @@ pub fn format(...@@ -61,8 +64,10 @@ pub fn format(
61) !void {64) !void {
62 _ = options;65 _ = options;
63 comptime std.debug.assert(fmt.len == 0);66 comptime std.debug.assert(fmt.len == 0);
64 return ctx.tv.print(writer, 3, ctx.mod) catch |err| switch (err) {67 return ctx.tv.print(writer, 3, ctx.mod, null) catch |err| switch (err) {
65 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function68 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
69 error.ComptimeBreak, error.ComptimeReturn => unreachable,
70 error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we actually pass `opt_sema`
66 else => |e| return e,71 else => |e| return e,
67 };72 };
68}73}
...@@ -73,11 +78,12 @@ pub fn print(...@@ -73,11 +78,12 @@ pub fn print(
73 writer: anytype,78 writer: anytype,
74 level: u8,79 level: u8,
75 mod: *Module,80 mod: *Module,
76) (@TypeOf(writer).Error || Allocator.Error)!void {81 /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output.
77 var val = tv.val;82 opt_sema: ?*Sema,
78 var ty = tv.ty;83) (@TypeOf(writer).Error || Module.CompileError)!void {
79 const ip = &mod.intern_pool;84 const ip = &mod.intern_pool;
80 while (true) switch (ip.indexToKey(val.toIntern())) {85 const val = tv.val;
86 switch (ip.indexToKey(val.toIntern())) {
81 .int_type,87 .int_type,
82 .ptr_type,88 .ptr_type,
83 .array_type,89 .array_type,
...@@ -94,324 +100,298 @@ pub fn print(...@@ -94,324 +100,298 @@ pub fn print(
94 .func_type,100 .func_type,
95 .error_set_type,101 .error_set_type,
96 .inferred_error_set_type,102 .inferred_error_set_type,
97 => return Type.print(val.toType(), writer, mod),103 => try Type.print(val.toType(), writer, mod),
98 .undef => return writer.writeAll("undefined"),104 .undef => try writer.writeAll("undefined"),
99 .simple_value => |simple_value| switch (simple_value) {105 .simple_value => |simple_value| switch (simple_value) {
100 .void => return writer.writeAll("{}"),106 .void => try writer.writeAll("{}"),
101 .empty_struct => return printAggregate(ty, val, writer, level, mod),107 .empty_struct => try writer.writeAll(".{}"),
102 .generic_poison => return writer.writeAll("(generic poison)"),108 .generic_poison => try writer.writeAll("(generic poison)"),
103 else => return writer.writeAll(@tagName(simple_value)),109 else => try writer.writeAll(@tagName(simple_value)),
104 },110 },
105 .variable => return writer.writeAll("(variable)"),111 .variable => try writer.writeAll("(variable)"),
106 .extern_func => |extern_func| return writer.print("(extern function '{}')", .{112 .extern_func => |extern_func| try writer.print("(extern function '{}')", .{
107 mod.declPtr(extern_func.decl).name.fmt(ip),113 mod.declPtr(extern_func.decl).name.fmt(ip),
108 }),114 }),
109 .func => |func| return writer.print("(function '{}')", .{115 .func => |func| try writer.print("(function '{}')", .{
110 mod.declPtr(func.owner_decl).name.fmt(ip),116 mod.declPtr(func.owner_decl).name.fmt(ip),
111 }),117 }),
112 .int => |int| switch (int.storage) {118 .int => |int| switch (int.storage) {
113 inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}),119 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
114 .lazy_align => |lazy_ty| return writer.print("{d}", .{120 .lazy_align => |ty| if (opt_sema) |sema| {
115 Type.fromInterned(lazy_ty).abiAlignment(mod),121 const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar;
116 }),122 try writer.print("{}", .{a.toByteUnits(0)});
117 .lazy_size => |lazy_ty| return writer.print("{d}", .{123 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}),
118 Type.fromInterned(lazy_ty).abiSize(mod),124 .lazy_size => |ty| if (opt_sema) |sema| {
119 }),125 const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar;
126 try writer.print("{}", .{s});
127 } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(mod)}),
120 },128 },
121 .err => |err| return writer.print("error.{}", .{129 .err => |err| try writer.print("error.{}", .{
122 err.name.fmt(ip),130 err.name.fmt(ip),
123 }),131 }),
124 .error_union => |error_union| switch (error_union.val) {132 .error_union => |error_union| switch (error_union.val) {
125 .err_name => |err_name| return writer.print("error.{}", .{133 .err_name => |err_name| try writer.print("error.{}", .{
126 err_name.fmt(ip),134 err_name.fmt(ip),
127 }),135 }),
128 .payload => |payload| {136 .payload => |payload| try print(.{
129 val = Value.fromInterned(payload);137 .ty = tv.ty.errorUnionPayload(mod),
130 ty = ty.errorUnionPayload(mod);138 .val = Value.fromInterned(payload),
131 },139 }, writer, level, mod, opt_sema),
132 },140 },
133 .enum_literal => |enum_literal| return writer.print(".{}", .{141 .enum_literal => |enum_literal| try writer.print(".{}", .{
134 enum_literal.fmt(ip),142 enum_literal.fmt(ip),
135 }),143 }),
136 .enum_tag => |enum_tag| {144 .enum_tag => |enum_tag| {
137 if (level == 0) {145 const enum_type = ip.loadEnumType(val.typeOf(mod).toIntern());
138 return writer.writeAll("(enum)");
139 }
140 const enum_type = ip.loadEnumType(ty.toIntern());
141 if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {146 if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {
142 try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});147 try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});
143 return;148 return;
144 }149 }
150 if (level == 0) {
151 try writer.writeAll("@enumFromInt(...)");
152 }
145 try writer.writeAll("@enumFromInt(");153 try writer.writeAll("@enumFromInt(");
146 try print(.{154 try print(.{
147 .ty = Type.fromInterned(ip.typeOf(enum_tag.int)),155 .ty = Type.fromInterned(ip.typeOf(enum_tag.int)),
148 .val = Value.fromInterned(enum_tag.int),156 .val = Value.fromInterned(enum_tag.int),
149 }, writer, level - 1, mod);157 }, writer, level - 1, mod, opt_sema);
150 try writer.writeAll(")");158 try writer.writeAll(")");
151 return;
152 },159 },
153 .empty_enum_value => return writer.writeAll("(empty enum value)"),160 .empty_enum_value => try writer.writeAll("(empty enum value)"),
154 .float => |float| switch (float.storage) {161 .float => |float| switch (float.storage) {
155 inline else => |x| return writer.print("{d}", .{@as(f64, @floatCast(x))}),162 inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}),
156 },163 },
157 .slice => |slice| {164 .slice => |slice| {
158 const ptr_ty = switch (ip.indexToKey(slice.ptr)) {165 const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) {
159 .ptr => |ptr| ty: {166 .field, .elem, .eu_payload, .opt_payload => unreachable,
160 if (ptr.addr == .int) return print(.{167 .anon_decl, .comptime_alloc, .comptime_field => true,
161 .ty = Type.fromInterned(ptr.ty),168 .decl, .int => false,
162 .val = Value.fromInterned(slice.ptr),
163 }, writer, level - 1, mod);
164 break :ty ip.indexToKey(ptr.ty).ptr_type;
165 },
166 .undef => |ptr_ty| ip.indexToKey(ptr_ty).ptr_type,
167 else => unreachable,
168 };169 };
169 if (level == 0) {170 if (print_contents) {
170 return writer.writeAll(".{ ... }");171 // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's
171 }172 // currently not possible without e.g. triggering compile errors.
172 const elem_ty = Type.fromInterned(ptr_ty.child);
173 const len = Value.fromInterned(slice.len).toUnsignedInt(mod);
174 if (elem_ty.eql(Type.u8, mod)) str: {
175 const max_len = @min(len, max_string_len);
176 var buf: [max_string_len]u8 = undefined;
177 for (buf[0..max_len], 0..) |*c, i| {
178 const maybe_elem = try val.maybeElemValue(mod, i);
179 const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }");
180 if (elem.isUndef(mod)) break :str;
181 c.* = @as(u8, @intCast(elem.toUnsignedInt(mod)));
182 }
183 const truncated = if (len > max_string_len) " (truncated)" else "";
184 return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
185 }173 }
186 try writer.writeAll(".{ ");174 try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema);
187 const max_len = @min(len, max_aggregate_items);175 try writer.writeAll("[0..");
188 for (0..max_len) |i| {176 try print(.{
189 if (i != 0) try writer.writeAll(", ");177 .ty = Type.usize,
190 const maybe_elem = try val.maybeElemValue(mod, i);178 .val = Value.fromInterned(slice.len),
191 const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }");179 }, writer, level - 1, mod, opt_sema);
192 try print(.{180 try writer.writeAll("]");
193 .ty = elem_ty,
194 .val = elem,
195 }, writer, level - 1, mod);
196 }
197 if (len > max_aggregate_items) {
198 try writer.writeAll(", ...");
199 }
200 return writer.writeAll(" }");
201 },181 },
202 .ptr => |ptr| {182 .ptr => {
203 switch (ptr.addr) {183 const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) {
204 .decl => |decl_index| {184 .field, .elem, .eu_payload, .opt_payload => unreachable,
205 const decl = mod.declPtr(decl_index);185 .anon_decl, .comptime_alloc, .comptime_field => true,
206 if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)});186 .decl, .int => false,
207 return print(.{187 };
208 .ty = decl.typeOf(mod),188 if (print_contents) {
209 .val = decl.val,189 // TODO: eventually we want to load the pointer with `opt_sema`, but that's
210 }, writer, level - 1, mod);190 // currently not possible without e.g. triggering compile errors.
211 },
212 .anon_decl => |anon_decl| {
213 const decl_val = anon_decl.val;
214 if (level == 0) return writer.print("(anon decl '{d}')", .{
215 @intFromEnum(decl_val),
216 });
217 return print(.{
218 .ty = Type.fromInterned(ip.typeOf(decl_val)),
219 .val = Value.fromInterned(decl_val),
220 }, writer, level - 1, mod);
221 },
222 .comptime_alloc => {
223 // TODO: we need a Sema to print this!
224 return writer.writeAll("(comptime alloc)");
225 },
226 .comptime_field => |field_val_ip| {
227 return print(.{
228 .ty = Type.fromInterned(ip.typeOf(field_val_ip)),
229 .val = Value.fromInterned(field_val_ip),
230 }, writer, level - 1, mod);
231 },
232 .int => |int_ip| {
233 try writer.writeAll("@ptrFromInt(");
234 try print(.{
235 .ty = Type.usize,
236 .val = Value.fromInterned(int_ip),
237 }, writer, level - 1, mod);
238 try writer.writeByte(')');
239 },
240 .eu_payload => |eu_ip| {
241 try writer.writeAll("(payload of ");
242 try print(.{
243 .ty = Type.fromInterned(ip.typeOf(eu_ip)),
244 .val = Value.fromInterned(eu_ip),
245 }, writer, level - 1, mod);
246 try writer.writeAll(")");
247 },
248 .opt_payload => |opt_ip| {
249 try print(.{
250 .ty = Type.fromInterned(ip.typeOf(opt_ip)),
251 .val = Value.fromInterned(opt_ip),
252 }, writer, level - 1, mod);
253 try writer.writeAll(".?");
254 },
255 .elem => |elem| {
256 if (level == 0) {
257 try writer.writeAll("(...)");
258 } else {
259 try print(.{
260 .ty = Type.fromInterned(ip.typeOf(elem.base)),
261 .val = Value.fromInterned(elem.base),
262 }, writer, level - 1, mod);
263 }
264 try writer.print("[{}]", .{elem.index});
265 },
266 .field => |field| {
267 const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base));
268 if (level == 0) {
269 try writer.writeAll("(...)");
270 } else {
271 try print(.{
272 .ty = ptr_container_ty,
273 .val = Value.fromInterned(field.base),
274 }, writer, level - 1, mod);
275 }
276
277 const container_ty = ptr_container_ty.childType(mod);
278 switch (container_ty.zigTypeTag(mod)) {
279 .Struct => {
280 if (container_ty.structFieldName(@intCast(field.index), mod).unwrap()) |field_name| {
281 try writer.print(".{i}", .{field_name.fmt(ip)});
282 } else {
283 try writer.print("[{d}]", .{field.index});
284 }
285 },
286 .Union => {
287 const field_name = mod.typeToUnion(container_ty).?.loadTagType(ip).names.get(ip)[@intCast(field.index)];
288 try writer.print(".{i}", .{field_name.fmt(ip)});
289 },
290 .Pointer => {
291 std.debug.assert(container_ty.isSlice(mod));
292 try writer.writeAll(switch (field.index) {
293 Value.slice_ptr_index => ".ptr",
294 Value.slice_len_index => ".len",
295 else => unreachable,
296 });
297 },
298 else => unreachable,
299 }
300 },
301 }191 }
302 return;192 try printPtr(val.toIntern(), writer, false, false, 0, level, mod, opt_sema);
303 },193 },
304 .opt => |opt| switch (opt.val) {194 .opt => |opt| switch (opt.val) {
305 .none => return writer.writeAll("null"),195 .none => try writer.writeAll("null"),
306 else => |payload| {196 else => |payload| try print(.{
307 val = Value.fromInterned(payload);197 .ty = tv.ty.childType(mod),
308 ty = ty.optionalChild(mod);198 .val = Value.fromInterned(payload),
309 },199 }, writer, level, mod, opt_sema),
310 },
311 .aggregate => |aggregate| switch (aggregate.storage) {
312 .bytes => |bytes| {
313 // Strip the 0 sentinel off of strings before printing
314 const zero_sent = blk: {
315 const sent = ty.sentinel(mod) orelse break :blk false;
316 break :blk sent.eql(Value.zero_u8, Type.u8, mod);
317 };
318 const str = if (zero_sent) bytes[0 .. bytes.len - 1] else bytes;
319 return writer.print("\"{}\"", .{std.zig.fmtEscapes(str)});
320 },
321 .elems, .repeated_elem => return printAggregate(ty, val, writer, level, mod),
322 },200 },
201 .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, mod, opt_sema),
323 .un => |un| {202 .un => |un| {
324 try writer.writeAll(".{ ");203 if (level == 0) {
325 if (level > 0) {204 try writer.writeAll(".{ ... }");
326 if (un.tag != .none) {205 return;
327 try print(.{206 }
328 .ty = ty.unionTagTypeHypothetical(mod),207 if (un.tag == .none) {
329 .val = Value.fromInterned(un.tag),208 const backing_ty = try tv.ty.unionBackingType(mod);
330 }, writer, level - 1, mod);209 try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(mod)});
331 try writer.writeAll(" = ");210 try print(.{
332 const field_ty = ty.unionFieldType(Value.fromInterned(un.tag), mod).?;211 .ty = backing_ty,
333 try print(.{212 .val = Value.fromInterned(un.val),
334 .ty = field_ty,213 }, writer, level - 1, mod, opt_sema);
335 .val = Value.fromInterned(un.val),214 try writer.writeAll("))");
336 }, writer, level - 1, mod);215 } else {
337 } else {216 try writer.writeAll(".{ ");
338 try writer.writeAll("(unknown tag) = ");217 try print(.{
339 const backing_ty = try ty.unionBackingType(mod);218 .ty = tv.ty.unionTagTypeHypothetical(mod),
340 try print(.{219 .val = Value.fromInterned(un.tag),
341 .ty = backing_ty,220 }, writer, level - 1, mod, opt_sema);
342 .val = Value.fromInterned(un.val),221 try writer.writeAll(" = ");
343 }, writer, level - 1, mod);222 const field_ty = tv.ty.unionFieldType(Value.fromInterned(un.tag), mod).?;
344 }223 try print(.{
345 } else try writer.writeAll("...");224 .ty = field_ty,
346 return writer.writeAll(" }");225 .val = Value.fromInterned(un.val),
226 }, writer, level - 1, mod, opt_sema);
227 try writer.writeAll(" }");
228 }
347 },229 },
348 .memoized_call => unreachable,230 .memoized_call => unreachable,
349 };231 }
350}232}
351233
352fn printAggregate(234fn printAggregate(
353 ty: Type,
354 val: Value,235 val: Value,
236 aggregate: InternPool.Key.Aggregate,
355 writer: anytype,237 writer: anytype,
356 level: u8,238 level: u8,
357 mod: *Module,239 zcu: *Zcu,
358) (@TypeOf(writer).Error || Allocator.Error)!void {240 opt_sema: ?*Sema,
241) (@TypeOf(writer).Error || Module.CompileError)!void {
359 if (level == 0) {242 if (level == 0) {
360 return writer.writeAll(".{ ... }");243 return writer.writeAll(".{ ... }");
361 }244 }
362 const ip = &mod.intern_pool;245 const ip = &zcu.intern_pool;
363 if (ty.zigTypeTag(mod) == .Struct) {246 const ty = Type.fromInterned(aggregate.ty);
364 try writer.writeAll(".{");247 switch (ty.zigTypeTag(zcu)) {
365 const max_len = @min(ty.structFieldCount(mod), max_aggregate_items);248 .Struct => if (!ty.isTuple(zcu)) {
366249 if (ty.structFieldCount(zcu) == 0) {
367 for (0..max_len) |i| {250 return writer.writeAll(".{}");
368 if (i != 0) try writer.writeAll(", ");251 }
252 try writer.writeAll(".{ ");
253 const max_len = @min(ty.structFieldCount(zcu), max_aggregate_items);
254 for (0..max_len) |i| {
255 if (i != 0) try writer.writeAll(", ");
256 const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?;
257 try writer.print(".{i} = ", .{field_name.fmt(ip)});
258 try print(.{
259 .ty = ty.structFieldType(i, zcu),
260 .val = try val.fieldValue(zcu, i),
261 }, writer, level - 1, zcu, opt_sema);
262 }
263 try writer.writeAll(" }");
264 return;
265 },
266 .Array => if (aggregate.storage == .bytes) {
267 return writer.print("\"{}\".*", .{std.zig.fmtEscapes(aggregate.storage.bytes)});
268 } else if (ty.arrayLen(zcu) == 0) {
269 return writer.writeAll(".{}");
270 },
271 .Vector => if (ty.arrayLen(zcu) == 0) {
272 return writer.writeAll(".{}");
273 },
274 else => unreachable,
275 }
369276
370 const field_name = ty.structFieldName(@intCast(i), mod);277 const elem_ty = ty.childType(zcu);
278 const len = ty.arrayLen(zcu);
371279
372 if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(ip)});280 try writer.writeAll(".{ ");
373 try print(.{
374 .ty = ty.structFieldType(i, mod),
375 .val = try val.fieldValue(mod, i),
376 }, writer, level - 1, mod);
377 }
378 if (ty.structFieldCount(mod) > max_aggregate_items) {
379 try writer.writeAll(", ...");
380 }
381 return writer.writeAll("}");
382 } else {
383 const elem_ty = ty.elemType2(mod);
384 const len = ty.arrayLen(mod);
385281
386 if (elem_ty.eql(Type.u8, mod)) str: {282 const max_len = @min(len, max_aggregate_items);
387 const max_len: usize = @min(len, max_string_len);283 for (0..max_len) |i| {
388 var buf: [max_string_len]u8 = undefined;284 if (i != 0) try writer.writeAll(", ");
285 try print(.{
286 .ty = elem_ty,
287 .val = try val.fieldValue(zcu, i),
288 }, writer, level - 1, zcu, opt_sema);
289 }
290 if (len > max_aggregate_items) {
291 try writer.writeAll(", ...");
292 }
293 return writer.writeAll(" }");
294}
389295
390 var i: u32 = 0;296fn printPtr(
391 while (i < max_len) : (i += 1) {297 ptr_val: InternPool.Index,
392 const elem = try val.fieldValue(mod, i);298 writer: anytype,
393 if (elem.isUndef(mod)) break :str;299 force_type: bool,
394 buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str;300 force_addrof: bool,
301 leading_parens: u32,
302 level: u8,
303 zcu: *Zcu,
304 opt_sema: ?*Sema,
305) (@TypeOf(writer).Error || Module.CompileError)!void {
306 const ip = &zcu.intern_pool;
307 const ptr = switch (ip.indexToKey(ptr_val)) {
308 .undef => |ptr_ty| {
309 if (force_addrof) try writer.writeAll("&");
310 try writer.writeByteNTimes('(', leading_parens);
311 try writer.print("@as({}, undefined)", .{Type.fromInterned(ptr_ty).fmt(zcu)});
312 return;
313 },
314 .ptr => |ptr| ptr,
315 else => unreachable,
316 };
317 switch (ptr.addr) {
318 .int => |int| {
319 if (force_addrof) try writer.writeAll("&");
320 try writer.writeByteNTimes('(', leading_parens);
321 if (force_type) {
322 try writer.print("@as({}, @ptrFromInt(", .{Type.fromInterned(ptr.ty).fmt(zcu)});
323 try print(.{
324 .ty = Type.usize,
325 .val = Value.fromInterned(int),
326 }, writer, level - 1, zcu, opt_sema);
327 try writer.writeAll("))");
328 } else {
329 try writer.writeAll("@ptrFromInt(");
330 try print(.{
331 .ty = Type.usize,
332 .val = Value.fromInterned(int),
333 }, writer, level - 1, zcu, opt_sema);
334 try writer.writeAll(")");
395 }335 }
396336 },
397 const truncated = if (len > max_string_len) " (truncated)" else "";337 .decl => |index| {
398 return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });338 try writer.writeAll("&");
399 }339 try zcu.declPtr(index).renderFullyQualifiedName(zcu, writer);
400340 },
401 try writer.writeAll(".{ ");341 .comptime_alloc => try writer.writeAll("&(comptime alloc)"),
402342 .anon_decl => |anon| {
403 const max_len = @min(len, max_aggregate_items);343 const ty = Type.fromInterned(ip.typeOf(anon.val));
404 var i: u32 = 0;344 try writer.print("&@as({}, ", .{ty.fmt(zcu)});
405 while (i < max_len) : (i += 1) {
406 if (i != 0) try writer.writeAll(", ");
407 try print(.{345 try print(.{
408 .ty = elem_ty,346 .ty = ty,
409 .val = try val.fieldValue(mod, i),347 .val = Value.fromInterned(anon.val),
410 }, writer, level - 1, mod);348 }, writer, level - 1, zcu, opt_sema);
411 }349 try writer.writeAll(")");
412 if (len > max_aggregate_items) {350 },
413 try writer.writeAll(", ...");351 .comptime_field => |val| {
414 }352 const ty = Type.fromInterned(ip.typeOf(val));
415 return writer.writeAll(" }");353 try writer.print("&@as({}, ", .{ty.fmt(zcu)});
354 try print(.{
355 .ty = ty,
356 .val = Value.fromInterned(val),
357 }, writer, level - 1, zcu, opt_sema);
358 try writer.writeAll(")");
359 },
360 .eu_payload => |base| {
361 try printPtr(base, writer, true, true, leading_parens, level, zcu, opt_sema);
362 try writer.writeAll(".?");
363 },
364 .opt_payload => |base| {
365 try writer.writeAll("(");
366 try printPtr(base, writer, true, true, leading_parens + 1, level, zcu, opt_sema);
367 try writer.writeAll(" catch unreachable");
368 },
369 .elem => |elem| {
370 try printPtr(elem.base, writer, true, true, leading_parens, level, zcu, opt_sema);
371 try writer.print("[{d}]", .{elem.index});
372 },
373 .field => |field| {
374 try printPtr(field.base, writer, true, true, leading_parens, level, zcu, opt_sema);
375 const base_ty = Type.fromInterned(ip.typeOf(field.base)).childType(zcu);
376 switch (base_ty.zigTypeTag(zcu)) {
377 .Struct => if (base_ty.isTuple(zcu)) {
378 try writer.print("[{d}]", .{field.index});
379 } else {
380 const field_name = base_ty.structFieldName(@intCast(field.index), zcu).unwrap().?;
381 try writer.print(".{i}", .{field_name.fmt(ip)});
382 },
383 .Union => {
384 const tag_ty = base_ty.unionTagTypeHypothetical(zcu);
385 const field_name = tag_ty.enumFieldName(@intCast(field.index), zcu);
386 try writer.print(".{i}", .{field_name.fmt(ip)});
387 },
388 .Pointer => switch (field.index) {
389 Value.slice_ptr_index => try writer.writeAll(".ptr"),
390 Value.slice_len_index => try writer.writeAll(".len"),
391 else => unreachable,
392 },
393 else => unreachable,
394 }
395 },
416 }396 }
417}397}
src/Value.zig+44-92
...@@ -305,16 +305,16 @@ pub fn toBool(val: Value) bool {...@@ -305,16 +305,16 @@ pub fn toBool(val: Value) bool {
305 };305 };
306}306}
307307
308fn isDeclRef(val: Value, mod: *Module) bool {308fn ptrHasIntAddr(val: Value, mod: *Module) bool {
309 var check = val;309 var check = val;
310 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {310 while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) {
311 .ptr => |ptr| switch (ptr.addr) {311 .ptr => |ptr| switch (ptr.addr) {
312 .decl, .comptime_alloc, .comptime_field, .anon_decl => return true,312 .decl, .comptime_alloc, .comptime_field, .anon_decl => return false,
313 .int => return true,
313 .eu_payload, .opt_payload => |base| check = Value.fromInterned(base),314 .eu_payload, .opt_payload => |base| check = Value.fromInterned(base),
314 .elem, .field => |base_index| check = Value.fromInterned(base_index.base),315 .elem, .field => |base_index| check = Value.fromInterned(base_index.base),
315 .int => return false,
316 },316 },
317 else => return false,317 else => unreachable,
318 };318 };
319}319}
320320
...@@ -439,7 +439,7 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{...@@ -439,7 +439,7 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{
439 },439 },
440 .Pointer => {440 .Pointer => {
441 if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout;441 if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout;
442 if (val.isDeclRef(mod)) return error.ReinterpretDeclRef;442 if (!val.ptrHasIntAddr(mod)) return error.ReinterpretDeclRef;
443 return val.writeToMemory(Type.usize, mod, buffer);443 return val.writeToMemory(Type.usize, mod, buffer);
444 },444 },
445 .Optional => {445 .Optional => {
...@@ -566,7 +566,7 @@ pub fn writeToPackedMemory(...@@ -566,7 +566,7 @@ pub fn writeToPackedMemory(
566 },566 },
567 .Pointer => {567 .Pointer => {
568 assert(!ty.isSlice(mod)); // No well defined layout.568 assert(!ty.isSlice(mod)); // No well defined layout.
569 if (val.isDeclRef(mod)) return error.ReinterpretDeclRef;569 if (!val.ptrHasIntAddr(mod)) return error.ReinterpretDeclRef;
570 return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset);570 return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset);
571 },571 },
572 .Optional => {572 .Optional => {
...@@ -1261,62 +1261,23 @@ pub fn slicePtr(val: Value, mod: *Module) Value {...@@ -1261,62 +1261,23 @@ pub fn slicePtr(val: Value, mod: *Module) Value {
1261 return Value.fromInterned(mod.intern_pool.slicePtr(val.toIntern()));1261 return Value.fromInterned(mod.intern_pool.slicePtr(val.toIntern()));
1262}1262}
12631263
1264pub fn sliceLen(val: Value, mod: *Module) u64 {1264/// Gets the `len` field of a slice value as a `u64`.
1265 const ip = &mod.intern_pool;1265/// Resolves the length using the provided `Sema` if necessary.
1266 return switch (ip.indexToKey(val.toIntern())) {1266pub fn sliceLen(val: Value, sema: *Sema) !u64 {
1267 .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) {1267 return Value.fromInterned(sema.mod.intern_pool.sliceLen(val.toIntern())).toUnsignedIntAdvanced(sema);
1268 .decl => |decl| mod.declPtr(decl).typeOf(mod).toIntern(),
1269 .comptime_alloc => @panic("TODO"),
1270 .anon_decl => |anon_decl| ip.typeOf(anon_decl.val),
1271 .comptime_field => |comptime_field| ip.typeOf(comptime_field),
1272 else => unreachable,
1273 })) {
1274 .array_type => |array_type| array_type.len,
1275 else => 1,
1276 },
1277 .slice => |slice| Value.fromInterned(slice.len).toUnsignedInt(mod),
1278 else => unreachable,
1279 };
1280}
1281
1282/// Asserts the value is a single-item pointer to an array, or an array,
1283/// or an unknown-length pointer, and returns the element value at the index.
1284pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
1285 return (try val.maybeElemValue(mod, index)).?;
1286}
1287
1288/// Like `elemValue`, but returns `null` instead of asserting on failure.
1289pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value {
1290 return val.maybeElemValueFull(null, mod, index);
1291}1268}
12921269
1293pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) Allocator.Error!?Value {1270/// Asserts the value is an aggregate, and returns the element value at the given index.
1294 return switch (mod.intern_pool.indexToKey(val.toIntern())) {1271pub fn elemValue(val: Value, zcu: *Zcu, index: usize) Allocator.Error!Value {
1295 .undef => |ty| Value.fromInterned((try mod.intern(.{1272 const ip = &zcu.intern_pool;
1296 .undef = Type.fromInterned(ty).elemType2(mod).toIntern(),1273 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
1297 }))),1274 .undef => |ty| {
1298 .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index),1275 return Value.fromInterned(try zcu.intern(.{ .undef = Type.fromInterned(ty).childType(zcu).toIntern() }));
1299 .ptr => |ptr| switch (ptr.addr) {1276 },
1300 .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index),
1301 .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index),
1302 .comptime_alloc => |idx| if (sema) |s| Value.fromInterned(
1303 try s.getComptimeAlloc(idx).val.intern(mod, s.arena),
1304 ).maybeElemValueFull(sema, mod, index) else null,
1305 .int, .eu_payload => null,
1306 .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index),
1307 .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index),
1308 .elem => |elem| Value.fromInterned(elem.base).maybeElemValueFull(sema, mod, index + @as(usize, @intCast(elem.index))),
1309 .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| {
1310 const base_decl = mod.declPtr(decl_index);
1311 const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index)));
1312 return field_val.maybeElemValueFull(sema, mod, index);
1313 } else null,
1314 },
1315 .opt => |opt| Value.fromInterned(opt.val).maybeElemValueFull(sema, mod, index),
1316 .aggregate => |aggregate| {1277 .aggregate => |aggregate| {
1317 const len = mod.intern_pool.aggregateTypeLen(aggregate.ty);1278 const len = ip.aggregateTypeLen(aggregate.ty);
1318 if (index < len) return Value.fromInterned(switch (aggregate.storage) {1279 if (index < len) return Value.fromInterned(switch (aggregate.storage) {
1319 .bytes => |bytes| try mod.intern(.{ .int = .{1280 .bytes => |bytes| try zcu.intern(.{ .int = .{
1320 .ty = .u8_type,1281 .ty = .u8_type,
1321 .storage = .{ .u64 = bytes[index] },1282 .storage = .{ .u64 = bytes[index] },
1322 } }),1283 } }),
...@@ -1324,10 +1285,10 @@ pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize)...@@ -1324,10 +1285,10 @@ pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize)
1324 .repeated_elem => |elem| elem,1285 .repeated_elem => |elem| elem,
1325 });1286 });
1326 assert(index == len);1287 assert(index == len);
1327 return Value.fromInterned(mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel);1288 return Type.fromInterned(aggregate.ty).sentinel(zcu).?;
1328 },1289 },
1329 else => null,1290 else => unreachable,
1330 };1291 }
1331}1292}
13321293
1333pub fn isLazyAlign(val: Value, mod: *Module) bool {1294pub fn isLazyAlign(val: Value, mod: *Module) bool {
...@@ -1359,39 +1320,26 @@ pub fn sliceArray(...@@ -1359,39 +1320,26 @@ pub fn sliceArray(
1359) error{OutOfMemory}!Value {1320) error{OutOfMemory}!Value {
1360 // TODO: write something like getCoercedInts to avoid needing to dupe1321 // TODO: write something like getCoercedInts to avoid needing to dupe
1361 const mod = sema.mod;1322 const mod = sema.mod;
1362 return switch (mod.intern_pool.indexToKey(val.toIntern())) {1323 const aggregate = mod.intern_pool.indexToKey(val.toIntern()).aggregate;
1363 .ptr => |ptr| switch (ptr.addr) {1324 return Value.fromInterned(try mod.intern(.{ .aggregate = .{
1364 .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end),1325 .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) {
1365 .comptime_alloc => |idx| try Value.fromInterned(1326 .array_type => |array_type| try mod.arrayType(.{
1366 try sema.getComptimeAlloc(idx).val.intern(mod, sema.arena),1327 .len = @as(u32, @intCast(end - start)),
1367 ).sliceArray(sema, start, end),1328 .child = array_type.child,
1368 .comptime_field => |comptime_field| Value.fromInterned(comptime_field)1329 .sentinel = if (end == array_type.len) array_type.sentinel else .none,
1369 .sliceArray(sema, start, end),1330 }),
1370 .elem => |elem| Value.fromInterned(elem.base)1331 .vector_type => |vector_type| try mod.vectorType(.{
1371 .sliceArray(sema, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))),1332 .len = @as(u32, @intCast(end - start)),
1333 .child = vector_type.child,
1334 }),
1372 else => unreachable,1335 else => unreachable,
1336 }.toIntern(),
1337 .storage = switch (aggregate.storage) {
1338 .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) },
1339 .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) },
1340 .repeated_elem => |elem| .{ .repeated_elem = elem },
1373 },1341 },
1374 .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{1342 } }));
1375 .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) {
1376 .array_type => |array_type| try mod.arrayType(.{
1377 .len = @as(u32, @intCast(end - start)),
1378 .child = array_type.child,
1379 .sentinel = if (end == array_type.len) array_type.sentinel else .none,
1380 }),
1381 .vector_type => |vector_type| try mod.vectorType(.{
1382 .len = @as(u32, @intCast(end - start)),
1383 .child = vector_type.child,
1384 }),
1385 else => unreachable,
1386 }.toIntern(),
1387 .storage = switch (aggregate.storage) {
1388 .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) },
1389 .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) },
1390 .repeated_elem => |elem| .{ .repeated_elem = elem },
1391 },
1392 } }))),
1393 else => unreachable,
1394 };
1395}1343}
13961344
1397pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {1345pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value {
...@@ -3586,6 +3534,10 @@ pub fn isGenericPoison(val: Value) bool {...@@ -3586,6 +3534,10 @@ pub fn isGenericPoison(val: Value) bool {
3586 return val.toIntern() == .generic_poison;3534 return val.toIntern() == .generic_poison;
3587}3535}
35883536
3537pub fn typeOf(val: Value, zcu: *const Zcu) Type {
3538 return Type.fromInterned(zcu.intern_pool.typeOf(val.toIntern()));
3539}
3540
3589/// For an integer (comptime or fixed-width) `val`, returns the comptime-known bounds of the value.3541/// For an integer (comptime or fixed-width) `val`, returns the comptime-known bounds of the value.
3590/// If `val` is not undef, the bounds are both `val`.3542/// If `val` is not undef, the bounds are both `val`.
3591/// If `val` is undef and has a fixed-width type, the bounds are the bounds of the type.3543/// If `val` is undef and has a fixed-width type, the bounds are the bounds of the type.
test/behavior/basic.zig-25
...@@ -693,31 +693,6 @@ test "string concatenation" {...@@ -693,31 +693,6 @@ test "string concatenation" {
693 try expect(b[len] == 0);693 try expect(b[len] == 0);
694}694}
695695
696fn manyptrConcat(comptime s: [*:0]const u8) [*:0]const u8 {
697 return "very " ++ s;
698}
699
700test "comptime manyptr concatenation" {
701 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
702 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
703 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
704
705 const s = "epic";
706 const actual = manyptrConcat(s);
707 const expected = "very epic";
708
709 const len = mem.len(actual);
710 const len_with_null = len + 1;
711 {
712 var i: u32 = 0;
713 while (i < len_with_null) : (i += 1) {
714 try expect(actual[i] == expected[i]);
715 }
716 }
717 try expect(actual[len] == 0);
718 try expect(expected[len] == 0);
719}
720
721test "result location is optional inside error union" {696test "result location is optional inside error union" {
722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO697 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
723 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO698 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO