commit f14f47424d57b143a936d2ab3998b38ecef616a0 (tree)
parent 657ee8bd369d306042a2185fc748f819f51f8a72
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Sat, 14 Feb 2026 00:18:25 +0000
astgen: fix structInitExpr rvalue, RL handling, sentinel coercion, and empty init
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
| M | astgen.c | | | 226 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
1 file changed, 132 insertions(+), 94 deletions(-)
diff --git a/astgen.c b/astgen.c
@@ -4044,8 +4044,72 @@ static uint32_t callExpr(
return call_index + ZIR_REF_START_INDEX;
}
+// structInitExprAnon (AstGen.zig:1865-1893).
+// Anonymous struct init using struct_init_anon instruction.
+static uint32_t structInitExprAnon(GenZir* gz, Scope* scope, uint32_t node,
+ const uint32_t* fields, uint32_t fields_len) {
+ AstGenCtx* ag = gz->astgen;
+ const Ast* tree = ag->tree;
+
+ ensureExtraCapacity(ag, 3 + fields_len * 2);
+ uint32_t payload_index = ag->extra_len;
+ ag->extra[ag->extra_len++] = node; // abs_node
+ ag->extra[ag->extra_len++] = ag->source_line; // abs_line
+ ag->extra[ag->extra_len++] = fields_len;
+ uint32_t items_start = ag->extra_len;
+ ag->extra_len += fields_len * 2;
+
+ for (uint32_t i = 0; i < fields_len; i++) {
+ uint32_t field_init = fields[i];
+ uint32_t name_token = firstToken(tree, field_init) - 2;
+ uint32_t str_index = identAsString(ag, name_token);
+ uint32_t init_ref = expr(gz, scope, field_init);
+ ag->extra[items_start + i * 2] = str_index;
+ ag->extra[items_start + i * 2 + 1] = init_ref;
+ }
+
+ return addPlNodePayloadIndex(
+ gz, ZIR_INST_STRUCT_INIT_ANON, node, payload_index);
+}
+
+// structInitExprTyped (AstGen.zig:1896-1931).
+// Typed struct init using struct_init or struct_init_ref instruction.
+static uint32_t structInitExprTyped(GenZir* gz, Scope* scope, uint32_t node,
+ const uint32_t* fields, uint32_t fields_len, uint32_t ty_inst,
+ bool is_ref) {
+ AstGenCtx* ag = gz->astgen;
+ const Ast* tree = ag->tree;
+
+ ensureExtraCapacity(ag, 3 + fields_len * 2);
+ uint32_t payload_index = ag->extra_len;
+ ag->extra[ag->extra_len++] = node; // abs_node
+ ag->extra[ag->extra_len++] = ag->source_line; // abs_line
+ ag->extra[ag->extra_len++] = fields_len;
+ uint32_t items_start = ag->extra_len;
+ ag->extra_len += fields_len * 2;
+
+ for (uint32_t i = 0; i < fields_len; i++) {
+ uint32_t field_init = fields[i];
+ uint32_t name_token = firstToken(tree, field_init) - 2;
+ uint32_t str_index = identAsString(ag, name_token);
+ uint32_t field_ty_inst = addPlNodeBin(gz,
+ ZIR_INST_STRUCT_INIT_FIELD_TYPE, field_init, ty_inst, str_index);
+ ResultLoc elem_rl = { .tag = RL_COERCED_TY,
+ .data = field_ty_inst,
+ .src_node = 0,
+ .ctx = RI_CTX_NONE };
+ uint32_t init_ref = exprRl(gz, scope, elem_rl, field_init);
+ ag->extra[items_start + i * 2]
+ = field_ty_inst - ZIR_REF_START_INDEX; // .toIndex()
+ ag->extra[items_start + i * 2 + 1] = init_ref;
+ }
+
+ ZirInstTag init_tag
+ = is_ref ? ZIR_INST_STRUCT_INIT_REF : ZIR_INST_STRUCT_INIT;
+ return addPlNodePayloadIndex(gz, init_tag, node, payload_index);
+}
+
// --- structInitExpr (AstGen.zig:1674) ---
-// Simplified: handles .{} (empty tuple), .{.a = b} (anon init).
static uint32_t structInitExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
AstGenCtx* ag = gz->astgen;
@@ -4118,7 +4182,15 @@ static uint32_t structInitExpr(
if (rl.tag == RL_DISCARD) {
return ZIR_REF_VOID_VALUE;
}
- return ZIR_REF_EMPTY_TUPLE;
+ if (rl.tag == RL_PTR) {
+ // AstGen.zig:1691-1696.
+ uint32_t ty_inst = rlResultType(gz, rl, node);
+ uint32_t val = addUnNode(
+ gz, ZIR_INST_STRUCT_INIT_EMPTY_RESULT, ty_inst, node);
+ return rvalue(gz, rl, val, node);
+ }
+ // RL_NONE, RL_REF, RL_INFERRED_PTR (AstGen.zig:1697-1699).
+ return rvalue(gz, rl, ZIR_REF_EMPTY_TUPLE, node);
}
// Pre-register all field names to match upstream string ordering.
@@ -4130,8 +4202,46 @@ static uint32_t structInitExpr(
}
if (type_expr_node == 0 && fields_len > 0) {
- // structInitExprPtr for RL_PTR (AstGen.zig:1843-1846, 1934-1964).
- if (rl.tag == RL_PTR) {
+ // Anonymous struct init with fields (AstGen.zig:1821-1861).
+ switch (rl.tag) {
+ case RL_NONE:
+ // structInitExprAnon (AstGen.zig:1822, 1865-1893).
+ return structInitExprAnon(gz, scope, node, fields, fields_len);
+ case RL_DISCARD: {
+ // Even if discarding we must perform side-effects
+ // (AstGen.zig:1823-1828).
+ for (uint32_t i = 0; i < fields_len; i++)
+ exprRl(gz, scope, RL_DISCARD_VAL, fields[i]);
+ return ZIR_REF_VOID_VALUE;
+ }
+ case RL_REF: {
+ // structInitExprAnon + ref (AstGen.zig:1830-1833).
+ uint32_t result
+ = structInitExprAnon(gz, scope, node, fields, fields_len);
+ return addUnTok(gz, ZIR_INST_REF, result, firstToken(tree, node));
+ }
+ case RL_REF_COERCED_TY: {
+ // Get elem type, validate, structInitExprTyped(is_ref=true)
+ // (AstGen.zig:1834-1837).
+ uint32_t result_ty_inst
+ = addUnNode(gz, ZIR_INST_ELEM_TYPE, rl.data, node);
+ addUnNode(gz, ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY,
+ result_ty_inst, node);
+ return structInitExprTyped(
+ gz, scope, node, fields, fields_len, result_ty_inst, true);
+ }
+ case RL_TY:
+ case RL_COERCED_TY: {
+ // validate_struct_init_result_ty +
+ // structInitExprTyped(is_ref=false) (AstGen.zig:1839-1841).
+ uint32_t ty_inst = rl.data;
+ addUnNode(
+ gz, ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY, ty_inst, node);
+ return structInitExprTyped(
+ gz, scope, node, fields, fields_len, ty_inst, false);
+ }
+ case RL_PTR: {
+ // structInitExprPtr (AstGen.zig:1843-1846, 1934-1964).
uint32_t struct_ptr_inst
= addUnNode(gz, ZIR_INST_OPT_EU_BASE_PTR_INIT, rl.data, node);
// Block payload: body_len = fields_len.
@@ -4155,68 +4265,22 @@ static uint32_t structInitExpr(
ResultLoc ptr_rl = { .tag = RL_PTR,
.data = field_ptr,
.src_node = 0,
- .ctx = rl.ctx };
+ .ctx = RI_CTX_NONE };
exprRl(gz, scope, ptr_rl, field_init);
}
addPlNodePayloadIndex(
gz, ZIR_INST_VALIDATE_PTR_STRUCT_INIT, node, payload_index);
return ZIR_REF_VOID_VALUE;
}
- // Anonymous struct init with RL type (AstGen.zig:1706-1731).
- if (rl.tag == RL_TY || rl.tag == RL_COERCED_TY) {
- uint32_t ty_inst = rl.data;
- // validate_struct_init_result_ty (AstGen.zig:1840).
- addUnNode(
- gz, ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY, ty_inst, node);
- // structInitExprTyped (AstGen.zig:1896-1931).
- ensureExtraCapacity(ag, 3 + fields_len * 2);
- uint32_t payload_index = ag->extra_len;
- ag->extra[ag->extra_len++] = node;
- ag->extra[ag->extra_len++] = ag->source_line;
- ag->extra[ag->extra_len++] = fields_len;
- uint32_t items_start = ag->extra_len;
- ag->extra_len += fields_len * 2;
- for (uint32_t i = 0; i < fields_len; i++) {
- uint32_t field_init = fields[i];
- uint32_t name_token = firstToken(tree, field_init) - 2;
- uint32_t str_index = identAsString(ag, name_token);
- uint32_t field_ty_inst
- = addPlNodeBin(gz, ZIR_INST_STRUCT_INIT_FIELD_TYPE,
- field_init, ty_inst, str_index);
- ResultLoc elem_rl = {
- .tag = RL_COERCED_TY, .data = field_ty_inst, .src_node = 0
- };
- uint32_t init_ref = exprRl(gz, scope, elem_rl, field_init);
- ag->extra[items_start + i * 2]
- = field_ty_inst - ZIR_REF_START_INDEX;
- ag->extra[items_start + i * 2 + 1] = init_ref;
- }
- return addPlNodePayloadIndex(
- gz, ZIR_INST_STRUCT_INIT, node, payload_index);
+ case RL_INFERRED_PTR: {
+ // Standard anon init + rvalue store (AstGen.zig:1847-1852).
+ uint32_t struct_inst
+ = structInitExprAnon(gz, scope, node, fields, fields_len);
+ return rvalue(gz, rl, struct_inst, node);
}
- // Anonymous struct init without RL type (AstGen.zig:1864).
- // StructInitAnon payload: abs_node, abs_line, fields_len.
- ensureExtraCapacity(ag, 3 + fields_len * 2);
- uint32_t payload_index = ag->extra_len;
- ag->extra[ag->extra_len++] = node; // abs_node
- ag->extra[ag->extra_len++] = ag->source_line; // abs_line
- ag->extra[ag->extra_len++] = fields_len;
- // Reserve space for field entries.
- uint32_t items_start = ag->extra_len;
- ag->extra_len += fields_len * 2;
-
- for (uint32_t i = 0; i < fields_len; i++) {
- uint32_t field_init = fields[i];
- // field name is 2 tokens before the field init's first token.
- uint32_t name_token = firstToken(tree, field_init) - 2;
- uint32_t str_index = identAsString(ag, name_token);
- uint32_t init_ref = expr(gz, scope, field_init);
- ag->extra[items_start + i * 2] = str_index;
- ag->extra[items_start + i * 2 + 1] = init_ref;
}
-
- return addPlNodePayloadIndex(
- gz, ZIR_INST_STRUCT_INIT_ANON, node, payload_index);
+ SET_ERROR(ag);
+ return ZIR_REF_VOID_VALUE;
}
// Typed init: evaluate type, emit struct_init_empty or struct_init.
@@ -4246,7 +4310,7 @@ static uint32_t structInitExpr(
uint32_t elem_type_node
= tree->extra_data.arr[type_nd.rhs + 1];
uint32_t elem_type = typeExpr(gz, scope, elem_type_node);
- ResultLoc sent_rl = { .tag = RL_COERCED_TY,
+ ResultLoc sent_rl = { .tag = RL_TY,
.data = elem_type,
.src_node = 0,
.ctx = RI_CTX_NONE };
@@ -4270,41 +4334,15 @@ static uint32_t structInitExpr(
if (type_expr_node != 0 && fields_len > 0) {
uint32_t ty_inst = typeExpr(gz, scope, type_expr_node);
addUnNode(gz, ZIR_INST_VALIDATE_STRUCT_INIT_TY, ty_inst, node);
-
- // structInitExprTyped (AstGen.zig:1896-1931).
- // StructInit payload: abs_node, abs_line, fields_len.
- ensureExtraCapacity(ag, 3 + fields_len * 2);
- uint32_t payload_index = ag->extra_len;
- ag->extra[ag->extra_len++] = node; // abs_node
- ag->extra[ag->extra_len++] = ag->source_line; // abs_line
- ag->extra[ag->extra_len++] = fields_len;
- // Reserve space for field items (field_type + init each).
- uint32_t items_start = ag->extra_len;
- ag->extra_len += fields_len * 2;
-
- for (uint32_t i = 0; i < fields_len; i++) {
- uint32_t field_init = fields[i];
- uint32_t name_token = firstToken(tree, field_init) - 2;
- uint32_t str_index = identAsString(ag, name_token);
- // struct_init_field_type (AstGen.zig:1918-1921).
- uint32_t field_ty_inst
- = addPlNodeBin(gz, ZIR_INST_STRUCT_INIT_FIELD_TYPE, field_init,
- ty_inst, str_index);
- // Evaluate init with coerced_ty (AstGen.zig:1924).
- ResultLoc elem_rl = { .tag = RL_COERCED_TY,
- .data = field_ty_inst,
- .src_node = 0,
- .ctx = rl.ctx };
- uint32_t init_ref = exprRl(gz, scope, elem_rl, field_init);
- ag->extra[items_start + i * 2]
- = field_ty_inst - ZIR_REF_START_INDEX; // .toIndex()
- ag->extra[items_start + i * 2 + 1] = init_ref;
- }
-
- bool is_ref = (RL_IS_REF(rl));
- ZirInstTag init_tag
- = is_ref ? ZIR_INST_STRUCT_INIT_REF : ZIR_INST_STRUCT_INIT;
- return addPlNodePayloadIndex(gz, init_tag, node, payload_index);
+ // Upstream: .ref => structInitExprTyped(is_ref=true)
+ // else => rvalue(structInitExprTyped(is_ref=false))
+ if (rl.tag == RL_REF) {
+ return structInitExprTyped(
+ gz, scope, node, fields, fields_len, ty_inst, true);
+ }
+ uint32_t struct_inst = structInitExprTyped(
+ gz, scope, node, fields, fields_len, ty_inst, false);
+ return rvalue(gz, rl, struct_inst, node);
}
SET_ERROR(ag);