authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-04-29 19:58:39+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-04-30 09:03:58+01:00
log72d954e7d3cfb8b46a26d5a199a9a5ecd36d87be
tree593dcfa9fd869bab3b94506a588e01d22cab8706
parentfdac89d6cd65fa19bd5c6d381b62d980d97e5852
signaturelock-open Commit is signed but in an unrecognized format.

compiler: remove array multiplication from the language

Resolves: https://github.com/ziglang/zig/issues/24738

21 files changed, 20 insertions(+), 421 deletions(-)

lib/compiler/reduce/Walk.zig-1
......@@ -248,7 +248,6 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
248248 .add_wrap,
249249 .add_sat,
250250 .array_cat,
251 .array_mult,
252251 .assign,
253252 .assign_bit_and,
254253 .assign_bit_or,
lib/docs/wasm/Walk.zig-1
......@@ -709,7 +709,6 @@ fn expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index)
709709 .less_or_equal,
710710 .array_cat,
711711
712 .array_mult,
713712 .error_union,
714713 .merge_error_sets,
715714 .bool_and,
lib/docs/wasm/html_render.zig+1-2
......@@ -302,7 +302,6 @@ pub fn fileSourceHtml(
302302 .minus_pipe_equal,
303303 .asterisk,
304304 .asterisk_equal,
305 .asterisk_asterisk,
306305 .asterisk_percent,
307306 .asterisk_percent_equal,
308307 .asterisk_pipe,
......@@ -328,7 +327,7 @@ pub fn fileSourceHtml(
328327 .tilde,
329328 => try appendEscaped(out, slice),
330329
331 .invalid, .invalid_periodasterisks => return error.InvalidToken,
330 .invalid => return error.InvalidToken,
332331 }
333332 }
334333}
lib/std/crypto/Certificate.zig+1-1
......@@ -1092,7 +1092,7 @@ pub const rsa = struct {
10921092 }
10931093 var m_p_buf: [8 + Hash.digest_length + Hash.digest_length]u8 = undefined;
10941094 var m_p = m_p_buf[0 .. 8 + Hash.digest_length + sLen];
1095 std.mem.copyForwards(u8, m_p, @as(*const [8]u8, @splat(0)));
1095 std.mem.copyForwards(u8, m_p, @as(*const [8]u8, &@splat(0)));
10961096 std.mem.copyForwards(u8, m_p[8..], &mHash);
10971097 std.mem.copyForwards(u8, m_p[(8 + Hash.digest_length)..], salt);
10981098
lib/std/zig.zig-2
......@@ -811,7 +811,6 @@ pub const SimpleComptimeReason = enum(u32) {
811811 compile_error_string,
812812 inline_assembly_code,
813813 atomic_order,
814 array_mul_factor,
815814 slice_cat_operand,
816815 inline_call_target,
817816 generic_call_target,
......@@ -899,7 +898,6 @@ pub const SimpleComptimeReason = enum(u32) {
899898 .compile_error_string => "compile error string must be comptime-known",
900899 .inline_assembly_code => "inline assembly code must be comptime-known",
901900 .atomic_order => "atomic order must be comptime-known",
902 .array_mul_factor => "array multiplication factor must be comptime-known",
903901 .slice_cat_operand => "slice being concatenated must be comptime-known",
904902 .inline_call_target => "function being called inline must be comptime-known",
905903 .generic_call_target => "generic function being called must be comptime-known",
lib/std/zig/Ast.zig+1-21
......@@ -331,11 +331,6 @@ pub fn rootDecls(tree: Ast) []const Node.Index {
331331
332332pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void {
333333 switch (parse_error.tag) {
334 .asterisk_after_ptr_deref => {
335 // Note that the token will point at the `.*` but ideally the source
336 // location would point to the `*` after the `.*`.
337 return w.writeAll("'.*' cannot be followed by '*'; are you missing a space?");
338 },
339334 .chained_comparison_operators => {
340335 return w.writeAll("comparison operators cannot be chained");
341336 },
......@@ -687,7 +682,6 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {
687682 .mul,
688683 .div,
689684 .mod,
690 .array_mult,
691685 .mul_wrap,
692686 .mul_sat,
693687 .add,
......@@ -924,7 +918,6 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {
924918 .mul,
925919 .div,
926920 .mod,
927 .array_mult,
928921 .mul_wrap,
929922 .mul_sat,
930923 .add,
......@@ -2111,9 +2104,7 @@ fn fullFnProtoComponents(tree: Ast, info: full.FnProto.Components) full.FnProto
21112104
21122105fn fullPtrTypeComponents(tree: Ast, info: full.PtrType.Components) full.PtrType {
21132106 const size: std.builtin.Type.Pointer.Size = switch (tree.tokenTag(info.main_token)) {
2114 .asterisk,
2115 .asterisk_asterisk,
2116 => .one,
2107 .asterisk => .one,
21172108 .l_bracket => switch (tree.tokenTag(info.main_token + 1)) {
21182109 .asterisk => if (tree.tokenTag(info.main_token + 2) == .identifier) .c else .many,
21192110 else => .slice,
......@@ -2842,7 +2833,6 @@ pub const Error = struct {
28422833 } = .{ .none = {} },
28432834
28442835 pub const Tag = enum {
2845 asterisk_after_ptr_deref,
28462836 chained_comparison_operators,
28472837 decl_between_fields,
28482838 expected_block,
......@@ -3178,8 +3168,6 @@ pub const Node = struct {
31783168 div,
31793169 /// `lhs % rhs`. The `main_token` field is the `%` token.
31803170 mod,
3181 /// `lhs ** rhs`. The `main_token` field is the `**` token.
3182 array_mult,
31833171 /// `lhs *% rhs`. The `main_token` field is the `*%` token.
31843172 mul_wrap,
31853173 /// `lhs *| rhs`. The `main_token` field is the `*|` token.
......@@ -3250,8 +3238,6 @@ pub const Node = struct {
32503238 ///
32513239 /// The `main_token` is the asterisk if a single item pointer or the
32523240 /// lbracket if a slice, many-item pointer, or C-pointer.
3253 /// The `main_token` might be a ** token, which is shared with a
3254 /// parent/child pointer type and may require special handling.
32553241 ptr_type_aligned,
32563242 /// `[*:lhs]rhs`,
32573243 /// `*rhs`,
......@@ -3263,8 +3249,6 @@ pub const Node = struct {
32633249 ///
32643250 /// The `main_token` is the asterisk if a single item pointer or the
32653251 /// lbracket if a slice, many-item pointer, or C-pointer.
3266 /// The `main_token` might be a ** token, which is shared with a
3267 /// parent/child pointer type and may require special handling.
32683252 ptr_type_sentinel,
32693253 /// The `data` field is a `.extra_and_node`:
32703254 /// 1. a `ExtraIndex` to `PtrType`.
......@@ -3272,8 +3256,6 @@ pub const Node = struct {
32723256 ///
32733257 /// The `main_token` is the asterisk if a single item pointer or the
32743258 /// lbracket if a slice, many-item pointer, or C-pointer.
3275 /// The `main_token` might be a ** token, which is shared with a
3276 /// parent/child pointer type and may require special handling.
32773259 ptr_type,
32783260 /// The `data` field is a `.extra_and_node`:
32793261 /// 1. a `ExtraIndex` to `PtrTypeBitRange`.
......@@ -3281,8 +3263,6 @@ pub const Node = struct {
32813263 ///
32823264 /// The `main_token` is the asterisk if a single item pointer or the
32833265 /// lbracket if a slice, many-item pointer, or C-pointer.
3284 /// The `main_token` might be a ** token, which is shared with a
3285 /// parent/child pointer type and may require special handling.
32863266 ptr_type_bit_range,
32873267 /// `lhs[rhs..]`
32883268 ///
lib/std/zig/Ast/Render.zig-12
......@@ -508,7 +508,6 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
508508 .add_wrap,
509509 .add_sat,
510510 .array_cat,
511 .array_mult,
512511 .bang_equal,
513512 .bit_and,
514513 .bit_or,
......@@ -1028,16 +1027,6 @@ fn renderPtrType(r: *Render, ptr_type: Ast.full.PtrType, space: Space) Error!voi
10281027
10291028 switch (ptr_type.size) {
10301029 .one => {
1031 // Since ** tokens exist and the same token is shared by two
1032 // nested pointer types, we check to see if we are the parent
1033 // in such a relationship. If so, skip rendering anything for
1034 // this pointer type and rely on the child to render our asterisk
1035 // as well when it renders the ** token.
1036 if (tree.tokenTag(main_token) == .asterisk_asterisk and
1037 main_token == tree.nodeMainToken(ptr_type.ast.child_type))
1038 {
1039 return renderExpression(r, ptr_type.ast.child_type, space);
1040 }
10411030 try renderToken(r, main_token, .none); // asterisk
10421031 },
10431032 .many => {
......@@ -3223,7 +3212,6 @@ fn nodeCausesSliceOpSpace(tag: Ast.Node.Tag) bool {
32233212 .add,
32243213 .add_wrap,
32253214 .array_cat,
3226 .array_mult,
32273215 .assign,
32283216 .assign_bit_and,
32293217 .assign_bit_or,
lib/std/zig/AstGen.zig-16
......@@ -507,7 +507,6 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
507507 .less_than,
508508 .less_or_equal,
509509 .array_cat,
510 .array_mult,
511510 .bool_and,
512511 .bool_or,
513512 .@"asm",
......@@ -777,19 +776,6 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
777776 .less_or_equal => return simpleBinOp(gz, scope, ri, node, .cmp_lte),
778777 .array_cat => return simpleBinOp(gz, scope, ri, node, .array_cat),
779778
780 .array_mult => {
781 // This syntax form does not currently use the result type in the language specification.
782 // However, the result type can be used to emit more optimal code for large multiplications by
783 // having Sema perform a coercion before the multiplication operation.
784 const lhs_node, const rhs_node = tree.nodeData(node).node_and_node;
785 const result = try gz.addPlNode(.array_mul, node, Zir.Inst.ArrayMul{
786 .res_ty = if (try ri.rl.resultType(gz, node)) |t| t else .none,
787 .lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node),
788 .rhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, rhs_node, .array_mul_factor),
789 });
790 return rvalue(gz, ri, result, node);
791 },
792
793779 .error_union, .merge_error_sets => |tag| {
794780 const inst_tag: Zir.Inst.Tag = switch (tag) {
795781 .error_union => .error_union_type,
......@@ -2713,7 +2699,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
27132699 .alloc_inferred_comptime_mut,
27142700 .make_ptr_const,
27152701 .array_cat,
2716 .array_mul,
27172702 .array_type,
27182703 .array_type_sentinel,
27192704 .elem_type,
......@@ -10307,7 +10292,6 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
1030710292 .add_wrap,
1030810293 .add_sat,
1030910294 .array_cat,
10310 .array_mult,
1031110295 .assign,
1031210296 .assign_destructure,
1031310297 .assign_bit_and,
lib/std/zig/AstRlAnnotate.zig-6
......@@ -269,12 +269,6 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
269269 return false;
270270 },
271271
272 .array_mult => {
273 const lhs, const rhs = tree.nodeData(node).node_and_node;
274 _ = try astrl.expr(lhs, block, ResultInfo.none);
275 _ = try astrl.expr(rhs, block, ResultInfo.type_only);
276 return false;
277 },
278272 .error_union, .merge_error_sets => {
279273 const lhs, const rhs = tree.nodeData(node).node_and_node;
280274 _ = try astrl.expr(lhs, block, ResultInfo.none);
lib/std/zig/AstSmith.zig+4-10
......@@ -18,7 +18,6 @@ token_tag_buf: [2048]Token.Tag,
1818token_start_buf: [2048]std.zig.Ast.ByteOffset,
1919tokens_len: usize,
2020
21/// For `.asterisk`, this also includes `.asterisk2`
2221not_token: ?Token.Tag,
2322not_token_comptime: bool,
2423/// ExprSuffix
......@@ -196,7 +195,6 @@ fn preservePegEndOfWord(a: *AstSmith) SourceError!void {
196195/// Assumes the token has not been written yet
197196fn addTokenTag(a: *AstSmith, tag: Token.Tag) SourceError!void {
198197 assert(tag != a.not_token);
199 if (a.not_token == .asterisk) assert(tag != .asterisk_asterisk);
200198 a.not_token = null;
201199
202200 if (a.not_token_comptime) assert(tag != .keyword_comptime);
......@@ -240,9 +238,7 @@ fn pegToken(a: *AstSmith, tag: Token.Tag) SourceError!void {
240238
241239 switch (lexeme[0]) {
242240 '_', 'a'...'z', 'A'...'Z', '0'...'9' => try a.preservePegEndOfWord(),
243 '*' => if (a.tokens_len > 0 and a.source_buf[a.source_len - 1] == '*' and
244 a.token_tag_buf[a.tokens_len - 1] != .asterisk_asterisk)
245 {
241 '*' => if (a.tokens_len > 0 and a.source_buf[a.source_len - 1] == '*') {
246242 try a.addSourceByte(' ');
247243 },
248244 '.' => if (a.tokens_len > 0 and switch (a.source_buf[a.source_len - 1]) {
......@@ -1723,13 +1719,11 @@ fn pegAdditionOp(a: *AstSmith) SourceError!void {
17231719/// / ASTERISK
17241720/// / SLASH
17251721/// / PERCENT
1726/// / ASTERISK2
17271722/// / ASTERISKPERCENT
17281723/// / ASTERISKPIPE
17291724fn pegMultiplyOp(a: *AstSmith) SourceError!void {
17301725 const tags = [_]Token.Tag{
17311726 .asterisk,
1732 .asterisk_asterisk,
17331727 .pipe_pipe,
17341728 .slash,
17351729 .percent,
......@@ -1865,9 +1859,9 @@ fn pegSliceTypeStart(a: *AstSmith) SourceError!void {
18651859 try a.pegToken(.r_bracket);
18661860}
18671861
1868/// SinglePtrTypeStart <- ASTERISK / ASTERISK2
1862/// SinglePtrTypeStart <- ASTERISK
18691863fn pegSinglePtrTypeStart(a: *AstSmith) SourceError!void {
1870 try a.pegToken(if (!a.smith.value(bool)) .asterisk else .asterisk_asterisk);
1864 try a.pegToken(.asterisk);
18711865}
18721866
18731867/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
......@@ -1889,7 +1883,7 @@ fn pegManyPtrTypeStart(a: *AstSmith) SourceError!void {
18891883 try a.pegToken(.r_bracket);
18901884}
18911885
1892/// ArrayTypeStart <- LBRACKET !(ASTERISK / ASTERISK2) Expr (COLON Expr)? RBRACKET
1886/// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
18931887fn pegArrayTypeStart(a: *AstSmith) SourceError!void {
18941888 try a.pegToken(.l_bracket);
18951889 a.not_token = .asterisk;
lib/std/zig/Parse.zig+2-64
......@@ -1609,7 +1609,6 @@ const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec
16091609 .asterisk = .{ .prec = 70, .tag = .mul },
16101610 .slash = .{ .prec = 70, .tag = .div },
16111611 .percent = .{ .prec = 70, .tag = .mod },
1612 .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult },
16131612 .asterisk_percent = .{ .prec = 70, .tag = .mul_wrap },
16141613 .asterisk_pipe = .{ .prec = 70, .tag = .mul_sat },
16151614});
......@@ -1709,11 +1708,11 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {
17091708///
17101709/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
17111710///
1712/// SinglePtrTypeStart <- ASTERISK / ASTERISK2
1711/// SinglePtrTypeStart <- ASTERISK
17131712///
17141713/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
17151714///
1716/// ArrayTypeStart <- LBRACKET Expr !(ASTERISK / ASTERISK2) (COLON Expr)? RBRACKET
1715/// ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET
17171716///
17181717/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
17191718fn parseTypeExpr(p: *Parse) Error!?Node.Index {
......@@ -1777,59 +1776,6 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index {
17771776 });
17781777 }
17791778 },
1780 .asterisk_asterisk => {
1781 const asterisk = p.nextToken();
1782 const mods = try p.parsePtrModifiers();
1783 const elem_type = try p.expectTypeExpr();
1784 const inner: Node.Index = inner: {
1785 if (mods.bit_range_start != .none) {
1786 break :inner try p.addNode(.{
1787 .tag = .ptr_type_bit_range,
1788 .main_token = asterisk,
1789 .data = .{ .extra_and_node = .{
1790 try p.addExtra(Node.PtrTypeBitRange{
1791 .sentinel = .none,
1792 .align_node = mods.align_node.unwrap().?,
1793 .addrspace_node = mods.addrspace_node,
1794 .bit_range_start = mods.bit_range_start.unwrap().?,
1795 .bit_range_end = mods.bit_range_end.unwrap().?,
1796 }),
1797 elem_type,
1798 } },
1799 });
1800 } else if (mods.addrspace_node != .none) {
1801 break :inner try p.addNode(.{
1802 .tag = .ptr_type,
1803 .main_token = asterisk,
1804 .data = .{ .extra_and_node = .{
1805 try p.addExtra(Node.PtrType{
1806 .sentinel = .none,
1807 .align_node = mods.align_node,
1808 .addrspace_node = mods.addrspace_node,
1809 }),
1810 elem_type,
1811 } },
1812 });
1813 } else {
1814 break :inner try p.addNode(.{
1815 .tag = .ptr_type_aligned,
1816 .main_token = asterisk,
1817 .data = .{ .opt_node_and_node = .{
1818 mods.align_node,
1819 elem_type,
1820 } },
1821 });
1822 }
1823 };
1824 return try p.addNode(.{
1825 .tag = .ptr_type_aligned,
1826 .main_token = asterisk,
1827 .data = .{ .opt_node_and_node = .{
1828 .none,
1829 inner,
1830 } },
1831 });
1832 },
18331779 .l_bracket => switch (p.tokenTag(p.tok_i + 1)) {
18341780 .asterisk => {
18351781 const l_bracket = p.nextToken();
......@@ -3257,14 +3203,6 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
32573203 .main_token = p.nextToken(),
32583204 .data = .{ .node = lhs },
32593205 }),
3260 .invalid_periodasterisks => {
3261 try p.warn(.asterisk_after_ptr_deref);
3262 return try p.addNode(.{
3263 .tag = .deref,
3264 .main_token = p.nextToken(),
3265 .data = .{ .node = lhs },
3266 });
3267 },
32683206 .period => switch (p.tokenTag(p.tok_i + 1)) {
32693207 .identifier => return try p.addNode(.{
32703208 .tag = .field_access,
lib/std/zig/TokenSmith.zig-6
......@@ -57,12 +57,6 @@ pub fn gen(smith: *Smith) TokenSmith {
5757 @memcpy(t.source_buf[t.source_len..][0..lexeme.len], lexeme);
5858 t.source_len += @intCast(lexeme.len);
5959
60 if (tag == .invalid_periodasterisks) {
61 t.tag_buf[t.tags_len] = .asterisk;
62 t.start_buf[t.tags_len] = t.source_len - 1;
63 t.tags_len += 1;
64 }
65
6660 t.source_buf[t.source_len] = '\n';
6761 t.source_len += 1;
6862 } else sw: switch (tag) {
lib/std/zig/Zir.zig-16
......@@ -250,9 +250,6 @@ pub const Inst = struct {
250250 /// Array concatenation. `a ++ b`
251251 /// Uses the `pl_node` union field. Payload is `Bin`.
252252 array_cat,
253 /// Array multiplication `a ** b`
254 /// Uses the `pl_node` union field. Payload is `ArrayMul`.
255 array_mul,
256253 /// `[N]T` syntax. No source location provided.
257254 /// Uses the `pl_node` union field. Payload is `Bin`. lhs is length, rhs is element type.
258255 array_type,
......@@ -1102,7 +1099,6 @@ pub const Inst = struct {
11021099 .alloc_inferred_comptime_mut,
11031100 .make_ptr_const,
11041101 .array_cat,
1105 .array_mul,
11061102 .array_type,
11071103 .array_type_sentinel,
11081104 .reify_int,
......@@ -1396,7 +1392,6 @@ pub const Inst = struct {
13961392 .resolve_inferred_alloc,
13971393 .make_ptr_const,
13981394 .array_cat,
1399 .array_mul,
14001395 .array_type,
14011396 .array_type_sentinel,
14021397 .reify_int,
......@@ -1630,7 +1625,6 @@ pub const Inst = struct {
16301625 .param_anytype = .str_tok,
16311626 .param_anytype_comptime = .str_tok,
16321627 .array_cat = .pl_node,
1633 .array_mul = .pl_node,
16341628 .array_type = .pl_node,
16351629 .array_type_sentinel = .pl_node,
16361630 .reify_int = .pl_node,
......@@ -3961,15 +3955,6 @@ pub const Inst = struct {
39613955 expect_len: u32,
39623956 };
39633957
3964 pub const ArrayMul = struct {
3965 /// The result type of the array multiplication operation, or `.none` if none was available.
3966 res_ty: Ref,
3967 /// The LHS of the array multiplication.
3968 lhs: Ref,
3969 /// The RHS of the array multiplication.
3970 rhs: Ref,
3971 };
3972
39733958 pub const RestoreErrRetIndex = struct {
39743959 src_node: Ast.Node.Offset,
39753960 /// If `.none`, restore the trace to its state upon function entry.
......@@ -4121,7 +4106,6 @@ fn findTrackableInner(
41214106 .param_anytype,
41224107 .param_anytype_comptime,
41234108 .array_cat,
4124 .array_mul,
41254109 .array_type,
41264110 .array_type_sentinel,
41274111 .reify_int,
lib/std/zig/ZonGen.zig-1
......@@ -166,7 +166,6 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
166166 .less_than,
167167 .less_or_equal,
168168 .array_cat,
169 .array_mult,
170169 .bool_and,
171170 .bool_or,
172171 .bool_not,
lib/std/zig/llvm/Builder.zig+2-2
......@@ -7628,7 +7628,7 @@ pub const Constant = enum(u32) {
76287628 const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
76297629 string: [
76307630 (std.math.big.int.Const{
7631 .limbs = &@splat(maxInt(std.math.big.Limb)),
7631 .limbs = &@as([expected_limbs]std.math.big.Limb, @splat(maxInt(std.math.big.Limb))),
76327632 .positive = false,
76337633 }).sizeInBaseUpperBound(10)
76347634 ]u8,
......@@ -10595,7 +10595,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
1059510595 const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
1059610596 string: [
1059710597 (std.math.big.int.Const{
10598 .limbs = &@splat(maxInt(std.math.big.Limb)),
10598 .limbs = &@as([expected_limbs]std.math.big.Limb, @splat(maxInt(std.math.big.Limb))),
1059910599 .positive = false,
1060010600 }).sizeInBaseUpperBound(10)
1060110601 ]u8,
lib/std/zig/parser_test.zig+3-30
......@@ -2764,13 +2764,6 @@ test "zig fmt: comments before var decl in struct" {
27642764 );
27652765}
27662766
2767test "zig fmt: array literal with 1 item on 1 line" {
2768 try testCanonical(
2769 \\var s = []const u64{0} ** 25;
2770 \\
2771 );
2772}
2773
27742767test "zig fmt: comments before global variables" {
27752768 try testCanonical(
27762769 \\/// Foo copies keys and values before they go into the map, and
......@@ -2911,7 +2904,7 @@ test "zig fmt: function attributes" {
29112904 );
29122905}
29132906
2914test "zig fmt: nested pointers with ** tokens" {
2907test "zig fmt: deeply nested pointers" {
29152908 try testCanonical(
29162909 \\const x: *u32 = undefined;
29172910 \\const x: **u32 = undefined;
......@@ -3001,7 +2994,6 @@ test "zig fmt: infix operators" {
30012994 \\ _ = i.i;
30022995 \\ _ = i || i;
30032996 \\ _ = i!i;
3004 \\ _ = i ** i;
30052997 \\ _ = i ++ i;
30062998 \\ _ = i orelse i;
30072999 \\ _ = i % i;
......@@ -4565,7 +4557,7 @@ test "zig fmt: integer literals with underscore separators" {
45654557test "zig fmt: hex literals with underscore separators" {
45664558 try testTransform(
45674559 \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 {
4568 \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000;
4560 \\ var c: [1_000]u64 = @splat(0xFFFF_FFFF_FFFF_FFFF);
45694561 \\ for (c [ 1_0 .. ], 0..) |_, i| {
45704562 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
45714563 \\ }
......@@ -4575,7 +4567,7 @@ test "zig fmt: hex literals with underscore separators" {
45754567 \\
45764568 ,
45774569 \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 {
4578 \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000;
4570 \\ var c: [1_000]u64 = @splat(0xFFFF_FFFF_FFFF_FFFF);
45794571 \\ for (c[1_0..], 0..) |_, i| {
45804572 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
45814573 \\ }
......@@ -7083,25 +7075,6 @@ test "recovery: invalid global error set access" {
70837075 });
70847076}
70857077
7086test "recovery: invalid asterisk after pointer dereference" {
7087 try testError(
7088 \\test "" {
7089 \\ var sequence = "repeat".*** 10;
7090 \\}
7091 , &[_]Error{
7092 .asterisk_after_ptr_deref,
7093 .mismatched_binary_op_whitespace,
7094 });
7095 try testError(
7096 \\test "" {
7097 \\ var sequence = "repeat".** 10&a;
7098 \\}
7099 , &[_]Error{
7100 .asterisk_after_ptr_deref,
7101 .mismatched_binary_op_whitespace,
7102 });
7103}
7104
71057078test "recovery: missing semicolon after if, for, while stmt" {
71067079 try testError(
71077080 \\test "" {
lib/std/zig/tokenizer.zig+4-43
......@@ -64,7 +64,6 @@ pub const Token = struct {
6464
6565 pub const Tag = enum {
6666 invalid,
67 invalid_periodasterisks,
6867 identifier,
6968 string_literal,
7069 multiline_string_literal_line,
......@@ -109,7 +108,6 @@ pub const Token = struct {
109108 minus_pipe_equal,
110109 asterisk,
111110 asterisk_equal,
112 asterisk_asterisk,
113111 asterisk_percent,
114112 asterisk_percent_equal,
115113 asterisk_pipe,
......@@ -197,7 +195,6 @@ pub const Token = struct {
197195 .container_doc_comment,
198196 => null,
199197
200 .invalid_periodasterisks => ".**",
201198 .bang => "!",
202199 .pipe => "|",
203200 .pipe_pipe => "||",
......@@ -236,7 +233,6 @@ pub const Token = struct {
236233 .minus_pipe_equal => "-|=",
237234 .asterisk => "*",
238235 .asterisk_equal => "*=",
239 .asterisk_asterisk => "**",
240236 .asterisk_percent => "*%",
241237 .asterisk_percent_equal => "*%=",
242238 .asterisk_pipe => "*|",
......@@ -386,7 +382,6 @@ pub const Tokenizer = struct {
386382 angle_bracket_angle_bracket_right,
387383 period,
388384 period_2,
389 period_asterisk,
390385 saw_at_sign,
391386 invalid,
392387 };
......@@ -569,10 +564,6 @@ pub const Tokenizer = struct {
569564 result.tag = .asterisk_equal;
570565 self.index += 1;
571566 },
572 '*' => {
573 result.tag = .asterisk_asterisk;
574 self.index += 1;
575 },
576567 '%' => continue :state .asterisk_percent,
577568 '|' => continue :state .asterisk_pipe,
578569 else => result.tag = .asterisk,
......@@ -915,7 +906,10 @@ pub const Tokenizer = struct {
915906 self.index += 1;
916907 switch (self.buffer[self.index]) {
917908 '.' => continue :state .period_2,
918 '*' => continue :state .period_asterisk,
909 '*' => {
910 result.tag = .period_asterisk;
911 self.index += 1;
912 },
919913 else => result.tag = .period,
920914 }
921915 },
......@@ -931,14 +925,6 @@ pub const Tokenizer = struct {
931925 }
932926 },
933927
934 .period_asterisk => {
935 self.index += 1;
936 switch (self.buffer[self.index]) {
937 '*' => result.tag = .invalid_periodasterisks,
938 else => result.tag = .period_asterisk,
939 }
940 },
941
942928 .slash => {
943929 self.index += 1;
944930 switch (self.buffer[self.index]) {
......@@ -1343,31 +1329,6 @@ test "correctly parse pointer assignment" {
13431329 });
13441330}
13451331
1346test "correctly parse pointer dereference followed by asterisk" {
1347 try testTokenize("\"b\".* ** 10", &.{
1348 .string_literal,
1349 .period_asterisk,
1350 .asterisk_asterisk,
1351 .number_literal,
1352 });
1353
1354 try testTokenize("(\"b\".*)** 10", &.{
1355 .l_paren,
1356 .string_literal,
1357 .period_asterisk,
1358 .r_paren,
1359 .asterisk_asterisk,
1360 .number_literal,
1361 });
1362
1363 try testTokenize("\"b\".*** 10", &.{
1364 .string_literal,
1365 .invalid_periodasterisks,
1366 .asterisk_asterisk,
1367 .number_literal,
1368 });
1369}
1370
13711332test "range literals" {
13721333 try testTokenize("0...9", &.{ .number_literal, .ellipsis3, .number_literal });
13731334 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });
src/Sema.zig-169
......@@ -1171,7 +1171,6 @@ fn analyzeBodyInner(
11711171 .make_ptr_const => try sema.zirMakePtrConst(block, inst),
11721172 .anyframe_type => try sema.zirAnyframeType(block, inst),
11731173 .array_cat => try sema.zirArrayCat(block, inst),
1174 .array_mul => try sema.zirArrayMul(block, inst),
11751174 .array_type => try sema.zirArrayType(block, inst),
11761175 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
11771176 .reify_int => try sema.zirReifyInt(block, inst),
......@@ -13861,174 +13860,6 @@ fn analyzeTupleMul(
1386113860 return block.addAggregateInit(tuple_ty, element_refs);
1386213861}
1386313862
13864fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
13865 const tracy = trace(@src());
13866 defer tracy.end();
13867
13868 const pt = sema.pt;
13869 const zcu = pt.zcu;
13870 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
13871 const extra = sema.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
13872 const uncoerced_lhs = sema.resolveInst(extra.lhs);
13873 const uncoerced_lhs_ty = sema.typeOf(uncoerced_lhs);
13874 const src: LazySrcLoc = block.nodeOffset(inst_data.src_node);
13875 const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
13876 const operator_src = block.src(.{ .node_offset_main_token = inst_data.src_node });
13877 const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
13878
13879 const lhs, const lhs_ty = coerced_lhs: {
13880 // If we have a result type, we might be able to do this more efficiently
13881 // by coercing the LHS first. Specifically, if we want an array or vector
13882 // and have a tuple, coerce the tuple immediately.
13883 no_coerce: {
13884 if (extra.res_ty == .none) break :no_coerce;
13885 const res_ty = try sema.resolveTypeOrPoison(block, src, extra.res_ty) orelse break :no_coerce;
13886 if (!uncoerced_lhs_ty.isTuple(zcu)) break :no_coerce;
13887 const lhs_len = uncoerced_lhs_ty.structFieldCount(zcu);
13888 const lhs_dest_ty = switch (res_ty.zigTypeTag(zcu)) {
13889 else => break :no_coerce,
13890 .array => try pt.arrayType(.{
13891 .child = res_ty.childType(zcu).toIntern(),
13892 .len = lhs_len,
13893 .sentinel = if (res_ty.sentinel(zcu)) |s| s.toIntern() else .none,
13894 }),
13895 .vector => try pt.vectorType(.{
13896 .child = res_ty.childType(zcu).toIntern(),
13897 .len = lhs_len,
13898 }),
13899 };
13900 // Attempt to coerce to this type, but don't emit an error if it fails. Instead,
13901 // just exit out of this path and let the usual error happen later, so that error
13902 // messages are consistent.
13903 const coerced = sema.coerceExtra(block, lhs_dest_ty, uncoerced_lhs, lhs_src, .{ .report_err = false }) catch |err| switch (err) {
13904 error.NotCoercible => break :no_coerce,
13905 else => |e| return e,
13906 };
13907 break :coerced_lhs .{ coerced, lhs_dest_ty };
13908 }
13909 break :coerced_lhs .{ uncoerced_lhs, uncoerced_lhs_ty };
13910 };
13911
13912 if (lhs_ty.isTuple(zcu)) {
13913 // In `**` rhs must be comptime-known, but lhs can be runtime-known
13914 const factor = try sema.resolveInt(block, rhs_src, extra.rhs, .usize, .{ .simple = .array_mul_factor });
13915 const factor_casted = try sema.usizeCast(block, rhs_src, factor);
13916 return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted);
13917 }
13918
13919 // Analyze the lhs first, to catch the case that someone tried to do exponentiation
13920 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse {
13921 const msg = msg: {
13922 const msg = try sema.errMsg(lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)});
13923 errdefer msg.destroy(sema.gpa);
13924 switch (lhs_ty.zigTypeTag(zcu)) {
13925 .int, .float, .comptime_float, .comptime_int, .vector => {
13926 try sema.errNote(operator_src, msg, "this operator multiplies arrays; use std.math.pow for exponentiation", .{});
13927 },
13928 else => {},
13929 }
13930 break :msg msg;
13931 };
13932 return sema.failWithOwnedErrorMsg(block, msg);
13933 };
13934
13935 // In `**` rhs must be comptime-known, but lhs can be runtime-known
13936 const factor = try sema.resolveInt(block, rhs_src, extra.rhs, .usize, .{ .simple = .array_mul_factor });
13937
13938 const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch
13939 return sema.fail(block, rhs_src, "operation results in overflow", .{});
13940 const result_len = try sema.usizeCast(block, src, result_len_u64);
13941
13942 const result_ty = try pt.arrayType(.{
13943 .len = result_len,
13944 .sentinel = if (lhs_info.sentinel) |s| s.toIntern() else .none,
13945 .child = lhs_info.elem_type.toIntern(),
13946 });
13947
13948 const ptr_addrspace = if (lhs_ty.zigTypeTag(zcu) == .pointer) lhs_ty.ptrAddressSpace(zcu) else null;
13949 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
13950
13951 if (sema.resolveValue(lhs)) |lhs_val| ct: {
13952 const lhs_sub_val = if (lhs_ty.isSinglePointer(zcu))
13953 try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :ct
13954 else if (lhs_ty.isSlice(zcu))
13955 try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :ct
13956 else
13957 lhs_val;
13958
13959 const val = v: {
13960 // Optimization for the common pattern of a single element repeated N times, such
13961 // as zero-filling a byte array.
13962 if (lhs_len == 1 and lhs_info.sentinel == null) {
13963 const elem_val = try lhs_sub_val.elemValue(pt, 0);
13964 break :v try pt.aggregateSplatValue(result_ty, elem_val);
13965 }
13966
13967 const element_vals = try sema.arena.alloc(InternPool.Index, result_len);
13968 var elem_i: usize = 0;
13969 while (elem_i < result_len) {
13970 var lhs_i: usize = 0;
13971 while (lhs_i < lhs_len) : (lhs_i += 1) {
13972 const elem_val = try lhs_sub_val.elemValue(pt, lhs_i);
13973 element_vals[elem_i] = elem_val.toIntern();
13974 elem_i += 1;
13975 }
13976 }
13977 break :v try pt.aggregateValue(result_ty, element_vals);
13978 };
13979 return sema.addConstantMaybeRef(val, ptr_addrspace != null);
13980 }
13981
13982 try sema.requireRuntimeBlock(block, src, lhs_src);
13983
13984 // Grab all the LHS values ahead of time, rather than repeatedly emitting instructions
13985 // to get the same elem values.
13986 const lhs_vals = try sema.arena.alloc(Air.Inst.Ref, lhs_len);
13987 for (lhs_vals, 0..) |*lhs_val, idx| {
13988 const idx_ref = try pt.intRef(.usize, idx);
13989 lhs_val.* = try sema.elemVal(block, lhs_src, lhs, idx_ref, src, false);
13990 }
13991
13992 if (ptr_addrspace) |ptr_as| {
13993 const alloc_ty = try pt.ptrType(.{
13994 .child = result_ty.toIntern(),
13995 .flags = .{
13996 .address_space = ptr_as,
13997 .is_const = true,
13998 },
13999 });
14000 const alloc = try block.addTy(.alloc, alloc_ty);
14001 const elem_ptr_ty = try pt.ptrType(.{
14002 .child = lhs_info.elem_type.toIntern(),
14003 .flags = .{ .address_space = ptr_as },
14004 });
14005
14006 var elem_i: usize = 0;
14007 while (elem_i < result_len) {
14008 for (lhs_vals) |lhs_val| {
14009 const elem_index = try pt.intRef(.usize, elem_i);
14010 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
14011 try sema.storePtr2(block, src, elem_ptr, src, lhs_val, lhs_src, .store);
14012 elem_i += 1;
14013 }
14014 }
14015 if (lhs_info.sentinel) |sent_val| {
14016 const elem_index = try pt.intRef(.usize, result_len);
14017 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
14018 const init = Air.internedToRef(sent_val.toIntern());
14019 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
14020 }
14021
14022 return alloc;
14023 }
14024
14025 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
14026 for (0..try sema.usizeCast(block, rhs_src, factor)) |i| {
14027 @memcpy(element_refs[i * lhs_len ..][0..lhs_len], lhs_vals);
14028 }
14029 return block.addAggregateInit(result_ty, element_refs);
14030}
14031
1403213863fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1403313864 const pt = sema.pt;
1403413865 const zcu = pt.zcu;
src/print_zir.zig-14
......@@ -416,8 +416,6 @@ const Writer = struct {
416416
417417 .for_len => try self.writePlNodeMultiOp(stream, inst),
418418
419 .array_mul => try self.writeArrayMul(stream, inst),
420
421419 .elem_val_imm => try self.writeElemValImm(stream, inst),
422420
423421 .@"export" => try self.writePlNodeExport(stream, inst),
......@@ -1046,18 +1044,6 @@ const Writer = struct {
10461044 try self.writeSrcNode(stream, inst_data.src_node);
10471045 }
10481046
1049 fn writeArrayMul(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
1050 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
1051 const extra = self.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
1052 try self.writeInstRef(stream, extra.res_ty);
1053 try stream.writeAll(", ");
1054 try self.writeInstRef(stream, extra.lhs);
1055 try stream.writeAll(", ");
1056 try self.writeInstRef(stream, extra.rhs);
1057 try stream.writeAll(") ");
1058 try self.writeSrcNode(stream, inst_data.src_node);
1059 }
1060
10611047 fn writeElemValImm(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
10621048 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm;
10631049 try self.writeInstRef(stream, inst_data.operand);
tools/docgen.zig+1-2
......@@ -871,7 +871,6 @@ fn tokenizeAndPrintRaw(
871871 .minus_pipe_equal,
872872 .asterisk,
873873 .asterisk_equal,
874 .asterisk_asterisk,
875874 .asterisk_percent,
876875 .asterisk_percent_equal,
877876 .asterisk_pipe,
......@@ -897,7 +896,7 @@ fn tokenizeAndPrintRaw(
897896 .tilde,
898897 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
899898
900 .invalid, .invalid_periodasterisks => return parseError(
899 .invalid => return parseError(
901900 docgen_tokenizer,
902901 source_token,
903902 "syntax error",
tools/doctest.zig+1-2
......@@ -800,7 +800,6 @@ fn tokenizeAndPrint(arena: Allocator, out: *Writer, raw_src: []const u8) !void {
800800 .minus_pipe_equal,
801801 .asterisk,
802802 .asterisk_equal,
803 .asterisk_asterisk,
804803 .asterisk_percent,
805804 .asterisk_percent_equal,
806805 .asterisk_pipe,
......@@ -826,7 +825,7 @@ fn tokenizeAndPrint(arena: Allocator, out: *Writer, raw_src: []const u8) !void {
826825 .tilde,
827826 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
828827
829 .invalid, .invalid_periodasterisks => fatal("syntax error", .{}),
828 .invalid => fatal("syntax error", .{}),
830829 }
831830 index = token.loc.end;
832831 }