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:
784
stage0/astgen.c
784
stage0/astgen.c
@@ -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(
|
||||||
|
¶m_gz, scope, coerced_type_ri, param_type_node);
|
||||||
|
if (ag->has_compile_errors) {
|
||||||
|
gzUnstack(¶m_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(¶m_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, ¶m_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;
|
||||||
uint32_t rbrace_tok = lastToken(tree, block_node);
|
|
||||||
uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
|
// SrcLocs only emitted when there's a body (AstGen.zig:12081-12108).
|
||||||
advanceSourceCursor(ag, rbrace_start);
|
uint32_t src_locs_len = 0;
|
||||||
uint32_t rbrace_line = ag->source_line - gz->decl_line;
|
uint32_t rbrace_line = 0;
|
||||||
uint32_t rbrace_column = ag->source_column;
|
uint32_t rbrace_column = 0;
|
||||||
|
if (body_len > 0) {
|
||||||
|
uint32_t rbrace_tok = lastToken(tree, block_node);
|
||||||
|
uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
|
||||||
|
advanceSourceCursor(ag, rbrace_start);
|
||||||
|
rbrace_line = ag->source_line - gz->decl_line;
|
||||||
|
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,16 +11984,18 @@ 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).
|
||||||
uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
|
if (body_len > 0) {
|
||||||
ag->extra[ag->extra_len++] = lbrace_line;
|
uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
|
||||||
ag->extra[ag->extra_len++] = rbrace_line;
|
ag->extra[ag->extra_len++] = lbrace_line;
|
||||||
ag->extra[ag->extra_len++] = columns;
|
ag->extra[ag->extra_len++] = rbrace_line;
|
||||||
// proto_hash (4 words): zero for now.
|
ag->extra[ag->extra_len++] = columns;
|
||||||
ag->extra[ag->extra_len++] = 0;
|
// proto_hash (4 words): zero for now.
|
||||||
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;
|
||||||
|
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;
|
||||||
uint32_t rbrace_tok = lastToken(tree, block_node);
|
|
||||||
uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
|
// SrcLocs only emitted when there's a body (AstGen.zig:12081-12108).
|
||||||
advanceSourceCursor(ag, rbrace_start);
|
uint32_t src_locs_len = 0;
|
||||||
uint32_t rbrace_line = ag->source_line - gz->decl_line;
|
uint32_t rbrace_line = 0;
|
||||||
uint32_t rbrace_column = ag->source_column;
|
uint32_t rbrace_column = 0;
|
||||||
|
if (body_len > 0) {
|
||||||
|
uint32_t rbrace_tok = lastToken(tree, block_node);
|
||||||
|
uint32_t rbrace_start = tree->tokens.starts[rbrace_tok];
|
||||||
|
advanceSourceCursor(ag, rbrace_start);
|
||||||
|
rbrace_line = ag->source_line - gz->decl_line;
|
||||||
|
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,16 +12116,18 @@ 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).
|
||||||
uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
|
if (body_len > 0) {
|
||||||
ag->extra[ag->extra_len++] = lbrace_line;
|
uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16);
|
||||||
ag->extra[ag->extra_len++] = rbrace_line;
|
ag->extra[ag->extra_len++] = lbrace_line;
|
||||||
ag->extra[ag->extra_len++] = columns;
|
ag->extra[ag->extra_len++] = rbrace_line;
|
||||||
// proto_hash (4 words): zero for now.
|
ag->extra[ag->extra_len++] = columns;
|
||||||
ag->extra[ag->extra_len++] = 0;
|
// proto_hash (4 words): zero for now.
|
||||||
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;
|
||||||
|
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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user