astgen: fix structInitExpr rvalue, RL handling, sentinel coercion, and empty init

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 00:18:25 +00:00
parent 657ee8bd36
commit f14f47424d

224
astgen.c
View File

@@ -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;
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);
}
return addPlNodePayloadIndex(
gz, ZIR_INST_STRUCT_INIT, node, payload_index);
}
// 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);