| author | |
| committer | |
| log | 152a2ceaf738301cd59165a4f17d915391321bdc |
| tree | f2239a36d9d2ce92bfaf34742620ce74ec7defb5 |
| parent | 884d957b6c291961536c10401f60264da26cba30 |
| signature |
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: #194354 files changed, 406 insertions(+), 467 deletions(-)
src/Sema.zig+112-80| ... | ... | @@ -1881,10 +1881,10 @@ pub fn toConstString( |
| 1881 | 1881 | air_inst: Air.Inst.Ref, |
| 1882 | 1882 | reason: NeededComptimeReason, |
| 1883 | 1883 | ) ![]u8 { |
| 1884 | const wanted_type = Type.slice_const_u8; | |
| 1885 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); | |
| 1886 | const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason); | |
| 1887 | return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); | |
| 1884 | const coerced_inst = try sema.coerce(block, Type.slice_const_u8, air_inst, src); | |
| 1885 | const slice_val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason); | |
| 1886 | const arr_val = try sema.derefSliceAsArray(block, src, slice_val, reason); | |
| 1887 | return arr_val.toAllocatedBytes(arr_val.typeOf(sema.mod), sema.arena, sema.mod); | |
| 1888 | 1888 | } |
| 1889 | 1889 | |
| 1890 | 1890 | pub fn resolveConstStringIntern( |
| ... | ... | @@ -14498,12 +14498,16 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14498 | 14498 | else => unreachable, |
| 14499 | 14499 | }) |rhs_val| { |
| 14500 | 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 | 14504 | else |
| 14503 | 14505 | lhs_val; |
| 14504 | 14506 | |
| 14505 | 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 | 14511 | else |
| 14508 | 14512 | rhs_val; |
| 14509 | 14513 | |
| ... | ... | @@ -14623,10 +14627,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 14623 | 14627 | .Pointer => { |
| 14624 | 14628 | const ptr_info = operand_ty.ptrInfo(mod); |
| 14625 | 14629 | switch (ptr_info.flags.size) { |
| 14626 | // TODO: in the Many case here this should only work if the type | |
| 14627 | // has a sentinel, and this code should compute the length based | |
| 14628 | // on the sentinel value. | |
| 14629 | .Slice, .Many => { | |
| 14630 | .Slice => { | |
| 14630 | 14631 | const val = try sema.resolveConstDefinedValue(block, src, operand, .{ |
| 14631 | 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 | 14637 | .none => null, |
| 14637 | 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 | 14643 | .One => { |
| ... | ... | @@ -14644,7 +14645,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 14644 | 14645 | return Type.fromInterned(ptr_info.child).arrayInfo(mod); |
| 14645 | 14646 | } |
| 14646 | 14647 | }, |
| 14647 | .C => {}, | |
| 14648 | .C, .Many => {}, | |
| 14648 | 14649 | } |
| 14649 | 14650 | }, |
| 14650 | 14651 | .Struct => { |
| ... | ... | @@ -14830,9 +14831,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14830 | 14831 | const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null; |
| 14831 | 14832 | const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); |
| 14832 | 14833 | |
| 14833 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { | |
| 14834 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| ct: { | |
| 14834 | 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 | 14839 | else |
| 14837 | 14840 | lhs_val; |
| 14838 | 14841 | |
| ... | ... | @@ -14840,7 +14843,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14840 | 14843 | // Optimization for the common pattern of a single element repeated N times, such |
| 14841 | 14844 | // as zero-filling a byte array. |
| 14842 | 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 | 14847 | break :v try mod.intern(.{ .aggregate = .{ |
| 14845 | 14848 | .ty = result_ty.toIntern(), |
| 14846 | 14849 | .storage = .{ .repeated_elem = elem_val.toIntern() }, |
| ... | ... | @@ -14852,7 +14855,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14852 | 14855 | while (elem_i < result_len) { |
| 14853 | 14856 | var lhs_i: usize = 0; |
| 14854 | 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 | 14859 | element_vals[elem_i] = elem_val.toIntern(); |
| 14857 | 14860 | elem_i += 1; |
| 14858 | 14861 | } |
| ... | ... | @@ -21124,7 +21127,9 @@ fn zirReify( |
| 21124 | 21127 | .needed_comptime_reason = "operand to @Type must be comptime-known", |
| 21125 | 21128 | }); |
| 21126 | 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 | 21133 | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; |
| 21129 | 21134 | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { |
| 21130 | 21135 | .Type => return .type_type, |
| ... | ... | @@ -21365,11 +21370,15 @@ fn zirReify( |
| 21365 | 21370 | const payload_val = Value.fromInterned(union_val.val).optionalValue(mod) orelse |
| 21366 | 21371 | return Air.internedToRef(Type.anyerror.toIntern()); |
| 21367 | 21372 | |
| 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 | 21378 | var names: InferredErrorSet.NameMap = .{}; |
| 21370 | 21379 | try names.ensureUnusedCapacity(sema.arena, len); |
| 21371 | 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 | 21382 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 21374 | 21383 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21375 | 21384 | ip, |
| ... | ... | @@ -21417,7 +21426,7 @@ fn zirReify( |
| 21417 | 21426 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); |
| 21418 | 21427 | |
| 21419 | 21428 | // Decls |
| 21420 | if (decls_val.sliceLen(mod) > 0) { | |
| 21429 | if (try decls_val.sliceLen(sema) > 0) { | |
| 21421 | 21430 | return sema.fail(block, src, "reified structs must have no decls", .{}); |
| 21422 | 21431 | } |
| 21423 | 21432 | |
| ... | ... | @@ -21425,7 +21434,11 @@ fn zirReify( |
| 21425 | 21434 | return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); |
| 21426 | 21435 | } |
| 21427 | 21436 | |
| 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 | 21443 | .Enum => { |
| 21431 | 21444 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | ... | @@ -21446,11 +21459,15 @@ fn zirReify( |
| 21446 | 21459 | try ip.getOrPutString(gpa, "is_exhaustive"), |
| 21447 | 21460 | ).?); |
| 21448 | 21461 | |
| 21449 | if (decls_val.sliceLen(mod) > 0) { | |
| 21462 | if (try decls_val.sliceLen(sema) > 0) { | |
| 21450 | 21463 | return sema.fail(block, src, "reified enums must have no decls", .{}); |
| 21451 | 21464 | } |
| 21452 | 21465 | |
| 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 | 21472 | .Opaque => { |
| 21456 | 21473 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | ... | @@ -21460,7 +21477,7 @@ fn zirReify( |
| 21460 | 21477 | ).?); |
| 21461 | 21478 | |
| 21462 | 21479 | // Decls |
| 21463 | if (decls_val.sliceLen(mod) > 0) { | |
| 21480 | if (try decls_val.sliceLen(sema) > 0) { | |
| 21464 | 21481 | return sema.fail(block, src, "reified opaque must have no decls", .{}); |
| 21465 | 21482 | } |
| 21466 | 21483 | |
| ... | ... | @@ -21505,12 +21522,16 @@ fn zirReify( |
| 21505 | 21522 | try ip.getOrPutString(gpa, "decls"), |
| 21506 | 21523 | ).?); |
| 21507 | 21524 | |
| 21508 | if (decls_val.sliceLen(mod) > 0) { | |
| 21525 | if (try decls_val.sliceLen(sema) > 0) { | |
| 21509 | 21526 | return sema.fail(block, src, "reified unions must have no decls", .{}); |
| 21510 | 21527 | } |
| 21511 | 21528 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); |
| 21512 | 21529 | |
| 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 | 21536 | .Fn => { |
| 21516 | 21537 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | ... | @@ -21530,7 +21551,7 @@ fn zirReify( |
| 21530 | 21551 | ip, |
| 21531 | 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 | 21555 | ip, |
| 21535 | 21556 | try ip.getOrPutString(gpa, "params"), |
| 21536 | 21557 | ).?); |
| ... | ... | @@ -21549,12 +21570,16 @@ fn zirReify( |
| 21549 | 21570 | const return_type = return_type_val.optionalValue(mod) orelse |
| 21550 | 21571 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| 21551 | 21572 | |
| 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 | 21578 | const param_types = try sema.arena.alloc(InternPool.Index, args_len); |
| 21554 | 21579 | |
| 21555 | 21580 | var noalias_bits: u32 = 0; |
| 21556 | 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 | 21583 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 21559 | 21584 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21560 | 21585 | ip, |
| ... | ... | @@ -21615,7 +21640,7 @@ fn reifyEnum( |
| 21615 | 21640 | |
| 21616 | 21641 | // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`. |
| 21617 | 21642 | |
| 21618 | const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); | |
| 21643 | const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); | |
| 21619 | 21644 | |
| 21620 | 21645 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21621 | 21646 | // 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 | 21654 | std.hash.autoHash(&hasher, fields_len); |
| 21630 | 21655 | |
| 21631 | 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); | |
| 21633 | 21658 | |
| 21634 | 21659 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21635 | 21660 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); |
| ... | ... | @@ -21674,7 +21699,7 @@ fn reifyEnum( |
| 21674 | 21699 | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 21675 | 21700 | |
| 21676 | 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); | |
| 21678 | 21703 | |
| 21679 | 21704 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21680 | 21705 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); |
| ... | ... | @@ -21736,7 +21761,7 @@ fn reifyUnion( |
| 21736 | 21761 | |
| 21737 | 21762 | // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`. |
| 21738 | 21763 | |
| 21739 | const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); | |
| 21764 | const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); | |
| 21740 | 21765 | |
| 21741 | 21766 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21742 | 21767 | // 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 | 21777 | var any_aligns = false; |
| 21753 | 21778 | |
| 21754 | 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); | |
| 21756 | 21781 | |
| 21757 | 21782 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21758 | 21783 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | ... | @@ -21828,7 +21853,7 @@ fn reifyUnion( |
| 21828 | 21853 | var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len); |
| 21829 | 21854 | |
| 21830 | 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); | |
| 21832 | 21857 | |
| 21833 | 21858 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21834 | 21859 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | ... | @@ -21880,7 +21905,7 @@ fn reifyUnion( |
| 21880 | 21905 | try field_names.ensureTotalCapacity(sema.arena, fields_len); |
| 21881 | 21906 | |
| 21882 | 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); | |
| 21884 | 21909 | |
| 21885 | 21910 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21886 | 21911 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | ... | @@ -21974,7 +21999,7 @@ fn reifyStruct( |
| 21974 | 21999 | |
| 21975 | 22000 | // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`. |
| 21976 | 22001 | |
| 21977 | const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); | |
| 22002 | const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); | |
| 21978 | 22003 | |
| 21979 | 22004 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21980 | 22005 | // 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 | 22018 | var any_aligned_fields = false; |
| 21994 | 22019 | |
| 21995 | 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); | |
| 21997 | 22022 | |
| 21998 | 22023 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21999 | 22024 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | ... | @@ -22071,7 +22096,7 @@ fn reifyStruct( |
| 22071 | 22096 | const struct_type = ip.loadStructType(wip_ty.index); |
| 22072 | 22097 | |
| 22073 | 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); | |
| 22075 | 22100 | |
| 22076 | 22101 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 22077 | 22102 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | ... | @@ -23892,11 +23917,9 @@ fn resolveExportOptions( |
| 23892 | 23917 | const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); |
| 23893 | 23918 | |
| 23894 | 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 | 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); | |
| 23900 | 23923 | |
| 23901 | 23924 | const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); |
| 23902 | 23925 | const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ |
| ... | ... | @@ -23908,9 +23931,10 @@ fn resolveExportOptions( |
| 23908 | 23931 | const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ |
| 23909 | 23932 | .needed_comptime_reason = "linksection of exported value must be comptime-known", |
| 23910 | 23933 | }); |
| 23911 | const section_ty = Type.slice_const_u8; | |
| 23912 | 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 | 23938 | else |
| 23915 | 23939 | null; |
| 23916 | 23940 | |
| ... | ... | @@ -26028,10 +26052,9 @@ fn resolveExternOptions( |
| 26028 | 26052 | const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); |
| 26029 | 26053 | |
| 26030 | 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 | 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); | |
| 26035 | 26058 | |
| 26036 | 26059 | const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src); |
| 26037 | 26060 | const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{ |
| ... | ... | @@ -26050,7 +26073,9 @@ fn resolveExternOptions( |
| 26050 | 26073 | }); |
| 26051 | 26074 | |
| 26052 | 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 | 26079 | if (library_name.len == 0) { |
| 26055 | 26080 | return sema.fail(block, library_src, "library name cannot be empty", .{}); |
| 26056 | 26081 | } |
| ... | ... | @@ -28564,7 +28589,7 @@ fn elemValSlice( |
| 28564 | 28589 | |
| 28565 | 28590 | if (maybe_slice_val) |slice_val| { |
| 28566 | 28591 | runtime_src = elem_index_src; |
| 28567 | const slice_len = slice_val.sliceLen(mod); | |
| 28592 | const slice_len = try slice_val.sliceLen(sema); | |
| 28568 | 28593 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 28569 | 28594 | if (slice_len_s == 0) { |
| 28570 | 28595 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| ... | ... | @@ -28589,7 +28614,7 @@ fn elemValSlice( |
| 28589 | 28614 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 28590 | 28615 | if (oob_safety and block.wantSafety()) { |
| 28591 | 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 | 28618 | else |
| 28594 | 28619 | try block.addTyOp(.slice_len, Type.usize, slice); |
| 28595 | 28620 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | ... | @@ -28626,7 +28651,7 @@ fn elemPtrSlice( |
| 28626 | 28651 | if (slice_val.isUndef(mod)) { |
| 28627 | 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 | 28655 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 28631 | 28656 | if (slice_len_s == 0) { |
| 28632 | 28657 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| ... | ... | @@ -28649,7 +28674,7 @@ fn elemPtrSlice( |
| 28649 | 28674 | const len_inst = len: { |
| 28650 | 28675 | if (maybe_undef_slice_val) |slice_val| |
| 28651 | 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 | 28678 | break :len try block.addTyOp(.slice_len, Type.usize, slice); |
| 28654 | 28679 | }; |
| 28655 | 28680 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | ... | @@ -31523,16 +31548,11 @@ fn coerceArrayPtrToSlice( |
| 31523 | 31548 | if (try sema.resolveValue(inst)) |val| { |
| 31524 | 31549 | const ptr_array_ty = sema.typeOf(inst); |
| 31525 | 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 | 31553 | const slice_val = try mod.intern(.{ .slice = .{ |
| 31527 | 31554 | .ty = dest_ty.toIntern(), |
| 31528 | .ptr = try mod.intern(.{ .ptr = .{ | |
| 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 | } }), | |
| 31555 | .ptr = slice_ptr.toIntern(), | |
| 31536 | 31556 | .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(), |
| 31537 | 31557 | } }); |
| 31538 | 31558 | return Air.internedToRef(slice_val); |
| ... | ... | @@ -32602,7 +32622,7 @@ fn analyzeSliceLen( |
| 32602 | 32622 | if (slice_val.isUndef(mod)) { |
| 32603 | 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 | 32627 | try sema.requireRuntimeBlock(block, src, null); |
| 32608 | 32628 | return block.addTyOp(.slice_len, Type.usize, slice_inst); |
| ... | ... | @@ -33041,7 +33061,7 @@ fn analyzeSlice( |
| 33041 | 33061 | return sema.fail(block, src, "slice of undefined", .{}); |
| 33042 | 33062 | } |
| 33043 | 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 | 33065 | const len_plus_sent = slice_len + @intFromBool(has_sentinel); |
| 33046 | 33066 | const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); |
| 33047 | 33067 | if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { |
| ... | ... | @@ -33056,7 +33076,7 @@ fn analyzeSlice( |
| 33056 | 33076 | "end index {} out of bounds for slice of length {d}{s}", |
| 33057 | 33077 | .{ |
| 33058 | 33078 | end_val.fmtValue(Type.usize, mod), |
| 33059 | slice_val.sliceLen(mod), | |
| 33079 | try slice_val.sliceLen(sema), | |
| 33060 | 33080 | sentinel_label, |
| 33061 | 33081 | }, |
| 33062 | 33082 | ); |
| ... | ... | @@ -33285,7 +33305,7 @@ fn analyzeSlice( |
| 33285 | 33305 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { |
| 33286 | 33306 | // we don't need to add one for sentinels because the |
| 33287 | 33307 | // 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 | } |
| 33290 | 33310 | |
| 33291 | 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 | 39023 | } |
| 39004 | 39024 | |
| 39005 | 39025 | /// Returns true if any value contained in `val` is undefined. |
| 39006 | fn anyUndef(sema: *Sema, val: Value) !bool { | |
| 39026 | fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool { | |
| 39007 | 39027 | const mod = sema.mod; |
| 39008 | return switch (val.toIntern()) { | |
| 39028 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 39009 | 39029 | .undef => true, |
| 39010 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 39011 | .undef => true, | |
| 39012 | .simple_value => |v| v == .undefined, | |
| 39013 | .slice => |slice| for (0..@intCast(Value.fromInterned(slice.len).toUnsignedInt(mod))) |idx| { | |
| 39014 | if (try sema.anyUndef((try val.maybeElemValueFull(sema, mod, idx)).?)) break true; | |
| 39015 | } else false, | |
| 39016 | .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { | |
| 39017 | const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; | |
| 39018 | if (try sema.anyUndef(Value.fromInterned(elem))) break true; | |
| 39019 | } else false, | |
| 39020 | else => false, | |
| 39021 | }, | |
| 39030 | .simple_value => |v| v == .undefined, | |
| 39031 | .slice => { | |
| 39032 | // If the slice contents are runtime-known, reification will fail later on with a | |
| 39033 | // specific error message. | |
| 39034 | const arr = try sema.maybeDerefSliceAsArray(block, src, val) orelse return false; | |
| 39035 | return sema.anyUndef(block, src, arr); | |
| 39036 | }, | |
| 39037 | .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { | |
| 39038 | const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; | |
| 39039 | if (try sema.anyUndef(block, src, Value.fromInterned(elem))) break true; | |
| 39040 | } else false, | |
| 39041 | else => false, | |
| 39022 | 39042 | }; |
| 39023 | 39043 | } |
| 39024 | 39044 | |
| ... | ... | @@ -39050,6 +39070,20 @@ fn derefSliceAsArray( |
| 39050 | 39070 | slice_val: Value, |
| 39051 | 39071 | reason: NeededComptimeReason, |
| 39052 | 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. | |
| 39081 | fn maybeDerefSliceAsArray( | |
| 39082 | sema: *Sema, | |
| 39083 | block: *Block, | |
| 39084 | src: LazySrcLoc, | |
| 39085 | slice_val: Value, | |
| 39086 | ) CompileError!?Value { | |
| 39053 | 39087 | const zcu = sema.mod; |
| 39054 | 39088 | const ip = &zcu.intern_pool; |
| 39055 | 39089 | assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu)); |
| ... | ... | @@ -39072,7 +39106,5 @@ fn derefSliceAsArray( |
| 39072 | 39106 | break :p p; |
| 39073 | 39107 | }); |
| 39074 | 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 { | |
| 39076 | return sema.failWithNeededComptime(block, src, reason); | |
| 39077 | }; | |
| 39109 | return sema.pointerDeref(block, src, casted_ptr, ptr_ty); | |
| 39078 | 39110 | } |
src/TypedValue.zig+250-270| ... | ... | @@ -1,7 +1,10 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const Type = @import("type.zig").Type; |
| 3 | 3 | const Value = @import("Value.zig"); |
| 4 | const Module = @import("Module.zig"); | |
| 4 | const Zcu = @import("Module.zig"); | |
| 5 | const Module = Zcu; | |
| 6 | const Sema = @import("Sema.zig"); | |
| 7 | const InternPool = @import("InternPool.zig"); | |
| 5 | 8 | const Allocator = std.mem.Allocator; |
| 6 | 9 | const TypedValue = @This(); |
| 7 | 10 | const Target = std.Target; |
| ... | ... | @@ -61,8 +64,10 @@ pub fn format( |
| 61 | 64 | ) !void { |
| 62 | 65 | _ = options; |
| 63 | 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 | 68 | 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 | 71 | else => |e| return e, |
| 67 | 72 | }; |
| 68 | 73 | } |
| ... | ... | @@ -73,11 +78,12 @@ pub fn print( |
| 73 | 78 | writer: anytype, |
| 74 | 79 | level: u8, |
| 75 | 80 | mod: *Module, |
| 76 | ) (@TypeOf(writer).Error || Allocator.Error)!void { | |
| 77 | var val = tv.val; | |
| 78 | var ty = tv.ty; | |
| 81 | /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output. | |
| 82 | opt_sema: ?*Sema, | |
| 83 | ) (@TypeOf(writer).Error || Module.CompileError)!void { | |
| 79 | 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 | 87 | .int_type, |
| 82 | 88 | .ptr_type, |
| 83 | 89 | .array_type, |
| ... | ... | @@ -94,324 +100,298 @@ pub fn print( |
| 94 | 100 | .func_type, |
| 95 | 101 | .error_set_type, |
| 96 | 102 | .inferred_error_set_type, |
| 97 | => return Type.print(val.toType(), writer, mod), | |
| 98 | .undef => return writer.writeAll("undefined"), | |
| 103 | => try Type.print(val.toType(), writer, mod), | |
| 104 | .undef => try writer.writeAll("undefined"), | |
| 99 | 105 | .simple_value => |simple_value| switch (simple_value) { |
| 100 | .void => return writer.writeAll("{}"), | |
| 101 | .empty_struct => return printAggregate(ty, val, writer, level, mod), | |
| 102 | .generic_poison => return writer.writeAll("(generic poison)"), | |
| 103 | else => return writer.writeAll(@tagName(simple_value)), | |
| 106 | .void => try writer.writeAll("{}"), | |
| 107 | .empty_struct => try writer.writeAll(".{}"), | |
| 108 | .generic_poison => try writer.writeAll("(generic poison)"), | |
| 109 | else => try writer.writeAll(@tagName(simple_value)), | |
| 104 | 110 | }, |
| 105 | .variable => return writer.writeAll("(variable)"), | |
| 106 | .extern_func => |extern_func| return writer.print("(extern function '{}')", .{ | |
| 111 | .variable => try writer.writeAll("(variable)"), | |
| 112 | .extern_func => |extern_func| try writer.print("(extern function '{}')", .{ | |
| 107 | 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 | 116 | mod.declPtr(func.owner_decl).name.fmt(ip), |
| 111 | 117 | }), |
| 112 | 118 | .int => |int| switch (int.storage) { |
| 113 | inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), | |
| 114 | .lazy_align => |lazy_ty| return writer.print("{d}", .{ | |
| 115 | Type.fromInterned(lazy_ty).abiAlignment(mod), | |
| 116 | }), | |
| 117 | .lazy_size => |lazy_ty| return writer.print("{d}", .{ | |
| 118 | Type.fromInterned(lazy_ty).abiSize(mod), | |
| 119 | }), | |
| 119 | inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}), | |
| 120 | .lazy_align => |ty| if (opt_sema) |sema| { | |
| 121 | const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar; | |
| 122 | try writer.print("{}", .{a.toByteUnits(0)}); | |
| 123 | } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}), | |
| 124 | .lazy_size => |ty| if (opt_sema) |sema| { | |
| 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 | 130 | err.name.fmt(ip), |
| 123 | 131 | }), |
| 124 | 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 | 134 | err_name.fmt(ip), |
| 127 | 135 | }), |
| 128 | .payload => |payload| { | |
| 129 | val = Value.fromInterned(payload); | |
| 130 | ty = ty.errorUnionPayload(mod); | |
| 131 | }, | |
| 136 | .payload => |payload| try print(.{ | |
| 137 | .ty = tv.ty.errorUnionPayload(mod), | |
| 138 | .val = Value.fromInterned(payload), | |
| 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 | 142 | enum_literal.fmt(ip), |
| 135 | 143 | }), |
| 136 | 144 | .enum_tag => |enum_tag| { |
| 137 | if (level == 0) { | |
| 138 | return writer.writeAll("(enum)"); | |
| 139 | } | |
| 140 | const enum_type = ip.loadEnumType(ty.toIntern()); | |
| 145 | const enum_type = ip.loadEnumType(val.typeOf(mod).toIntern()); | |
| 141 | 146 | if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { |
| 142 | 147 | try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); |
| 143 | 148 | return; |
| 144 | 149 | } |
| 150 | if (level == 0) { | |
| 151 | try writer.writeAll("@enumFromInt(...)"); | |
| 152 | } | |
| 145 | 153 | try writer.writeAll("@enumFromInt("); |
| 146 | 154 | try print(.{ |
| 147 | 155 | .ty = Type.fromInterned(ip.typeOf(enum_tag.int)), |
| 148 | 156 | .val = Value.fromInterned(enum_tag.int), |
| 149 | }, writer, level - 1, mod); | |
| 157 | }, writer, level - 1, mod, opt_sema); | |
| 150 | 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 | 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 | 164 | .slice => |slice| { |
| 158 | const ptr_ty = switch (ip.indexToKey(slice.ptr)) { | |
| 159 | .ptr => |ptr| ty: { | |
| 160 | if (ptr.addr == .int) return print(.{ | |
| 161 | .ty = Type.fromInterned(ptr.ty), | |
| 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, | |
| 165 | const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) { | |
| 166 | .field, .elem, .eu_payload, .opt_payload => unreachable, | |
| 167 | .anon_decl, .comptime_alloc, .comptime_field => true, | |
| 168 | .decl, .int => false, | |
| 168 | 169 | }; |
| 169 | if (level == 0) { | |
| 170 | return writer.writeAll(".{ ... }"); | |
| 171 | } | |
| 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 }); | |
| 170 | if (print_contents) { | |
| 171 | // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's | |
| 172 | // currently not possible without e.g. triggering compile errors. | |
| 185 | 173 | } |
| 186 | try writer.writeAll(".{ "); | |
| 187 | const max_len = @min(len, max_aggregate_items); | |
| 188 | for (0..max_len) |i| { | |
| 189 | if (i != 0) try writer.writeAll(", "); | |
| 190 | const maybe_elem = try val.maybeElemValue(mod, i); | |
| 191 | const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }"); | |
| 192 | try print(.{ | |
| 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(" }"); | |
| 174 | try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema); | |
| 175 | try writer.writeAll("[0.."); | |
| 176 | try print(.{ | |
| 177 | .ty = Type.usize, | |
| 178 | .val = Value.fromInterned(slice.len), | |
| 179 | }, writer, level - 1, mod, opt_sema); | |
| 180 | try writer.writeAll("]"); | |
| 201 | 181 | }, |
| 202 | .ptr => |ptr| { | |
| 203 | switch (ptr.addr) { | |
| 204 | .decl => |decl_index| { | |
| 205 | const decl = mod.declPtr(decl_index); | |
| 206 | if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); | |
| 207 | return print(.{ | |
| 208 | .ty = decl.typeOf(mod), | |
| 209 | .val = decl.val, | |
| 210 | }, writer, level - 1, mod); | |
| 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 | }, | |
| 182 | .ptr => { | |
| 183 | const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) { | |
| 184 | .field, .elem, .eu_payload, .opt_payload => unreachable, | |
| 185 | .anon_decl, .comptime_alloc, .comptime_field => true, | |
| 186 | .decl, .int => false, | |
| 187 | }; | |
| 188 | if (print_contents) { | |
| 189 | // TODO: eventually we want to load the pointer with `opt_sema`, but that's | |
| 190 | // currently not possible without e.g. triggering compile errors. | |
| 301 | 191 | } |
| 302 | return; | |
| 192 | try printPtr(val.toIntern(), writer, false, false, 0, level, mod, opt_sema); | |
| 303 | 193 | }, |
| 304 | 194 | .opt => |opt| switch (opt.val) { |
| 305 | .none => return writer.writeAll("null"), | |
| 306 | else => |payload| { | |
| 307 | val = Value.fromInterned(payload); | |
| 308 | ty = ty.optionalChild(mod); | |
| 309 | }, | |
| 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), | |
| 195 | .none => try writer.writeAll("null"), | |
| 196 | else => |payload| try print(.{ | |
| 197 | .ty = tv.ty.childType(mod), | |
| 198 | .val = Value.fromInterned(payload), | |
| 199 | }, writer, level, mod, opt_sema), | |
| 322 | 200 | }, |
| 201 | .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, mod, opt_sema), | |
| 323 | 202 | .un => |un| { |
| 324 | try writer.writeAll(".{ "); | |
| 325 | if (level > 0) { | |
| 326 | if (un.tag != .none) { | |
| 327 | try print(.{ | |
| 328 | .ty = ty.unionTagTypeHypothetical(mod), | |
| 329 | .val = Value.fromInterned(un.tag), | |
| 330 | }, writer, level - 1, mod); | |
| 331 | try writer.writeAll(" = "); | |
| 332 | const field_ty = ty.unionFieldType(Value.fromInterned(un.tag), mod).?; | |
| 333 | try print(.{ | |
| 334 | .ty = field_ty, | |
| 335 | .val = Value.fromInterned(un.val), | |
| 336 | }, writer, level - 1, mod); | |
| 337 | } else { | |
| 338 | try writer.writeAll("(unknown tag) = "); | |
| 339 | const backing_ty = try ty.unionBackingType(mod); | |
| 340 | try print(.{ | |
| 341 | .ty = backing_ty, | |
| 342 | .val = Value.fromInterned(un.val), | |
| 343 | }, writer, level - 1, mod); | |
| 344 | } | |
| 345 | } else try writer.writeAll("..."); | |
| 346 | return writer.writeAll(" }"); | |
| 203 | if (level == 0) { | |
| 204 | try writer.writeAll(".{ ... }"); | |
| 205 | return; | |
| 206 | } | |
| 207 | if (un.tag == .none) { | |
| 208 | const backing_ty = try tv.ty.unionBackingType(mod); | |
| 209 | try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(mod)}); | |
| 210 | try print(.{ | |
| 211 | .ty = backing_ty, | |
| 212 | .val = Value.fromInterned(un.val), | |
| 213 | }, writer, level - 1, mod, opt_sema); | |
| 214 | try writer.writeAll("))"); | |
| 215 | } else { | |
| 216 | try writer.writeAll(".{ "); | |
| 217 | try print(.{ | |
| 218 | .ty = tv.ty.unionTagTypeHypothetical(mod), | |
| 219 | .val = Value.fromInterned(un.tag), | |
| 220 | }, writer, level - 1, mod, opt_sema); | |
| 221 | try writer.writeAll(" = "); | |
| 222 | const field_ty = tv.ty.unionFieldType(Value.fromInterned(un.tag), mod).?; | |
| 223 | try print(.{ | |
| 224 | .ty = field_ty, | |
| 225 | .val = Value.fromInterned(un.val), | |
| 226 | }, writer, level - 1, mod, opt_sema); | |
| 227 | try writer.writeAll(" }"); | |
| 228 | } | |
| 347 | 229 | }, |
| 348 | 230 | .memoized_call => unreachable, |
| 349 | }; | |
| 231 | } | |
| 350 | 232 | } |
| 351 | 233 | |
| 352 | 234 | fn printAggregate( |
| 353 | ty: Type, | |
| 354 | 235 | val: Value, |
| 236 | aggregate: InternPool.Key.Aggregate, | |
| 355 | 237 | writer: anytype, |
| 356 | 238 | level: u8, |
| 357 | mod: *Module, | |
| 358 | ) (@TypeOf(writer).Error || Allocator.Error)!void { | |
| 239 | zcu: *Zcu, | |
| 240 | opt_sema: ?*Sema, | |
| 241 | ) (@TypeOf(writer).Error || Module.CompileError)!void { | |
| 359 | 242 | if (level == 0) { |
| 360 | 243 | return writer.writeAll(".{ ... }"); |
| 361 | 244 | } |
| 362 | const ip = &mod.intern_pool; | |
| 363 | if (ty.zigTypeTag(mod) == .Struct) { | |
| 364 | try writer.writeAll(".{"); | |
| 365 | const max_len = @min(ty.structFieldCount(mod), max_aggregate_items); | |
| 366 | ||
| 367 | for (0..max_len) |i| { | |
| 368 | if (i != 0) try writer.writeAll(", "); | |
| 245 | const ip = &zcu.intern_pool; | |
| 246 | const ty = Type.fromInterned(aggregate.ty); | |
| 247 | switch (ty.zigTypeTag(zcu)) { | |
| 248 | .Struct => if (!ty.isTuple(zcu)) { | |
| 249 | if (ty.structFieldCount(zcu) == 0) { | |
| 250 | return 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 | } | |
| 369 | 276 | |
| 370 | const field_name = ty.structFieldName(@intCast(i), mod); | |
| 277 | const elem_ty = ty.childType(zcu); | |
| 278 | const len = ty.arrayLen(zcu); | |
| 371 | 279 | |
| 372 | if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(ip)}); | |
| 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); | |
| 280 | try writer.writeAll(".{ "); | |
| 385 | 281 | |
| 386 | if (elem_ty.eql(Type.u8, mod)) str: { | |
| 387 | const max_len: usize = @min(len, max_string_len); | |
| 388 | var buf: [max_string_len]u8 = undefined; | |
| 282 | const max_len = @min(len, max_aggregate_items); | |
| 283 | for (0..max_len) |i| { | |
| 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 | } | |
| 389 | 295 | |
| 390 | var i: u32 = 0; | |
| 391 | while (i < max_len) : (i += 1) { | |
| 392 | const elem = try val.fieldValue(mod, i); | |
| 393 | if (elem.isUndef(mod)) break :str; | |
| 394 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; | |
| 296 | fn printPtr( | |
| 297 | ptr_val: InternPool.Index, | |
| 298 | writer: anytype, | |
| 299 | force_type: bool, | |
| 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 | } |
| 396 | ||
| 397 | const truncated = if (len > max_string_len) " (truncated)" else ""; | |
| 398 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | |
| 399 | } | |
| 400 | ||
| 401 | try writer.writeAll(".{ "); | |
| 402 | ||
| 403 | const max_len = @min(len, max_aggregate_items); | |
| 404 | var i: u32 = 0; | |
| 405 | while (i < max_len) : (i += 1) { | |
| 406 | if (i != 0) try writer.writeAll(", "); | |
| 336 | }, | |
| 337 | .decl => |index| { | |
| 338 | try writer.writeAll("&"); | |
| 339 | try zcu.declPtr(index).renderFullyQualifiedName(zcu, writer); | |
| 340 | }, | |
| 341 | .comptime_alloc => try writer.writeAll("&(comptime alloc)"), | |
| 342 | .anon_decl => |anon| { | |
| 343 | const ty = Type.fromInterned(ip.typeOf(anon.val)); | |
| 344 | try writer.print("&@as({}, ", .{ty.fmt(zcu)}); | |
| 407 | 345 | try print(.{ |
| 408 | .ty = elem_ty, | |
| 409 | .val = try val.fieldValue(mod, i), | |
| 410 | }, writer, level - 1, mod); | |
| 411 | } | |
| 412 | if (len > max_aggregate_items) { | |
| 413 | try writer.writeAll(", ..."); | |
| 414 | } | |
| 415 | return writer.writeAll(" }"); | |
| 346 | .ty = ty, | |
| 347 | .val = Value.fromInterned(anon.val), | |
| 348 | }, writer, level - 1, zcu, opt_sema); | |
| 349 | try writer.writeAll(")"); | |
| 350 | }, | |
| 351 | .comptime_field => |val| { | |
| 352 | const ty = Type.fromInterned(ip.typeOf(val)); | |
| 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 | 305 | }; |
| 306 | 306 | } |
| 307 | 307 | |
| 308 | fn isDeclRef(val: Value, mod: *Module) bool { | |
| 308 | fn ptrHasIntAddr(val: Value, mod: *Module) bool { | |
| 309 | 309 | var check = val; |
| 310 | 310 | while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) { |
| 311 | 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 | 314 | .eu_payload, .opt_payload => |base| check = Value.fromInterned(base), |
| 314 | 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 | } |
| 320 | 320 | |
| ... | ... | @@ -439,7 +439,7 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ |
| 439 | 439 | }, |
| 440 | 440 | .Pointer => { |
| 441 | 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 | 443 | return val.writeToMemory(Type.usize, mod, buffer); |
| 444 | 444 | }, |
| 445 | 445 | .Optional => { |
| ... | ... | @@ -566,7 +566,7 @@ pub fn writeToPackedMemory( |
| 566 | 566 | }, |
| 567 | 567 | .Pointer => { |
| 568 | 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 | 570 | return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); |
| 571 | 571 | }, |
| 572 | 572 | .Optional => { |
| ... | ... | @@ -1261,62 +1261,23 @@ pub fn slicePtr(val: Value, mod: *Module) Value { |
| 1261 | 1261 | return Value.fromInterned(mod.intern_pool.slicePtr(val.toIntern())); |
| 1262 | 1262 | } |
| 1263 | 1263 | |
| 1264 | pub fn sliceLen(val: Value, mod: *Module) u64 { | |
| 1265 | const ip = &mod.intern_pool; | |
| 1266 | return switch (ip.indexToKey(val.toIntern())) { | |
| 1267 | .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) { | |
| 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. | |
| 1284 | pub 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. | |
| 1289 | pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value { | |
| 1290 | return val.maybeElemValueFull(null, mod, index); | |
| 1264 | /// Gets the `len` field of a slice value as a `u64`. | |
| 1265 | /// Resolves the length using the provided `Sema` if necessary. | |
| 1266 | pub fn sliceLen(val: Value, sema: *Sema) !u64 { | |
| 1267 | return Value.fromInterned(sema.mod.intern_pool.sliceLen(val.toIntern())).toUnsignedIntAdvanced(sema); | |
| 1291 | 1268 | } |
| 1292 | 1269 | |
| 1293 | pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) Allocator.Error!?Value { | |
| 1294 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1295 | .undef => |ty| Value.fromInterned((try mod.intern(.{ | |
| 1296 | .undef = Type.fromInterned(ty).elemType2(mod).toIntern(), | |
| 1297 | }))), | |
| 1298 | .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index), | |
| 1299 | .ptr => |ptr| switch (ptr.addr) { | |
| 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), | |
| 1270 | /// Asserts the value is an aggregate, and returns the element value at the given index. | |
| 1271 | pub fn elemValue(val: Value, zcu: *Zcu, index: usize) Allocator.Error!Value { | |
| 1272 | const ip = &zcu.intern_pool; | |
| 1273 | switch (zcu.intern_pool.indexToKey(val.toIntern())) { | |
| 1274 | .undef => |ty| { | |
| 1275 | return Value.fromInterned(try zcu.intern(.{ .undef = Type.fromInterned(ty).childType(zcu).toIntern() })); | |
| 1276 | }, | |
| 1316 | 1277 | .aggregate => |aggregate| { |
| 1317 | const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); | |
| 1278 | const len = ip.aggregateTypeLen(aggregate.ty); | |
| 1318 | 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 | 1281 | .ty = .u8_type, |
| 1321 | 1282 | .storage = .{ .u64 = bytes[index] }, |
| 1322 | 1283 | } }), |
| ... | ... | @@ -1324,10 +1285,10 @@ pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) |
| 1324 | 1285 | .repeated_elem => |elem| elem, |
| 1325 | 1286 | }); |
| 1326 | 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, | |
| 1330 | }; | |
| 1290 | else => unreachable, | |
| 1291 | } | |
| 1331 | 1292 | } |
| 1332 | 1293 | |
| 1333 | 1294 | pub fn isLazyAlign(val: Value, mod: *Module) bool { |
| ... | ... | @@ -1359,39 +1320,26 @@ pub fn sliceArray( |
| 1359 | 1320 | ) error{OutOfMemory}!Value { |
| 1360 | 1321 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 1361 | 1322 | const mod = sema.mod; |
| 1362 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | |
| 1363 | .ptr => |ptr| switch (ptr.addr) { | |
| 1364 | .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end), | |
| 1365 | .comptime_alloc => |idx| try Value.fromInterned( | |
| 1366 | try sema.getComptimeAlloc(idx).val.intern(mod, sema.arena), | |
| 1367 | ).sliceArray(sema, start, end), | |
| 1368 | .comptime_field => |comptime_field| Value.fromInterned(comptime_field) | |
| 1369 | .sliceArray(sema, start, end), | |
| 1370 | .elem => |elem| Value.fromInterned(elem.base) | |
| 1371 | .sliceArray(sema, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))), | |
| 1323 | const aggregate = mod.intern_pool.indexToKey(val.toIntern()).aggregate; | |
| 1324 | return Value.fromInterned(try mod.intern(.{ .aggregate = .{ | |
| 1325 | .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { | |
| 1326 | .array_type => |array_type| try mod.arrayType(.{ | |
| 1327 | .len = @as(u32, @intCast(end - start)), | |
| 1328 | .child = array_type.child, | |
| 1329 | .sentinel = if (end == array_type.len) array_type.sentinel else .none, | |
| 1330 | }), | |
| 1331 | .vector_type => |vector_type| try mod.vectorType(.{ | |
| 1332 | .len = @as(u32, @intCast(end - start)), | |
| 1333 | .child = vector_type.child, | |
| 1334 | }), | |
| 1372 | 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 = .{ | |
| 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 | }; | |
| 1342 | } })); | |
| 1395 | 1343 | } |
| 1396 | 1344 | |
| 1397 | 1345 | pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { |
| ... | ... | @@ -3586,6 +3534,10 @@ pub fn isGenericPoison(val: Value) bool { |
| 3586 | 3534 | return val.toIntern() == .generic_poison; |
| 3587 | 3535 | } |
| 3588 | 3536 | |
| 3537 | pub fn typeOf(val: Value, zcu: *const Zcu) Type { | |
| 3538 | return Type.fromInterned(zcu.intern_pool.typeOf(val.toIntern())); | |
| 3539 | } | |
| 3540 | ||
| 3589 | 3541 | /// For an integer (comptime or fixed-width) `val`, returns the comptime-known bounds of the value. |
| 3590 | 3542 | /// If `val` is not undef, the bounds are both `val`. |
| 3591 | 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 | 693 | try expect(b[len] == 0); |
| 694 | 694 | } |
| 695 | 695 | |
| 696 | fn manyptrConcat(comptime s: [*:0]const u8) [*:0]const u8 { | |
| 697 | return "very " ++ s; | |
| 698 | } | |
| 699 | ||
| 700 | test "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 | ||
| 721 | 696 | test "result location is optional inside error union" { |
| 722 | 697 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 723 | 698 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |