astgen: typeCast DBG_STMT, builtinEvalToError, memset/memcpy fixes

- Add emitDbgStmt and result type from RL to typeCast builtins
  (@intCast, @truncate, @ptrCast, @enumFromInt, @bitCast)
- Pass ResultLoc to builtinCall for result type access
- Fix @memset: upstream derives elem_ty via typeof+indexable_ptr_elem_type
  and evaluates value with coerced_ty RL
- Fix @memcpy/@memset to return void_value (not instruction ref)
- Add builtinEvalToError: per-builtin eval_to_error lookup instead of
  always returning MAYBE for all builtins
- Fix nodeMayAppendToErrorTrace: pass loop var 'n' to nodeMayEvalToError
  instead of original 'node' parameter

Corpus: ref=4177 got=4160, mismatch at inst[557], gap=17

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 15:09:25 +00:00
parent 0d9afc0ae6
commit c525da4553

255
astgen.c
View File

@@ -217,6 +217,7 @@ typedef struct {
uint32_t decl_node_index; uint32_t decl_node_index;
uint32_t decl_line; uint32_t decl_line;
bool is_comptime; bool is_comptime;
bool is_inline; // true for inline for/while, labeled blocks in comptime
bool c_import; // true inside @cImport block bool c_import; // true inside @cImport block
uint32_t instructions_top; // start index in shared array uint32_t instructions_top; // start index in shared array
uint32_t break_block; // UINT32_MAX = none (AstGen.zig:11780) uint32_t break_block; // UINT32_MAX = none (AstGen.zig:11780)
@@ -842,11 +843,11 @@ static uint32_t addBreak(GenZir* gz, ZirInstTag tag, uint32_t block_inst,
// Mirrors GenZir.addCondBr (AstGen.zig:12834). // Mirrors GenZir.addCondBr (AstGen.zig:12834).
// Creates condbr instruction placeholder with src_node set. // Creates condbr instruction placeholder with src_node set.
// Payload is filled later by setCondBrPayload. // Payload is filled later by setCondBrPayload.
static uint32_t addCondBr(GenZir* gz, uint32_t node) { static uint32_t addCondBr(GenZir* gz, ZirInstTag tag, uint32_t node) {
AstGenCtx* ag = gz->astgen; AstGenCtx* ag = gz->astgen;
ensureInstCapacity(ag, 1); ensureInstCapacity(ag, 1);
uint32_t idx = ag->inst_len; uint32_t idx = ag->inst_len;
ag->inst_tags[idx] = ZIR_INST_CONDBR; ag->inst_tags[idx] = tag;
ZirInstData data; ZirInstData data;
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index;
@@ -1690,7 +1691,8 @@ static uint32_t simpleCBuiltin(GenZir* gz, Scope* scope, uint32_t node,
} }
// Mirrors builtinCall (AstGen.zig:9191) dispatch. // Mirrors builtinCall (AstGen.zig:9191) dispatch.
static uint32_t builtinCall(GenZir* gz, Scope* scope, uint32_t node) { static uint32_t builtinCall(
GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
AstGenCtx* ag = gz->astgen; AstGenCtx* ag = gz->astgen;
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
@@ -1719,12 +1721,17 @@ static uint32_t builtinCall(GenZir* gz, Scope* scope, uint32_t node) {
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
return simpleCBuiltin(gz, scope, node, nd.lhs, (uint16_t)ZIR_EXT_C_INCLUDE); return simpleCBuiltin(gz, scope, node, nd.lhs, (uint16_t)ZIR_EXT_C_INCLUDE);
} }
// @intCast (AstGen.zig:9416). // @intCast — typeCast pattern (AstGen.zig:9416, 9807-9826).
if (name_len == 7 && memcmp(source + name_start, "intCast", 7) == 0) { if (name_len == 7 && memcmp(source + name_start, "intCast", 7) == 0) {
advanceSourceCursorToMainToken(ag, node);
uint32_t saved_line = ag->source_line - gz->decl_line;
uint32_t saved_col = ag->source_column;
uint32_t result_type = rlResultType(gz, rl, node);
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs); uint32_t operand = expr(gz, scope, nd.lhs);
emitDbgStmt(gz, saved_line, saved_col);
return addPlNodeBin(gz, ZIR_INST_INT_CAST, node, return addPlNodeBin(gz, ZIR_INST_INT_CAST, node,
ZIR_REF_NONE, operand); result_type, operand);
} }
// @embedFile (AstGen.zig:9626). // @embedFile (AstGen.zig:9626).
if (name_len == 9 && memcmp(source + name_start, "embedFile", 9) == 0) { if (name_len == 9 && memcmp(source + name_start, "embedFile", 9) == 0) {
@@ -1753,47 +1760,74 @@ static uint32_t builtinCall(GenZir* gz, Scope* scope, uint32_t node) {
uint32_t operand = expr(gz, scope, nd.rhs); uint32_t operand = expr(gz, scope, nd.rhs);
return addPlNodeBin(gz, ZIR_INST_AS_NODE, node, dest_type, operand); return addPlNodeBin(gz, ZIR_INST_AS_NODE, node, dest_type, operand);
} }
// @truncate (AstGen.zig:9416). // @truncate — typeCast pattern (AstGen.zig:9417, 9807-9826).
if (name_len == 8 && memcmp(source + name_start, "truncate", 8) == 0) { if (name_len == 8 && memcmp(source + name_start, "truncate", 8) == 0) {
advanceSourceCursorToMainToken(ag, node);
uint32_t saved_line = ag->source_line - gz->decl_line;
uint32_t saved_col = ag->source_column;
uint32_t result_type = rlResultType(gz, rl, node);
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs); uint32_t operand = expr(gz, scope, nd.lhs);
emitDbgStmt(gz, saved_line, saved_col);
return addPlNodeBin(gz, ZIR_INST_TRUNCATE, node, return addPlNodeBin(gz, ZIR_INST_TRUNCATE, node,
ZIR_REF_NONE, operand); result_type, operand);
} }
// @ptrCast (AstGen.zig:9416). // @ptrCast — typeCast pattern (AstGen.zig:9056, 9807-9826).
if (name_len == 7 && memcmp(source + name_start, "ptrCast", 7) == 0) { if (name_len == 7 && memcmp(source + name_start, "ptrCast", 7) == 0) {
advanceSourceCursorToMainToken(ag, node);
uint32_t saved_line = ag->source_line - gz->decl_line;
uint32_t saved_col = ag->source_column;
uint32_t result_type = rlResultType(gz, rl, node);
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs); uint32_t operand = expr(gz, scope, nd.lhs);
emitDbgStmt(gz, saved_line, saved_col);
return addPlNodeBin(gz, ZIR_INST_PTR_CAST, node, return addPlNodeBin(gz, ZIR_INST_PTR_CAST, node,
ZIR_REF_NONE, operand); result_type, operand);
} }
// @enumFromInt (AstGen.zig:9480). // @enumFromInt — typeCast pattern (AstGen.zig:9414, 9807-9826).
if (name_len == 11 && memcmp(source + name_start, "enumFromInt", 11) == 0) { if (name_len == 11 && memcmp(source + name_start, "enumFromInt", 11) == 0) {
advanceSourceCursorToMainToken(ag, node);
uint32_t saved_line = ag->source_line - gz->decl_line;
uint32_t saved_col = ag->source_column;
uint32_t result_type = rlResultType(gz, rl, node);
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs); uint32_t operand = expr(gz, scope, nd.lhs);
emitDbgStmt(gz, saved_line, saved_col);
return addPlNodeBin(gz, ZIR_INST_ENUM_FROM_INT, node, return addPlNodeBin(gz, ZIR_INST_ENUM_FROM_INT, node,
ZIR_REF_NONE, operand); result_type, operand);
} }
// @bitCast (AstGen.zig:9416). // @bitCast — typeCast pattern (AstGen.zig:9416, 9807-9826).
if (name_len == 7 && memcmp(source + name_start, "bitCast", 7) == 0) { if (name_len == 7 && memcmp(source + name_start, "bitCast", 7) == 0) {
advanceSourceCursorToMainToken(ag, node);
uint32_t saved_line = ag->source_line - gz->decl_line;
uint32_t saved_col = ag->source_column;
uint32_t result_type = rlResultType(gz, rl, node);
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
uint32_t operand = expr(gz, scope, nd.lhs); uint32_t operand = expr(gz, scope, nd.lhs);
emitDbgStmt(gz, saved_line, saved_col);
return addPlNodeBin(gz, ZIR_INST_BITCAST, node, return addPlNodeBin(gz, ZIR_INST_BITCAST, node,
ZIR_REF_NONE, operand); result_type, operand);
} }
// @memcpy (AstGen.zig:9586). // @memcpy (AstGen.zig:9631-9637).
if (name_len == 6 && memcmp(source + name_start, "memcpy", 6) == 0) { if (name_len == 6 && memcmp(source + name_start, "memcpy", 6) == 0) {
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
uint32_t dst = expr(gz, scope, nd.lhs); uint32_t dst = expr(gz, scope, nd.lhs);
uint32_t src = expr(gz, scope, nd.rhs); uint32_t src = expr(gz, scope, nd.rhs);
return addPlNodeBin(gz, ZIR_INST_MEMCPY, node, dst, src); addPlNodeBin(gz, ZIR_INST_MEMCPY, node, dst, src);
return ZIR_REF_VOID_VALUE;
} }
// @memset (AstGen.zig:9582). // @memset (AstGen.zig:9638-9647).
if (name_len == 6 && memcmp(source + name_start, "memset", 6) == 0) { if (name_len == 6 && memcmp(source + name_start, "memset", 6) == 0) {
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
uint32_t dst = expr(gz, scope, nd.lhs); uint32_t lhs = expr(gz, scope, nd.lhs);
uint32_t val = expr(gz, scope, nd.rhs); uint32_t lhs_ty = addUnNode(gz, ZIR_INST_TYPEOF, lhs, nd.lhs);
return addPlNodeBin(gz, ZIR_INST_MEMSET, node, dst, val); uint32_t elem_ty =
addUnNode(gz, ZIR_INST_INDEXABLE_PTR_ELEM_TYPE, lhs_ty, nd.lhs);
ResultLoc val_rl = {
.tag = RL_COERCED_TY, .data = elem_ty, .src_node = 0};
uint32_t val = exprRl(gz, scope, val_rl, nd.rhs);
addPlNodeBin(gz, ZIR_INST_MEMSET, node, lhs, val);
return ZIR_REF_VOID_VALUE;
} }
// @min (AstGen.zig:9155). // @min (AstGen.zig:9155).
if (name_len == 3 && memcmp(source + name_start, "min", 3) == 0) { if (name_len == 3 && memcmp(source + name_start, "min", 3) == 0) {
@@ -1837,13 +1871,45 @@ static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node) {
tok_end++; tok_end++;
uint32_t tok_len = tok_end - tok_start; uint32_t tok_len = tok_end - tok_start;
// Check well-known primitive refs (primitive_instrs map, AstGen.zig:8300). // Check well-known primitive refs (primitive_instrs map,
// AstGen.zig:10236-10281).
// clang-format off // clang-format off
if (tok_len == 2 && memcmp(source+tok_start, "u1", 2) == 0) return ZIR_REF_U1_TYPE;
if (tok_len == 2 && memcmp(source+tok_start, "u8", 2) == 0) return ZIR_REF_U8_TYPE; if (tok_len == 2 && memcmp(source+tok_start, "u8", 2) == 0) return ZIR_REF_U8_TYPE;
if (tok_len == 2 && memcmp(source+tok_start, "i8", 2) == 0) return ZIR_REF_I8_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "u16", 3) == 0) return ZIR_REF_U16_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "i16", 3) == 0) return ZIR_REF_I16_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "u29", 3) == 0) return ZIR_REF_U29_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "u32", 3) == 0) return ZIR_REF_U32_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "i32", 3) == 0) return ZIR_REF_I32_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "u64", 3) == 0) return ZIR_REF_U64_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "i64", 3) == 0) return ZIR_REF_I64_TYPE;
if (tok_len == 4 && memcmp(source+tok_start, "u128", 4) == 0) return ZIR_REF_U128_TYPE;
if (tok_len == 4 && memcmp(source+tok_start, "i128", 4) == 0) return ZIR_REF_I128_TYPE;
if (tok_len == 5 && memcmp(source+tok_start, "usize", 5) == 0) return ZIR_REF_USIZE_TYPE; if (tok_len == 5 && memcmp(source+tok_start, "usize", 5) == 0) return ZIR_REF_USIZE_TYPE;
if (tok_len == 5 && memcmp(source+tok_start, "isize", 5) == 0) return ZIR_REF_ISIZE_TYPE;
if (tok_len == 6 && memcmp(source+tok_start, "c_char", 6) == 0) return ZIR_REF_C_CHAR_TYPE;
if (tok_len == 7 && memcmp(source+tok_start, "c_short", 7) == 0) return ZIR_REF_C_SHORT_TYPE;
if (tok_len == 8 && memcmp(source+tok_start, "c_ushort", 8) == 0) return ZIR_REF_C_USHORT_TYPE;
if (tok_len == 5 && memcmp(source+tok_start, "c_int", 5) == 0) return ZIR_REF_C_INT_TYPE;
if (tok_len == 6 && memcmp(source+tok_start, "c_uint", 6) == 0) return ZIR_REF_C_UINT_TYPE;
if (tok_len == 6 && memcmp(source+tok_start, "c_long", 6) == 0) return ZIR_REF_C_LONG_TYPE;
if (tok_len == 7 && memcmp(source+tok_start, "c_ulong", 7) == 0) return ZIR_REF_C_ULONG_TYPE;
if (tok_len == 10 && memcmp(source+tok_start, "c_longlong", 10) == 0) return ZIR_REF_C_LONGLONG_TYPE;
if (tok_len == 11 && memcmp(source+tok_start, "c_ulonglong", 11) == 0) return ZIR_REF_C_ULONGLONG_TYPE;
if (tok_len == 14 && memcmp(source+tok_start, "comptime_float", 14) == 0) return ZIR_REF_COMPTIME_FLOAT_TYPE;
if (tok_len == 12 && memcmp(source+tok_start, "comptime_int", 12) == 0) return ZIR_REF_COMPTIME_INT_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "f16", 3) == 0) return ZIR_REF_F16_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "f32", 3) == 0) return ZIR_REF_F32_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "f64", 3) == 0) return ZIR_REF_F64_TYPE;
if (tok_len == 3 && memcmp(source+tok_start, "f80", 3) == 0) return ZIR_REF_F80_TYPE;
if (tok_len == 4 && memcmp(source+tok_start, "f128", 4) == 0) return ZIR_REF_F128_TYPE;
if (tok_len == 9 && memcmp(source+tok_start, "anyopaque", 9) == 0) return ZIR_REF_ANYOPAQUE_TYPE;
if (tok_len == 4 && memcmp(source+tok_start, "bool", 4) == 0) return ZIR_REF_BOOL_TYPE; if (tok_len == 4 && memcmp(source+tok_start, "bool", 4) == 0) return ZIR_REF_BOOL_TYPE;
if (tok_len == 4 && memcmp(source+tok_start, "void", 4) == 0) return ZIR_REF_VOID_TYPE; if (tok_len == 4 && memcmp(source+tok_start, "void", 4) == 0) return ZIR_REF_VOID_TYPE;
if (tok_len == 6 && memcmp(source+tok_start, "c_uint", 6) == 0) return ZIR_REF_C_UINT_TYPE; if (tok_len == 4 && memcmp(source+tok_start, "type", 4) == 0) return ZIR_REF_TYPE_TYPE;
if (tok_len == 8 && memcmp(source+tok_start, "anyerror", 8) == 0) return ZIR_REF_ANYERROR_TYPE;
if (tok_len == 8 && memcmp(source+tok_start, "noreturn", 8) == 0) return ZIR_REF_NORETURN_TYPE;
if (tok_len == 4 && memcmp(source+tok_start, "true", 4) == 0) return ZIR_REF_BOOL_TRUE; if (tok_len == 4 && memcmp(source+tok_start, "true", 4) == 0) return ZIR_REF_BOOL_TRUE;
if (tok_len == 5 && memcmp(source+tok_start, "false", 5) == 0) return ZIR_REF_BOOL_FALSE; if (tok_len == 5 && memcmp(source+tok_start, "false", 5) == 0) return ZIR_REF_BOOL_FALSE;
if (tok_len == 4 && memcmp(source+tok_start, "null", 4) == 0) return ZIR_REF_NULL_VALUE; if (tok_len == 4 && memcmp(source+tok_start, "null", 4) == 0) return ZIR_REF_NULL_VALUE;
@@ -1886,7 +1952,7 @@ static uint32_t identifierExpr(
// Check for primitive types FIRST (AstGen.zig:8298-8338). // Check for primitive types FIRST (AstGen.zig:8298-8338).
uint32_t prim = tryResolvePrimitiveIdent(gz, node); uint32_t prim = tryResolvePrimitiveIdent(gz, node);
if (prim != ZIR_REF_NONE) if (prim != ZIR_REF_NONE)
return prim; return rvalue(gz, rl, prim, node);
// Scope chain walk (AstGen.zig:8340-8461). // Scope chain walk (AstGen.zig:8340-8461).
uint32_t name_str = identAsString(ag, ident_token); uint32_t name_str = identAsString(ag, ident_token);
@@ -2819,7 +2885,7 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
return rvalue(gz, rl, numberLiteral(gz, node), node); return rvalue(gz, rl, numberLiteral(gz, node), node);
case AST_NODE_BUILTIN_CALL_TWO: case AST_NODE_BUILTIN_CALL_TWO:
case AST_NODE_BUILTIN_CALL_TWO_COMMA: case AST_NODE_BUILTIN_CALL_TWO_COMMA:
return rvalue(gz, rl, builtinCall(gz, scope, node), node); return rvalue(gz, rl, builtinCall(gz, scope, rl, node), node);
case AST_NODE_FIELD_ACCESS: case AST_NODE_FIELD_ACCESS:
return fieldAccessExpr(gz, scope, rl, node); return fieldAccessExpr(gz, scope, rl, node);
case AST_NODE_IDENTIFIER: case AST_NODE_IDENTIFIER:
@@ -3177,7 +3243,7 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
} }
if (block_inst != UINT32_MAX) { if (block_inst != UINT32_MAX) {
// Found target (AstGen.zig:2188-2228). // Found target (AstGen.zig:2188-2228).
ZirInstTag break_tag = block_gz->is_comptime ZirInstTag break_tag = block_gz->is_inline
? ZIR_INST_BREAK_INLINE ? ZIR_INST_BREAK_INLINE
: ZIR_INST_BREAK; : ZIR_INST_BREAK;
if (opt_rhs == 0) { if (opt_rhs == 0) {
@@ -3245,7 +3311,10 @@ static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
GenZir* gz2 = (GenZir*)s; GenZir* gz2 = (GenZir*)s;
if (gz2->continue_block != UINT32_MAX) { if (gz2->continue_block != UINT32_MAX) {
genDefers(gz, s, scope, DEFER_NORMAL_ONLY); genDefers(gz, s, scope, DEFER_NORMAL_ONLY);
addBreak(gz, ZIR_INST_BREAK, gz2->continue_block, ZirInstTag break_tag = gz2->is_inline
? ZIR_INST_BREAK_INLINE
: ZIR_INST_BREAK;
addBreak(gz, break_tag, gz2->continue_block,
ZIR_REF_VOID_VALUE, ZIR_REF_VOID_VALUE,
(int32_t)node - (int32_t)gz->decl_node_index); (int32_t)node - (int32_t)gz->decl_node_index);
return ZIR_REF_UNREACHABLE_VALUE; return ZIR_REF_UNREACHABLE_VALUE;
@@ -3480,6 +3549,7 @@ static uint32_t blockExprExpr(
gzAppendInstruction(gz, block_inst); gzAppendInstruction(gz, block_inst);
GenZir block_scope = makeSubBlock(gz, scope); GenZir block_scope = makeSubBlock(gz, scope);
block_scope.is_inline = force_comptime; // AstGen.zig:2503
if (force_comptime) if (force_comptime)
block_scope.is_comptime = true; block_scope.is_comptime = true;
// Set label on block_scope (AstGen.zig:2504-2508). // Set label on block_scope (AstGen.zig:2504-2508).
@@ -3736,7 +3806,7 @@ static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) {
bool_bit = cond_inst; bool_bit = cond_inst;
} }
uint32_t condbr = addCondBr(&block_scope, node); uint32_t condbr = addCondBr(&block_scope, ZIR_INST_CONDBR, node);
uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node);
setBlockBody(ag, &block_scope, block_inst); setBlockBody(ag, &block_scope, block_inst);
gzAppendInstruction(gz, block_inst); gzAppendInstruction(gz, block_inst);
@@ -3852,6 +3922,11 @@ static uint32_t forExpr(
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
AstNodeTag node_tag = tree->nodes.tags[node]; AstNodeTag node_tag = tree->nodes.tags[node];
// Detect inline keyword (AstGen.zig:6847).
uint32_t main_token = tree->nodes.main_tokens[node];
bool is_inline = (main_token > 0
&& tree->tokens.tags[main_token - 1] == TOKEN_KEYWORD_INLINE);
// Extract input nodes and body/else nodes. // Extract input nodes and body/else nodes.
// FOR_SIMPLE: lhs = input node, rhs = body (Ast.zig:1960-1968). // FOR_SIMPLE: lhs = input node, rhs = body (Ast.zig:1960-1968).
// FOR: lhs = extra_data index, rhs = packed AstFor (Ast.zig:1970-1981). // FOR: lhs = extra_data index, rhs = packed AstFor (Ast.zig:1970-1981).
@@ -3881,8 +3956,9 @@ static uint32_t forExpr(
uint32_t lens[FOR_MAX_INPUTS][2]; // [ref0, ref1] per input uint32_t lens[FOR_MAX_INPUTS][2]; // [ref0, ref1] per input
// Allocate index counter (AstGen.zig:6865-6874). // Allocate index counter (AstGen.zig:6865-6874).
uint32_t index_ptr ZirInstTag alloc_tag
= addUnNode(gz, ZIR_INST_ALLOC, ZIR_REF_USIZE_TYPE, node); = is_inline ? ZIR_INST_ALLOC_COMPTIME_MUT : ZIR_INST_ALLOC;
uint32_t index_ptr = addUnNode(gz, alloc_tag, ZIR_REF_USIZE_TYPE, node);
addPlNodeBin(gz, ZIR_INST_STORE_NODE, node, index_ptr, ZIR_REF_ZERO_USIZE); addPlNodeBin(gz, ZIR_INST_STORE_NODE, node, index_ptr, ZIR_REF_ZERO_USIZE);
// Compute payload_token (AstGen.zig fullForComponents:2349-2350). // Compute payload_token (AstGen.zig fullForComponents:2349-2350).
@@ -3967,9 +4043,11 @@ static uint32_t forExpr(
} }
// Create loop (AstGen.zig:6944-6956). // Create loop (AstGen.zig:6944-6956).
uint32_t loop_inst = makeBlockInst(ag, ZIR_INST_LOOP, gz, node); ZirInstTag loop_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_LOOP;
uint32_t loop_inst = makeBlockInst(ag, loop_tag, gz, node);
GenZir loop_scope = makeSubBlock(gz, scope); GenZir loop_scope = makeSubBlock(gz, scope);
loop_scope.is_inline = is_inline;
// Load index (AstGen.zig:6955-6956). // Load index (AstGen.zig:6955-6956).
uint32_t index = addUnNode(&loop_scope, ZIR_INST_LOAD, index_ptr, node); uint32_t index = addUnNode(&loop_scope, ZIR_INST_LOAD, index_ptr, node);
@@ -3980,8 +4058,11 @@ static uint32_t forExpr(
// Create condbr + block (AstGen.zig:6967-6974). // Create condbr + block (AstGen.zig:6967-6974).
GenZir cond_scope = makeSubBlock(&loop_scope, &loop_scope.base); GenZir cond_scope = makeSubBlock(&loop_scope, &loop_scope.base);
uint32_t condbr = addCondBr(&cond_scope, node); ZirInstTag condbr_tag
uint32_t cond_block = makeBlockInst(ag, ZIR_INST_BLOCK, &loop_scope, node); = is_inline ? ZIR_INST_CONDBR_INLINE : ZIR_INST_CONDBR;
uint32_t condbr = addCondBr(&cond_scope, condbr_tag, node);
ZirInstTag block_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_BLOCK;
uint32_t cond_block = makeBlockInst(ag, block_tag, &loop_scope, node);
setBlockBody(ag, &cond_scope, cond_block); setBlockBody(ag, &cond_scope, cond_block);
loop_scope.break_block = loop_inst; loop_scope.break_block = loop_inst;
gzAppendInstruction(&loop_scope, cond_block); gzAppendInstruction(&loop_scope, cond_block);
@@ -4068,12 +4149,13 @@ static uint32_t forExpr(
addInstruction(gz, ZIR_INST_EXTENDED, ext_data); addInstruction(gz, ZIR_INST_EXTENDED, ext_data);
} }
addBreak(&then_scope, ZIR_INST_BREAK, cond_block, ZIR_REF_VOID_VALUE, ZirInstTag break_tag = is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK;
addBreak(&then_scope, break_tag, cond_block, ZIR_REF_VOID_VALUE,
AST_NODE_OFFSET_NONE); AST_NODE_OFFSET_NONE);
// Else branch: break out of loop (AstGen.zig:7066-7091). // Else branch: break out of loop (AstGen.zig:7066-7091).
GenZir else_scope = makeSubBlock(&loop_scope, &loop_scope.base); GenZir else_scope = makeSubBlock(&loop_scope, &loop_scope.base);
addBreak(&else_scope, ZIR_INST_BREAK, loop_inst, ZIR_REF_VOID_VALUE, addBreak(&else_scope, break_tag, loop_inst, ZIR_REF_VOID_VALUE,
AST_NODE_OFFSET_NONE); AST_NODE_OFFSET_NONE);
setCondBrPayload(ag, condbr, cond, &then_scope, &else_scope); setCondBrPayload(ag, condbr, cond, &then_scope, &else_scope);
@@ -4084,12 +4166,14 @@ static uint32_t forExpr(
addPlNodeBin( addPlNodeBin(
&loop_scope, ZIR_INST_STORE_NODE, node, index_ptr, index_plus_one); &loop_scope, ZIR_INST_STORE_NODE, node, index_ptr, index_plus_one);
// Repeat (AstGen.zig:7112). // Repeat (AstGen.zig:7110-7111).
{ {
ZirInstTag repeat_tag
= is_inline ? ZIR_INST_REPEAT_INLINE : ZIR_INST_REPEAT;
ZirInstData repeat_data; ZirInstData repeat_data;
memset(&repeat_data, 0, sizeof(repeat_data)); memset(&repeat_data, 0, sizeof(repeat_data));
repeat_data.node = (int32_t)node - (int32_t)loop_scope.decl_node_index; repeat_data.node = (int32_t)node - (int32_t)loop_scope.decl_node_index;
addInstruction(&loop_scope, ZIR_INST_REPEAT, repeat_data); addInstruction(&loop_scope, repeat_tag, repeat_data);
} }
setBlockBody(ag, &loop_scope, loop_inst); setBlockBody(ag, &loop_scope, loop_inst);
@@ -4128,7 +4212,7 @@ static uint32_t orelseCatchExpr(
uint32_t condition = addUnNode(&block_scope, test_tag, operand, node); uint32_t condition = addUnNode(&block_scope, test_tag, operand, node);
// condbr in block_scope (AstGen.zig:6076). // condbr in block_scope (AstGen.zig:6076).
uint32_t condbr = addCondBr(&block_scope, node); uint32_t condbr = addCondBr(&block_scope, ZIR_INST_CONDBR, node);
// Create block in parent gz (AstGen.zig:6078-6081). // Create block in parent gz (AstGen.zig:6078-6081).
uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node);
@@ -4174,36 +4258,47 @@ static uint32_t whileExpr(
const Ast* tree = ag->tree; const Ast* tree = ag->tree;
AstData nd = tree->nodes.datas[node]; AstData nd = tree->nodes.datas[node];
// Detect inline keyword (AstGen.zig:6558).
uint32_t main_token = tree->nodes.main_tokens[node];
bool is_inline = (main_token > 0
&& tree->tokens.tags[main_token - 1] == TOKEN_KEYWORD_INLINE);
// WHILE_SIMPLE: lhs = cond_expr, rhs = body. // WHILE_SIMPLE: lhs = cond_expr, rhs = body.
uint32_t cond_node = nd.lhs; uint32_t cond_node = nd.lhs;
uint32_t body_node = nd.rhs; uint32_t body_node = nd.rhs;
// Create loop instruction (AstGen.zig:6562-6564). // Create loop instruction (AstGen.zig:6562-6564).
uint32_t loop_inst = makeBlockInst(ag, ZIR_INST_LOOP, gz, node); ZirInstTag loop_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_LOOP;
uint32_t loop_inst = makeBlockInst(ag, loop_tag, gz, node);
gzAppendInstruction(gz, loop_inst); gzAppendInstruction(gz, loop_inst);
GenZir loop_scope = makeSubBlock(gz, scope); GenZir loop_scope = makeSubBlock(gz, scope);
loop_scope.is_inline = is_inline;
// Evaluate condition in cond_scope (AstGen.zig:6571-6607). // Evaluate condition in cond_scope (AstGen.zig:6571-6607).
GenZir cond_scope = makeSubBlock(&loop_scope, &loop_scope.base); GenZir cond_scope = makeSubBlock(&loop_scope, &loop_scope.base);
uint32_t cond = expr(&cond_scope, &cond_scope.base, cond_node); uint32_t cond = expr(&cond_scope, &cond_scope.base, cond_node);
// Create condbr + cond_block (AstGen.zig:6609-6615). // Create condbr + cond_block (AstGen.zig:6609-6615).
uint32_t condbr = addCondBr(&cond_scope, node); ZirInstTag condbr_tag
uint32_t cond_block = makeBlockInst(ag, ZIR_INST_BLOCK, &loop_scope, node); = is_inline ? ZIR_INST_CONDBR_INLINE : ZIR_INST_CONDBR;
uint32_t condbr = addCondBr(&cond_scope, condbr_tag, node);
ZirInstTag block_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_BLOCK;
uint32_t cond_block = makeBlockInst(ag, block_tag, &loop_scope, node);
setBlockBody(ag, &cond_scope, cond_block); // unstacks cond_scope setBlockBody(ag, &cond_scope, cond_block); // unstacks cond_scope
gzAppendInstruction(&loop_scope, cond_block); gzAppendInstruction(&loop_scope, cond_block);
// Create continue_block (AstGen.zig:6694). // Create continue_block (AstGen.zig:6694).
uint32_t continue_block uint32_t continue_block = makeBlockInst(ag, block_tag, &loop_scope, node);
= makeBlockInst(ag, ZIR_INST_BLOCK, &loop_scope, node);
// Add repeat to loop_scope (AstGen.zig:6696-6697). // Add repeat to loop_scope (AstGen.zig:6696-6697).
{ {
ZirInstTag repeat_tag
= is_inline ? ZIR_INST_REPEAT_INLINE : ZIR_INST_REPEAT;
ZirInstData repeat_data; ZirInstData repeat_data;
memset(&repeat_data, 0, sizeof(repeat_data)); memset(&repeat_data, 0, sizeof(repeat_data));
repeat_data.node = (int32_t)node - (int32_t)loop_scope.decl_node_index; repeat_data.node = (int32_t)node - (int32_t)loop_scope.decl_node_index;
addInstruction(&loop_scope, ZIR_INST_REPEAT, repeat_data); addInstruction(&loop_scope, repeat_tag, repeat_data);
} }
// Set loop body and configure break/continue (AstGen.zig:6699-6701). // Set loop body and configure break/continue (AstGen.zig:6699-6701).
@@ -4238,19 +4333,29 @@ static uint32_t whileExpr(
ext_data.extended.operand = 0; ext_data.extended.operand = 0;
addInstruction(gz, ZIR_INST_EXTENDED, ext_data); addInstruction(gz, ZIR_INST_EXTENDED, ext_data);
} }
addBreak(&continue_scope, ZIR_INST_BREAK, continue_block, ZirInstTag break_tag
= is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK;
addBreak(&continue_scope, break_tag, continue_block,
ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE);
} }
setBlockBody(ag, &continue_scope, continue_block); setBlockBody(ag, &continue_scope, continue_block);
// Break cond_block from then_scope (AstGen.zig:7064). // Break cond_block from then_scope (AstGen.zig:7064).
addBreak(&then_scope, ZIR_INST_BREAK, cond_block, ZIR_REF_VOID_VALUE, {
AST_NODE_OFFSET_NONE); ZirInstTag break_tag
= is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK;
addBreak(&then_scope, break_tag, cond_block, ZIR_REF_VOID_VALUE,
AST_NODE_OFFSET_NONE);
}
// Else scope: break loop with void (AstGen.zig:6785-6788). // Else scope: break loop with void (AstGen.zig:6785-6788).
GenZir else_scope = makeSubBlock(gz, &cond_scope.base); GenZir else_scope = makeSubBlock(gz, &cond_scope.base);
addBreak(&else_scope, ZIR_INST_BREAK, loop_inst, ZIR_REF_VOID_VALUE, {
AST_NODE_OFFSET_NONE); ZirInstTag break_tag
= is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK;
addBreak(&else_scope, break_tag, loop_inst, ZIR_REF_VOID_VALUE,
AST_NODE_OFFSET_NONE);
}
// Wire up condbr (AstGen.zig:6795). // Wire up condbr (AstGen.zig:6795).
setCondBrPayload(ag, condbr, cond, &then_scope, &else_scope); setCondBrPayload(ag, condbr, cond, &then_scope, &else_scope);
@@ -4703,6 +4808,37 @@ static void assignOp(
addPlNodeBin(gz, ZIR_INST_STORE_NODE, infix_node, lhs_ptr, result); addPlNodeBin(gz, ZIR_INST_STORE_NODE, infix_node, lhs_ptr, result);
} }
// --- builtinEvalToError (BuiltinFn.zig) ---
// Returns per-builtin eval_to_error. Default is .never; only a few are
// .maybe or .always. Mirrors BuiltinFn.list lookup in AstGen.zig:10539.
static int builtinEvalToError(const Ast* tree, uint32_t node) {
uint32_t main_tok = tree->nodes.main_tokens[node];
uint32_t tok_start = tree->tokens.starts[main_tok];
const char* source = tree->source;
uint32_t name_start = tok_start + 1; // skip '@'
uint32_t name_end = name_start;
while (name_end < tree->source_len
&& ((source[name_end] >= 'a' && source[name_end] <= 'z')
|| (source[name_end] >= 'A' && source[name_end] <= 'Z')
|| source[name_end] == '_')) {
name_end++;
}
uint32_t name_len = name_end - name_start;
const char* name = source + name_start;
// clang-format off
// .always:
if (name_len == 12 && memcmp(name, "errorFromInt", 12) == 0)
return 1; // EVAL_TO_ERROR_ALWAYS
// .maybe:
if (name_len == 2 && memcmp(name, "as", 2) == 0) return 2;
if (name_len == 4 && memcmp(name, "call", 4) == 0) return 2;
if (name_len == 5 && memcmp(name, "field", 5) == 0) return 2;
if (name_len == 9 && memcmp(name, "errorCast", 9) == 0) return 2;
// clang-format on
// Default: .never
return 0;
}
// --- nodeMayEvalToError (AstGen.zig:10340) --- // --- nodeMayEvalToError (AstGen.zig:10340) ---
// Three-way result: 0=never, 1=always, 2=maybe. // Three-way result: 0=never, 1=always, 2=maybe.
#define EVAL_TO_ERROR_NEVER 0 #define EVAL_TO_ERROR_NEVER 0
@@ -4760,12 +4896,13 @@ static int nodeMayEvalToError(const Ast* tree, uint32_t node) {
return EVAL_TO_ERROR_MAYBE; return EVAL_TO_ERROR_MAYBE;
return EVAL_TO_ERROR_NEVER; return EVAL_TO_ERROR_NEVER;
} }
// Builtins: simplified — return maybe for safety. // Builtins: look up per-builtin eval_to_error
// (AstGen.zig:10530-10541).
case AST_NODE_BUILTIN_CALL: case AST_NODE_BUILTIN_CALL:
case AST_NODE_BUILTIN_CALL_COMMA: case AST_NODE_BUILTIN_CALL_COMMA:
case AST_NODE_BUILTIN_CALL_TWO: case AST_NODE_BUILTIN_CALL_TWO:
case AST_NODE_BUILTIN_CALL_TWO_COMMA: case AST_NODE_BUILTIN_CALL_TWO_COMMA:
return EVAL_TO_ERROR_MAYBE; return builtinEvalToError(tree, n);
// Everything else: .never // Everything else: .never
default: default:
return EVAL_TO_ERROR_NEVER; return EVAL_TO_ERROR_NEVER;
@@ -4796,7 +4933,7 @@ static bool nodeMayAppendToErrorTrace(const Ast* tree, uint32_t node) {
continue; continue;
// Anything else: check if it may eval to error. // Anything else: check if it may eval to error.
default: default:
return nodeMayEvalToError(tree, node) != EVAL_TO_ERROR_NEVER; return nodeMayEvalToError(tree, n) != EVAL_TO_ERROR_NEVER;
} }
} }
} }
@@ -4910,12 +5047,20 @@ static void varDecl(GenZir* gz, Scope* scope, uint32_t node,
// --- CONST path (AstGen.zig:3232-3340) --- // --- CONST path (AstGen.zig:3232-3340) ---
if (!nodesNeedRlContains(ag, node)) { if (!nodesNeedRlContains(ag, node)) {
// Rvalue path (AstGen.zig:3246-3271). // Rvalue path (AstGen.zig:3246-3271).
// Evaluate type annotation if present (AstGen.zig:3248). // Evaluate type annotation and build result_info
if (type_node != 0) // (AstGen.zig:3247-3250).
(void)typeExpr(gz, scope, type_node); ResultLoc result_info;
if (type_node != 0) {
uint32_t type_ref = typeExpr(gz, scope, type_node);
result_info = (ResultLoc) {
.tag = RL_TY, .data = type_ref, .src_node = 0
};
} else {
result_info = RL_NONE_VAL;
}
// Evaluate init expression (AstGen.zig:3259-3264). // Evaluate init expression (AstGen.zig:3251-3252).
uint32_t init_ref = expr(gz, scope, init_node); uint32_t init_ref = exprRl(gz, scope, result_info, init_node);
if (ag->has_compile_errors) if (ag->has_compile_errors)
return; return;