commit 24bc3012f3118f836f8013bfada7db00fa5ce708 (tree)
parent dd29c8a6f9c873ddd9177397e6fe827e7d7ae5d2
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Sat, 14 Feb 2026 10:19:36 +0000
astgen: blockExpr rvalue, local_ptr rvalue, array_mult
- blockExpr: call rvalue on void result for unlabeled blocks, matching
upstream AstGen.zig:2431. This was causing a missing STORE_NODE when
empty blocks like {} were used as struct field values with pointer RL.
- identifierExpr: call rvalueNoCoercePreRef after LOAD in local_ptr case,
matching upstream AstGen.zig:8453-8454.
- Implement AST_NODE_ARRAY_MULT (** operator) with ArrayMul payload,
matching upstream AstGen.zig:774-785.
- Enable parser_test.zig and astgen_test.zig corpus tests.
- Enable combined corpus test (all 5 files pass).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
2 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/stage0/astgen.c b/stage0/astgen.c
@@ -2480,6 +2480,7 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node);
#define COMPTIME_REASON_ADDRSPACE 51
#define COMPTIME_REASON_FIELD_NAME 42
#define COMPTIME_REASON_COMPTIME_KEYWORD 53
+#define COMPTIME_REASON_ARRAY_MUL_FACTOR 22
#define COMPTIME_REASON_SWITCH_ITEM 56
#define COMPTIME_REASON_TUPLE_FIELD_DEFAULT_VALUE 57
@@ -3100,7 +3101,8 @@ static uint32_t identifierExpr(
if (lp->name == name_str) {
if (RL_IS_REF(rl))
return lp->ptr;
- return addUnNode(gz, ZIR_INST_LOAD, lp->ptr, node);
+ uint32_t val = addUnNode(gz, ZIR_INST_LOAD, lp->ptr, node);
+ return rvalueNoCoercePreRef(gz, rl, val, node);
}
s = lp->parent;
continue;
@@ -4590,6 +4592,20 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
case AST_NODE_ARRAY_CAT:
return rvalue(
gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_ARRAY_CAT), node);
+ // array_mult (AstGen.zig:774-785): ** binary operator.
+ case AST_NODE_ARRAY_MULT: {
+ uint32_t res_ty = rlResultType(gz, rl, node);
+ uint32_t lhs = exprRl(gz, scope, RL_NONE_VAL, nd.lhs);
+ ResultLoc rhs_rl = { .tag = RL_COERCED_TY,
+ .data = ZIR_REF_USIZE_TYPE,
+ .src_node = 0,
+ .ctx = 0 };
+ uint32_t rhs = comptimeExpr(
+ gz, scope, rhs_rl, nd.rhs, COMPTIME_REASON_ARRAY_MUL_FACTOR);
+ uint32_t result = addPlNodeTriple(gz, ZIR_INST_ARRAY_MUL, node,
+ res_ty != 0 ? res_ty : ZIR_REF_NONE, lhs, rhs);
+ return rvalue(gz, rl, result, node);
+ }
// grouped_expression (AstGen.zig:1100): passthrough.
case AST_NODE_GROUPED_EXPRESSION:
return exprRl(gz, scope, rl, ag->tree->nodes.datas[node].lhs);
@@ -5386,7 +5402,6 @@ static uint32_t expr(GenZir* gz, Scope* scope, uint32_t node) {
static uint32_t blockExprExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
- (void)rl;
AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree;
AstNodeTag tag = tree->nodes.tags[node];
@@ -5459,7 +5474,8 @@ static uint32_t blockExprExpr(
GenZir sub_gz = makeSubBlock(gz, scope);
blockExprStmts(&sub_gz, &sub_gz.base, statements, stmt_count);
}
- return ZIR_REF_VOID_VALUE;
+ // AstGen.zig:2431
+ return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node);
}
// Labeled block (AstGen.zig:2466-2536).
diff --git a/stage0/astgen_test.zig b/stage0/astgen_test.zig
@@ -256,6 +256,32 @@ fn expectEqualZir(gpa: Allocator, ref: Zir, got: c.Zir) !void {
@as(i32, @intCast(got_counts[t])) - @as(i32, @intCast(ref_counts[t])),
});
}
+ // Find first tag divergence.
+ const min_len = @min(ref_len, got.inst_len);
+ for (0..min_len) |i| {
+ const ref_tag: u8 = @intFromEnum(ref_tags[i]);
+ const got_tag: u8 = @intCast(got.inst_tags[i]);
+ if (ref_tag != got_tag) {
+ std.debug.print("first divergence at [{d}]: ref_tag={d} got_tag={d}\n", .{ i, ref_tag, got_tag });
+ // Show ref instruction data for this position.
+ const rd = ref_datas[i];
+ std.debug.print(" ref pl_node: src_node={d} payload={d}\n", .{
+ rd.pl_node.src_node, rd.pl_node.payload_index,
+ });
+ // Scan for nearest declaration.
+ var j: usize = i;
+ while (j > 0) {
+ j -= 1;
+ if (ref_tags[j] == .declaration) {
+ std.debug.print(" nearest decl at [{d}]: src_node={d}\n", .{
+ j, ref_datas[j].declaration.src_node,
+ });
+ break;
+ }
+ }
+ break;
+ }
+ }
return error.TestExpectedEqual;
}
@@ -817,9 +843,6 @@ test "astgen: corpus tokenizer_test.zig" {
}
test "astgen: corpus parser_test.zig" {
- // TODO: 10+ extra data mismatches (ref=48 got=32, bit 4 = propagate_error_trace)
- // in call instruction flags — ctx propagation differs from upstream.
- if (true) return error.SkipZigTest;
const gpa = std.testing.allocator;
try corpusCheck(gpa, @embedFile("parser_test.zig"));
}
@@ -857,7 +880,7 @@ test "astgen: struct init typed" {
}
test "astgen: corpus" {
- if (true) return error.SkipZigTest; // TODO: parser_test.zig fails
+ // All individual corpus tests now pass.
const gpa = std.testing.allocator;
var any_fail = false;