commit 72d954e7d3cfb8b46a26d5a199a9a5ecd36d87be (tree)
parent fdac89d6cd65fa19bd5c6d381b62d980d97e5852
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date: Wed, 29 Apr 2026 19:58:39 +0100
compiler: remove array multiplication from the language
Resolves: https://github.com/ziglang/zig/issues/24738
Diffstat:
21 files changed, 20 insertions(+), 421 deletions(-)
diff --git a/lib/compiler/reduce/Walk.zig b/lib/compiler/reduce/Walk.zig
@@ -248,7 +248,6 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
.add_wrap,
.add_sat,
.array_cat,
- .array_mult,
.assign,
.assign_bit_and,
.assign_bit_or,
diff --git a/lib/docs/wasm/Walk.zig b/lib/docs/wasm/Walk.zig
@@ -709,7 +709,6 @@ fn expr(w: *Walk, scope: *Scope, parent_decl: Decl.Index, node: Ast.Node.Index)
.less_or_equal,
.array_cat,
- .array_mult,
.error_union,
.merge_error_sets,
.bool_and,
diff --git a/lib/docs/wasm/html_render.zig b/lib/docs/wasm/html_render.zig
@@ -302,7 +302,6 @@ pub fn fileSourceHtml(
.minus_pipe_equal,
.asterisk,
.asterisk_equal,
- .asterisk_asterisk,
.asterisk_percent,
.asterisk_percent_equal,
.asterisk_pipe,
@@ -328,7 +327,7 @@ pub fn fileSourceHtml(
.tilde,
=> try appendEscaped(out, slice),
- .invalid, .invalid_periodasterisks => return error.InvalidToken,
+ .invalid => return error.InvalidToken,
}
}
}
diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig
@@ -1092,7 +1092,7 @@ pub const rsa = struct {
}
var m_p_buf: [8 + Hash.digest_length + Hash.digest_length]u8 = undefined;
var m_p = m_p_buf[0 .. 8 + Hash.digest_length + sLen];
- std.mem.copyForwards(u8, m_p, @as(*const [8]u8, @splat(0)));
+ std.mem.copyForwards(u8, m_p, @as(*const [8]u8, &@splat(0)));
std.mem.copyForwards(u8, m_p[8..], &mHash);
std.mem.copyForwards(u8, m_p[(8 + Hash.digest_length)..], salt);
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
@@ -811,7 +811,6 @@ pub const SimpleComptimeReason = enum(u32) {
compile_error_string,
inline_assembly_code,
atomic_order,
- array_mul_factor,
slice_cat_operand,
inline_call_target,
generic_call_target,
@@ -899,7 +898,6 @@ pub const SimpleComptimeReason = enum(u32) {
.compile_error_string => "compile error string must be comptime-known",
.inline_assembly_code => "inline assembly code must be comptime-known",
.atomic_order => "atomic order must be comptime-known",
- .array_mul_factor => "array multiplication factor must be comptime-known",
.slice_cat_operand => "slice being concatenated must be comptime-known",
.inline_call_target => "function being called inline must be comptime-known",
.generic_call_target => "generic function being called must be comptime-known",
diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig
@@ -331,11 +331,6 @@ pub fn rootDecls(tree: Ast) []const Node.Index {
pub fn renderError(tree: Ast, parse_error: Error, w: *Writer) Writer.Error!void {
switch (parse_error.tag) {
- .asterisk_after_ptr_deref => {
- // Note that the token will point at the `.*` but ideally the source
- // location would point to the `*` after the `.*`.
- return w.writeAll("'.*' cannot be followed by '*'; are you missing a space?");
- },
.chained_comparison_operators => {
return w.writeAll("comparison operators cannot be chained");
},
@@ -687,7 +682,6 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {
.mul,
.div,
.mod,
- .array_mult,
.mul_wrap,
.mul_sat,
.add,
@@ -924,7 +918,6 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {
.mul,
.div,
.mod,
- .array_mult,
.mul_wrap,
.mul_sat,
.add,
@@ -2111,9 +2104,7 @@ fn fullFnProtoComponents(tree: Ast, info: full.FnProto.Components) full.FnProto
fn fullPtrTypeComponents(tree: Ast, info: full.PtrType.Components) full.PtrType {
const size: std.builtin.Type.Pointer.Size = switch (tree.tokenTag(info.main_token)) {
- .asterisk,
- .asterisk_asterisk,
- => .one,
+ .asterisk => .one,
.l_bracket => switch (tree.tokenTag(info.main_token + 1)) {
.asterisk => if (tree.tokenTag(info.main_token + 2) == .identifier) .c else .many,
else => .slice,
@@ -2842,7 +2833,6 @@ pub const Error = struct {
} = .{ .none = {} },
pub const Tag = enum {
- asterisk_after_ptr_deref,
chained_comparison_operators,
decl_between_fields,
expected_block,
@@ -3178,8 +3168,6 @@ pub const Node = struct {
div,
/// `lhs % rhs`. The `main_token` field is the `%` token.
mod,
- /// `lhs ** rhs`. The `main_token` field is the `**` token.
- array_mult,
/// `lhs *% rhs`. The `main_token` field is the `*%` token.
mul_wrap,
/// `lhs *| rhs`. The `main_token` field is the `*|` token.
@@ -3250,8 +3238,6 @@ pub const Node = struct {
///
/// The `main_token` is the asterisk if a single item pointer or the
/// lbracket if a slice, many-item pointer, or C-pointer.
- /// The `main_token` might be a ** token, which is shared with a
- /// parent/child pointer type and may require special handling.
ptr_type_aligned,
/// `[*:lhs]rhs`,
/// `*rhs`,
@@ -3263,8 +3249,6 @@ pub const Node = struct {
///
/// The `main_token` is the asterisk if a single item pointer or the
/// lbracket if a slice, many-item pointer, or C-pointer.
- /// The `main_token` might be a ** token, which is shared with a
- /// parent/child pointer type and may require special handling.
ptr_type_sentinel,
/// The `data` field is a `.extra_and_node`:
/// 1. a `ExtraIndex` to `PtrType`.
@@ -3272,8 +3256,6 @@ pub const Node = struct {
///
/// The `main_token` is the asterisk if a single item pointer or the
/// lbracket if a slice, many-item pointer, or C-pointer.
- /// The `main_token` might be a ** token, which is shared with a
- /// parent/child pointer type and may require special handling.
ptr_type,
/// The `data` field is a `.extra_and_node`:
/// 1. a `ExtraIndex` to `PtrTypeBitRange`.
@@ -3281,8 +3263,6 @@ pub const Node = struct {
///
/// The `main_token` is the asterisk if a single item pointer or the
/// lbracket if a slice, many-item pointer, or C-pointer.
- /// The `main_token` might be a ** token, which is shared with a
- /// parent/child pointer type and may require special handling.
ptr_type_bit_range,
/// `lhs[rhs..]`
///
diff --git a/lib/std/zig/Ast/Render.zig b/lib/std/zig/Ast/Render.zig
@@ -508,7 +508,6 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
.add_wrap,
.add_sat,
.array_cat,
- .array_mult,
.bang_equal,
.bit_and,
.bit_or,
@@ -1028,16 +1027,6 @@ fn renderPtrType(r: *Render, ptr_type: Ast.full.PtrType, space: Space) Error!voi
switch (ptr_type.size) {
.one => {
- // Since ** tokens exist and the same token is shared by two
- // nested pointer types, we check to see if we are the parent
- // in such a relationship. If so, skip rendering anything for
- // this pointer type and rely on the child to render our asterisk
- // as well when it renders the ** token.
- if (tree.tokenTag(main_token) == .asterisk_asterisk and
- main_token == tree.nodeMainToken(ptr_type.ast.child_type))
- {
- return renderExpression(r, ptr_type.ast.child_type, space);
- }
try renderToken(r, main_token, .none); // asterisk
},
.many => {
@@ -3223,7 +3212,6 @@ fn nodeCausesSliceOpSpace(tag: Ast.Node.Tag) bool {
.add,
.add_wrap,
.array_cat,
- .array_mult,
.assign,
.assign_bit_and,
.assign_bit_or,
diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig
@@ -507,7 +507,6 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
.less_than,
.less_or_equal,
.array_cat,
- .array_mult,
.bool_and,
.bool_or,
.@"asm",
@@ -777,19 +776,6 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
.less_or_equal => return simpleBinOp(gz, scope, ri, node, .cmp_lte),
.array_cat => return simpleBinOp(gz, scope, ri, node, .array_cat),
- .array_mult => {
- // This syntax form does not currently use the result type in the language specification.
- // However, the result type can be used to emit more optimal code for large multiplications by
- // having Sema perform a coercion before the multiplication operation.
- const lhs_node, const rhs_node = tree.nodeData(node).node_and_node;
- const result = try gz.addPlNode(.array_mul, node, Zir.Inst.ArrayMul{
- .res_ty = if (try ri.rl.resultType(gz, node)) |t| t else .none,
- .lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node),
- .rhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, rhs_node, .array_mul_factor),
- });
- return rvalue(gz, ri, result, node);
- },
-
.error_union, .merge_error_sets => |tag| {
const inst_tag: Zir.Inst.Tag = switch (tag) {
.error_union => .error_union_type,
@@ -2713,7 +2699,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.alloc_inferred_comptime_mut,
.make_ptr_const,
.array_cat,
- .array_mul,
.array_type,
.array_type_sentinel,
.elem_type,
@@ -10307,7 +10292,6 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
.add_wrap,
.add_sat,
.array_cat,
- .array_mult,
.assign,
.assign_destructure,
.assign_bit_and,
diff --git a/lib/std/zig/AstRlAnnotate.zig b/lib/std/zig/AstRlAnnotate.zig
@@ -269,12 +269,6 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
return false;
},
- .array_mult => {
- const lhs, const rhs = tree.nodeData(node).node_and_node;
- _ = try astrl.expr(lhs, block, ResultInfo.none);
- _ = try astrl.expr(rhs, block, ResultInfo.type_only);
- return false;
- },
.error_union, .merge_error_sets => {
const lhs, const rhs = tree.nodeData(node).node_and_node;
_ = try astrl.expr(lhs, block, ResultInfo.none);
diff --git a/lib/std/zig/AstSmith.zig b/lib/std/zig/AstSmith.zig
@@ -18,7 +18,6 @@ token_tag_buf: [2048]Token.Tag,
token_start_buf: [2048]std.zig.Ast.ByteOffset,
tokens_len: usize,
-/// For `.asterisk`, this also includes `.asterisk2`
not_token: ?Token.Tag,
not_token_comptime: bool,
/// ExprSuffix
@@ -196,7 +195,6 @@ fn preservePegEndOfWord(a: *AstSmith) SourceError!void {
/// Assumes the token has not been written yet
fn addTokenTag(a: *AstSmith, tag: Token.Tag) SourceError!void {
assert(tag != a.not_token);
- if (a.not_token == .asterisk) assert(tag != .asterisk_asterisk);
a.not_token = null;
if (a.not_token_comptime) assert(tag != .keyword_comptime);
@@ -240,9 +238,7 @@ fn pegToken(a: *AstSmith, tag: Token.Tag) SourceError!void {
switch (lexeme[0]) {
'_', 'a'...'z', 'A'...'Z', '0'...'9' => try a.preservePegEndOfWord(),
- '*' => if (a.tokens_len > 0 and a.source_buf[a.source_len - 1] == '*' and
- a.token_tag_buf[a.tokens_len - 1] != .asterisk_asterisk)
- {
+ '*' => if (a.tokens_len > 0 and a.source_buf[a.source_len - 1] == '*') {
try a.addSourceByte(' ');
},
'.' => if (a.tokens_len > 0 and switch (a.source_buf[a.source_len - 1]) {
@@ -1723,13 +1719,11 @@ fn pegAdditionOp(a: *AstSmith) SourceError!void {
/// / ASTERISK
/// / SLASH
/// / PERCENT
-/// / ASTERISK2
/// / ASTERISKPERCENT
/// / ASTERISKPIPE
fn pegMultiplyOp(a: *AstSmith) SourceError!void {
const tags = [_]Token.Tag{
.asterisk,
- .asterisk_asterisk,
.pipe_pipe,
.slash,
.percent,
@@ -1865,9 +1859,9 @@ fn pegSliceTypeStart(a: *AstSmith) SourceError!void {
try a.pegToken(.r_bracket);
}
-/// SinglePtrTypeStart <- ASTERISK / ASTERISK2
+/// SinglePtrTypeStart <- ASTERISK
fn pegSinglePtrTypeStart(a: *AstSmith) SourceError!void {
- try a.pegToken(if (!a.smith.value(bool)) .asterisk else .asterisk_asterisk);
+ try a.pegToken(.asterisk);
}
/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
@@ -1889,7 +1883,7 @@ fn pegManyPtrTypeStart(a: *AstSmith) SourceError!void {
try a.pegToken(.r_bracket);
}
-/// ArrayTypeStart <- LBRACKET !(ASTERISK / ASTERISK2) Expr (COLON Expr)? RBRACKET
+/// ArrayTypeStart <- LBRACKET !ASTERISK Expr (COLON Expr)? RBRACKET
fn pegArrayTypeStart(a: *AstSmith) SourceError!void {
try a.pegToken(.l_bracket);
a.not_token = .asterisk;
diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig
@@ -1609,7 +1609,6 @@ const operTable = std.enums.directEnumArrayDefault(Token.Tag, OperInfo, .{ .prec
.asterisk = .{ .prec = 70, .tag = .mul },
.slash = .{ .prec = 70, .tag = .div },
.percent = .{ .prec = 70, .tag = .mod },
- .asterisk_asterisk = .{ .prec = 70, .tag = .array_mult },
.asterisk_percent = .{ .prec = 70, .tag = .mul_wrap },
.asterisk_pipe = .{ .prec = 70, .tag = .mul_sat },
});
@@ -1709,11 +1708,11 @@ fn expectPrefixExpr(p: *Parse) Error!Node.Index {
///
/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
///
-/// SinglePtrTypeStart <- ASTERISK / ASTERISK2
+/// SinglePtrTypeStart <- ASTERISK
///
/// ManyPtrTypeStart <- LBRACKET ASTERISK (LETTERC / COLON Expr)? RBRACKET
///
-/// ArrayTypeStart <- LBRACKET Expr !(ASTERISK / ASTERISK2) (COLON Expr)? RBRACKET
+/// ArrayTypeStart <- LBRACKET Expr !ASTERISK (COLON Expr)? RBRACKET
///
/// BitAlign <- KEYWORD_align LPAREN Expr (COLON Expr COLON Expr)? RPAREN
fn parseTypeExpr(p: *Parse) Error!?Node.Index {
@@ -1777,59 +1776,6 @@ fn parseTypeExpr(p: *Parse) Error!?Node.Index {
});
}
},
- .asterisk_asterisk => {
- const asterisk = p.nextToken();
- const mods = try p.parsePtrModifiers();
- const elem_type = try p.expectTypeExpr();
- const inner: Node.Index = inner: {
- if (mods.bit_range_start != .none) {
- break :inner try p.addNode(.{
- .tag = .ptr_type_bit_range,
- .main_token = asterisk,
- .data = .{ .extra_and_node = .{
- try p.addExtra(Node.PtrTypeBitRange{
- .sentinel = .none,
- .align_node = mods.align_node.unwrap().?,
- .addrspace_node = mods.addrspace_node,
- .bit_range_start = mods.bit_range_start.unwrap().?,
- .bit_range_end = mods.bit_range_end.unwrap().?,
- }),
- elem_type,
- } },
- });
- } else if (mods.addrspace_node != .none) {
- break :inner try p.addNode(.{
- .tag = .ptr_type,
- .main_token = asterisk,
- .data = .{ .extra_and_node = .{
- try p.addExtra(Node.PtrType{
- .sentinel = .none,
- .align_node = mods.align_node,
- .addrspace_node = mods.addrspace_node,
- }),
- elem_type,
- } },
- });
- } else {
- break :inner try p.addNode(.{
- .tag = .ptr_type_aligned,
- .main_token = asterisk,
- .data = .{ .opt_node_and_node = .{
- mods.align_node,
- elem_type,
- } },
- });
- }
- };
- return try p.addNode(.{
- .tag = .ptr_type_aligned,
- .main_token = asterisk,
- .data = .{ .opt_node_and_node = .{
- .none,
- inner,
- } },
- });
- },
.l_bracket => switch (p.tokenTag(p.tok_i + 1)) {
.asterisk => {
const l_bracket = p.nextToken();
@@ -3257,14 +3203,6 @@ fn parseSuffixOp(p: *Parse, lhs: Node.Index) !?Node.Index {
.main_token = p.nextToken(),
.data = .{ .node = lhs },
}),
- .invalid_periodasterisks => {
- try p.warn(.asterisk_after_ptr_deref);
- return try p.addNode(.{
- .tag = .deref,
- .main_token = p.nextToken(),
- .data = .{ .node = lhs },
- });
- },
.period => switch (p.tokenTag(p.tok_i + 1)) {
.identifier => return try p.addNode(.{
.tag = .field_access,
diff --git a/lib/std/zig/TokenSmith.zig b/lib/std/zig/TokenSmith.zig
@@ -57,12 +57,6 @@ pub fn gen(smith: *Smith) TokenSmith {
@memcpy(t.source_buf[t.source_len..][0..lexeme.len], lexeme);
t.source_len += @intCast(lexeme.len);
- if (tag == .invalid_periodasterisks) {
- t.tag_buf[t.tags_len] = .asterisk;
- t.start_buf[t.tags_len] = t.source_len - 1;
- t.tags_len += 1;
- }
-
t.source_buf[t.source_len] = '\n';
t.source_len += 1;
} else sw: switch (tag) {
diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig
@@ -250,9 +250,6 @@ pub const Inst = struct {
/// Array concatenation. `a ++ b`
/// Uses the `pl_node` union field. Payload is `Bin`.
array_cat,
- /// Array multiplication `a ** b`
- /// Uses the `pl_node` union field. Payload is `ArrayMul`.
- array_mul,
/// `[N]T` syntax. No source location provided.
/// Uses the `pl_node` union field. Payload is `Bin`. lhs is length, rhs is element type.
array_type,
@@ -1102,7 +1099,6 @@ pub const Inst = struct {
.alloc_inferred_comptime_mut,
.make_ptr_const,
.array_cat,
- .array_mul,
.array_type,
.array_type_sentinel,
.reify_int,
@@ -1396,7 +1392,6 @@ pub const Inst = struct {
.resolve_inferred_alloc,
.make_ptr_const,
.array_cat,
- .array_mul,
.array_type,
.array_type_sentinel,
.reify_int,
@@ -1630,7 +1625,6 @@ pub const Inst = struct {
.param_anytype = .str_tok,
.param_anytype_comptime = .str_tok,
.array_cat = .pl_node,
- .array_mul = .pl_node,
.array_type = .pl_node,
.array_type_sentinel = .pl_node,
.reify_int = .pl_node,
@@ -3961,15 +3955,6 @@ pub const Inst = struct {
expect_len: u32,
};
- pub const ArrayMul = struct {
- /// The result type of the array multiplication operation, or `.none` if none was available.
- res_ty: Ref,
- /// The LHS of the array multiplication.
- lhs: Ref,
- /// The RHS of the array multiplication.
- rhs: Ref,
- };
-
pub const RestoreErrRetIndex = struct {
src_node: Ast.Node.Offset,
/// If `.none`, restore the trace to its state upon function entry.
@@ -4121,7 +4106,6 @@ fn findTrackableInner(
.param_anytype,
.param_anytype_comptime,
.array_cat,
- .array_mul,
.array_type,
.array_type_sentinel,
.reify_int,
diff --git a/lib/std/zig/ZonGen.zig b/lib/std/zig/ZonGen.zig
@@ -166,7 +166,6 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
.less_than,
.less_or_equal,
.array_cat,
- .array_mult,
.bool_and,
.bool_or,
.bool_not,
diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig
@@ -7628,7 +7628,7 @@ pub const Constant = enum(u32) {
const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
string: [
(std.math.big.int.Const{
- .limbs = &@splat(maxInt(std.math.big.Limb)),
+ .limbs = &@as([expected_limbs]std.math.big.Limb, @splat(maxInt(std.math.big.Limb))),
.positive = false,
}).sizeInBaseUpperBound(10)
]u8,
@@ -10595,7 +10595,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
string: [
(std.math.big.int.Const{
- .limbs = &@splat(maxInt(std.math.big.Limb)),
+ .limbs = &@as([expected_limbs]std.math.big.Limb, @splat(maxInt(std.math.big.Limb))),
.positive = false,
}).sizeInBaseUpperBound(10)
]u8,
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
@@ -2764,13 +2764,6 @@ test "zig fmt: comments before var decl in struct" {
);
}
-test "zig fmt: array literal with 1 item on 1 line" {
- try testCanonical(
- \\var s = []const u64{0} ** 25;
- \\
- );
-}
-
test "zig fmt: comments before global variables" {
try testCanonical(
\\/// Foo copies keys and values before they go into the map, and
@@ -2911,7 +2904,7 @@ test "zig fmt: function attributes" {
);
}
-test "zig fmt: nested pointers with ** tokens" {
+test "zig fmt: deeply nested pointers" {
try testCanonical(
\\const x: *u32 = undefined;
\\const x: **u32 = undefined;
@@ -3001,7 +2994,6 @@ test "zig fmt: infix operators" {
\\ _ = i.i;
\\ _ = i || i;
\\ _ = i!i;
- \\ _ = i ** i;
\\ _ = i ++ i;
\\ _ = i orelse i;
\\ _ = i % i;
@@ -4565,7 +4557,7 @@ test "zig fmt: integer literals with underscore separators" {
test "zig fmt: hex literals with underscore separators" {
try testTransform(
\\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 {
- \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000;
+ \\ var c: [1_000]u64 = @splat(0xFFFF_FFFF_FFFF_FFFF);
\\ for (c [ 1_0 .. ], 0..) |_, i| {
\\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
\\ }
@@ -4575,7 +4567,7 @@ test "zig fmt: hex literals with underscore separators" {
\\
,
\\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 {
- \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000;
+ \\ var c: [1_000]u64 = @splat(0xFFFF_FFFF_FFFF_FFFF);
\\ for (c[1_0..], 0..) |_, i| {
\\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
\\ }
@@ -7083,25 +7075,6 @@ test "recovery: invalid global error set access" {
});
}
-test "recovery: invalid asterisk after pointer dereference" {
- try testError(
- \\test "" {
- \\ var sequence = "repeat".*** 10;
- \\}
- , &[_]Error{
- .asterisk_after_ptr_deref,
- .mismatched_binary_op_whitespace,
- });
- try testError(
- \\test "" {
- \\ var sequence = "repeat".** 10&a;
- \\}
- , &[_]Error{
- .asterisk_after_ptr_deref,
- .mismatched_binary_op_whitespace,
- });
-}
-
test "recovery: missing semicolon after if, for, while stmt" {
try testError(
\\test "" {
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
@@ -64,7 +64,6 @@ pub const Token = struct {
pub const Tag = enum {
invalid,
- invalid_periodasterisks,
identifier,
string_literal,
multiline_string_literal_line,
@@ -109,7 +108,6 @@ pub const Token = struct {
minus_pipe_equal,
asterisk,
asterisk_equal,
- asterisk_asterisk,
asterisk_percent,
asterisk_percent_equal,
asterisk_pipe,
@@ -197,7 +195,6 @@ pub const Token = struct {
.container_doc_comment,
=> null,
- .invalid_periodasterisks => ".**",
.bang => "!",
.pipe => "|",
.pipe_pipe => "||",
@@ -236,7 +233,6 @@ pub const Token = struct {
.minus_pipe_equal => "-|=",
.asterisk => "*",
.asterisk_equal => "*=",
- .asterisk_asterisk => "**",
.asterisk_percent => "*%",
.asterisk_percent_equal => "*%=",
.asterisk_pipe => "*|",
@@ -386,7 +382,6 @@ pub const Tokenizer = struct {
angle_bracket_angle_bracket_right,
period,
period_2,
- period_asterisk,
saw_at_sign,
invalid,
};
@@ -569,10 +564,6 @@ pub const Tokenizer = struct {
result.tag = .asterisk_equal;
self.index += 1;
},
- '*' => {
- result.tag = .asterisk_asterisk;
- self.index += 1;
- },
'%' => continue :state .asterisk_percent,
'|' => continue :state .asterisk_pipe,
else => result.tag = .asterisk,
@@ -915,7 +906,10 @@ pub const Tokenizer = struct {
self.index += 1;
switch (self.buffer[self.index]) {
'.' => continue :state .period_2,
- '*' => continue :state .period_asterisk,
+ '*' => {
+ result.tag = .period_asterisk;
+ self.index += 1;
+ },
else => result.tag = .period,
}
},
@@ -931,14 +925,6 @@ pub const Tokenizer = struct {
}
},
- .period_asterisk => {
- self.index += 1;
- switch (self.buffer[self.index]) {
- '*' => result.tag = .invalid_periodasterisks,
- else => result.tag = .period_asterisk,
- }
- },
-
.slash => {
self.index += 1;
switch (self.buffer[self.index]) {
@@ -1343,31 +1329,6 @@ test "correctly parse pointer assignment" {
});
}
-test "correctly parse pointer dereference followed by asterisk" {
- try testTokenize("\"b\".* ** 10", &.{
- .string_literal,
- .period_asterisk,
- .asterisk_asterisk,
- .number_literal,
- });
-
- try testTokenize("(\"b\".*)** 10", &.{
- .l_paren,
- .string_literal,
- .period_asterisk,
- .r_paren,
- .asterisk_asterisk,
- .number_literal,
- });
-
- try testTokenize("\"b\".*** 10", &.{
- .string_literal,
- .invalid_periodasterisks,
- .asterisk_asterisk,
- .number_literal,
- });
-}
-
test "range literals" {
try testTokenize("0...9", &.{ .number_literal, .ellipsis3, .number_literal });
try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -1171,7 +1171,6 @@ fn analyzeBodyInner(
.make_ptr_const => try sema.zirMakePtrConst(block, inst),
.anyframe_type => try sema.zirAnyframeType(block, inst),
.array_cat => try sema.zirArrayCat(block, inst),
- .array_mul => try sema.zirArrayMul(block, inst),
.array_type => try sema.zirArrayType(block, inst),
.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
.reify_int => try sema.zirReifyInt(block, inst),
@@ -13861,174 +13860,6 @@ fn analyzeTupleMul(
return block.addAggregateInit(tuple_ty, element_refs);
}
-fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const pt = sema.pt;
- const zcu = pt.zcu;
- const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
- const extra = sema.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
- const uncoerced_lhs = sema.resolveInst(extra.lhs);
- const uncoerced_lhs_ty = sema.typeOf(uncoerced_lhs);
- const src: LazySrcLoc = block.nodeOffset(inst_data.src_node);
- const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
- const operator_src = block.src(.{ .node_offset_main_token = inst_data.src_node });
- const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
-
- const lhs, const lhs_ty = coerced_lhs: {
- // If we have a result type, we might be able to do this more efficiently
- // by coercing the LHS first. Specifically, if we want an array or vector
- // and have a tuple, coerce the tuple immediately.
- no_coerce: {
- if (extra.res_ty == .none) break :no_coerce;
- const res_ty = try sema.resolveTypeOrPoison(block, src, extra.res_ty) orelse break :no_coerce;
- if (!uncoerced_lhs_ty.isTuple(zcu)) break :no_coerce;
- const lhs_len = uncoerced_lhs_ty.structFieldCount(zcu);
- const lhs_dest_ty = switch (res_ty.zigTypeTag(zcu)) {
- else => break :no_coerce,
- .array => try pt.arrayType(.{
- .child = res_ty.childType(zcu).toIntern(),
- .len = lhs_len,
- .sentinel = if (res_ty.sentinel(zcu)) |s| s.toIntern() else .none,
- }),
- .vector => try pt.vectorType(.{
- .child = res_ty.childType(zcu).toIntern(),
- .len = lhs_len,
- }),
- };
- // Attempt to coerce to this type, but don't emit an error if it fails. Instead,
- // just exit out of this path and let the usual error happen later, so that error
- // messages are consistent.
- const coerced = sema.coerceExtra(block, lhs_dest_ty, uncoerced_lhs, lhs_src, .{ .report_err = false }) catch |err| switch (err) {
- error.NotCoercible => break :no_coerce,
- else => |e| return e,
- };
- break :coerced_lhs .{ coerced, lhs_dest_ty };
- }
- break :coerced_lhs .{ uncoerced_lhs, uncoerced_lhs_ty };
- };
-
- if (lhs_ty.isTuple(zcu)) {
- // In `**` rhs must be comptime-known, but lhs can be runtime-known
- const factor = try sema.resolveInt(block, rhs_src, extra.rhs, .usize, .{ .simple = .array_mul_factor });
- const factor_casted = try sema.usizeCast(block, rhs_src, factor);
- return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted);
- }
-
- // Analyze the lhs first, to catch the case that someone tried to do exponentiation
- const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse {
- const msg = msg: {
- const msg = try sema.errMsg(lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
- switch (lhs_ty.zigTypeTag(zcu)) {
- .int, .float, .comptime_float, .comptime_int, .vector => {
- try sema.errNote(operator_src, msg, "this operator multiplies arrays; use std.math.pow for exponentiation", .{});
- },
- else => {},
- }
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- };
-
- // In `**` rhs must be comptime-known, but lhs can be runtime-known
- const factor = try sema.resolveInt(block, rhs_src, extra.rhs, .usize, .{ .simple = .array_mul_factor });
-
- const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch
- return sema.fail(block, rhs_src, "operation results in overflow", .{});
- const result_len = try sema.usizeCast(block, src, result_len_u64);
-
- const result_ty = try pt.arrayType(.{
- .len = result_len,
- .sentinel = if (lhs_info.sentinel) |s| s.toIntern() else .none,
- .child = lhs_info.elem_type.toIntern(),
- });
-
- const ptr_addrspace = if (lhs_ty.zigTypeTag(zcu) == .pointer) lhs_ty.ptrAddressSpace(zcu) else null;
- const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
-
- if (sema.resolveValue(lhs)) |lhs_val| ct: {
- const lhs_sub_val = if (lhs_ty.isSinglePointer(zcu))
- try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :ct
- else if (lhs_ty.isSlice(zcu))
- try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :ct
- else
- lhs_val;
-
- const val = v: {
- // Optimization for the common pattern of a single element repeated N times, such
- // as zero-filling a byte array.
- if (lhs_len == 1 and lhs_info.sentinel == null) {
- const elem_val = try lhs_sub_val.elemValue(pt, 0);
- break :v try pt.aggregateSplatValue(result_ty, elem_val);
- }
-
- const element_vals = try sema.arena.alloc(InternPool.Index, result_len);
- var elem_i: usize = 0;
- while (elem_i < result_len) {
- var lhs_i: usize = 0;
- while (lhs_i < lhs_len) : (lhs_i += 1) {
- const elem_val = try lhs_sub_val.elemValue(pt, lhs_i);
- element_vals[elem_i] = elem_val.toIntern();
- elem_i += 1;
- }
- }
- break :v try pt.aggregateValue(result_ty, element_vals);
- };
- return sema.addConstantMaybeRef(val, ptr_addrspace != null);
- }
-
- try sema.requireRuntimeBlock(block, src, lhs_src);
-
- // Grab all the LHS values ahead of time, rather than repeatedly emitting instructions
- // to get the same elem values.
- const lhs_vals = try sema.arena.alloc(Air.Inst.Ref, lhs_len);
- for (lhs_vals, 0..) |*lhs_val, idx| {
- const idx_ref = try pt.intRef(.usize, idx);
- lhs_val.* = try sema.elemVal(block, lhs_src, lhs, idx_ref, src, false);
- }
-
- if (ptr_addrspace) |ptr_as| {
- const alloc_ty = try pt.ptrType(.{
- .child = result_ty.toIntern(),
- .flags = .{
- .address_space = ptr_as,
- .is_const = true,
- },
- });
- const alloc = try block.addTy(.alloc, alloc_ty);
- const elem_ptr_ty = try pt.ptrType(.{
- .child = lhs_info.elem_type.toIntern(),
- .flags = .{ .address_space = ptr_as },
- });
-
- var elem_i: usize = 0;
- while (elem_i < result_len) {
- for (lhs_vals) |lhs_val| {
- const elem_index = try pt.intRef(.usize, elem_i);
- const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
- try sema.storePtr2(block, src, elem_ptr, src, lhs_val, lhs_src, .store);
- elem_i += 1;
- }
- }
- if (lhs_info.sentinel) |sent_val| {
- const elem_index = try pt.intRef(.usize, result_len);
- const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
- const init = Air.internedToRef(sent_val.toIntern());
- try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
- }
-
- return alloc;
- }
-
- const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
- for (0..try sema.usizeCast(block, rhs_src, factor)) |i| {
- @memcpy(element_refs[i * lhs_len ..][0..lhs_len], lhs_vals);
- }
- return block.addAggregateInit(result_ty, element_refs);
-}
-
fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
diff --git a/src/print_zir.zig b/src/print_zir.zig
@@ -416,8 +416,6 @@ const Writer = struct {
.for_len => try self.writePlNodeMultiOp(stream, inst),
- .array_mul => try self.writeArrayMul(stream, inst),
-
.elem_val_imm => try self.writeElemValImm(stream, inst),
.@"export" => try self.writePlNodeExport(stream, inst),
@@ -1046,18 +1044,6 @@ const Writer = struct {
try self.writeSrcNode(stream, inst_data.src_node);
}
- fn writeArrayMul(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
- const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
- const extra = self.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
- try self.writeInstRef(stream, extra.res_ty);
- try stream.writeAll(", ");
- try self.writeInstRef(stream, extra.lhs);
- try stream.writeAll(", ");
- try self.writeInstRef(stream, extra.rhs);
- try stream.writeAll(") ");
- try self.writeSrcNode(stream, inst_data.src_node);
- }
-
fn writeElemValImm(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm;
try self.writeInstRef(stream, inst_data.operand);
diff --git a/tools/docgen.zig b/tools/docgen.zig
@@ -871,7 +871,6 @@ fn tokenizeAndPrintRaw(
.minus_pipe_equal,
.asterisk,
.asterisk_equal,
- .asterisk_asterisk,
.asterisk_percent,
.asterisk_percent_equal,
.asterisk_pipe,
@@ -897,7 +896,7 @@ fn tokenizeAndPrintRaw(
.tilde,
=> try writeEscaped(out, src[token.loc.start..token.loc.end]),
- .invalid, .invalid_periodasterisks => return parseError(
+ .invalid => return parseError(
docgen_tokenizer,
source_token,
"syntax error",
diff --git a/tools/doctest.zig b/tools/doctest.zig
@@ -800,7 +800,6 @@ fn tokenizeAndPrint(arena: Allocator, out: *Writer, raw_src: []const u8) !void {
.minus_pipe_equal,
.asterisk,
.asterisk_equal,
- .asterisk_asterisk,
.asterisk_percent,
.asterisk_percent_equal,
.asterisk_pipe,
@@ -826,7 +825,7 @@ fn tokenizeAndPrint(arena: Allocator, out: *Writer, raw_src: []const u8) !void {
.tilde,
=> try writeEscaped(out, src[token.loc.start..token.loc.end]),
- .invalid, .invalid_periodasterisks => fatal("syntax error", .{}),
+ .invalid => fatal("syntax error", .{}),
}
index = token.loc.end;
}