| ... | ... | @@ -139,8 +139,7 @@ const MaybeComptimeAlloc = struct { |
| 139 | 139 | }; |
| 140 | 140 | |
| 141 | 141 | const ComptimeAlloc = struct { |
| 142 | | ty: Type, |
| 143 | | val: Value, |
| 142 | val: MutableValue, |
| 144 | 143 | is_const: bool, |
| 145 | 144 | /// `.none` indicates that the alignment is the natural alignment of `val`. |
| 146 | 145 | alignment: Alignment, |
| ... | ... | @@ -153,8 +152,7 @@ const ComptimeAlloc = struct { |
| 153 | 152 | fn newComptimeAlloc(sema: *Sema, block: *Block, ty: Type, alignment: Alignment) !ComptimeAllocIndex { |
| 154 | 153 | const idx = sema.comptime_allocs.items.len; |
| 155 | 154 | try sema.comptime_allocs.append(sema.gpa, .{ |
| 156 | | .ty = ty, |
| 157 | | .val = Value.fromInterned(try sema.mod.intern(.{ .undef = ty.toIntern() })), |
| 155 | .val = .{ .interned = try sema.mod.intern(.{ .undef = ty.toIntern() }) }, |
| 158 | 156 | .is_const = false, |
| 159 | 157 | .alignment = alignment, |
| 160 | 158 | .runtime_index = block.runtime_index, |
| ... | ... | @@ -175,6 +173,7 @@ const log = std.log.scoped(.sema); |
| 175 | 173 | |
| 176 | 174 | const Sema = @This(); |
| 177 | 175 | const Value = @import("Value.zig"); |
| 176 | const MutableValue = @import("mutable_value.zig").MutableValue; |
| 178 | 177 | const Type = @import("type.zig").Type; |
| 179 | 178 | const TypedValue = @import("TypedValue.zig"); |
| 180 | 179 | const Air = @import("Air.zig"); |
| ... | ... | @@ -3762,10 +3761,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 3762 | 3761 | if (!sema.isComptimeMutablePtr(ptr_val)) break :already_ct; |
| 3763 | 3762 | const alloc_index = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr.comptime_alloc; |
| 3764 | 3763 | const ct_alloc = sema.getComptimeAlloc(alloc_index); |
| 3765 | | const interned = try ct_alloc.val.intern(ct_alloc.ty, mod); |
| 3764 | const interned = try ct_alloc.val.intern(mod, sema.arena); |
| 3766 | 3765 | if (Value.fromInterned(interned).canMutateComptimeVarState(mod)) { |
| 3767 | 3766 | // Preserve the comptime alloc, just make the pointer const. |
| 3768 | | ct_alloc.val = Value.fromInterned(interned); |
| 3767 | ct_alloc.val = .{ .interned = interned }; |
| 3769 | 3768 | ct_alloc.is_const = true; |
| 3770 | 3769 | return sema.makePtrConst(block, alloc); |
| 3771 | 3770 | } else { |
| ... | ... | @@ -4030,7 +4029,7 @@ fn finishResolveComptimeKnownAllocPtr( |
| 4030 | 4029 | const alloc_index = existing_comptime_alloc orelse a: { |
| 4031 | 4030 | const idx = try sema.newComptimeAlloc(block, alloc_ty.childType(zcu), alloc_ty.ptrAlignment(zcu)); |
| 4032 | 4031 | const alloc = sema.getComptimeAlloc(idx); |
| 4033 | | alloc.val = Value.fromInterned(result_val); |
| 4032 | alloc.val = .{ .interned = result_val }; |
| 4034 | 4033 | break :a idx; |
| 4035 | 4034 | }; |
| 4036 | 4035 | sema.getComptimeAlloc(alloc_index).is_const = true; |
| ... | ... | @@ -4193,7 +4192,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4193 | 4192 | .anon_decl => |a| a.val, |
| 4194 | 4193 | .comptime_alloc => |i| val: { |
| 4195 | 4194 | const alloc = sema.getComptimeAlloc(i); |
| 4196 | | break :val try alloc.val.intern(alloc.ty, mod); |
| 4195 | break :val try alloc.val.intern(mod, sema.arena); |
| 4197 | 4196 | }, |
| 4198 | 4197 | else => unreachable, |
| 4199 | 4198 | }; |
| ... | ... | @@ -5597,7 +5596,7 @@ fn storeToInferredAllocComptime( |
| 5597 | 5596 | } }); |
| 5598 | 5597 | } else { |
| 5599 | 5598 | const alloc_index = try sema.newComptimeAlloc(block, operand_ty, iac.alignment); |
| 5600 | | sema.getComptimeAlloc(alloc_index).val = operand_val; |
| 5599 | sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() }; |
| 5601 | 5600 | iac.ptr = try zcu.intern(.{ .ptr = .{ |
| 5602 | 5601 | .ty = alloc_ty.toIntern(), |
| 5603 | 5602 | .addr = .{ .comptime_alloc = alloc_index }, |
| ... | ... | @@ -30655,21 +30654,22 @@ fn storePtrVal( |
| 30655 | 30654 | .opv => {}, |
| 30656 | 30655 | .direct => |val_ptr| { |
| 30657 | 30656 | if (mut_kit.root == .comptime_field) { |
| 30658 | | val_ptr.* = Value.fromInterned((try val_ptr.intern(operand_ty, mod))); |
| 30659 | | if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { |
| 30657 | val_ptr.* = .{ .interned = try val_ptr.intern(mod, sema.arena) }; |
| 30658 | if (operand_val.toIntern() != val_ptr.interned) { |
| 30660 | 30659 | // TODO use failWithInvalidComptimeFieldStore |
| 30661 | 30660 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); |
| 30662 | 30661 | } |
| 30663 | 30662 | return; |
| 30664 | 30663 | } |
| 30665 | | val_ptr.* = Value.fromInterned((try operand_val.intern(operand_ty, mod))); |
| 30664 | val_ptr.* = .{ .interned = operand_val.toIntern() }; |
| 30666 | 30665 | }, |
| 30667 | 30666 | .reinterpret => |reinterpret| { |
| 30668 | 30667 | try sema.resolveTypeLayout(mut_kit.ty); |
| 30669 | 30668 | const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod)); |
| 30670 | 30669 | const buffer = try sema.gpa.alloc(u8, abi_size); |
| 30671 | 30670 | defer sema.gpa.free(buffer); |
| 30672 | | reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) { |
| 30671 | const interned_old = Value.fromInterned(try reinterpret.val_ptr.intern(mod, sema.arena)); |
| 30672 | interned_old.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) { |
| 30673 | 30673 | error.OutOfMemory => return error.OutOfMemory, |
| 30674 | 30674 | error.ReinterpretDeclRef => unreachable, |
| 30675 | 30675 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already |
| ... | ... | @@ -30693,7 +30693,7 @@ fn storePtrVal( |
| 30693 | 30693 | error.IllDefinedMemoryLayout => unreachable, |
| 30694 | 30694 | error.Unimplemented => return sema.fail(block, src, "TODO: implement readFromMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), |
| 30695 | 30695 | }; |
| 30696 | | reinterpret.val_ptr.* = Value.fromInterned((try val.intern(mut_kit.ty, mod))); |
| 30696 | reinterpret.val_ptr.* = .{ .interned = val.toIntern() }; |
| 30697 | 30697 | }, |
| 30698 | 30698 | .bad_decl_ty, .bad_ptr_ty => { |
| 30699 | 30699 | // TODO show the decl declaration site in a note and explain whether the decl |
| ... | ... | @@ -30718,11 +30718,11 @@ const ComptimePtrMutationKit = struct { |
| 30718 | 30718 | opv, |
| 30719 | 30719 | /// The pointer type matches the actual comptime Value so a direct |
| 30720 | 30720 | /// modification is possible. |
| 30721 | | direct: *Value, |
| 30721 | direct: *MutableValue, |
| 30722 | 30722 | /// The largest parent Value containing pointee and having a well-defined memory layout. |
| 30723 | 30723 | /// This is used for bitcasting, if direct dereferencing failed. |
| 30724 | 30724 | reinterpret: struct { |
| 30725 | | val_ptr: *Value, |
| 30725 | val_ptr: *MutableValue, |
| 30726 | 30726 | byte_offset: usize, |
| 30727 | 30727 | /// If set, write the operand to packed memory |
| 30728 | 30728 | write_packed: bool = false, |
| ... | ... | @@ -30754,15 +30754,15 @@ fn beginComptimePtrMutation( |
| 30754 | 30754 | .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already |
| 30755 | 30755 | .comptime_alloc => |alloc_index| { |
| 30756 | 30756 | const alloc = sema.getComptimeAlloc(alloc_index); |
| 30757 | | return sema.beginComptimePtrMutationInner(block, src, alloc.ty, &alloc.val, ptr_elem_ty, .{ .alloc = alloc_index }); |
| 30757 | return sema.beginComptimePtrMutationInner(block, src, alloc.val.typeOf(mod), &alloc.val, ptr_elem_ty, .{ .alloc = alloc_index }); |
| 30758 | 30758 | }, |
| 30759 | 30759 | .comptime_field => |comptime_field| { |
| 30760 | | const duped = try sema.arena.create(Value); |
| 30761 | | duped.* = Value.fromInterned(comptime_field); |
| 30760 | const duped = try sema.arena.create(MutableValue); |
| 30761 | duped.* = .{ .interned = comptime_field }; |
| 30762 | 30762 | return sema.beginComptimePtrMutationInner( |
| 30763 | 30763 | block, |
| 30764 | 30764 | src, |
| 30765 | | Type.fromInterned(mod.intern_pool.typeOf(comptime_field)), |
| 30765 | duped.typeOf(mod), |
| 30766 | 30766 | duped, |
| 30767 | 30767 | ptr_elem_ty, |
| 30768 | 30768 | .comptime_field, |
| ... | ... | @@ -30775,36 +30775,28 @@ fn beginComptimePtrMutation( |
| 30775 | 30775 | .opv => unreachable, |
| 30776 | 30776 | .direct => |val_ptr| { |
| 30777 | 30777 | const payload_ty = parent.ty.errorUnionPayload(mod); |
| 30778 | | if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { |
| 30779 | | return ComptimePtrMutationKit{ |
| 30780 | | .root = parent.root, |
| 30781 | | .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, |
| 30782 | | .ty = payload_ty, |
| 30783 | | }; |
| 30784 | | } else { |
| 30778 | try val_ptr.unintern(mod, sema.arena, false, false); |
| 30779 | if (val_ptr.* == .interned) { |
| 30785 | 30780 | // An error union has been initialized to undefined at comptime and now we |
| 30786 | 30781 | // are for the first time setting the payload. We must change the |
| 30787 | | // representation of the error union from `undef` to `opt_payload`. |
| 30788 | | |
| 30789 | | const payload = try sema.arena.create(Value.Payload.SubValue); |
| 30790 | | payload.* = .{ |
| 30791 | | .base = .{ .tag = .eu_payload }, |
| 30792 | | .data = Value.fromInterned((try mod.intern(.{ .undef = payload_ty.toIntern() }))), |
| 30793 | | }; |
| 30794 | | |
| 30795 | | val_ptr.* = Value.initPayload(&payload.base); |
| 30796 | | |
| 30797 | | return ComptimePtrMutationKit{ |
| 30798 | | .root = parent.root, |
| 30799 | | .pointee = .{ .direct = &payload.data }, |
| 30800 | | .ty = payload_ty, |
| 30801 | | }; |
| 30782 | // representation of the error union to `eu_payload`. |
| 30783 | const child = try sema.arena.create(MutableValue); |
| 30784 | child.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) }; |
| 30785 | val_ptr.* = .{ .eu_payload = .{ |
| 30786 | .ty = parent.ty.toIntern(), |
| 30787 | .child = child, |
| 30788 | } }; |
| 30802 | 30789 | } |
| 30790 | return .{ |
| 30791 | .root = parent.root, |
| 30792 | .pointee = .{ .direct = val_ptr.eu_payload.child }, |
| 30793 | .ty = payload_ty, |
| 30794 | }; |
| 30803 | 30795 | }, |
| 30804 | 30796 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 30805 | 30797 | // Even though the parent value type has well-defined memory layout, our |
| 30806 | 30798 | // pointer type does not. |
| 30807 | | .reinterpret => return ComptimePtrMutationKit{ |
| 30799 | .reinterpret => return .{ |
| 30808 | 30800 | .root = parent.root, |
| 30809 | 30801 | .pointee = .bad_ptr_ty, |
| 30810 | 30802 | .ty = eu_ty, |
| ... | ... | @@ -30818,46 +30810,28 @@ fn beginComptimePtrMutation( |
| 30818 | 30810 | .opv => unreachable, |
| 30819 | 30811 | .direct => |val_ptr| { |
| 30820 | 30812 | const payload_ty = parent.ty.optionalChild(mod); |
| 30821 | | switch (val_ptr.ip_index) { |
| 30822 | | .none => return ComptimePtrMutationKit{ |
| 30823 | | .root = parent.root, |
| 30824 | | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, |
| 30825 | | .ty = payload_ty, |
| 30826 | | }, |
| 30827 | | else => { |
| 30828 | | const payload_val = switch (mod.intern_pool.indexToKey(val_ptr.ip_index)) { |
| 30829 | | .undef => try mod.intern(.{ .undef = payload_ty.toIntern() }), |
| 30830 | | .opt => |opt| switch (opt.val) { |
| 30831 | | .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), |
| 30832 | | else => |payload| payload, |
| 30833 | | }, |
| 30834 | | else => unreachable, |
| 30835 | | }; |
| 30836 | | |
| 30837 | | // An optional has been initialized to undefined at comptime and now we |
| 30838 | | // are for the first time setting the payload. We must change the |
| 30839 | | // representation of the optional from `undef` to `opt_payload`. |
| 30840 | | |
| 30841 | | const payload = try sema.arena.create(Value.Payload.SubValue); |
| 30842 | | payload.* = .{ |
| 30843 | | .base = .{ .tag = .opt_payload }, |
| 30844 | | .data = Value.fromInterned(payload_val), |
| 30845 | | }; |
| 30846 | | |
| 30847 | | val_ptr.* = Value.initPayload(&payload.base); |
| 30848 | | |
| 30849 | | return ComptimePtrMutationKit{ |
| 30850 | | .root = parent.root, |
| 30851 | | .pointee = .{ .direct = &payload.data }, |
| 30852 | | .ty = payload_ty, |
| 30853 | | }; |
| 30854 | | }, |
| 30813 | try val_ptr.unintern(mod, sema.arena, false, false); |
| 30814 | if (val_ptr.* == .interned) { |
| 30815 | // An optional has been initialized to undefined at comptime and now we |
| 30816 | // are for the first time setting the payload. We must change the |
| 30817 | // representation of the optional to `opt_payload`. |
| 30818 | const child = try sema.arena.create(MutableValue); |
| 30819 | child.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) }; |
| 30820 | val_ptr.* = .{ .opt_payload = .{ |
| 30821 | .ty = parent.ty.toIntern(), |
| 30822 | .child = child, |
| 30823 | } }; |
| 30855 | 30824 | } |
| 30825 | return .{ |
| 30826 | .root = parent.root, |
| 30827 | .pointee = .{ .direct = val_ptr.opt_payload.child }, |
| 30828 | .ty = payload_ty, |
| 30829 | }; |
| 30856 | 30830 | }, |
| 30857 | 30831 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 30858 | 30832 | // Even though the parent value type has well-defined memory layout, our |
| 30859 | 30833 | // pointer type does not. |
| 30860 | | .reinterpret => return ComptimePtrMutationKit{ |
| 30834 | .reinterpret => return .{ |
| 30861 | 30835 | .root = parent.root, |
| 30862 | 30836 | .pointee = .bad_ptr_ty, |
| 30863 | 30837 | .ty = opt_ty, |
| ... | ... | @@ -30916,106 +30890,28 @@ fn beginComptimePtrMutation( |
| 30916 | 30890 | }; |
| 30917 | 30891 | } |
| 30918 | 30892 | |
| 30919 | | switch (val_ptr.ip_index) { |
| 30920 | | .none => switch (val_ptr.tag()) { |
| 30921 | | .bytes => { |
| 30922 | | // An array is memory-optimized to store a slice of bytes, but we are about |
| 30923 | | // to modify an individual field and the representation has to change. |
| 30924 | | // If we wanted to avoid this, there would need to be special detection |
| 30925 | | // elsewhere to identify when writing a value to an array element that is stored |
| 30926 | | // using the `bytes` tag, and handle it without making a call to this function. |
| 30927 | | const arena = sema.arena; |
| 30928 | | |
| 30929 | | const bytes = val_ptr.castTag(.bytes).?.data; |
| 30930 | | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); |
| 30931 | | // bytes.len may be one greater than dest_len because of the case when |
| 30932 | | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. |
| 30933 | | assert(bytes.len >= dest_len); |
| 30934 | | const elems = try arena.alloc(Value, @intCast(dest_len)); |
| 30935 | | for (elems, 0..) |*elem, i| { |
| 30936 | | elem.* = try mod.intValue(elem_ty, bytes[i]); |
| 30937 | | } |
| 30938 | | |
| 30939 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 30940 | | |
| 30941 | | return beginComptimePtrMutationInner( |
| 30942 | | sema, |
| 30943 | | block, |
| 30944 | | src, |
| 30945 | | elem_ty, |
| 30946 | | &elems[@intCast(elem_ptr.index)], |
| 30947 | | ptr_elem_ty, |
| 30948 | | parent.root, |
| 30949 | | ); |
| 30950 | | }, |
| 30951 | | .repeated => { |
| 30952 | | // An array is memory-optimized to store only a single element value, and |
| 30953 | | // that value is understood to be the same for the entire length of the array. |
| 30954 | | // However, now we want to modify an individual field and so the |
| 30955 | | // representation has to change. If we wanted to avoid this, there would |
| 30956 | | // need to be special detection elsewhere to identify when writing a value to an |
| 30957 | | // array element that is stored using the `repeated` tag, and handle it |
| 30958 | | // without making a call to this function. |
| 30959 | | const arena = sema.arena; |
| 30960 | | |
| 30961 | | const repeated_val = try val_ptr.castTag(.repeated).?.data.intern(parent.ty.childType(mod), mod); |
| 30962 | | const array_len_including_sentinel = |
| 30963 | | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); |
| 30964 | | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 30965 | | @memset(elems, Value.fromInterned(repeated_val)); |
| 30966 | | |
| 30967 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 30968 | | |
| 30969 | | return beginComptimePtrMutationInner( |
| 30970 | | sema, |
| 30971 | | block, |
| 30972 | | src, |
| 30973 | | elem_ty, |
| 30974 | | &elems[@intCast(elem_ptr.index)], |
| 30975 | | ptr_elem_ty, |
| 30976 | | parent.root, |
| 30977 | | ); |
| 30978 | | }, |
| 30979 | | |
| 30980 | | .aggregate => return beginComptimePtrMutationInner( |
| 30981 | | sema, |
| 30982 | | block, |
| 30983 | | src, |
| 30984 | | elem_ty, |
| 30985 | | &val_ptr.castTag(.aggregate).?.data[@intCast(elem_ptr.index)], |
| 30986 | | ptr_elem_ty, |
| 30987 | | parent.root, |
| 30988 | | ), |
| 30893 | try val_ptr.unintern(mod, sema.arena, false, false); |
| 30894 | |
| 30895 | const aggregate = switch (val_ptr.*) { |
| 30896 | .interned, |
| 30897 | .bytes, |
| 30898 | .repeated, |
| 30899 | .eu_payload, |
| 30900 | .opt_payload, |
| 30901 | .slice, |
| 30902 | .un, |
| 30903 | => unreachable, |
| 30904 | .aggregate => |*a| a, |
| 30905 | }; |
| 30989 | 30906 | |
| 30990 | | else => unreachable, |
| 30991 | | }, |
| 30992 | | else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { |
| 30993 | | .undef => { |
| 30994 | | // An array has been initialized to undefined at comptime and now we |
| 30995 | | // are for the first time setting an element. We must change the representation |
| 30996 | | // of the array from `undef` to `array`. |
| 30997 | | const arena = sema.arena; |
| 30998 | | |
| 30999 | | const array_len_including_sentinel = |
| 31000 | | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); |
| 31001 | | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 31002 | | @memset(elems, Value.fromInterned((try mod.intern(.{ .undef = elem_ty.toIntern() })))); |
| 31003 | | |
| 31004 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 31005 | | |
| 31006 | | return beginComptimePtrMutationInner( |
| 31007 | | sema, |
| 31008 | | block, |
| 31009 | | src, |
| 31010 | | elem_ty, |
| 31011 | | &elems[@intCast(elem_ptr.index)], |
| 31012 | | ptr_elem_ty, |
| 31013 | | parent.root, |
| 31014 | | ); |
| 31015 | | }, |
| 31016 | | else => unreachable, |
| 31017 | | }, |
| 31018 | | } |
| 30907 | return sema.beginComptimePtrMutationInner( |
| 30908 | block, |
| 30909 | src, |
| 30910 | elem_ty, |
| 30911 | &aggregate.elems[@intCast(elem_ptr.index)], |
| 30912 | ptr_elem_ty, |
| 30913 | parent.root, |
| 30914 | ); |
| 31019 | 30915 | }, |
| 31020 | 30916 | else => { |
| 31021 | 30917 | if (elem_ptr.index != 0) { |
| ... | ... | @@ -31039,7 +30935,7 @@ fn beginComptimePtrMutation( |
| 31039 | 30935 | if (!base_elem_ty.hasWellDefinedLayout(mod)) { |
| 31040 | 30936 | // Even though the parent value type has well-defined memory layout, our |
| 31041 | 30937 | // pointer type does not. |
| 31042 | | return ComptimePtrMutationKit{ |
| 30938 | return .{ |
| 31043 | 30939 | .root = parent.root, |
| 31044 | 30940 | .pointee = .bad_ptr_ty, |
| 31045 | 30941 | .ty = base_elem_ty, |
| ... | ... | @@ -31049,7 +30945,7 @@ fn beginComptimePtrMutation( |
| 31049 | 30945 | const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); |
| 31050 | 30946 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 31051 | 30947 | const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); |
| 31052 | | return ComptimePtrMutationKit{ |
| 30948 | return .{ |
| 31053 | 30949 | .root = parent.root, |
| 31054 | 30950 | .pointee = .{ .reinterpret = .{ |
| 31055 | 30951 | .val_ptr = reinterpret.val_ptr, |
| ... | ... | @@ -31068,56 +30964,68 @@ fn beginComptimePtrMutation( |
| 31068 | 30964 | var parent = try sema.beginComptimePtrMutation(block, src, Value.fromInterned(field_ptr.base), base_child_ty); |
| 31069 | 30965 | switch (parent.pointee) { |
| 31070 | 30966 | .opv => unreachable, |
| 31071 | | .direct => |val_ptr| switch (val_ptr.ip_index) { |
| 31072 | | .empty_struct => { |
| 31073 | | const duped = try sema.arena.create(Value); |
| 31074 | | duped.* = val_ptr.*; |
| 31075 | | return beginComptimePtrMutationInner( |
| 31076 | | sema, |
| 31077 | | block, |
| 31078 | | src, |
| 31079 | | parent.ty.structFieldType(field_index, mod), |
| 31080 | | duped, |
| 31081 | | ptr_elem_ty, |
| 31082 | | parent.root, |
| 31083 | | ); |
| 31084 | | }, |
| 31085 | | .none => switch (val_ptr.tag()) { |
| 31086 | | .aggregate => return beginComptimePtrMutationInner( |
| 31087 | | sema, |
| 30967 | .direct => |val_ptr| { |
| 30968 | try val_ptr.unintern(mod, sema.arena, false, false); |
| 30969 | switch (val_ptr.*) { |
| 30970 | .interned, |
| 30971 | .eu_payload, |
| 30972 | .opt_payload, |
| 30973 | .repeated, |
| 30974 | .bytes, |
| 30975 | => unreachable, |
| 30976 | .aggregate => |*a| return sema.beginComptimePtrMutationInner( |
| 31088 | 30977 | block, |
| 31089 | 30978 | src, |
| 31090 | 30979 | parent.ty.structFieldType(field_index, mod), |
| 31091 | | &val_ptr.castTag(.aggregate).?.data[field_index], |
| 30980 | &a.elems[field_index], |
| 31092 | 30981 | ptr_elem_ty, |
| 31093 | 30982 | parent.root, |
| 31094 | 30983 | ), |
| 31095 | | .repeated => { |
| 31096 | | const arena = sema.arena; |
| 31097 | | |
| 31098 | | const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 31099 | | @memset(elems, val_ptr.castTag(.repeated).?.data); |
| 31100 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 31101 | | |
| 31102 | | return beginComptimePtrMutationInner( |
| 31103 | | sema, |
| 30984 | .slice => |*s| switch (field_index) { |
| 30985 | Value.slice_ptr_index => return sema.beginComptimePtrMutationInner( |
| 31104 | 30986 | block, |
| 31105 | 30987 | src, |
| 31106 | | parent.ty.structFieldType(field_index, mod), |
| 31107 | | &elems[field_index], |
| 30988 | parent.ty.slicePtrFieldType(mod), |
| 30989 | s.ptr, |
| 31108 | 30990 | ptr_elem_ty, |
| 31109 | 30991 | parent.root, |
| 31110 | | ); |
| 30992 | ), |
| 30993 | Value.slice_len_index => return sema.beginComptimePtrMutationInner( |
| 30994 | block, |
| 30995 | src, |
| 30996 | Type.usize, |
| 30997 | s.len, |
| 30998 | ptr_elem_ty, |
| 30999 | parent.root, |
| 31000 | ), |
| 31001 | else => unreachable, |
| 31111 | 31002 | }, |
| 31112 | | .@"union" => { |
| 31113 | | const payload = &val_ptr.castTag(.@"union").?.data; |
| 31003 | .un => |*un| { |
| 31114 | 31004 | const layout = base_child_ty.containerLayout(mod); |
| 31115 | 31005 | |
| 31116 | 31006 | const tag_type = base_child_ty.unionTagTypeHypothetical(mod); |
| 31117 | 31007 | const hypothetical_tag = try mod.enumValueFieldIndex(tag_type, field_index); |
| 31118 | | if (layout == .auto or (payload.tag != null and hypothetical_tag.eql(payload.tag.?, tag_type, mod))) { |
| 31008 | if (un.tag == .none and un.payload.* == .interned and un.payload.interned == .undef) { |
| 31009 | // A union has been initialized to undefined at comptime and now we |
| 31010 | // are for the first time setting the payload. We must change the |
| 31011 | // tag implicitly. |
| 31012 | const payload_ty = parent.ty.structFieldType(field_index, mod); |
| 31013 | un.tag = hypothetical_tag.toIntern(); |
| 31014 | un.payload.* = .{ .interned = try mod.intern(.{ .undef = payload_ty.toIntern() }) }; |
| 31015 | return beginComptimePtrMutationInner( |
| 31016 | sema, |
| 31017 | block, |
| 31018 | src, |
| 31019 | payload_ty, |
| 31020 | un.payload, |
| 31021 | ptr_elem_ty, |
| 31022 | parent.root, |
| 31023 | ); |
| 31024 | } |
| 31025 | |
| 31026 | if (layout == .auto or hypothetical_tag.toIntern() == un.tag) { |
| 31119 | 31027 | // We need to set the active field of the union. |
| 31120 | | payload.tag = hypothetical_tag; |
| 31028 | un.tag = hypothetical_tag.toIntern(); |
| 31121 | 31029 | |
| 31122 | 31030 | const field_ty = parent.ty.structFieldType(field_index, mod); |
| 31123 | 31031 | return beginComptimePtrMutationInner( |
| ... | ... | @@ -31125,7 +31033,7 @@ fn beginComptimePtrMutation( |
| 31125 | 31033 | block, |
| 31126 | 31034 | src, |
| 31127 | 31035 | field_ty, |
| 31128 | | &payload.val, |
| 31036 | un.payload, |
| 31129 | 31037 | ptr_elem_ty, |
| 31130 | 31038 | parent.root, |
| 31131 | 31039 | ); |
| ... | ... | @@ -31133,11 +31041,10 @@ fn beginComptimePtrMutation( |
| 31133 | 31041 | // Writing to a different field (a different or unknown tag is active) requires reinterpreting |
| 31134 | 31042 | // memory of the entire union, which requires knowing its abiSize. |
| 31135 | 31043 | try sema.resolveTypeLayout(parent.ty); |
| 31136 | | |
| 31137 | 31044 | // This union value no longer has a well-defined tag type. |
| 31138 | 31045 | // The reinterpretation will read it back out as .none. |
| 31139 | | payload.val = try payload.val.unintern(sema.arena, mod); |
| 31140 | | return ComptimePtrMutationKit{ |
| 31046 | try un.payload.unintern(mod, sema.arena, false, false); |
| 31047 | return .{ |
| 31141 | 31048 | .root = parent.root, |
| 31142 | 31049 | .pointee = .{ .reinterpret = .{ |
| 31143 | 31050 | .val_ptr = val_ptr, |
| ... | ... | @@ -31148,119 +31055,12 @@ fn beginComptimePtrMutation( |
| 31148 | 31055 | }; |
| 31149 | 31056 | } |
| 31150 | 31057 | }, |
| 31151 | | .slice => switch (field_index) { |
| 31152 | | Value.slice_ptr_index => return beginComptimePtrMutationInner( |
| 31153 | | sema, |
| 31154 | | block, |
| 31155 | | src, |
| 31156 | | parent.ty.slicePtrFieldType(mod), |
| 31157 | | &val_ptr.castTag(.slice).?.data.ptr, |
| 31158 | | ptr_elem_ty, |
| 31159 | | parent.root, |
| 31160 | | ), |
| 31161 | | |
| 31162 | | Value.slice_len_index => return beginComptimePtrMutationInner( |
| 31163 | | sema, |
| 31164 | | block, |
| 31165 | | src, |
| 31166 | | Type.usize, |
| 31167 | | &val_ptr.castTag(.slice).?.data.len, |
| 31168 | | ptr_elem_ty, |
| 31169 | | parent.root, |
| 31170 | | ), |
| 31171 | | |
| 31172 | | else => unreachable, |
| 31173 | | }, |
| 31174 | | else => unreachable, |
| 31175 | | }, |
| 31176 | | else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { |
| 31177 | | .undef => { |
| 31178 | | // A struct or union has been initialized to undefined at comptime and now we |
| 31179 | | // are for the first time setting a field. We must change the representation |
| 31180 | | // of the struct/union from `undef` to `struct`/`union`. |
| 31181 | | const arena = sema.arena; |
| 31182 | | |
| 31183 | | switch (parent.ty.zigTypeTag(mod)) { |
| 31184 | | .Struct => { |
| 31185 | | const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 31186 | | for (fields, 0..) |*field, i| field.* = Value.fromInterned((try mod.intern(.{ |
| 31187 | | .undef = parent.ty.structFieldType(i, mod).toIntern(), |
| 31188 | | }))); |
| 31189 | | |
| 31190 | | val_ptr.* = try Value.Tag.aggregate.create(arena, fields); |
| 31191 | | |
| 31192 | | return beginComptimePtrMutationInner( |
| 31193 | | sema, |
| 31194 | | block, |
| 31195 | | src, |
| 31196 | | parent.ty.structFieldType(field_index, mod), |
| 31197 | | &fields[field_index], |
| 31198 | | ptr_elem_ty, |
| 31199 | | parent.root, |
| 31200 | | ); |
| 31201 | | }, |
| 31202 | | .Union => { |
| 31203 | | const payload = try arena.create(Value.Payload.Union); |
| 31204 | | const tag_ty = parent.ty.unionTagTypeHypothetical(mod); |
| 31205 | | const payload_ty = parent.ty.structFieldType(field_index, mod); |
| 31206 | | payload.* = .{ .data = .{ |
| 31207 | | .tag = try mod.enumValueFieldIndex(tag_ty, field_index), |
| 31208 | | .val = Value.fromInterned((try mod.intern(.{ .undef = payload_ty.toIntern() }))), |
| 31209 | | } }; |
| 31210 | | |
| 31211 | | val_ptr.* = Value.initPayload(&payload.base); |
| 31212 | | |
| 31213 | | return beginComptimePtrMutationInner( |
| 31214 | | sema, |
| 31215 | | block, |
| 31216 | | src, |
| 31217 | | payload_ty, |
| 31218 | | &payload.data.val, |
| 31219 | | ptr_elem_ty, |
| 31220 | | parent.root, |
| 31221 | | ); |
| 31222 | | }, |
| 31223 | | .Pointer => { |
| 31224 | | assert(parent.ty.isSlice(mod)); |
| 31225 | | const ptr_ty = parent.ty.slicePtrFieldType(mod); |
| 31226 | | val_ptr.* = try Value.Tag.slice.create(arena, .{ |
| 31227 | | .ptr = Value.fromInterned((try mod.intern(.{ .undef = ptr_ty.toIntern() }))), |
| 31228 | | .len = Value.fromInterned((try mod.intern(.{ .undef = .usize_type }))), |
| 31229 | | }); |
| 31230 | | |
| 31231 | | switch (field_index) { |
| 31232 | | Value.slice_ptr_index => return beginComptimePtrMutationInner( |
| 31233 | | sema, |
| 31234 | | block, |
| 31235 | | src, |
| 31236 | | ptr_ty, |
| 31237 | | &val_ptr.castTag(.slice).?.data.ptr, |
| 31238 | | ptr_elem_ty, |
| 31239 | | parent.root, |
| 31240 | | ), |
| 31241 | | Value.slice_len_index => return beginComptimePtrMutationInner( |
| 31242 | | sema, |
| 31243 | | block, |
| 31244 | | src, |
| 31245 | | Type.usize, |
| 31246 | | &val_ptr.castTag(.slice).?.data.len, |
| 31247 | | ptr_elem_ty, |
| 31248 | | parent.root, |
| 31249 | | ), |
| 31250 | | |
| 31251 | | else => unreachable, |
| 31252 | | } |
| 31253 | | }, |
| 31254 | | else => unreachable, |
| 31255 | | } |
| 31256 | | }, |
| 31257 | | else => unreachable, |
| 31258 | | }, |
| 31058 | } |
| 31259 | 31059 | }, |
| 31260 | 31060 | .reinterpret => |reinterpret| { |
| 31261 | 31061 | const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod); |
| 31262 | 31062 | const field_offset = try sema.usizeCast(block, src, field_offset_u64); |
| 31263 | | return ComptimePtrMutationKit{ |
| 31063 | return .{ |
| 31264 | 31064 | .root = parent.root, |
| 31265 | 31065 | .pointee = .{ .reinterpret = .{ |
| 31266 | 31066 | .val_ptr = reinterpret.val_ptr, |
| ... | ... | @@ -31280,7 +31080,7 @@ fn beginComptimePtrMutationInner( |
| 31280 | 31080 | block: *Block, |
| 31281 | 31081 | src: LazySrcLoc, |
| 31282 | 31082 | decl_ty: Type, |
| 31283 | | decl_val: *Value, |
| 31083 | decl_val: *MutableValue, |
| 31284 | 31084 | ptr_elem_ty: Type, |
| 31285 | 31085 | root: ComptimePtrMutationKit.Root, |
| 31286 | 31086 | ) CompileError!ComptimePtrMutationKit { |
| ... | ... | @@ -31288,7 +31088,13 @@ fn beginComptimePtrMutationInner( |
| 31288 | 31088 | const target = mod.getTarget(); |
| 31289 | 31089 | const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; |
| 31290 | 31090 | |
| 31291 | | decl_val.* = try decl_val.unintern(sema.arena, mod); |
| 31091 | const old_decl_val = decl_val.*; |
| 31092 | try decl_val.unintern(mod, sema.arena, false, false); |
| 31093 | if (decl_val.* == .un and decl_val.un.tag == .none and decl_val.un.payload.* == .interned and decl_val.un.payload.interned == .undef) { |
| 31094 | // HACKHACK: undefined union - re-intern it for now |
| 31095 | // `unintern` probably should just leave these as is, but I'm leaving it until I rewrite comptime pointer access. |
| 31096 | decl_val.* = old_decl_val; |
| 31097 | } |
| 31292 | 31098 | |
| 31293 | 31099 | if (coerce_ok) { |
| 31294 | 31100 | return ComptimePtrMutationKit{ |
| ... | ... | @@ -31334,21 +31140,16 @@ fn beginComptimePtrMutationInner( |
| 31334 | 31140 | }; |
| 31335 | 31141 | } |
| 31336 | 31142 | |
| 31337 | | const TypedValueAndOffset = struct { |
| 31338 | | tv: TypedValue, |
| 31339 | | byte_offset: usize, |
| 31340 | | }; |
| 31341 | | |
| 31342 | 31143 | const ComptimePtrLoadKit = struct { |
| 31343 | 31144 | /// The Value and Type corresponding to the pointee of the provided pointer. |
| 31344 | 31145 | /// If a direct dereference is not possible, this is null. |
| 31345 | | pointee: ?TypedValue, |
| 31146 | pointee: ?MutableValue, |
| 31346 | 31147 | /// The largest parent Value containing `pointee` and having a well-defined memory layout. |
| 31347 | 31148 | /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null). |
| 31348 | | parent: ?TypedValueAndOffset, |
| 31349 | | /// Whether the `pointee` could be mutated by further |
| 31350 | | /// semantic analysis and a copy must be performed. |
| 31351 | | is_mutable: bool, |
| 31149 | parent: ?struct { |
| 31150 | val: MutableValue, |
| 31151 | byte_offset: usize, |
| 31152 | }, |
| 31352 | 31153 | /// If the root decl could not be used as `parent`, this is the type that |
| 31353 | 31154 | /// caused that by not having a well-defined layout |
| 31354 | 31155 | ty_without_well_defined_layout: ?Type, |
| ... | ... | @@ -31375,53 +31176,41 @@ fn beginComptimePtrLoad( |
| 31375 | 31176 | .ptr => |ptr| switch (ptr.addr) { |
| 31376 | 31177 | .decl => |decl_index| blk: { |
| 31377 | 31178 | const decl = mod.declPtr(decl_index); |
| 31378 | | const decl_tv = try decl.typedValue(mod); |
| 31379 | 31179 | try sema.declareDependency(.{ .decl_val = decl_index }); |
| 31380 | 31180 | if (decl.val.getVariable(mod) != null) return error.RuntimeLoad; |
| 31381 | | |
| 31181 | const decl_val: MutableValue = .{ .interned = decl.val.toIntern() }; |
| 31382 | 31182 | const layout_defined = decl.typeOf(mod).hasWellDefinedLayout(mod); |
| 31383 | 31183 | break :blk ComptimePtrLoadKit{ |
| 31384 | | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, |
| 31385 | | .pointee = decl_tv, |
| 31386 | | .is_mutable = false, |
| 31184 | .parent = if (layout_defined) .{ .val = decl_val, .byte_offset = 0 } else null, |
| 31185 | .pointee = decl_val, |
| 31387 | 31186 | .ty_without_well_defined_layout = if (!layout_defined) decl.typeOf(mod) else null, |
| 31388 | 31187 | }; |
| 31389 | 31188 | }, |
| 31390 | 31189 | .comptime_alloc => |alloc_index| kit: { |
| 31391 | 31190 | const alloc = sema.getComptimeAlloc(alloc_index); |
| 31392 | | const alloc_tv: TypedValue = .{ |
| 31393 | | .ty = alloc.ty, |
| 31394 | | .val = alloc.val, |
| 31395 | | }; |
| 31396 | | const layout_defined = alloc.ty.hasWellDefinedLayout(mod); |
| 31191 | const alloc_ty = alloc.val.typeOf(mod); |
| 31192 | const layout_defined = alloc_ty.hasWellDefinedLayout(mod); |
| 31397 | 31193 | break :kit .{ |
| 31398 | | .parent = if (layout_defined) .{ .tv = alloc_tv, .byte_offset = 0 } else null, |
| 31399 | | .pointee = alloc_tv, |
| 31400 | | .is_mutable = true, |
| 31401 | | .ty_without_well_defined_layout = if (!layout_defined) alloc.ty else null, |
| 31194 | .parent = if (layout_defined) .{ .val = alloc.val, .byte_offset = 0 } else null, |
| 31195 | .pointee = alloc.val, |
| 31196 | .ty_without_well_defined_layout = if (!layout_defined) alloc_ty else null, |
| 31402 | 31197 | }; |
| 31403 | 31198 | }, |
| 31404 | 31199 | .anon_decl => |anon_decl| blk: { |
| 31405 | 31200 | const decl_val = anon_decl.val; |
| 31406 | 31201 | if (Value.fromInterned(decl_val).getVariable(mod) != null) return error.RuntimeLoad; |
| 31407 | 31202 | const decl_ty = Type.fromInterned(ip.typeOf(decl_val)); |
| 31408 | | const decl_tv: TypedValue = .{ .ty = decl_ty, .val = Value.fromInterned(decl_val) }; |
| 31203 | const decl_mv: MutableValue = .{ .interned = decl_val }; |
| 31409 | 31204 | const layout_defined = decl_ty.hasWellDefinedLayout(mod); |
| 31410 | 31205 | break :blk ComptimePtrLoadKit{ |
| 31411 | | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, |
| 31412 | | .pointee = decl_tv, |
| 31413 | | .is_mutable = false, |
| 31206 | .parent = if (layout_defined) .{ .val = decl_mv, .byte_offset = 0 } else null, |
| 31207 | .pointee = decl_mv, |
| 31414 | 31208 | .ty_without_well_defined_layout = if (!layout_defined) decl_ty else null, |
| 31415 | 31209 | }; |
| 31416 | 31210 | }, |
| 31417 | 31211 | .int => return error.RuntimeLoad, |
| 31418 | 31212 | .eu_payload, .opt_payload => |container_ptr| blk: { |
| 31419 | 31213 | const container_ty = Type.fromInterned(ip.typeOf(container_ptr)).childType(mod); |
| 31420 | | const payload_ty = switch (ptr.addr) { |
| 31421 | | .eu_payload => container_ty.errorUnionPayload(mod), |
| 31422 | | .opt_payload => container_ty.optionalChild(mod), |
| 31423 | | else => unreachable, |
| 31424 | | }; |
| 31425 | 31214 | var deref = try sema.beginComptimePtrLoad(block, src, Value.fromInterned(container_ptr), container_ty); |
| 31426 | 31215 | |
| 31427 | 31216 | // eu_payload and opt_payload never have a well-defined layout |
| ... | ... | @@ -31430,15 +31219,14 @@ fn beginComptimePtrLoad( |
| 31430 | 31219 | deref.ty_without_well_defined_layout = container_ty; |
| 31431 | 31220 | } |
| 31432 | 31221 | |
| 31433 | | if (deref.pointee) |*tv| { |
| 31222 | if (deref.pointee) |pointee| { |
| 31223 | const pointee_ty = pointee.typeOf(mod); |
| 31434 | 31224 | const coerce_in_mem_ok = |
| 31435 | | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or |
| 31436 | | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; |
| 31225 | (try sema.coerceInMemoryAllowed(block, container_ty, pointee_ty, false, target, src, src)) == .ok or |
| 31226 | (try sema.coerceInMemoryAllowed(block, pointee_ty, container_ty, false, target, src, src)) == .ok; |
| 31437 | 31227 | if (coerce_in_mem_ok) { |
| 31438 | | const payload_val = switch (tv.val.ip_index) { |
| 31439 | | .none => tv.val.cast(Value.Payload.SubValue).?.data, |
| 31440 | | .null_value => return sema.fail(block, src, "attempt to use null value", .{}), |
| 31441 | | else => Value.fromInterned(switch (ip.indexToKey(tv.val.toIntern())) { |
| 31228 | deref.pointee = switch (pointee) { |
| 31229 | .interned => |ip_index| .{ .interned = switch (ip.indexToKey(ip_index)) { |
| 31442 | 31230 | .error_union => |error_union| switch (error_union.val) { |
| 31443 | 31231 | .err_name => |err_name| return sema.fail( |
| 31444 | 31232 | block, |
| ... | ... | @@ -31453,23 +31241,20 @@ fn beginComptimePtrLoad( |
| 31453 | 31241 | else => |payload| payload, |
| 31454 | 31242 | }, |
| 31455 | 31243 | else => unreachable, |
| 31456 | | }), |
| 31244 | } }, |
| 31245 | .eu_payload, .opt_payload => |p| p.child.*, |
| 31246 | else => unreachable, |
| 31457 | 31247 | }; |
| 31458 | | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; |
| 31459 | 31248 | break :blk deref; |
| 31460 | 31249 | } |
| 31461 | 31250 | } |
| 31462 | 31251 | deref.pointee = null; |
| 31463 | 31252 | break :blk deref; |
| 31464 | 31253 | }, |
| 31465 | | .comptime_field => |comptime_field| blk: { |
| 31466 | | const field_ty = Type.fromInterned(ip.typeOf(comptime_field)); |
| 31467 | | break :blk ComptimePtrLoadKit{ |
| 31468 | | .parent = null, |
| 31469 | | .pointee = .{ .ty = field_ty, .val = Value.fromInterned(comptime_field) }, |
| 31470 | | .is_mutable = false, |
| 31471 | | .ty_without_well_defined_layout = field_ty, |
| 31472 | | }; |
| 31254 | .comptime_field => |field_val| .{ |
| 31255 | .parent = null, |
| 31256 | .pointee = .{ .interned = field_val }, |
| 31257 | .ty_without_well_defined_layout = Type.fromInterned(ip.typeOf(field_val)), |
| 31473 | 31258 | }, |
| 31474 | 31259 | .elem => |elem_ptr| blk: { |
| 31475 | 31260 | const elem_ty = Type.fromInterned(ip.typeOf(elem_ptr.base)).elemType2(mod); |
| ... | ... | @@ -31502,30 +31287,37 @@ fn beginComptimePtrLoad( |
| 31502 | 31287 | |
| 31503 | 31288 | // If we're loading an elem that was derived from a different type |
| 31504 | 31289 | // than the true type of the underlying decl, we cannot deref directly |
| 31505 | | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { |
| 31506 | | const deref_elem_ty = deref.pointee.?.ty.childType(mod); |
| 31507 | | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or |
| 31508 | | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; |
| 31290 | const ty_matches = if (deref.pointee) |pointee| match: { |
| 31291 | const ty = pointee.typeOf(mod); |
| 31292 | if (!ty.isArrayOrVector(mod)) break :match false; |
| 31293 | const deref_elem_ty = ty.childType(mod); |
| 31294 | if ((try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok) break :match true; |
| 31295 | if ((try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok) break :match true; |
| 31296 | break :match false; |
| 31509 | 31297 | } else false; |
| 31510 | 31298 | if (!ty_matches) { |
| 31511 | 31299 | deref.pointee = null; |
| 31512 | 31300 | break :blk deref; |
| 31513 | 31301 | } |
| 31514 | 31302 | |
| 31515 | | var array_tv = deref.pointee.?; |
| 31516 | | const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); |
| 31303 | var array_val = deref.pointee.?; |
| 31304 | const check_len = array_val.typeOf(mod).arrayLenIncludingSentinel(mod); |
| 31517 | 31305 | if (maybe_array_ty) |load_ty| { |
| 31518 | 31306 | // It's possible that we're loading a [N]T, in which case we'd like to slice |
| 31519 | 31307 | // the pointee array directly from our parent array. |
| 31520 | 31308 | if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) { |
| 31521 | 31309 | const len = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); |
| 31522 | 31310 | const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); |
| 31523 | | deref.pointee = if (elem_ptr.index + len <= check_len) TypedValue{ |
| 31524 | | .ty = try mod.arrayType(.{ |
| 31525 | | .len = len, |
| 31526 | | .child = elem_ty.toIntern(), |
| 31527 | | }), |
| 31528 | | .val = try array_tv.val.sliceArray(sema, elem_idx, elem_idx + len), |
| 31311 | deref.pointee = if (elem_ptr.index + len <= check_len) switch (array_val) { |
| 31312 | .aggregate => |a| .{ .aggregate = .{ |
| 31313 | .ty = (try mod.arrayType(.{ .len = len, .child = elem_ty.toIntern() })).toIntern(), |
| 31314 | .elems = a.elems[elem_idx..][0..len], |
| 31315 | } }, |
| 31316 | else => .{ |
| 31317 | .interned = (try (Value.fromInterned( |
| 31318 | try array_val.intern(mod, sema.arena), |
| 31319 | ).sliceArray(sema, elem_idx, elem_idx + len))).toIntern(), |
| 31320 | }, |
| 31529 | 31321 | } else null; |
| 31530 | 31322 | break :blk deref; |
| 31531 | 31323 | } |
| ... | ... | @@ -31536,18 +31328,12 @@ fn beginComptimePtrLoad( |
| 31536 | 31328 | break :blk deref; |
| 31537 | 31329 | } |
| 31538 | 31330 | if (elem_ptr.index == check_len - 1) { |
| 31539 | | if (array_tv.ty.sentinel(mod)) |sent| { |
| 31540 | | deref.pointee = TypedValue{ |
| 31541 | | .ty = elem_ty, |
| 31542 | | .val = sent, |
| 31543 | | }; |
| 31331 | if (array_val.typeOf(mod).sentinel(mod)) |sent| { |
| 31332 | deref.pointee = .{ .interned = sent.toIntern() }; |
| 31544 | 31333 | break :blk deref; |
| 31545 | 31334 | } |
| 31546 | 31335 | } |
| 31547 | | deref.pointee = TypedValue{ |
| 31548 | | .ty = elem_ty, |
| 31549 | | .val = try array_tv.val.elemValue(mod, @intCast(elem_ptr.index)), |
| 31550 | | }; |
| 31336 | deref.pointee = try array_val.getElem(mod, @intCast(elem_ptr.index)); |
| 31551 | 31337 | break :blk deref; |
| 31552 | 31338 | }, |
| 31553 | 31339 | .field => |field_ptr| blk: { |
| ... | ... | @@ -31571,37 +31357,17 @@ fn beginComptimePtrLoad( |
| 31571 | 31357 | deref.ty_without_well_defined_layout = container_ty; |
| 31572 | 31358 | } |
| 31573 | 31359 | |
| 31574 | | const tv = deref.pointee orelse { |
| 31575 | | deref.pointee = null; |
| 31576 | | break :blk deref; |
| 31577 | | }; |
| 31360 | const pointee = deref.pointee orelse break :blk deref; |
| 31361 | const pointee_ty = pointee.typeOf(mod); |
| 31578 | 31362 | const coerce_in_mem_ok = |
| 31579 | | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or |
| 31580 | | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; |
| 31363 | (try sema.coerceInMemoryAllowed(block, container_ty, pointee_ty, false, target, src, src)) == .ok or |
| 31364 | (try sema.coerceInMemoryAllowed(block, pointee_ty, container_ty, false, target, src, src)) == .ok; |
| 31581 | 31365 | if (!coerce_in_mem_ok) { |
| 31582 | 31366 | deref.pointee = null; |
| 31583 | 31367 | break :blk deref; |
| 31584 | 31368 | } |
| 31585 | 31369 | |
| 31586 | | if (container_ty.isSlice(mod)) { |
| 31587 | | deref.pointee = switch (field_index) { |
| 31588 | | Value.slice_ptr_index => TypedValue{ |
| 31589 | | .ty = container_ty.slicePtrFieldType(mod), |
| 31590 | | .val = tv.val.slicePtr(mod), |
| 31591 | | }, |
| 31592 | | Value.slice_len_index => TypedValue{ |
| 31593 | | .ty = Type.usize, |
| 31594 | | .val = Value.fromInterned(ip.indexToKey(try tv.val.intern(tv.ty, mod)).slice.len), |
| 31595 | | }, |
| 31596 | | else => unreachable, |
| 31597 | | }; |
| 31598 | | } else { |
| 31599 | | const field_ty = container_ty.structFieldType(field_index, mod); |
| 31600 | | deref.pointee = TypedValue{ |
| 31601 | | .ty = field_ty, |
| 31602 | | .val = try tv.val.fieldValue(mod, field_index), |
| 31603 | | }; |
| 31604 | | } |
| 31370 | deref.pointee = try pointee.getElem(mod, field_index); |
| 31605 | 31371 | break :blk deref; |
| 31606 | 31372 | }, |
| 31607 | 31373 | }, |
| ... | ... | @@ -31612,9 +31378,9 @@ fn beginComptimePtrLoad( |
| 31612 | 31378 | else => unreachable, |
| 31613 | 31379 | }; |
| 31614 | 31380 | |
| 31615 | | if (deref.pointee) |tv| { |
| 31616 | | if (deref.parent == null and tv.ty.hasWellDefinedLayout(mod)) { |
| 31617 | | deref.parent = .{ .tv = tv, .byte_offset = 0 }; |
| 31381 | if (deref.pointee) |val| { |
| 31382 | if (deref.parent == null and val.typeOf(mod).hasWellDefinedLayout(mod)) { |
| 31383 | deref.parent = .{ .val = val, .byte_offset = 0 }; |
| 31618 | 31384 | } |
| 31619 | 31385 | } |
| 31620 | 31386 | return deref; |
| ... | ... | @@ -38289,17 +38055,18 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value |
| 38289 | 38055 | else => |e| return e, |
| 38290 | 38056 | }; |
| 38291 | 38057 | |
| 38292 | | if (deref.pointee) |tv| { |
| 38058 | if (deref.pointee) |pointee| { |
| 38059 | const uncoerced_val = Value.fromInterned(try pointee.intern(mod, sema.arena)); |
| 38060 | const ty = Type.fromInterned(mod.intern_pool.typeOf(uncoerced_val.toIntern())); |
| 38293 | 38061 | const coerce_in_mem_ok = |
| 38294 | | (try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or |
| 38295 | | (try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok; |
| 38062 | (try sema.coerceInMemoryAllowed(block, load_ty, ty, false, target, src, src)) == .ok or |
| 38063 | (try sema.coerceInMemoryAllowed(block, ty, load_ty, false, target, src, src)) == .ok; |
| 38296 | 38064 | if (coerce_in_mem_ok) { |
| 38297 | 38065 | // We have a Value that lines up in virtual memory exactly with what we want to load, |
| 38298 | 38066 | // and it is in-memory coercible to load_ty. It may be returned without modifications. |
| 38299 | 38067 | // Move mutable decl values to the InternPool and assert other decls are already in |
| 38300 | 38068 | // the InternPool. |
| 38301 | | const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern(); |
| 38302 | | const coerced_val = try mod.getCoerced(Value.fromInterned(uncoerced_val), load_ty); |
| 38069 | const coerced_val = try mod.getCoerced(uncoerced_val, load_ty); |
| 38303 | 38070 | return .{ .val = coerced_val }; |
| 38304 | 38071 | } |
| 38305 | 38072 | } |
| ... | ... | @@ -38313,21 +38080,35 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value |
| 38313 | 38080 | const load_sz = try sema.typeAbiSize(load_ty); |
| 38314 | 38081 | |
| 38315 | 38082 | // Try the smaller bit-cast first, since that's more efficient than using the larger `parent` |
| 38316 | | if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(tv.ty)) |
| 38317 | | return DerefResult{ .val = (try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0)) orelse return .runtime_load }; |
| 38083 | if (deref.pointee) |pointee| { |
| 38084 | const val_ip_index = try pointee.intern(mod, sema.arena); |
| 38085 | const val = Value.fromInterned(val_ip_index); |
| 38086 | const ty = Type.fromInterned(mod.intern_pool.typeOf(val_ip_index)); |
| 38087 | if (load_sz <= try sema.typeAbiSize(ty)) { |
| 38088 | return .{ .val = (try sema.bitCastVal(block, src, val, ty, load_ty, 0)) orelse return .runtime_load }; |
| 38089 | } |
| 38090 | } |
| 38318 | 38091 | |
| 38319 | 38092 | // If that fails, try to bit-cast from the largest parent value with a well-defined layout |
| 38320 | | if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent.tv.ty)) |
| 38321 | | return DerefResult{ .val = (try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset)) orelse return .runtime_load }; |
| 38093 | if (deref.parent) |parent| { |
| 38094 | const parent_ip_index = try parent.val.intern(mod, sema.arena); |
| 38095 | const parent_val = Value.fromInterned(parent_ip_index); |
| 38096 | const parent_ty = Type.fromInterned(mod.intern_pool.typeOf(parent_ip_index)); |
| 38097 | if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent_ty)) { |
| 38098 | return .{ .val = (try sema.bitCastVal(block, src, parent_val, parent_ty, load_ty, parent.byte_offset)) orelse return .runtime_load }; |
| 38099 | } |
| 38100 | } |
| 38322 | 38101 | |
| 38323 | 38102 | if (deref.ty_without_well_defined_layout) |bad_ty| { |
| 38324 | 38103 | // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem |
| 38325 | 38104 | // is that some type we encountered when de-referencing does not have a well-defined layout. |
| 38326 | | return DerefResult{ .needed_well_defined = bad_ty }; |
| 38105 | return .{ .needed_well_defined = bad_ty }; |
| 38327 | 38106 | } else { |
| 38328 | 38107 | // If all encountered types had well-defined layouts, the parent is the root decl and it just |
| 38329 | 38108 | // wasn't big enough for the load. |
| 38330 | | return DerefResult{ .out_of_bounds = deref.parent.?.tv.ty }; |
| 38109 | const parent_ip_index = try deref.parent.?.val.intern(mod, sema.arena); |
| 38110 | const parent_ty = Type.fromInterned(mod.intern_pool.typeOf(parent_ip_index)); |
| 38111 | return .{ .out_of_bounds = parent_ty }; |
| 38331 | 38112 | } |
| 38332 | 38113 | } |
| 38333 | 38114 | |