| ... | @@ -3235,7 +3235,7 @@ fn zirValidateArrayInit( | ... | @@ -3235,7 +3235,7 @@ fn zirValidateArrayInit( |
| 3235 | // any ZIR instructions at comptime; we need to do that here. | 3235 | // any ZIR instructions at comptime; we need to do that here. |
| 3236 | if (array_ty.sentinel()) |sentinel_val| { | 3236 | if (array_ty.sentinel()) |sentinel_val| { |
| 3237 | const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); | 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 | const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val); | 3239 | const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val); |
| 3240 | try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); | 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,6 +15746,7 @@ pub const PanicId = enum { |
| 15746 | cast_to_null, | 15746 | cast_to_null, |
| 15747 | incorrect_alignment, | 15747 | incorrect_alignment, |
| 15748 | invalid_error_code, | 15748 | invalid_error_code, |
| | 15749 | index_out_of_bounds, |
| 15749 | }; | 15750 | }; |
| 15750 | | 15751 | |
| 15751 | fn addSafetyCheck( | 15752 | fn addSafetyCheck( |
| ... | @@ -15867,6 +15868,7 @@ fn safetyPanic( | ... | @@ -15867,6 +15868,7 @@ fn safetyPanic( |
| 15867 | .cast_to_null => "cast causes pointer to be null", | 15868 | .cast_to_null => "cast causes pointer to be null", |
| 15868 | .incorrect_alignment => "incorrect alignment", | 15869 | .incorrect_alignment => "incorrect alignment", |
| 15869 | .invalid_error_code => "invalid error code", | 15870 | .invalid_error_code => "invalid error code", |
| | 15871 | .index_out_of_bounds => "attempt to index out of bounds", |
| 15870 | }; | 15872 | }; |
| 15871 | | 15873 | |
| 15872 | const msg_inst = msg_inst: { | 15874 | const msg_inst = msg_inst: { |
| ... | @@ -16483,10 +16485,10 @@ fn structFieldPtr( | ... | @@ -16483,10 +16485,10 @@ fn structFieldPtr( |
| 16483 | return sema.analyzeRef(block, src, len_inst); | 16485 | return sema.analyzeRef(block, src, len_inst); |
| 16484 | } | 16486 | } |
| 16485 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); | 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 | } else if (struct_ty.isAnonStruct()) { | 16489 | } else if (struct_ty.isAnonStruct()) { |
| 16488 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); | 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 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 16494 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| ... | @@ -16806,67 +16808,55 @@ fn elemPtr( | ... | @@ -16806,67 +16808,55 @@ fn elemPtr( |
| 16806 | sema: *Sema, | 16808 | sema: *Sema, |
| 16807 | block: *Block, | 16809 | block: *Block, |
| 16808 | src: LazySrcLoc, | 16810 | src: LazySrcLoc, |
| 16809 | array_ptr: Air.Inst.Ref, | 16811 | indexable_ptr: Air.Inst.Ref, |
| 16810 | elem_index: Air.Inst.Ref, | 16812 | elem_index: Air.Inst.Ref, |
| 16811 | elem_index_src: LazySrcLoc, | 16813 | elem_index_src: LazySrcLoc, |
| 16812 | ) CompileError!Air.Inst.Ref { | 16814 | ) CompileError!Air.Inst.Ref { |
| 16813 | const array_ptr_src = src; // TODO better source location | 16815 | const indexable_ptr_src = src; // TODO better source location |
| 16814 | const array_ptr_ty = sema.typeOf(array_ptr); | 16816 | const indexable_ptr_ty = sema.typeOf(indexable_ptr); |
| 16815 | const array_ty = switch (array_ptr_ty.zigTypeTag()) { | 16817 | const indexable_ty = switch (indexable_ptr_ty.zigTypeTag()) { |
| 16816 | .Pointer => array_ptr_ty.elemType(), | 16818 | .Pointer => indexable_ptr_ty.elemType(), |
| 16817 | else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}), | 16819 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty}), |
| 16818 | }; | 16820 | }; |
| 16819 | if (!array_ty.isIndexable()) { | 16821 | if (!indexable_ty.isIndexable()) { |
| 16820 | return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty}); | 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 | .Pointer => { | 16826 | .Pointer => { |
| 16825 | // In all below cases, we have to deref the ptr operand to get the actual array pointer. | 16827 | // In all below cases, we have to deref the ptr operand to get the actual indexable pointer. |
| 16826 | const array = try sema.analyzeLoad(block, array_ptr_src, array_ptr, array_ptr_src); | 16828 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); |
| 16827 | const target = sema.mod.getTarget(); | 16829 | const target = sema.mod.getTarget(); |
| 16828 | const result_ty = try array_ty.elemPtrType(sema.arena, target); | 16830 | const result_ty = try indexable_ty.elemPtrType(sema.arena, target); |
| 16829 | switch (array_ty.ptrSize()) { | 16831 | switch (indexable_ty.ptrSize()) { |
| 16830 | .Slice => { | 16832 | .Slice => return sema.elemPtrSlice(block, indexable_ptr_src, indexable, elem_index_src, elem_index), |
| 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 | }, | | |
| 16843 | .Many, .C => { | 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 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 16835 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 16846 | | 16836 | |
| 16847 | const runtime_src = rs: { | 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 | const index_val = maybe_index_val orelse break :rs elem_index_src; | 16839 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 16850 | const index = @intCast(usize, index_val.toUnsignedInt()); | 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 | return sema.addConstant(result_ty, elem_ptr); | 16842 | return sema.addConstant(result_ty, elem_ptr); |
| 16853 | }; | 16843 | }; |
| 16854 | | 16844 | |
| 16855 | try sema.requireRuntimeBlock(block, runtime_src); | 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 | .One => { | 16848 | .One => { |
| 16859 | assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable | 16849 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable |
| 16860 | return sema.elemPtrArray(block, array_ptr_src, array, elem_index, elem_index_src); | 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 | .Struct => { | 16855 | .Struct => { |
| 16866 | // Tuple field access. | 16856 | // Tuple field access. |
| 16867 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); | 16857 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); |
| 16868 | const index = @intCast(u32, index_val.toUnsignedInt()); | 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 | else => unreachable, | 16861 | else => unreachable, |
| 16872 | } | 16862 | } |
| ... | @@ -16876,90 +16866,66 @@ fn elemVal( | ... | @@ -16876,90 +16866,66 @@ fn elemVal( |
| 16876 | sema: *Sema, | 16866 | sema: *Sema, |
| 16877 | block: *Block, | 16867 | block: *Block, |
| 16878 | src: LazySrcLoc, | 16868 | src: LazySrcLoc, |
| 16879 | array: Air.Inst.Ref, | 16869 | indexable: Air.Inst.Ref, |
| 16880 | elem_index_uncasted: Air.Inst.Ref, | 16870 | elem_index_uncasted: Air.Inst.Ref, |
| 16881 | elem_index_src: LazySrcLoc, | 16871 | elem_index_src: LazySrcLoc, |
| 16882 | ) CompileError!Air.Inst.Ref { | 16872 | ) CompileError!Air.Inst.Ref { |
| 16883 | const array_src = src; // TODO better source location | 16873 | const indexable_src = src; // TODO better source location |
| 16884 | const array_ty = sema.typeOf(array); | 16874 | const indexable_ty = sema.typeOf(indexable); |
| 16885 | | 16875 | |
| 16886 | if (!array_ty.isIndexable()) { | 16876 | if (!indexable_ty.isIndexable()) { |
| 16887 | return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty}); | 16877 | return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty}); |
| 16888 | } | 16878 | } |
| 16889 | | 16879 | |
| 16890 | // TODO in case of a vector of pointers, we need to detect whether the element | 16880 | // TODO in case of a vector of pointers, we need to detect whether the element |
| 16891 | // index is a scalar or vector instead of unconditionally casting to usize. | 16881 | // index is a scalar or vector instead of unconditionally casting to usize. |
| 16892 | const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); | 16882 | const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); |
| 16893 | | 16883 | |
| 16894 | switch (array_ty.zigTypeTag()) { | 16884 | switch (indexable_ty.zigTypeTag()) { |
| 16895 | .Pointer => switch (array_ty.ptrSize()) { | 16885 | .Pointer => switch (indexable_ty.ptrSize()) { |
| 16896 | .Slice => { | 16886 | .Slice => return sema.elemValSlice(block, indexable_src, indexable, elem_index_src, elem_index), |
| 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 | }, | | |
| 16921 | .Many, .C => { | 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 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 16889 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 16924 | | 16890 | |
| 16925 | const runtime_src = rs: { | 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 | const index_val = maybe_index_val orelse break :rs elem_index_src; | 16893 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 16928 | const index = @intCast(usize, index_val.toUnsignedInt()); | 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 | var payload: Value.Payload.ElemPtr = .{ .data = .{ | 16897 | var payload: Value.Payload.ElemPtr = .{ .data = .{ |
| 16932 | .array_ptr = array_val, | 16898 | .array_ptr = indexable_val, |
| 16933 | .elem_ty = elem_ty, | 16899 | .elem_ty = elem_ty, |
| 16934 | .index = index, | 16900 | .index = index, |
| 16935 | } }; | 16901 | } }; |
| 16936 | const elem_ptr_val = Value.initPayload(&payload.base); | 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 | return sema.addConstant(elem_ty, elem_val); | 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 | try sema.requireRuntimeBlock(block, runtime_src); | 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 | .One => { | 16913 | .One => { |
| 16948 | assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable | 16914 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable |
| 16949 | const elem_ptr = try sema.elemPtr(block, array_src, array, elem_index, elem_index_src); | 16915 | const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src); |
| 16950 | return sema.analyzeLoad(block, array_src, elem_ptr, 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 | .Vector => { | 16920 | .Vector => { |
| 16955 | // TODO: If the index is a vector, the result should be a vector. | 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 | .Struct => { | 16924 | .Struct => { |
| 16959 | // Tuple field access. | 16925 | // Tuple field access. |
| 16960 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); | 16926 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index); |
| 16961 | const index = @intCast(u32, index_val.toUnsignedInt()); | 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 | else => unreachable, | 16930 | else => unreachable, |
| 16965 | } | 16931 | } |
| ... | @@ -16968,22 +16934,26 @@ fn elemVal( | ... | @@ -16968,22 +16934,26 @@ fn elemVal( |
| 16968 | fn tupleFieldPtr( | 16934 | fn tupleFieldPtr( |
| 16969 | sema: *Sema, | 16935 | sema: *Sema, |
| 16970 | block: *Block, | 16936 | block: *Block, |
| | 16937 | tuple_ptr_src: LazySrcLoc, |
| 16971 | tuple_ptr: Air.Inst.Ref, | 16938 | tuple_ptr: Air.Inst.Ref, |
| 16972 | field_index: u32, | | |
| 16973 | tuple_src: LazySrcLoc, | | |
| 16974 | field_index_src: LazySrcLoc, | 16939 | field_index_src: LazySrcLoc, |
| | 16940 | field_index: u32, |
| 16975 | ) CompileError!Air.Inst.Ref { | 16941 | ) CompileError!Air.Inst.Ref { |
| 16976 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); | 16942 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); |
| 16977 | const tuple_ty = tuple_ptr_ty.childType(); | 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 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ | 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 | const target = sema.mod.getTarget(); | 16957 | const target = sema.mod.getTarget(); |
| 16988 | const ptr_field_ty = try Type.ptr(sema.arena, target, .{ | 16958 | const ptr_field_ty = try Type.ptr(sema.arena, target, .{ |
| 16989 | .pointee_type = field_ty, | 16959 | .pointee_type = field_ty, |
| ... | @@ -16991,7 +16961,7 @@ fn tupleFieldPtr( | ... | @@ -16991,7 +16961,7 @@ fn tupleFieldPtr( |
| 16991 | .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(), | 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 | return sema.addConstant( | 16965 | return sema.addConstant( |
| 16996 | ptr_field_ty, | 16966 | ptr_field_ty, |
| 16997 | try Value.Tag.field_ptr.create(sema.arena, .{ | 16967 | try Value.Tag.field_ptr.create(sema.arena, .{ |
| ... | @@ -17002,29 +16972,33 @@ fn tupleFieldPtr( | ... | @@ -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 | return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); | 16976 | return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); |
| 17007 | } | 16977 | } |
| 17008 | | 16978 | |
| 17009 | fn tupleField( | 16979 | fn tupleField( |
| 17010 | sema: *Sema, | 16980 | sema: *Sema, |
| 17011 | block: *Block, | 16981 | block: *Block, |
| 17012 | tuple: Air.Inst.Ref, | | |
| 17013 | field_index: u32, | | |
| 17014 | tuple_src: LazySrcLoc, | 16982 | tuple_src: LazySrcLoc, |
| | 16983 | tuple: Air.Inst.Ref, |
| 17015 | field_index_src: LazySrcLoc, | 16984 | field_index_src: LazySrcLoc, |
| | 16985 | field_index: u32, |
| 17016 | ) CompileError!Air.Inst.Ref { | 16986 | ) CompileError!Air.Inst.Ref { |
| 17017 | const tuple_ty = sema.typeOf(tuple); | 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 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ | 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]; | 17000 | const field_ty = tuple_fields.types[field_index]; |
| 17027 | const field_val = tuple_info.values[field_index]; | 17001 | const field_val = tuple_fields.values[field_index]; |
| 17028 | | 17002 | |
| 17029 | if (field_val.tag() != .unreachable_value) { | 17003 | if (field_val.tag() != .unreachable_value) { |
| 17030 | return sema.addConstant(field_ty, field_val); // comptime field | 17004 | return sema.addConstant(field_ty, field_val); // comptime field |
| ... | @@ -17043,57 +17017,221 @@ fn tupleField( | ... | @@ -17043,57 +17017,221 @@ fn tupleField( |
| 17043 | fn elemValArray( | 17017 | fn elemValArray( |
| 17044 | sema: *Sema, | 17018 | sema: *Sema, |
| 17045 | block: *Block, | 17019 | block: *Block, |
| 17046 | array: Air.Inst.Ref, | | |
| 17047 | elem_index: Air.Inst.Ref, | | |
| 17048 | array_src: LazySrcLoc, | 17020 | array_src: LazySrcLoc, |
| | 17021 | array: Air.Inst.Ref, |
| 17049 | elem_index_src: LazySrcLoc, | 17022 | elem_index_src: LazySrcLoc, |
| | 17023 | elem_index: Air.Inst.Ref, |
| 17050 | ) CompileError!Air.Inst.Ref { | 17024 | ) CompileError!Air.Inst.Ref { |
| 17051 | const array_ty = sema.typeOf(array); | 17025 | const array_ty = sema.typeOf(array); |
| 17052 | if (try sema.resolveMaybeUndefVal(block, array_src, array)) |array_val| { | 17026 | const array_sent = array_ty.sentinel() != null; |
| 17053 | const elem_ty = array_ty.childType(); | 17027 | const array_len = array_ty.arrayLen(); |
| 17054 | if (array_val.isUndef()) return sema.addConstUndef(elem_ty); | 17028 | const array_len_s = array_len + @boolToInt(array_sent); |
| 17055 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 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 | if (maybe_index_val) |index_val| { | 17050 | if (maybe_index_val) |index_val| { |
| 17057 | const index = @intCast(usize, index_val.toUnsignedInt()); | 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 | const elem_val = try array_val.elemValue(sema.arena, index); | 17052 | const elem_val = try array_val.elemValue(sema.arena, index); |
| 17065 | return sema.addConstant(elem_ty, elem_val); | 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 | return block.addBinOp(.array_elem_val, array, elem_index); | 17068 | return block.addBinOp(.array_elem_val, array, elem_index); |
| 17070 | } | 17069 | } |
| 17071 | | 17070 | |
| 17072 | fn elemPtrArray( | 17071 | fn elemPtrArray( |
| 17073 | sema: *Sema, | 17072 | sema: *Sema, |
| 17074 | block: *Block, | 17073 | block: *Block, |
| 17075 | src: LazySrcLoc, | 17074 | array_ptr_src: LazySrcLoc, |
| 17076 | array_ptr: Air.Inst.Ref, | 17075 | array_ptr: Air.Inst.Ref, |
| 17077 | elem_index: Air.Inst.Ref, | | |
| 17078 | elem_index_src: LazySrcLoc, | 17076 | elem_index_src: LazySrcLoc, |
| | 17077 | elem_index: Air.Inst.Ref, |
| 17079 | ) CompileError!Air.Inst.Ref { | 17078 | ) CompileError!Air.Inst.Ref { |
| | 17079 | const target = sema.mod.getTarget(); |
| 17080 | const array_ptr_ty = sema.typeOf(array_ptr); | 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 | const target = sema.mod.getTarget(); | 17192 | const target = sema.mod.getTarget(); |
| 17082 | const result_ty = try array_ptr_ty.elemPtrType(sema.arena, target); | 17193 | const slice_ty = sema.typeOf(slice); |
| 17083 | | 17194 | const slice_sent = slice_ty.sentinel() != null; |
| 17084 | if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| { | 17195 | const elem_ptr_ty = try slice_ty.elemPtrType(sema.arena, target); |
| 17085 | if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| { | 17196 | |
| 17086 | // Both array pointer and index are compile-time known. | 17197 | const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(block, slice_src, slice); |
| 17087 | const index_u64 = index_val.toUnsignedInt(); | 17198 | // index must be defined since it can index out of bounds |
| 17088 | // @intCast here because it would have been impossible to construct a value that | 17199 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 17089 | // required a larger index. | 17200 | |
| 17090 | const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, @intCast(usize, index_u64)); | 17201 | if (maybe_undef_slice_val) |slice_val| { |
| 17091 | return sema.addConstant(result_ty, elem_ptr); | 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 | 17220 | |
| 17095 | try sema.requireRuntimeBlock(block, src); | 17221 | const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src; |
| 17096 | return block.addPtrElemPtr(array_ptr, elem_index, result_ty); | 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 | fn coerce( | 17237 | fn coerce( |
| ... | @@ -18000,7 +18138,7 @@ fn storePtr2( | ... | @@ -18000,7 +18138,7 @@ fn storePtr2( |
| 18000 | for (tuple.types) |_, i_usize| { | 18138 | for (tuple.types) |_, i_usize| { |
| 18001 | const i = @intCast(u32, i_usize); | 18139 | const i = @intCast(u32, i_usize); |
| 18002 | const elem_src = operand_src; // TODO better source location | 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 | const elem_index = try sema.addIntUnsigned(Type.usize, i); | 18142 | const elem_index = try sema.addIntUnsigned(Type.usize, i); |
| 18005 | const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src); | 18143 | const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src); |
| 18006 | try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); | 18144 | try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store); |
| ... | @@ -18885,7 +19023,7 @@ fn coerceArrayLike( | ... | @@ -18885,7 +19023,7 @@ fn coerceArrayLike( |
| 18885 | try Value.Tag.int_u64.create(sema.arena, i), | 19023 | try Value.Tag.int_u64.create(sema.arena, i), |
| 18886 | ); | 19024 | ); |
| 18887 | const elem_src = inst_src; // TODO better source location | 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 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); | 19027 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 18890 | element_refs[i] = coerced; | 19028 | element_refs[i] = coerced; |
| 18891 | if (runtime_src == null) { | 19029 | if (runtime_src == null) { |
| ... | @@ -18942,7 +19080,7 @@ fn coerceTupleToArray( | ... | @@ -18942,7 +19080,7 @@ fn coerceTupleToArray( |
| 18942 | for (element_vals) |*elem, i_usize| { | 19080 | for (element_vals) |*elem, i_usize| { |
| 18943 | const i = @intCast(u32, i_usize); | 19081 | const i = @intCast(u32, i_usize); |
| 18944 | const elem_src = inst_src; // TODO better source location | 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 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); | 19084 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 18947 | element_refs[i] = coerced; | 19085 | element_refs[i] = coerced; |
| 18948 | if (runtime_src == null) { | 19086 | if (runtime_src == null) { |
| ... | @@ -19042,7 +19180,7 @@ fn coerceTupleToStruct( | ... | @@ -19042,7 +19180,7 @@ fn coerceTupleToStruct( |
| 19042 | if (field.is_comptime) { | 19180 | if (field.is_comptime) { |
| 19043 | return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to structs when one of the destination struct fields is comptime", .{}); | 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 | const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); | 19184 | const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); |
| 19047 | field_refs[field_index] = coerced; | 19185 | field_refs[field_index] = coerced; |
| 19048 | if (runtime_src == null) { | 19186 | if (runtime_src == null) { |