astgen: fix arrayInitExpr sentinel, discard RL, and non-inferred typed init

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 22:48:48 +00:00
parent 91e1d1bd2e
commit 2a1df547d6

163
astgen.c
View File

@@ -3209,7 +3209,11 @@ static uint32_t arrayTypeExpr(GenZir* gz, Scope* scope, uint32_t node) {
} }
// --- arrayInitExpr (AstGen.zig:1431) --- // --- arrayInitExpr (AstGen.zig:1431) ---
// Simplified: handles typed array init with inferred [_] length. // Handles typed array init: [_]T{...}, [_:s]T{...}, and [N]T{...}.
static uint32_t arrayInitExprTyped(GenZir* gz, Scope* scope, uint32_t node,
const uint32_t* elements, uint32_t elem_count, uint32_t ty_inst,
uint32_t elem_ty, bool is_ref);
static uint32_t arrayInitExpr( static uint32_t arrayInitExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
@@ -3258,56 +3262,134 @@ static uint32_t arrayInitExpr(
return ZIR_REF_VOID_VALUE; return ZIR_REF_VOID_VALUE;
} }
// Check if the type is [_]T (inferred length) (AstGen.zig:1446-1474). // Determine array_ty and elem_ty (AstGen.zig:1443-1482).
if (tree->nodes.tags[type_expr_node] == AST_NODE_ARRAY_TYPE) { uint32_t array_ty = ZIR_REF_NONE;
uint32_t elem_ty = ZIR_REF_NONE;
// Check if the type is [_]T or [_:s]T (inferred length)
// (AstGen.zig:1446-1474, fullArrayType handles both array_type and
// array_type_sentinel).
AstNodeTag type_tag = tree->nodes.tags[type_expr_node];
if (type_tag == AST_NODE_ARRAY_TYPE
|| type_tag == AST_NODE_ARRAY_TYPE_SENTINEL) {
AstData type_nd = tree->nodes.datas[type_expr_node]; AstData type_nd = tree->nodes.datas[type_expr_node];
uint32_t elem_count_node = type_nd.lhs; uint32_t elem_count_node = type_nd.lhs;
uint32_t elem_type_node = type_nd.rhs;
// Check if elem_count is `_` identifier. // This intentionally does not support `@"_"` syntax.
if (tree->nodes.tags[elem_count_node] == AST_NODE_IDENTIFIER if (tree->nodes.tags[elem_count_node] == AST_NODE_IDENTIFIER
&& isUnderscoreIdent(tree, elem_count_node)) { && isUnderscoreIdent(tree, elem_count_node)) {
// Inferred length: addInt(elem_count) (AstGen.zig:1452). // Inferred length: addInt(elem_count) (AstGen.zig:1452).
uint32_t len_inst = addInt(gz, elem_count); uint32_t len_inst = addInt(gz, elem_count);
uint32_t elem_type = typeExpr(gz, scope, elem_type_node);
uint32_t array_type_inst = addPlNodeBin(
gz, ZIR_INST_ARRAY_TYPE, type_expr_node, len_inst, elem_type);
// arrayInitExprTyped (AstGen.zig:1484-1513, 1598-1642). if (type_tag == AST_NODE_ARRAY_TYPE) {
// Only RL_REF produces array_init_ref; all other RLs use // [_]T: elem_type_node is rhs (AstGen.zig:1454-1459).
// array_init + rvalue (AstGen.zig:1507-1511). uint32_t elem_type_node = type_nd.rhs;
bool is_ref = (rl.tag == RL_REF); elem_ty = typeExpr(gz, scope, elem_type_node);
uint32_t operands_len = elem_count + 1; array_ty = addPlNodeBin(gz, ZIR_INST_ARRAY_TYPE,
ensureExtraCapacity(ag, 1 + operands_len); type_expr_node, len_inst, elem_ty);
uint32_t payload_index = ag->extra_len; } else {
ag->extra[ag->extra_len++] = operands_len; // [_:s]T: sentinel and elem_type from extra data
ag->extra[ag->extra_len++] = array_type_inst; // (AstGen.zig:1460-1473).
uint32_t extra_start = ag->extra_len; uint32_t sentinel_node = tree->extra_data.arr[type_nd.rhs];
ag->extra_len += elem_count; uint32_t elem_type_node
for (uint32_t i = 0; i < elem_count; i++) { = tree->extra_data.arr[type_nd.rhs + 1];
// Use elem_type as coercion target for each element. elem_ty = typeExpr(gz, scope, elem_type_node);
ResultLoc elem_rl = { ResultLoc sent_rl = { .tag = RL_TY,
.tag = RL_COERCED_TY, .data = elem_type, .src_node = 0 .data = elem_ty,
}; .src_node = 0,
uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]); .ctx = RI_CTX_NONE };
ag->extra[extra_start + i] = elem_ref; uint32_t sentinel = comptimeExpr(gz, scope, sent_rl,
sentinel_node, COMPTIME_REASON_ARRAY_SENTINEL);
array_ty = addPlNodeTriple(gz, ZIR_INST_ARRAY_TYPE_SENTINEL,
type_expr_node, len_inst, elem_ty, sentinel);
} }
ZirInstTag init_tag goto typed_init;
= is_ref ? ZIR_INST_ARRAY_INIT_REF : ZIR_INST_ARRAY_INIT;
ZirInstData idata;
idata.pl_node.src_node
= (int32_t)node - (int32_t)gz->decl_node_index;
idata.pl_node.payload_index = payload_index;
uint32_t result = addInstruction(gz, init_tag, idata);
if (is_ref)
return result;
return rvalue(gz, rl, result, node);
} }
} }
// Non-inferred length: evaluate type normally. // Non-inferred length: evaluate type normally (AstGen.zig:1476-1481).
SET_ERROR(ag); array_ty = typeExpr(gz, scope, type_expr_node);
return ZIR_REF_VOID_VALUE; // validate_array_init_ty: ArrayInit{ty, init_count}
addPlNodeBin(
gz, ZIR_INST_VALIDATE_ARRAY_INIT_TY, node, array_ty, elem_count);
elem_ty = ZIR_REF_NONE;
typed_init:
// Typed inits do not use RLS for language simplicity
// (AstGen.zig:1484-1513).
if (rl.tag == RL_DISCARD) {
// discard RL: evaluate elements but don't emit array_init
// (AstGen.zig:1487-1506).
if (elem_ty != ZIR_REF_NONE) {
ResultLoc elem_rl
= { .tag = RL_TY, .data = elem_ty, .src_node = 0 };
for (uint32_t i = 0; i < elem_count; i++) {
exprRl(gz, scope, elem_rl, elements[i]);
}
} else {
for (uint32_t i = 0; i < elem_count; i++) {
uint32_t this_elem_ty
= addBin(gz, ZIR_INST_ARRAY_INIT_ELEM_TYPE, array_ty, i);
ResultLoc elem_rl
= { .tag = RL_TY, .data = this_elem_ty, .src_node = 0 };
exprRl(gz, scope, elem_rl, elements[i]);
}
}
return ZIR_REF_VOID_VALUE;
}
if (rl.tag == RL_REF) {
// ref RL: arrayInitExprTyped with is_ref=true
// (AstGen.zig:1507).
return arrayInitExprTyped(
gz, scope, node, elements, elem_count, array_ty, elem_ty, true);
}
// All other RLs: arrayInitExprTyped + rvalue (AstGen.zig:1508-1511).
uint32_t array_inst = arrayInitExprTyped(
gz, scope, node, elements, elem_count, array_ty, elem_ty, false);
return rvalue(gz, rl, array_inst, node);
}
// arrayInitExprTyped (AstGen.zig:1598-1642).
// Emits array_init or array_init_ref instruction.
static uint32_t arrayInitExprTyped(GenZir* gz, Scope* scope, uint32_t node,
const uint32_t* elements, uint32_t elem_count, uint32_t ty_inst,
uint32_t elem_ty, bool is_ref) {
AstGenCtx* ag = gz->astgen;
uint32_t operands_len = elem_count + 1; // +1 for type
ensureExtraCapacity(ag, 1 + operands_len);
uint32_t payload_index = ag->extra_len;
ag->extra[ag->extra_len++] = operands_len;
ag->extra[ag->extra_len++] = ty_inst;
uint32_t extra_start = ag->extra_len;
ag->extra_len += elem_count;
if (elem_ty != ZIR_REF_NONE) {
// Known elem type: use coerced_ty RL (AstGen.zig:1617-1623).
ResultLoc elem_rl
= { .tag = RL_COERCED_TY, .data = elem_ty, .src_node = 0 };
for (uint32_t i = 0; i < elem_count; i++) {
uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]);
ag->extra[extra_start + i] = elem_ref;
}
} else {
// Unknown elem type: use array_init_elem_type per element
// (AstGen.zig:1625-1637).
for (uint32_t i = 0; i < elem_count; i++) {
uint32_t this_elem_ty
= addBin(gz, ZIR_INST_ARRAY_INIT_ELEM_TYPE, ty_inst, i);
ResultLoc elem_rl = {
.tag = RL_COERCED_TY, .data = this_elem_ty, .src_node = 0
};
uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]);
ag->extra[extra_start + i] = elem_ref;
}
}
ZirInstTag init_tag
= is_ref ? ZIR_INST_ARRAY_INIT_REF : ZIR_INST_ARRAY_INIT;
return addPlNodePayloadIndex(gz, init_tag, node, payload_index);
} }
// --- simpleBinOp (AstGen.zig:2204) --- // --- simpleBinOp (AstGen.zig:2204) ---
@@ -5195,10 +5277,11 @@ static uint32_t arrayInitDotExpr(
ag->extra[items_start + i] ag->extra[items_start + i]
= elem_ptr_inst - ZIR_REF_START_INDEX; // .toIndex() = elem_ptr_inst - ZIR_REF_START_INDEX; // .toIndex()
// Evaluate element with ptr RL (AstGen.zig:1668). // Evaluate element with ptr RL (AstGen.zig:1668).
// Upstream creates fresh ResultInfo with default ctx (.none).
ResultLoc ptr_rl = { .tag = RL_PTR, ResultLoc ptr_rl = { .tag = RL_PTR,
.data = elem_ptr_inst, .data = elem_ptr_inst,
.src_node = 0, .src_node = 0,
.ctx = rl.ctx }; .ctx = RI_CTX_NONE };
exprRl(gz, scope, ptr_rl, elements[i]); exprRl(gz, scope, ptr_rl, elements[i]);
} }
addPlNodePayloadIndex( addPlNodePayloadIndex(