| author | |
| committer | |
| log | c96f9a017a863e1f8cb610b7caba60ce93ab5616 |
| tree | 501d159d47c55437222a0c771563fb6a0bbdf784 |
| parent | 072e062443e441f63dc1694766dd716c15a287c1 |
Resolves: #204337 files changed, 138 insertions(+), 32 deletions(-)
lib/std/zig/AstGen.zig+2-2| ... | ... | @@ -2716,7 +2716,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2716 | 2716 | .array_type_sentinel, |
| 2717 | 2717 | .elem_type, |
| 2718 | 2718 | .indexable_ptr_elem_type, |
| 2719 | .vector_elem_type, | |
| 2719 | .vec_arr_elem_type, | |
| 2720 | 2720 | .vector_type, |
| 2721 | 2721 | .indexable_ptr_len, |
| 2722 | 2722 | .anyframe_type, |
| ... | ... | @@ -9529,7 +9529,7 @@ fn builtinCall( |
| 9529 | 9529 | |
| 9530 | 9530 | .splat => { |
| 9531 | 9531 | const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name); |
| 9532 | const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node); | |
| 9532 | const elem_type = try gz.addUnNode(.vec_arr_elem_type, result_type, node); | |
| 9533 | 9533 | const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]); |
| 9534 | 9534 | const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ |
| 9535 | 9535 | .lhs = result_type, |
lib/std/zig/Zir.zig+6-6| ... | ... | @@ -247,9 +247,9 @@ pub const Inst = struct { |
| 247 | 247 | /// element type. Emits a compile error if the type is not an indexable pointer. |
| 248 | 248 | /// Uses the `un_node` field. |
| 249 | 249 | indexable_ptr_elem_type, |
| 250 | /// Given a vector type, returns its element type. | |
| 250 | /// Given a vector or array type, returns its element type. | |
| 251 | 251 | /// Uses the `un_node` field. |
| 252 | vector_elem_type, | |
| 252 | vec_arr_elem_type, | |
| 253 | 253 | /// Given a pointer to an indexable object, returns the len property. This is |
| 254 | 254 | /// used by for loops. This instruction also emits a for-loop specific compile |
| 255 | 255 | /// error if the indexable object is not indexable. |
| ... | ... | @@ -1065,7 +1065,7 @@ pub const Inst = struct { |
| 1065 | 1065 | .vector_type, |
| 1066 | 1066 | .elem_type, |
| 1067 | 1067 | .indexable_ptr_elem_type, |
| 1068 | .vector_elem_type, | |
| 1068 | .vec_arr_elem_type, | |
| 1069 | 1069 | .indexable_ptr_len, |
| 1070 | 1070 | .anyframe_type, |
| 1071 | 1071 | .as_node, |
| ... | ... | @@ -1375,7 +1375,7 @@ pub const Inst = struct { |
| 1375 | 1375 | .vector_type, |
| 1376 | 1376 | .elem_type, |
| 1377 | 1377 | .indexable_ptr_elem_type, |
| 1378 | .vector_elem_type, | |
| 1378 | .vec_arr_elem_type, | |
| 1379 | 1379 | .indexable_ptr_len, |
| 1380 | 1380 | .anyframe_type, |
| 1381 | 1381 | .as_node, |
| ... | ... | @@ -1607,7 +1607,7 @@ pub const Inst = struct { |
| 1607 | 1607 | .vector_type = .pl_node, |
| 1608 | 1608 | .elem_type = .un_node, |
| 1609 | 1609 | .indexable_ptr_elem_type = .un_node, |
| 1610 | .vector_elem_type = .un_node, | |
| 1610 | .vec_arr_elem_type = .un_node, | |
| 1611 | 1611 | .indexable_ptr_len = .un_node, |
| 1612 | 1612 | .anyframe_type = .un_node, |
| 1613 | 1613 | .as_node = .pl_node, |
| ... | ... | @@ -3781,7 +3781,7 @@ fn findDeclsInner( |
| 3781 | 3781 | .vector_type, |
| 3782 | 3782 | .elem_type, |
| 3783 | 3783 | .indexable_ptr_elem_type, |
| 3784 | .vector_elem_type, | |
| 3784 | .vec_arr_elem_type, | |
| 3785 | 3785 | .indexable_ptr_len, |
| 3786 | 3786 | .anyframe_type, |
| 3787 | 3787 | .as_node, |
src/Sema.zig+55-14| ... | ... | @@ -1087,7 +1087,7 @@ fn analyzeBodyInner( |
| 1087 | 1087 | .elem_val_imm => try sema.zirElemValImm(block, inst), |
| 1088 | 1088 | .elem_type => try sema.zirElemType(block, inst), |
| 1089 | 1089 | .indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst), |
| 1090 | .vector_elem_type => try sema.zirVectorElemType(block, inst), | |
| 1090 | .vec_arr_elem_type => try sema.zirVecArrElemType(block, inst), | |
| 1091 | 1091 | .enum_literal => try sema.zirEnumLiteral(block, inst), |
| 1092 | 1092 | .decl_literal => try sema.zirDeclLiteral(block, inst, true), |
| 1093 | 1093 | .decl_literal_no_coerce => try sema.zirDeclLiteral(block, inst, false), |
| ... | ... | @@ -2046,7 +2046,7 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi |
| 2046 | 2046 | const bin = sema.code.instructions.items(.data)[@intFromEnum(inst)].bin; |
| 2047 | 2047 | cur = bin.lhs; |
| 2048 | 2048 | }, |
| 2049 | .indexable_ptr_elem_type, .vector_elem_type => { | |
| 2049 | .indexable_ptr_elem_type, .vec_arr_elem_type => { | |
| 2050 | 2050 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 2051 | 2051 | cur = un_node.operand; |
| 2052 | 2052 | }, |
| ... | ... | @@ -8603,7 +8603,7 @@ fn zirIndexablePtrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 8603 | 8603 | return Air.internedToRef(elem_ty.toIntern()); |
| 8604 | 8604 | } |
| 8605 | 8605 | |
| 8606 | fn zirVectorElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 8606 | fn zirVecArrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 8607 | 8607 | const pt = sema.pt; |
| 8608 | 8608 | const zcu = pt.zcu; |
| 8609 | 8609 | const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| ... | ... | @@ -8615,8 +8615,9 @@ fn zirVectorElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 8615 | 8615 | error.GenericPoison => return .generic_poison_type, |
| 8616 | 8616 | else => |e| return e, |
| 8617 | 8617 | }; |
| 8618 | if (!vec_ty.isVector(zcu)) { | |
| 8619 | return sema.fail(block, block.nodeOffset(un_node.src_node), "expected vector type, found '{}'", .{vec_ty.fmt(pt)}); | |
| 8618 | switch (vec_ty.zigTypeTag(zcu)) { | |
| 8619 | .array, .vector => {}, | |
| 8620 | else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{}'", .{vec_ty.fmt(pt)}), | |
| 8620 | 8621 | } |
| 8621 | 8622 | return Air.internedToRef(vec_ty.childType(zcu).toIntern()); |
| 8622 | 8623 | } |
| ... | ... | @@ -24804,26 +24805,66 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 24804 | 24805 | const scalar_src = block.builtinCallArgSrc(inst_data.src_node, 0); |
| 24805 | 24806 | const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@splat"); |
| 24806 | 24807 | |
| 24807 | if (!dest_ty.isVector(zcu)) return sema.fail(block, src, "expected vector type, found '{}'", .{dest_ty.fmt(pt)}); | |
| 24808 | switch (dest_ty.zigTypeTag(zcu)) { | |
| 24809 | .array, .vector => {}, | |
| 24810 | else => return sema.fail(block, src, "expected array or vector type, found '{}'", .{dest_ty.fmt(pt)}), | |
| 24811 | } | |
| 24808 | 24812 | |
| 24809 | if (!dest_ty.hasRuntimeBits(zcu)) { | |
| 24813 | const operand = try sema.resolveInst(extra.rhs); | |
| 24814 | const scalar_ty = dest_ty.childType(zcu); | |
| 24815 | const scalar = try sema.coerce(block, scalar_ty, operand, scalar_src); | |
| 24816 | ||
| 24817 | const len = try sema.usizeCast(block, src, dest_ty.arrayLen(zcu)); | |
| 24818 | ||
| 24819 | // `len == 0` because `[0:s]T` always has a comptime-known splat. | |
| 24820 | if (!dest_ty.hasRuntimeBits(zcu) or len == 0) { | |
| 24810 | 24821 | const empty_aggregate = try pt.intern(.{ .aggregate = .{ |
| 24811 | 24822 | .ty = dest_ty.toIntern(), |
| 24812 | .storage = .{ .elems = &[_]InternPool.Index{} }, | |
| 24823 | .storage = .{ .elems = &.{} }, | |
| 24813 | 24824 | } }); |
| 24814 | 24825 | return Air.internedToRef(empty_aggregate); |
| 24815 | 24826 | } |
| 24816 | 24827 | |
| 24817 | const operand = try sema.resolveInst(extra.rhs); | |
| 24818 | const scalar_ty = dest_ty.childType(zcu); | |
| 24819 | const scalar = try sema.coerce(block, scalar_ty, operand, scalar_src); | |
| 24828 | const maybe_sentinel = dest_ty.sentinel(zcu); | |
| 24829 | ||
| 24820 | 24830 | if (try sema.resolveValue(scalar)) |scalar_val| { |
| 24821 | if (scalar_val.isUndef(zcu)) return pt.undefRef(dest_ty); | |
| 24822 | return Air.internedToRef((try sema.splat(dest_ty, scalar_val)).toIntern()); | |
| 24831 | if (scalar_val.isUndef(zcu) and maybe_sentinel == null) { | |
| 24832 | return pt.undefRef(dest_ty); | |
| 24833 | } | |
| 24834 | // TODO: I didn't want to put `.aggregate` on a separate line here; `zig fmt` bugs have forced my hand | |
| 24835 | return Air.internedToRef(try pt.intern(.{ | |
| 24836 | .aggregate = .{ | |
| 24837 | .ty = dest_ty.toIntern(), | |
| 24838 | .storage = s: { | |
| 24839 | full: { | |
| 24840 | if (dest_ty.zigTypeTag(zcu) == .vector) break :full; | |
| 24841 | const sentinel = maybe_sentinel orelse break :full; | |
| 24842 | if (sentinel.toIntern() == scalar_val.toIntern()) break :full; | |
| 24843 | // This is a array with non-zero length and a sentinel which does not match the element. | |
| 24844 | // We have to use the full `elems` representation. | |
| 24845 | const elems = try sema.arena.alloc(InternPool.Index, len + 1); | |
| 24846 | @memset(elems[0..len], scalar_val.toIntern()); | |
| 24847 | elems[len] = sentinel.toIntern(); | |
| 24848 | break :s .{ .elems = elems }; | |
| 24849 | } | |
| 24850 | break :s .{ .repeated_elem = scalar_val.toIntern() }; | |
| 24851 | }, | |
| 24852 | }, | |
| 24853 | })); | |
| 24823 | 24854 | } |
| 24824 | 24855 | |
| 24825 | 24856 | try sema.requireRuntimeBlock(block, src, scalar_src); |
| 24826 | return block.addTyOp(.splat, dest_ty, scalar); | |
| 24857 | ||
| 24858 | switch (dest_ty.zigTypeTag(zcu)) { | |
| 24859 | .array => { | |
| 24860 | const elems = try sema.arena.alloc(Air.Inst.Ref, len + @intFromBool(maybe_sentinel != null)); | |
| 24861 | @memset(elems[0..len], scalar); | |
| 24862 | if (maybe_sentinel) |s| elems[len] = Air.internedToRef(s.toIntern()); | |
| 24863 | return block.addAggregateInit(dest_ty, elems); | |
| 24864 | }, | |
| 24865 | .vector => return block.addTyOp(.splat, dest_ty, scalar), | |
| 24866 | else => unreachable, | |
| 24867 | } | |
| 24827 | 24868 | } |
| 24828 | 24869 | |
| 24829 | 24870 | fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
src/print_zir.zig+1-1| ... | ... | @@ -203,7 +203,7 @@ const Writer = struct { |
| 203 | 203 | .alloc_comptime_mut, |
| 204 | 204 | .elem_type, |
| 205 | 205 | .indexable_ptr_elem_type, |
| 206 | .vector_elem_type, | |
| 206 | .vec_arr_elem_type, | |
| 207 | 207 | .indexable_ptr_len, |
| 208 | 208 | .anyframe_type, |
| 209 | 209 | .bit_not, |
test/behavior/array.zig+67| ... | ... | @@ -1021,3 +1021,70 @@ test "runtime index of array of zero-bit values" { |
| 1021 | 1021 | try std.testing.expect(result.index == 0); |
| 1022 | 1022 | try std.testing.expect(result.value == {}); |
| 1023 | 1023 | } |
| 1024 | ||
| 1025 | test "@splat array" { | |
| 1026 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1027 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1028 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 1029 | const S = struct { | |
| 1030 | fn doTheTest(comptime T: type, x: T) !void { | |
| 1031 | const arr: [10]T = @splat(x); | |
| 1032 | for (arr) |elem| { | |
| 1033 | try expectEqual(x, elem); | |
| 1034 | } | |
| 1035 | } | |
| 1036 | }; | |
| 1037 | ||
| 1038 | try S.doTheTest(u32, 123); | |
| 1039 | try comptime S.doTheTest(u32, 123); | |
| 1040 | ||
| 1041 | const Foo = struct { x: u8 }; | |
| 1042 | try S.doTheTest(Foo, .{ .x = 10 }); | |
| 1043 | try comptime S.doTheTest(Foo, .{ .x = 10 }); | |
| 1044 | } | |
| 1045 | ||
| 1046 | test "@splat array with sentinel" { | |
| 1047 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1048 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1049 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 1050 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 1051 | const S = struct { | |
| 1052 | fn doTheTest(comptime T: type, x: T, comptime s: T) !void { | |
| 1053 | const arr: [10:s]T = @splat(x); | |
| 1054 | for (arr) |elem| { | |
| 1055 | try expectEqual(x, elem); | |
| 1056 | } | |
| 1057 | const ptr: [*]const T = &arr; | |
| 1058 | try expectEqual(s, ptr[10]); // sentinel correct | |
| 1059 | } | |
| 1060 | }; | |
| 1061 | ||
| 1062 | try S.doTheTest(u32, 100, 42); | |
| 1063 | try comptime S.doTheTest(u32, 100, 42); | |
| 1064 | ||
| 1065 | try S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null); | |
| 1066 | try comptime S.doTheTest(?*anyopaque, @ptrFromInt(0x1000), null); | |
| 1067 | } | |
| 1068 | ||
| 1069 | test "@splat zero-length array" { | |
| 1070 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1071 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1072 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 1073 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 1074 | const S = struct { | |
| 1075 | fn doTheTest(comptime T: type, comptime s: T) !void { | |
| 1076 | var runtime_undef: T = undefined; | |
| 1077 | runtime_undef = undefined; | |
| 1078 | // The array should be comptime-known despite the `@splat` operand being runtime-known. | |
| 1079 | const arr: [0:s]T = @splat(runtime_undef); | |
| 1080 | const ptr: [*]const T = &arr; | |
| 1081 | comptime assert(ptr[0] == s); | |
| 1082 | } | |
| 1083 | }; | |
| 1084 | ||
| 1085 | try S.doTheTest(u32, 42); | |
| 1086 | try comptime S.doTheTest(u32, 42); | |
| 1087 | ||
| 1088 | try S.doTheTest(?*anyopaque, null); | |
| 1089 | try comptime S.doTheTest(?*anyopaque, null); | |
| 1090 | } |
test/cases/compile_errors/splat_bad_result_type.zig created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | export fn f() void { | |
| 2 | _ = @as(u32, @splat(5)); | |
| 3 | } | |
| 4 | ||
| 5 | // error | |
| 6 | // | |
| 7 | // :2:18: error: expected array or vector type, found 'u32' |
test/cases/compile_errors/splat_result_type_non_vector.zig deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | export fn f() void { | |
| 2 | _ = @as(u32, @splat(5)); | |
| 3 | } | |
| 4 | ||
| 5 | // error | |
| 6 | // backend=stage2 | |
| 7 | // target=native | |
| 8 | // | |
| 9 | // :2:18: error: expected vector type, found 'u32' |