diff --git a/astgen.c b/astgen.c index fd8ab7b2af..42545ec308 100644 --- a/astgen.c +++ b/astgen.c @@ -217,6 +217,7 @@ typedef struct { uint32_t decl_node_index; uint32_t decl_line; bool is_comptime; + bool is_inline; // true for inline for/while, labeled blocks in comptime bool c_import; // true inside @cImport block uint32_t instructions_top; // start index in shared array 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). // Creates condbr instruction placeholder with src_node set. // 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; ensureInstCapacity(ag, 1); uint32_t idx = ag->inst_len; - ag->inst_tags[idx] = ZIR_INST_CONDBR; + ag->inst_tags[idx] = tag; ZirInstData data; memset(&data, 0, sizeof(data)); 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. -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; 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]; 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) { + 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]; uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); return addPlNodeBin(gz, ZIR_INST_INT_CAST, node, - ZIR_REF_NONE, operand); + result_type, operand); } // @embedFile (AstGen.zig:9626). 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); 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) { + 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]; uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); 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) { + 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]; uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); 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) { + 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]; uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); 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) { + 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]; uint32_t operand = expr(gz, scope, nd.lhs); + emitDbgStmt(gz, saved_line, saved_col); 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) { AstData nd = tree->nodes.datas[node]; uint32_t dst = expr(gz, scope, nd.lhs); 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) { AstData nd = tree->nodes.datas[node]; - uint32_t dst = expr(gz, scope, nd.lhs); - uint32_t val = expr(gz, scope, nd.rhs); - return addPlNodeBin(gz, ZIR_INST_MEMSET, node, dst, val); + uint32_t lhs = expr(gz, scope, nd.lhs); + uint32_t lhs_ty = addUnNode(gz, ZIR_INST_TYPEOF, lhs, nd.lhs); + 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). 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++; 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 + 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, "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, "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, "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 == 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; @@ -1886,7 +1952,7 @@ static uint32_t identifierExpr( // Check for primitive types FIRST (AstGen.zig:8298-8338). uint32_t prim = tryResolvePrimitiveIdent(gz, node); if (prim != ZIR_REF_NONE) - return prim; + return rvalue(gz, rl, prim, node); // Scope chain walk (AstGen.zig:8340-8461). 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); case AST_NODE_BUILTIN_CALL_TWO: 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: return fieldAccessExpr(gz, scope, rl, node); 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) { // 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; 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; if (gz2->continue_block != UINT32_MAX) { 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, (int32_t)node - (int32_t)gz->decl_node_index); return ZIR_REF_UNREACHABLE_VALUE; @@ -3480,6 +3549,7 @@ static uint32_t blockExprExpr( gzAppendInstruction(gz, block_inst); GenZir block_scope = makeSubBlock(gz, scope); + block_scope.is_inline = force_comptime; // AstGen.zig:2503 if (force_comptime) block_scope.is_comptime = true; // 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; } - 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); setBlockBody(ag, &block_scope, block_inst); gzAppendInstruction(gz, block_inst); @@ -3852,6 +3922,11 @@ static uint32_t forExpr( AstData nd = tree->nodes.datas[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. // FOR_SIMPLE: lhs = input node, rhs = body (Ast.zig:1960-1968). // 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 // Allocate index counter (AstGen.zig:6865-6874). - uint32_t index_ptr - = addUnNode(gz, ZIR_INST_ALLOC, ZIR_REF_USIZE_TYPE, node); + ZirInstTag alloc_tag + = 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); // Compute payload_token (AstGen.zig fullForComponents:2349-2350). @@ -3967,9 +4043,11 @@ static uint32_t forExpr( } // 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); + loop_scope.is_inline = is_inline; // Load index (AstGen.zig:6955-6956). 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). GenZir cond_scope = makeSubBlock(&loop_scope, &loop_scope.base); - uint32_t condbr = addCondBr(&cond_scope, node); - uint32_t cond_block = makeBlockInst(ag, ZIR_INST_BLOCK, &loop_scope, node); + ZirInstTag condbr_tag + = 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); loop_scope.break_block = loop_inst; gzAppendInstruction(&loop_scope, cond_block); @@ -4068,12 +4149,13 @@ static uint32_t forExpr( 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); // Else branch: break out of loop (AstGen.zig:7066-7091). 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); setCondBrPayload(ag, condbr, cond, &then_scope, &else_scope); @@ -4084,12 +4166,14 @@ static uint32_t forExpr( addPlNodeBin( &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; memset(&repeat_data, 0, sizeof(repeat_data)); 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); @@ -4128,7 +4212,7 @@ static uint32_t orelseCatchExpr( uint32_t condition = addUnNode(&block_scope, test_tag, operand, node); // 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). uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); @@ -4174,36 +4258,47 @@ static uint32_t whileExpr( const Ast* tree = ag->tree; 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. uint32_t cond_node = nd.lhs; uint32_t body_node = nd.rhs; // 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); GenZir loop_scope = makeSubBlock(gz, scope); + loop_scope.is_inline = is_inline; // Evaluate condition in cond_scope (AstGen.zig:6571-6607). GenZir cond_scope = makeSubBlock(&loop_scope, &loop_scope.base); uint32_t cond = expr(&cond_scope, &cond_scope.base, cond_node); // Create condbr + cond_block (AstGen.zig:6609-6615). - uint32_t condbr = addCondBr(&cond_scope, node); - uint32_t cond_block = makeBlockInst(ag, ZIR_INST_BLOCK, &loop_scope, node); + ZirInstTag condbr_tag + = 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 gzAppendInstruction(&loop_scope, cond_block); // Create continue_block (AstGen.zig:6694). - uint32_t continue_block - = makeBlockInst(ag, ZIR_INST_BLOCK, &loop_scope, node); + uint32_t continue_block = makeBlockInst(ag, block_tag, &loop_scope, node); // Add repeat to loop_scope (AstGen.zig:6696-6697). { + ZirInstTag repeat_tag + = is_inline ? ZIR_INST_REPEAT_INLINE : ZIR_INST_REPEAT; ZirInstData repeat_data; memset(&repeat_data, 0, sizeof(repeat_data)); 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). @@ -4238,19 +4333,29 @@ static uint32_t whileExpr( ext_data.extended.operand = 0; 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); } setBlockBody(ag, &continue_scope, continue_block); // 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). 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). 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); } +// --- 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) --- // Three-way result: 0=never, 1=always, 2=maybe. #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_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_COMMA: case AST_NODE_BUILTIN_CALL_TWO: case AST_NODE_BUILTIN_CALL_TWO_COMMA: - return EVAL_TO_ERROR_MAYBE; + return builtinEvalToError(tree, n); // Everything else: .never default: return EVAL_TO_ERROR_NEVER; @@ -4796,7 +4933,7 @@ static bool nodeMayAppendToErrorTrace(const Ast* tree, uint32_t node) { continue; // Anything else: check if it may eval to error. 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) --- if (!nodesNeedRlContains(ag, node)) { // Rvalue path (AstGen.zig:3246-3271). - // Evaluate type annotation if present (AstGen.zig:3248). - if (type_node != 0) - (void)typeExpr(gz, scope, type_node); + // Evaluate type annotation and build result_info + // (AstGen.zig:3247-3250). + 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). - uint32_t init_ref = expr(gz, scope, init_node); + // Evaluate init expression (AstGen.zig:3251-3252). + uint32_t init_ref = exprRl(gz, scope, result_info, init_node); if (ag->has_compile_errors) return;