| ... | ... | @@ -3235,7 +3235,7 @@ fn zirValidateArrayInit( |
| 3235 | 3235 | // any ZIR instructions at comptime; we need to do that here. |
| 3236 | 3236 | if (array_ty.sentinel()) |sentinel_val| { |
| 3237 | 3237 | const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); |
| 3238 | | const sentinel_ptr = try sema.elemPtrArray(block, init_src, array_ptr, array_len_ref, init_src); |
| 3238 | const sentinel_ptr = try sema.elemPtrArray(block, init_src, array_ptr, init_src, array_len_ref); |
| 3239 | 3239 | const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val); |
| 3240 | 3240 | try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); |
| 3241 | 3241 | } |
| ... | ... | @@ -15746,6 +15746,7 @@ pub const PanicId = enum { |
| 15746 | 15746 | cast_to_null, |
| 15747 | 15747 | incorrect_alignment, |
| 15748 | 15748 | invalid_error_code, |
| 15749 | index_out_of_bounds, |
| 15749 | 15750 | }; |
| 15750 | 15751 | |
| 15751 | 15752 | fn addSafetyCheck( |
| ... | ... | @@ -15867,6 +15868,7 @@ fn safetyPanic( |
| 15867 | 15868 | .cast_to_null => "cast causes pointer to be null", |
| 15868 | 15869 | .incorrect_alignment => "incorrect alignment", |
| 15869 | 15870 | .invalid_error_code => "invalid error code", |
| 15871 | .index_out_of_bounds => "attempt to index out of bounds", |
| 15870 | 15872 | }; |
| 15871 | 15873 | |
| 15872 | 15874 | const msg_inst = msg_inst: { |
| ... | ... | @@ -16483,10 +16485,10 @@ fn structFieldPtr( |
| 16483 | 16485 | return sema.analyzeRef(block, src, len_inst); |
| 16484 | 16486 | } |
| 16485 | 16487 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); |
| 16486 | | return sema.tupleFieldPtr(block, struct_ptr, field_index, src, field_name_src); |
| 16488 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index); |
| 16487 | 16489 | } else if (struct_ty.isAnonStruct()) { |
| 16488 | 16490 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); |
| 16489 | | return sema.tupleFieldPtr(block, struct_ptr, field_index, src, field_name_src); |
| 16491 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index); |
| 16490 | 16492 | } |
| 16491 | 16493 | |
| 16492 | 16494 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| ... | ... | @@ -16806,67 +16808,55 @@ fn elemPtr( |
| 16806 | 16808 | sema: *Sema, |
| 16807 | 16809 | block: *Block, |
| 16808 | 16810 | src: LazySrcLoc, |
| 16809 | | array_ptr: Air.Inst.Ref, |
| 16811 | indexable_ptr: Air.Inst.Ref, |
| 16810 | 16812 | elem_index: Air.Inst.Ref, |
| 16811 | 16813 | elem_index_src: LazySrcLoc, |
| 16812 | 16814 | ) CompileError!Air.Inst.Ref { |
| 16813 | | const array_ptr_src = src; // TODO better source location |
| 16814 | | const array_ptr_ty = sema.typeOf(array_ptr); |
| 16815 | | const array_ty = switch (array_ptr_ty.zigTypeTag()) { |
| 16816 | | .Pointer => array_ptr_ty.elemType(), |
| 16817 | | else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}), |
| 16815 | const indexable_ptr_src = src; // TODO better source location |
| 16816 | const indexable_ptr_ty = sema.typeOf(indexable_ptr); |
| 16817 | const indexable_ty = switch (indexable_ptr_ty.zigTypeTag()) { |
| 16818 | .Pointer => indexable_ptr_ty.elemType(), |
| 16819 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty}), |
| 16818 | 16820 | }; |
| 16819 | | if (!array_ty.isIndexable()) { |
| 16820 | | return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty}); |
| 16821 | if (!indexable_ty.isIndexable()) { |
| 16822 | return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty}); |
| 16821 | 16823 | } |
| 16822 | 16824 | |
| 16823 | | switch (array_ty.zigTypeTag()) { |
| 16825 | switch (indexable_ty.zigTypeTag()) { |
| 16824 | 16826 | .Pointer => { |
| 16825 | | // In all below cases, we have to deref the ptr operand to get the actual array pointer. |
| 16826 | | const array = try sema.analyzeLoad(block, array_ptr_src, array_ptr, array_ptr_src); |
| 16827 | // In all below cases, we have to deref the ptr operand to get the actual indexable pointer. |
| 16828 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); |
| 16827 | 16829 | const target = sema.mod.getTarget(); |
| 16828 | | const result_ty = try array_ty.elemPtrType(sema.arena, target); |
| 16829 | | switch (array_ty.ptrSize()) { |
| 16830 | | .Slice => { |
| 16831 | | const maybe_slice_val = try sema.resolveDefinedValue(block, array_ptr_src, array); |
| 16832 | | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 16833 | | const runtime_src = if (maybe_slice_val) |slice_val| rs: { |
| 16834 | | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 16835 | | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 16836 | | const elem_ptr = try slice_val.elemPtr(array_ty, sema.arena, index); |
| 16837 | | return sema.addConstant(result_ty, elem_ptr); |
| 16838 | | } else array_ptr_src; |
| 16839 | | |
| 16840 | | try sema.requireRuntimeBlock(block, runtime_src); |
| 16841 | | return block.addSliceElemPtr(array, elem_index, result_ty); |
| 16842 | | }, |
| 16830 | const result_ty = try indexable_ty.elemPtrType(sema.arena, target); |
| 16831 | switch (indexable_ty.ptrSize()) { |
| 16832 | .Slice => return sema.elemPtrSlice(block, indexable_ptr_src, indexable, elem_index_src, elem_index), |
| 16843 | 16833 | .Many, .C => { |
| 16844 | | const maybe_ptr_val = try sema.resolveDefinedValue(block, array_ptr_src, array); |
| 16834 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_ptr_src, indexable); |
| 16845 | 16835 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 16846 | 16836 | |
| 16847 | 16837 | const runtime_src = rs: { |
| 16848 | | const ptr_val = maybe_ptr_val orelse break :rs array_ptr_src; |
| 16838 | const ptr_val = maybe_ptr_val orelse break :rs indexable_ptr_src; |
| 16849 | 16839 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 16850 | 16840 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 16851 | | const elem_ptr = try ptr_val.elemPtr(array_ty, sema.arena, index); |
| 16841 | const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index); |
| 16852 | 16842 | return sema.addConstant(result_ty, elem_ptr); |
| 16853 | 16843 | }; |
| 16854 | 16844 | |
| 16855 | 16845 | try sema.requireRuntimeBlock(block, runtime_src); |
| 16856 | | return block.addPtrElemPtr(array, elem_index, result_ty); |
| 16846 | return block.addPtrElemPtr(indexable, elem_index, result_ty); |
| 16857 | 16847 | }, |
| 16858 | 16848 | .One => { |
| 16859 | | assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable |
| 16860 | | return sema.elemPtrArray(block, array_ptr_src, array, elem_index, elem_index_src); |
| 16849 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable |
| 16850 | return sema.elemPtrArray(block, indexable_ptr_src, indexable, elem_index_src, elem_index); |
| 16861 | 16851 | }, |
| 16862 | 16852 | } |
| 16863 | 16853 | }, |
| 16864 | | .Array, .Vector => return sema.elemPtrArray(block, array_ptr_src, array_ptr, elem_index, elem_index_src), |
| 16854 | .Array, .Vector => return sema.elemPtrArray(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index), |
| 16865 | 16855 | .Struct => { |
| 16866 | 16856 | // Tuple field access. |
| 16867 | 16857 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); |
| 16868 | 16858 | const index = @intCast(u32, index_val.toUnsignedInt()); |
| 16869 | | return sema.tupleFieldPtr(block, array_ptr, index, src, elem_index_src); |
| 16859 | return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index); |
| 16870 | 16860 | }, |
| 16871 | 16861 | else => unreachable, |
| 16872 | 16862 | } |
| ... | ... | @@ -16876,90 +16866,66 @@ fn elemVal( |
| 16876 | 16866 | sema: *Sema, |
| 16877 | 16867 | block: *Block, |
| 16878 | 16868 | src: LazySrcLoc, |
| 16879 | | array: Air.Inst.Ref, |
| 16869 | indexable: Air.Inst.Ref, |
| 16880 | 16870 | elem_index_uncasted: Air.Inst.Ref, |
| 16881 | 16871 | elem_index_src: LazySrcLoc, |
| 16882 | 16872 | ) CompileError!Air.Inst.Ref { |
| 16883 | | const array_src = src; // TODO better source location |
| 16884 | | const array_ty = sema.typeOf(array); |
| 16873 | const indexable_src = src; // TODO better source location |
| 16874 | const indexable_ty = sema.typeOf(indexable); |
| 16885 | 16875 | |
| 16886 | | if (!array_ty.isIndexable()) { |
| 16887 | | return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty}); |
| 16876 | if (!indexable_ty.isIndexable()) { |
| 16877 | return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty}); |
| 16888 | 16878 | } |
| 16889 | 16879 | |
| 16890 | 16880 | // TODO in case of a vector of pointers, we need to detect whether the element |
| 16891 | 16881 | // index is a scalar or vector instead of unconditionally casting to usize. |
| 16892 | 16882 | const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); |
| 16893 | 16883 | |
| 16894 | | switch (array_ty.zigTypeTag()) { |
| 16895 | | .Pointer => switch (array_ty.ptrSize()) { |
| 16896 | | .Slice => { |
| 16897 | | const maybe_slice_val = try sema.resolveDefinedValue(block, array_src, array); |
| 16898 | | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 16899 | | const runtime_src = if (maybe_slice_val) |slice_val| rs: { |
| 16900 | | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 16901 | | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 16902 | | |
| 16903 | | const elem_ty = array_ty.elemType2(); |
| 16904 | | |
| 16905 | | var payload: Value.Payload.ElemPtr = .{ .data = .{ |
| 16906 | | .array_ptr = slice_val.slicePtr(), |
| 16907 | | .elem_ty = elem_ty, |
| 16908 | | .index = index, |
| 16909 | | } }; |
| 16910 | | const elem_ptr_val = Value.initPayload(&payload.base); |
| 16911 | | |
| 16912 | | if (try sema.pointerDeref(block, array_src, elem_ptr_val, array_ty)) |elem_val| { |
| 16913 | | return sema.addConstant(elem_ty, elem_val); |
| 16914 | | } |
| 16915 | | break :rs array_src; |
| 16916 | | } else array_src; |
| 16917 | | |
| 16918 | | try sema.requireRuntimeBlock(block, runtime_src); |
| 16919 | | return block.addBinOp(.slice_elem_val, array, elem_index); |
| 16920 | | }, |
| 16884 | switch (indexable_ty.zigTypeTag()) { |
| 16885 | .Pointer => switch (indexable_ty.ptrSize()) { |
| 16886 | .Slice => return sema.elemValSlice(block, indexable_src, indexable, elem_index_src, elem_index), |
| 16921 | 16887 | .Many, .C => { |
| 16922 | | const maybe_array_val = try sema.resolveDefinedValue(block, array_src, array); |
| 16888 | const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| 16923 | 16889 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 16924 | 16890 | |
| 16925 | 16891 | const runtime_src = rs: { |
| 16926 | | const array_val = maybe_array_val orelse break :rs array_src; |
| 16892 | const indexable_val = maybe_indexable_val orelse break :rs indexable_src; |
| 16927 | 16893 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 16928 | 16894 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 16929 | | const elem_ty = array_ty.elemType2(); |
| 16895 | const elem_ty = indexable_ty.elemType2(); |
| 16930 | 16896 | |
| 16931 | 16897 | var payload: Value.Payload.ElemPtr = .{ .data = .{ |
| 16932 | | .array_ptr = array_val, |
| 16898 | .array_ptr = indexable_val, |
| 16933 | 16899 | .elem_ty = elem_ty, |
| 16934 | 16900 | .index = index, |
| 16935 | 16901 | } }; |
| 16936 | 16902 | const elem_ptr_val = Value.initPayload(&payload.base); |
| 16937 | 16903 | |
| 16938 | | if (try sema.pointerDeref(block, array_src, elem_ptr_val, array_ty)) |elem_val| { |
| 16904 | if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| { |
| 16939 | 16905 | return sema.addConstant(elem_ty, elem_val); |
| 16940 | 16906 | } |
| 16941 | | break :rs array_src; |
| 16907 | break :rs indexable_src; |
| 16942 | 16908 | }; |
| 16943 | 16909 | |
| 16944 | 16910 | try sema.requireRuntimeBlock(block, runtime_src); |
| 16945 | | return block.addBinOp(.ptr_elem_val, array, elem_index); |
| 16911 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); |
| 16946 | 16912 | }, |
| 16947 | 16913 | .One => { |
| 16948 | | assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable |
| 16949 | | const elem_ptr = try sema.elemPtr(block, array_src, array, elem_index, elem_index_src); |
| 16950 | | return sema.analyzeLoad(block, array_src, elem_ptr, elem_index_src); |
| 16914 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable |
| 16915 | const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src); |
| 16916 | return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); |
| 16951 | 16917 | }, |
| 16952 | 16918 | }, |
| 16953 | | .Array => return elemValArray(sema, block, array, elem_index, array_src, elem_index_src), |
| 16919 | .Array => return elemValArray(sema, block, indexable_src, indexable, elem_index_src, elem_index), |
| 16954 | 16920 | .Vector => { |
| 16955 | 16921 | // TODO: If the index is a vector, the result should be a vector. |
| 16956 | | return elemValArray(sema, block, array, elem_index, array_src, elem_index_src); |
| 16922 | return elemValArray(sema, block, indexable_src, indexable, elem_index_src, elem_index); |
| 16957 | 16923 | }, |
| 16958 | 16924 | .Struct => { |
| 16959 | 16925 | // Tuple field access. |
| 16960 | 16926 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); |
| 16961 | 16927 | const index = @intCast(u32, index_val.toUnsignedInt()); |
| 16962 | | return tupleField(sema, block, array, index, array_src, elem_index_src); |
| 16928 | return tupleField(sema, block, indexable_src, indexable, elem_index_src, index); |
| 16963 | 16929 | }, |
| 16964 | 16930 | else => unreachable, |
| 16965 | 16931 | } |
| ... | ... | @@ -16968,22 +16934,26 @@ fn elemVal( |
| 16968 | 16934 | fn tupleFieldPtr( |
| 16969 | 16935 | sema: *Sema, |
| 16970 | 16936 | block: *Block, |
| 16937 | tuple_ptr_src: LazySrcLoc, |
| 16971 | 16938 | tuple_ptr: Air.Inst.Ref, |
| 16972 | | field_index: u32, |
| 16973 | | tuple_src: LazySrcLoc, |
| 16974 | 16939 | field_index_src: LazySrcLoc, |
| 16940 | field_index: u32, |
| 16975 | 16941 | ) CompileError!Air.Inst.Ref { |
| 16976 | 16942 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); |
| 16977 | 16943 | const tuple_ty = tuple_ptr_ty.childType(); |
| 16978 | | const tuple = tuple_ty.tupleFields(); |
| 16944 | const tuple_fields = tuple_ty.tupleFields(); |
| 16945 | |
| 16946 | if (tuple_fields.types.len == 0) { |
| 16947 | return sema.fail(block, field_index_src, "indexing into empty tuple", .{}); |
| 16948 | } |
| 16979 | 16949 | |
| 16980 | | if (field_index > tuple.types.len) { |
| 16950 | if (field_index >= tuple_fields.types.len) { |
| 16981 | 16951 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ |
| 16982 | | field_index, tuple.types.len, |
| 16952 | field_index, tuple_fields.types.len, |
| 16983 | 16953 | }); |
| 16984 | 16954 | } |
| 16985 | 16955 | |
| 16986 | | const field_ty = tuple.types[field_index]; |
| 16956 | const field_ty = tuple_fields.types[field_index]; |
| 16987 | 16957 | const target = sema.mod.getTarget(); |
| 16988 | 16958 | const ptr_field_ty = try Type.ptr(sema.arena, target, .{ |
| 16989 | 16959 | .pointee_type = field_ty, |
| ... | ... | @@ -16991,7 +16961,7 @@ fn tupleFieldPtr( |
| 16991 | 16961 | .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(), |
| 16992 | 16962 | }); |
| 16993 | 16963 | |
| 16994 | | if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple_ptr)) |tuple_ptr_val| { |
| 16964 | if (try sema.resolveMaybeUndefVal(block, tuple_ptr_src, tuple_ptr)) |tuple_ptr_val| { |
| 16995 | 16965 | return sema.addConstant( |
| 16996 | 16966 | ptr_field_ty, |
| 16997 | 16967 | try Value.Tag.field_ptr.create(sema.arena, .{ |
| ... | ... | @@ -17002,29 +16972,33 @@ fn tupleFieldPtr( |
| 17002 | 16972 | ); |
| 17003 | 16973 | } |
| 17004 | 16974 | |
| 17005 | | try sema.requireRuntimeBlock(block, tuple_src); |
| 16975 | try sema.requireRuntimeBlock(block, tuple_ptr_src); |
| 17006 | 16976 | return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); |
| 17007 | 16977 | } |
| 17008 | 16978 | |
| 17009 | 16979 | fn tupleField( |
| 17010 | 16980 | sema: *Sema, |
| 17011 | 16981 | block: *Block, |
| 17012 | | tuple: Air.Inst.Ref, |
| 17013 | | field_index: u32, |
| 17014 | 16982 | tuple_src: LazySrcLoc, |
| 16983 | tuple: Air.Inst.Ref, |
| 17015 | 16984 | field_index_src: LazySrcLoc, |
| 16985 | field_index: u32, |
| 17016 | 16986 | ) CompileError!Air.Inst.Ref { |
| 17017 | 16987 | const tuple_ty = sema.typeOf(tuple); |
| 17018 | | const tuple_info = tuple_ty.tupleFields(); |
| 16988 | const tuple_fields = tuple_ty.tupleFields(); |
| 16989 | |
| 16990 | if (tuple_fields.types.len == 0) { |
| 16991 | return sema.fail(block, field_index_src, "indexing into empty tuple", .{}); |
| 16992 | } |
| 17019 | 16993 | |
| 17020 | | if (field_index > tuple_info.types.len) { |
| 16994 | if (field_index >= tuple_fields.types.len) { |
| 17021 | 16995 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ |
| 17022 | | field_index, tuple_info.types.len, |
| 16996 | field_index, tuple_fields.types.len, |
| 17023 | 16997 | }); |
| 17024 | 16998 | } |
| 17025 | 16999 | |
| 17026 | | const field_ty = tuple_info.types[field_index]; |
| 17027 | | const field_val = tuple_info.values[field_index]; |
| 17000 | const field_ty = tuple_fields.types[field_index]; |
| 17001 | const field_val = tuple_fields.values[field_index]; |
| 17028 | 17002 | |
| 17029 | 17003 | if (field_val.tag() != .unreachable_value) { |
| 17030 | 17004 | return sema.addConstant(field_ty, field_val); // comptime field |
| ... | ... | @@ -17043,57 +17017,221 @@ fn tupleField( |
| 17043 | 17017 | fn elemValArray( |
| 17044 | 17018 | sema: *Sema, |
| 17045 | 17019 | block: *Block, |
| 17046 | | array: Air.Inst.Ref, |
| 17047 | | elem_index: Air.Inst.Ref, |
| 17048 | 17020 | array_src: LazySrcLoc, |
| 17021 | array: Air.Inst.Ref, |
| 17049 | 17022 | elem_index_src: LazySrcLoc, |
| 17023 | elem_index: Air.Inst.Ref, |
| 17050 | 17024 | ) CompileError!Air.Inst.Ref { |
| 17051 | 17025 | const array_ty = sema.typeOf(array); |
| 17052 | | if (try sema.resolveMaybeUndefVal(block, array_src, array)) |array_val| { |
| 17053 | | const elem_ty = array_ty.childType(); |
| 17054 | | if (array_val.isUndef()) return sema.addConstUndef(elem_ty); |
| 17055 | | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 17026 | const array_sent = array_ty.sentinel() != null; |
| 17027 | const array_len = array_ty.arrayLen(); |
| 17028 | const array_len_s = array_len + @boolToInt(array_sent); |
| 17029 | const elem_ty = array_ty.childType(); |
| 17030 | |
| 17031 | if (array_len_s == 0) { |
| 17032 | return sema.fail(block, elem_index_src, "indexing into empty array", .{}); |
| 17033 | } |
| 17034 | |
| 17035 | const maybe_undef_array_val = try sema.resolveMaybeUndefVal(block, array_src, array); |
| 17036 | // index must be defined since it can access out of bounds |
| 17037 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 17038 | |
| 17039 | if (maybe_index_val) |index_val| { |
| 17040 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 17041 | if (index >= array_len_s) { |
| 17042 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; |
| 17043 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); |
| 17044 | } |
| 17045 | } |
| 17046 | if (maybe_undef_array_val) |array_val| { |
| 17047 | if (array_val.isUndef()) { |
| 17048 | return sema.addConstUndef(elem_ty); |
| 17049 | } |
| 17056 | 17050 | if (maybe_index_val) |index_val| { |
| 17057 | 17051 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 17058 | | const len = array_ty.arrayLenIncludingSentinel(); |
| 17059 | | if (index >= len) { |
| 17060 | | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}", .{ |
| 17061 | | index, len, |
| 17062 | | }); |
| 17063 | | } |
| 17064 | 17052 | const elem_val = try array_val.elemValue(sema.arena, index); |
| 17065 | 17053 | return sema.addConstant(elem_ty, elem_val); |
| 17066 | 17054 | } |
| 17067 | 17055 | } |
| 17068 | | try sema.requireRuntimeBlock(block, array_src); |
| 17056 | |
| 17057 | const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; |
| 17058 | try sema.requireRuntimeBlock(block, runtime_src); |
| 17059 | if (block.wantSafety()) { |
| 17060 | // Runtime check is only needed if unable to comptime check |
| 17061 | if (maybe_index_val == null) { |
| 17062 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); |
| 17063 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; |
| 17064 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); |
| 17065 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); |
| 17066 | } |
| 17067 | } |
| 17069 | 17068 | return block.addBinOp(.array_elem_val, array, elem_index); |
| 17070 | 17069 | } |
| 17071 | 17070 | |
| 17072 | 17071 | fn elemPtrArray( |
| 17073 | 17072 | sema: *Sema, |
| 17074 | 17073 | block: *Block, |
| 17075 | | src: LazySrcLoc, |
| 17074 | array_ptr_src: LazySrcLoc, |
| 17076 | 17075 | array_ptr: Air.Inst.Ref, |
| 17077 | | elem_index: Air.Inst.Ref, |
| 17078 | 17076 | elem_index_src: LazySrcLoc, |
| 17077 | elem_index: Air.Inst.Ref, |
| 17079 | 17078 | ) CompileError!Air.Inst.Ref { |
| 17079 | const target = sema.mod.getTarget(); |
| 17080 | 17080 | const array_ptr_ty = sema.typeOf(array_ptr); |
| 17081 | const array_ty = array_ptr_ty.childType(); |
| 17082 | const array_sent = array_ty.sentinel() != null; |
| 17083 | const array_len = array_ty.arrayLen(); |
| 17084 | const array_len_s = array_len + @boolToInt(array_sent); |
| 17085 | const elem_ptr_ty = try array_ptr_ty.elemPtrType(sema.arena, target); |
| 17086 | |
| 17087 | if (array_len_s == 0) { |
| 17088 | return sema.fail(block, elem_index_src, "indexing into empty array", .{}); |
| 17089 | } |
| 17090 | |
| 17091 | const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(block, array_ptr_src, array_ptr); |
| 17092 | // index must be defined since it can index out of bounds |
| 17093 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 17094 | |
| 17095 | if (maybe_index_val) |index_val| { |
| 17096 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 17097 | if (index >= array_len_s) { |
| 17098 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; |
| 17099 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); |
| 17100 | } |
| 17101 | } |
| 17102 | if (maybe_undef_array_ptr_val) |array_ptr_val| { |
| 17103 | if (array_ptr_val.isUndef()) { |
| 17104 | return sema.addConstUndef(elem_ptr_ty); |
| 17105 | } |
| 17106 | if (maybe_index_val) |index_val| { |
| 17107 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 17108 | const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index); |
| 17109 | return sema.addConstant(elem_ptr_ty, elem_ptr); |
| 17110 | } |
| 17111 | } |
| 17112 | |
| 17113 | const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src; |
| 17114 | try sema.requireRuntimeBlock(block, runtime_src); |
| 17115 | if (block.wantSafety()) { |
| 17116 | // Runtime check is only needed if unable to comptime check |
| 17117 | if (maybe_index_val == null) { |
| 17118 | const len_inst = try sema.addIntUnsigned(Type.usize, array_len); |
| 17119 | const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; |
| 17120 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); |
| 17121 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); |
| 17122 | } |
| 17123 | } |
| 17124 | return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); |
| 17125 | } |
| 17126 | |
| 17127 | fn elemValSlice( |
| 17128 | sema: *Sema, |
| 17129 | block: *Block, |
| 17130 | slice_src: LazySrcLoc, |
| 17131 | slice: Air.Inst.Ref, |
| 17132 | elem_index_src: LazySrcLoc, |
| 17133 | elem_index: Air.Inst.Ref, |
| 17134 | ) CompileError!Air.Inst.Ref { |
| 17135 | const slice_ty = sema.typeOf(slice); |
| 17136 | const slice_sent = slice_ty.sentinel() != null; |
| 17137 | const elem_ty = slice_ty.elemType2(); |
| 17138 | var runtime_src = slice_src; |
| 17139 | |
| 17140 | // slice must be defined since it can dereferenced as null |
| 17141 | const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); |
| 17142 | // index must be defined since it can index out of bounds |
| 17143 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 17144 | |
| 17145 | if (maybe_slice_val) |slice_val| { |
| 17146 | runtime_src = elem_index_src; |
| 17147 | const slice_len = slice_val.sliceLen(); |
| 17148 | const slice_len_s = slice_len + @boolToInt(slice_sent); |
| 17149 | if (slice_len_s == 0) { |
| 17150 | return sema.fail(block, elem_index_src, "indexing into empty slice", .{}); |
| 17151 | } |
| 17152 | if (maybe_index_val) |index_val| { |
| 17153 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 17154 | if (index >= slice_len_s) { |
| 17155 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 17156 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 17157 | } |
| 17158 | var elem_ptr_pl: Value.Payload.ElemPtr = .{ .data = .{ |
| 17159 | .array_ptr = slice_val.slicePtr(), |
| 17160 | .elem_ty = elem_ty, |
| 17161 | .index = index, |
| 17162 | } }; |
| 17163 | const elem_ptr_val = Value.initPayload(&elem_ptr_pl.base); |
| 17164 | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| { |
| 17165 | return sema.addConstant(elem_ty, elem_val); |
| 17166 | } |
| 17167 | runtime_src = slice_src; |
| 17168 | } |
| 17169 | } |
| 17170 | |
| 17171 | try sema.requireRuntimeBlock(block, runtime_src); |
| 17172 | if (block.wantSafety()) { |
| 17173 | const len_inst = if (maybe_slice_val) |slice_val| |
| 17174 | try sema.addIntUnsigned(Type.usize, slice_val.sliceLen()) |
| 17175 | else |
| 17176 | try block.addTyOp(.slice_len, Type.usize, slice); |
| 17177 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| 17178 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); |
| 17179 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); |
| 17180 | } |
| 17181 | return block.addBinOp(.slice_elem_val, slice, elem_index); |
| 17182 | } |
| 17183 | |
| 17184 | fn elemPtrSlice( |
| 17185 | sema: *Sema, |
| 17186 | block: *Block, |
| 17187 | slice_src: LazySrcLoc, |
| 17188 | slice: Air.Inst.Ref, |
| 17189 | elem_index_src: LazySrcLoc, |
| 17190 | elem_index: Air.Inst.Ref, |
| 17191 | ) CompileError!Air.Inst.Ref { |
| 17081 | 17192 | const target = sema.mod.getTarget(); |
| 17082 | | const result_ty = try array_ptr_ty.elemPtrType(sema.arena, target); |
| 17083 | | |
| 17084 | | if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| { |
| 17085 | | if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| { |
| 17086 | | // Both array pointer and index are compile-time known. |
| 17087 | | const index_u64 = index_val.toUnsignedInt(); |
| 17088 | | // @intCast here because it would have been impossible to construct a value that |
| 17089 | | // required a larger index. |
| 17090 | | const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, @intCast(usize, index_u64)); |
| 17091 | | return sema.addConstant(result_ty, elem_ptr); |
| 17193 | const slice_ty = sema.typeOf(slice); |
| 17194 | const slice_sent = slice_ty.sentinel() != null; |
| 17195 | const elem_ptr_ty = try slice_ty.elemPtrType(sema.arena, target); |
| 17196 | |
| 17197 | const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(block, slice_src, slice); |
| 17198 | // index must be defined since it can index out of bounds |
| 17199 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 17200 | |
| 17201 | if (maybe_undef_slice_val) |slice_val| { |
| 17202 | if (slice_val.isUndef()) { |
| 17203 | return sema.addConstUndef(elem_ptr_ty); |
| 17204 | } |
| 17205 | const slice_len = slice_val.sliceLen(); |
| 17206 | const slice_len_s = slice_len + @boolToInt(slice_sent); |
| 17207 | if (slice_len_s == 0) { |
| 17208 | return sema.fail(block, elem_index_src, "indexing into empty slice", .{}); |
| 17209 | } |
| 17210 | if (maybe_index_val) |index_val| { |
| 17211 | const index = @intCast(usize, index_val.toUnsignedInt()); |
| 17212 | if (index >= slice_len_s) { |
| 17213 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 17214 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 17215 | } |
| 17216 | const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index); |
| 17217 | return sema.addConstant(elem_ptr_ty, elem_ptr_val); |
| 17092 | 17218 | } |
| 17093 | 17219 | } |
| 17094 | | // TODO safety check for array bounds |
| 17095 | | try sema.requireRuntimeBlock(block, src); |
| 17096 | | return block.addPtrElemPtr(array_ptr, elem_index, result_ty); |
| 17220 | |
| 17221 | const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src; |
| 17222 | try sema.requireRuntimeBlock(block, runtime_src); |
| 17223 | if (block.wantSafety()) { |
| 17224 | const len_inst = len: { |
| 17225 | if (maybe_undef_slice_val) |slice_val| |
| 17226 | if (!slice_val.isUndef()) |
| 17227 | break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen()); |
| 17228 | break :len try block.addTyOp(.slice_len, Type.usize, slice); |
| 17229 | }; |
| 17230 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| 17231 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); |
| 17232 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); |
| 17233 | } |
| 17234 | return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); |
| 17097 | 17235 | } |
| 17098 | 17236 | |
| 17099 | 17237 | fn coerce( |
| ... | ... | @@ -18000,7 +18138,7 @@ fn storePtr2( |
| 18000 | 18138 | for (tuple.types) |_, i_usize| { |
| 18001 | 18139 | const i = @intCast(u32, i_usize); |
| 18002 | 18140 | const elem_src = operand_src; // TODO better source location |
| 18003 | | const elem = try tupleField(sema, block, uncasted_operand, i, operand_src, elem_src); |
| 18141 | const elem = try tupleField(sema, block, operand_src, uncasted_operand, elem_src, i); |
| 18004 | 18142 | const elem_index = try sema.addIntUnsigned(Type.usize, i); |
| 18005 | 18143 | const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src); |
| 18006 | 18144 | try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); |
| ... | ... | @@ -18885,7 +19023,7 @@ fn coerceArrayLike( |
| 18885 | 19023 | try Value.Tag.int_u64.create(sema.arena, i), |
| 18886 | 19024 | ); |
| 18887 | 19025 | const elem_src = inst_src; // TODO better source location |
| 18888 | | const elem_ref = try elemValArray(sema, block, inst, index_ref, inst_src, elem_src); |
| 19026 | const elem_ref = try elemValArray(sema, block, inst_src, inst, elem_src, index_ref); |
| 18889 | 19027 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 18890 | 19028 | element_refs[i] = coerced; |
| 18891 | 19029 | if (runtime_src == null) { |
| ... | ... | @@ -18942,7 +19080,7 @@ fn coerceTupleToArray( |
| 18942 | 19080 | for (element_vals) |*elem, i_usize| { |
| 18943 | 19081 | const i = @intCast(u32, i_usize); |
| 18944 | 19082 | const elem_src = inst_src; // TODO better source location |
| 18945 | | const elem_ref = try tupleField(sema, block, inst, i, inst_src, elem_src); |
| 19083 | const elem_ref = try tupleField(sema, block, inst_src, inst, elem_src, i); |
| 18946 | 19084 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 18947 | 19085 | element_refs[i] = coerced; |
| 18948 | 19086 | if (runtime_src == null) { |
| ... | ... | @@ -19042,7 +19180,7 @@ fn coerceTupleToStruct( |
| 19042 | 19180 | if (field.is_comptime) { |
| 19043 | 19181 | return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to structs when one of the destination struct fields is comptime", .{}); |
| 19044 | 19182 | } |
| 19045 | | const elem_ref = try tupleField(sema, block, inst, i, inst_src, field_src); |
| 19183 | const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i); |
| 19046 | 19184 | const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); |
| 19047 | 19185 | field_refs[field_index] = coerced; |
| 19048 | 19186 | if (runtime_src == null) { |