From f14f47424d57b143a936d2ab3998b38ecef616a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Sat, 14 Feb 2026 00:18:25 +0000 Subject: [PATCH] astgen: fix structInitExpr rvalue, RL handling, sentinel coercion, and empty init Co-Authored-By: Claude Opus 4.6 --- astgen.c | 224 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 131 insertions(+), 93 deletions(-) diff --git a/astgen.c b/astgen.c index 96aa521943..e11413e465 100644 --- 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; + // 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); } - - 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); + uint32_t struct_inst = structInitExprTyped( + gz, scope, node, fields, fields_len, ty_inst, false); + return rvalue(gz, rl, struct_inst, node); } SET_ERROR(ag);