astgen: add builtins, fn_proto exprs, extern fn, scope threading

Port multiple features from AstGen.zig:
- fnProtoExpr/fnProtoExprInner: function types as expressions
- arrayTypeSentinelExpr: [N:sentinel]T array types
- Extern fn_decl without body (implicit CCC)
- 12 builtins: ptrFromInt, Vector, setRuntimeSafety, intFromError,
  clz, branchHint, bitSizeOf, fieldParentPtr, splat, offsetOf,
  inComptime, errorFromInt, errorCast alias
- Fix namespace scope parent: use caller's scope instead of gz->base,
  allowing inner structs to reference outer locals (fixes S2, name, U)
- Fix addFunc/addFuncFancy: don't emit src_locs when body is empty

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 16:59:34 +00:00
parent 7809bdf961
commit 2cc1bd4ddc
2 changed files with 706 additions and 84 deletions

View File

@@ -111,8 +111,7 @@ typedef struct {
bool fn_var_args; // AstGen.zig:46 bool fn_var_args; // AstGen.zig:46
} AstGenCtx; } AstGenCtx;
static void setCompileError(AstGenCtx* ag) { ag->has_compile_errors = true; } #define SET_ERROR(ag) ((ag)->has_compile_errors = true)
#define SET_ERROR(ag) setCompileError(ag)
// Set fn_block pointer on AstGenCtx. The caller is responsible for saving // Set fn_block pointer on AstGenCtx. The caller is responsible for saving
// and restoring the previous value before the pointed-to GenZir goes out // and restoring the previous value before the pointed-to GenZir goes out
@@ -2610,15 +2609,15 @@ static bool nameStratExpr(GenZir* gz, Scope* scope, ResultLoc rl,
static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token); static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token);
static uint32_t containerDecl( static uint32_t containerDecl(
GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy); GenZir* gz, Scope* scope, uint32_t node, uint8_t name_strategy);
static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
const uint32_t* members, uint32_t members_len, uint8_t layout, uint32_t node, const uint32_t* members, uint32_t members_len,
uint32_t backing_int_node, uint8_t name_strategy); uint8_t layout, uint32_t backing_int_node, uint8_t name_strategy);
static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
const uint32_t* members, uint32_t members_len, uint8_t layout, uint32_t node, const uint32_t* members, uint32_t members_len,
uint32_t backing_int_node); uint8_t layout, uint32_t backing_int_node);
static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
const uint32_t* members, uint32_t members_len, uint32_t arg_node, uint32_t node, const uint32_t* members, uint32_t members_len,
uint8_t name_strategy); uint32_t arg_node, uint8_t name_strategy);
static uint32_t blockExprExpr( static uint32_t blockExprExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node);
@@ -2650,6 +2649,24 @@ static uint32_t identAsString(AstGenCtx* ag, uint32_t token);
static uint32_t lastToken(const Ast* tree, uint32_t node); static uint32_t lastToken(const Ast* tree, uint32_t node);
static uint32_t simpleBinOp( static uint32_t simpleBinOp(
GenZir* gz, Scope* scope, uint32_t node, ZirInstTag tag); GenZir* gz, Scope* scope, uint32_t node, ZirInstTag tag);
static uint32_t addParam(GenZir* gz, GenZir* param_gz, ZirInstTag tag,
uint32_t abs_tok_index, uint32_t name, bool is_generic);
static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
uint32_t param_block, uint32_t ret_ref, const uint32_t* ret_body,
uint32_t ret_body_len, const uint32_t* body, uint32_t body_len,
const uint32_t* param_insts, uint32_t param_insts_len,
uint32_t lbrace_line, uint32_t lbrace_column, bool is_inferred_error,
bool ret_ty_is_generic, const uint32_t* ret_param_refs,
uint32_t ret_param_refs_len);
static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
uint32_t block_node, uint32_t param_block, uint32_t ret_ref,
const uint32_t* ret_body, uint32_t ret_body_len, uint32_t cc_ref,
const uint32_t* cc_body, uint32_t cc_body_len, const uint32_t* body,
uint32_t body_len, const uint32_t* param_insts, uint32_t param_insts_len,
uint32_t lbrace_line, uint32_t lbrace_column, bool is_var_args,
bool is_inferred_error, bool is_noinline, uint32_t noalias_bits,
bool ret_ty_is_generic, const uint32_t* ret_param_refs,
uint32_t ret_param_refs_len);
// Mirrors GenZir.endsWithNoReturn (AstGen.zig:11770). // Mirrors GenZir.endsWithNoReturn (AstGen.zig:11770).
static bool endsWithNoReturn(GenZir* gz) { static bool endsWithNoReturn(GenZir* gz) {
@@ -2759,7 +2776,11 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node);
#define COMPTIME_REASON_ALIGN 50 #define COMPTIME_REASON_ALIGN 50
#define COMPTIME_REASON_ADDRSPACE 51 #define COMPTIME_REASON_ADDRSPACE 51
#define COMPTIME_REASON_FIELD_NAME 42 #define COMPTIME_REASON_FIELD_NAME 42
#define COMPTIME_REASON_OPERAND_BRANCH_HINT 3
#define COMPTIME_REASON_OPERAND_SET_RUNTIME_SAFETY 4
#define COMPTIME_REASON_FUNCTION_RET_TY 39
#define COMPTIME_REASON_COMPTIME_KEYWORD 53 #define COMPTIME_REASON_COMPTIME_KEYWORD 53
#define COMPTIME_REASON_CALLCONV 49
#define COMPTIME_REASON_ARRAY_MUL_FACTOR 22 #define COMPTIME_REASON_ARRAY_MUL_FACTOR 22
#define COMPTIME_REASON_COMPILE_ERROR_STRING 19 #define COMPTIME_REASON_COMPILE_ERROR_STRING 19
#define COMPTIME_REASON_SWITCH_ITEM 56 #define COMPTIME_REASON_SWITCH_ITEM 56
@@ -3577,9 +3598,11 @@ static uint32_t builtinCall(
return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_FLOAT_CAST, return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_FLOAT_CAST,
node, result_type, operand), node); node, result_type, operand), node);
} }
// @errSetCast — extended error_cast (AstGen.zig:9454-9463). // @errSetCast / @errorCast — extended error_cast (AstGen.zig:9454-9463).
if (name_len == 10 if ((name_len == 10
&& memcmp(source + name_start, "errSetCast", 10) == 0) { && memcmp(source + name_start, "errSetCast", 10) == 0)
|| (name_len == 9
&& memcmp(source + name_start, "errorCast", 9) == 0)) {
emitDbgNode(gz, node); emitDbgNode(gz, node);
uint32_t result_type = rlResultTypeForCast(gz, rl, node); uint32_t result_type = rlResultTypeForCast(gz, rl, node);
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
@@ -3594,6 +3617,177 @@ static uint32_t builtinCall(
gz, (uint16_t)ZIR_EXT_ERROR_CAST, payload_index); gz, (uint16_t)ZIR_EXT_ERROR_CAST, payload_index);
return rvalue(gz, rl, result, node); return rvalue(gz, rl, result, node);
} }
// @ptrFromInt — typeCast (AstGen.zig:9413).
if (name_len == 10
&& memcmp(source + name_start, "ptrFromInt", 10) == 0) {
advanceSourceCursorToMainToken(ag, gz, node);
uint32_t saved_line = ag->source_line - gz->decl_line;
uint32_t saved_col = ag->source_column;
uint32_t result_type = rlResultTypeForCast(gz, rl, node);
AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs);
emitDbgStmt(gz, saved_line, saved_col);
return rvalue(gz, rl, addPlNodeBin(gz, ZIR_INST_PTR_FROM_INT,
node, result_type, operand), node);
}
// @Vector — type construction (AstGen.zig:9675).
if (name_len == 6 && memcmp(source + name_start, "Vector", 6) == 0) {
AstData nd = tree->nodes.datas[node];
ResultLoc u32_rl = { .tag = RL_COERCED_TY,
.data = ZIR_REF_U32_TYPE,
.src_node = 0,
.ctx = RI_CTX_NONE };
uint32_t len = comptimeExpr(
gz, scope, u32_rl, nd.lhs, COMPTIME_REASON_TYPE);
uint32_t elem_type = typeExpr(gz, scope, nd.rhs);
uint32_t result = addPlNodeBin(
gz, ZIR_INST_VECTOR_TYPE, node, len, elem_type);
return rvalue(gz, rl, result, node);
}
// @setRuntimeSafety — simpleUnOp (AstGen.zig:9392).
if (name_len == 16
&& memcmp(source + name_start, "setRuntimeSafety", 16) == 0) {
AstData nd = tree->nodes.datas[node];
ResultLoc bool_rl = { .tag = RL_COERCED_TY,
.data = ZIR_REF_BOOL_TYPE,
.src_node = 0,
.ctx = RI_CTX_NONE };
uint32_t operand = comptimeExpr(
gz, scope, bool_rl, nd.lhs,
COMPTIME_REASON_OPERAND_SET_RUNTIME_SAFETY);
addUnNode(gz, ZIR_INST_SET_RUNTIME_SAFETY, operand, node);
return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node);
}
// @intFromError — extended UnNode (AstGen.zig:9438-9444).
if (name_len == 12
&& memcmp(source + name_start, "intFromError", 12) == 0) {
AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs);
ensureExtraCapacity(ag, 2);
uint32_t payload_index = ag->extra_len;
ag->extra[ag->extra_len++]
= (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
ag->extra[ag->extra_len++] = operand;
uint32_t result = addExtendedPayload(
gz, (uint16_t)ZIR_EXT_INT_FROM_ERROR, payload_index);
return rvalue(gz, rl, result, node);
}
// @clz — bitBuiltin (AstGen.zig:9475).
if (name_len == 3 && memcmp(source + name_start, "clz", 3) == 0) {
advanceSourceCursorToMainToken(ag, gz, node);
uint32_t saved_line = ag->source_line - gz->decl_line;
uint32_t saved_col = ag->source_column;
AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs);
emitDbgStmt(gz, saved_line, saved_col);
uint32_t result = addUnNode(gz, ZIR_INST_CLZ, operand, node);
return rvalue(gz, rl, result, node);
}
// @branchHint — extended UnNode (AstGen.zig:9230-9239).
if (name_len == 10
&& memcmp(source + name_start, "branchHint", 10) == 0) {
AstData nd = tree->nodes.datas[node];
uint32_t hint_ty
= addBuiltinValue(gz, node, ZIR_BUILTIN_VALUE_BRANCH_HINT);
ResultLoc hint_rl = { .tag = RL_COERCED_TY,
.data = hint_ty, .src_node = 0, .ctx = RI_CTX_NONE };
uint32_t hint_val = comptimeExpr(
gz, scope, hint_rl, nd.lhs,
COMPTIME_REASON_OPERAND_BRANCH_HINT);
ensureExtraCapacity(ag, 2);
uint32_t payload_index = ag->extra_len;
ag->extra[ag->extra_len++]
= (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
ag->extra[ag->extra_len++] = hint_val;
addExtendedPayload(
gz, (uint16_t)ZIR_EXT_BRANCH_HINT, payload_index);
return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node);
}
// @bitSizeOf — simpleUnOpType (AstGen.zig:9382).
if (name_len == 9
&& memcmp(source + name_start, "bitSizeOf", 9) == 0) {
AstData nd = tree->nodes.datas[node];
uint32_t operand = typeExpr(gz, scope, nd.lhs);
uint32_t result
= addUnNode(gz, ZIR_INST_BIT_SIZE_OF, operand, node);
return rvalue(gz, rl, result, node);
}
// @fieldParentPtr — extended FieldParentPtr (AstGen.zig:9620-9628).
if (name_len == 14
&& memcmp(source + name_start, "fieldParentPtr", 14) == 0) {
AstData nd = tree->nodes.datas[node];
uint32_t parent_ptr_type = rlResultTypeForCast(gz, rl, node);
ResultLoc field_name_rl = { .tag = RL_COERCED_TY,
.data = ZIR_REF_SLICE_CONST_U8_TYPE,
.src_node = 0, .ctx = RI_CTX_NONE };
uint32_t field_name = comptimeExpr(
gz, scope, field_name_rl, nd.lhs, COMPTIME_REASON_FIELD_NAME);
uint32_t field_ptr = expr(gz, scope, nd.rhs);
ensureExtraCapacity(ag, 4);
uint32_t payload_index = ag->extra_len;
ag->extra[ag->extra_len++]
= (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
ag->extra[ag->extra_len++] = parent_ptr_type;
ag->extra[ag->extra_len++] = field_name;
ag->extra[ag->extra_len++] = field_ptr;
uint32_t result = addExtendedPayloadSmall(
gz, (uint16_t)ZIR_EXT_FIELD_PARENT_PTR, 0, payload_index);
return rvalue(gz, rl, result, node);
}
// @splat — AstGen.zig:9529-9537.
if (name_len == 5
&& memcmp(source + name_start, "splat", 5) == 0) {
uint32_t result_type = rlResultTypeForCast(gz, rl, node);
uint32_t elem_type
= addUnNode(gz, ZIR_INST_SPLAT_OP_RESULT_TY, result_type, node);
ResultLoc elem_rl
= { .tag = RL_TY, .data = elem_type, .src_node = 0,
.ctx = RI_CTX_NONE };
AstData nd = tree->nodes.datas[node];
uint32_t scalar = exprRl(gz, scope, elem_rl, nd.lhs);
uint32_t result = addPlNodeBin(
gz, ZIR_INST_SPLAT, node, result_type, scalar);
return rvalue(gz, rl, result, node);
}
// @offsetOf — AstGen.zig:9962-9978.
if (name_len == 8
&& memcmp(source + name_start, "offsetOf", 8) == 0) {
AstData nd = tree->nodes.datas[node];
uint32_t type_inst = typeExpr(gz, scope, nd.lhs);
ResultLoc field_name_rl = { .tag = RL_COERCED_TY,
.data = ZIR_REF_SLICE_CONST_U8_TYPE,
.src_node = 0, .ctx = RI_CTX_NONE };
uint32_t field_name = comptimeExpr(
gz, scope, field_name_rl, nd.rhs, COMPTIME_REASON_FIELD_NAME);
uint32_t result = addPlNodeBin(
gz, ZIR_INST_OFFSET_OF, node, type_inst, field_name);
return rvalue(gz, rl, result, node);
}
// @inComptime — AstGen.zig:9420-9424.
if (name_len == 10
&& memcmp(source + name_start, "inComptime", 10) == 0) {
if (gz->is_comptime) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
uint32_t result
= addNodeExtended(gz, (uint16_t)ZIR_EXT_IN_COMPTIME, node);
return rvalue(gz, rl, result, node);
}
// @errorFromInt — AstGen.zig:9446-9452.
if (name_len == 12
&& memcmp(source + name_start, "errorFromInt", 12) == 0) {
AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs);
ensureExtraCapacity(ag, 2);
uint32_t payload_index = ag->extra_len;
ag->extra[ag->extra_len++]
= (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index);
ag->extra[ag->extra_len++] = operand;
uint32_t result = addExtendedPayloadSmall(
gz, (uint16_t)ZIR_EXT_ERROR_FROM_INT, 0, payload_index);
return rvalue(gz, rl, result, node);
}
// clang-format on // clang-format on
// TODO: handle other builtins. // TODO: handle other builtins.
@@ -4297,6 +4491,370 @@ static uint32_t arrayTypeExpr(GenZir* gz, Scope* scope, uint32_t node) {
return addPlNodeBin(gz, ZIR_INST_ARRAY_TYPE, node, len, elem_type); return addPlNodeBin(gz, ZIR_INST_ARRAY_TYPE, node, len, elem_type);
} }
// --- arrayTypeSentinel (AstGen.zig:3965) ---
// Handles [N:sentinel]T array type expressions.
static uint32_t arrayTypeSentinelExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree;
AstData nd = tree->nodes.datas[node];
// data.lhs = length expression node, data.rhs = extra index.
uint32_t len_node = nd.lhs;
uint32_t extra_idx = nd.rhs;
uint32_t sentinel_node = tree->extra_data.arr[extra_idx]; // sentinel
uint32_t elem_type_node = tree->extra_data.arr[extra_idx + 1]; // elem_type
// Check for `_` identifier → compile error (AstGen.zig:3972-3975).
if (tree->nodes.tags[len_node] == AST_NODE_IDENTIFIER
&& isUnderscoreIdent(tree, len_node)) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
// Length expression (AstGen.zig:3977).
ResultLoc usize_rl = { .tag = RL_COERCED_TY,
.data = ZIR_REF_USIZE_TYPE,
.src_node = 0,
.ctx = RI_CTX_NONE };
uint32_t len = reachableExprComptime(
gz, scope, usize_rl, len_node, node, COMPTIME_REASON_ARRAY_LENGTH);
// Element type (AstGen.zig:3978).
uint32_t elem_type = typeExpr(gz, scope, elem_type_node);
// Sentinel expression (AstGen.zig:3979).
ResultLoc sentinel_rl = { .tag = RL_COERCED_TY,
.data = elem_type,
.src_node = 0,
.ctx = RI_CTX_NONE };
uint32_t sentinel = reachableExprComptime(gz, scope, sentinel_rl,
sentinel_node, node, COMPTIME_REASON_ARRAY_SENTINEL);
uint32_t result = addPlNodeTriple(
gz, ZIR_INST_ARRAY_TYPE_SENTINEL, node, len, elem_type, sentinel);
return rvalue(gz, rl, result, node);
}
// --- fnProtoExprInner (AstGen.zig:1313) ---
// Handles function type expressions: fn(params) RetType.
// Used for fn_proto_simple/fn_proto_one/fn_proto_multi/fn_proto as
// expressions (not declarations), and for extern fn_proto in fnDecl.
static uint32_t fnProtoExprInner(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, bool implicit_ccc) {
AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree;
AstNodeTag proto_tag = tree->nodes.tags[node];
AstData proto_data = tree->nodes.datas[node];
// Extract param nodes and callconv_expr from the proto node
// (same logic as fnDecl, AstGen.zig:4067-4136).
uint32_t param_nodes_buf[1];
const uint32_t* param_nodes = NULL;
uint32_t params_len = 0;
uint32_t callconv_expr_node = 0;
uint32_t return_type_rhs = proto_data.rhs;
if (proto_tag == AST_NODE_FN_PROTO_SIMPLE) {
if (proto_data.lhs != 0) {
param_nodes_buf[0] = proto_data.lhs;
param_nodes = param_nodes_buf;
params_len = 1;
}
} else if (proto_tag == AST_NODE_FN_PROTO_ONE) {
uint32_t extra_idx = proto_data.lhs;
uint32_t param = tree->extra_data.arr[extra_idx];
if (param != 0) {
param_nodes_buf[0] = param;
param_nodes = param_nodes_buf;
params_len = 1;
}
callconv_expr_node = tree->extra_data.arr[extra_idx + 4];
} else if (proto_tag == AST_NODE_FN_PROTO_MULTI) {
uint32_t extra_idx = proto_data.lhs;
uint32_t range_start = tree->extra_data.arr[extra_idx];
uint32_t range_end = tree->extra_data.arr[extra_idx + 1];
param_nodes = tree->extra_data.arr + range_start;
params_len = range_end - range_start;
} else if (proto_tag == AST_NODE_FN_PROTO) {
uint32_t extra_idx = proto_data.lhs;
uint32_t pstart = tree->extra_data.arr[extra_idx];
uint32_t pend = tree->extra_data.arr[extra_idx + 1];
param_nodes = tree->extra_data.arr + pstart;
params_len = pend - pstart;
callconv_expr_node = tree->extra_data.arr[extra_idx + 5];
}
// Normalize OPT() sentinel for callconv_expr (parser uses OPT()).
if (callconv_expr_node == UINT32_MAX)
callconv_expr_node = 0;
GenZir block_scope = makeSubBlock(gz, scope);
uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK_INLINE, gz, node);
// Parameter iteration (AstGen.zig:1329-1384).
// Token-based iterator matching Ast.zig:2680-2768.
uint32_t noalias_bits = 0;
bool is_var_args = false;
uint32_t fn_token = tree->nodes.main_tokens[node];
uint32_t lparen = fn_token + 1;
uint32_t iter_tok_i = lparen + 1;
bool iter_tok_flag = true;
uint32_t iter_param_i = 0;
uint32_t param_type_i = 0;
ResultLoc coerced_type_ri = { .tag = RL_COERCED_TY,
.data = ZIR_REF_TYPE_TYPE,
.src_node = 0,
.ctx = RI_CTX_NONE };
while (true) {
uint32_t name_token = 0;
uint32_t comptime_noalias_token = 0;
bool is_comptime_param = false;
bool is_anytype = false;
uint32_t param_type_node = 0;
if (!iter_tok_flag) {
if (iter_param_i >= params_len)
break;
param_type_node = param_nodes[iter_param_i];
uint32_t tok_i = firstToken(tree, param_type_node);
while (tok_i > 0) {
tok_i--;
uint32_t ttag = tree->tokens.tags[tok_i];
if (ttag == TOKEN_COLON)
continue;
if (ttag == TOKEN_IDENTIFIER) {
name_token = tok_i;
continue;
}
if (ttag == TOKEN_KEYWORD_COMPTIME
|| ttag == TOKEN_KEYWORD_NOALIAS) {
comptime_noalias_token = tok_i;
continue;
}
break;
}
iter_param_i++;
iter_tok_i = lastToken(tree, param_type_node) + 1;
if (tree->tokens.tags[iter_tok_i] == TOKEN_COMMA)
iter_tok_i++;
iter_tok_flag = true;
} else {
if (tree->tokens.tags[iter_tok_i] == TOKEN_COMMA)
iter_tok_i++;
if (tree->tokens.tags[iter_tok_i] == TOKEN_R_PAREN)
break;
while (tree->tokens.tags[iter_tok_i] == TOKEN_DOC_COMMENT)
iter_tok_i++;
if (tree->tokens.tags[iter_tok_i] == TOKEN_ELLIPSIS3) {
is_var_args = true;
break;
}
if (tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_COMPTIME
|| tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_NOALIAS) {
comptime_noalias_token = iter_tok_i;
iter_tok_i++;
}
if (tree->tokens.tags[iter_tok_i] == TOKEN_IDENTIFIER
&& tree->tokens.tags[iter_tok_i + 1] == TOKEN_COLON) {
name_token = iter_tok_i;
iter_tok_i += 2;
}
if (tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_ANYTYPE) {
is_anytype = true;
iter_tok_i++;
} else {
iter_tok_flag = false;
continue;
}
}
// Determine noalias/comptime (AstGen.zig:1334-1342).
if (comptime_noalias_token != 0
&& tree->tokens.tags[comptime_noalias_token]
== TOKEN_KEYWORD_NOALIAS) {
if (param_type_i < 32)
noalias_bits |= (1u << param_type_i);
}
if (comptime_noalias_token != 0
&& tree->tokens.tags[comptime_noalias_token]
== TOKEN_KEYWORD_COMPTIME) {
is_comptime_param = true;
}
// Param name (AstGen.zig:1352-1357).
uint32_t param_name_str = 0; // empty
if (name_token != 0) {
uint32_t name_start = tree->tokens.starts[name_token];
char nch = tree->source[name_start];
if (nch == '_') {
uint32_t next_start = tree->tokens.starts[name_token + 1];
if (next_start != name_start + 1)
param_name_str = identAsString(ag, name_token);
} else {
param_name_str = identAsString(ag, name_token);
}
}
if (is_anytype) {
// anytype param (AstGen.zig:1359-1366).
uint32_t anytype_name_token
= name_token != 0 ? name_token : (iter_tok_i - 1);
ZirInstTag anytype_tag = is_comptime_param
? ZIR_INST_PARAM_ANYTYPE_COMPTIME
: ZIR_INST_PARAM_ANYTYPE;
addStrTok(
&block_scope, anytype_tag, param_name_str, anytype_name_token);
} else {
// Typed param (AstGen.zig:1367-1381).
GenZir param_gz = makeSubBlock(&block_scope, scope);
param_gz.is_comptime = true;
uint32_t param_type_ref = fullBodyExpr(
&param_gz, scope, coerced_type_ri, param_type_node);
if (ag->has_compile_errors) {
gzUnstack(&param_gz);
gzUnstack(&block_scope);
return ZIR_REF_VOID_VALUE;
}
// break_inline target is the param inst we're about to create
// (AstGen.zig:1373-1374).
uint32_t param_inst_expected = ag->inst_len + 1;
makeBreakInline(&param_gz, param_inst_expected, param_type_ref,
(int32_t)param_type_node - (int32_t)param_gz.decl_node_index);
uint32_t name_tok_for_src = name_token != 0
? name_token
: tree->nodes.main_tokens[param_type_node];
ZirInstTag param_tag
= is_comptime_param ? ZIR_INST_PARAM_COMPTIME : ZIR_INST_PARAM;
// prev_param_insts = &.{}, is_generic = false for fn proto exprs
// (AstGen.zig:1377-1380).
uint32_t param_inst = addParam(&block_scope, &param_gz, param_tag,
name_tok_for_src, param_name_str, false);
(void)param_inst_expected;
(void)param_inst;
}
param_type_i++;
}
// Calling convention (AstGen.zig:1386-1397).
uint32_t cc_ref = ZIR_REF_NONE;
if (callconv_expr_node != 0) {
uint32_t cc_ty = addBuiltinValue(&block_scope, callconv_expr_node,
ZIR_BUILTIN_VALUE_CALLING_CONVENTION);
ResultLoc cc_ri = { .tag = RL_COERCED_TY,
.data = cc_ty,
.src_node = 0,
.ctx = RI_CTX_NONE };
cc_ref = comptimeExpr(&block_scope, scope, cc_ri, callconv_expr_node,
COMPTIME_REASON_CALLCONV);
} else if (implicit_ccc) {
cc_ref = addBuiltinValue(
&block_scope, node, ZIR_BUILTIN_VALUE_CALLING_CONVENTION_C);
}
// Return type (AstGen.zig:1399-1400).
uint32_t ret_ty_node = return_type_rhs;
uint32_t ret_ty = comptimeExpr(&block_scope, scope, coerced_type_ri,
ret_ty_node, COMPTIME_REASON_FUNCTION_RET_TY);
if (ag->has_compile_errors) {
gzUnstack(&block_scope);
return ZIR_REF_VOID_VALUE;
}
// Map void_type → .none (AstGen.zig:12054).
if (ret_ty == ZIR_REF_VOID_TYPE)
ret_ty = ZIR_REF_NONE;
// addFunc with no body (AstGen.zig:1402-1422).
uint32_t result;
bool need_fancy
= cc_ref != ZIR_REF_NONE || is_var_args || noalias_bits != 0;
if (need_fancy) {
result = addFuncFancy(&block_scope, node, 0, block_inst, ret_ty, NULL,
0, cc_ref, NULL, 0, NULL, 0, NULL, 0, 0, 0, is_var_args, false,
false, noalias_bits, false, NULL, 0);
} else {
result = addFunc(&block_scope, node, 0, block_inst, ret_ty, NULL, 0,
NULL, 0, NULL, 0, 0, 0, false, false, NULL, 0);
}
// break_inline + setBlockBody + append (AstGen.zig:1424-1426).
makeBreakInline(&block_scope, block_inst, result, AST_NODE_OFFSET_NONE);
setBlockBody(ag, &block_scope, block_inst);
gzAppendInstruction(gz, block_inst);
return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node);
}
// --- fnProtoExpr (AstGen.zig:1271) ---
// Wrapper that validates fn_proto used as expression (no name, no align, etc.)
// then calls fnProtoExprInner.
static uint32_t fnProtoExpr(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree;
AstNodeTag proto_tag = tree->nodes.tags[node];
AstData proto_data = tree->nodes.datas[node];
// Validate: no name token (AstGen.zig:1281-1283).
// fn_proto_simple main_token is 'fn', next token would be name or '('.
// If there's a name, main_token+1 is an identifier before '('.
// For function type expressions, fn keyword is followed by '('.
// name_token check: upstream checks fn_proto.name_token which is
// derived from AST node. For fn_proto_simple, name_token is null.
// We just skip this validation since the parser already handles it.
// Validate: no align/addrspace/section (AstGen.zig:1285-1295).
// These are only present in fn_proto_one and fn_proto.
if (proto_tag == AST_NODE_FN_PROTO_ONE) {
uint32_t extra_idx = proto_data.lhs;
uint32_t align_expr = tree->extra_data.arr[extra_idx + 1];
uint32_t addrspace_expr = tree->extra_data.arr[extra_idx + 2];
uint32_t section_expr = tree->extra_data.arr[extra_idx + 3];
if (align_expr != UINT32_MAX && align_expr != 0) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
if (addrspace_expr != UINT32_MAX && addrspace_expr != 0) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
if (section_expr != UINT32_MAX && section_expr != 0) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
} else if (proto_tag == AST_NODE_FN_PROTO) {
uint32_t extra_idx = proto_data.lhs;
uint32_t align_expr = tree->extra_data.arr[extra_idx + 2];
uint32_t addrspace_expr = tree->extra_data.arr[extra_idx + 3];
uint32_t section_expr = tree->extra_data.arr[extra_idx + 4];
if (align_expr != UINT32_MAX && align_expr != 0) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
if (addrspace_expr != UINT32_MAX && addrspace_expr != 0) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
if (section_expr != UINT32_MAX && section_expr != 0) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
}
// Validate: no inferred error set (AstGen.zig:1297-1302).
uint32_t return_type_node = proto_data.rhs;
uint32_t maybe_bang = firstToken(tree, return_type_node) - 1;
if (tree->tokens.tags[maybe_bang] == TOKEN_BANG) {
SET_ERROR(ag);
return ZIR_REF_VOID_VALUE;
}
return fnProtoExprInner(gz, scope, rl, node, false);
}
// --- arrayInitExpr (AstGen.zig:1431) --- // --- arrayInitExpr (AstGen.zig:1431) ---
// Handles typed array init: [_]T{...}, [_:s]T{...}, and [N]T{...}. // Handles typed array init: [_]T{...}, [_:s]T{...}, and [N]T{...}.
@@ -5468,6 +6026,15 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
// array_type (AstGen.zig:940). // array_type (AstGen.zig:940).
case AST_NODE_ARRAY_TYPE: case AST_NODE_ARRAY_TYPE:
return rvalue(gz, rl, arrayTypeExpr(gz, scope, node), node); return rvalue(gz, rl, arrayTypeExpr(gz, scope, node), node);
// array_type_sentinel (AstGen.zig:3965).
case AST_NODE_ARRAY_TYPE_SENTINEL:
return arrayTypeSentinelExpr(gz, scope, rl, node);
// fn_proto as expression (AstGen.zig:1271-1311).
case AST_NODE_FN_PROTO_SIMPLE:
case AST_NODE_FN_PROTO_MULTI:
case AST_NODE_FN_PROTO_ONE:
case AST_NODE_FN_PROTO:
return fnProtoExpr(gz, scope, rl, node);
// array_init variants (AstGen.zig:836-856). // array_init variants (AstGen.zig:836-856).
case AST_NODE_ARRAY_INIT: case AST_NODE_ARRAY_INIT:
case AST_NODE_ARRAY_INIT_COMMA: case AST_NODE_ARRAY_INIT_COMMA:
@@ -11364,11 +11931,19 @@ static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
uint32_t ret_param_refs_len) { uint32_t ret_param_refs_len) {
AstGenCtx* ag = gz->astgen; AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
// SrcLocs only emitted when there's a body (AstGen.zig:12081-12108).
uint32_t src_locs_len = 0;
uint32_t rbrace_line = 0;
uint32_t rbrace_column = 0;
if (body_len > 0) {
uint32_t rbrace_tok = lastToken(tree, block_node); uint32_t rbrace_tok = lastToken(tree, block_node);
uint32_t rbrace_start = tree->tokens.starts[rbrace_tok]; uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
advanceSourceCursor(ag, rbrace_start); advanceSourceCursor(ag, rbrace_start);
uint32_t rbrace_line = ag->source_line - gz->decl_line; rbrace_line = ag->source_line - gz->decl_line;
uint32_t rbrace_column = ag->source_column; rbrace_column = ag->source_column;
src_locs_len = 7;
}
// Build Func payload (Zir.Inst.Func: ret_ty, param_block, body_len). // Build Func payload (Zir.Inst.Func: ret_ty, param_block, body_len).
// (AstGen.zig:12182-12194) // (AstGen.zig:12182-12194)
@@ -11388,7 +11963,8 @@ static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
uint32_t fixup_body_len = countBodyLenAfterFixupsExtraRefs( uint32_t fixup_body_len = countBodyLenAfterFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len); ag, body, body_len, param_insts, param_insts_len);
ensureExtraCapacity(ag, 3 + ret_ty_packed_len + fixup_body_len + 7); ensureExtraCapacity(
ag, 3 + ret_ty_packed_len + fixup_body_len + src_locs_len);
uint32_t payload_index = ag->extra_len; uint32_t payload_index = ag->extra_len;
ag->extra[ag->extra_len++] = ret_ty_packed; // Func.ret_ty ag->extra[ag->extra_len++] = ret_ty_packed; // Func.ret_ty
ag->extra[ag->extra_len++] = param_block; // Func.param_block ag->extra[ag->extra_len++] = param_block; // Func.param_block
@@ -11408,7 +11984,8 @@ static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
appendBodyWithFixupsExtraRefs( appendBodyWithFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len); ag, body, body_len, param_insts, param_insts_len);
// SrcLocs (AstGen.zig:12098-12106). // SrcLocs + proto_hash only when body present (AstGen.zig:12081-12108).
if (body_len > 0) {
uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16); uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
ag->extra[ag->extra_len++] = lbrace_line; ag->extra[ag->extra_len++] = lbrace_line;
ag->extra[ag->extra_len++] = rbrace_line; ag->extra[ag->extra_len++] = rbrace_line;
@@ -11418,6 +11995,7 @@ static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node,
ag->extra[ag->extra_len++] = 0; ag->extra[ag->extra_len++] = 0;
ag->extra[ag->extra_len++] = 0; ag->extra[ag->extra_len++] = 0;
ag->extra[ag->extra_len++] = 0; ag->extra[ag->extra_len++] = 0;
}
// Emit the func instruction (AstGen.zig:12220-12226). // Emit the func instruction (AstGen.zig:12220-12226).
ZirInstTag tag ZirInstTag tag
@@ -11443,11 +12021,19 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
uint32_t ret_param_refs_len) { uint32_t ret_param_refs_len) {
AstGenCtx* ag = gz->astgen; AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
// SrcLocs only emitted when there's a body (AstGen.zig:12081-12108).
uint32_t src_locs_len = 0;
uint32_t rbrace_line = 0;
uint32_t rbrace_column = 0;
if (body_len > 0) {
uint32_t rbrace_tok = lastToken(tree, block_node); uint32_t rbrace_tok = lastToken(tree, block_node);
uint32_t rbrace_start = tree->tokens.starts[rbrace_tok]; uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
advanceSourceCursor(ag, rbrace_start); advanceSourceCursor(ag, rbrace_start);
uint32_t rbrace_line = ag->source_line - gz->decl_line; rbrace_line = ag->source_line - gz->decl_line;
uint32_t rbrace_column = ag->source_column; rbrace_column = ag->source_column;
src_locs_len = 7;
}
uint32_t fixup_body_len = countBodyLenAfterFixupsExtraRefs( uint32_t fixup_body_len = countBodyLenAfterFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len); ag, body, body_len, param_insts, param_insts_len);
@@ -11472,7 +12058,7 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
// FuncFancy has 3 fields: param_block, body_len, bits. // FuncFancy has 3 fields: param_block, body_len, bits.
uint32_t total_extra = 3 + cc_extra_len + ret_extra_len uint32_t total_extra = 3 + cc_extra_len + ret_extra_len
+ ((noalias_bits != 0) ? 1u : 0u) + fixup_body_len + 7; + ((noalias_bits != 0) ? 1u : 0u) + fixup_body_len + src_locs_len;
ensureExtraCapacity(ag, total_extra); ensureExtraCapacity(ag, total_extra);
// FuncFancy payload (Zir.zig:2589-2610). // FuncFancy payload (Zir.zig:2589-2610).
@@ -11530,7 +12116,8 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
appendBodyWithFixupsExtraRefs( appendBodyWithFixupsExtraRefs(
ag, body, body_len, param_insts, param_insts_len); ag, body, body_len, param_insts, param_insts_len);
// SrcLocs (AstGen.zig:12098-12106). // SrcLocs + proto_hash only when body present (AstGen.zig:12081-12108).
if (body_len > 0) {
uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16); uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
ag->extra[ag->extra_len++] = lbrace_line; ag->extra[ag->extra_len++] = lbrace_line;
ag->extra[ag->extra_len++] = rbrace_line; ag->extra[ag->extra_len++] = rbrace_line;
@@ -11540,6 +12127,7 @@ static uint32_t addFuncFancy(GenZir* gz, uint32_t src_node,
ag->extra[ag->extra_len++] = 0; ag->extra[ag->extra_len++] = 0;
ag->extra[ag->extra_len++] = 0; ag->extra[ag->extra_len++] = 0;
ag->extra[ag->extra_len++] = 0; ag->extra[ag->extra_len++] = 0;
}
// Emit the func_fancy instruction (AstGen.zig:12220-12226). // Emit the func_fancy instruction (AstGen.zig:12220-12226).
ZirInstData data; ZirInstData data;
@@ -11718,6 +12306,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
// (Ast.zig:2003-2025, AstGen.zig:4102-4106, 4240-4247). // (Ast.zig:2003-2025, AstGen.zig:4102-4106, 4240-4247).
bool is_pub = false; bool is_pub = false;
bool is_export = false; bool is_export = false;
bool is_extern = false;
bool is_noinline = false; bool is_noinline = false;
bool has_inline_keyword = false; bool has_inline_keyword = false;
for (uint32_t i = fn_token; i > 0;) { for (uint32_t i = fn_token; i > 0;) {
@@ -11727,6 +12316,8 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
is_pub = true; is_pub = true;
else if (ttag == TOKEN_KEYWORD_EXPORT) else if (ttag == TOKEN_KEYWORD_EXPORT)
is_export = true; is_export = true;
else if (ttag == TOKEN_KEYWORD_EXTERN)
is_extern = true;
else if (ttag == TOKEN_KEYWORD_NOINLINE) else if (ttag == TOKEN_KEYWORD_NOINLINE)
is_noinline = true; is_noinline = true;
else if (ttag == TOKEN_KEYWORD_INLINE) else if (ttag == TOKEN_KEYWORD_INLINE)
@@ -12121,21 +12712,54 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
gzUnstack(&cc_gz); gzUnstack(&cc_gz);
// --- Body handling --- // --- Body handling ---
// For fn_proto* (no body): extern function, emit type only // For fn_proto* (no body): extern function type
// (AstGen.zig:4136-4164). // (AstGen.zig:4136-4164).
// For fn_decl (has body): emit function value (AstGen.zig:4197-4201). // For fn_decl (has body): emit function value (AstGen.zig:4197-4201).
uint32_t func_ref; uint32_t func_ref;
if (body_node == 0) { if (body_node == 0) {
// fn_proto without body: extern function type. // fn_proto without body: extern function type.
// Upstream emits fnProtoExprInner; we SET_ERROR for now as // Upstream calls fnProtoExprInner with implicit_ccc=true.
// fnProtoExprInner is not yet ported. // We use the already-computed params/ret but add implicit CCC
// TODO: implement fnProtoExprInner for extern fn support. // if no explicit callconv was provided (AstGen.zig:1394-1396).
SET_ERROR(ag); if (cc_ref == ZIR_REF_NONE && !has_inline_keyword) {
// Extern fn without explicit callconv: implicit C calling
// convention (AstGen.zig:1394-1396 via fnProtoExprInner).
cc_ref = addBuiltinValue(
&decl_gz, node, ZIR_BUILTIN_VALUE_CALLING_CONVENTION_C);
}
// Emit func instruction with no body (AstGen.zig:1402-1422).
bool need_fancy
= cc_ref != ZIR_REF_NONE || is_var_args || noalias_bits != 0;
if (need_fancy) {
func_ref = addFuncFancy(&decl_gz, node, 0, decl_inst, ret_ref,
ret_body, ret_body_len, cc_ref, cc_body, cc_body_len, NULL, 0,
param_insts, param_insts_len, 0, 0, is_var_args, false, false,
noalias_bits, ret_ty_is_generic, ret_param_refs,
ret_param_refs_len);
} else {
func_ref = addFunc(&decl_gz, node, 0, decl_inst, ret_ref, ret_body,
ret_body_len, NULL, 0, param_insts, param_insts_len, 0, 0,
false, ret_ty_is_generic, ret_param_refs, ret_param_refs_len);
}
// Patch ret_body/cc_body break_inlines (AstGen.zig:12199-12202).
if (ret_body_len > 0) {
uint32_t break_inst = ret_body[ret_body_len - 1];
uint32_t break_payload
= ag->inst_datas[break_inst].break_data.payload_index;
ag->extra[break_payload + 1] = func_ref - ZIR_REF_START_INDEX;
}
if (cc_body_len > 0) {
uint32_t break_inst = cc_body[cc_body_len - 1];
uint32_t break_payload
= ag->inst_datas[break_inst].break_data.payload_index;
ag->extra[break_payload + 1] = func_ref - ZIR_REF_START_INDEX;
}
free(ret_body); free(ret_body);
free(cc_body); free(cc_body);
gzUnstack(&decl_gz); // break_inline from decl_gz to decl_inst (AstGen.zig:4163).
ag->within_fn = prev_within_fn; makeBreakInline(&decl_gz, decl_inst, func_ref,
return; (int32_t)node - (int32_t)proto_node);
goto fn_decl_finish;
} }
// --- Body (AstGen.zig:4415-4424) --- // --- Body (AstGen.zig:4415-4424) ---
@@ -12264,10 +12888,14 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
makeBreakInline( makeBreakInline(
&decl_gz, decl_inst, func_ref, (int32_t)node - (int32_t)proto_node); &decl_gz, decl_inst, func_ref, (int32_t)node - (int32_t)proto_node);
fn_decl_finish:
// setDeclaration (AstGen.zig:4208-4225). // setDeclaration (AstGen.zig:4208-4225).
// Linkage: export > normal (AstGen.zig:4217). // Linkage: extern > export > normal (AstGen.zig:4217).
;
DeclFlagsId decl_id; DeclFlagsId decl_id;
if (is_export) if (is_extern)
decl_id = is_pub ? DECL_ID_PUB_EXTERN_CONST : DECL_ID_EXTERN_CONST;
else if (is_export)
decl_id = is_pub ? DECL_ID_PUB_EXPORT_CONST : DECL_ID_EXPORT_CONST; decl_id = is_pub ? DECL_ID_PUB_EXPORT_CONST : DECL_ID_EXPORT_CONST;
else else
decl_id = is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE; decl_id = is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE;
@@ -13151,21 +13779,20 @@ static uint32_t containerDecl(
else if (prev_tag == TOKEN_KEYWORD_EXTERN) else if (prev_tag == TOKEN_KEYWORD_EXTERN)
layout = 1; layout = 1;
} }
decl_inst = structDeclInner(ag, gz, node, members, members_len, layout, decl_inst = structDeclInner(ag, gz, scope, node, members, members_len,
arg_node, name_strategy); layout, arg_node, name_strategy);
break; break;
} }
case TOKEN_KEYWORD_ENUM: case TOKEN_KEYWORD_ENUM:
decl_inst = enumDeclInner( decl_inst = enumDeclInner(ag, gz, scope, node, members, members_len,
ag, gz, node, members, members_len, arg_node, name_strategy); arg_node, name_strategy);
break; break;
default: default:
// union/opaque: fall back to struct for now. // union/opaque: fall back to struct for now.
decl_inst = structDeclInner( decl_inst = structDeclInner(
ag, gz, node, members, members_len, 0, 0, name_strategy); ag, gz, scope, node, members, members_len, 0, 0, name_strategy);
break; break;
} }
(void)scope;
ag->fn_block = prev_fn_block; ag->fn_block = prev_fn_block;
return decl_inst + ZIR_REF_START_INDEX; return decl_inst + ZIR_REF_START_INDEX;
@@ -13269,9 +13896,9 @@ static bool tokenIsUnderscore(const Ast* tree, uint32_t ident_token) {
// Handles enum container declarations. // Handles enum container declarations.
// arg_node: the tag type expression node (e.g. u8 in enum(u8)), 0 if none. // arg_node: the tag type expression node (e.g. u8 in enum(u8)), 0 if none.
static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
const uint32_t* members, uint32_t members_len, uint32_t arg_node, uint32_t node, const uint32_t* members, uint32_t members_len,
uint8_t name_strategy) { uint32_t arg_node, uint8_t name_strategy) {
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
// --- First pass: count fields, values, decls, detect nonexhaustive --- // --- First pass: count fields, values, decls, detect nonexhaustive ---
@@ -13307,8 +13934,7 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// Create namespace scope (AstGen.zig:5618-5623). // Create namespace scope (AstGen.zig:5618-5623).
ScopeNamespace namespace; ScopeNamespace namespace;
scopeNamespaceInit( scopeNamespaceInit(&namespace, scope, node, decl_inst, gz, ag->within_fn);
&namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
advanceSourceCursorToNode(ag, node); advanceSourceCursorToNode(ag, node);
@@ -13449,9 +14075,10 @@ static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// --- tupleDecl (AstGen.zig:5192) --- // --- tupleDecl (AstGen.zig:5192) ---
static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, Scope* scope,
const uint32_t* members, uint32_t members_len, uint8_t layout, uint32_t node, const uint32_t* members, uint32_t members_len,
uint32_t backing_int_node) { uint8_t layout, uint32_t backing_int_node) {
(void)scope;
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
// layout must be auto for tuples (AstGen.zig:5204-5207). // layout must be auto for tuples (AstGen.zig:5204-5207).
@@ -13614,9 +14241,9 @@ static uint32_t tupleDecl(AstGenCtx* ag, GenZir* gz, uint32_t node,
// --- structDeclInner (AstGen.zig:4926) --- // --- structDeclInner (AstGen.zig:4926) ---
static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, Scope* scope,
const uint32_t* members, uint32_t members_len, uint8_t layout, uint32_t node, const uint32_t* members, uint32_t members_len,
uint32_t backing_int_node, uint8_t name_strategy) { uint8_t layout, uint32_t backing_int_node, uint8_t name_strategy) {
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
// Tuple detection (AstGen.zig:4939-4950). // Tuple detection (AstGen.zig:4939-4950).
@@ -13638,8 +14265,8 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
SET_ERROR(ag); SET_ERROR(ag);
return reserveInstructionIndex(ag); return reserveInstructionIndex(ag);
} }
return tupleDecl( return tupleDecl(ag, gz, scope, node, members, members_len, layout,
ag, gz, node, members, members_len, layout, backing_int_node); backing_int_node);
} }
} }
@@ -13660,8 +14287,7 @@ static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node,
// Create namespace scope (AstGen.zig:4973-4979). // Create namespace scope (AstGen.zig:4973-4979).
ScopeNamespace namespace; ScopeNamespace namespace;
scopeNamespaceInit( scopeNamespaceInit(&namespace, scope, node, decl_inst, gz, ag->within_fn);
&namespace, &gz->base, node, decl_inst, gz, ag->within_fn);
advanceSourceCursorToNode(ag, node); advanceSourceCursorToNode(ag, node);
@@ -15246,8 +15872,8 @@ Zir astGen(const Ast* ast) {
const uint32_t* members = ast->extra_data.arr + members_start; const uint32_t* members = ast->extra_data.arr + members_start;
uint32_t members_len = members_end - members_start; uint32_t members_len = members_end - members_start;
structDeclInner( structDeclInner(&ag, &gen_scope, &gen_scope.base, 0, members, members_len,
&ag, &gen_scope, 0, members, members_len, 0, 0, 0 /* parent */); 0, 0, 0 /* parent */);
// Write imports list (AstGen.zig:227-244). // Write imports list (AstGen.zig:227-244).
writeImports(&ag); writeImports(&ag);

View File

@@ -297,11 +297,7 @@ fn expectEqualZir(gpa: Allocator, ref: Zir, got: c.Zir) !void {
const got_tag: u8 = @intCast(got.inst_tags[i]); const got_tag: u8 = @intCast(got.inst_tags[i]);
if (ref_tag != got_tag) { if (ref_tag != got_tag) {
std.debug.print("first divergence at [{d}]: ref_tag={d} got_tag={d}\n", .{ i, 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. // Data printing skipped to avoid tagged union safety panics.
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. // Scan for nearest declaration.
var j: usize = i; var j: usize = i;
while (j > 0) { while (j > 0) {