astgen.c (411494B) - Raw
1 // astgen.c — AST to ZIR conversion, ported from lib/std/zig/AstGen.zig. 2 // 3 // Structural translation of AstGen.zig into C. 4 // Each function corresponds to a Zig function with the same name, 5 // with line references to Zig 0.15.1 AstGen.zig. 6 7 #include "astgen.h" 8 #include "common.h" 9 #include <assert.h> 10 #include <stdlib.h> 11 #include <string.h> 12 13 // --- Declaration.Flags.Id enum (Zir.zig:2724) --- 14 15 typedef enum { 16 DECL_ID_UNNAMED_TEST, 17 DECL_ID_TEST, 18 DECL_ID_DECLTEST, 19 DECL_ID_COMPTIME, 20 DECL_ID_CONST_SIMPLE, 21 DECL_ID_CONST_TYPED, 22 DECL_ID_CONST, 23 DECL_ID_PUB_CONST_SIMPLE, 24 DECL_ID_PUB_CONST_TYPED, 25 DECL_ID_PUB_CONST, 26 DECL_ID_EXTERN_CONST_SIMPLE, 27 DECL_ID_EXTERN_CONST, 28 DECL_ID_PUB_EXTERN_CONST_SIMPLE, 29 DECL_ID_PUB_EXTERN_CONST, 30 DECL_ID_EXPORT_CONST, 31 DECL_ID_PUB_EXPORT_CONST, 32 DECL_ID_VAR_SIMPLE, 33 DECL_ID_VAR, 34 DECL_ID_VAR_THREADLOCAL, 35 DECL_ID_PUB_VAR_SIMPLE, 36 DECL_ID_PUB_VAR, 37 DECL_ID_PUB_VAR_THREADLOCAL, 38 DECL_ID_EXTERN_VAR, 39 DECL_ID_EXTERN_VAR_THREADLOCAL, 40 DECL_ID_PUB_EXTERN_VAR, 41 DECL_ID_PUB_EXTERN_VAR_THREADLOCAL, 42 DECL_ID_EXPORT_VAR, 43 DECL_ID_EXPORT_VAR_THREADLOCAL, 44 DECL_ID_PUB_EXPORT_VAR, 45 DECL_ID_PUB_EXPORT_VAR_THREADLOCAL, 46 } DeclFlagsId; 47 48 // --- Import tracking (AstGen.zig:265) --- 49 50 typedef struct { 51 uint32_t name; // NullTerminatedString index 52 uint32_t token; // Ast.TokenIndex 53 } ImportEntry; 54 55 // --- AstGen internal context (mirrors AstGen struct, AstGen.zig:153) --- 56 57 typedef struct { 58 const Ast* tree; 59 ZirInstTag* inst_tags; 60 ZirInstData* inst_datas; 61 uint32_t inst_len; 62 uint32_t inst_cap; 63 uint32_t* extra; 64 uint32_t extra_len; 65 uint32_t extra_cap; 66 uint8_t* string_bytes; 67 uint32_t string_bytes_len; 68 uint32_t string_bytes_cap; 69 // String dedup table: stores positions in string_bytes that are 70 // registered for deduplication (mirrors AstGen.string_table). 71 // Only strings added via identAsString/strLitAsString (non-embedded-null) 72 // are registered. Multiline strings are NOT registered. 73 uint32_t* string_table; 74 uint32_t string_table_len; 75 uint32_t string_table_cap; 76 uint32_t source_offset; 77 uint32_t source_line; 78 uint32_t source_column; 79 ImportEntry* imports; 80 uint32_t imports_len; 81 uint32_t imports_cap; 82 // Namespace decl table: maps string indices to node indices. 83 // Populated by scanContainer, used by identifier resolution. 84 uint32_t* decl_names; // string indices 85 uint32_t* decl_nodes; // node indices 86 uint32_t decl_table_len; 87 uint32_t decl_table_cap; 88 // Shared dynamic array for GenZir instructions (AstGen.zig:11796). 89 // Sub-blocks share this array and track their slice via 90 // instructions_top. 91 uint32_t* scratch_instructions; 92 uint32_t scratch_inst_len; 93 uint32_t scratch_inst_cap; 94 // Scratch extra array for call arguments (mirrors AstGen.scratch in Zig). 95 // Used to collect body lengths + body instructions before copying to 96 // extra. 97 uint32_t* scratch_extra; 98 uint32_t scratch_extra_len; 99 uint32_t scratch_extra_cap; 100 // Return type ref for the current function (set during fnDecl/testDecl). 101 uint32_t fn_ret_ty; // ZirInstRef 102 // Pointer to the fn_block GenZir for the current function (AstGen.zig:45). 103 void* fn_block; // GenZir* 104 // ref_table: deferred REF instructions (AstGen.zig:58-68). 105 // Key = operand inst index, Value = ref inst index. 106 uint32_t* ref_table_keys; 107 uint32_t* ref_table_vals; 108 uint32_t ref_table_len; 109 uint32_t ref_table_cap; 110 // nodes_need_rl: set of AST node indices that need result locations. 111 // Populated by astRlAnnotate() pre-pass (AstRlAnnotate.zig). 112 uint32_t* nodes_need_rl; 113 uint32_t nodes_need_rl_len; 114 uint32_t nodes_need_rl_cap; 115 bool has_compile_errors; 116 } AstGenCtx; 117 118 static void setCompileError(AstGenCtx* ag, const char* where, int line) { 119 (void)where; 120 (void)line; 121 ag->has_compile_errors = true; 122 } 123 #define SET_ERROR(ag) setCompileError(ag, __func__, __LINE__) 124 125 // Set fn_block pointer on AstGenCtx. The caller is responsible for saving 126 // and restoring the previous value before the pointed-to GenZir goes out 127 // of scope (AstGen.zig:45). 128 static void setFnBlock(AstGenCtx* ag, void* block) { ag->fn_block = block; } 129 130 // --- ref_table operations (AstGen.zig:58-68) --- 131 // Simple linear-scan hash table for deferred REF instructions. 132 133 // Returns pointer to existing value if key found, NULL if not found. 134 static uint32_t* refTableGet(AstGenCtx* ag, uint32_t key) { 135 for (uint32_t i = 0; i < ag->ref_table_len; i++) { 136 if (ag->ref_table_keys[i] == key) 137 return &ag->ref_table_vals[i]; 138 } 139 return NULL; 140 } 141 142 // getOrPut: returns pointer to value slot; sets *found to true if existed. 143 static uint32_t* refTableGetOrPut(AstGenCtx* ag, uint32_t key, bool* found) { 144 for (uint32_t i = 0; i < ag->ref_table_len; i++) { 145 if (ag->ref_table_keys[i] == key) { 146 *found = true; 147 return &ag->ref_table_vals[i]; 148 } 149 } 150 *found = false; 151 if (ag->ref_table_len >= ag->ref_table_cap) { 152 uint32_t new_cap = ag->ref_table_cap == 0 ? 16 : ag->ref_table_cap * 2; 153 ag->ref_table_keys 154 = realloc(ag->ref_table_keys, new_cap * sizeof(uint32_t)); 155 ag->ref_table_vals 156 = realloc(ag->ref_table_vals, new_cap * sizeof(uint32_t)); 157 ag->ref_table_cap = new_cap; 158 } 159 uint32_t idx = ag->ref_table_len++; 160 ag->ref_table_keys[idx] = key; 161 return &ag->ref_table_vals[idx]; 162 } 163 164 // fetchRemove: if key exists, remove it and return true with *val set. 165 static bool refTableFetchRemove(AstGenCtx* ag, uint32_t key, uint32_t* val) { 166 for (uint32_t i = 0; i < ag->ref_table_len; i++) { 167 if (ag->ref_table_keys[i] == key) { 168 *val = ag->ref_table_vals[i]; 169 // Swap with last element. 170 ag->ref_table_len--; 171 if (i < ag->ref_table_len) { 172 ag->ref_table_keys[i] = ag->ref_table_keys[ag->ref_table_len]; 173 ag->ref_table_vals[i] = ag->ref_table_vals[ag->ref_table_len]; 174 } 175 return true; 176 } 177 } 178 return false; 179 } 180 181 // --- Result location (AstGen.zig:11808) --- 182 // Simplified version of ResultInfo.Loc. 183 // Defined here (before GenZir) because GenZir.break_result_info uses it. 184 185 // ResultInfo.Context (AstGen.zig:371-386). 186 typedef enum { 187 RI_CTX_NONE, 188 RI_CTX_RETURN, 189 RI_CTX_ERROR_HANDLING_EXPR, 190 RI_CTX_SHIFT_OP, 191 RI_CTX_FN_ARG, 192 RI_CTX_CONST_INIT, 193 RI_CTX_ASSIGNMENT, 194 } ResultCtx; 195 196 typedef enum { 197 RL_NONE, // Just compute the value. 198 RL_REF, // Compute a pointer to the value. 199 RL_DISCARD, // Compute but discard (emit ensure_result_non_error). 200 RL_TY, // Coerce to specific type. 201 RL_COERCED_TY, // Coerce to specific type, result is the coercion. 202 RL_PTR, // Store result to typed pointer. data=alloc inst, src_node=node. 203 RL_INFERRED_PTR, // Store result to inferred pointer. data=alloc inst. 204 RL_REF_COERCED_TY, // Ref with pointer type. data=ptr_ty_inst. 205 } ResultLocTag; 206 207 typedef struct { 208 ResultLocTag tag; 209 uint32_t data; // ZirInstRef: ty_inst for TY/COERCED_TY, alloc inst for 210 // PTR/INFERRED_PTR. 211 uint32_t src_node; // Only used for RL_PTR. 212 ResultCtx ctx; // ResultInfo.Context (AstGen.zig:371). 213 } ResultLoc; 214 215 #define RL_NONE_VAL \ 216 ((ResultLoc) { \ 217 .tag = RL_NONE, .data = 0, .src_node = 0, .ctx = RI_CTX_NONE }) 218 #define RL_REF_VAL \ 219 ((ResultLoc) { \ 220 .tag = RL_REF, .data = 0, .src_node = 0, .ctx = RI_CTX_NONE }) 221 #define RL_DISCARD_VAL \ 222 ((ResultLoc) { \ 223 .tag = RL_DISCARD, .data = 0, .src_node = 0, .ctx = RI_CTX_NONE }) 224 #define RL_IS_REF(rl) ((rl).tag == RL_REF || (rl).tag == RL_REF_COERCED_TY) 225 226 // --- Scope types (AstGen.zig:11621-11768) --- 227 228 typedef enum { 229 SCOPE_GEN_ZIR, 230 SCOPE_LOCAL_VAL, 231 SCOPE_LOCAL_PTR, 232 SCOPE_DEFER_NORMAL, 233 SCOPE_DEFER_ERROR, 234 SCOPE_NAMESPACE, 235 SCOPE_TOP, 236 SCOPE_LABEL, 237 } ScopeTag; 238 239 typedef struct Scope { 240 ScopeTag tag; 241 } Scope; 242 243 // --- GenZir scope (mirrors GenZir struct, AstGen.zig:11772) --- 244 // 245 // Sub-blocks share the parent AstGenCtx's scratch_instructions array and 246 // record their starting offset (instructions_top). This mirrors the upstream 247 // GenZir.instructions / instructions_top design (AstGen.zig:11796-11850). 248 249 typedef struct { 250 Scope base; // tag = SCOPE_GEN_ZIR 251 Scope* parent; 252 AstGenCtx* astgen; 253 uint32_t decl_node_index; 254 uint32_t decl_line; 255 bool is_comptime; 256 bool is_inline; // true for inline for/while, labeled blocks in comptime 257 bool c_import; // true inside @cImport block 258 uint32_t instructions_top; // start index in shared array 259 uint32_t break_block; // UINT32_MAX = none (AstGen.zig:11780) 260 uint32_t continue_block; // UINT32_MAX = none (AstGen.zig:11784) 261 // Label for labeled blocks (AstGen.zig:11800, 11869-11874). 262 uint32_t label_token; // UINT32_MAX = no label 263 uint32_t label_block_inst; // the BLOCK instruction index 264 ResultLoc break_result_info; // RL for break values 265 } GenZir; 266 267 // Scope.LocalVal (AstGen.zig:11682). 268 // This is always a `const` local and the `inst` is a value type, not a 269 // pointer. 270 typedef struct { 271 Scope base; // tag = SCOPE_LOCAL_VAL 272 Scope* parent; 273 GenZir* gen_zir; 274 uint32_t inst; // ZirInstRef 275 uint32_t token_src; // Ast.TokenIndex 276 uint32_t name; // NullTerminatedString (string table index) 277 } ScopeLocalVal; 278 279 // Scope.LocalPtr (AstGen.zig:11704). 280 // This could be a `const` or `var` local. It has a pointer instead of a value. 281 typedef struct { 282 Scope base; // tag = SCOPE_LOCAL_PTR 283 Scope* parent; 284 GenZir* gen_zir; 285 uint32_t ptr; // ZirInstRef 286 uint32_t token_src; // Ast.TokenIndex 287 uint32_t name; // NullTerminatedString (string table index) 288 bool maybe_comptime; 289 } ScopeLocalPtr; 290 291 // Scope.Defer (AstGen.zig:11741). 292 typedef struct { 293 Scope base; // tag = SCOPE_DEFER_NORMAL or SCOPE_DEFER_ERROR 294 Scope* parent; 295 uint32_t index; 296 uint32_t len; 297 } ScopeDefer; 298 299 // Scope.Label — for labeled blocks and loops. 300 typedef struct { 301 Scope base; // tag = SCOPE_LABEL 302 Scope* parent; 303 uint32_t label_name; // NullTerminatedString 304 uint32_t block_inst; // instruction index (not ref) 305 } ScopeLabel; 306 307 // --- GenZir instruction helpers (AstGen.zig:11830-11850) --- 308 309 // Returns the number of instructions in this scope. 310 static uint32_t gzInstructionsLen(const GenZir* gz) { 311 return gz->astgen->scratch_inst_len - gz->instructions_top; 312 } 313 314 // Returns pointer to start of this scope's instructions in the shared array. 315 static const uint32_t* gzInstructionsSlice(const GenZir* gz) { 316 return gz->astgen->scratch_instructions + gz->instructions_top; 317 } 318 319 // Mirrors GenZir.instructionsSliceUpto (AstGen.zig:11835). 320 // Returns instructions from gz up to (but not including) stacked_gz's start. 321 static uint32_t gzInstructionsLenUpto( 322 const GenZir* gz, const GenZir* stacked_gz) { 323 return stacked_gz->instructions_top - gz->instructions_top; 324 } 325 326 static const uint32_t* gzInstructionsSliceUpto( 327 const GenZir* gz, const GenZir* stacked_gz) { 328 (void)stacked_gz; // used only for length computation 329 return gz->astgen->scratch_instructions + gz->instructions_top; 330 } 331 332 // Mirrors GenZir.unstack (AstGen.zig:11822). 333 // Restores the shared array length to this scope's start. 334 static void gzUnstack(GenZir* gz) { 335 gz->astgen->scratch_inst_len = gz->instructions_top; 336 } 337 338 // Append an instruction index to this scope's portion of the shared array. 339 static void gzAppendInstruction(GenZir* gz, uint32_t inst_idx) { 340 AstGenCtx* ag = gz->astgen; 341 if (ag->scratch_inst_len >= ag->scratch_inst_cap) { 342 uint32_t new_cap 343 = ag->scratch_inst_cap > 0 ? ag->scratch_inst_cap * 2 : 64; 344 uint32_t* p 345 = realloc(ag->scratch_instructions, new_cap * sizeof(uint32_t)); 346 if (!p) 347 exit(1); 348 ag->scratch_instructions = p; 349 ag->scratch_inst_cap = new_cap; 350 } 351 ag->scratch_instructions[ag->scratch_inst_len++] = inst_idx; 352 } 353 354 // Mirrors GenZir.makeSubBlock (AstGen.zig:11852). 355 static GenZir makeSubBlock(GenZir* parent, Scope* scope) { 356 GenZir sub; 357 memset(&sub, 0, sizeof(sub)); 358 sub.base.tag = SCOPE_GEN_ZIR; 359 sub.parent = scope; 360 sub.astgen = parent->astgen; 361 sub.decl_node_index = parent->decl_node_index; 362 sub.decl_line = parent->decl_line; 363 sub.is_comptime = parent->is_comptime; 364 sub.c_import = parent->c_import; 365 sub.instructions_top = parent->astgen->scratch_inst_len; 366 sub.break_block = UINT32_MAX; 367 sub.continue_block = UINT32_MAX; 368 sub.label_token = UINT32_MAX; 369 return sub; 370 } 371 372 // --- Capacity helpers --- 373 374 static void ensureExtraCapacity(AstGenCtx* ag, uint32_t additional) { 375 uint32_t needed = ag->extra_len + additional; 376 if (needed > ag->extra_cap) { 377 uint32_t new_cap = ag->extra_cap * 2; 378 if (new_cap < needed) 379 new_cap = needed; 380 uint32_t* p = realloc(ag->extra, new_cap * sizeof(uint32_t)); 381 if (!p) 382 exit(1); 383 ag->extra = p; 384 ag->extra_cap = new_cap; 385 } 386 } 387 388 static void ensureInstCapacity(AstGenCtx* ag, uint32_t additional) { 389 uint32_t needed = ag->inst_len + additional; 390 if (needed > ag->inst_cap) { 391 uint32_t new_cap = ag->inst_cap * 2; 392 if (new_cap < needed) 393 new_cap = needed; 394 ZirInstTag* t = realloc(ag->inst_tags, new_cap * sizeof(ZirInstTag)); 395 ZirInstData* d 396 = realloc(ag->inst_datas, new_cap * sizeof(ZirInstData)); 397 if (!t || !d) 398 exit(1); 399 ag->inst_tags = t; 400 ag->inst_datas = d; 401 ag->inst_cap = new_cap; 402 } 403 } 404 405 static void ensureStringBytesCapacity(AstGenCtx* ag, uint32_t additional) { 406 uint32_t needed = ag->string_bytes_len + additional; 407 if (needed > ag->string_bytes_cap) { 408 uint32_t new_cap = ag->string_bytes_cap * 2; 409 if (new_cap < needed) 410 new_cap = needed; 411 uint8_t* p = realloc(ag->string_bytes, new_cap * sizeof(uint8_t)); 412 if (!p) 413 exit(1); 414 ag->string_bytes = p; 415 ag->string_bytes_cap = new_cap; 416 } 417 } 418 419 // --- Extra data helpers --- 420 421 static uint32_t addExtraU32(AstGenCtx* ag, uint32_t value) { 422 ensureExtraCapacity(ag, 1); 423 uint32_t idx = ag->extra_len; 424 ag->extra[ag->extra_len++] = value; 425 return idx; 426 } 427 428 // --- Instruction helpers --- 429 430 // Mirrors AstGen.reserveInstructionIndex (AstGen.zig:12902). 431 static uint32_t reserveInstructionIndex(AstGenCtx* ag) { 432 ensureInstCapacity(ag, 1); 433 uint32_t idx = ag->inst_len; 434 memset(&ag->inst_datas[idx], 0, sizeof(ZirInstData)); 435 ag->inst_tags[idx] = (ZirInstTag)0; 436 ag->inst_len++; 437 return idx; 438 } 439 440 // Forward declarations. 441 static int32_t tokenIndexToRelative(const GenZir* gz, uint32_t token); 442 static uint32_t firstToken(const Ast* tree, uint32_t node); 443 static bool nodesNeedRlContains(const AstGenCtx* ag, uint32_t node); 444 445 // Mirrors GenZir.makeUnTok (AstGen.zig:12520). 446 // Allocates an instruction but does NOT add to GenZir body. 447 // Returns the raw instruction INDEX (not a Ref). 448 static uint32_t makeUnTok( 449 GenZir* gz, ZirInstTag tag, uint32_t operand, uint32_t abs_tok_index) { 450 AstGenCtx* ag = gz->astgen; 451 ensureInstCapacity(ag, 1); 452 uint32_t idx = ag->inst_len; 453 ZirInstData data; 454 data.un_tok.src_tok = tokenIndexToRelative(gz, abs_tok_index); 455 data.un_tok.operand = operand; 456 ag->inst_tags[idx] = tag; 457 ag->inst_datas[idx] = data; 458 ag->inst_len++; 459 return idx; // Raw index, NOT a Ref. 460 } 461 462 // Mirrors GenZir.add (AstGen.zig:13162). 463 // Appends an instruction and records it in the GenZir body. 464 // Returns the instruction index as a Ref (index + ZIR_INST_REF_START_INDEX). 465 static uint32_t addInstruction(GenZir* gz, ZirInstTag tag, ZirInstData data) { 466 AstGenCtx* ag = gz->astgen; 467 ensureInstCapacity(ag, 1); 468 uint32_t idx = ag->inst_len; 469 ag->inst_tags[idx] = tag; 470 ag->inst_datas[idx] = data; 471 ag->inst_len++; 472 // Record in sub-block body. 473 gzAppendInstruction(gz, idx); 474 return idx + ZIR_REF_START_INDEX; // toRef() 475 } 476 477 // Mirrors GenZir.addInt (AstGen.zig:12238). 478 static uint32_t addInt(GenZir* gz, uint64_t integer) { 479 ZirInstData data; 480 data.int_val = integer; 481 return addInstruction(gz, ZIR_INST_INT, data); 482 } 483 484 // Mirrors GenZir.add for bin data (Zir.zig:1877). 485 // Creates an instruction with bin data (lhs + rhs stored in inst_datas). 486 static uint32_t addBin( 487 GenZir* gz, ZirInstTag tag, uint32_t lhs, uint32_t rhs) { 488 ZirInstData data; 489 data.bin.lhs = lhs; 490 data.bin.rhs = rhs; 491 return addInstruction(gz, tag, data); 492 } 493 494 // Mirrors GenZir.addPlNode (AstGen.zig:12308). 495 // Creates an instruction with pl_node data and 2-word payload. 496 static uint32_t addPlNodeBin( 497 GenZir* gz, ZirInstTag tag, uint32_t node, uint32_t lhs, uint32_t rhs) { 498 AstGenCtx* ag = gz->astgen; 499 ensureExtraCapacity(ag, 2); 500 uint32_t payload_index = ag->extra_len; 501 ag->extra[ag->extra_len++] = lhs; 502 ag->extra[ag->extra_len++] = rhs; 503 ZirInstData data; 504 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 505 data.pl_node.payload_index = payload_index; 506 return addInstruction(gz, tag, data); 507 } 508 509 // Mirrors addPlNode for 3-operand payloads (e.g. ArrayTypeSentinel). 510 static uint32_t addPlNodeTriple(GenZir* gz, ZirInstTag tag, uint32_t node, 511 uint32_t a, uint32_t b, uint32_t c) { 512 AstGenCtx* ag = gz->astgen; 513 ensureExtraCapacity(ag, 3); 514 uint32_t payload_index = ag->extra_len; 515 ag->extra[ag->extra_len++] = a; 516 ag->extra[ag->extra_len++] = b; 517 ag->extra[ag->extra_len++] = c; 518 ZirInstData data; 519 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 520 data.pl_node.payload_index = payload_index; 521 return addInstruction(gz, tag, data); 522 } 523 524 // Checks if an AST identifier node is the single underscore `_`. 525 // Used for inferred array length detection in [_]T patterns. 526 // Intentionally does NOT support @"_" syntax (matches upstream). 527 static bool isUnderscoreIdent(const Ast* tree, uint32_t ident_node) { 528 uint32_t id_tok = tree->nodes.main_tokens[ident_node]; 529 uint32_t id_start = tree->tokens.starts[id_tok]; 530 if (tree->source[id_start] != '_') 531 return false; 532 if (id_start + 1 >= tree->source_len) 533 return true; 534 char next = tree->source[id_start + 1]; 535 return !((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') 536 || next == '_' || (next >= '0' && next <= '9')); 537 } 538 539 // Mirrors GenZir.addUnNode (AstGen.zig:12406). 540 static uint32_t addUnNode( 541 GenZir* gz, ZirInstTag tag, uint32_t operand, uint32_t node) { 542 ZirInstData data; 543 data.un_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 544 data.un_node.operand = operand; 545 return addInstruction(gz, tag, data); 546 } 547 548 // Mirrors GenZir.addUnTok (AstGen.zig:12497). 549 static uint32_t addUnTok( 550 GenZir* gz, ZirInstTag tag, uint32_t operand, uint32_t abs_tok_index) { 551 ZirInstData data; 552 data.un_tok.src_tok = tokenIndexToRelative(gz, abs_tok_index); 553 data.un_tok.operand = operand; 554 return addInstruction(gz, tag, data); 555 } 556 557 // Mirrors GenZir.addStrTok (AstGen.zig:12349). 558 static uint32_t addStrTok( 559 GenZir* gz, ZirInstTag tag, uint32_t str_index, uint32_t token) { 560 ZirInstData data; 561 data.str_tok.start = str_index; 562 data.str_tok.src_tok = tokenIndexToRelative(gz, token); 563 return addInstruction(gz, tag, data); 564 } 565 566 // Mirrors GenZir.addPlNodePayloadIndex (AstGen.zig:12332). 567 static uint32_t addPlNodePayloadIndex( 568 GenZir* gz, ZirInstTag tag, uint32_t node, uint32_t payload_index) { 569 ZirInstData data; 570 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 571 data.pl_node.payload_index = payload_index; 572 return addInstruction(gz, tag, data); 573 } 574 575 // --- Source cursor (AstGen.zig:13335-13359) --- 576 577 // Mirrors AstGen.advanceSourceCursor (AstGen.zig:13342). 578 static void advanceSourceCursor(AstGenCtx* ag, uint32_t end) { 579 const char* source = ag->tree->source; 580 uint32_t i = ag->source_offset; 581 uint32_t line = ag->source_line; 582 uint32_t column = ag->source_column; 583 assert(i <= end); 584 while (i < end) { 585 if (source[i] == '\n') { 586 line++; 587 column = 0; 588 } else { 589 column++; 590 } 591 i++; 592 } 593 ag->source_offset = i; 594 ag->source_line = line; 595 ag->source_column = column; 596 } 597 598 // Mirrors tree.firstToken (Ast.zig:596). 599 // Recurse through nodes to find the first token. 600 static uint32_t firstToken(const Ast* tree, uint32_t node) { 601 uint32_t n = node; 602 while (1) { 603 AstNodeTag tag = tree->nodes.tags[n]; 604 switch (tag) { 605 case AST_NODE_ROOT: 606 return 0; 607 608 // Return main_token directly (Ast.zig:602-643). 609 case AST_NODE_TEST_DECL: 610 case AST_NODE_ERRDEFER: 611 case AST_NODE_DEFER: 612 case AST_NODE_BOOL_NOT: 613 case AST_NODE_NEGATION: 614 case AST_NODE_BIT_NOT: 615 case AST_NODE_NEGATION_WRAP: 616 case AST_NODE_ADDRESS_OF: 617 case AST_NODE_TRY: 618 case AST_NODE_AWAIT: 619 case AST_NODE_OPTIONAL_TYPE: 620 case AST_NODE_SWITCH: 621 case AST_NODE_SWITCH_COMMA: 622 case AST_NODE_IF_SIMPLE: 623 case AST_NODE_IF: 624 case AST_NODE_SUSPEND: 625 case AST_NODE_RESUME: 626 case AST_NODE_CONTINUE: 627 case AST_NODE_BREAK: 628 case AST_NODE_RETURN: 629 case AST_NODE_ANYFRAME_TYPE: 630 case AST_NODE_IDENTIFIER: 631 case AST_NODE_ANYFRAME_LITERAL: 632 case AST_NODE_CHAR_LITERAL: 633 case AST_NODE_NUMBER_LITERAL: 634 case AST_NODE_UNREACHABLE_LITERAL: 635 case AST_NODE_STRING_LITERAL: 636 case AST_NODE_MULTILINE_STRING_LITERAL: 637 case AST_NODE_GROUPED_EXPRESSION: 638 case AST_NODE_BUILTIN_CALL_TWO: 639 case AST_NODE_BUILTIN_CALL_TWO_COMMA: 640 case AST_NODE_BUILTIN_CALL: 641 case AST_NODE_BUILTIN_CALL_COMMA: 642 case AST_NODE_ERROR_SET_DECL: 643 case AST_NODE_COMPTIME: 644 case AST_NODE_NOSUSPEND: 645 case AST_NODE_ASM_SIMPLE: 646 case AST_NODE_ASM: 647 case AST_NODE_ARRAY_TYPE: 648 case AST_NODE_ARRAY_TYPE_SENTINEL: 649 case AST_NODE_ERROR_VALUE: 650 case AST_NODE_PTR_TYPE_ALIGNED: 651 case AST_NODE_PTR_TYPE_SENTINEL: 652 case AST_NODE_PTR_TYPE: 653 case AST_NODE_PTR_TYPE_BIT_RANGE: 654 return tree->nodes.main_tokens[n]; 655 656 // Return main_token - 1: dot-prefixed inits and enum_literal 657 // (Ast.zig:645-654). 658 case AST_NODE_ARRAY_INIT_DOT: 659 case AST_NODE_ARRAY_INIT_DOT_COMMA: 660 case AST_NODE_ARRAY_INIT_DOT_TWO: 661 case AST_NODE_ARRAY_INIT_DOT_TWO_COMMA: 662 case AST_NODE_STRUCT_INIT_DOT: 663 case AST_NODE_STRUCT_INIT_DOT_COMMA: 664 case AST_NODE_STRUCT_INIT_DOT_TWO: 665 case AST_NODE_STRUCT_INIT_DOT_TWO_COMMA: 666 case AST_NODE_ENUM_LITERAL: 667 return tree->nodes.main_tokens[n] - 1; 668 669 // Recurse into LHS: all binary ops and compound expressions 670 // (Ast.zig:656-733). 671 case AST_NODE_CATCH: 672 case AST_NODE_EQUAL_EQUAL: 673 case AST_NODE_BANG_EQUAL: 674 case AST_NODE_LESS_THAN: 675 case AST_NODE_GREATER_THAN: 676 case AST_NODE_LESS_OR_EQUAL: 677 case AST_NODE_GREATER_OR_EQUAL: 678 case AST_NODE_ASSIGN_MUL: 679 case AST_NODE_ASSIGN_DIV: 680 case AST_NODE_ASSIGN_MOD: 681 case AST_NODE_ASSIGN_ADD: 682 case AST_NODE_ASSIGN_SUB: 683 case AST_NODE_ASSIGN_SHL: 684 case AST_NODE_ASSIGN_SHL_SAT: 685 case AST_NODE_ASSIGN_SHR: 686 case AST_NODE_ASSIGN_BIT_AND: 687 case AST_NODE_ASSIGN_BIT_XOR: 688 case AST_NODE_ASSIGN_BIT_OR: 689 case AST_NODE_ASSIGN_MUL_WRAP: 690 case AST_NODE_ASSIGN_ADD_WRAP: 691 case AST_NODE_ASSIGN_SUB_WRAP: 692 case AST_NODE_ASSIGN_MUL_SAT: 693 case AST_NODE_ASSIGN_ADD_SAT: 694 case AST_NODE_ASSIGN_SUB_SAT: 695 case AST_NODE_ASSIGN: 696 case AST_NODE_MERGE_ERROR_SETS: 697 case AST_NODE_MUL: 698 case AST_NODE_DIV: 699 case AST_NODE_MOD: 700 case AST_NODE_ARRAY_MULT: 701 case AST_NODE_MUL_WRAP: 702 case AST_NODE_MUL_SAT: 703 case AST_NODE_ADD: 704 case AST_NODE_SUB: 705 case AST_NODE_ARRAY_CAT: 706 case AST_NODE_ADD_WRAP: 707 case AST_NODE_SUB_WRAP: 708 case AST_NODE_ADD_SAT: 709 case AST_NODE_SUB_SAT: 710 case AST_NODE_SHL: 711 case AST_NODE_SHL_SAT: 712 case AST_NODE_SHR: 713 case AST_NODE_BIT_AND: 714 case AST_NODE_BIT_XOR: 715 case AST_NODE_BIT_OR: 716 case AST_NODE_ORELSE: 717 case AST_NODE_BOOL_AND: 718 case AST_NODE_BOOL_OR: 719 case AST_NODE_SLICE_OPEN: 720 case AST_NODE_ARRAY_ACCESS: 721 case AST_NODE_ARRAY_INIT_ONE: 722 case AST_NODE_ARRAY_INIT_ONE_COMMA: 723 case AST_NODE_SWITCH_RANGE: 724 case AST_NODE_ERROR_UNION: 725 case AST_NODE_FOR_RANGE: 726 case AST_NODE_CALL_ONE: 727 case AST_NODE_CALL_ONE_COMMA: 728 case AST_NODE_STRUCT_INIT_ONE: 729 case AST_NODE_STRUCT_INIT_ONE_COMMA: 730 case AST_NODE_CALL: 731 case AST_NODE_CALL_COMMA: 732 case AST_NODE_STRUCT_INIT: 733 case AST_NODE_STRUCT_INIT_COMMA: 734 case AST_NODE_SLICE: 735 case AST_NODE_SLICE_SENTINEL: 736 case AST_NODE_ARRAY_INIT: 737 case AST_NODE_ARRAY_INIT_COMMA: 738 case AST_NODE_FIELD_ACCESS: 739 case AST_NODE_UNWRAP_OPTIONAL: 740 case AST_NODE_DEREF: 741 case AST_NODE_ASYNC_CALL_ONE: 742 case AST_NODE_ASYNC_CALL_ONE_COMMA: 743 case AST_NODE_ASYNC_CALL: 744 case AST_NODE_ASYNC_CALL_COMMA: 745 n = tree->nodes.datas[n].lhs; 746 continue; 747 748 // Var decls: scan backwards for modifiers (Ast.zig:771-792). 749 case AST_NODE_GLOBAL_VAR_DECL: 750 case AST_NODE_LOCAL_VAR_DECL: 751 case AST_NODE_SIMPLE_VAR_DECL: 752 case AST_NODE_ALIGNED_VAR_DECL: { 753 uint32_t mt = tree->nodes.main_tokens[n]; 754 uint32_t i = mt; 755 while (i > 0) { 756 TokenizerTag tt = tree->tokens.tags[i - 1]; 757 if (tt == TOKEN_KEYWORD_EXTERN || tt == TOKEN_KEYWORD_EXPORT 758 || tt == TOKEN_KEYWORD_PUB 759 || tt == TOKEN_KEYWORD_THREADLOCAL 760 || tt == TOKEN_KEYWORD_COMPTIME 761 || tt == TOKEN_STRING_LITERAL) { 762 i--; 763 } else { 764 break; 765 } 766 } 767 return i; 768 } 769 // Fn decls: scan backwards for modifiers (Ast.zig:737-759). 770 case AST_NODE_FN_DECL: 771 case AST_NODE_FN_PROTO_SIMPLE: 772 case AST_NODE_FN_PROTO_MULTI: 773 case AST_NODE_FN_PROTO_ONE: 774 case AST_NODE_FN_PROTO: { 775 uint32_t mt = tree->nodes.main_tokens[n]; 776 uint32_t i = mt; 777 while (i > 0) { 778 TokenizerTag tt = tree->tokens.tags[i - 1]; 779 if (tt == TOKEN_KEYWORD_EXTERN || tt == TOKEN_KEYWORD_EXPORT 780 || tt == TOKEN_KEYWORD_PUB || tt == TOKEN_KEYWORD_INLINE 781 || tt == TOKEN_KEYWORD_NOINLINE 782 || tt == TOKEN_STRING_LITERAL) { 783 i--; 784 } else { 785 break; 786 } 787 } 788 return i; 789 } 790 // Container fields: check for preceding comptime (Ast.zig:761-769). 791 case AST_NODE_CONTAINER_FIELD_INIT: 792 case AST_NODE_CONTAINER_FIELD_ALIGN: 793 case AST_NODE_CONTAINER_FIELD: { 794 uint32_t mt = tree->nodes.main_tokens[n]; 795 if (mt > 0 && tree->tokens.tags[mt - 1] == TOKEN_KEYWORD_COMPTIME) 796 return mt - 1; 797 return mt; 798 } 799 // Blocks: check for label (Ast.zig:794-805). 800 case AST_NODE_BLOCK: 801 case AST_NODE_BLOCK_SEMICOLON: 802 case AST_NODE_BLOCK_TWO: 803 case AST_NODE_BLOCK_TWO_SEMICOLON: { 804 uint32_t lbrace = tree->nodes.main_tokens[n]; 805 if (lbrace >= 2 && tree->tokens.tags[lbrace - 1] == TOKEN_COLON 806 && tree->tokens.tags[lbrace - 2] == TOKEN_IDENTIFIER) 807 return lbrace - 2; 808 return lbrace; 809 } 810 // Fallback for any remaining node types. 811 default: 812 return tree->nodes.main_tokens[n]; 813 } 814 } 815 } 816 817 // Mirrors AstGen.advanceSourceCursorToNode (AstGen.zig:13335). 818 static void advanceSourceCursorToNode(AstGenCtx* ag, uint32_t node) { 819 uint32_t ft = firstToken(ag->tree, node); 820 uint32_t token_start = ag->tree->tokens.starts[ft]; 821 (void)0; // cursor backward check disabled temporarily 822 advanceSourceCursor(ag, token_start); 823 } 824 825 // Mirrors maybeAdvanceSourceCursorToMainToken (AstGen.zig:13324). 826 // Skips advancing when in comptime scope (matching upstream behavior). 827 static void advanceSourceCursorToMainToken( 828 AstGenCtx* ag, const GenZir* gz, uint32_t node) { 829 if (gz->is_comptime) 830 return; 831 uint32_t main_tok = ag->tree->nodes.main_tokens[node]; 832 uint32_t token_start = ag->tree->tokens.starts[main_tok]; 833 advanceSourceCursor(ag, token_start); 834 } 835 836 // --- Token helpers --- 837 838 // Mirrors GenZir.tokenIndexToRelative (AstGen.zig:11897). 839 // Returns destination - base as i32. 840 static int32_t tokenIndexToRelative(const GenZir* gz, uint32_t token) { 841 uint32_t base = firstToken(gz->astgen->tree, gz->decl_node_index); 842 return (int32_t)token - (int32_t)base; 843 } 844 845 // --- String bytes helpers --- 846 847 // Search for an existing null-terminated string in string_bytes. 848 // Returns the index if found, or UINT32_MAX if not found. 849 // Mirrors string_table dedup (AstGen.zig:11564). 850 // Find a string in string_table (registered strings only). 851 // Mirrors AstGen.string_table hash table lookup. 852 static uint32_t findExistingString( 853 const AstGenCtx* ag, const char* str, uint32_t len) { 854 for (uint32_t k = 0; k < ag->string_table_len; k++) { 855 uint32_t pos = ag->string_table[k]; 856 // Compare: string at pos is null-terminated in string_bytes. 857 const char* existing = (const char*)ag->string_bytes + pos; 858 uint32_t existing_len = (uint32_t)strlen(existing); 859 if (existing_len == len && memcmp(existing, str, len) == 0) { 860 return pos; 861 } 862 } 863 return UINT32_MAX; 864 } 865 866 // Register a string position in the string table for deduplication. 867 static void registerString(AstGenCtx* ag, uint32_t pos) { 868 if (ag->string_table_len >= ag->string_table_cap) { 869 uint32_t new_cap = ag->string_table_cap * 2; 870 if (new_cap < 64) 871 new_cap = 64; 872 uint32_t* p = realloc(ag->string_table, new_cap * sizeof(uint32_t)); 873 if (!p) 874 exit(1); 875 ag->string_table = p; 876 ag->string_table_cap = new_cap; 877 } 878 ag->string_table[ag->string_table_len++] = pos; 879 } 880 881 // Mirrors AstGen.tokenIdentEql (AstGen.zig:6148-6152). 882 // Compares two identifier tokens by source text without touching string_bytes. 883 static bool tokenIdentEql(const Ast* tree, uint32_t tok1, uint32_t tok2) { 884 uint32_t s1 = tree->tokens.starts[tok1]; 885 uint32_t s2 = tree->tokens.starts[tok2]; 886 uint32_t e1 = tree->tokens.starts[tok1 + 1]; 887 uint32_t e2 = tree->tokens.starts[tok2 + 1]; 888 // Token length includes trailing whitespace in starts delta, but for 889 // identifiers the actual content is a contiguous alphanumeric/underscore 890 // run. Compute actual identifier lengths. 891 uint32_t len1 = 0; 892 while (s1 + len1 < e1) { 893 char c = tree->source[s1 + len1]; 894 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 895 || (c >= '0' && c <= '9') || c == '_')) 896 break; 897 len1++; 898 } 899 uint32_t len2 = 0; 900 while (s2 + len2 < e2) { 901 char c = tree->source[s2 + len2]; 902 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') 903 || (c >= '0' && c <= '9') || c == '_')) 904 break; 905 len2++; 906 } 907 return len1 == len2 908 && memcmp(tree->source + s1, tree->source + s2, len1) == 0; 909 } 910 911 // Forward declaration for strLitAsString (used by identAsString for @"..." 912 // quoted identifiers with escapes). 913 static void strLitAsString(AstGenCtx* ag, uint32_t str_lit_token, 914 uint32_t* out_index, uint32_t* out_len); 915 916 // Mirrors AstGen.identAsString (AstGen.zig:11530). 917 // Handles both bare identifiers and @"..." quoted identifiers. 918 static uint32_t identAsString(AstGenCtx* ag, uint32_t ident_token) { 919 uint32_t start = ag->tree->tokens.starts[ident_token]; 920 const char* source = ag->tree->source; 921 922 if (source[start] == '@' && start + 1 < ag->tree->source_len 923 && source[start + 1] == '"') { 924 // Quoted identifier: @"name" (AstGen.zig:11297-11308). 925 // Extract content between quotes, handling escapes. 926 uint32_t si, sl; 927 // str_lit_token refers to the same token, content starts after @" 928 // We reuse strLitAsString but offset by 1 to skip '@'. 929 // Actually, strLitAsString expects a token whose source starts 930 // with '"'. The @"..." token starts with '@'. We need to handle 931 // the offset manually. 932 uint32_t content_start = start + 2; // skip @" 933 uint32_t content_end = content_start; 934 while ( 935 content_end < ag->tree->source_len && source[content_end] != '"') 936 content_end++; 937 // Check for escapes. 938 bool has_escapes = false; 939 for (uint32_t j = content_start; j < content_end; j++) { 940 if (source[j] == '\\') { 941 has_escapes = true; 942 break; 943 } 944 } 945 946 if (!has_escapes) { 947 uint32_t content_len = content_end - content_start; 948 uint32_t existing 949 = findExistingString(ag, source + content_start, content_len); 950 if (existing != UINT32_MAX) 951 return existing; 952 uint32_t str_index = ag->string_bytes_len; 953 ensureStringBytesCapacity(ag, content_len + 1); 954 memcpy(ag->string_bytes + ag->string_bytes_len, 955 source + content_start, content_len); 956 ag->string_bytes_len += content_len; 957 ag->string_bytes[ag->string_bytes_len++] = 0; 958 registerString(ag, str_index); 959 return str_index; 960 } 961 962 // With escapes: use strLitAsString-like decoding. 963 strLitAsString(ag, ident_token, &si, &sl); 964 return si; 965 } 966 967 // Bare identifier: scan alphanumeric + underscore. 968 uint32_t end = start; 969 while (end < ag->tree->source_len) { 970 char ch = source[end]; 971 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') 972 || (ch >= '0' && ch <= '9') || ch == '_') { 973 end++; 974 } else { 975 break; 976 } 977 } 978 uint32_t ident_len = end - start; 979 980 // Check for existing string (dedup). 981 uint32_t existing = findExistingString(ag, source + start, ident_len); 982 if (existing != UINT32_MAX) 983 return existing; 984 985 uint32_t str_index = ag->string_bytes_len; 986 ensureStringBytesCapacity(ag, ident_len + 1); 987 memcpy(ag->string_bytes + ag->string_bytes_len, source + start, ident_len); 988 ag->string_bytes_len += ident_len; 989 ag->string_bytes[ag->string_bytes_len++] = 0; 990 registerString(ag, str_index); 991 return str_index; 992 } 993 994 // Mirrors AstGen.strLitAsString (AstGen.zig:11553). 995 // Decodes string literal, checks for embedded nulls. 996 // If embedded null found: store raw bytes without trailing null, no dedup. 997 // Otherwise: dedup via string_table, add trailing null. 998 static void strLitAsString(AstGenCtx* ag, uint32_t str_lit_token, 999 uint32_t* out_index, uint32_t* out_len) { 1000 uint32_t tok_start = ag->tree->tokens.starts[str_lit_token]; 1001 const char* source = ag->tree->source; 1002 1003 // Skip opening quote. 1004 uint32_t i = tok_start + 1; 1005 // Find closing quote, skipping escaped characters. 1006 uint32_t raw_end = i; 1007 while (raw_end < ag->tree->source_len) { 1008 if (source[raw_end] == '\\') { 1009 raw_end += 2; // skip escape + escaped char 1010 } else if (source[raw_end] == '"') { 1011 break; 1012 } else { 1013 raw_end++; 1014 } 1015 } 1016 1017 // Check if there are any escape sequences. 1018 bool has_escapes = false; 1019 for (uint32_t j = i; j < raw_end; j++) { 1020 if (source[j] == '\\') { 1021 has_escapes = true; 1022 break; 1023 } 1024 } 1025 1026 if (!has_escapes) { 1027 // Fast path: no escapes, no embedded nulls possible. 1028 uint32_t content_len = raw_end - i; 1029 uint32_t existing = findExistingString(ag, source + i, content_len); 1030 if (existing != UINT32_MAX) { 1031 *out_index = existing; 1032 *out_len = content_len; 1033 return; 1034 } 1035 uint32_t str_index = ag->string_bytes_len; 1036 ensureStringBytesCapacity(ag, content_len + 1); 1037 memcpy( 1038 ag->string_bytes + ag->string_bytes_len, source + i, content_len); 1039 ag->string_bytes_len += content_len; 1040 ag->string_bytes[ag->string_bytes_len++] = 0; 1041 registerString(ag, str_index); 1042 *out_index = str_index; 1043 *out_len = content_len; 1044 return; 1045 } 1046 1047 // Slow path: process escape sequences (AstGen.zig:11558). 1048 // Decode directly into string_bytes (like upstream). 1049 uint32_t str_index = ag->string_bytes_len; 1050 uint32_t max_len = raw_end - i; 1051 ensureStringBytesCapacity(ag, max_len + 1); 1052 while (i < raw_end) { 1053 if (source[i] == '\\') { 1054 i++; 1055 if (i >= raw_end) 1056 break; 1057 switch (source[i]) { 1058 case 'n': 1059 ag->string_bytes[ag->string_bytes_len++] = '\n'; 1060 break; 1061 case 'r': 1062 ag->string_bytes[ag->string_bytes_len++] = '\r'; 1063 break; 1064 case 't': 1065 ag->string_bytes[ag->string_bytes_len++] = '\t'; 1066 break; 1067 case '\\': 1068 ag->string_bytes[ag->string_bytes_len++] = '\\'; 1069 break; 1070 case '\'': 1071 ag->string_bytes[ag->string_bytes_len++] = '\''; 1072 break; 1073 case '"': 1074 ag->string_bytes[ag->string_bytes_len++] = '"'; 1075 break; 1076 case 'x': { 1077 // \xNN hex escape. 1078 uint8_t val = 0; 1079 for (int k = 0; k < 2 && i + 1 < raw_end; k++) { 1080 i++; 1081 char c = source[i]; 1082 if (c >= '0' && c <= '9') 1083 val = (uint8_t)(val * 16 + (uint8_t)(c - '0')); 1084 else if (c >= 'a' && c <= 'f') 1085 val = (uint8_t)(val * 16 + 10 + (uint8_t)(c - 'a')); 1086 else if (c >= 'A' && c <= 'F') 1087 val = (uint8_t)(val * 16 + 10 + (uint8_t)(c - 'A')); 1088 } 1089 ag->string_bytes[ag->string_bytes_len++] = val; 1090 break; 1091 } 1092 case 'u': { 1093 // \u{NNNNNN} unicode escape (string_literal.zig:194-231). 1094 // Skip past '{'. 1095 i++; 1096 // Parse hex digits until '}'. 1097 uint32_t codepoint = 0; 1098 while (i + 1 < raw_end) { 1099 i++; 1100 char c = source[i]; 1101 if (c >= '0' && c <= '9') { 1102 codepoint = codepoint * 16 + (uint32_t)(c - '0'); 1103 } else if (c >= 'a' && c <= 'f') { 1104 codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'a'); 1105 } else if (c >= 'A' && c <= 'F') { 1106 codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'A'); 1107 } else { 1108 // Must be '}', done. 1109 break; 1110 } 1111 } 1112 // Encode codepoint as UTF-8 (unicode.zig:53-82). 1113 if (codepoint <= 0x7F) { 1114 ag->string_bytes[ag->string_bytes_len++] 1115 = (uint8_t)codepoint; 1116 } else if (codepoint <= 0x7FF) { 1117 ag->string_bytes[ag->string_bytes_len++] 1118 = (uint8_t)(0xC0 | (codepoint >> 6)); 1119 ag->string_bytes[ag->string_bytes_len++] 1120 = (uint8_t)(0x80 | (codepoint & 0x3F)); 1121 } else if (codepoint <= 0xFFFF) { 1122 ag->string_bytes[ag->string_bytes_len++] 1123 = (uint8_t)(0xE0 | (codepoint >> 12)); 1124 ag->string_bytes[ag->string_bytes_len++] 1125 = (uint8_t)(0x80 | ((codepoint >> 6) & 0x3F)); 1126 ag->string_bytes[ag->string_bytes_len++] 1127 = (uint8_t)(0x80 | (codepoint & 0x3F)); 1128 } else { 1129 ag->string_bytes[ag->string_bytes_len++] 1130 = (uint8_t)(0xF0 | (codepoint >> 18)); 1131 ag->string_bytes[ag->string_bytes_len++] 1132 = (uint8_t)(0x80 | ((codepoint >> 12) & 0x3F)); 1133 ag->string_bytes[ag->string_bytes_len++] 1134 = (uint8_t)(0x80 | ((codepoint >> 6) & 0x3F)); 1135 ag->string_bytes[ag->string_bytes_len++] 1136 = (uint8_t)(0x80 | (codepoint & 0x3F)); 1137 } 1138 break; 1139 } 1140 default: 1141 ag->string_bytes[ag->string_bytes_len++] = (uint8_t)source[i]; 1142 break; 1143 } 1144 } else { 1145 ag->string_bytes[ag->string_bytes_len++] = (uint8_t)source[i]; 1146 } 1147 i++; 1148 } 1149 uint32_t decoded_len = ag->string_bytes_len - str_index; 1150 uint8_t* key = ag->string_bytes + str_index; 1151 1152 // Check for embedded null bytes (AstGen.zig:11560). 1153 // If found, skip dedup and don't add trailing null. 1154 bool has_embedded_null = false; 1155 for (uint32_t j = 0; j < decoded_len; j++) { 1156 if (key[j] == 0) { 1157 has_embedded_null = true; 1158 break; 1159 } 1160 } 1161 if (has_embedded_null) { 1162 *out_index = str_index; 1163 *out_len = decoded_len; 1164 return; 1165 } 1166 1167 // Dedup against string_table (AstGen.zig:11564-11585). 1168 uint32_t existing = findExistingString(ag, (const char*)key, decoded_len); 1169 if (existing != UINT32_MAX) { 1170 // Shrink back (AstGen.zig:11570). 1171 ag->string_bytes_len = str_index; 1172 *out_index = existing; 1173 *out_len = decoded_len; 1174 return; 1175 } 1176 1177 // New entry: add trailing null and register. 1178 ensureStringBytesCapacity(ag, 1); 1179 ag->string_bytes[ag->string_bytes_len++] = 0; 1180 registerString(ag, str_index); 1181 *out_index = str_index; 1182 *out_len = decoded_len; 1183 } 1184 1185 // --- Declaration helpers --- 1186 1187 // Mirrors GenZir.makeDeclaration (AstGen.zig:12906). 1188 static uint32_t makeDeclaration(AstGenCtx* ag, uint32_t node) { 1189 ensureInstCapacity(ag, 1); 1190 uint32_t idx = ag->inst_len; 1191 ag->inst_tags[idx] = ZIR_INST_DECLARATION; 1192 ZirInstData data; 1193 memset(&data, 0, sizeof(data)); 1194 data.declaration.src_node = node; 1195 // payload_index is set later by setDeclaration. 1196 ag->inst_datas[idx] = data; 1197 ag->inst_len++; 1198 return idx; 1199 } 1200 1201 // Mirrors GenZir.makeBreakCommon (AstGen.zig:12667). 1202 // Creates a break_inline instruction with a Break payload in extra. 1203 // Records the instruction in the GenZir body. 1204 static uint32_t makeBreakInline(GenZir* gz, uint32_t block_inst, 1205 uint32_t operand, int32_t operand_src_node) { 1206 AstGenCtx* ag = gz->astgen; 1207 ensureInstCapacity(ag, 1); 1208 ensureExtraCapacity(ag, 2); 1209 1210 // Write Zir.Inst.Break payload to extra (Zir.zig:2489). 1211 uint32_t payload_index = ag->extra_len; 1212 ag->extra[ag->extra_len++] = (uint32_t)operand_src_node; 1213 ag->extra[ag->extra_len++] = block_inst; 1214 1215 uint32_t idx = ag->inst_len; 1216 ag->inst_tags[idx] = ZIR_INST_BREAK_INLINE; 1217 ZirInstData data; 1218 data.break_data.operand = operand; 1219 data.break_data.payload_index = payload_index; 1220 ag->inst_datas[idx] = data; 1221 ag->inst_len++; 1222 1223 // Record in sub-block body. 1224 gzAppendInstruction(gz, idx); 1225 return idx; 1226 } 1227 1228 // Mirrors GenZir.makeBlockInst (AstGen.zig:12890). 1229 // Creates a pl_node instruction with payload_index left as 0 (set later). 1230 // Does NOT append to gz's instruction list. 1231 // Returns instruction index (not a ref). 1232 static uint32_t makeBlockInst( 1233 AstGenCtx* ag, ZirInstTag tag, const GenZir* gz, uint32_t node) { 1234 ensureInstCapacity(ag, 1); 1235 uint32_t idx = ag->inst_len; 1236 ag->inst_tags[idx] = tag; 1237 ZirInstData data; 1238 memset(&data, 0, sizeof(data)); 1239 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 1240 data.pl_node.payload_index = 0; // set later 1241 ag->inst_datas[idx] = data; 1242 ag->inst_len++; 1243 return idx; 1244 } 1245 1246 // Mirrors appendPossiblyRefdBodyInst (AstGen.zig:13675-13683). 1247 // Appends body_inst first, then recursively appends ref_table entry. 1248 static void appendPossiblyRefdBodyInst(AstGenCtx* ag, uint32_t body_inst) { 1249 ag->extra[ag->extra_len++] = body_inst; 1250 uint32_t ref_inst; 1251 if (refTableFetchRemove(ag, body_inst, &ref_inst)) { 1252 appendPossiblyRefdBodyInst(ag, ref_inst); 1253 } 1254 } 1255 1256 // Mirrors appendBodyWithFixupsExtraRefsArrayList (AstGen.zig:13659-13673). 1257 // First processes extra_refs (e.g. param_insts), prepending their ref_table 1258 // entries. Then writes body instructions with ref_table fixups. 1259 static void appendBodyWithFixupsExtraRefs(AstGenCtx* ag, const uint32_t* body, 1260 uint32_t body_len, const uint32_t* extra_refs, uint32_t extra_refs_len) { 1261 for (uint32_t i = 0; i < extra_refs_len; i++) { 1262 uint32_t ref_inst; 1263 if (refTableFetchRemove(ag, extra_refs[i], &ref_inst)) { 1264 appendPossiblyRefdBodyInst(ag, ref_inst); 1265 } 1266 } 1267 for (uint32_t i = 0; i < body_len; i++) { 1268 appendPossiblyRefdBodyInst(ag, body[i]); 1269 } 1270 } 1271 1272 // Scratch extra capacity helper (for call arg bodies). 1273 static void ensureScratchExtraCapacity(AstGenCtx* ag, uint32_t additional) { 1274 uint32_t needed = ag->scratch_extra_len + additional; 1275 if (needed > ag->scratch_extra_cap) { 1276 uint32_t new_cap = ag->scratch_extra_cap * 2; 1277 if (new_cap < needed) 1278 new_cap = needed; 1279 if (new_cap < 64) 1280 new_cap = 64; 1281 uint32_t* p = realloc(ag->scratch_extra, new_cap * sizeof(uint32_t)); 1282 if (!p) 1283 exit(1); 1284 ag->scratch_extra = p; 1285 ag->scratch_extra_cap = new_cap; 1286 } 1287 } 1288 1289 // Like appendPossiblyRefdBodyInst but appends to scratch_extra instead of 1290 // extra. 1291 static void appendPossiblyRefdBodyInstScratch( 1292 AstGenCtx* ag, uint32_t body_inst) { 1293 ag->scratch_extra[ag->scratch_extra_len++] = body_inst; 1294 uint32_t ref_inst; 1295 if (refTableFetchRemove(ag, body_inst, &ref_inst)) { 1296 ensureScratchExtraCapacity(ag, 1); 1297 appendPossiblyRefdBodyInstScratch(ag, ref_inst); 1298 } 1299 } 1300 1301 // Mirrors countBodyLenAfterFixupsExtraRefs (AstGen.zig:13694-13711). 1302 static uint32_t countBodyLenAfterFixupsExtraRefs(AstGenCtx* ag, 1303 const uint32_t* body, uint32_t body_len, const uint32_t* extra_refs, 1304 uint32_t extra_refs_len) { 1305 uint32_t count = body_len; 1306 for (uint32_t i = 0; i < body_len; i++) { 1307 uint32_t check_inst = body[i]; 1308 const uint32_t* ref; 1309 while ((ref = refTableGet(ag, check_inst)) != NULL) { 1310 count++; 1311 check_inst = *ref; 1312 } 1313 } 1314 for (uint32_t i = 0; i < extra_refs_len; i++) { 1315 uint32_t check_inst = extra_refs[i]; 1316 const uint32_t* ref; 1317 while ((ref = refTableGet(ag, check_inst)) != NULL) { 1318 count++; 1319 check_inst = *ref; 1320 } 1321 } 1322 return count; 1323 } 1324 1325 // Mirrors countBodyLenAfterFixups (AstGen.zig:13686-13688). 1326 static uint32_t countBodyLenAfterFixups( 1327 AstGenCtx* ag, const uint32_t* body, uint32_t body_len) { 1328 return countBodyLenAfterFixupsExtraRefs(ag, body, body_len, NULL, 0); 1329 } 1330 1331 // Mirrors GenZir.setBlockBody (AstGen.zig:11949). 1332 // Writes Block payload (body_len + instruction indices) to extra. 1333 // Sets the instruction's payload_index. Unstacks gz. 1334 static void setBlockBody(AstGenCtx* ag, GenZir* gz, uint32_t inst) { 1335 uint32_t raw_body_len = gzInstructionsLen(gz); 1336 const uint32_t* body = gzInstructionsSlice(gz); 1337 uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_body_len); 1338 ensureExtraCapacity(ag, 1 + body_len); 1339 uint32_t payload_index = ag->extra_len; 1340 ag->extra[ag->extra_len++] = body_len; 1341 for (uint32_t i = 0; i < raw_body_len; i++) { 1342 appendPossiblyRefdBodyInst(ag, body[i]); 1343 } 1344 ag->inst_datas[inst].pl_node.payload_index = payload_index; 1345 gzUnstack(gz); 1346 } 1347 1348 // Mirrors GenZir.setTryBody (AstGen.zig:11997). 1349 // Writes Try payload (operand + body_len + instruction indices) to extra. 1350 // Sets the instruction's payload_index. Unstacks gz. 1351 static void setTryBody( 1352 AstGenCtx* ag, GenZir* gz, uint32_t inst, uint32_t operand) { 1353 uint32_t raw_body_len = gzInstructionsLen(gz); 1354 const uint32_t* body = gzInstructionsSlice(gz); 1355 uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_body_len); 1356 ensureExtraCapacity(ag, 2 + body_len); 1357 uint32_t payload_index = ag->extra_len; 1358 ag->extra[ag->extra_len++] = operand; // Try.operand 1359 ag->extra[ag->extra_len++] = body_len; // Try.body_len 1360 for (uint32_t i = 0; i < raw_body_len; i++) { 1361 appendPossiblyRefdBodyInst(ag, body[i]); 1362 } 1363 ag->inst_datas[inst].pl_node.payload_index = payload_index; 1364 gzUnstack(gz); 1365 } 1366 1367 // Mirrors GenZir.setBlockComptimeBody (AstGen.zig:11972). 1368 // Like setBlockBody but prepends comptime_reason before body_len. 1369 // Asserts inst is a BLOCK_COMPTIME. 1370 static void setBlockComptimeBody( 1371 AstGenCtx* ag, GenZir* gz, uint32_t inst, uint32_t comptime_reason) { 1372 uint32_t raw_body_len = gzInstructionsLen(gz); 1373 const uint32_t* body = gzInstructionsSlice(gz); 1374 uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_body_len); 1375 ensureExtraCapacity(ag, 2 + body_len); 1376 uint32_t payload_index = ag->extra_len; 1377 ag->extra[ag->extra_len++] = comptime_reason; 1378 ag->extra[ag->extra_len++] = body_len; 1379 for (uint32_t i = 0; i < raw_body_len; i++) { 1380 appendPossiblyRefdBodyInst(ag, body[i]); 1381 } 1382 ag->inst_datas[inst].pl_node.payload_index = payload_index; 1383 gzUnstack(gz); 1384 } 1385 1386 // Mirrors GenZir.addBreak (AstGen.zig:12623). 1387 // Creates a ZIR_INST_BREAK instruction. 1388 static uint32_t addBreak(GenZir* gz, ZirInstTag tag, uint32_t block_inst, 1389 uint32_t operand, int32_t operand_src_node) { 1390 AstGenCtx* ag = gz->astgen; 1391 ensureInstCapacity(ag, 1); 1392 ensureExtraCapacity(ag, 2); 1393 1394 uint32_t payload_index = ag->extra_len; 1395 ag->extra[ag->extra_len++] = (uint32_t)operand_src_node; 1396 ag->extra[ag->extra_len++] = block_inst; 1397 1398 uint32_t idx = ag->inst_len; 1399 ag->inst_tags[idx] = tag; 1400 ZirInstData data; 1401 data.break_data.operand = operand; 1402 data.break_data.payload_index = payload_index; 1403 ag->inst_datas[idx] = data; 1404 ag->inst_len++; 1405 gzAppendInstruction(gz, idx); 1406 return idx; 1407 } 1408 1409 // Mirrors GenZir.addCondBr (AstGen.zig:12834). 1410 // Creates condbr instruction placeholder with src_node set. 1411 // Payload is filled later by setCondBrPayload. 1412 static uint32_t addCondBr(GenZir* gz, ZirInstTag tag, uint32_t node) { 1413 AstGenCtx* ag = gz->astgen; 1414 ensureInstCapacity(ag, 1); 1415 uint32_t idx = ag->inst_len; 1416 ag->inst_tags[idx] = tag; 1417 ZirInstData data; 1418 memset(&data, 0, sizeof(data)); 1419 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 1420 data.pl_node.payload_index = 0; // set later 1421 ag->inst_datas[idx] = data; 1422 ag->inst_len++; 1423 gzAppendInstruction(gz, idx); 1424 return idx; 1425 } 1426 1427 // Mirrors setCondBrPayload (AstGen.zig:6501). 1428 // Writes CondBr payload: {condition, then_body_len, else_body_len} then 1429 // then_body instructions, then else_body instructions. Unstacks both scopes. 1430 // IMPORTANT: then_gz and else_gz are stacked (else on top of then), so 1431 // then's instructions must use instructionsSliceUpto(else_gz) to avoid 1432 // including else_gz's instructions in then's body. 1433 static void setCondBrPayload(AstGenCtx* ag, uint32_t condbr_inst, 1434 uint32_t condition, GenZir* then_gz, GenZir* else_gz) { 1435 uint32_t raw_then_len = gzInstructionsLenUpto(then_gz, else_gz); 1436 const uint32_t* then_body = gzInstructionsSliceUpto(then_gz, else_gz); 1437 uint32_t raw_else_len = gzInstructionsLen(else_gz); 1438 const uint32_t* else_body = gzInstructionsSlice(else_gz); 1439 1440 uint32_t then_len = countBodyLenAfterFixups(ag, then_body, raw_then_len); 1441 uint32_t else_len = countBodyLenAfterFixups(ag, else_body, raw_else_len); 1442 1443 ensureExtraCapacity(ag, 3 + then_len + else_len); 1444 uint32_t payload_index = ag->extra_len; 1445 ag->extra[ag->extra_len++] = condition; // CondBr.condition 1446 ag->extra[ag->extra_len++] = then_len; // CondBr.then_body_len 1447 ag->extra[ag->extra_len++] = else_len; // CondBr.else_body_len 1448 for (uint32_t i = 0; i < raw_then_len; i++) 1449 appendPossiblyRefdBodyInst(ag, then_body[i]); 1450 for (uint32_t i = 0; i < raw_else_len; i++) 1451 appendPossiblyRefdBodyInst(ag, else_body[i]); 1452 1453 ag->inst_datas[condbr_inst].pl_node.payload_index = payload_index; 1454 gzUnstack(else_gz); 1455 gzUnstack(then_gz); 1456 } 1457 1458 // Does this Declaration.Flags.Id have a name? (Zir.zig:2762) 1459 static bool declIdHasName(DeclFlagsId id) { 1460 return id != DECL_ID_UNNAMED_TEST && id != DECL_ID_COMPTIME; 1461 } 1462 1463 // Does this Declaration.Flags.Id have a lib name? (Zir.zig:2771) 1464 static bool declIdHasLibName(DeclFlagsId id) { 1465 switch (id) { 1466 case DECL_ID_EXTERN_CONST: 1467 case DECL_ID_PUB_EXTERN_CONST: 1468 case DECL_ID_EXTERN_VAR: 1469 case DECL_ID_EXTERN_VAR_THREADLOCAL: 1470 case DECL_ID_PUB_EXTERN_VAR: 1471 case DECL_ID_PUB_EXTERN_VAR_THREADLOCAL: 1472 return true; 1473 default: 1474 return false; 1475 } 1476 } 1477 1478 // Does this Declaration.Flags.Id have a type body? (Zir.zig:2783) 1479 static bool declIdHasTypeBody(DeclFlagsId id) { 1480 switch (id) { 1481 case DECL_ID_UNNAMED_TEST: 1482 case DECL_ID_TEST: 1483 case DECL_ID_DECLTEST: 1484 case DECL_ID_COMPTIME: 1485 case DECL_ID_CONST_SIMPLE: 1486 case DECL_ID_PUB_CONST_SIMPLE: 1487 case DECL_ID_VAR_SIMPLE: 1488 case DECL_ID_PUB_VAR_SIMPLE: 1489 return false; 1490 default: 1491 return true; 1492 } 1493 } 1494 1495 // Does this Declaration.Flags.Id have a value body? (Zir.zig:2800) 1496 static bool declIdHasValueBody(DeclFlagsId id) { 1497 switch (id) { 1498 case DECL_ID_EXTERN_CONST_SIMPLE: 1499 case DECL_ID_EXTERN_CONST: 1500 case DECL_ID_PUB_EXTERN_CONST_SIMPLE: 1501 case DECL_ID_PUB_EXTERN_CONST: 1502 case DECL_ID_EXTERN_VAR: 1503 case DECL_ID_EXTERN_VAR_THREADLOCAL: 1504 case DECL_ID_PUB_EXTERN_VAR: 1505 case DECL_ID_PUB_EXTERN_VAR_THREADLOCAL: 1506 return false; 1507 default: 1508 return true; 1509 } 1510 } 1511 1512 // Does this Declaration.Flags.Id have special bodies? (Zir.zig:2815) 1513 static bool declIdHasSpecialBodies(DeclFlagsId id) { 1514 switch (id) { 1515 case DECL_ID_UNNAMED_TEST: 1516 case DECL_ID_TEST: 1517 case DECL_ID_DECLTEST: 1518 case DECL_ID_COMPTIME: 1519 case DECL_ID_CONST_SIMPLE: 1520 case DECL_ID_CONST_TYPED: 1521 case DECL_ID_PUB_CONST_SIMPLE: 1522 case DECL_ID_PUB_CONST_TYPED: 1523 case DECL_ID_EXTERN_CONST_SIMPLE: 1524 case DECL_ID_PUB_EXTERN_CONST_SIMPLE: 1525 case DECL_ID_VAR_SIMPLE: 1526 case DECL_ID_PUB_VAR_SIMPLE: 1527 return false; 1528 default: 1529 return true; 1530 } 1531 } 1532 1533 // Mirrors setDeclaration (AstGen.zig:13883). 1534 // Full version with type/align/linksection/addrspace/value bodies. 1535 typedef struct { 1536 uint32_t src_line; 1537 uint32_t src_column; 1538 DeclFlagsId id; 1539 uint32_t name; // NullTerminatedString index 1540 uint32_t lib_name; // NullTerminatedString index (UINT32_MAX=none) 1541 const uint32_t* type_body; 1542 uint32_t type_body_len; 1543 const uint32_t* align_body; 1544 uint32_t align_body_len; 1545 const uint32_t* linksection_body; 1546 uint32_t linksection_body_len; 1547 const uint32_t* addrspace_body; 1548 uint32_t addrspace_body_len; 1549 const uint32_t* value_body; 1550 uint32_t value_body_len; 1551 } SetDeclArgs; 1552 1553 static void setDeclaration( 1554 AstGenCtx* ag, uint32_t decl_inst, SetDeclArgs args) { 1555 DeclFlagsId id = args.id; 1556 bool has_name = declIdHasName(id); 1557 bool has_lib_name = declIdHasLibName(id); 1558 bool has_type_body_field = declIdHasTypeBody(id); 1559 bool has_special_bodies = declIdHasSpecialBodies(id); 1560 bool has_value_body_field = declIdHasValueBody(id); 1561 1562 uint32_t type_len 1563 = countBodyLenAfterFixups(ag, args.type_body, args.type_body_len); 1564 uint32_t align_len 1565 = countBodyLenAfterFixups(ag, args.align_body, args.align_body_len); 1566 uint32_t linksection_len = countBodyLenAfterFixups( 1567 ag, args.linksection_body, args.linksection_body_len); 1568 uint32_t addrspace_len = countBodyLenAfterFixups( 1569 ag, args.addrspace_body, args.addrspace_body_len); 1570 uint32_t value_len 1571 = countBodyLenAfterFixups(ag, args.value_body, args.value_body_len); 1572 1573 uint32_t need = 6; // src_hash[4] + flags[2] 1574 if (has_name) 1575 need++; 1576 if (has_lib_name) 1577 need++; 1578 if (has_type_body_field) 1579 need++; 1580 if (has_special_bodies) 1581 need += 3; 1582 if (has_value_body_field) 1583 need++; 1584 need += type_len + align_len + linksection_len + addrspace_len + value_len; 1585 ensureExtraCapacity(ag, need); 1586 1587 uint32_t payload_start = ag->extra_len; 1588 1589 // src_hash (4 words): zero-filled; hash comparison skipped in tests. 1590 ag->extra[ag->extra_len++] = 0; 1591 ag->extra[ag->extra_len++] = 0; 1592 ag->extra[ag->extra_len++] = 0; 1593 ag->extra[ag->extra_len++] = 0; 1594 1595 // Declaration.Flags: packed struct(u64) { src_line: u30, src_column: u29, 1596 // id: u5 } (Zir.zig:2719) 1597 uint64_t flags = 0; 1598 flags |= (uint64_t)(args.src_line & 0x3FFFFFFFu); 1599 flags |= (uint64_t)(args.src_column & 0x1FFFFFFFu) << 30; 1600 flags |= (uint64_t)((uint32_t)id & 0x1Fu) << 59; 1601 ag->extra[ag->extra_len++] = (uint32_t)(flags & 0xFFFFFFFFu); 1602 ag->extra[ag->extra_len++] = (uint32_t)(flags >> 32); 1603 1604 if (has_name) 1605 ag->extra[ag->extra_len++] = args.name; 1606 if (has_lib_name) { 1607 ag->extra[ag->extra_len++] 1608 = (args.lib_name != UINT32_MAX) ? args.lib_name : 0; 1609 } 1610 if (has_type_body_field) 1611 ag->extra[ag->extra_len++] = type_len; 1612 if (has_special_bodies) { 1613 ag->extra[ag->extra_len++] = align_len; 1614 ag->extra[ag->extra_len++] = linksection_len; 1615 ag->extra[ag->extra_len++] = addrspace_len; 1616 } 1617 if (has_value_body_field) 1618 ag->extra[ag->extra_len++] = value_len; 1619 1620 for (uint32_t i = 0; i < args.type_body_len; i++) 1621 appendPossiblyRefdBodyInst(ag, args.type_body[i]); 1622 for (uint32_t i = 0; i < args.align_body_len; i++) 1623 appendPossiblyRefdBodyInst(ag, args.align_body[i]); 1624 for (uint32_t i = 0; i < args.linksection_body_len; i++) 1625 appendPossiblyRefdBodyInst(ag, args.linksection_body[i]); 1626 for (uint32_t i = 0; i < args.addrspace_body_len; i++) 1627 appendPossiblyRefdBodyInst(ag, args.addrspace_body[i]); 1628 for (uint32_t i = 0; i < args.value_body_len; i++) 1629 appendPossiblyRefdBodyInst(ag, args.value_body[i]); 1630 1631 ag->inst_datas[decl_inst].declaration.payload_index = payload_start; 1632 } 1633 1634 // --- StructDecl.Small packing (Zir.zig StructDecl.Small) --- 1635 1636 typedef struct { 1637 bool has_captures_len; 1638 bool has_fields_len; 1639 bool has_decls_len; 1640 bool has_backing_int; 1641 bool known_non_opv; 1642 bool known_comptime_only; 1643 uint8_t name_strategy; // 2 bits 1644 uint8_t layout; // 2 bits 1645 bool any_default_inits; 1646 bool any_comptime_fields; 1647 bool any_aligned_fields; 1648 } StructDeclSmall; 1649 1650 static uint16_t packStructDeclSmall(StructDeclSmall s) { 1651 uint16_t r = 0; 1652 if (s.has_captures_len) 1653 r |= (1u << 0); 1654 if (s.has_fields_len) 1655 r |= (1u << 1); 1656 if (s.has_decls_len) 1657 r |= (1u << 2); 1658 if (s.has_backing_int) 1659 r |= (1u << 3); 1660 if (s.known_non_opv) 1661 r |= (1u << 4); 1662 if (s.known_comptime_only) 1663 r |= (1u << 5); 1664 r |= (uint16_t)(s.name_strategy & 0x3u) << 6; 1665 r |= (uint16_t)(s.layout & 0x3u) << 8; 1666 if (s.any_default_inits) 1667 r |= (1u << 10); 1668 if (s.any_comptime_fields) 1669 r |= (1u << 11); 1670 if (s.any_aligned_fields) 1671 r |= (1u << 12); 1672 return r; 1673 } 1674 1675 // Mirrors GenZir.setStruct (AstGen.zig:12935). 1676 // Writes StructDecl payload and optional length fields. 1677 // The caller appends captures, backing_int, decls, fields, bodies after. 1678 static void setStruct(AstGenCtx* ag, uint32_t inst, uint32_t src_node, 1679 StructDeclSmall small, uint32_t captures_len, uint32_t fields_len, 1680 uint32_t decls_len) { 1681 ensureExtraCapacity(ag, 6 + 3); 1682 1683 uint32_t payload_index = ag->extra_len; 1684 1685 // fields_hash (4 words): zero-filled; hash comparison skipped in tests. 1686 ag->extra[ag->extra_len++] = 0; 1687 ag->extra[ag->extra_len++] = 0; 1688 ag->extra[ag->extra_len++] = 0; 1689 ag->extra[ag->extra_len++] = 0; 1690 1691 ag->extra[ag->extra_len++] = ag->source_line; 1692 ag->extra[ag->extra_len++] = src_node; 1693 1694 if (small.has_captures_len) 1695 ag->extra[ag->extra_len++] = captures_len; 1696 if (small.has_fields_len) 1697 ag->extra[ag->extra_len++] = fields_len; 1698 if (small.has_decls_len) 1699 ag->extra[ag->extra_len++] = decls_len; 1700 1701 ag->inst_tags[inst] = ZIR_INST_EXTENDED; 1702 ZirInstData data; 1703 memset(&data, 0, sizeof(data)); 1704 data.extended.opcode = (uint16_t)ZIR_EXT_STRUCT_DECL; 1705 data.extended.small = packStructDeclSmall(small); 1706 data.extended.operand = payload_index; 1707 ag->inst_datas[inst] = data; 1708 } 1709 1710 // --- scanContainer (AstGen.zig:13384) --- 1711 1712 // Add a name→node entry to the decl table. 1713 static void addDeclToTable( 1714 AstGenCtx* ag, uint32_t name_str_index, uint32_t node) { 1715 if (ag->decl_table_len >= ag->decl_table_cap) { 1716 uint32_t new_cap = ag->decl_table_cap > 0 ? ag->decl_table_cap * 2 : 8; 1717 uint32_t* n = realloc(ag->decl_names, new_cap * sizeof(uint32_t)); 1718 uint32_t* d = realloc(ag->decl_nodes, new_cap * sizeof(uint32_t)); 1719 if (!n || !d) 1720 exit(1); 1721 ag->decl_names = n; 1722 ag->decl_nodes = d; 1723 ag->decl_table_cap = new_cap; 1724 } 1725 ag->decl_names[ag->decl_table_len] = name_str_index; 1726 ag->decl_nodes[ag->decl_table_len] = node; 1727 ag->decl_table_len++; 1728 } 1729 1730 // Mirrors scanContainer (AstGen.zig:13384). 1731 // Also populates the decl table (namespace.decls) for identifier resolution. 1732 static uint32_t scanContainer( 1733 AstGenCtx* ag, const uint32_t* members, uint32_t member_count) { 1734 const Ast* tree = ag->tree; 1735 uint32_t decl_count = 0; 1736 for (uint32_t i = 0; i < member_count; i++) { 1737 uint32_t member = members[i]; 1738 AstNodeTag tag = tree->nodes.tags[member]; 1739 switch (tag) { 1740 case AST_NODE_GLOBAL_VAR_DECL: 1741 case AST_NODE_LOCAL_VAR_DECL: 1742 case AST_NODE_SIMPLE_VAR_DECL: 1743 case AST_NODE_ALIGNED_VAR_DECL: { 1744 decl_count++; 1745 uint32_t name_token = tree->nodes.main_tokens[member] + 1; 1746 uint32_t name_str = identAsString(ag, name_token); 1747 addDeclToTable(ag, name_str, member); 1748 break; 1749 } 1750 case AST_NODE_FN_PROTO_SIMPLE: 1751 case AST_NODE_FN_PROTO_MULTI: 1752 case AST_NODE_FN_PROTO_ONE: 1753 case AST_NODE_FN_PROTO: 1754 case AST_NODE_FN_DECL: { 1755 decl_count++; 1756 uint32_t name_token = tree->nodes.main_tokens[member] + 1; 1757 uint32_t name_str = identAsString(ag, name_token); 1758 addDeclToTable(ag, name_str, member); 1759 break; 1760 } 1761 // Container fields: add field name to string table for ordering 1762 // (AstGen.zig:13509). 1763 case AST_NODE_CONTAINER_FIELD_INIT: 1764 case AST_NODE_CONTAINER_FIELD_ALIGN: 1765 case AST_NODE_CONTAINER_FIELD: { 1766 uint32_t main_token = tree->nodes.main_tokens[member]; 1767 identAsString(ag, main_token); 1768 break; 1769 } 1770 case AST_NODE_COMPTIME: 1771 decl_count++; 1772 break; 1773 case AST_NODE_TEST_DECL: { 1774 decl_count++; 1775 // Process test name string to match upstream string table 1776 // ordering (AstGen.zig:13465-13500). 1777 uint32_t test_name_token = tree->nodes.main_tokens[member] + 1; 1778 TokenizerTag tt = tree->tokens.tags[test_name_token]; 1779 if (tt == TOKEN_STRING_LITERAL) { 1780 uint32_t si, sl; 1781 strLitAsString(ag, test_name_token, &si, &sl); 1782 } else if (tt == TOKEN_IDENTIFIER) { 1783 identAsString(ag, test_name_token); 1784 } 1785 break; 1786 } 1787 default: 1788 break; 1789 } 1790 } 1791 return decl_count; 1792 } 1793 1794 // --- Import tracking --- 1795 1796 static void addImport(AstGenCtx* ag, uint32_t name_index, uint32_t token) { 1797 // Check for duplicates. 1798 for (uint32_t i = 0; i < ag->imports_len; i++) { 1799 if (ag->imports[i].name == name_index) 1800 return; 1801 } 1802 if (ag->imports_len >= ag->imports_cap) { 1803 uint32_t new_cap = ag->imports_cap > 0 ? ag->imports_cap * 2 : 4; 1804 ImportEntry* p = realloc(ag->imports, new_cap * sizeof(ImportEntry)); 1805 if (!p) 1806 exit(1); 1807 ag->imports = p; 1808 ag->imports_cap = new_cap; 1809 } 1810 ag->imports[ag->imports_len].name = name_index; 1811 ag->imports[ag->imports_len].token = token; 1812 ag->imports_len++; 1813 } 1814 1815 // Write imports list to extra (AstGen.zig:227-244). 1816 static void writeImports(AstGenCtx* ag) { 1817 if (ag->imports_len == 0) { 1818 ag->extra[ZIR_EXTRA_IMPORTS] = 0; 1819 return; 1820 } 1821 uint32_t need = 1 + ag->imports_len * 2; 1822 ensureExtraCapacity(ag, need); 1823 uint32_t imports_index = ag->extra_len; 1824 ag->extra[ag->extra_len++] = ag->imports_len; 1825 for (uint32_t i = 0; i < ag->imports_len; i++) { 1826 ag->extra[ag->extra_len++] = ag->imports[i].name; 1827 ag->extra[ag->extra_len++] = ag->imports[i].token; 1828 } 1829 ag->extra[ZIR_EXTRA_IMPORTS] = imports_index; 1830 } 1831 1832 // ri.br() (AstGen.zig:274-282): convert coerced_ty to ty for branching. 1833 static inline ResultLoc rlBr(ResultLoc rl) { 1834 if (rl.tag == RL_COERCED_TY) { 1835 return (ResultLoc) { 1836 .tag = RL_TY, .data = rl.data, .src_node = 0, .ctx = rl.ctx 1837 }; 1838 } 1839 return rl; 1840 } 1841 1842 // setBreakResultInfo (AstGen.zig:11905-11926): compute break result info 1843 // from parent RL. Converts coerced_ty → ty, discard → discard, else passes 1844 // through. For ptr/inferred_ptr, converts to ty/none respectively. 1845 static ResultLoc breakResultInfo( 1846 GenZir* gz, ResultLoc parent_rl, uint32_t node, bool need_rl) { 1847 // First: compute block_ri (AstGen.zig:7639-7646). 1848 // When need_rl is true, forward the rl as-is (don't convert ptr→ty). 1849 ResultLoc block_ri; 1850 if (need_rl) { 1851 block_ri = parent_rl; 1852 } else { 1853 switch (parent_rl.tag) { 1854 case RL_PTR: { 1855 uint32_t ptr_ty 1856 = addUnNode(gz, ZIR_INST_TYPEOF, parent_rl.data, node); 1857 uint32_t ty = addUnNode(gz, ZIR_INST_ELEM_TYPE, ptr_ty, node); 1858 block_ri = (ResultLoc) { 1859 .tag = RL_TY, .data = ty, .src_node = 0, .ctx = parent_rl.ctx 1860 }; 1861 break; 1862 } 1863 case RL_INFERRED_PTR: 1864 block_ri = (ResultLoc) { 1865 .tag = RL_NONE, .data = 0, .src_node = 0, .ctx = parent_rl.ctx 1866 }; 1867 break; 1868 default: 1869 block_ri = parent_rl; 1870 break; 1871 } 1872 } 1873 // Then: setBreakResultInfo (AstGen.zig:11910-11925). 1874 switch (block_ri.tag) { 1875 case RL_COERCED_TY: 1876 return (ResultLoc) { .tag = RL_TY, 1877 .data = block_ri.data, 1878 .src_node = 0, 1879 .ctx = block_ri.ctx }; 1880 case RL_DISCARD: 1881 // Don't forward ctx (AstGen.zig:11916-11920). 1882 return RL_DISCARD_VAL; 1883 default: 1884 return block_ri; 1885 } 1886 } 1887 1888 // resultType (AstGen.zig:341-351): extract result type from RL. 1889 // Returns 0 if no result type available. 1890 static uint32_t rlResultType(GenZir* gz, ResultLoc rl, uint32_t node) { 1891 switch (rl.tag) { 1892 case RL_TY: 1893 case RL_COERCED_TY: 1894 return rl.data; 1895 case RL_REF_COERCED_TY: 1896 // AstGen.zig:345: .ref_coerced_ty => |ptr_ty| gz.addUnNode(.elem_type, 1897 // ptr_ty, node) 1898 return addUnNode(gz, ZIR_INST_ELEM_TYPE, rl.data, node); 1899 case RL_PTR: { 1900 // typeof(ptr) -> elem_type (AstGen.zig:346-349). 1901 uint32_t ptr_ty = addUnNode(gz, ZIR_INST_TYPEOF, rl.data, node); 1902 return addUnNode(gz, ZIR_INST_ELEM_TYPE, ptr_ty, node); 1903 } 1904 default: 1905 return 0; 1906 } 1907 } 1908 1909 // rvalue (AstGen.zig:11051-11224): apply result location wrapping. 1910 static uint32_t rvalue( 1911 GenZir* gz, ResultLoc rl, uint32_t result, uint32_t node) { 1912 switch (rl.tag) { 1913 case RL_NONE: 1914 case RL_COERCED_TY: 1915 return result; 1916 case RL_DISCARD: 1917 // ensure_result_non_error (AstGen.zig:11071-11074). 1918 addUnNode(gz, ZIR_INST_ENSURE_RESULT_NON_ERROR, result, node); 1919 return ZIR_REF_VOID_VALUE; 1920 case RL_REF: 1921 case RL_REF_COERCED_TY: { 1922 // coerce_ptr_elem_ty for ref_coerced_ty (AstGen.zig:11077-11083). 1923 uint32_t coerced_result = result; 1924 if (rl.tag == RL_REF_COERCED_TY) { 1925 coerced_result = addPlNodeBin( 1926 gz, ZIR_INST_COERCE_PTR_ELEM_TY, node, rl.data, result); 1927 } 1928 AstGenCtx* ag = gz->astgen; 1929 uint32_t src_token = firstToken(ag->tree, node); 1930 // If result is not an instruction index (e.g. a well-known ref), 1931 // emit ref directly (AstGen.zig:11091-11092). 1932 if (coerced_result < ZIR_REF_START_INDEX) { 1933 return addUnTok(gz, ZIR_INST_REF, coerced_result, src_token); 1934 } 1935 // Deduplication via ref_table (AstGen.zig:11093-11097). 1936 uint32_t result_index = coerced_result - ZIR_REF_START_INDEX; 1937 bool found; 1938 uint32_t* val_ptr = refTableGetOrPut(ag, result_index, &found); 1939 if (!found) { 1940 *val_ptr = makeUnTok(gz, ZIR_INST_REF, coerced_result, src_token); 1941 } 1942 return *val_ptr + ZIR_REF_START_INDEX; 1943 } 1944 case RL_TY: { 1945 // Quick elimination of common, unnecessary type coercions 1946 // (AstGen.zig:11099-11209). 1947 #define RC(t, v) (((uint64_t)(t) << 32) | (uint64_t)(v)) 1948 uint64_t combined = RC(rl.data, result); 1949 switch (combined) { 1950 // Identity: type of result is already correct 1951 // (AstGen.zig:11109-11176). 1952 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_U1_TYPE): 1953 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_U8_TYPE): 1954 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_I8_TYPE): 1955 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_U16_TYPE): 1956 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_U29_TYPE): 1957 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_I16_TYPE): 1958 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_U32_TYPE): 1959 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_I32_TYPE): 1960 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_U64_TYPE): 1961 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_I64_TYPE): 1962 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_U128_TYPE): 1963 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_I128_TYPE): 1964 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_USIZE_TYPE): 1965 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_ISIZE_TYPE): 1966 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_CHAR_TYPE): 1967 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_SHORT_TYPE): 1968 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_USHORT_TYPE): 1969 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_INT_TYPE): 1970 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_UINT_TYPE): 1971 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_LONG_TYPE): 1972 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_ULONG_TYPE): 1973 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_LONGLONG_TYPE): 1974 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_ULONGLONG_TYPE): 1975 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_C_LONGDOUBLE_TYPE): 1976 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_F16_TYPE): 1977 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_F32_TYPE): 1978 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_F64_TYPE): 1979 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_F80_TYPE): 1980 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_F128_TYPE): 1981 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_ANYOPAQUE_TYPE): 1982 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_BOOL_TYPE): 1983 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_VOID_TYPE): 1984 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_TYPE_TYPE): 1985 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_ANYERROR_TYPE): 1986 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_COMPTIME_INT_TYPE): 1987 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_COMPTIME_FLOAT_TYPE): 1988 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_NORETURN_TYPE): 1989 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_ANYFRAME_TYPE): 1990 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_NULL_TYPE): 1991 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_UNDEFINED_TYPE): 1992 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_ENUM_LITERAL_TYPE): 1993 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_PTR_USIZE_TYPE): 1994 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_PTR_CONST_COMPTIME_INT_TYPE): 1995 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_MANYPTR_U8_TYPE): 1996 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_MANYPTR_CONST_U8_TYPE): 1997 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_MANYPTR_CONST_U8_SENTINEL_0_TYPE): 1998 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_SLICE_CONST_U8_TYPE): 1999 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_SLICE_CONST_U8_SENTINEL_0_TYPE): 2000 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_ANYERROR_VOID_ERROR_UNION_TYPE): 2001 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_GENERIC_POISON_TYPE): 2002 case RC(ZIR_REF_TYPE_TYPE, ZIR_REF_EMPTY_TUPLE_TYPE): 2003 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ZERO): 2004 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ONE): 2005 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_NEGATIVE_ONE): 2006 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_UNDEF_USIZE): 2007 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ZERO_USIZE): 2008 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ONE_USIZE): 2009 case RC(ZIR_REF_U1_TYPE, ZIR_REF_UNDEF_U1): 2010 case RC(ZIR_REF_U1_TYPE, ZIR_REF_ZERO_U1): 2011 case RC(ZIR_REF_U1_TYPE, ZIR_REF_ONE_U1): 2012 case RC(ZIR_REF_U8_TYPE, ZIR_REF_ZERO_U8): 2013 case RC(ZIR_REF_U8_TYPE, ZIR_REF_ONE_U8): 2014 case RC(ZIR_REF_U8_TYPE, ZIR_REF_FOUR_U8): 2015 case RC(ZIR_REF_BOOL_TYPE, ZIR_REF_UNDEF_BOOL): 2016 case RC(ZIR_REF_BOOL_TYPE, ZIR_REF_BOOL_TRUE): 2017 case RC(ZIR_REF_BOOL_TYPE, ZIR_REF_BOOL_FALSE): 2018 case RC(ZIR_REF_VOID_TYPE, ZIR_REF_VOID_VALUE): 2019 return result; 2020 // Conversions (AstGen.zig:11178-11202). 2021 case RC(ZIR_REF_BOOL_TYPE, ZIR_REF_UNDEF): 2022 return ZIR_REF_UNDEF_BOOL; 2023 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_UNDEF): 2024 return ZIR_REF_UNDEF_USIZE; 2025 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_UNDEF_U1): 2026 return ZIR_REF_UNDEF_USIZE; 2027 case RC(ZIR_REF_U1_TYPE, ZIR_REF_UNDEF): 2028 return ZIR_REF_UNDEF_U1; 2029 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ZERO): 2030 return ZIR_REF_ZERO_USIZE; 2031 case RC(ZIR_REF_U1_TYPE, ZIR_REF_ZERO): 2032 return ZIR_REF_ZERO_U1; 2033 case RC(ZIR_REF_U8_TYPE, ZIR_REF_ZERO): 2034 return ZIR_REF_ZERO_U8; 2035 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ONE): 2036 return ZIR_REF_ONE_USIZE; 2037 case RC(ZIR_REF_U1_TYPE, ZIR_REF_ONE): 2038 return ZIR_REF_ONE_U1; 2039 case RC(ZIR_REF_U8_TYPE, ZIR_REF_ONE): 2040 return ZIR_REF_ONE_U8; 2041 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ZERO_USIZE): 2042 return ZIR_REF_ZERO; 2043 case RC(ZIR_REF_U1_TYPE, ZIR_REF_ZERO_USIZE): 2044 return ZIR_REF_ZERO_U1; 2045 case RC(ZIR_REF_U8_TYPE, ZIR_REF_ZERO_USIZE): 2046 return ZIR_REF_ZERO_U8; 2047 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ONE_USIZE): 2048 return ZIR_REF_ONE; 2049 case RC(ZIR_REF_U1_TYPE, ZIR_REF_ONE_USIZE): 2050 return ZIR_REF_ONE_U1; 2051 case RC(ZIR_REF_U8_TYPE, ZIR_REF_ONE_USIZE): 2052 return ZIR_REF_ONE_U8; 2053 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ZERO_U1): 2054 return ZIR_REF_ZERO; 2055 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ZERO_U8): 2056 return ZIR_REF_ZERO; 2057 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ZERO_U1): 2058 return ZIR_REF_ZERO_USIZE; 2059 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ZERO_U8): 2060 return ZIR_REF_ZERO_USIZE; 2061 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ONE_U1): 2062 return ZIR_REF_ONE; 2063 case RC(ZIR_REF_COMPTIME_INT_TYPE, ZIR_REF_ONE_U8): 2064 return ZIR_REF_ONE; 2065 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ONE_U1): 2066 return ZIR_REF_ONE_USIZE; 2067 case RC(ZIR_REF_USIZE_TYPE, ZIR_REF_ONE_U8): 2068 return ZIR_REF_ONE_USIZE; 2069 default: { 2070 ZirInstTag as_tag = (rl.ctx == RI_CTX_SHIFT_OP) 2071 ? ZIR_INST_AS_SHIFT_OPERAND 2072 : ZIR_INST_AS_NODE; 2073 return addPlNodeBin(gz, as_tag, node, rl.data, result); 2074 } 2075 } 2076 #undef RC 2077 } 2078 case RL_PTR: 2079 // store_node (AstGen.zig:11211-11216). 2080 addPlNodeBin(gz, ZIR_INST_STORE_NODE, 2081 rl.src_node != 0 ? rl.src_node : node, rl.data, result); 2082 return ZIR_REF_VOID_VALUE; 2083 case RL_INFERRED_PTR: 2084 // store_to_inferred_ptr (AstGen.zig:11218-11223). 2085 addPlNodeBin( 2086 gz, ZIR_INST_STORE_TO_INFERRED_PTR, node, rl.data, result); 2087 return ZIR_REF_VOID_VALUE; 2088 } 2089 return result; 2090 } 2091 2092 // rvalueNoCoercePreRef (AstGen.zig:11042-11049): like rvalue but does NOT 2093 // emit coerce_ptr_elem_ty for RL_REF_COERCED_TY. Used for local var refs. 2094 static uint32_t rvalueNoCoercePreRef( 2095 GenZir* gz, ResultLoc rl, uint32_t result, uint32_t node) { 2096 if (rl.tag == RL_REF_COERCED_TY) { 2097 ResultLoc ref_rl = rl; 2098 ref_rl.tag = RL_REF; 2099 return rvalue(gz, ref_rl, result, node); 2100 } 2101 return rvalue(gz, rl, result, node); 2102 } 2103 2104 // --- Expression evaluation (AstGen.zig:634) --- 2105 2106 // Forward declarations. 2107 static uint32_t expr(GenZir* gz, Scope* scope, uint32_t node); 2108 // --- DefersToEmit (AstGen.zig:3008) --- 2109 #define DEFER_NORMAL_ONLY 0 2110 #define DEFER_BOTH_SANS_ERR 1 2111 2112 // --- DeferCounts (AstGen.zig:2966) --- 2113 typedef struct { 2114 bool have_any; 2115 bool have_normal; 2116 bool have_err; 2117 bool need_err_code; 2118 } DeferCounts; 2119 static DeferCounts countDefers(const Scope* outer_scope, Scope* inner_scope); 2120 2121 static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); 2122 static void assignStmt(GenZir* gz, Scope* scope, uint32_t infix_node); 2123 static void assignOp( 2124 GenZir* gz, Scope* scope, uint32_t infix_node, ZirInstTag op_tag); 2125 static uint32_t shiftOp( 2126 GenZir* gz, Scope* scope, uint32_t node, ZirInstTag tag); 2127 static void emitDbgStmt(GenZir* gz, uint32_t line, uint32_t column); 2128 static void genDefers( 2129 GenZir* gz, const Scope* outer_scope, Scope* inner_scope, int which); 2130 static void emitDbgStmtForceCurrentIndex( 2131 GenZir* gz, uint32_t line, uint32_t column); 2132 static void emitDbgNode(GenZir* gz, uint32_t node); 2133 static void addDbgVar( 2134 GenZir* gz, ZirInstTag tag, uint32_t name, uint32_t inst); 2135 static bool addEnsureResult( 2136 GenZir* gz, uint32_t maybe_unused_result, uint32_t statement); 2137 static void blockExprStmts( 2138 GenZir* gz, Scope* scope, const uint32_t* statements, uint32_t stmt_count); 2139 static uint32_t fullBodyExpr( 2140 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); 2141 static uint32_t containerDecl(GenZir* gz, Scope* scope, uint32_t node); 2142 static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, 2143 const uint32_t* members, uint32_t members_len); 2144 static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, 2145 const uint32_t* members, uint32_t members_len); 2146 static uint32_t blockExprExpr( 2147 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); 2148 static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); 2149 static uint32_t forExpr( 2150 GenZir* gz, Scope* scope, uint32_t node, bool is_statement); 2151 static uint32_t orelseCatchExpr( 2152 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, bool is_catch); 2153 static uint32_t arrayInitDotExpr( 2154 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); 2155 static uint32_t switchExpr( 2156 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node); 2157 static uint32_t whileExpr( 2158 GenZir* gz, Scope* scope, uint32_t node, bool is_statement); 2159 #define EVAL_TO_ERROR_NEVER 0 2160 #define EVAL_TO_ERROR_ALWAYS 1 2161 #define EVAL_TO_ERROR_MAYBE 2 2162 static int nodeMayEvalToError(const Ast* tree, uint32_t node); 2163 static bool nodeMayAppendToErrorTrace(const Ast* tree, uint32_t node); 2164 static void addSaveErrRetIndex(GenZir* gz, uint32_t operand); 2165 static void addRestoreErrRetIndexBlock( 2166 GenZir* gz, uint32_t block_inst, uint32_t operand, uint32_t node); 2167 static void restoreErrRetIndex(GenZir* gz, uint32_t block_inst, ResultLoc rl, 2168 uint32_t node, uint32_t result); 2169 static uint32_t identAsString(AstGenCtx* ag, uint32_t token); 2170 static uint32_t lastToken(const Ast* tree, uint32_t node); 2171 static uint32_t simpleBinOp( 2172 GenZir* gz, Scope* scope, uint32_t node, ZirInstTag tag); 2173 2174 // Mirrors GenZir.endsWithNoReturn (AstGen.zig:11770). 2175 static bool endsWithNoReturn(GenZir* gz) { 2176 uint32_t len = gzInstructionsLen(gz); 2177 if (len == 0) 2178 return false; 2179 uint32_t last = gzInstructionsSlice(gz)[len - 1]; 2180 ZirInstTag tag = gz->astgen->inst_tags[last]; 2181 switch (tag) { 2182 case ZIR_INST_BREAK: 2183 case ZIR_INST_BREAK_INLINE: 2184 case ZIR_INST_CONDBR: 2185 case ZIR_INST_CONDBR_INLINE: 2186 case ZIR_INST_COMPILE_ERROR: 2187 case ZIR_INST_RET_NODE: 2188 case ZIR_INST_RET_LOAD: 2189 case ZIR_INST_RET_IMPLICIT: 2190 case ZIR_INST_RET_ERR_VALUE: 2191 case ZIR_INST_UNREACHABLE: 2192 case ZIR_INST_REPEAT: 2193 case ZIR_INST_REPEAT_INLINE: 2194 case ZIR_INST_PANIC: 2195 case ZIR_INST_TRAP: 2196 case ZIR_INST_CHECK_COMPTIME_CONTROL_FLOW: 2197 case ZIR_INST_SWITCH_CONTINUE: 2198 return true; 2199 default: 2200 return false; 2201 } 2202 } 2203 2204 // Mirrors GenZir.refIsNoReturn (AstGen.zig:11885). 2205 static bool refIsNoReturn(GenZir* gz, uint32_t inst_ref) { 2206 if (inst_ref == ZIR_REF_UNREACHABLE_VALUE) 2207 return true; 2208 if (inst_ref >= ZIR_REF_START_INDEX) { 2209 uint32_t inst_index = inst_ref - ZIR_REF_START_INDEX; 2210 ZirInstTag tag = gz->astgen->inst_tags[inst_index]; 2211 switch (tag) { 2212 case ZIR_INST_BREAK: 2213 case ZIR_INST_BREAK_INLINE: 2214 case ZIR_INST_CONDBR: 2215 case ZIR_INST_CONDBR_INLINE: 2216 case ZIR_INST_COMPILE_ERROR: 2217 case ZIR_INST_RET_NODE: 2218 case ZIR_INST_RET_LOAD: 2219 case ZIR_INST_RET_IMPLICIT: 2220 case ZIR_INST_RET_ERR_VALUE: 2221 case ZIR_INST_UNREACHABLE: 2222 case ZIR_INST_REPEAT: 2223 case ZIR_INST_REPEAT_INLINE: 2224 case ZIR_INST_PANIC: 2225 case ZIR_INST_TRAP: 2226 case ZIR_INST_CHECK_COMPTIME_CONTROL_FLOW: 2227 case ZIR_INST_SWITCH_CONTINUE: 2228 return true; 2229 default: 2230 return false; 2231 } 2232 } 2233 return false; 2234 } 2235 2236 static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node); 2237 2238 // SimpleComptimeReason (std.zig:727) — values used in block_comptime payload. 2239 #define COMPTIME_REASON_TYPE 29 2240 #define COMPTIME_REASON_ARRAY_SENTINEL 30 2241 #define COMPTIME_REASON_POINTER_SENTINEL 31 2242 #define COMPTIME_REASON_SLICE_SENTINEL 32 2243 #define COMPTIME_REASON_ARRAY_LENGTH 33 2244 #define COMPTIME_REASON_ALIGN 50 2245 #define COMPTIME_REASON_ADDRSPACE 51 2246 #define COMPTIME_REASON_COMPTIME_KEYWORD 53 2247 #define COMPTIME_REASON_SWITCH_ITEM 56 2248 2249 // Mirrors comptimeExpr2 (AstGen.zig:1982). 2250 // Evaluates a node in a comptime block_comptime scope. 2251 static uint32_t comptimeExpr( 2252 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, uint32_t reason) { 2253 // Skip wrapping when already in comptime context (AstGen.zig:1990). 2254 if (gz->is_comptime) 2255 return exprRl(gz, scope, rl, node); 2256 // Optimization: certain node types are trivially comptime and don't need 2257 // a block_comptime wrapper (AstGen.zig:1997-2046). 2258 AstGenCtx* ag = gz->astgen; 2259 AstNodeTag tag = ag->tree->nodes.tags[node]; 2260 switch (tag) { 2261 // Identifier handling (AstGen.zig:2000-2003): 2262 // Upstream calls identifier() with force_comptime which resolves 2263 // primitives/int types directly and only wraps others in block_comptime. 2264 // We mirror this by resolving primitives here and falling through for 2265 // non-primitives. 2266 case AST_NODE_IDENTIFIER: { 2267 uint32_t prim = tryResolvePrimitiveIdent(gz, node); 2268 if (prim != ZIR_REF_NONE) 2269 return prim; 2270 break; // non-primitive: fall through to block_comptime wrapping 2271 } 2272 case AST_NODE_NUMBER_LITERAL: 2273 case AST_NODE_CHAR_LITERAL: 2274 case AST_NODE_STRING_LITERAL: 2275 case AST_NODE_MULTILINE_STRING_LITERAL: 2276 case AST_NODE_ENUM_LITERAL: 2277 case AST_NODE_ERROR_VALUE: 2278 // Type expressions that force comptime eval of sub-expressions 2279 // (AstGen.zig:2017-2042). 2280 case AST_NODE_ERROR_UNION: 2281 case AST_NODE_MERGE_ERROR_SETS: 2282 case AST_NODE_OPTIONAL_TYPE: 2283 case AST_NODE_PTR_TYPE_ALIGNED: 2284 case AST_NODE_PTR_TYPE_SENTINEL: 2285 case AST_NODE_PTR_TYPE: 2286 case AST_NODE_PTR_TYPE_BIT_RANGE: 2287 case AST_NODE_ARRAY_TYPE: 2288 case AST_NODE_ARRAY_TYPE_SENTINEL: 2289 case AST_NODE_FN_PROTO_SIMPLE: 2290 case AST_NODE_FN_PROTO_MULTI: 2291 case AST_NODE_FN_PROTO_ONE: 2292 case AST_NODE_FN_PROTO: 2293 case AST_NODE_CONTAINER_DECL: 2294 case AST_NODE_CONTAINER_DECL_TRAILING: 2295 case AST_NODE_CONTAINER_DECL_ARG: 2296 case AST_NODE_CONTAINER_DECL_ARG_TRAILING: 2297 case AST_NODE_CONTAINER_DECL_TWO: 2298 case AST_NODE_CONTAINER_DECL_TWO_TRAILING: 2299 case AST_NODE_TAGGED_UNION: 2300 case AST_NODE_TAGGED_UNION_TRAILING: 2301 case AST_NODE_TAGGED_UNION_ENUM_TAG: 2302 case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: 2303 case AST_NODE_TAGGED_UNION_TWO: 2304 case AST_NODE_TAGGED_UNION_TWO_TRAILING: 2305 return exprRl(gz, scope, rl, node); 2306 default: 2307 break; 2308 } 2309 // General case: wrap in block_comptime (AstGen.zig:2078-2096). 2310 uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK_COMPTIME, gz, node); 2311 GenZir block_scope = makeSubBlock(gz, scope); 2312 block_scope.is_comptime = true; 2313 // Transform RL to type-only (AstGen.zig:2084-2090). 2314 ResultLoc ty_only_rl; 2315 uint32_t res_ty = rlResultType(gz, rl, node); 2316 if (res_ty != 0) 2317 ty_only_rl = (ResultLoc) { 2318 .tag = RL_COERCED_TY, .data = res_ty, .src_node = 0, .ctx = rl.ctx 2319 }; 2320 else 2321 ty_only_rl = (ResultLoc) { 2322 .tag = RL_NONE, .data = 0, .src_node = 0, .ctx = rl.ctx 2323 }; 2324 uint32_t result = exprRl(&block_scope, scope, ty_only_rl, node); 2325 addBreak(&block_scope, ZIR_INST_BREAK_INLINE, block_inst, result, 2326 AST_NODE_OFFSET_NONE); 2327 setBlockComptimeBody(ag, &block_scope, block_inst, reason); 2328 gzAppendInstruction(gz, block_inst); 2329 return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node); 2330 } 2331 2332 // Mirrors typeExpr (AstGen.zig:394). 2333 static uint32_t typeExpr(GenZir* gz, Scope* scope, uint32_t node) { 2334 ResultLoc rl = { .tag = RL_COERCED_TY, 2335 .data = ZIR_REF_TYPE_TYPE, 2336 .src_node = 0, 2337 .ctx = RI_CTX_NONE }; 2338 return comptimeExpr(gz, scope, rl, node, COMPTIME_REASON_TYPE); 2339 } 2340 2341 // Mirrors numberLiteral (AstGen.zig:8544). 2342 // Parses integer and float literals, returns appropriate ZIR ref. 2343 static uint32_t numberLiteral(GenZir* gz, uint32_t node) { 2344 AstGenCtx* ag = gz->astgen; 2345 uint32_t num_token = ag->tree->nodes.main_tokens[node]; 2346 uint32_t tok_start = ag->tree->tokens.starts[num_token]; 2347 const char* source = ag->tree->source; 2348 2349 // Determine token length by scanning to next non-number character. 2350 uint32_t tok_end = tok_start; 2351 while (tok_end < ag->tree->source_len 2352 && ((source[tok_end] >= '0' && source[tok_end] <= '9') 2353 || source[tok_end] == '_' || source[tok_end] == '.' 2354 || source[tok_end] == 'x' || source[tok_end] == 'o' 2355 || source[tok_end] == 'b' 2356 || (source[tok_end] >= 'a' && source[tok_end] <= 'f') 2357 || (source[tok_end] >= 'A' && source[tok_end] <= 'F'))) { 2358 tok_end++; 2359 } 2360 2361 // Parse the integer value (simplified: decimal and hex). 2362 uint64_t value = 0; 2363 bool is_hex = false; 2364 uint32_t pos = tok_start; 2365 if (tok_end - tok_start >= 2 && source[tok_start] == '0' 2366 && source[tok_start + 1] == 'x') { 2367 is_hex = true; 2368 pos = tok_start + 2; 2369 } 2370 2371 if (is_hex) { 2372 for (; pos < tok_end; pos++) { 2373 if (source[pos] == '_') 2374 continue; 2375 if (source[pos] >= '0' && source[pos] <= '9') 2376 value = value * 16 + (uint64_t)(source[pos] - '0'); 2377 else if (source[pos] >= 'a' && source[pos] <= 'f') 2378 value = value * 16 + 10 + (uint64_t)(source[pos] - 'a'); 2379 else if (source[pos] >= 'A' && source[pos] <= 'F') 2380 value = value * 16 + 10 + (uint64_t)(source[pos] - 'A'); 2381 } 2382 } else { 2383 for (; pos < tok_end; pos++) { 2384 if (source[pos] == '_') 2385 continue; 2386 if (source[pos] == '.') 2387 break; // float — not handled yet 2388 if (source[pos] >= '0' && source[pos] <= '9') 2389 value = value * 10 + (uint64_t)(source[pos] - '0'); 2390 } 2391 } 2392 2393 // Special cases for 0 and 1 (AstGen.zig:8687-8703). 2394 if (value == 0) 2395 return ZIR_REF_ZERO; 2396 if (value == 1) 2397 return ZIR_REF_ONE; 2398 2399 return addInt(gz, value); 2400 } 2401 2402 // Mirrors builtinCall (AstGen.zig:9191), @import case (AstGen.zig:9242). 2403 static uint32_t builtinCallImport(GenZir* gz, Scope* scope, uint32_t node) { 2404 (void)scope; 2405 AstGenCtx* ag = gz->astgen; 2406 const Ast* tree = ag->tree; 2407 2408 // For builtin_call_two: data.lhs = first arg node. 2409 AstData node_data = tree->nodes.datas[node]; 2410 uint32_t operand_node = node_data.lhs; 2411 2412 assert(tree->nodes.tags[operand_node] == AST_NODE_STRING_LITERAL); 2413 uint32_t str_lit_token = tree->nodes.main_tokens[operand_node]; 2414 2415 uint32_t str_index, str_len; 2416 strLitAsString(ag, str_lit_token, &str_index, &str_len); 2417 2418 // Write Import payload to extra (Zir.Inst.Import: res_ty, path). 2419 ensureExtraCapacity(ag, 2); 2420 uint32_t payload_index = ag->extra_len; 2421 ag->extra[ag->extra_len++] = ZIR_REF_NONE; // res_ty = .none 2422 ag->extra[ag->extra_len++] = str_index; // path 2423 2424 // Create .import instruction with pl_tok data. 2425 ZirInstData data; 2426 data.pl_tok.src_tok = tokenIndexToRelative(gz, str_lit_token); 2427 data.pl_tok.payload_index = payload_index; 2428 uint32_t result_ref = addInstruction(gz, ZIR_INST_IMPORT, data); 2429 2430 // Track import (AstGen.zig:9269). 2431 addImport(ag, str_index, str_lit_token); 2432 2433 return result_ref; 2434 } 2435 2436 // Mirrors cImport (AstGen.zig:10011). 2437 static uint32_t cImportExpr(GenZir* gz, Scope* scope, uint32_t node) { 2438 AstGenCtx* ag = gz->astgen; 2439 AstData nd = ag->tree->nodes.datas[node]; 2440 uint32_t body_node = nd.lhs; // first arg = body 2441 2442 uint32_t block_inst = makeBlockInst(ag, ZIR_INST_C_IMPORT, gz, node); 2443 2444 GenZir block_scope = makeSubBlock(gz, scope); 2445 block_scope.is_comptime = true; 2446 block_scope.c_import = true; 2447 2448 // Use fullBodyExpr to inline unlabeled block body (AstGen.zig:10028). 2449 fullBodyExpr(&block_scope, &block_scope.base, RL_NONE_VAL, body_node); 2450 2451 // ensure_result_used on gz (parent), not block_scope (AstGen.zig:10029). 2452 addUnNode(gz, ZIR_INST_ENSURE_RESULT_USED, ZIR_REF_VOID_VALUE, node); 2453 2454 // break_inline (AstGen.zig:10030-10032). 2455 makeBreakInline( 2456 &block_scope, block_inst, ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); 2457 2458 setBlockBody(ag, &block_scope, block_inst); 2459 // block_scope unstacked now, can add to gz. 2460 gzAppendInstruction(gz, block_inst); 2461 2462 return block_inst + ZIR_REF_START_INDEX; // toRef() 2463 } 2464 2465 // Mirrors simpleCBuiltin (AstGen.zig:9938). 2466 static uint32_t simpleCBuiltin(GenZir* gz, Scope* scope, uint32_t node, 2467 uint32_t operand_node, uint16_t ext_tag) { 2468 AstGenCtx* ag = gz->astgen; 2469 2470 // Evaluate operand as comptime string. 2471 uint32_t operand = expr(gz, scope, operand_node); 2472 2473 // Emit extended instruction with UnNode payload (AstGen.zig:9954). 2474 ensureExtraCapacity(ag, 2); 2475 uint32_t payload_index = ag->extra_len; 2476 ag->extra[ag->extra_len++] 2477 = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); 2478 ag->extra[ag->extra_len++] = operand; 2479 2480 ZirInstData data; 2481 data.extended.opcode = ext_tag; 2482 data.extended.small = 0xAAAAu; // undefined (addExtendedPayload passes 2483 // undefined for small) 2484 data.extended.operand = payload_index; 2485 addInstruction(gz, ZIR_INST_EXTENDED, data); 2486 2487 return ZIR_REF_VOID_VALUE; 2488 } 2489 2490 // Mirrors builtinCall (AstGen.zig:9191) dispatch. 2491 static uint32_t builtinCall( 2492 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 2493 AstGenCtx* ag = gz->astgen; 2494 const Ast* tree = ag->tree; 2495 2496 uint32_t builtin_token = tree->nodes.main_tokens[node]; 2497 uint32_t tok_start = tree->tokens.starts[builtin_token]; 2498 const char* source = tree->source; 2499 2500 // Identify builtin name from source. 2501 // Skip '@' prefix and scan identifier. 2502 uint32_t name_start = tok_start + 1; // skip '@' 2503 uint32_t name_end = name_start; 2504 while (name_end < tree->source_len 2505 && ((source[name_end] >= 'a' && source[name_end] <= 'z') 2506 || (source[name_end] >= 'A' && source[name_end] <= 'Z') 2507 || source[name_end] == '_')) { 2508 name_end++; 2509 } 2510 uint32_t name_len = name_end - name_start; 2511 2512 // clang-format off 2513 if (name_len == 6 && memcmp(source + name_start, "import", 6) == 0) 2514 return builtinCallImport(gz, scope, node); 2515 if (name_len == 7 && memcmp(source + name_start, "cImport", 7) == 0) 2516 return cImportExpr(gz, scope, node); 2517 if (name_len == 8 && memcmp(source + name_start, "cInclude", 8) == 0) { 2518 AstData nd = tree->nodes.datas[node]; 2519 return simpleCBuiltin(gz, scope, node, nd.lhs, (uint16_t)ZIR_EXT_C_INCLUDE); 2520 } 2521 // @intCast — typeCast pattern (AstGen.zig:9416, 9807-9826). 2522 if (name_len == 7 && memcmp(source + name_start, "intCast", 7) == 0) { 2523 advanceSourceCursorToMainToken(ag, gz, node); 2524 uint32_t saved_line = ag->source_line - gz->decl_line; 2525 uint32_t saved_col = ag->source_column; 2526 uint32_t result_type = rlResultType(gz, rl, node); 2527 AstData nd = tree->nodes.datas[node]; 2528 uint32_t operand = expr(gz, scope, nd.lhs); 2529 emitDbgStmt(gz, saved_line, saved_col); 2530 return addPlNodeBin(gz, ZIR_INST_INT_CAST, node, 2531 result_type, operand); 2532 } 2533 // @embedFile (AstGen.zig:9626). 2534 if (name_len == 9 && memcmp(source + name_start, "embedFile", 9) == 0) { 2535 AstData nd = tree->nodes.datas[node]; 2536 uint32_t operand = expr(gz, scope, nd.lhs); 2537 return addUnNode(gz, ZIR_INST_EMBED_FILE, operand, node); 2538 } 2539 // @intFromEnum (AstGen.zig:9478). 2540 if (name_len == 11 && memcmp(source + name_start, "intFromEnum", 11) == 0) { 2541 AstData nd = tree->nodes.datas[node]; 2542 uint32_t operand = expr(gz, scope, nd.lhs); 2543 return addUnNode(gz, ZIR_INST_INT_FROM_ENUM, operand, node); 2544 } 2545 // @tagName (AstGen.zig:9407) — simpleUnOp with dbg_stmt. 2546 if (name_len == 7 && memcmp(source + name_start, "tagName", 7) == 0) { 2547 advanceSourceCursorToMainToken(ag, gz, node); 2548 uint32_t saved_line = ag->source_line - gz->decl_line; 2549 uint32_t saved_col = ag->source_column; 2550 AstData nd = tree->nodes.datas[node]; 2551 uint32_t operand = expr(gz, scope, nd.lhs); 2552 emitDbgStmt(gz, saved_line, saved_col); 2553 return addUnNode(gz, ZIR_INST_TAG_NAME, operand, node); 2554 } 2555 // @as (AstGen.zig:8909-8920). 2556 if (name_len == 2 && memcmp(source + name_start, "as", 2) == 0) { 2557 AstData nd = tree->nodes.datas[node]; 2558 uint32_t dest_type = typeExpr(gz, scope, nd.lhs); 2559 ResultLoc as_rl = { .tag = RL_TY, .data = dest_type, .src_node = 0, 2560 .ctx = rl.ctx }; 2561 uint32_t operand = exprRl(gz, scope, as_rl, nd.rhs); 2562 return rvalue(gz, rl, operand, node); 2563 } 2564 // @truncate — typeCast pattern (AstGen.zig:9417, 9807-9826). 2565 if (name_len == 8 && memcmp(source + name_start, "truncate", 8) == 0) { 2566 advanceSourceCursorToMainToken(ag, gz, node); 2567 uint32_t saved_line = ag->source_line - gz->decl_line; 2568 uint32_t saved_col = ag->source_column; 2569 uint32_t result_type = rlResultType(gz, rl, node); 2570 AstData nd = tree->nodes.datas[node]; 2571 uint32_t operand = expr(gz, scope, nd.lhs); 2572 emitDbgStmt(gz, saved_line, saved_col); 2573 return addPlNodeBin(gz, ZIR_INST_TRUNCATE, node, 2574 result_type, operand); 2575 } 2576 // @ptrCast — typeCast pattern (AstGen.zig:9056, 9807-9826). 2577 if (name_len == 7 && memcmp(source + name_start, "ptrCast", 7) == 0) { 2578 advanceSourceCursorToMainToken(ag, gz, node); 2579 uint32_t saved_line = ag->source_line - gz->decl_line; 2580 uint32_t saved_col = ag->source_column; 2581 uint32_t result_type = rlResultType(gz, rl, node); 2582 AstData nd = tree->nodes.datas[node]; 2583 uint32_t operand = expr(gz, scope, nd.lhs); 2584 emitDbgStmt(gz, saved_line, saved_col); 2585 return addPlNodeBin(gz, ZIR_INST_PTR_CAST, node, 2586 result_type, operand); 2587 } 2588 // @enumFromInt — typeCast pattern (AstGen.zig:9414, 9807-9826). 2589 if (name_len == 11 && memcmp(source + name_start, "enumFromInt", 11) == 0) { 2590 advanceSourceCursorToMainToken(ag, gz, node); 2591 uint32_t saved_line = ag->source_line - gz->decl_line; 2592 uint32_t saved_col = ag->source_column; 2593 uint32_t result_type = rlResultType(gz, rl, node); 2594 AstData nd = tree->nodes.datas[node]; 2595 uint32_t operand = expr(gz, scope, nd.lhs); 2596 emitDbgStmt(gz, saved_line, saved_col); 2597 return addPlNodeBin(gz, ZIR_INST_ENUM_FROM_INT, node, 2598 result_type, operand); 2599 } 2600 // @bitCast (AstGen.zig:8944-8958, dispatched at 9313). 2601 if (name_len == 7 && memcmp(source + name_start, "bitCast", 7) == 0) { 2602 uint32_t result_type = rlResultType(gz, rl, node); 2603 AstData nd = tree->nodes.datas[node]; 2604 uint32_t operand = expr(gz, scope, nd.lhs); 2605 return addPlNodeBin(gz, ZIR_INST_BITCAST, node, 2606 result_type, operand); 2607 } 2608 // @memcpy (AstGen.zig:9631-9637). 2609 if (name_len == 6 && memcmp(source + name_start, "memcpy", 6) == 0) { 2610 AstData nd = tree->nodes.datas[node]; 2611 uint32_t dst = expr(gz, scope, nd.lhs); 2612 uint32_t src = expr(gz, scope, nd.rhs); 2613 addPlNodeBin(gz, ZIR_INST_MEMCPY, node, dst, src); 2614 return ZIR_REF_VOID_VALUE; 2615 } 2616 // @memset (AstGen.zig:9638-9647). 2617 if (name_len == 6 && memcmp(source + name_start, "memset", 6) == 0) { 2618 AstData nd = tree->nodes.datas[node]; 2619 uint32_t lhs = expr(gz, scope, nd.lhs); 2620 uint32_t lhs_ty = addUnNode(gz, ZIR_INST_TYPEOF, lhs, nd.lhs); 2621 uint32_t elem_ty = 2622 addUnNode(gz, ZIR_INST_INDEXABLE_PTR_ELEM_TYPE, lhs_ty, nd.lhs); 2623 ResultLoc val_rl = { 2624 .tag = RL_COERCED_TY, .data = elem_ty, .src_node = 0}; 2625 uint32_t val = exprRl(gz, scope, val_rl, nd.rhs); 2626 addPlNodeBin(gz, ZIR_INST_MEMSET, node, lhs, val); 2627 return ZIR_REF_VOID_VALUE; 2628 } 2629 // @min (AstGen.zig:9155). 2630 if (name_len == 3 && memcmp(source + name_start, "min", 3) == 0) { 2631 AstData nd = tree->nodes.datas[node]; 2632 uint32_t a = expr(gz, scope, nd.lhs); 2633 uint32_t b = expr(gz, scope, nd.rhs); 2634 return addPlNodeBin(gz, ZIR_INST_MIN, node, a, b); 2635 } 2636 // @max (AstGen.zig:9155). 2637 if (name_len == 3 && memcmp(source + name_start, "max", 3) == 0) { 2638 AstData nd = tree->nodes.datas[node]; 2639 uint32_t a = expr(gz, scope, nd.lhs); 2640 uint32_t b = expr(gz, scope, nd.rhs); 2641 return addPlNodeBin(gz, ZIR_INST_MAX, node, a, b); 2642 } 2643 // clang-format on 2644 2645 // TODO: handle other builtins. 2646 SET_ERROR(ag); 2647 return ZIR_REF_VOID_VALUE; 2648 } 2649 2650 // --- identifier (AstGen.zig:8282) --- 2651 // Simplified: handles decl_val resolution for container-level declarations. 2652 2653 // Tries to resolve an identifier as a primitive type or integer type. 2654 // Returns the ZIR ref if it's a primitive/int type, or ZIR_REF_NONE. 2655 // Mirrors primitive_instrs + integer type checks in identifier() 2656 // (AstGen.zig:8298-8337). 2657 static uint32_t tryResolvePrimitiveIdent(GenZir* gz, uint32_t node) { 2658 AstGenCtx* ag = gz->astgen; 2659 uint32_t ident_token = ag->tree->nodes.main_tokens[node]; 2660 uint32_t tok_start = ag->tree->tokens.starts[ident_token]; 2661 const char* source = ag->tree->source; 2662 uint32_t tok_end = tok_start; 2663 while (tok_end < ag->tree->source_len 2664 && ((source[tok_end] >= 'a' && source[tok_end] <= 'z') 2665 || (source[tok_end] >= 'A' && source[tok_end] <= 'Z') 2666 || (source[tok_end] >= '0' && source[tok_end] <= '9') 2667 || source[tok_end] == '_')) 2668 tok_end++; 2669 uint32_t tok_len = tok_end - tok_start; 2670 2671 // Check well-known primitive refs (primitive_instrs map, 2672 // AstGen.zig:10236-10281). 2673 // clang-format off 2674 if (tok_len == 2 && memcmp(source+tok_start, "u1", 2) == 0) return ZIR_REF_U1_TYPE; 2675 if (tok_len == 2 && memcmp(source+tok_start, "u8", 2) == 0) return ZIR_REF_U8_TYPE; 2676 if (tok_len == 2 && memcmp(source+tok_start, "i8", 2) == 0) return ZIR_REF_I8_TYPE; 2677 if (tok_len == 3 && memcmp(source+tok_start, "u16", 3) == 0) return ZIR_REF_U16_TYPE; 2678 if (tok_len == 3 && memcmp(source+tok_start, "i16", 3) == 0) return ZIR_REF_I16_TYPE; 2679 if (tok_len == 3 && memcmp(source+tok_start, "u29", 3) == 0) return ZIR_REF_U29_TYPE; 2680 if (tok_len == 3 && memcmp(source+tok_start, "u32", 3) == 0) return ZIR_REF_U32_TYPE; 2681 if (tok_len == 3 && memcmp(source+tok_start, "i32", 3) == 0) return ZIR_REF_I32_TYPE; 2682 if (tok_len == 3 && memcmp(source+tok_start, "u64", 3) == 0) return ZIR_REF_U64_TYPE; 2683 if (tok_len == 3 && memcmp(source+tok_start, "i64", 3) == 0) return ZIR_REF_I64_TYPE; 2684 if (tok_len == 4 && memcmp(source+tok_start, "u128", 4) == 0) return ZIR_REF_U128_TYPE; 2685 if (tok_len == 4 && memcmp(source+tok_start, "i128", 4) == 0) return ZIR_REF_I128_TYPE; 2686 if (tok_len == 5 && memcmp(source+tok_start, "usize", 5) == 0) return ZIR_REF_USIZE_TYPE; 2687 if (tok_len == 5 && memcmp(source+tok_start, "isize", 5) == 0) return ZIR_REF_ISIZE_TYPE; 2688 if (tok_len == 6 && memcmp(source+tok_start, "c_char", 6) == 0) return ZIR_REF_C_CHAR_TYPE; 2689 if (tok_len == 7 && memcmp(source+tok_start, "c_short", 7) == 0) return ZIR_REF_C_SHORT_TYPE; 2690 if (tok_len == 8 && memcmp(source+tok_start, "c_ushort", 8) == 0) return ZIR_REF_C_USHORT_TYPE; 2691 if (tok_len == 5 && memcmp(source+tok_start, "c_int", 5) == 0) return ZIR_REF_C_INT_TYPE; 2692 if (tok_len == 6 && memcmp(source+tok_start, "c_uint", 6) == 0) return ZIR_REF_C_UINT_TYPE; 2693 if (tok_len == 6 && memcmp(source+tok_start, "c_long", 6) == 0) return ZIR_REF_C_LONG_TYPE; 2694 if (tok_len == 7 && memcmp(source+tok_start, "c_ulong", 7) == 0) return ZIR_REF_C_ULONG_TYPE; 2695 if (tok_len == 10 && memcmp(source+tok_start, "c_longlong", 10) == 0) return ZIR_REF_C_LONGLONG_TYPE; 2696 if (tok_len == 11 && memcmp(source+tok_start, "c_ulonglong", 11) == 0) return ZIR_REF_C_ULONGLONG_TYPE; 2697 if (tok_len == 14 && memcmp(source+tok_start, "comptime_float", 14) == 0) return ZIR_REF_COMPTIME_FLOAT_TYPE; 2698 if (tok_len == 12 && memcmp(source+tok_start, "comptime_int", 12) == 0) return ZIR_REF_COMPTIME_INT_TYPE; 2699 if (tok_len == 3 && memcmp(source+tok_start, "f16", 3) == 0) return ZIR_REF_F16_TYPE; 2700 if (tok_len == 3 && memcmp(source+tok_start, "f32", 3) == 0) return ZIR_REF_F32_TYPE; 2701 if (tok_len == 3 && memcmp(source+tok_start, "f64", 3) == 0) return ZIR_REF_F64_TYPE; 2702 if (tok_len == 3 && memcmp(source+tok_start, "f80", 3) == 0) return ZIR_REF_F80_TYPE; 2703 if (tok_len == 4 && memcmp(source+tok_start, "f128", 4) == 0) return ZIR_REF_F128_TYPE; 2704 if (tok_len == 9 && memcmp(source+tok_start, "anyopaque", 9) == 0) return ZIR_REF_ANYOPAQUE_TYPE; 2705 if (tok_len == 4 && memcmp(source+tok_start, "bool", 4) == 0) return ZIR_REF_BOOL_TYPE; 2706 if (tok_len == 4 && memcmp(source+tok_start, "void", 4) == 0) return ZIR_REF_VOID_TYPE; 2707 if (tok_len == 4 && memcmp(source+tok_start, "type", 4) == 0) return ZIR_REF_TYPE_TYPE; 2708 if (tok_len == 8 && memcmp(source+tok_start, "anyerror", 8) == 0) return ZIR_REF_ANYERROR_TYPE; 2709 if (tok_len == 8 && memcmp(source+tok_start, "noreturn", 8) == 0) return ZIR_REF_NORETURN_TYPE; 2710 if (tok_len == 4 && memcmp(source+tok_start, "true", 4) == 0) return ZIR_REF_BOOL_TRUE; 2711 if (tok_len == 5 && memcmp(source+tok_start, "false", 5) == 0) return ZIR_REF_BOOL_FALSE; 2712 if (tok_len == 4 && memcmp(source+tok_start, "null", 4) == 0) return ZIR_REF_NULL_VALUE; 2713 if (tok_len == 9 && memcmp(source+tok_start, "undefined", 9) == 0) return ZIR_REF_UNDEF; 2714 // clang-format on 2715 2716 // Integer type detection: u29, i13, etc. (AstGen.zig:8304-8336). 2717 if (tok_len >= 2 2718 && (source[tok_start] == 'u' || source[tok_start] == 'i')) { 2719 // Zig Signedness enum: unsigned=1, signed=0 2720 uint8_t signedness = (source[tok_start] == 'u') ? 1 : 0; 2721 uint16_t bit_count = 0; 2722 bool valid = true; 2723 for (uint32_t k = tok_start + 1; k < tok_end; k++) { 2724 if (source[k] >= '0' && source[k] <= '9') { 2725 bit_count 2726 = (uint16_t)(bit_count * 10 + (uint16_t)(source[k] - '0')); 2727 } else { 2728 valid = false; 2729 break; 2730 } 2731 } 2732 if (valid && bit_count > 0) { 2733 ZirInstData data; 2734 data.int_type.src_node 2735 = (int32_t)node - (int32_t)gz->decl_node_index; 2736 data.int_type.signedness = signedness; 2737 data.int_type._pad = 0; 2738 data.int_type.bit_count = bit_count; 2739 return addInstruction(gz, ZIR_INST_INT_TYPE, data); 2740 } 2741 } 2742 return ZIR_REF_NONE; 2743 } 2744 2745 static uint32_t identifierExpr( 2746 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 2747 AstGenCtx* ag = gz->astgen; 2748 uint32_t ident_token = ag->tree->nodes.main_tokens[node]; 2749 2750 // Check for primitive types FIRST (AstGen.zig:8298-8338). 2751 uint32_t prim = tryResolvePrimitiveIdent(gz, node); 2752 if (prim != ZIR_REF_NONE) 2753 return rvalue(gz, rl, prim, node); 2754 2755 // Scope chain walk (AstGen.zig:8340-8461). 2756 uint32_t name_str = identAsString(ag, ident_token); 2757 for (Scope* s = scope; s != NULL;) { 2758 switch (s->tag) { 2759 case SCOPE_LOCAL_VAL: { 2760 ScopeLocalVal* lv = (ScopeLocalVal*)s; 2761 if (lv->name == name_str) 2762 return rvalueNoCoercePreRef(gz, rl, lv->inst, node); 2763 s = lv->parent; 2764 continue; 2765 } 2766 case SCOPE_LOCAL_PTR: { 2767 ScopeLocalPtr* lp = (ScopeLocalPtr*)s; 2768 if (lp->name == name_str) { 2769 if (RL_IS_REF(rl)) 2770 return lp->ptr; 2771 return addUnNode(gz, ZIR_INST_LOAD, lp->ptr, node); 2772 } 2773 s = lp->parent; 2774 continue; 2775 } 2776 case SCOPE_GEN_ZIR: { 2777 GenZir* gzs = (GenZir*)s; 2778 s = gzs->parent; 2779 continue; 2780 } 2781 case SCOPE_DEFER_NORMAL: 2782 case SCOPE_DEFER_ERROR: { 2783 ScopeDefer* sd = (ScopeDefer*)s; 2784 s = sd->parent; 2785 continue; 2786 } 2787 case SCOPE_LABEL: { 2788 ScopeLabel* sl = (ScopeLabel*)s; 2789 s = sl->parent; 2790 continue; 2791 } 2792 case SCOPE_NAMESPACE: 2793 case SCOPE_TOP: 2794 goto decl_table; 2795 } 2796 } 2797 decl_table: 2798 2799 // Decl table lookup (AstGen.zig:8462-8520). 2800 for (uint32_t i = 0; i < ag->decl_table_len; i++) { 2801 if (ag->decl_names[i] == name_str) { 2802 ZirInstTag itag 2803 = (RL_IS_REF(rl)) ? ZIR_INST_DECL_REF : ZIR_INST_DECL_VAL; 2804 ZirInstData data; 2805 data.str_tok.start = name_str; 2806 data.str_tok.src_tok = tokenIndexToRelative(gz, ident_token); 2807 return addInstruction(gz, itag, data); 2808 } 2809 } 2810 2811 SET_ERROR(ag); 2812 return ZIR_REF_VOID_VALUE; 2813 } 2814 2815 // --- fieldAccess (AstGen.zig:6154) --- 2816 // Simplified: emits field_val instruction with Field payload. 2817 2818 static uint32_t fieldAccessExpr( 2819 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 2820 AstGenCtx* ag = gz->astgen; 2821 const Ast* tree = ag->tree; 2822 AstData nd = tree->nodes.datas[node]; 2823 2824 // data.lhs = object node, data.rhs = field identifier token. 2825 uint32_t object_node = nd.lhs; 2826 uint32_t field_ident = nd.rhs; 2827 2828 // Get field name as string (AstGen.zig:6180). 2829 uint32_t str_index = identAsString(ag, field_ident); 2830 2831 // Evaluate the LHS object expression (AstGen.zig:6181). 2832 // For .ref rl, LHS is also evaluated with .ref (AstGen.zig:6161). 2833 ResultLoc lhs_rl = (RL_IS_REF(rl)) ? RL_REF_VAL : RL_NONE_VAL; 2834 uint32_t lhs = exprRl(gz, scope, lhs_rl, object_node); 2835 2836 // Emit dbg_stmt for the dot token (AstGen.zig:6183-6184). 2837 advanceSourceCursorToMainToken(ag, gz, node); 2838 { 2839 uint32_t line = ag->source_line - gz->decl_line; 2840 uint32_t column = ag->source_column; 2841 emitDbgStmt(gz, line, column); 2842 } 2843 2844 // Emit field_val instruction with Field payload (AstGen.zig:6186-6189). 2845 ensureExtraCapacity(ag, 2); 2846 uint32_t payload_index = ag->extra_len; 2847 ag->extra[ag->extra_len++] = lhs; // Field.lhs 2848 ag->extra[ag->extra_len++] = str_index; // Field.field_name_start 2849 2850 // .ref → field_ptr, else → field_val (AstGen.zig:6160-6164). 2851 ZirInstTag ftag 2852 = (RL_IS_REF(rl)) ? ZIR_INST_FIELD_PTR : ZIR_INST_FIELD_VAL; 2853 ZirInstData data; 2854 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 2855 data.pl_node.payload_index = payload_index; 2856 uint32_t access = addInstruction(gz, ftag, data); 2857 // For ref, return directly; otherwise apply rvalue (AstGen.zig:6161-6164). 2858 if (RL_IS_REF(rl)) 2859 return access; 2860 return rvalue(gz, rl, access, node); 2861 } 2862 2863 // --- ptrType (AstGen.zig:3833) --- 2864 2865 static uint32_t ptrTypeExpr(GenZir* gz, Scope* scope, uint32_t node) { 2866 AstGenCtx* ag = gz->astgen; 2867 const Ast* tree = ag->tree; 2868 AstNodeTag tag = tree->nodes.tags[node]; 2869 AstData nd = tree->nodes.datas[node]; 2870 uint32_t main_tok = tree->nodes.main_tokens[node]; 2871 2872 // child_type is always in rhs for all ptr_type variants. 2873 uint32_t child_type_node = nd.rhs; 2874 2875 // Determine size from main_token (Ast.zig:2122-2131). 2876 // Pointer.Size: one=0, many=1, slice=2, c=3. 2877 uint8_t size; 2878 TokenizerTag main_tok_tag = tree->tokens.tags[main_tok]; 2879 if (main_tok_tag == TOKEN_ASTERISK 2880 || main_tok_tag == TOKEN_ASTERISK_ASTERISK) { 2881 size = 0; // one 2882 } else { 2883 assert(main_tok_tag == TOKEN_L_BRACKET); 2884 TokenizerTag next_tag = tree->tokens.tags[main_tok + 1]; 2885 if (next_tag == TOKEN_ASTERISK) { 2886 // [*c]T vs [*]T: c-pointer if next-next is identifier. 2887 if (tree->tokens.tags[main_tok + 2] == TOKEN_IDENTIFIER) 2888 size = 3; // c 2889 else 2890 size = 1; // many 2891 } else { 2892 size = 2; // slice 2893 } 2894 } 2895 2896 // Determine sentinel, align, addrspace, bit_range nodes from AST variant 2897 // (Ast.zig:1656-1696). 2898 uint32_t sentinel_node = UINT32_MAX; 2899 uint32_t align_node = UINT32_MAX; 2900 uint32_t addrspace_node = UINT32_MAX; 2901 uint32_t bit_range_start = UINT32_MAX; 2902 uint32_t bit_range_end = UINT32_MAX; 2903 2904 if (tag == AST_NODE_PTR_TYPE_ALIGNED) { 2905 // opt_node_and_node: lhs = optional align_node (0=none), rhs = child. 2906 if (nd.lhs != 0) 2907 align_node = nd.lhs; 2908 } else if (tag == AST_NODE_PTR_TYPE_SENTINEL) { 2909 // opt_node_and_node: lhs = optional sentinel (0=none), rhs = child. 2910 if (nd.lhs != 0) 2911 sentinel_node = nd.lhs; 2912 } else if (tag == AST_NODE_PTR_TYPE) { 2913 // extra_and_node: lhs = extra index to AstPtrType, rhs = child_type. 2914 const AstPtrType* pt 2915 = (const AstPtrType*)(tree->extra_data.arr + nd.lhs); 2916 if (pt->sentinel != UINT32_MAX) 2917 sentinel_node = pt->sentinel; 2918 if (pt->align_node != UINT32_MAX) 2919 align_node = pt->align_node; 2920 if (pt->addrspace_node != UINT32_MAX) 2921 addrspace_node = pt->addrspace_node; 2922 } else if (tag == AST_NODE_PTR_TYPE_BIT_RANGE) { 2923 // extra_and_node: lhs = extra index to AstPtrTypeBitRange. 2924 const AstPtrTypeBitRange* pt 2925 = (const AstPtrTypeBitRange*)(tree->extra_data.arr + nd.lhs); 2926 if (pt->sentinel != UINT32_MAX) 2927 sentinel_node = pt->sentinel; 2928 align_node = pt->align_node; 2929 if (pt->addrspace_node != UINT32_MAX) 2930 addrspace_node = pt->addrspace_node; 2931 bit_range_start = pt->bit_range_start; 2932 bit_range_end = pt->bit_range_end; 2933 } 2934 2935 // Scan tokens between main_token and child_type to find const/volatile/ 2936 // allowzero (Ast.zig:2139-2164). 2937 bool has_const = false; 2938 bool has_volatile = false; 2939 bool has_allowzero = false; 2940 { 2941 uint32_t i; 2942 if (sentinel_node != UINT32_MAX) { 2943 i = lastToken(tree, sentinel_node) + 1; 2944 } else if (size == 1 || size == 3) { 2945 // many or c: start after main_token. 2946 i = main_tok + 1; 2947 } else { 2948 i = main_tok; 2949 } 2950 uint32_t end = firstToken(tree, child_type_node); 2951 while (i < end) { 2952 TokenizerTag tt = tree->tokens.tags[i]; 2953 if (tt == TOKEN_KEYWORD_ALLOWZERO) { 2954 has_allowzero = true; 2955 } else if (tt == TOKEN_KEYWORD_CONST) { 2956 has_const = true; 2957 } else if (tt == TOKEN_KEYWORD_VOLATILE) { 2958 has_volatile = true; 2959 } else if (tt == TOKEN_KEYWORD_ALIGN) { 2960 // Skip over align expression. 2961 if (bit_range_end != UINT32_MAX) 2962 i = lastToken(tree, bit_range_end) + 1; 2963 else if (align_node != UINT32_MAX) 2964 i = lastToken(tree, align_node) + 1; 2965 } 2966 i++; 2967 } 2968 } 2969 2970 // Evaluate element type (AstGen.zig:3847). 2971 uint32_t elem_type = typeExpr(gz, scope, child_type_node); 2972 2973 // Evaluate trailing expressions (AstGen.zig:3856-3897). 2974 uint32_t sentinel_ref = ZIR_REF_NONE; 2975 uint32_t align_ref = ZIR_REF_NONE; 2976 uint32_t addrspace_ref = ZIR_REF_NONE; 2977 uint32_t bit_start_ref = ZIR_REF_NONE; 2978 uint32_t bit_end_ref = ZIR_REF_NONE; 2979 uint32_t trailing_count = 0; 2980 2981 if (sentinel_node != UINT32_MAX) { 2982 uint32_t reason = (size == 2) ? COMPTIME_REASON_SLICE_SENTINEL 2983 : COMPTIME_REASON_POINTER_SENTINEL; 2984 ResultLoc srl = { 2985 .tag = RL_TY, .data = elem_type, .src_node = 0, .ctx = RI_CTX_NONE 2986 }; 2987 sentinel_ref = comptimeExpr(gz, scope, srl, sentinel_node, reason); 2988 trailing_count++; 2989 } 2990 if (addrspace_node != UINT32_MAX) { 2991 // Upstream creates addrspace_ty via addBuiltinValue, we don't have 2992 // that yet, so pass RL_NONE (matching previous behavior). 2993 addrspace_ref = comptimeExpr( 2994 gz, scope, RL_NONE_VAL, addrspace_node, COMPTIME_REASON_ADDRSPACE); 2995 trailing_count++; 2996 } 2997 if (align_node != UINT32_MAX) { 2998 ResultLoc arl = { .tag = RL_COERCED_TY, 2999 .data = ZIR_REF_U29_TYPE, 3000 .src_node = 0, 3001 .ctx = RI_CTX_NONE }; 3002 align_ref 3003 = comptimeExpr(gz, scope, arl, align_node, COMPTIME_REASON_ALIGN); 3004 trailing_count++; 3005 } 3006 if (bit_range_start != UINT32_MAX) { 3007 ResultLoc brl = { .tag = RL_COERCED_TY, 3008 .data = ZIR_REF_U16_TYPE, 3009 .src_node = 0, 3010 .ctx = RI_CTX_NONE }; 3011 bit_start_ref = comptimeExpr( 3012 gz, scope, brl, bit_range_start, COMPTIME_REASON_TYPE); 3013 bit_end_ref = comptimeExpr( 3014 gz, scope, brl, bit_range_end, COMPTIME_REASON_TYPE); 3015 trailing_count += 2; 3016 } 3017 3018 // Build PtrType payload: { elem_type, src_node } + trailing 3019 // (AstGen.zig:3905-3921). 3020 ensureExtraCapacity(ag, 2 + trailing_count); 3021 uint32_t payload_index = ag->extra_len; 3022 ag->extra[ag->extra_len++] = elem_type; 3023 ag->extra[ag->extra_len++] 3024 = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); 3025 if (sentinel_ref != ZIR_REF_NONE) 3026 ag->extra[ag->extra_len++] = sentinel_ref; 3027 if (align_ref != ZIR_REF_NONE) 3028 ag->extra[ag->extra_len++] = align_ref; 3029 if (addrspace_ref != ZIR_REF_NONE) 3030 ag->extra[ag->extra_len++] = addrspace_ref; 3031 if (bit_start_ref != ZIR_REF_NONE) { 3032 ag->extra[ag->extra_len++] = bit_start_ref; 3033 ag->extra[ag->extra_len++] = bit_end_ref; 3034 } 3035 3036 // Build flags packed byte (AstGen.zig:3927-3934). 3037 uint8_t flags = 0; 3038 if (has_allowzero) 3039 flags |= (1 << 0); // is_allowzero 3040 if (!has_const) 3041 flags |= (1 << 1); // is_mutable 3042 if (has_volatile) 3043 flags |= (1 << 2); // is_volatile 3044 if (sentinel_ref != ZIR_REF_NONE) 3045 flags |= (1 << 3); // has_sentinel 3046 if (align_ref != ZIR_REF_NONE) 3047 flags |= (1 << 4); // has_align 3048 if (addrspace_ref != ZIR_REF_NONE) 3049 flags |= (1 << 5); // has_addrspace 3050 if (bit_start_ref != ZIR_REF_NONE) 3051 flags |= (1 << 6); // has_bit_range 3052 3053 ZirInstData data; 3054 data.ptr_type.flags = flags; 3055 data.ptr_type.size = size; 3056 data.ptr_type._pad = 0; 3057 data.ptr_type.payload_index = payload_index; 3058 return addInstruction(gz, ZIR_INST_PTR_TYPE, data); 3059 } 3060 3061 // --- arrayType (AstGen.zig:940) --- 3062 3063 static uint32_t arrayTypeExpr(GenZir* gz, Scope* scope, uint32_t node) { 3064 AstGenCtx* ag = gz->astgen; 3065 const Ast* tree = ag->tree; 3066 AstData nd = tree->nodes.datas[node]; 3067 3068 // data.lhs = length expr node, data.rhs = element type node. 3069 // Check for `_` identifier → compile error (AstGen.zig:3950-3953). 3070 if (tree->nodes.tags[nd.lhs] == AST_NODE_IDENTIFIER 3071 && isUnderscoreIdent(tree, nd.lhs)) { 3072 SET_ERROR(ag); 3073 return ZIR_REF_VOID_VALUE; 3074 } 3075 ResultLoc len_rl = { .tag = RL_COERCED_TY, 3076 .data = ZIR_REF_USIZE_TYPE, 3077 .src_node = 0, 3078 .ctx = RI_CTX_NONE }; 3079 uint32_t len 3080 = comptimeExpr(gz, scope, len_rl, nd.lhs, COMPTIME_REASON_TYPE); 3081 uint32_t elem_type = typeExpr(gz, scope, nd.rhs); 3082 return addPlNodeBin(gz, ZIR_INST_ARRAY_TYPE, node, len, elem_type); 3083 } 3084 3085 // --- arrayInitExpr (AstGen.zig:1431) --- 3086 // Simplified: handles typed array init with inferred [_] length. 3087 3088 static uint32_t arrayInitExpr( 3089 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 3090 AstGenCtx* ag = gz->astgen; 3091 const Ast* tree = ag->tree; 3092 AstNodeTag tag = tree->nodes.tags[node]; 3093 AstData nd = tree->nodes.datas[node]; 3094 3095 // Get elements and type expression based on the variant. 3096 uint32_t type_expr_node = 0; 3097 uint32_t elem_buf[2]; 3098 const uint32_t* elements = NULL; 3099 uint32_t elem_count = 0; 3100 3101 switch (tag) { 3102 case AST_NODE_ARRAY_INIT_ONE: 3103 case AST_NODE_ARRAY_INIT_ONE_COMMA: { 3104 type_expr_node = nd.lhs; 3105 if (nd.rhs != 0) { 3106 elem_buf[0] = nd.rhs; 3107 elements = elem_buf; 3108 elem_count = 1; 3109 } 3110 break; 3111 } 3112 case AST_NODE_ARRAY_INIT: 3113 case AST_NODE_ARRAY_INIT_COMMA: { 3114 // data = node_and_extra: lhs = type_expr, rhs = extra_index. 3115 // extra[rhs] = SubRange.start, extra[rhs+1] = SubRange.end. 3116 // Elements are extra_data[start..end]. 3117 type_expr_node = nd.lhs; 3118 uint32_t extra_idx = nd.rhs; 3119 uint32_t range_start = tree->extra_data.arr[extra_idx]; 3120 uint32_t range_end = tree->extra_data.arr[extra_idx + 1]; 3121 elements = tree->extra_data.arr + range_start; 3122 elem_count = range_end - range_start; 3123 break; 3124 } 3125 default: 3126 SET_ERROR(ag); 3127 return ZIR_REF_VOID_VALUE; 3128 } 3129 3130 if (type_expr_node == 0 || elem_count == 0) { 3131 SET_ERROR(ag); 3132 return ZIR_REF_VOID_VALUE; 3133 } 3134 3135 // Check if the type is [_]T (inferred length) (AstGen.zig:1446-1474). 3136 if (tree->nodes.tags[type_expr_node] == AST_NODE_ARRAY_TYPE) { 3137 AstData type_nd = tree->nodes.datas[type_expr_node]; 3138 uint32_t elem_count_node = type_nd.lhs; 3139 uint32_t elem_type_node = type_nd.rhs; 3140 3141 // Check if elem_count is `_` identifier. 3142 if (tree->nodes.tags[elem_count_node] == AST_NODE_IDENTIFIER 3143 && isUnderscoreIdent(tree, elem_count_node)) { 3144 // Inferred length: addInt(elem_count) (AstGen.zig:1452). 3145 uint32_t len_inst = addInt(gz, elem_count); 3146 uint32_t elem_type = typeExpr(gz, scope, elem_type_node); 3147 uint32_t array_type_inst = addPlNodeBin( 3148 gz, ZIR_INST_ARRAY_TYPE, type_expr_node, len_inst, elem_type); 3149 3150 // arrayInitExprTyped (AstGen.zig:1484-1513, 1598-1642). 3151 // Only RL_REF produces array_init_ref; all other RLs use 3152 // array_init + rvalue (AstGen.zig:1507-1511). 3153 bool is_ref = (rl.tag == RL_REF); 3154 uint32_t operands_len = elem_count + 1; 3155 ensureExtraCapacity(ag, 1 + operands_len); 3156 uint32_t payload_index = ag->extra_len; 3157 ag->extra[ag->extra_len++] = operands_len; 3158 ag->extra[ag->extra_len++] = array_type_inst; 3159 uint32_t extra_start = ag->extra_len; 3160 ag->extra_len += elem_count; 3161 for (uint32_t i = 0; i < elem_count; i++) { 3162 // Use elem_type as coercion target for each element. 3163 ResultLoc elem_rl = { 3164 .tag = RL_COERCED_TY, .data = elem_type, .src_node = 0 3165 }; 3166 uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]); 3167 ag->extra[extra_start + i] = elem_ref; 3168 } 3169 ZirInstTag init_tag 3170 = is_ref ? ZIR_INST_ARRAY_INIT_REF : ZIR_INST_ARRAY_INIT; 3171 ZirInstData idata; 3172 idata.pl_node.src_node 3173 = (int32_t)node - (int32_t)gz->decl_node_index; 3174 idata.pl_node.payload_index = payload_index; 3175 uint32_t result = addInstruction(gz, init_tag, idata); 3176 if (is_ref) 3177 return result; 3178 return rvalue(gz, rl, result, node); 3179 } 3180 } 3181 3182 // Non-inferred length: evaluate type normally. 3183 SET_ERROR(ag); 3184 return ZIR_REF_VOID_VALUE; 3185 } 3186 3187 // --- simpleBinOp (AstGen.zig:2204) --- 3188 3189 static uint32_t simpleBinOp( 3190 GenZir* gz, Scope* scope, uint32_t node, ZirInstTag op_tag) { 3191 AstGenCtx* ag = gz->astgen; 3192 AstData nd = ag->tree->nodes.datas[node]; 3193 uint32_t lhs = exprRl(gz, scope, RL_NONE_VAL, nd.lhs); 3194 // For arithmetic ops, advance cursor before RHS (AstGen.zig:6245-6256). 3195 uint32_t saved_line = 0, saved_col = 0; 3196 bool need_dbg = false; 3197 if (op_tag == ZIR_INST_ADD || op_tag == ZIR_INST_SUB 3198 || op_tag == ZIR_INST_MUL || op_tag == ZIR_INST_DIV 3199 || op_tag == ZIR_INST_MOD_REM) { 3200 if (!gz->is_comptime) { 3201 advanceSourceCursorToMainToken(ag, gz, node); 3202 } 3203 saved_line = ag->source_line - gz->decl_line; 3204 saved_col = ag->source_column; 3205 need_dbg = true; 3206 } 3207 uint32_t rhs = exprRl(gz, scope, RL_NONE_VAL, nd.rhs); 3208 if (need_dbg) { 3209 emitDbgStmt(gz, saved_line, saved_col); 3210 } 3211 return addPlNodeBin(gz, op_tag, node, lhs, rhs); 3212 } 3213 3214 // --- shiftOp (AstGen.zig:9978) --- 3215 3216 static uint32_t shiftOp( 3217 GenZir* gz, Scope* scope, uint32_t node, ZirInstTag tag) { 3218 AstGenCtx* ag = gz->astgen; 3219 AstData nd = ag->tree->nodes.datas[node]; 3220 uint32_t lhs = exprRl(gz, scope, RL_NONE_VAL, nd.lhs); 3221 3222 advanceSourceCursorToMainToken(ag, gz, node); 3223 uint32_t saved_line = ag->source_line - gz->decl_line; 3224 uint32_t saved_col = ag->source_column; 3225 3226 uint32_t log2_int_type 3227 = addUnNode(gz, ZIR_INST_TYPEOF_LOG2_INT_TYPE, lhs, nd.lhs); 3228 ResultLoc rhs_rl = { .tag = RL_TY, 3229 .data = log2_int_type, 3230 .src_node = 0, 3231 .ctx = RI_CTX_SHIFT_OP }; 3232 uint32_t rhs = exprRl(gz, scope, rhs_rl, nd.rhs); 3233 3234 emitDbgStmt(gz, saved_line, saved_col); 3235 3236 return addPlNodeBin(gz, tag, node, lhs, rhs); 3237 } 3238 3239 // --- multilineStringLiteral (AstGen.zig:8645) --- 3240 // Port of strLitNodeAsString for multiline strings. 3241 static uint32_t multilineStringLiteral( 3242 GenZir* gz, Scope* scope, uint32_t node) { 3243 (void)scope; 3244 AstGenCtx* ag = gz->astgen; 3245 const Ast* tree = ag->tree; 3246 AstData nd = tree->nodes.datas[node]; 3247 uint32_t start_tok = nd.lhs; 3248 uint32_t end_tok = nd.rhs; 3249 3250 uint32_t str_index = ag->string_bytes_len; 3251 3252 // First line: no preceding newline. 3253 for (uint32_t tok_i = start_tok; tok_i <= end_tok; tok_i++) { 3254 uint32_t tok_start = tree->tokens.starts[tok_i]; 3255 const char* source = tree->source; 3256 // Skip leading `\\` (2 chars). 3257 uint32_t content_start = tok_start + 2; 3258 // Find end of line. 3259 uint32_t content_end = content_start; 3260 while (content_end < tree->source_len && source[content_end] != '\n') 3261 content_end++; 3262 uint32_t line_len = content_end - content_start; 3263 3264 if (tok_i > start_tok) { 3265 // Prepend newline for lines after the first. 3266 ensureStringBytesCapacity(ag, line_len + 1); 3267 ag->string_bytes[ag->string_bytes_len++] = '\n'; 3268 } else { 3269 ensureStringBytesCapacity(ag, line_len); 3270 } 3271 memcpy(ag->string_bytes + ag->string_bytes_len, source + content_start, 3272 line_len); 3273 ag->string_bytes_len += line_len; 3274 } 3275 3276 uint32_t len = ag->string_bytes_len - str_index; 3277 ensureStringBytesCapacity(ag, 1); 3278 ag->string_bytes[ag->string_bytes_len++] = 0; // null terminator 3279 3280 ZirInstData data; 3281 data.str.start = str_index; 3282 data.str.len = len; 3283 return addInstruction(gz, ZIR_INST_STR, data); 3284 } 3285 3286 // --- ret (AstGen.zig:8119) --- 3287 static uint32_t retExpr(GenZir* gz, Scope* scope, uint32_t node) { 3288 AstGenCtx* ag = gz->astgen; 3289 const Ast* tree = ag->tree; 3290 3291 // Ensure debug line/column information is emitted for this return 3292 // expression (AstGen.zig:8141-8144). 3293 if (!gz->is_comptime) { 3294 emitDbgNode(gz, node); 3295 } 3296 uint32_t ret_lc_line = ag->source_line - gz->decl_line; 3297 uint32_t ret_lc_column = ag->source_column; 3298 3299 // AstGen.zig:8123: return outside function is an error. 3300 if (ag->fn_block == NULL) { 3301 SET_ERROR(ag); 3302 return ZIR_REF_UNREACHABLE_VALUE; 3303 } 3304 const Scope* defer_outer = &((GenZir*)ag->fn_block)->base; 3305 3306 AstData nd = tree->nodes.datas[node]; 3307 uint32_t operand_node = nd.lhs; // optional 3308 3309 if (operand_node == 0) { 3310 // Void return (AstGen.zig:8148-8156). 3311 genDefers(gz, defer_outer, scope, DEFER_NORMAL_ONLY); 3312 // Restore error trace unconditionally (AstGen.zig:8153). 3313 ZirInstData rdata; 3314 rdata.un_node.operand = ZIR_REF_NONE; 3315 rdata.un_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 3316 addInstruction( 3317 gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); 3318 addUnNode(gz, ZIR_INST_RET_NODE, ZIR_REF_VOID_VALUE, node); 3319 return ZIR_REF_UNREACHABLE_VALUE; 3320 } 3321 3322 // Fast path: return error.Foo (AstGen.zig:8159-8175). 3323 if (tree->nodes.tags[operand_node] == AST_NODE_ERROR_VALUE) { 3324 uint32_t error_token = tree->nodes.main_tokens[operand_node] + 2; 3325 uint32_t err_name_str = identAsString(ag, error_token); 3326 DeferCounts dc = countDefers(defer_outer, scope); 3327 if (!dc.need_err_code) { 3328 genDefers(gz, defer_outer, scope, DEFER_BOTH_SANS_ERR); 3329 emitDbgStmt(gz, ret_lc_line, ret_lc_column); 3330 addStrTok(gz, ZIR_INST_RET_ERR_VALUE, err_name_str, error_token); 3331 return ZIR_REF_UNREACHABLE_VALUE; 3332 } 3333 // need_err_code path: not implemented yet, fall through to general. 3334 } 3335 3336 // Evaluate operand with result location (AstGen.zig:8178-8186). 3337 // If nodes_need_rl contains this return node, use ptr-based RL; 3338 // otherwise use coerced_ty. 3339 ResultLoc ret_rl = RL_NONE_VAL; 3340 bool use_ptr = nodesNeedRlContains(ag, node); 3341 uint32_t ret_ptr_inst = 0; 3342 if (use_ptr) { 3343 // Create ret_ptr instruction (AstGen.zig:8179). 3344 ZirInstData rpdata; 3345 rpdata.node = (int32_t)node - (int32_t)gz->decl_node_index; 3346 ret_ptr_inst = addInstruction(gz, ZIR_INST_RET_PTR, rpdata); 3347 ret_rl.tag = RL_PTR; 3348 ret_rl.data = ret_ptr_inst; 3349 } else if (ag->fn_ret_ty != 0) { 3350 ret_rl.tag = RL_COERCED_TY; 3351 ret_rl.data = ag->fn_ret_ty; 3352 } 3353 ret_rl.ctx = RI_CTX_RETURN; 3354 uint32_t operand = exprRl(gz, scope, ret_rl, operand_node); 3355 3356 // Emit RESTORE_ERR_RET_INDEX based on nodeMayEvalToError 3357 // (AstGen.zig:8188-8253). 3358 int eval_to_err = nodeMayEvalToError(tree, operand_node); 3359 if (eval_to_err == EVAL_TO_ERROR_NEVER) { 3360 // Returning non-error: pop error trace unconditionally 3361 // (AstGen.zig:8190-8198). 3362 genDefers(gz, defer_outer, scope, DEFER_NORMAL_ONLY); 3363 ZirInstData rdata; 3364 rdata.un_node.operand = ZIR_REF_NONE; 3365 rdata.un_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 3366 addInstruction( 3367 gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); 3368 emitDbgStmt(gz, ret_lc_line, ret_lc_column); 3369 // addRet (AstGen.zig:13188-13194). 3370 if (use_ptr) { 3371 addUnNode(gz, ZIR_INST_RET_LOAD, ret_ptr_inst, node); 3372 } else { 3373 addUnNode(gz, ZIR_INST_RET_NODE, operand, node); 3374 } 3375 return ZIR_REF_UNREACHABLE_VALUE; 3376 } else if (eval_to_err == EVAL_TO_ERROR_ALWAYS) { 3377 // .always: emit both error defers and regular defers 3378 // (AstGen.zig:8200-8206). 3379 uint32_t err_code = use_ptr 3380 ? addUnNode(gz, ZIR_INST_LOAD, ret_ptr_inst, node) 3381 : operand; 3382 (void)err_code; 3383 // TODO: genDefers with .both = err_code when errdefer is implemented. 3384 genDefers(gz, defer_outer, scope, DEFER_NORMAL_ONLY); 3385 emitDbgStmt(gz, ret_lc_line, ret_lc_column); 3386 if (use_ptr) { 3387 addUnNode(gz, ZIR_INST_RET_LOAD, ret_ptr_inst, node); 3388 } else { 3389 addUnNode(gz, ZIR_INST_RET_NODE, operand, node); 3390 } 3391 return ZIR_REF_UNREACHABLE_VALUE; 3392 } else { 3393 // .maybe (AstGen.zig:8208-8252). 3394 DeferCounts dc = countDefers(defer_outer, scope); 3395 if (!dc.have_err) { 3396 // Only regular defers; no branch needed (AstGen.zig:8210-8220). 3397 genDefers(gz, defer_outer, scope, DEFER_NORMAL_ONLY); 3398 emitDbgStmt(gz, ret_lc_line, ret_lc_column); 3399 uint32_t result = use_ptr 3400 ? addUnNode(gz, ZIR_INST_LOAD, ret_ptr_inst, node) 3401 : operand; 3402 ZirInstData rdata; 3403 rdata.un_node.operand = result; 3404 rdata.un_node.src_node 3405 = (int32_t)node - (int32_t)gz->decl_node_index; 3406 addInstruction(gz, ZIR_INST_RESTORE_ERR_RET_INDEX_FN_ENTRY, rdata); 3407 if (use_ptr) { 3408 addUnNode(gz, ZIR_INST_RET_LOAD, ret_ptr_inst, node); 3409 } else { 3410 addUnNode(gz, ZIR_INST_RET_NODE, operand, node); 3411 } 3412 return ZIR_REF_UNREACHABLE_VALUE; 3413 } 3414 // have_err path: emit conditional branch (not yet implemented). 3415 // Fall through to simplified path. 3416 genDefers(gz, defer_outer, scope, DEFER_NORMAL_ONLY); 3417 emitDbgStmt(gz, ret_lc_line, ret_lc_column); 3418 if (use_ptr) { 3419 addUnNode(gz, ZIR_INST_RET_LOAD, ret_ptr_inst, node); 3420 } else { 3421 addUnNode(gz, ZIR_INST_RET_NODE, operand, node); 3422 } 3423 return ZIR_REF_UNREACHABLE_VALUE; 3424 } 3425 } 3426 3427 // --- calleeExpr (AstGen.zig:10183) --- 3428 // Returns: 0 = direct call, 1 = field call. 3429 3430 typedef struct { 3431 bool is_field; 3432 uint32_t obj_ptr; // for field calls: ref to object 3433 uint32_t field_name_start; // for field calls: string index 3434 uint32_t direct; // for direct calls: ref to callee 3435 } Callee; 3436 3437 static Callee calleeExpr( 3438 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t fn_expr_node) { 3439 AstGenCtx* ag = gz->astgen; 3440 const Ast* tree = ag->tree; 3441 AstNodeTag tag = tree->nodes.tags[fn_expr_node]; 3442 3443 if (tag == AST_NODE_FIELD_ACCESS) { 3444 AstData nd = tree->nodes.datas[fn_expr_node]; 3445 uint32_t object_node = nd.lhs; 3446 uint32_t field_ident = nd.rhs; 3447 uint32_t str_index = identAsString(ag, field_ident); 3448 // Evaluate object with .ref rl (AstGen.zig:10207). 3449 uint32_t lhs = exprRl(gz, scope, RL_REF_VAL, object_node); 3450 3451 // Advance to main token (the `.` dot) — not first token 3452 // (AstGen.zig:10209). 3453 advanceSourceCursorToMainToken(ag, gz, fn_expr_node); 3454 { 3455 uint32_t line = ag->source_line - gz->decl_line; 3456 uint32_t column = ag->source_column; 3457 emitDbgStmt(gz, line, column); 3458 } 3459 3460 Callee c; 3461 c.is_field = true; 3462 c.obj_ptr = lhs; 3463 c.field_name_start = str_index; 3464 c.direct = 0; 3465 return c; 3466 } 3467 3468 // enum_literal callee: decl literal call syntax (AstGen.zig:10217-10233). 3469 if (tag == AST_NODE_ENUM_LITERAL) { 3470 uint32_t res_ty = rlResultType(gz, rl, fn_expr_node); 3471 if (res_ty != 0) { 3472 uint32_t str_index 3473 = identAsString(ag, tree->nodes.main_tokens[fn_expr_node]); 3474 uint32_t callee = addPlNodeBin(gz, ZIR_INST_DECL_LITERAL_NO_COERCE, 3475 fn_expr_node, res_ty, str_index); 3476 Callee c; 3477 c.is_field = false; 3478 c.direct = callee; 3479 c.obj_ptr = 0; 3480 c.field_name_start = 0; 3481 return c; 3482 } 3483 // No result type: fall through to expr with rl=none. 3484 } 3485 3486 // Default: direct call (AstGen.zig:10235). 3487 Callee c; 3488 c.is_field = false; 3489 c.direct = expr(gz, scope, fn_expr_node); 3490 c.obj_ptr = 0; 3491 c.field_name_start = 0; 3492 return c; 3493 } 3494 3495 // --- callExpr (AstGen.zig:10058) --- 3496 static uint32_t callExpr( 3497 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 3498 AstGenCtx* ag = gz->astgen; 3499 const Ast* tree = ag->tree; 3500 AstNodeTag tag = tree->nodes.tags[node]; 3501 AstData nd = tree->nodes.datas[node]; 3502 3503 // Extract callee and args from AST. 3504 uint32_t fn_expr_node; 3505 uint32_t arg_buf[2]; 3506 const uint32_t* args = NULL; 3507 uint32_t args_len = 0; 3508 uint32_t lparen_tok; 3509 3510 switch (tag) { 3511 case AST_NODE_CALL_ONE: 3512 case AST_NODE_CALL_ONE_COMMA: { 3513 fn_expr_node = nd.lhs; 3514 lparen_tok = tree->nodes.main_tokens[node]; 3515 if (nd.rhs != 0) { 3516 arg_buf[0] = nd.rhs; 3517 args = arg_buf; 3518 args_len = 1; 3519 } 3520 break; 3521 } 3522 case AST_NODE_CALL: 3523 case AST_NODE_CALL_COMMA: { 3524 fn_expr_node = nd.lhs; 3525 lparen_tok = tree->nodes.main_tokens[node]; 3526 uint32_t extra_idx = nd.rhs; 3527 uint32_t range_start = tree->extra_data.arr[extra_idx]; 3528 uint32_t range_end = tree->extra_data.arr[extra_idx + 1]; 3529 args = tree->extra_data.arr + range_start; 3530 args_len = range_end - range_start; 3531 break; 3532 } 3533 default: 3534 SET_ERROR(ag); 3535 return ZIR_REF_VOID_VALUE; 3536 } 3537 3538 Callee callee = calleeExpr(gz, scope, rl, fn_expr_node); 3539 3540 // dbg_stmt before call (AstGen.zig:10078-10083). 3541 { 3542 advanceSourceCursor(ag, tree->tokens.starts[lparen_tok]); 3543 uint32_t line = ag->source_line - gz->decl_line; 3544 uint32_t column = ag->source_column; 3545 emitDbgStmtForceCurrentIndex(gz, line, column); 3546 } 3547 3548 // Reserve instruction slot for call (AstGen.zig:10093). 3549 uint32_t call_index = ag->inst_len; 3550 ensureInstCapacity(ag, 1); 3551 memset(&ag->inst_datas[call_index], 0, sizeof(ZirInstData)); 3552 ag->inst_tags[call_index] = (ZirInstTag)0; 3553 ag->inst_len++; 3554 gzAppendInstruction(gz, call_index); 3555 3556 // Process arguments in sub-blocks (AstGen.zig:10096-10116). 3557 // Upstream uses a separate scratch array; we use a local buffer for body 3558 // lengths and append body instructions to scratch_extra, then copy all 3559 // to extra after the call payload. 3560 uint32_t call_inst = call_index + ZIR_REF_START_INDEX; 3561 ResultLoc arg_rl = { .tag = RL_COERCED_TY, 3562 .data = call_inst, 3563 .src_node = 0, 3564 .ctx = RI_CTX_FN_ARG }; 3565 3566 // Use scratch_extra to collect body lengths + body instructions, 3567 // mirroring upstream's scratch array (AstGen.zig:10096-10116). 3568 uint32_t scratch_top = ag->scratch_extra_len; 3569 // Reserve space for cumulative body lengths (one per arg). 3570 ensureScratchExtraCapacity(ag, args_len); 3571 ag->scratch_extra_len += args_len; 3572 3573 for (uint32_t i = 0; i < args_len; i++) { 3574 GenZir arg_block = makeSubBlock(gz, scope); 3575 uint32_t arg_ref 3576 = exprRl(&arg_block, &arg_block.base, arg_rl, args[i]); 3577 3578 // break_inline with param_node src (AstGen.zig:10108). 3579 int32_t param_src 3580 = (int32_t)args[i] - (int32_t)arg_block.decl_node_index; 3581 makeBreakInline(&arg_block, call_index, arg_ref, param_src); 3582 3583 // Append arg_block body to scratch_extra (with ref_table fixups). 3584 uint32_t raw_body_len = gzInstructionsLen(&arg_block); 3585 const uint32_t* body = gzInstructionsSlice(&arg_block); 3586 uint32_t fixup_len = countBodyLenAfterFixups(ag, body, raw_body_len); 3587 ensureScratchExtraCapacity(ag, fixup_len); 3588 for (uint32_t j = 0; j < raw_body_len; j++) { 3589 appendPossiblyRefdBodyInstScratch(ag, body[j]); 3590 } 3591 // Record cumulative body length (AstGen.zig:10114). 3592 ag->scratch_extra[scratch_top + i] 3593 = ag->scratch_extra_len - scratch_top; 3594 gzUnstack(&arg_block); 3595 } 3596 3597 // Build call payload (AstGen.zig:10118-10168). 3598 // Upstream layout: [flags, callee/obj_ptr, field_name_start], then 3599 // body_lengths + body_instructions from scratch. 3600 // Flags layout (packed): modifier:u3, ensure_result_used:bool, 3601 // pop_error_return_trace:bool, args_len:u27. 3602 // pop_error_return_trace = !propagate_error_trace 3603 // (AstGen.zig:10121-10124). 3604 bool propagate_error_trace 3605 = (rl.ctx == RI_CTX_ERROR_HANDLING_EXPR || rl.ctx == RI_CTX_RETURN 3606 || rl.ctx == RI_CTX_FN_ARG || rl.ctx == RI_CTX_CONST_INIT); 3607 uint32_t flags = (propagate_error_trace ? 0u : (1u << 4)) 3608 | ((args_len & 0x7FFFFFFu) << 5); // args_len 3609 3610 if (callee.is_field) { 3611 // FieldCall: {flags, obj_ptr, field_name_start} (AstGen.zig:10148). 3612 ensureExtraCapacity(ag, 3 + (ag->scratch_extra_len - scratch_top)); 3613 uint32_t payload_index = ag->extra_len; 3614 ag->extra[ag->extra_len++] = flags; 3615 ag->extra[ag->extra_len++] = callee.obj_ptr; 3616 ag->extra[ag->extra_len++] = callee.field_name_start; 3617 // Append scratch data (body lengths + body instructions). 3618 if (args_len != 0) { 3619 memcpy(ag->extra + ag->extra_len, ag->scratch_extra + scratch_top, 3620 (ag->scratch_extra_len - scratch_top) * sizeof(uint32_t)); 3621 ag->extra_len += ag->scratch_extra_len - scratch_top; 3622 } 3623 ag->inst_tags[call_index] = ZIR_INST_FIELD_CALL; 3624 ag->inst_datas[call_index].pl_node.src_node 3625 = (int32_t)node - (int32_t)gz->decl_node_index; 3626 ag->inst_datas[call_index].pl_node.payload_index = payload_index; 3627 } else { 3628 // Call: {flags, callee} (AstGen.zig:10128). 3629 ensureExtraCapacity(ag, 2 + (ag->scratch_extra_len - scratch_top)); 3630 uint32_t payload_index = ag->extra_len; 3631 ag->extra[ag->extra_len++] = flags; 3632 ag->extra[ag->extra_len++] = callee.direct; 3633 // Append scratch data (body lengths + body instructions). 3634 if (args_len != 0) { 3635 memcpy(ag->extra + ag->extra_len, ag->scratch_extra + scratch_top, 3636 (ag->scratch_extra_len - scratch_top) * sizeof(uint32_t)); 3637 ag->extra_len += ag->scratch_extra_len - scratch_top; 3638 } 3639 ag->inst_tags[call_index] = ZIR_INST_CALL; 3640 ag->inst_datas[call_index].pl_node.src_node 3641 = (int32_t)node - (int32_t)gz->decl_node_index; 3642 ag->inst_datas[call_index].pl_node.payload_index = payload_index; 3643 } 3644 3645 // Restore scratch (AstGen.zig:10097 defer). 3646 ag->scratch_extra_len = scratch_top; 3647 3648 return call_index + ZIR_REF_START_INDEX; 3649 } 3650 3651 // --- structInitExpr (AstGen.zig:1674) --- 3652 // Simplified: handles .{} (empty tuple), .{.a = b} (anon init). 3653 static uint32_t structInitExpr( 3654 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 3655 AstGenCtx* ag = gz->astgen; 3656 const Ast* tree = ag->tree; 3657 AstNodeTag tag = tree->nodes.tags[node]; 3658 AstData nd = tree->nodes.datas[node]; 3659 3660 // Extract type_expr and fields. 3661 uint32_t type_expr_node = 0; // 0 = anonymous (.{...}) 3662 uint32_t field_buf[2]; 3663 const uint32_t* fields = NULL; 3664 uint32_t fields_len = 0; 3665 3666 switch (tag) { 3667 case AST_NODE_STRUCT_INIT_DOT_TWO: 3668 case AST_NODE_STRUCT_INIT_DOT_TWO_COMMA: { 3669 // .{.a = lhs, .b = rhs} 3670 uint32_t idx = 0; 3671 if (nd.lhs != 0) 3672 field_buf[idx++] = nd.lhs; 3673 if (nd.rhs != 0) 3674 field_buf[idx++] = nd.rhs; 3675 fields = field_buf; 3676 fields_len = idx; 3677 break; 3678 } 3679 case AST_NODE_STRUCT_INIT_DOT: 3680 case AST_NODE_STRUCT_INIT_DOT_COMMA: { 3681 uint32_t start = nd.lhs; 3682 uint32_t end = nd.rhs; 3683 fields = tree->extra_data.arr + start; 3684 fields_len = end - start; 3685 break; 3686 } 3687 case AST_NODE_STRUCT_INIT_ONE: 3688 case AST_NODE_STRUCT_INIT_ONE_COMMA: { 3689 type_expr_node = nd.lhs; 3690 if (nd.rhs != 0) { 3691 field_buf[0] = nd.rhs; 3692 fields = field_buf; 3693 fields_len = 1; 3694 } 3695 break; 3696 } 3697 case AST_NODE_STRUCT_INIT: 3698 case AST_NODE_STRUCT_INIT_COMMA: { 3699 type_expr_node = nd.lhs; 3700 uint32_t extra_idx = nd.rhs; 3701 uint32_t range_start = tree->extra_data.arr[extra_idx]; 3702 uint32_t range_end = tree->extra_data.arr[extra_idx + 1]; 3703 fields = tree->extra_data.arr + range_start; 3704 fields_len = range_end - range_start; 3705 break; 3706 } 3707 default: 3708 SET_ERROR(ag); 3709 return ZIR_REF_VOID_VALUE; 3710 } 3711 3712 if (type_expr_node == 0 && fields_len == 0) { 3713 // .{} — depends on result location (AstGen.zig:1687-1698). 3714 if (rl.tag == RL_REF_COERCED_TY) { 3715 return addUnNode( 3716 gz, ZIR_INST_STRUCT_INIT_EMPTY_REF_RESULT, rl.data, node); 3717 } 3718 if (rl.tag == RL_TY || rl.tag == RL_COERCED_TY) { 3719 return addUnNode( 3720 gz, ZIR_INST_STRUCT_INIT_EMPTY_RESULT, rl.data, node); 3721 } 3722 if (rl.tag == RL_DISCARD) { 3723 return ZIR_REF_VOID_VALUE; 3724 } 3725 return ZIR_REF_EMPTY_TUPLE; 3726 } 3727 3728 // Pre-register all field names to match upstream string ordering. 3729 // Upstream has a duplicate name check (AstGen.zig:1756-1806) that 3730 // adds all field names to string_bytes before evaluating values. 3731 for (uint32_t i = 0; i < fields_len; i++) { 3732 uint32_t name_token = firstToken(tree, fields[i]) - 2; 3733 identAsString(ag, name_token); 3734 } 3735 3736 if (type_expr_node == 0 && fields_len > 0) { 3737 // structInitExprPtr for RL_PTR (AstGen.zig:1843-1846, 1934-1964). 3738 if (rl.tag == RL_PTR) { 3739 uint32_t struct_ptr_inst 3740 = addUnNode(gz, ZIR_INST_OPT_EU_BASE_PTR_INIT, rl.data, node); 3741 // Block payload: body_len = fields_len. 3742 ensureExtraCapacity(ag, 1 + fields_len); 3743 uint32_t payload_index = ag->extra_len; 3744 ag->extra[ag->extra_len++] = fields_len; 3745 uint32_t items_start = ag->extra_len; 3746 ag->extra_len += fields_len; 3747 3748 for (uint32_t i = 0; i < fields_len; i++) { 3749 uint32_t field_init = fields[i]; 3750 uint32_t name_token = firstToken(tree, field_init) - 2; 3751 uint32_t str_index = identAsString(ag, name_token); 3752 // struct_init_field_ptr (AstGen.zig:1954-1957). 3753 uint32_t field_ptr 3754 = addPlNodeBin(gz, ZIR_INST_STRUCT_INIT_FIELD_PTR, 3755 field_init, struct_ptr_inst, str_index); 3756 ag->extra[items_start + i] 3757 = field_ptr - ZIR_REF_START_INDEX; // .toIndex() 3758 // Evaluate init with ptr RL (AstGen.zig:1960). 3759 ResultLoc ptr_rl = { .tag = RL_PTR, 3760 .data = field_ptr, 3761 .src_node = 0, 3762 .ctx = rl.ctx }; 3763 exprRl(gz, scope, ptr_rl, field_init); 3764 } 3765 addPlNodePayloadIndex( 3766 gz, ZIR_INST_VALIDATE_PTR_STRUCT_INIT, node, payload_index); 3767 return ZIR_REF_VOID_VALUE; 3768 } 3769 // Anonymous struct init with RL type (AstGen.zig:1706-1731). 3770 if (rl.tag == RL_TY || rl.tag == RL_COERCED_TY) { 3771 uint32_t ty_inst = rl.data; 3772 // validate_struct_init_result_ty (AstGen.zig:1840). 3773 addUnNode( 3774 gz, ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY, ty_inst, node); 3775 // structInitExprTyped (AstGen.zig:1896-1931). 3776 ensureExtraCapacity(ag, 3 + fields_len * 2); 3777 uint32_t payload_index = ag->extra_len; 3778 ag->extra[ag->extra_len++] = node; 3779 ag->extra[ag->extra_len++] = ag->source_line; 3780 ag->extra[ag->extra_len++] = fields_len; 3781 uint32_t items_start = ag->extra_len; 3782 ag->extra_len += fields_len * 2; 3783 for (uint32_t i = 0; i < fields_len; i++) { 3784 uint32_t field_init = fields[i]; 3785 uint32_t name_token = firstToken(tree, field_init) - 2; 3786 uint32_t str_index = identAsString(ag, name_token); 3787 uint32_t field_ty_inst 3788 = addPlNodeBin(gz, ZIR_INST_STRUCT_INIT_FIELD_TYPE, 3789 field_init, ty_inst, str_index); 3790 ResultLoc elem_rl = { 3791 .tag = RL_COERCED_TY, .data = field_ty_inst, .src_node = 0 3792 }; 3793 uint32_t init_ref = exprRl(gz, scope, elem_rl, field_init); 3794 ag->extra[items_start + i * 2] 3795 = field_ty_inst - ZIR_REF_START_INDEX; 3796 ag->extra[items_start + i * 2 + 1] = init_ref; 3797 } 3798 return addPlNodePayloadIndex( 3799 gz, ZIR_INST_STRUCT_INIT, node, payload_index); 3800 } 3801 // Anonymous struct init without RL type (AstGen.zig:1864). 3802 // StructInitAnon payload: abs_node, abs_line, fields_len. 3803 ensureExtraCapacity(ag, 3 + fields_len * 2); 3804 uint32_t payload_index = ag->extra_len; 3805 ag->extra[ag->extra_len++] = node; // abs_node 3806 ag->extra[ag->extra_len++] = ag->source_line; // abs_line 3807 ag->extra[ag->extra_len++] = fields_len; 3808 // Reserve space for field entries. 3809 uint32_t items_start = ag->extra_len; 3810 ag->extra_len += fields_len * 2; 3811 3812 for (uint32_t i = 0; i < fields_len; i++) { 3813 uint32_t field_init = fields[i]; 3814 // field name is 2 tokens before the field init's first token. 3815 uint32_t name_token = firstToken(tree, field_init) - 2; 3816 uint32_t str_index = identAsString(ag, name_token); 3817 uint32_t init_ref = expr(gz, scope, field_init); 3818 ag->extra[items_start + i * 2] = str_index; 3819 ag->extra[items_start + i * 2 + 1] = init_ref; 3820 } 3821 3822 return addPlNodePayloadIndex( 3823 gz, ZIR_INST_STRUCT_INIT_ANON, node, payload_index); 3824 } 3825 3826 // Typed init: evaluate type, emit struct_init_empty or struct_init. 3827 if (type_expr_node != 0 && fields_len == 0) { 3828 // Check for [_]T{} pattern (AstGen.zig:1707-1753). 3829 AstNodeTag type_tag = tree->nodes.tags[type_expr_node]; 3830 if (type_tag == AST_NODE_ARRAY_TYPE 3831 || type_tag == AST_NODE_ARRAY_TYPE_SENTINEL) { 3832 AstData type_nd = tree->nodes.datas[type_expr_node]; 3833 uint32_t elem_count_node = type_nd.lhs; 3834 if (tree->nodes.tags[elem_count_node] == AST_NODE_IDENTIFIER 3835 && isUnderscoreIdent(tree, elem_count_node)) { 3836 // Inferred length with 0 fields → length 0. 3837 if (type_tag == AST_NODE_ARRAY_TYPE) { 3838 uint32_t elem_type = typeExpr(gz, scope, type_nd.rhs); 3839 uint32_t array_type_inst 3840 = addPlNodeBin(gz, ZIR_INST_ARRAY_TYPE, type_expr_node, 3841 ZIR_REF_ZERO_USIZE, elem_type); 3842 return rvalue(gz, rl, 3843 addUnNode(gz, ZIR_INST_STRUCT_INIT_EMPTY, 3844 array_type_inst, node), 3845 node); 3846 } 3847 // ARRAY_TYPE_SENTINEL: extra[rhs] = sentinel, extra[rhs+1] 3848 // = elem_type 3849 uint32_t sentinel_node = tree->extra_data.arr[type_nd.rhs]; 3850 uint32_t elem_type_node 3851 = tree->extra_data.arr[type_nd.rhs + 1]; 3852 uint32_t elem_type = typeExpr(gz, scope, elem_type_node); 3853 ResultLoc sent_rl = { .tag = RL_COERCED_TY, 3854 .data = elem_type, 3855 .src_node = 0, 3856 .ctx = RI_CTX_NONE }; 3857 uint32_t sentinel = comptimeExpr(gz, scope, sent_rl, 3858 sentinel_node, COMPTIME_REASON_ARRAY_SENTINEL); 3859 uint32_t array_type_inst = addPlNodeTriple(gz, 3860 ZIR_INST_ARRAY_TYPE_SENTINEL, type_expr_node, 3861 ZIR_REF_ZERO_USIZE, elem_type, sentinel); 3862 return rvalue(gz, rl, 3863 addUnNode( 3864 gz, ZIR_INST_STRUCT_INIT_EMPTY, array_type_inst, node), 3865 node); 3866 } 3867 } 3868 uint32_t ty_inst = typeExpr(gz, scope, type_expr_node); 3869 return rvalue(gz, rl, 3870 addUnNode(gz, ZIR_INST_STRUCT_INIT_EMPTY, ty_inst, node), node); 3871 } 3872 3873 // Typed struct init with fields (AstGen.zig:1808-1818). 3874 if (type_expr_node != 0 && fields_len > 0) { 3875 uint32_t ty_inst = typeExpr(gz, scope, type_expr_node); 3876 addUnNode(gz, ZIR_INST_VALIDATE_STRUCT_INIT_TY, ty_inst, node); 3877 3878 // structInitExprTyped (AstGen.zig:1896-1931). 3879 // StructInit payload: abs_node, abs_line, fields_len. 3880 ensureExtraCapacity(ag, 3 + fields_len * 2); 3881 uint32_t payload_index = ag->extra_len; 3882 ag->extra[ag->extra_len++] = node; // abs_node 3883 ag->extra[ag->extra_len++] = ag->source_line; // abs_line 3884 ag->extra[ag->extra_len++] = fields_len; 3885 // Reserve space for field items (field_type + init each). 3886 uint32_t items_start = ag->extra_len; 3887 ag->extra_len += fields_len * 2; 3888 3889 for (uint32_t i = 0; i < fields_len; i++) { 3890 uint32_t field_init = fields[i]; 3891 uint32_t name_token = firstToken(tree, field_init) - 2; 3892 uint32_t str_index = identAsString(ag, name_token); 3893 // struct_init_field_type (AstGen.zig:1918-1921). 3894 uint32_t field_ty_inst 3895 = addPlNodeBin(gz, ZIR_INST_STRUCT_INIT_FIELD_TYPE, field_init, 3896 ty_inst, str_index); 3897 // Evaluate init with coerced_ty (AstGen.zig:1924). 3898 ResultLoc elem_rl = { .tag = RL_COERCED_TY, 3899 .data = field_ty_inst, 3900 .src_node = 0, 3901 .ctx = rl.ctx }; 3902 uint32_t init_ref = exprRl(gz, scope, elem_rl, field_init); 3903 ag->extra[items_start + i * 2] 3904 = field_ty_inst - ZIR_REF_START_INDEX; // .toIndex() 3905 ag->extra[items_start + i * 2 + 1] = init_ref; 3906 } 3907 3908 bool is_ref = (RL_IS_REF(rl)); 3909 ZirInstTag init_tag 3910 = is_ref ? ZIR_INST_STRUCT_INIT_REF : ZIR_INST_STRUCT_INIT; 3911 return addPlNodePayloadIndex(gz, init_tag, node, payload_index); 3912 } 3913 3914 SET_ERROR(ag); 3915 return ZIR_REF_VOID_VALUE; 3916 } 3917 3918 // --- tryExpr (AstGen.zig:5957) --- 3919 static uint32_t tryExpr(GenZir* gz, Scope* scope, uint32_t node) { 3920 AstGenCtx* ag = gz->astgen; 3921 AstData nd = ag->tree->nodes.datas[node]; 3922 uint32_t operand_node = nd.lhs; 3923 3924 if (!gz->is_comptime) { 3925 emitDbgNode(gz, node); 3926 } 3927 uint32_t try_lc_line = ag->source_line - gz->decl_line; 3928 uint32_t try_lc_column = ag->source_column; 3929 3930 // Evaluate operand (AstGen.zig:5993-6001). 3931 ResultLoc operand_rl = RL_NONE_VAL; 3932 operand_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR; 3933 uint32_t operand = exprRl(gz, scope, operand_rl, operand_node); 3934 3935 // Create try block instruction (AstGen.zig:6007). 3936 uint32_t try_inst = makeBlockInst(ag, ZIR_INST_TRY, gz, node); 3937 gzAppendInstruction(gz, try_inst); 3938 3939 // Else scope: extract error code, return it (AstGen.zig:6012-6025). 3940 GenZir else_scope = makeSubBlock(gz, scope); 3941 3942 uint32_t err_code 3943 = addUnNode(&else_scope, ZIR_INST_ERR_UNION_CODE, operand, node); 3944 3945 // Emit defers for error path (AstGen.zig:6019). 3946 if (ag->fn_block != NULL) { 3947 const Scope* fn_block_scope = &((GenZir*)ag->fn_block)->base; 3948 genDefers(&else_scope, fn_block_scope, scope, DEFER_BOTH_SANS_ERR); 3949 } 3950 3951 // Emit dbg_stmt at try keyword for error return tracing (AstGen.zig:6020). 3952 emitDbgStmt(&else_scope, try_lc_line, try_lc_column); 3953 3954 // ret_node with error code (AstGen.zig:6021). 3955 addUnNode(&else_scope, ZIR_INST_RET_NODE, err_code, node); 3956 3957 setTryBody(ag, &else_scope, try_inst, operand); 3958 // else_scope unstacked by setTryBody. 3959 3960 return try_inst + ZIR_REF_START_INDEX; // toRef() 3961 } 3962 3963 // --- boolBinOp (AstGen.zig:6274) --- 3964 // Short-circuiting boolean and/or. 3965 3966 static uint32_t boolBinOp( 3967 GenZir* gz, Scope* scope, uint32_t node, ZirInstTag zir_tag) { 3968 AstGenCtx* ag = gz->astgen; 3969 AstData nd = ag->tree->nodes.datas[node]; 3970 uint32_t lhs_node = nd.lhs; 3971 uint32_t rhs_node = nd.rhs; 3972 3973 // Evaluate LHS (AstGen.zig:6285). 3974 uint32_t lhs = expr(gz, scope, lhs_node); 3975 3976 // Reserve the bool_br instruction (payload set later) 3977 // (AstGen.zig:6286). 3978 uint32_t bool_br = reserveInstructionIndex(ag); 3979 gzAppendInstruction(gz, bool_br); 3980 3981 // Evaluate RHS in sub-block (AstGen.zig:6288-6293). 3982 GenZir rhs_scope = makeSubBlock(gz, scope); 3983 uint32_t rhs = expr(&rhs_scope, &rhs_scope.base, rhs_node); 3984 3985 if (!ag->has_compile_errors) { 3986 // break_inline from rhs to bool_br (AstGen.zig:6292). 3987 makeBreakInline(&rhs_scope, bool_br, rhs, 3988 (int32_t)rhs_node - (int32_t)rhs_scope.decl_node_index); 3989 } 3990 3991 // setBoolBrBody (AstGen.zig:6294, 11929-11944). 3992 uint32_t raw_body_len = gzInstructionsLen(&rhs_scope); 3993 const uint32_t* body = gzInstructionsSlice(&rhs_scope); 3994 uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_body_len); 3995 ensureExtraCapacity(ag, 2 + body_len); 3996 uint32_t payload_index = ag->extra_len; 3997 ag->extra[ag->extra_len++] = lhs; // BoolBr.lhs 3998 ag->extra[ag->extra_len++] = body_len; // BoolBr.body_len 3999 for (uint32_t i = 0; i < raw_body_len; i++) 4000 appendPossiblyRefdBodyInst(ag, body[i]); 4001 gzUnstack(&rhs_scope); 4002 4003 // Fill in the bool_br instruction. 4004 ag->inst_tags[bool_br] = zir_tag; 4005 ag->inst_datas[bool_br].pl_node.src_node 4006 = (int32_t)node - (int32_t)gz->decl_node_index; 4007 ag->inst_datas[bool_br].pl_node.payload_index = payload_index; 4008 4009 return bool_br + ZIR_REF_START_INDEX; 4010 } 4011 4012 // Mirrors expr (AstGen.zig:634) — main expression dispatcher. 4013 static uint32_t exprRl(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 4014 AstGenCtx* ag = gz->astgen; 4015 if (node == 0) { 4016 SET_ERROR(ag); 4017 return ZIR_REF_VOID_VALUE; 4018 } 4019 AstNodeTag tag = ag->tree->nodes.tags[node]; 4020 AstData nd = ag->tree->nodes.datas[node]; 4021 4022 switch (tag) { 4023 case AST_NODE_NUMBER_LITERAL: 4024 return rvalue(gz, rl, numberLiteral(gz, node), node); 4025 case AST_NODE_BUILTIN_CALL_TWO: 4026 case AST_NODE_BUILTIN_CALL_TWO_COMMA: 4027 return rvalue(gz, rl, builtinCall(gz, scope, rl, node), node); 4028 case AST_NODE_FIELD_ACCESS: 4029 return fieldAccessExpr(gz, scope, rl, node); 4030 case AST_NODE_IDENTIFIER: 4031 return identifierExpr(gz, scope, rl, node); 4032 case AST_NODE_STRING_LITERAL: { 4033 // Mirrors stringLiteral (AstGen.zig:8626). 4034 uint32_t str_lit_token = ag->tree->nodes.main_tokens[node]; 4035 uint32_t str_index, str_len; 4036 strLitAsString(ag, str_lit_token, &str_index, &str_len); 4037 ZirInstData data; 4038 data.str.start = str_index; 4039 data.str.len = str_len; 4040 uint32_t str_result = addInstruction(gz, ZIR_INST_STR, data); 4041 return rvalue(gz, rl, str_result, node); 4042 } 4043 // address_of (AstGen.zig:953-960): evaluate operand with .ref rl. 4044 case AST_NODE_ADDRESS_OF: { 4045 uint32_t operand_node = ag->tree->nodes.datas[node].lhs; 4046 // Check for result type to emit validate_ref_ty (AstGen.zig:954-956). 4047 uint32_t res_ty = rlResultType(gz, rl, node); 4048 ResultLoc operand_rl; 4049 if (res_ty != 0) { 4050 addUnTok(gz, ZIR_INST_VALIDATE_REF_TY, res_ty, 4051 firstToken(ag->tree, node)); 4052 // Pass ref_coerced_ty so init expressions can use the type 4053 // (AstGen.zig:958). 4054 operand_rl = (ResultLoc) { 4055 .tag = RL_REF_COERCED_TY, .data = res_ty, .src_node = 0 4056 }; 4057 } else { 4058 operand_rl = RL_REF_VAL; 4059 } 4060 uint32_t result = exprRl(gz, scope, operand_rl, operand_node); 4061 return rvalue(gz, rl, result, node); 4062 } 4063 // ptr_type (AstGen.zig:1077-1081). 4064 case AST_NODE_PTR_TYPE_ALIGNED: 4065 case AST_NODE_PTR_TYPE_SENTINEL: 4066 case AST_NODE_PTR_TYPE: 4067 case AST_NODE_PTR_TYPE_BIT_RANGE: 4068 return rvalue(gz, rl, ptrTypeExpr(gz, scope, node), node); 4069 // array_type (AstGen.zig:940). 4070 case AST_NODE_ARRAY_TYPE: 4071 return rvalue(gz, rl, arrayTypeExpr(gz, scope, node), node); 4072 // array_init variants (AstGen.zig:836-856). 4073 case AST_NODE_ARRAY_INIT: 4074 case AST_NODE_ARRAY_INIT_COMMA: 4075 case AST_NODE_ARRAY_INIT_ONE: 4076 case AST_NODE_ARRAY_INIT_ONE_COMMA: 4077 return arrayInitExpr(gz, scope, rl, node); 4078 // array_cat (AstGen.zig:772): ++ binary operator. 4079 case AST_NODE_ARRAY_CAT: 4080 return rvalue( 4081 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_ARRAY_CAT), node); 4082 // grouped_expression (AstGen.zig:1100): passthrough. 4083 case AST_NODE_GROUPED_EXPRESSION: 4084 return exprRl(gz, scope, rl, ag->tree->nodes.datas[node].lhs); 4085 // unreachable_literal (AstGen.zig:846-854). 4086 case AST_NODE_UNREACHABLE_LITERAL: { 4087 emitDbgNode(gz, node); 4088 ZirInstData udata; 4089 memset(&udata, 0, sizeof(udata)); 4090 udata.unreachable_data.src_node 4091 = (int32_t)node - (int32_t)gz->decl_node_index; 4092 addInstruction(gz, ZIR_INST_UNREACHABLE, udata); 4093 return ZIR_REF_UNREACHABLE_VALUE; 4094 } 4095 // enum_literal (AstGen.zig:993). 4096 case AST_NODE_ENUM_LITERAL: { 4097 uint32_t ident_token = ag->tree->nodes.main_tokens[node]; 4098 uint32_t str_index = identAsString(ag, ident_token); 4099 // If result type available, emit decl_literal (AstGen.zig:993-1003). 4100 uint32_t res_ty = rlResultType(gz, rl, node); 4101 if (res_ty != 0) { 4102 uint32_t res = addPlNodeBin( 4103 gz, ZIR_INST_DECL_LITERAL, node, res_ty, str_index); 4104 // decl_literal does the coercion for us (AstGen.zig:1001). 4105 // Only need rvalue for ptr/inferred_ptr/ref_coerced_ty. 4106 if (rl.tag == RL_TY || rl.tag == RL_COERCED_TY) 4107 return res; 4108 return rvalue(gz, rl, res, node); 4109 } 4110 return rvalue(gz, rl, 4111 addStrTok(gz, ZIR_INST_ENUM_LITERAL, str_index, ident_token), 4112 node); 4113 } 4114 // multiline_string_literal (AstGen.zig:8645). 4115 case AST_NODE_MULTILINE_STRING_LITERAL: 4116 return rvalue(gz, rl, multilineStringLiteral(gz, scope, node), node); 4117 // return (AstGen.zig:856). 4118 case AST_NODE_RETURN: 4119 return retExpr(gz, scope, node); 4120 // call (AstGen.zig:783-790). 4121 case AST_NODE_CALL_ONE: 4122 case AST_NODE_CALL_ONE_COMMA: 4123 case AST_NODE_CALL: 4124 case AST_NODE_CALL_COMMA: 4125 return rvalue(gz, rl, callExpr(gz, scope, rl, node), node); 4126 // struct_init (AstGen.zig:836-839). 4127 case AST_NODE_STRUCT_INIT_DOT_TWO: 4128 case AST_NODE_STRUCT_INIT_DOT_TWO_COMMA: 4129 case AST_NODE_STRUCT_INIT_DOT: 4130 case AST_NODE_STRUCT_INIT_DOT_COMMA: 4131 case AST_NODE_STRUCT_INIT_ONE: 4132 case AST_NODE_STRUCT_INIT_ONE_COMMA: 4133 case AST_NODE_STRUCT_INIT: 4134 case AST_NODE_STRUCT_INIT_COMMA: 4135 return structInitExpr(gz, scope, rl, node); 4136 // container_decl (AstGen.zig:1083-1098). 4137 case AST_NODE_CONTAINER_DECL: 4138 case AST_NODE_CONTAINER_DECL_TRAILING: 4139 case AST_NODE_CONTAINER_DECL_TWO: 4140 case AST_NODE_CONTAINER_DECL_TWO_TRAILING: 4141 case AST_NODE_CONTAINER_DECL_ARG: 4142 case AST_NODE_CONTAINER_DECL_ARG_TRAILING: 4143 case AST_NODE_TAGGED_UNION: 4144 case AST_NODE_TAGGED_UNION_TRAILING: 4145 case AST_NODE_TAGGED_UNION_TWO: 4146 case AST_NODE_TAGGED_UNION_TWO_TRAILING: 4147 case AST_NODE_TAGGED_UNION_ENUM_TAG: 4148 case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: 4149 return rvalue(gz, rl, containerDecl(gz, scope, node), node); 4150 // try (AstGen.zig:831). 4151 case AST_NODE_TRY: 4152 return rvalue(gz, rl, tryExpr(gz, scope, node), node); 4153 // Comparison operators (AstGen.zig:714-726). 4154 case AST_NODE_EQUAL_EQUAL: 4155 return rvalue( 4156 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_CMP_EQ), node); 4157 case AST_NODE_BANG_EQUAL: 4158 return rvalue( 4159 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_CMP_NEQ), node); 4160 case AST_NODE_LESS_THAN: 4161 return rvalue( 4162 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_CMP_LT), node); 4163 case AST_NODE_GREATER_THAN: 4164 return rvalue( 4165 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_CMP_GT), node); 4166 case AST_NODE_LESS_OR_EQUAL: 4167 return rvalue( 4168 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_CMP_LTE), node); 4169 case AST_NODE_GREATER_OR_EQUAL: 4170 return rvalue( 4171 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_CMP_GTE), node); 4172 // Arithmetic (AstGen.zig:656-698). 4173 case AST_NODE_ADD: 4174 return rvalue( 4175 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_ADD), node); 4176 case AST_NODE_SUB: 4177 return rvalue( 4178 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_SUB), node); 4179 case AST_NODE_MUL: 4180 return rvalue( 4181 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_MUL), node); 4182 case AST_NODE_DIV: 4183 return rvalue( 4184 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_DIV), node); 4185 case AST_NODE_MOD: 4186 return rvalue( 4187 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_MOD), node); 4188 // Bitwise (AstGen.zig:700-712). 4189 case AST_NODE_BIT_AND: 4190 return rvalue( 4191 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_BIT_AND), node); 4192 case AST_NODE_BIT_OR: 4193 return rvalue( 4194 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_BIT_OR), node); 4195 case AST_NODE_BIT_XOR: 4196 return rvalue( 4197 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_XOR), node); 4198 case AST_NODE_SHL: 4199 return rvalue(gz, rl, shiftOp(gz, scope, node, ZIR_INST_SHL), node); 4200 case AST_NODE_SHR: 4201 return rvalue(gz, rl, shiftOp(gz, scope, node, ZIR_INST_SHR), node); 4202 // Boolean operators (AstGen.zig:728-731) — special: boolBinOp. 4203 case AST_NODE_BOOL_AND: 4204 return rvalue( 4205 gz, rl, boolBinOp(gz, scope, node, ZIR_INST_BOOL_BR_AND), node); 4206 case AST_NODE_BOOL_OR: 4207 return rvalue( 4208 gz, rl, boolBinOp(gz, scope, node, ZIR_INST_BOOL_BR_OR), node); 4209 // Unary operators (AstGen.zig:919-938). 4210 case AST_NODE_BOOL_NOT: 4211 return rvalue(gz, rl, 4212 addUnNode(gz, ZIR_INST_BOOL_NOT, expr(gz, scope, nd.lhs), node), 4213 node); 4214 case AST_NODE_BIT_NOT: 4215 return rvalue(gz, rl, 4216 addUnNode(gz, ZIR_INST_BIT_NOT, expr(gz, scope, nd.lhs), node), 4217 node); 4218 case AST_NODE_NEGATION: 4219 return rvalue(gz, rl, 4220 addUnNode(gz, ZIR_INST_NEGATE, expr(gz, scope, nd.lhs), node), 4221 node); 4222 case AST_NODE_NEGATION_WRAP: 4223 return rvalue(gz, rl, 4224 addUnNode(gz, ZIR_INST_NEGATE_WRAP, expr(gz, scope, nd.lhs), node), 4225 node); 4226 // deref (AstGen.zig:942-951). 4227 case AST_NODE_DEREF: { 4228 uint32_t lhs = expr(gz, scope, nd.lhs); 4229 addUnNode(gz, ZIR_INST_VALIDATE_DEREF, lhs, node); 4230 if (RL_IS_REF(rl)) 4231 return lhs; 4232 return rvalue(gz, rl, addUnNode(gz, ZIR_INST_LOAD, lhs, node), node); 4233 } 4234 // optional_type (AstGen.zig:961-964). 4235 case AST_NODE_OPTIONAL_TYPE: 4236 return rvalue(gz, rl, 4237 addUnNode( 4238 gz, ZIR_INST_OPTIONAL_TYPE, typeExpr(gz, scope, nd.lhs), node), 4239 node); 4240 // unwrap_optional (AstGen.zig:966-985). 4241 case AST_NODE_UNWRAP_OPTIONAL: { 4242 uint32_t lhs = expr(gz, scope, nd.lhs); 4243 advanceSourceCursorToMainToken(ag, gz, node); 4244 uint32_t saved_line = ag->source_line - gz->decl_line; 4245 uint32_t saved_col = ag->source_column; 4246 emitDbgStmt(gz, saved_line, saved_col); 4247 return rvalue(gz, rl, 4248 addUnNode(gz, ZIR_INST_OPTIONAL_PAYLOAD_SAFE, lhs, node), node); 4249 } 4250 // error_union type (AstGen.zig:788-797). 4251 case AST_NODE_ERROR_UNION: { 4252 uint32_t lhs = typeExpr(gz, scope, nd.lhs); 4253 uint32_t rhs = typeExpr(gz, scope, nd.rhs); 4254 return rvalue(gz, rl, 4255 addPlNodeBin(gz, ZIR_INST_ERROR_UNION_TYPE, node, lhs, rhs), node); 4256 } 4257 // char_literal (AstGen.zig:8662-8675). 4258 case AST_NODE_CHAR_LITERAL: { 4259 uint32_t main_tok = ag->tree->nodes.main_tokens[node]; 4260 uint32_t tok_start = ag->tree->tokens.starts[main_tok]; 4261 const char* src = ag->tree->source; 4262 uint32_t ci = tok_start + 1; // skip opening quote 4263 uint64_t char_val; 4264 if (src[ci] == '\\') { 4265 // Escape sequence (AstGen.zig:8668-8675). 4266 ci++; 4267 switch (src[ci]) { 4268 case 'n': 4269 char_val = '\n'; 4270 break; 4271 case 'r': 4272 char_val = '\r'; 4273 break; 4274 case 't': 4275 char_val = '\t'; 4276 break; 4277 case '\\': 4278 char_val = '\\'; 4279 break; 4280 case '\'': 4281 char_val = '\''; 4282 break; 4283 case '"': 4284 char_val = '"'; 4285 break; 4286 case 'x': { 4287 // \xNN hex escape. 4288 uint8_t val = 0; 4289 for (int k = 0; k < 2; k++) { 4290 ci++; 4291 char c = src[ci]; 4292 if (c >= '0' && c <= '9') 4293 val = (uint8_t)(val * 16 + (uint8_t)(c - '0')); 4294 else if (c >= 'a' && c <= 'f') 4295 val = (uint8_t)(val * 16 + 10 + (uint8_t)(c - 'a')); 4296 else if (c >= 'A' && c <= 'F') 4297 val = (uint8_t)(val * 16 + 10 + (uint8_t)(c - 'A')); 4298 } 4299 char_val = val; 4300 break; 4301 } 4302 case 'u': { 4303 // \u{NNNNNN} unicode escape (string_literal.zig:194-231). 4304 // Skip past '{'. 4305 ci++; 4306 uint32_t codepoint = 0; 4307 while (true) { 4308 ci++; 4309 char c = src[ci]; 4310 if (c >= '0' && c <= '9') 4311 codepoint = codepoint * 16 + (uint32_t)(c - '0'); 4312 else if (c >= 'a' && c <= 'f') 4313 codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'a'); 4314 else if (c >= 'A' && c <= 'F') 4315 codepoint = codepoint * 16 + 10 + (uint32_t)(c - 'A'); 4316 else 4317 break; // Must be '}'. 4318 } 4319 char_val = codepoint; 4320 break; 4321 } 4322 default: 4323 char_val = (uint8_t)src[ci]; 4324 break; 4325 } 4326 } else { 4327 char_val = (uint64_t)(uint8_t)src[ci]; 4328 } 4329 return rvalue(gz, rl, addInt(gz, char_val), node); 4330 } 4331 // arrayAccess (AstGen.zig:6192-6221). 4332 case AST_NODE_ARRAY_ACCESS: { 4333 if (RL_IS_REF(rl)) { 4334 uint32_t lhs = exprRl(gz, scope, RL_REF_VAL, nd.lhs); 4335 advanceSourceCursorToMainToken(ag, gz, node); 4336 uint32_t saved_line = ag->source_line - gz->decl_line; 4337 uint32_t saved_col = ag->source_column; 4338 uint32_t rhs = expr(gz, scope, nd.rhs); 4339 emitDbgStmt(gz, saved_line, saved_col); 4340 return addPlNodeBin(gz, ZIR_INST_ELEM_PTR_NODE, node, lhs, rhs); 4341 } 4342 uint32_t lhs = expr(gz, scope, nd.lhs); 4343 advanceSourceCursorToMainToken(ag, gz, node); 4344 uint32_t saved_line = ag->source_line - gz->decl_line; 4345 uint32_t saved_col = ag->source_column; 4346 uint32_t rhs = expr(gz, scope, nd.rhs); 4347 emitDbgStmt(gz, saved_line, saved_col); 4348 return rvalue(gz, rl, 4349 addPlNodeBin(gz, ZIR_INST_ELEM_VAL_NODE, node, lhs, rhs), node); 4350 } 4351 // slice (AstGen.zig:882-939). 4352 case AST_NODE_SLICE_OPEN: { 4353 // (AstGen.zig:908-937). 4354 uint32_t lhs = exprRl(gz, scope, RL_REF_VAL, nd.lhs); 4355 advanceSourceCursorToMainToken(ag, gz, node); 4356 uint32_t saved_line = ag->source_line - gz->decl_line; 4357 uint32_t saved_col = ag->source_column; 4358 ResultLoc usize_rl = { .tag = RL_COERCED_TY, 4359 .data = ZIR_REF_USIZE_TYPE, 4360 .src_node = 0, 4361 .ctx = RI_CTX_NONE }; 4362 uint32_t start = exprRl(gz, scope, usize_rl, nd.rhs); 4363 emitDbgStmt(gz, saved_line, saved_col); 4364 return rvalue(gz, rl, 4365 addPlNodeBin(gz, ZIR_INST_SLICE_START, node, lhs, start), node); 4366 } 4367 case AST_NODE_SLICE: { 4368 // Slice[rhs]: { start, end } (AstGen.zig:908-937). 4369 const Ast* stree = ag->tree; 4370 uint32_t lhs = exprRl(gz, scope, RL_REF_VAL, nd.lhs); 4371 advanceSourceCursorToMainToken(ag, gz, node); 4372 uint32_t saved_line = ag->source_line - gz->decl_line; 4373 uint32_t saved_col = ag->source_column; 4374 uint32_t start_node = stree->extra_data.arr[nd.rhs]; 4375 uint32_t end_node = stree->extra_data.arr[nd.rhs + 1]; 4376 ResultLoc usize_rl = { .tag = RL_COERCED_TY, 4377 .data = ZIR_REF_USIZE_TYPE, 4378 .src_node = 0, 4379 .ctx = RI_CTX_NONE }; 4380 uint32_t start_ref = exprRl(gz, scope, usize_rl, start_node); 4381 uint32_t end_ref = exprRl(gz, scope, usize_rl, end_node); 4382 emitDbgStmt(gz, saved_line, saved_col); 4383 ensureExtraCapacity(ag, 3); 4384 uint32_t payload_index = ag->extra_len; 4385 ag->extra[ag->extra_len++] = lhs; 4386 ag->extra[ag->extra_len++] = start_ref; 4387 ag->extra[ag->extra_len++] = end_ref; 4388 ZirInstData data; 4389 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 4390 data.pl_node.payload_index = payload_index; 4391 return rvalue( 4392 gz, rl, addInstruction(gz, ZIR_INST_SLICE_END, data), node); 4393 } 4394 case AST_NODE_SLICE_SENTINEL: { 4395 // SliceSentinel[rhs]: { start, end, sentinel } 4396 // (AstGen.zig:908-925). 4397 const Ast* stree = ag->tree; 4398 uint32_t lhs = exprRl(gz, scope, RL_REF_VAL, nd.lhs); 4399 advanceSourceCursorToMainToken(ag, gz, node); 4400 uint32_t saved_line = ag->source_line - gz->decl_line; 4401 uint32_t saved_col = ag->source_column; 4402 uint32_t start_node = stree->extra_data.arr[nd.rhs]; 4403 uint32_t end_node = stree->extra_data.arr[nd.rhs + 1]; 4404 uint32_t sentinel_node = stree->extra_data.arr[nd.rhs + 2]; 4405 // start/end coerced to usize (AstGen.zig:911-912). 4406 ResultLoc usize_rl = { .tag = RL_COERCED_TY, 4407 .data = ZIR_REF_USIZE_TYPE, 4408 .src_node = 0, 4409 .ctx = RI_CTX_NONE }; 4410 uint32_t start_ref = exprRl(gz, scope, usize_rl, start_node); 4411 uint32_t end_ref = (end_node != 0) 4412 ? exprRl(gz, scope, usize_rl, end_node) 4413 : ZIR_REF_NONE; 4414 // sentinel: create slice_sentinel_ty and coerce (AstGen.zig:913-916). 4415 uint32_t sentinel_ty 4416 = addUnNode(gz, ZIR_INST_SLICE_SENTINEL_TY, lhs, node); 4417 ResultLoc sent_rl = { .tag = RL_COERCED_TY, 4418 .data = sentinel_ty, 4419 .src_node = 0, 4420 .ctx = RI_CTX_NONE }; 4421 uint32_t sentinel_ref = exprRl(gz, scope, sent_rl, sentinel_node); 4422 emitDbgStmt(gz, saved_line, saved_col); 4423 ensureExtraCapacity(ag, 4); 4424 uint32_t payload_index = ag->extra_len; 4425 ag->extra[ag->extra_len++] = lhs; 4426 ag->extra[ag->extra_len++] = start_ref; 4427 ag->extra[ag->extra_len++] = end_ref; 4428 ag->extra[ag->extra_len++] = sentinel_ref; 4429 ZirInstData data; 4430 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 4431 data.pl_node.payload_index = payload_index; 4432 return rvalue( 4433 gz, rl, addInstruction(gz, ZIR_INST_SLICE_SENTINEL, data), node); 4434 } 4435 // orelse (AstGen.zig:6031-6142). 4436 case AST_NODE_ORELSE: 4437 return orelseCatchExpr(gz, scope, rl, node, false); 4438 // catch (AstGen.zig:6031-6142). 4439 case AST_NODE_CATCH: 4440 return orelseCatchExpr(gz, scope, rl, node, true); 4441 // Block expressions (AstGen.zig:984-992). 4442 case AST_NODE_BLOCK_TWO: 4443 case AST_NODE_BLOCK_TWO_SEMICOLON: 4444 case AST_NODE_BLOCK: 4445 case AST_NODE_BLOCK_SEMICOLON: 4446 return rvalue(gz, rl, blockExprExpr(gz, scope, rl, node), node); 4447 // Anonymous array init (AstGen.zig:1119-1127). 4448 case AST_NODE_ARRAY_INIT_DOT_TWO: 4449 case AST_NODE_ARRAY_INIT_DOT_TWO_COMMA: 4450 case AST_NODE_ARRAY_INIT_DOT: 4451 case AST_NODE_ARRAY_INIT_DOT_COMMA: 4452 return arrayInitDotExpr(gz, scope, rl, node); 4453 // if (AstGen.zig:1013-1024). 4454 case AST_NODE_IF_SIMPLE: 4455 case AST_NODE_IF: 4456 return ifExpr(gz, scope, rlBr(rl), node); 4457 // for (AstGen.zig:1043-1060). 4458 case AST_NODE_FOR_SIMPLE: 4459 case AST_NODE_FOR: 4460 return rvalue(gz, rl, forExpr(gz, scope, node, false), node); 4461 // Merge error sets (AstGen.zig:788-797). 4462 case AST_NODE_MERGE_ERROR_SETS: { 4463 uint32_t lhs = typeExpr(gz, scope, nd.lhs); 4464 uint32_t rhs = typeExpr(gz, scope, nd.rhs); 4465 return rvalue(gz, rl, 4466 addPlNodeBin(gz, ZIR_INST_MERGE_ERROR_SETS, node, lhs, rhs), node); 4467 } 4468 // Wrapping arithmetic. 4469 case AST_NODE_ADD_WRAP: 4470 return rvalue( 4471 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_ADDWRAP), node); 4472 case AST_NODE_SUB_WRAP: 4473 return rvalue( 4474 gz, rl, simpleBinOp(gz, scope, node, ZIR_INST_SUBWRAP), node); 4475 // break (AstGen.zig:2150-2237). 4476 case AST_NODE_BREAK: { 4477 uint32_t opt_break_label = nd.lhs; // UINT32_MAX = none 4478 uint32_t opt_rhs = nd.rhs; // 0 = none 4479 4480 // Walk scope chain to find target block (AstGen.zig:2157-2187). 4481 for (Scope* s = scope; s != NULL;) { 4482 if (s->tag == SCOPE_GEN_ZIR) { 4483 GenZir* block_gz = (GenZir*)s; 4484 uint32_t block_inst = UINT32_MAX; 4485 if (opt_break_label != UINT32_MAX) { 4486 // Labeled break: check label on GenZir. 4487 // Use direct source text comparison, not identAsString, 4488 // to avoid adding label names to string_bytes 4489 // (AstGen.zig:2176 uses tokenIdentEql). 4490 if (block_gz->label_token != UINT32_MAX 4491 && tokenIdentEql(ag->tree, opt_break_label, 4492 block_gz->label_token)) { 4493 block_inst = block_gz->label_block_inst; 4494 } 4495 } else { 4496 // Unlabeled break: check break_block. 4497 if (block_gz->break_block != UINT32_MAX) 4498 block_inst = block_gz->break_block; 4499 } 4500 if (block_inst != UINT32_MAX) { 4501 // Found target (AstGen.zig:2188-2228). 4502 ZirInstTag break_tag = block_gz->is_inline 4503 ? ZIR_INST_BREAK_INLINE 4504 : ZIR_INST_BREAK; 4505 if (opt_rhs == 0) { 4506 // Void break (AstGen.zig:2195-2206). 4507 rvalue(gz, block_gz->break_result_info, 4508 ZIR_REF_VOID_VALUE, node); 4509 genDefers(gz, s, scope, DEFER_NORMAL_ONLY); 4510 if (!block_gz->is_comptime) { 4511 ZirInstData rdata; 4512 rdata.un_node.operand 4513 = block_inst + ZIR_REF_START_INDEX; 4514 rdata.un_node.src_node 4515 = (int32_t)node - (int32_t)gz->decl_node_index; 4516 addInstruction(gz, 4517 ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, 4518 rdata); 4519 } 4520 addBreak(gz, break_tag, block_inst, ZIR_REF_VOID_VALUE, 4521 AST_NODE_OFFSET_NONE); 4522 } else { 4523 // Value break (AstGen.zig:2208-2228). 4524 uint32_t operand = exprRl( 4525 gz, scope, block_gz->break_result_info, opt_rhs); 4526 genDefers(gz, s, scope, DEFER_NORMAL_ONLY); 4527 if (!block_gz->is_comptime) 4528 restoreErrRetIndex(gz, block_inst, 4529 block_gz->break_result_info, opt_rhs, operand); 4530 switch (block_gz->break_result_info.tag) { 4531 case RL_PTR: 4532 case RL_DISCARD: 4533 addBreak(gz, break_tag, block_inst, 4534 ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); 4535 break; 4536 default: 4537 addBreak(gz, break_tag, block_inst, operand, 4538 (int32_t)opt_rhs 4539 - (int32_t)gz->decl_node_index); 4540 break; 4541 } 4542 } 4543 return ZIR_REF_UNREACHABLE_VALUE; 4544 } 4545 s = block_gz->parent; 4546 } else if (s->tag == SCOPE_LOCAL_VAL) { 4547 s = ((ScopeLocalVal*)s)->parent; 4548 } else if (s->tag == SCOPE_LOCAL_PTR) { 4549 s = ((ScopeLocalPtr*)s)->parent; 4550 } else if (s->tag == SCOPE_DEFER_NORMAL 4551 || s->tag == SCOPE_DEFER_ERROR) { 4552 s = ((ScopeDefer*)s)->parent; 4553 } else if (s->tag == SCOPE_LABEL) { 4554 s = ((ScopeLabel*)s)->parent; 4555 } else { 4556 break; 4557 } 4558 } 4559 SET_ERROR(ag); 4560 return ZIR_REF_UNREACHABLE_VALUE; 4561 } 4562 // continue (AstGen.zig:2246-2340). 4563 case AST_NODE_CONTINUE: { 4564 // Walk scope chain to find GenZir with continue_block. 4565 for (Scope* s = scope; s != NULL;) { 4566 if (s->tag == SCOPE_GEN_ZIR) { 4567 GenZir* gz2 = (GenZir*)s; 4568 if (gz2->continue_block != UINT32_MAX) { 4569 genDefers(gz, s, scope, DEFER_NORMAL_ONLY); 4570 ZirInstTag break_tag = gz2->is_inline 4571 ? ZIR_INST_BREAK_INLINE 4572 : ZIR_INST_BREAK; 4573 if (break_tag == ZIR_INST_BREAK_INLINE) { 4574 // AstGen.zig:2328-2330. 4575 addUnNode(gz, ZIR_INST_CHECK_COMPTIME_CONTROL_FLOW, 4576 gz2->continue_block + ZIR_REF_START_INDEX, node); 4577 } 4578 // Restore error return index (AstGen.zig:2333-2334). 4579 if (!gz2->is_comptime) { 4580 ZirInstData rdata; 4581 rdata.un_node.operand 4582 = gz2->continue_block + ZIR_REF_START_INDEX; 4583 rdata.un_node.src_node 4584 = (int32_t)node - (int32_t)gz->decl_node_index; 4585 addInstruction(gz, 4586 ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, 4587 rdata); 4588 } 4589 addBreak(gz, break_tag, gz2->continue_block, 4590 ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); 4591 return ZIR_REF_UNREACHABLE_VALUE; 4592 } 4593 s = gz2->parent; 4594 } else if (s->tag == SCOPE_LOCAL_VAL) { 4595 s = ((ScopeLocalVal*)s)->parent; 4596 } else if (s->tag == SCOPE_LOCAL_PTR) { 4597 s = ((ScopeLocalPtr*)s)->parent; 4598 } else if (s->tag == SCOPE_DEFER_NORMAL 4599 || s->tag == SCOPE_DEFER_ERROR) { 4600 s = ((ScopeDefer*)s)->parent; 4601 } else if (s->tag == SCOPE_LABEL) { 4602 s = ((ScopeLabel*)s)->parent; 4603 } else { 4604 break; 4605 } 4606 } 4607 SET_ERROR(ag); 4608 return ZIR_REF_UNREACHABLE_VALUE; 4609 } 4610 // comptime (AstGen.zig:1104-1105). 4611 case AST_NODE_COMPTIME: { 4612 // comptimeExprAst / comptimeExpr2 (AstGen.zig:2104, 1982). 4613 uint32_t body_node = nd.lhs; 4614 4615 // If already comptime, just pass through (AstGen.zig:1990-1992). 4616 if (gz->is_comptime) 4617 return exprRl(gz, scope, rl, body_node); 4618 4619 // Create comptime block (AstGen.zig:2078-2098). 4620 uint32_t block_inst 4621 = makeBlockInst(ag, ZIR_INST_BLOCK_COMPTIME, gz, node); 4622 GenZir block_scope = makeSubBlock(gz, scope); 4623 block_scope.is_comptime = true; 4624 4625 // Transform RL to type-only (AstGen.zig:2084-2090). 4626 // Runtime-to-comptime boundary: can't pass runtime pointers. 4627 ResultLoc ty_only_rl; 4628 uint32_t res_ty = rlResultType(gz, rl, node); 4629 if (res_ty != 0) 4630 ty_only_rl = (ResultLoc) { .tag = RL_COERCED_TY, 4631 .data = res_ty, 4632 .src_node = 0, 4633 .ctx = rl.ctx }; 4634 else 4635 ty_only_rl = (ResultLoc) { 4636 .tag = RL_NONE, .data = 0, .src_node = 0, .ctx = rl.ctx 4637 }; 4638 4639 uint32_t result = exprRl(&block_scope, scope, ty_only_rl, body_node); 4640 addBreak(&block_scope, ZIR_INST_BREAK_INLINE, block_inst, result, 4641 AST_NODE_OFFSET_NONE); 4642 setBlockComptimeBody( 4643 ag, &block_scope, block_inst, COMPTIME_REASON_COMPTIME_KEYWORD); 4644 gzAppendInstruction(gz, block_inst); 4645 4646 // Apply rvalue to handle RL_PTR etc (AstGen.zig:2098). 4647 return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node); 4648 } 4649 // switch (AstGen.zig:1072-1078). 4650 case AST_NODE_SWITCH: 4651 case AST_NODE_SWITCH_COMMA: 4652 return switchExpr(gz, scope, rlBr(rl), node); 4653 // while (AstGen.zig:1037-1042). 4654 case AST_NODE_WHILE_SIMPLE: 4655 case AST_NODE_WHILE_CONT: 4656 case AST_NODE_WHILE: 4657 return rvalue(gz, rl, whileExpr(gz, scope, node, false), node); 4658 // error_value (AstGen.zig:1005-1010). 4659 case AST_NODE_ERROR_VALUE: { 4660 uint32_t error_token = nd.rhs; 4661 uint32_t str = identAsString(ag, error_token); 4662 return rvalue(gz, rl, 4663 addStrTok(gz, ZIR_INST_ERROR_VALUE, str, error_token), node); 4664 } 4665 // error_set_decl (AstGen.zig:5905-5955). 4666 case AST_NODE_ERROR_SET_DECL: { 4667 AstData esd = ag->tree->nodes.datas[node]; 4668 uint32_t lbrace = esd.lhs; 4669 uint32_t rbrace = esd.rhs; 4670 // Reserve 1 extra word for ErrorSetDecl.fields_len. 4671 ensureExtraCapacity(ag, 1 + (rbrace - lbrace)); 4672 uint32_t payload_index = ag->extra_len; 4673 ag->extra_len++; // placeholder for fields_len 4674 uint32_t fields_len = 0; 4675 for (uint32_t tok = lbrace + 1; tok < rbrace; tok++) { 4676 TokenizerTag ttag = ag->tree->tokens.tags[tok]; 4677 if (ttag == TOKEN_DOC_COMMENT || ttag == TOKEN_COMMA) 4678 continue; 4679 if (ttag == TOKEN_IDENTIFIER) { 4680 uint32_t str_index = identAsString(ag, tok); 4681 ensureExtraCapacity(ag, 1); 4682 ag->extra[ag->extra_len++] = str_index; 4683 fields_len++; 4684 } 4685 } 4686 ag->extra[payload_index] = fields_len; 4687 return rvalue(gz, rl, 4688 addPlNodePayloadIndex( 4689 gz, ZIR_INST_ERROR_SET_DECL, node, payload_index), 4690 node); 4691 } 4692 // assign in expr context (AstGen.zig:1011-1014). 4693 case AST_NODE_ASSIGN: 4694 assignStmt(gz, scope, node); 4695 return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); 4696 // Compound assignment operators (AstGen.zig:685-744). 4697 case AST_NODE_ASSIGN_ADD: 4698 assignOp(gz, scope, node, ZIR_INST_ADD); 4699 return ZIR_REF_VOID_VALUE; 4700 case AST_NODE_ASSIGN_SUB: 4701 assignOp(gz, scope, node, ZIR_INST_SUB); 4702 return ZIR_REF_VOID_VALUE; 4703 case AST_NODE_ASSIGN_MUL: 4704 assignOp(gz, scope, node, ZIR_INST_MUL); 4705 return ZIR_REF_VOID_VALUE; 4706 case AST_NODE_ASSIGN_DIV: 4707 assignOp(gz, scope, node, ZIR_INST_DIV); 4708 return ZIR_REF_VOID_VALUE; 4709 case AST_NODE_ASSIGN_MOD: 4710 assignOp(gz, scope, node, ZIR_INST_MOD_REM); 4711 return ZIR_REF_VOID_VALUE; 4712 case AST_NODE_ASSIGN_BIT_AND: 4713 assignOp(gz, scope, node, ZIR_INST_BIT_AND); 4714 return ZIR_REF_VOID_VALUE; 4715 case AST_NODE_ASSIGN_BIT_OR: 4716 assignOp(gz, scope, node, ZIR_INST_BIT_OR); 4717 return ZIR_REF_VOID_VALUE; 4718 case AST_NODE_ASSIGN_BIT_XOR: 4719 assignOp(gz, scope, node, ZIR_INST_XOR); 4720 return ZIR_REF_VOID_VALUE; 4721 case AST_NODE_ASSIGN_ADD_WRAP: 4722 assignOp(gz, scope, node, ZIR_INST_ADDWRAP); 4723 return ZIR_REF_VOID_VALUE; 4724 case AST_NODE_ASSIGN_SUB_WRAP: 4725 assignOp(gz, scope, node, ZIR_INST_SUBWRAP); 4726 return ZIR_REF_VOID_VALUE; 4727 case AST_NODE_ASSIGN_MUL_WRAP: 4728 assignOp(gz, scope, node, ZIR_INST_MULWRAP); 4729 return ZIR_REF_VOID_VALUE; 4730 case AST_NODE_ASSIGN_ADD_SAT: 4731 assignOp(gz, scope, node, ZIR_INST_ADD_SAT); 4732 return ZIR_REF_VOID_VALUE; 4733 case AST_NODE_ASSIGN_SUB_SAT: 4734 assignOp(gz, scope, node, ZIR_INST_SUB_SAT); 4735 return ZIR_REF_VOID_VALUE; 4736 case AST_NODE_ASSIGN_MUL_SAT: 4737 assignOp(gz, scope, node, ZIR_INST_MUL_SAT); 4738 return ZIR_REF_VOID_VALUE; 4739 default: 4740 SET_ERROR(ag); 4741 return ZIR_REF_VOID_VALUE; 4742 } 4743 } 4744 4745 static uint32_t expr(GenZir* gz, Scope* scope, uint32_t node) { 4746 return exprRl(gz, scope, RL_NONE_VAL, node); 4747 } 4748 4749 // --- blockExprExpr (AstGen.zig:2388-2536) --- 4750 // Handles block expressions (labeled and unlabeled). 4751 // Unlabeled blocks just execute statements and return void. 4752 // Labeled blocks (blk: { ... break :blk val; }) need a block instruction. 4753 4754 static uint32_t blockExprExpr( 4755 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 4756 (void)rl; 4757 AstGenCtx* ag = gz->astgen; 4758 const Ast* tree = ag->tree; 4759 AstNodeTag tag = tree->nodes.tags[node]; 4760 AstData nd = tree->nodes.datas[node]; 4761 4762 // Extract statements. 4763 uint32_t stmt_buf[2]; 4764 const uint32_t* statements = NULL; 4765 uint32_t stmt_count = 0; 4766 4767 switch (tag) { 4768 case AST_NODE_BLOCK_TWO: 4769 case AST_NODE_BLOCK_TWO_SEMICOLON: { 4770 uint32_t idx = 0; 4771 if (nd.lhs != 0) 4772 stmt_buf[idx++] = nd.lhs; 4773 if (nd.rhs != 0) 4774 stmt_buf[idx++] = nd.rhs; 4775 statements = stmt_buf; 4776 stmt_count = idx; 4777 break; 4778 } 4779 case AST_NODE_BLOCK: 4780 case AST_NODE_BLOCK_SEMICOLON: { 4781 uint32_t start = nd.lhs; 4782 uint32_t end = nd.rhs; 4783 statements = tree->extra_data.arr + start; 4784 stmt_count = end - start; 4785 break; 4786 } 4787 default: 4788 SET_ERROR(ag); 4789 return ZIR_REF_VOID_VALUE; 4790 } 4791 4792 // Check if labeled (AstGen.zig:2397-2402). 4793 // A labeled block has: identifier colon before the lbrace. 4794 uint32_t lbrace = tree->nodes.main_tokens[node]; 4795 bool is_labeled 4796 = (lbrace >= 2 && tree->tokens.tags[lbrace - 1] == TOKEN_COLON 4797 && tree->tokens.tags[lbrace - 2] == TOKEN_IDENTIFIER); 4798 4799 if (!is_labeled) { 4800 if (!gz->is_comptime) { 4801 // Non-comptime unlabeled block (AstGen.zig:2404-2425). 4802 // Create block_inst FIRST, add to gz, then process body. 4803 uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); 4804 gzAppendInstruction(gz, block_inst); 4805 4806 GenZir block_scope = makeSubBlock(gz, scope); 4807 blockExprStmts( 4808 &block_scope, &block_scope.base, statements, stmt_count); 4809 4810 if (!endsWithNoReturn(&block_scope)) { 4811 // restore_err_ret_index on gz (AstGen.zig:2420). 4812 ZirInstData rdata; 4813 rdata.un_node.operand = block_inst + ZIR_REF_START_INDEX; 4814 rdata.un_node.src_node 4815 = (int32_t)node - (int32_t)gz->decl_node_index; 4816 addInstruction( 4817 gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); 4818 // break on block_scope (AstGen.zig:2422). 4819 addBreak(&block_scope, ZIR_INST_BREAK, block_inst, 4820 ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); 4821 } 4822 setBlockBody(ag, &block_scope, block_inst); 4823 } else { 4824 // Comptime unlabeled block: inline statements 4825 // (AstGen.zig:2426-2429). 4826 GenZir sub_gz = makeSubBlock(gz, scope); 4827 blockExprStmts(&sub_gz, &sub_gz.base, statements, stmt_count); 4828 } 4829 return ZIR_REF_VOID_VALUE; 4830 } 4831 4832 // Labeled block (AstGen.zig:2466-2536). 4833 // Note: upstream blockExpr always passes force_comptime=false. 4834 uint32_t label_token = lbrace - 2; 4835 4836 // Compute break result info (AstGen.zig:2484-2492). 4837 bool need_rl = nodesNeedRlContains(ag, node); 4838 ResultLoc break_ri = breakResultInfo(gz, rl, node, need_rl); 4839 bool need_result_rvalue = (break_ri.tag != rl.tag); 4840 4841 // Reserve the block instruction (AstGen.zig:2500-2501). 4842 uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); 4843 gzAppendInstruction(gz, block_inst); 4844 4845 GenZir block_scope = makeSubBlock(gz, scope); 4846 // Set label on block_scope (AstGen.zig:2504-2508). 4847 block_scope.label_token = label_token; 4848 block_scope.label_block_inst = block_inst; 4849 block_scope.break_result_info = break_ri; 4850 4851 // Process statements (AstGen.zig:2512). 4852 blockExprStmts(&block_scope, &block_scope.base, statements, stmt_count); 4853 4854 if (!endsWithNoReturn(&block_scope)) { 4855 // Emit restore_err_ret_index (AstGen.zig:2515). 4856 ZirInstData rdata; 4857 rdata.un_node.operand = block_inst + ZIR_REF_START_INDEX; 4858 rdata.un_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 4859 addInstruction( 4860 gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); 4861 // rvalue + break (AstGen.zig:2516-2518). 4862 uint32_t result = rvalue( 4863 gz, block_scope.break_result_info, ZIR_REF_VOID_VALUE, node); 4864 addBreak(&block_scope, ZIR_INST_BREAK, block_inst, result, 4865 AST_NODE_OFFSET_NONE); 4866 } 4867 4868 setBlockBody(ag, &block_scope, block_inst); 4869 4870 // AstGen.zig:2531-2534. 4871 if (need_result_rvalue) 4872 return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node); 4873 return block_inst + ZIR_REF_START_INDEX; 4874 } 4875 4876 // --- arrayInitDotExpr (AstGen.zig:1576-1595) --- 4877 // Handles anonymous array init: `.{a, b, c}`. 4878 // Emits array_init_anon instruction with MultiOp payload. 4879 4880 static uint32_t arrayInitDotExpr( 4881 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 4882 AstGenCtx* ag = gz->astgen; 4883 const Ast* tree = ag->tree; 4884 AstNodeTag tag = tree->nodes.tags[node]; 4885 AstData nd = tree->nodes.datas[node]; 4886 4887 // Extract elements. 4888 uint32_t elem_buf[2]; 4889 const uint32_t* elements = NULL; 4890 uint32_t elem_count = 0; 4891 4892 switch (tag) { 4893 case AST_NODE_ARRAY_INIT_DOT_TWO: 4894 case AST_NODE_ARRAY_INIT_DOT_TWO_COMMA: { 4895 uint32_t idx = 0; 4896 if (nd.lhs != 0) 4897 elem_buf[idx++] = nd.lhs; 4898 if (nd.rhs != 0) 4899 elem_buf[idx++] = nd.rhs; 4900 elements = elem_buf; 4901 elem_count = idx; 4902 break; 4903 } 4904 case AST_NODE_ARRAY_INIT_DOT: 4905 case AST_NODE_ARRAY_INIT_DOT_COMMA: { 4906 uint32_t start = nd.lhs; 4907 uint32_t end = nd.rhs; 4908 elements = tree->extra_data.arr + start; 4909 elem_count = end - start; 4910 break; 4911 } 4912 default: 4913 SET_ERROR(ag); 4914 return ZIR_REF_VOID_VALUE; 4915 } 4916 4917 // Dispatch based on RL (AstGen.zig:1515-1572). 4918 switch (rl.tag) { 4919 case RL_NONE: { 4920 // arrayInitExprAnon (AstGen.zig:1576-1595). 4921 ensureExtraCapacity(ag, 1 + elem_count); 4922 uint32_t payload_index = ag->extra_len; 4923 ag->extra[ag->extra_len++] = elem_count; 4924 uint32_t extra_start = ag->extra_len; 4925 ag->extra_len += elem_count; 4926 for (uint32_t i = 0; i < elem_count; i++) { 4927 uint32_t elem_ref = expr(gz, scope, elements[i]); 4928 ag->extra[extra_start + i] = elem_ref; 4929 } 4930 return addPlNodePayloadIndex( 4931 gz, ZIR_INST_ARRAY_INIT_ANON, node, payload_index); 4932 } 4933 case RL_TY: 4934 case RL_COERCED_TY: { 4935 // validate_array_init_result_ty + arrayInitExprTyped 4936 // (AstGen.zig:1534-1539). 4937 uint32_t result_ty = rl.data; 4938 // Emit ArrayInit { ty, init_count } payload for 4939 // validate_array_init_result_ty. 4940 ensureExtraCapacity(ag, 2); 4941 uint32_t val_payload = ag->extra_len; 4942 ag->extra[ag->extra_len++] = result_ty; 4943 ag->extra[ag->extra_len++] = elem_count; 4944 addPlNodePayloadIndex( 4945 gz, ZIR_INST_VALIDATE_ARRAY_INIT_RESULT_TY, node, val_payload); 4946 4947 // arrayInitExprTyped (AstGen.zig:1598-1642) with elem_ty=none. 4948 uint32_t operands_len = elem_count + 1; // +1 for type 4949 ensureExtraCapacity(ag, 1 + operands_len); 4950 uint32_t payload_index = ag->extra_len; 4951 ag->extra[ag->extra_len++] = operands_len; 4952 ag->extra[ag->extra_len++] = result_ty; 4953 uint32_t extra_start = ag->extra_len; 4954 ag->extra_len += elem_count; 4955 for (uint32_t i = 0; i < elem_count; i++) { 4956 // array_init_elem_type uses bin data (AstGen.zig:1626-1632). 4957 uint32_t elem_ty 4958 = addBin(gz, ZIR_INST_ARRAY_INIT_ELEM_TYPE, result_ty, i); 4959 ResultLoc elem_rl 4960 = { .tag = RL_COERCED_TY, .data = elem_ty, .src_node = 0 }; 4961 uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]); 4962 ag->extra[extra_start + i] = elem_ref; 4963 } 4964 return addPlNodePayloadIndex( 4965 gz, ZIR_INST_ARRAY_INIT, node, payload_index); 4966 } 4967 case RL_INFERRED_PTR: { 4968 // arrayInitExprAnon + rvalue (AstGen.zig:1545-1551). 4969 ensureExtraCapacity(ag, 1 + elem_count); 4970 uint32_t payload_index = ag->extra_len; 4971 ag->extra[ag->extra_len++] = elem_count; 4972 uint32_t extra_start = ag->extra_len; 4973 ag->extra_len += elem_count; 4974 for (uint32_t i = 0; i < elem_count; i++) { 4975 uint32_t elem_ref = expr(gz, scope, elements[i]); 4976 ag->extra[extra_start + i] = elem_ref; 4977 } 4978 uint32_t result = addPlNodePayloadIndex( 4979 gz, ZIR_INST_ARRAY_INIT_ANON, node, payload_index); 4980 return rvalue(gz, rl, result, node); 4981 } 4982 case RL_DISCARD: { 4983 // Evaluate and discard each element (AstGen.zig:1517-1522). 4984 for (uint32_t i = 0; i < elem_count; i++) { 4985 exprRl(gz, scope, RL_DISCARD_VAL, elements[i]); 4986 } 4987 return ZIR_REF_VOID_VALUE; 4988 } 4989 case RL_REF: { 4990 // arrayInitExprAnon + ref (AstGen.zig:1523-1526). 4991 ensureExtraCapacity(ag, 1 + elem_count); 4992 uint32_t payload_index = ag->extra_len; 4993 ag->extra[ag->extra_len++] = elem_count; 4994 uint32_t extra_start = ag->extra_len; 4995 ag->extra_len += elem_count; 4996 for (uint32_t i = 0; i < elem_count; i++) { 4997 uint32_t elem_ref = expr(gz, scope, elements[i]); 4998 ag->extra[extra_start + i] = elem_ref; 4999 } 5000 uint32_t result = addPlNodePayloadIndex( 5001 gz, ZIR_INST_ARRAY_INIT_ANON, node, payload_index); 5002 return rvalue(gz, rl, result, node); 5003 } 5004 case RL_REF_COERCED_TY: { 5005 // validate_array_init_ref_ty + arrayInitExprTyped 5006 // (AstGen.zig:1527-1532). 5007 uint32_t ptr_ty_inst = rl.data; 5008 ensureExtraCapacity(ag, 2); 5009 uint32_t val_payload = ag->extra_len; 5010 ag->extra[ag->extra_len++] = ptr_ty_inst; 5011 ag->extra[ag->extra_len++] = elem_count; 5012 uint32_t dest_arr_ty_inst = addPlNodePayloadIndex( 5013 gz, ZIR_INST_VALIDATE_ARRAY_INIT_REF_TY, node, val_payload); 5014 5015 // arrayInitExprTyped with elem_ty=none, is_ref=true. 5016 uint32_t operands_len = elem_count + 1; 5017 ensureExtraCapacity(ag, 1 + operands_len); 5018 uint32_t ai_payload = ag->extra_len; 5019 ag->extra[ag->extra_len++] = operands_len; 5020 ag->extra[ag->extra_len++] = dest_arr_ty_inst; 5021 uint32_t extra_start2 = ag->extra_len; 5022 ag->extra_len += elem_count; 5023 for (uint32_t i = 0; i < elem_count; i++) { 5024 // array_init_elem_type uses bin data (AstGen.zig:1626-1632). 5025 uint32_t elem_ty = addBin( 5026 gz, ZIR_INST_ARRAY_INIT_ELEM_TYPE, dest_arr_ty_inst, i); 5027 ResultLoc elem_rl 5028 = { .tag = RL_COERCED_TY, .data = elem_ty, .src_node = 0 }; 5029 uint32_t elem_ref = exprRl(gz, scope, elem_rl, elements[i]); 5030 ag->extra[extra_start2 + i] = elem_ref; 5031 } 5032 return addPlNodePayloadIndex( 5033 gz, ZIR_INST_ARRAY_INIT_REF, node, ai_payload); 5034 } 5035 case RL_PTR: { 5036 // arrayInitExprPtr (AstGen.zig:1541-1543, 1645-1672). 5037 uint32_t array_ptr_inst 5038 = addUnNode(gz, ZIR_INST_OPT_EU_BASE_PTR_INIT, rl.data, node); 5039 // Block payload: body_len = elem_count. 5040 ensureExtraCapacity(ag, 1 + elem_count); 5041 uint32_t payload_index = ag->extra_len; 5042 ag->extra[ag->extra_len++] = elem_count; 5043 uint32_t items_start = ag->extra_len; 5044 ag->extra_len += elem_count; 5045 5046 for (uint32_t i = 0; i < elem_count; i++) { 5047 // array_init_elem_ptr: ElemPtrImm{ptr, index}. 5048 uint32_t elem_ptr_inst = addPlNodeBin(gz, 5049 ZIR_INST_ARRAY_INIT_ELEM_PTR, elements[i], array_ptr_inst, i); 5050 ag->extra[items_start + i] 5051 = elem_ptr_inst - ZIR_REF_START_INDEX; // .toIndex() 5052 // Evaluate element with ptr RL (AstGen.zig:1668). 5053 ResultLoc ptr_rl = { .tag = RL_PTR, 5054 .data = elem_ptr_inst, 5055 .src_node = 0, 5056 .ctx = rl.ctx }; 5057 exprRl(gz, scope, ptr_rl, elements[i]); 5058 } 5059 addPlNodePayloadIndex( 5060 gz, ZIR_INST_VALIDATE_PTR_ARRAY_INIT, node, payload_index); 5061 return ZIR_REF_VOID_VALUE; 5062 } 5063 } 5064 5065 // Fallback: anon init + rvalue. 5066 ensureExtraCapacity(ag, 1 + elem_count); 5067 uint32_t payload_index = ag->extra_len; 5068 ag->extra[ag->extra_len++] = elem_count; 5069 uint32_t extra_start = ag->extra_len; 5070 ag->extra_len += elem_count; 5071 for (uint32_t i = 0; i < elem_count; i++) { 5072 uint32_t elem_ref = expr(gz, scope, elements[i]); 5073 ag->extra[extra_start + i] = elem_ref; 5074 } 5075 uint32_t result = addPlNodePayloadIndex( 5076 gz, ZIR_INST_ARRAY_INIT_ANON, node, payload_index); 5077 return rvalue(gz, rl, result, node); 5078 } 5079 5080 // --- ifExpr (AstGen.zig:6300-6528) --- 5081 // Handles if and if_simple expressions. 5082 // Pattern: block_scope with condbr → then/else branches → setCondBrPayload. 5083 5084 static uint32_t ifExpr(GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 5085 AstGenCtx* ag = gz->astgen; 5086 const Ast* tree = ag->tree; 5087 bool need_rl = nodesNeedRlContains(ag, node); 5088 ResultLoc break_rl = breakResultInfo(gz, rl, node, need_rl); 5089 AstNodeTag tag = tree->nodes.tags[node]; 5090 AstData nd = tree->nodes.datas[node]; 5091 5092 uint32_t cond_node = nd.lhs; 5093 uint32_t then_node, else_node; 5094 5095 if (tag == AST_NODE_IF_SIMPLE) { 5096 then_node = nd.rhs; 5097 else_node = 0; 5098 } else { 5099 // AST_NODE_IF: rhs is index into extra → If{then_expr, else_expr} 5100 then_node = tree->extra_data.arr[nd.rhs]; 5101 else_node = tree->extra_data.arr[nd.rhs + 1]; 5102 } 5103 5104 // Detect payload capture: if (cond) |x| (AstGen.zig Ast.fullIf). 5105 // payload_pipe = lastToken(cond_expr) + 2; if pipe → payload_token + 1. 5106 uint32_t payload_token = 0; // 0 = no payload 5107 uint32_t last_cond_tok = lastToken(tree, cond_node); 5108 uint32_t pipe_tok = last_cond_tok + 2; 5109 if (pipe_tok < tree->tokens.len 5110 && tree->tokens.tags[pipe_tok] == TOKEN_PIPE) { 5111 payload_token = pipe_tok + 1; // identifier token 5112 } 5113 5114 // Detect error token: then_expr else |e| (AstGen.zig Ast.fullIf). 5115 uint32_t error_token = 0; 5116 if (else_node != 0) { 5117 uint32_t else_tok = lastToken(tree, then_node) + 1; // "else" keyword 5118 if (else_tok + 1 < tree->tokens.len 5119 && tree->tokens.tags[else_tok + 1] == TOKEN_PIPE) { 5120 error_token = else_tok + 2; 5121 } 5122 } 5123 5124 // Create block_scope (AstGen.zig:6326-6328). 5125 GenZir block_scope = makeSubBlock(gz, scope); 5126 5127 // Emit DBG_STMT for condition (AstGen.zig:6335). 5128 // NOTE: upstream emits into parent_gz AFTER block_scope is created, 5129 // so the dbg_stmt ends up in block_scope's range (shared array). 5130 emitDbgNode(gz, cond_node); 5131 5132 // Evaluate condition (AstGen.zig:6335-6363). 5133 uint32_t cond_inst; // the value (optional/err-union/bool) 5134 uint32_t bool_bit; // the boolean for condbr 5135 if (error_token != 0) { 5136 // Error union condition: if (err_union) |val| else |err|. 5137 // (AstGen.zig:6341). 5138 ResultLoc cond_rl = RL_NONE_VAL; 5139 cond_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR; 5140 cond_inst 5141 = exprRl(&block_scope, &block_scope.base, cond_rl, cond_node); 5142 bool_bit = addUnNode( 5143 &block_scope, ZIR_INST_IS_NON_ERR, cond_inst, cond_node); 5144 } else if (payload_token != 0) { 5145 // Optional condition: if (optional) |val|. 5146 cond_inst = expr(&block_scope, &block_scope.base, cond_node); 5147 bool_bit = addUnNode( 5148 &block_scope, ZIR_INST_IS_NON_NULL, cond_inst, cond_node); 5149 } else { 5150 // Bool condition (AstGen.zig:6356-6362). 5151 cond_inst = expr(&block_scope, &block_scope.base, cond_node); 5152 bool_bit = cond_inst; 5153 } 5154 5155 uint32_t condbr = addCondBr(&block_scope, ZIR_INST_CONDBR, node); 5156 uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); 5157 setBlockBody(ag, &block_scope, block_inst); 5158 gzAppendInstruction(gz, block_inst); 5159 5160 // Then branch (AstGen.zig:6372-6441). 5161 GenZir then_scope = makeSubBlock(gz, scope); 5162 Scope* then_sub_scope = &then_scope.base; 5163 ScopeLocalVal payload_val_scope; 5164 memset(&payload_val_scope, 0, sizeof(payload_val_scope)); 5165 5166 if (error_token != 0 && payload_token != 0) { 5167 // Error union with payload: unwrap payload (AstGen.zig:6379-6407). 5168 uint32_t payload_inst = addUnNode(&then_scope, 5169 ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE, cond_inst, then_node); 5170 uint32_t ident_name = identAsString(ag, payload_token); 5171 payload_val_scope = (ScopeLocalVal) { 5172 .base = { .tag = SCOPE_LOCAL_VAL }, 5173 .parent = &then_scope.base, 5174 .gen_zir = &then_scope, 5175 .inst = payload_inst, 5176 .token_src = payload_token, 5177 .name = ident_name, 5178 }; 5179 addDbgVar(&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); 5180 then_sub_scope = &payload_val_scope.base; 5181 } else if (payload_token != 0) { 5182 // Optional with payload: unwrap optional (AstGen.zig:6408-6431). 5183 uint32_t payload_inst = addUnNode(&then_scope, 5184 ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE, cond_inst, then_node); 5185 uint32_t ident_name = identAsString(ag, payload_token); 5186 payload_val_scope = (ScopeLocalVal) { 5187 .base = { .tag = SCOPE_LOCAL_VAL }, 5188 .parent = &then_scope.base, 5189 .gen_zir = &then_scope, 5190 .inst = payload_inst, 5191 .token_src = payload_token, 5192 .name = ident_name, 5193 }; 5194 addDbgVar(&then_scope, ZIR_INST_DBG_VAR_VAL, ident_name, payload_inst); 5195 then_sub_scope = &payload_val_scope.base; 5196 } 5197 5198 // Use fullBodyExpr for then body (AstGen.zig:6437). 5199 uint32_t then_result 5200 = fullBodyExpr(&then_scope, then_sub_scope, break_rl, then_node); 5201 if (!endsWithNoReturn(&then_scope)) { 5202 addBreak(&then_scope, ZIR_INST_BREAK, block_inst, then_result, 5203 (int32_t)then_node - (int32_t)gz->decl_node_index); 5204 } 5205 5206 // Else branch (AstGen.zig:6443-6489). 5207 GenZir else_scope = makeSubBlock(gz, scope); 5208 5209 // save_err_ret_index (AstGen.zig:6448-6449). 5210 bool do_err_trace = ag->fn_ret_ty != 0 && error_token != 0; 5211 if (do_err_trace && nodeMayAppendToErrorTrace(tree, cond_node)) 5212 addSaveErrRetIndex(&else_scope, ZIR_REF_NONE); 5213 5214 if (else_node != 0) { 5215 Scope* else_sub_scope = &else_scope.base; 5216 ScopeLocalVal error_val_scope; 5217 memset(&error_val_scope, 0, sizeof(error_val_scope)); 5218 5219 if (error_token != 0) { 5220 // Error capture: else |err| (AstGen.zig:6452-6475). 5221 uint32_t err_inst = addUnNode( 5222 &else_scope, ZIR_INST_ERR_UNION_CODE, cond_inst, cond_node); 5223 uint32_t err_name = identAsString(ag, error_token); 5224 error_val_scope = (ScopeLocalVal) { 5225 .base = { .tag = SCOPE_LOCAL_VAL }, 5226 .parent = &else_scope.base, 5227 .gen_zir = &else_scope, 5228 .inst = err_inst, 5229 .token_src = error_token, 5230 .name = err_name, 5231 }; 5232 addDbgVar(&else_scope, ZIR_INST_DBG_VAR_VAL, err_name, err_inst); 5233 else_sub_scope = &error_val_scope.base; 5234 } 5235 5236 // Use fullBodyExpr for else body (AstGen.zig:6478). 5237 uint32_t else_result 5238 = fullBodyExpr(&else_scope, else_sub_scope, break_rl, else_node); 5239 if (!endsWithNoReturn(&else_scope)) { 5240 // Restore error return index (AstGen.zig:6480-6482). 5241 if (do_err_trace) 5242 restoreErrRetIndex( 5243 &else_scope, block_inst, break_rl, else_node, else_result); 5244 addBreak(&else_scope, ZIR_INST_BREAK, block_inst, else_result, 5245 (int32_t)else_node - (int32_t)gz->decl_node_index); 5246 } 5247 } else { 5248 addBreak(&else_scope, ZIR_INST_BREAK, block_inst, ZIR_REF_VOID_VALUE, 5249 AST_NODE_OFFSET_NONE); 5250 } 5251 5252 // Wire up condbr (AstGen.zig:6491). 5253 setCondBrPayload(ag, condbr, bool_bit, &then_scope, &else_scope); 5254 5255 // AstGen.zig:6493-6497. 5256 bool need_result_rvalue = (break_rl.tag != rl.tag); 5257 if (need_result_rvalue) 5258 return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node); 5259 return block_inst + ZIR_REF_START_INDEX; 5260 } 5261 5262 // --- forExpr (AstGen.zig:6819-7125) --- 5263 // Handles for_simple and for (multi-input). 5264 // Supports both indexable and for_range inputs. 5265 5266 #define FOR_MAX_INPUTS 16 5267 5268 static uint32_t forExpr( 5269 GenZir* gz, Scope* scope, uint32_t node, bool is_statement) { 5270 AstGenCtx* ag = gz->astgen; 5271 const Ast* tree = ag->tree; 5272 AstData nd = tree->nodes.datas[node]; 5273 AstNodeTag node_tag = tree->nodes.tags[node]; 5274 5275 // Detect inline keyword (AstGen.zig:6847). 5276 uint32_t main_token = tree->nodes.main_tokens[node]; 5277 bool is_inline = (main_token > 0 5278 && tree->tokens.tags[main_token - 1] == TOKEN_KEYWORD_INLINE); 5279 5280 // Extract input nodes and body/else nodes. 5281 // FOR_SIMPLE: lhs = input node, rhs = body (Ast.zig:1960-1968). 5282 // FOR: lhs = extra_data index, rhs = packed AstFor (Ast.zig:1970-1981). 5283 uint32_t input_nodes[FOR_MAX_INPUTS]; 5284 uint32_t num_inputs; 5285 uint32_t body_node; 5286 if (node_tag == AST_NODE_FOR_SIMPLE) { 5287 input_nodes[0] = nd.lhs; 5288 num_inputs = 1; 5289 body_node = nd.rhs; 5290 } else { 5291 uint32_t extra_idx = nd.lhs; 5292 AstFor for_data; 5293 memcpy(&for_data, &nd.rhs, sizeof(AstFor)); 5294 num_inputs = for_data.inputs; 5295 if (num_inputs == 0 || num_inputs > FOR_MAX_INPUTS) { 5296 SET_ERROR(ag); 5297 return ZIR_REF_VOID_VALUE; 5298 } 5299 for (uint32_t i = 0; i < num_inputs; i++) 5300 input_nodes[i] = tree->extra_data.arr[extra_idx + i]; 5301 body_node = tree->extra_data.arr[extra_idx + num_inputs]; 5302 } 5303 5304 // Per-input arrays (AstGen.zig:6858-6862). 5305 uint32_t indexables[FOR_MAX_INPUTS]; 5306 uint32_t lens[FOR_MAX_INPUTS][2]; // [ref0, ref1] per input 5307 5308 // Allocate index counter (AstGen.zig:6865-6874). 5309 ZirInstTag alloc_tag 5310 = is_inline ? ZIR_INST_ALLOC_COMPTIME_MUT : ZIR_INST_ALLOC; 5311 uint32_t index_ptr = addUnNode(gz, alloc_tag, ZIR_REF_USIZE_TYPE, node); 5312 addPlNodeBin(gz, ZIR_INST_STORE_NODE, node, index_ptr, ZIR_REF_ZERO_USIZE); 5313 5314 // Compute payload_token (AstGen.zig fullForComponents:2349-2350). 5315 // payload_token = lastToken(inputs[last]) + 3 + has_comma 5316 uint32_t last_cond_tok = lastToken(tree, input_nodes[num_inputs - 1]); 5317 bool has_comma = (last_cond_tok + 1 < tree->tokens.len 5318 && tree->tokens.tags[last_cond_tok + 1] == TOKEN_COMMA); 5319 uint32_t payload_token = last_cond_tok + 3 + (has_comma ? 1 : 0); 5320 5321 // Process each input (AstGen.zig:6878-6925). 5322 uint32_t capture_token = payload_token; 5323 for (uint32_t i = 0; i < num_inputs; i++) { 5324 uint32_t input = input_nodes[i]; 5325 // Advance capture_token past this capture's ident (+comma). 5326 bool capture_is_ref 5327 = (tree->tokens.tags[capture_token] == TOKEN_ASTERISK); 5328 uint32_t ident_tok = capture_token + (capture_is_ref ? 1u : 0u); 5329 capture_token = ident_tok + 2; // skip ident + comma/pipe 5330 5331 emitDbgNode(gz, input); 5332 5333 if (tree->nodes.tags[input] == AST_NODE_FOR_RANGE) { 5334 // Range input (AstGen.zig:6892-6916). 5335 AstData range_nd = tree->nodes.datas[input]; 5336 uint32_t start_node = range_nd.lhs; 5337 uint32_t end_node = range_nd.rhs; 5338 5339 // AstGen.zig:6897-6902: expr with .rl = .{ .ty = .usize_type } 5340 ResultLoc usize_rl 5341 = { .tag = RL_TY, .data = ZIR_REF_USIZE_TYPE, .src_node = 0 }; 5342 uint32_t start_val = exprRl(gz, scope, usize_rl, start_node); 5343 5344 uint32_t end_val = ZIR_REF_NONE; 5345 if (end_node != 0) { 5346 end_val = exprRl(gz, scope, usize_rl, end_node); 5347 } 5348 5349 if (end_val == ZIR_REF_NONE) { 5350 lens[i][0] = ZIR_REF_NONE; 5351 lens[i][1] = ZIR_REF_NONE; 5352 } else { 5353 lens[i][0] = start_val; 5354 lens[i][1] = end_val; 5355 } 5356 5357 // Check if start is trivially zero. 5358 bool start_is_zero = false; 5359 if (tree->nodes.tags[start_node] == AST_NODE_NUMBER_LITERAL) { 5360 uint32_t tok = tree->nodes.main_tokens[start_node]; 5361 uint32_t ts = tree->tokens.starts[tok]; 5362 if (tree->source[ts] == '0' 5363 && (ts + 1 >= tree->source_len 5364 || tree->source[ts + 1] < '0' 5365 || tree->source[ts + 1] > '9')) 5366 start_is_zero = true; 5367 } 5368 indexables[i] = start_is_zero ? ZIR_REF_NONE : start_val; 5369 } else { 5370 // Regular indexable (AstGen.zig:6918-6923). 5371 uint32_t indexable = expr(gz, scope, input); 5372 indexables[i] = indexable; 5373 lens[i][0] = indexable; 5374 lens[i][1] = ZIR_REF_NONE; 5375 } 5376 } 5377 5378 // Emit for_len as MultiOp (AstGen.zig:6933-6942). 5379 uint32_t len; 5380 { 5381 uint32_t operands_len = num_inputs * 2; 5382 ensureExtraCapacity(ag, 1 + operands_len); 5383 uint32_t payload_index = ag->extra_len; 5384 ag->extra[ag->extra_len++] = operands_len; 5385 for (uint32_t i = 0; i < num_inputs; i++) { 5386 ag->extra[ag->extra_len++] = lens[i][0]; 5387 ag->extra[ag->extra_len++] = lens[i][1]; 5388 } 5389 ZirInstData data; 5390 data.pl_node.src_node = (int32_t)node - (int32_t)gz->decl_node_index; 5391 data.pl_node.payload_index = payload_index; 5392 len = addInstruction(gz, ZIR_INST_FOR_LEN, data); 5393 } 5394 5395 // Create loop (AstGen.zig:6944-6956). 5396 ZirInstTag loop_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_LOOP; 5397 uint32_t loop_inst = makeBlockInst(ag, loop_tag, gz, node); 5398 5399 GenZir loop_scope = makeSubBlock(gz, scope); 5400 loop_scope.is_inline = is_inline; 5401 5402 // Load index (AstGen.zig:6955-6956). 5403 // We need to finish loop_scope later once we have the deferred refs from 5404 // then_scope. However, the load must be removed from instructions in the 5405 // meantime or it appears to be part of parent_gz. 5406 uint32_t index = addUnNode(&loop_scope, ZIR_INST_LOAD, index_ptr, node); 5407 ag->scratch_inst_len--; // pop from loop_scope (AstGen.zig:6956) 5408 5409 // Condition: added to cond_scope (AstGen.zig:6958-6962). 5410 GenZir cond_scope = makeSubBlock(gz, &loop_scope.base); 5411 uint32_t cond 5412 = addPlNodeBin(&cond_scope, ZIR_INST_CMP_LT, node, index, len); 5413 5414 // Create condbr + block (AstGen.zig:6967-6974). 5415 ZirInstTag condbr_tag 5416 = is_inline ? ZIR_INST_CONDBR_INLINE : ZIR_INST_CONDBR; 5417 uint32_t condbr = addCondBr(&cond_scope, condbr_tag, node); 5418 ZirInstTag block_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_BLOCK; 5419 uint32_t cond_block = makeBlockInst(ag, block_tag, &loop_scope, node); 5420 setBlockBody(ag, &cond_scope, cond_block); 5421 5422 loop_scope.break_block = loop_inst; 5423 loop_scope.continue_block = cond_block; // AstGen.zig:6974 5424 5425 // Then branch: loop body (AstGen.zig:6982-7065). 5426 GenZir then_scope = makeSubBlock(gz, &cond_scope.base); 5427 5428 // Set up capture scopes for all inputs (AstGen.zig:6986-7045). 5429 ScopeLocalVal capture_scopes[FOR_MAX_INPUTS]; 5430 Scope* body_scope_parent = &then_scope.base; 5431 { 5432 capture_token = payload_token; 5433 for (uint32_t i = 0; i < num_inputs; i++) { 5434 uint32_t input = input_nodes[i]; 5435 bool capture_is_ref 5436 = (tree->tokens.tags[capture_token] == TOKEN_ASTERISK); 5437 uint32_t ident_tok = capture_token + (capture_is_ref ? 1u : 0u); 5438 capture_token = ident_tok + 2; 5439 5440 // Check if discard (AstGen.zig:6999). 5441 uint32_t ts = tree->tokens.starts[ident_tok]; 5442 bool is_discard = (tree->source[ts] == '_' 5443 && (ts + 1 >= tree->source_len 5444 || !((tree->source[ts + 1] >= 'a' 5445 && tree->source[ts + 1] <= 'z') 5446 || (tree->source[ts + 1] >= 'A' 5447 && tree->source[ts + 1] <= 'Z') 5448 || tree->source[ts + 1] == '_' 5449 || (tree->source[ts + 1] >= '0' 5450 && tree->source[ts + 1] <= '9')))); 5451 if (is_discard) 5452 continue; 5453 5454 // Compute capture inst (AstGen.zig:7004-7028). 5455 uint32_t capture_inst; 5456 bool is_counter = (tree->nodes.tags[input] == AST_NODE_FOR_RANGE); 5457 5458 if (indexables[i] == ZIR_REF_NONE) { 5459 // Start=0 counter: use index directly. 5460 capture_inst = index; 5461 } else if (is_counter) { 5462 // Counter with nonzero start: add. 5463 capture_inst = addPlNodeBin( 5464 &then_scope, ZIR_INST_ADD, input, indexables[i], index); 5465 } else if (capture_is_ref) { 5466 // Indexable by ref: elem_ptr. 5467 capture_inst = addPlNodeBin(&then_scope, ZIR_INST_ELEM_PTR, 5468 input, indexables[i], index); 5469 } else { 5470 // Indexable by val: elem_val. 5471 capture_inst = addPlNodeBin(&then_scope, ZIR_INST_ELEM_VAL, 5472 input, indexables[i], index); 5473 } 5474 5475 uint32_t name_str = identAsString(ag, ident_tok); 5476 capture_scopes[i] = (ScopeLocalVal) { 5477 .base = { .tag = SCOPE_LOCAL_VAL }, 5478 .parent = body_scope_parent, 5479 .gen_zir = &then_scope, 5480 .inst = capture_inst, 5481 .token_src = ident_tok, 5482 .name = name_str, 5483 }; 5484 // AstGen.zig:7040. 5485 addDbgVar( 5486 &then_scope, ZIR_INST_DBG_VAR_VAL, name_str, capture_inst); 5487 body_scope_parent = &capture_scopes[i].base; 5488 } 5489 } 5490 5491 // Execute body (AstGen.zig:7047-7048). 5492 uint32_t then_result 5493 = fullBodyExpr(&then_scope, body_scope_parent, RL_NONE_VAL, body_node); 5494 addEnsureResult(&then_scope, then_result, body_node); 5495 5496 // dbg_stmt + dbg_empty_stmt (AstGen.zig:7052-7061). 5497 advanceSourceCursor(ag, tree->tokens.starts[lastToken(tree, body_node)]); 5498 emitDbgStmt(gz, ag->source_line - gz->decl_line, ag->source_column); 5499 { 5500 ZirInstData ext_data; 5501 ext_data.extended.opcode = (uint16_t)ZIR_EXT_DBG_EMPTY_STMT; 5502 ext_data.extended.small = 0; 5503 ext_data.extended.operand = 0; 5504 addInstruction(gz, ZIR_INST_EXTENDED, ext_data); 5505 } 5506 5507 ZirInstTag break_tag = is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK; 5508 addBreak(&then_scope, break_tag, cond_block, ZIR_REF_VOID_VALUE, 5509 AST_NODE_OFFSET_NONE); 5510 5511 // Else branch: break out of loop (AstGen.zig:7066-7091). 5512 GenZir else_scope = makeSubBlock(gz, &cond_scope.base); 5513 addBreak(&else_scope, break_tag, loop_inst, ZIR_REF_VOID_VALUE, 5514 AST_NODE_OFFSET_NONE); 5515 5516 setCondBrPayload(ag, condbr, cond, &then_scope, &else_scope); 5517 5518 // then_scope and else_scope unstacked now. Resurrect loop_scope to 5519 // finally finish it (AstGen.zig:7095-7113). 5520 { 5521 // Reset loop_scope instructions and re-add index + cond_block. 5522 loop_scope.instructions_top = ag->scratch_inst_len; 5523 gzAppendInstruction(&loop_scope, index - ZIR_REF_START_INDEX); 5524 gzAppendInstruction(&loop_scope, cond_block); 5525 5526 // Increment the index variable (AstGen.zig:7100-7108). 5527 uint32_t index_plus_one = addPlNodeBin( 5528 &loop_scope, ZIR_INST_ADD_UNSAFE, node, index, ZIR_REF_ONE_USIZE); 5529 addPlNodeBin( 5530 &loop_scope, ZIR_INST_STORE_NODE, node, index_ptr, index_plus_one); 5531 5532 // Repeat (AstGen.zig:7110-7111). 5533 ZirInstTag repeat_tag 5534 = is_inline ? ZIR_INST_REPEAT_INLINE : ZIR_INST_REPEAT; 5535 ZirInstData repeat_data; 5536 memset(&repeat_data, 0, sizeof(repeat_data)); 5537 repeat_data.node = (int32_t)node - (int32_t)loop_scope.decl_node_index; 5538 addInstruction(&loop_scope, repeat_tag, repeat_data); 5539 5540 setBlockBody(ag, &loop_scope, loop_inst); 5541 } 5542 gzAppendInstruction(gz, loop_inst); 5543 5544 uint32_t result = loop_inst + ZIR_REF_START_INDEX; 5545 5546 // Emit ensure_result_used when used as statement (AstGen.zig:7121-7123). 5547 if (is_statement) { 5548 addUnNode(gz, ZIR_INST_ENSURE_RESULT_USED, result, node); 5549 } 5550 5551 return result; 5552 } 5553 5554 // --- orelseCatchExpr (AstGen.zig:6031-6142) --- 5555 // Handles `lhs orelse rhs` and `lhs catch rhs`. 5556 5557 static uint32_t orelseCatchExpr( 5558 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node, bool is_catch) { 5559 AstGenCtx* ag = gz->astgen; 5560 const Ast* tree = ag->tree; 5561 AstData nd = tree->nodes.datas[node]; 5562 5563 bool do_err_trace = is_catch && ag->fn_ret_ty != 0; 5564 5565 // breakResultInfo (AstGen.zig:6046-6058). 5566 bool need_rl = nodesNeedRlContains(ag, node); 5567 ResultLoc break_rl = breakResultInfo(gz, rl, node, need_rl); 5568 bool need_result_rvalue = (break_rl.tag != rl.tag); 5569 5570 // Create block_scope (AstGen.zig:6062-6063). 5571 GenZir block_scope = makeSubBlock(gz, scope); 5572 5573 // Evaluate operand in block_scope (AstGen.zig:6066-6074). 5574 ResultLoc operand_rl = RL_NONE_VAL; 5575 if (do_err_trace) { 5576 operand_rl.ctx = RI_CTX_ERROR_HANDLING_EXPR; 5577 } 5578 uint32_t operand 5579 = exprRl(&block_scope, &block_scope.base, operand_rl, nd.lhs); 5580 5581 // Check condition in block_scope (AstGen.zig:6075). 5582 ZirInstTag test_tag 5583 = is_catch ? ZIR_INST_IS_NON_ERR : ZIR_INST_IS_NON_NULL; 5584 uint32_t condition = addUnNode(&block_scope, test_tag, operand, node); 5585 5586 // condbr in block_scope (AstGen.zig:6076). 5587 uint32_t condbr = addCondBr(&block_scope, ZIR_INST_CONDBR, node); 5588 5589 // Create block in parent gz (AstGen.zig:6078-6081). 5590 uint32_t block_inst = makeBlockInst(ag, ZIR_INST_BLOCK, gz, node); 5591 setBlockBody(ag, &block_scope, block_inst); 5592 // block_scope unstacked now. 5593 gzAppendInstruction(gz, block_inst); 5594 5595 // Then branch: unwrap payload (AstGen.zig:6083-6092). 5596 GenZir then_scope = makeSubBlock(&block_scope, scope); 5597 ZirInstTag unwrap_tag = is_catch ? ZIR_INST_ERR_UNION_PAYLOAD_UNSAFE 5598 : ZIR_INST_OPTIONAL_PAYLOAD_UNSAFE; 5599 uint32_t unwrapped = addUnNode(&then_scope, unwrap_tag, operand, node); 5600 // Apply rvalue coercion unless rl is ref/ref_coerced_ty 5601 // (AstGen.zig:6088-6091). 5602 uint32_t then_result = (rl.tag == RL_REF || rl.tag == RL_REF_COERCED_TY) 5603 ? unwrapped 5604 : rvalue(&then_scope, break_rl, unwrapped, node); 5605 addBreak(&then_scope, ZIR_INST_BREAK, block_inst, then_result, 5606 (int32_t)node - (int32_t)gz->decl_node_index); 5607 5608 // Else branch: evaluate RHS (AstGen.zig:6094-6131). 5609 GenZir else_scope = makeSubBlock(&block_scope, scope); 5610 5611 // save_err_ret_index (AstGen.zig:6099-6100). 5612 if (do_err_trace && nodeMayAppendToErrorTrace(tree, nd.lhs)) 5613 addSaveErrRetIndex(&else_scope, ZIR_REF_NONE); 5614 5615 // Use fullBodyExpr (not expr) to inline unlabeled blocks 5616 // (AstGen.zig:6125). 5617 uint32_t else_result 5618 = fullBodyExpr(&else_scope, &else_scope.base, break_rl, nd.rhs); 5619 if (!endsWithNoReturn(&else_scope)) { 5620 // restoreErrRetIndex (AstGen.zig:6128-6129). 5621 if (do_err_trace) 5622 restoreErrRetIndex( 5623 &else_scope, block_inst, break_rl, nd.rhs, else_result); 5624 addBreak(&else_scope, ZIR_INST_BREAK, block_inst, else_result, 5625 (int32_t)nd.rhs - (int32_t)gz->decl_node_index); 5626 } 5627 5628 setCondBrPayload(ag, condbr, condition, &then_scope, &else_scope); 5629 5630 // AstGen.zig:6137-6141. 5631 if (need_result_rvalue) 5632 return rvalue(gz, rl, block_inst + ZIR_REF_START_INDEX, node); 5633 return block_inst + ZIR_REF_START_INDEX; 5634 } 5635 5636 // --- whileExpr (AstGen.zig:6529-6805) --- 5637 // Handles while_simple. 5638 // Structure: loop { cond_block { cond, condbr }, repeat } 5639 // condbr → then { continue_block { body, break continue }, break cond } 5640 // → else { break loop } 5641 5642 static uint32_t whileExpr( 5643 GenZir* gz, Scope* scope, uint32_t node, bool is_statement) { 5644 AstGenCtx* ag = gz->astgen; 5645 const Ast* tree = ag->tree; 5646 AstData nd = tree->nodes.datas[node]; 5647 5648 // Detect inline keyword (AstGen.zig:6558). 5649 uint32_t main_token = tree->nodes.main_tokens[node]; 5650 bool is_inline = (main_token > 0 5651 && tree->tokens.tags[main_token - 1] == TOKEN_KEYWORD_INLINE); 5652 5653 // WHILE_SIMPLE: lhs = cond_expr, rhs = body. 5654 uint32_t cond_node = nd.lhs; 5655 uint32_t body_node = nd.rhs; 5656 5657 // Create loop instruction (AstGen.zig:6562-6564). 5658 ZirInstTag loop_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_LOOP; 5659 uint32_t loop_inst = makeBlockInst(ag, loop_tag, gz, node); 5660 gzAppendInstruction(gz, loop_inst); 5661 5662 GenZir loop_scope = makeSubBlock(gz, scope); 5663 loop_scope.is_inline = is_inline; 5664 5665 // Evaluate condition in cond_scope (AstGen.zig:6571-6607). 5666 GenZir cond_scope = makeSubBlock(&loop_scope, &loop_scope.base); 5667 // Emit debug node for the condition expression (AstGen.zig:6579). 5668 emitDbgNode(&cond_scope, cond_node); 5669 uint32_t cond = expr(&cond_scope, &cond_scope.base, cond_node); 5670 5671 // Create condbr + cond_block (AstGen.zig:6609-6615). 5672 ZirInstTag condbr_tag 5673 = is_inline ? ZIR_INST_CONDBR_INLINE : ZIR_INST_CONDBR; 5674 uint32_t condbr = addCondBr(&cond_scope, condbr_tag, node); 5675 ZirInstTag block_tag = is_inline ? ZIR_INST_BLOCK_INLINE : ZIR_INST_BLOCK; 5676 uint32_t cond_block = makeBlockInst(ag, block_tag, &loop_scope, node); 5677 setBlockBody(ag, &cond_scope, cond_block); // unstacks cond_scope 5678 gzAppendInstruction(&loop_scope, cond_block); 5679 5680 // Create continue_block (AstGen.zig:6694). 5681 uint32_t continue_block = makeBlockInst(ag, block_tag, &loop_scope, node); 5682 5683 // Add repeat to loop_scope (AstGen.zig:6696-6697). 5684 { 5685 ZirInstTag repeat_tag 5686 = is_inline ? ZIR_INST_REPEAT_INLINE : ZIR_INST_REPEAT; 5687 ZirInstData repeat_data; 5688 memset(&repeat_data, 0, sizeof(repeat_data)); 5689 repeat_data.node = (int32_t)node - (int32_t)loop_scope.decl_node_index; 5690 addInstruction(&loop_scope, repeat_tag, repeat_data); 5691 } 5692 5693 // Set loop body and configure break/continue (AstGen.zig:6699-6701). 5694 setBlockBody(ag, &loop_scope, loop_inst); // unstacks loop_scope 5695 loop_scope.break_block = loop_inst; 5696 loop_scope.continue_block = continue_block; 5697 5698 // Stack then_scope (AstGen.zig:6708-6709). 5699 GenZir then_scope = makeSubBlock(gz, &cond_scope.base); 5700 5701 // Add continue_block to then_scope (AstGen.zig:6716). 5702 gzAppendInstruction(&then_scope, continue_block); 5703 5704 // Create continue_scope inside then_scope (AstGen.zig:6725). 5705 GenZir continue_scope = makeSubBlock(&then_scope, &then_scope.base); 5706 5707 // Execute body (AstGen.zig:6727-6730). 5708 emitDbgNode(&continue_scope, body_node); 5709 fullBodyExpr( 5710 &continue_scope, &continue_scope.base, RL_NONE_VAL, body_node); 5711 5712 // Break continue_block if not noreturn (AstGen.zig:6735-6747). 5713 if (!endsWithNoReturn(&continue_scope)) { 5714 // dbg_stmt + dbg_empty_stmt (AstGen.zig:6737-6745). 5715 advanceSourceCursor( 5716 ag, tree->tokens.starts[lastToken(tree, body_node)]); 5717 emitDbgStmt(gz, ag->source_line - gz->decl_line, ag->source_column); 5718 { 5719 ZirInstData ext_data; 5720 ext_data.extended.opcode = (uint16_t)ZIR_EXT_DBG_EMPTY_STMT; 5721 ext_data.extended.small = 0; 5722 ext_data.extended.operand = 0; 5723 addInstruction(gz, ZIR_INST_EXTENDED, ext_data); 5724 } 5725 ZirInstTag break_tag 5726 = is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK; 5727 addBreak(&continue_scope, break_tag, continue_block, 5728 ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); 5729 } 5730 setBlockBody(ag, &continue_scope, continue_block); 5731 5732 // Break cond_block from then_scope (AstGen.zig:7064). 5733 { 5734 ZirInstTag break_tag 5735 = is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK; 5736 addBreak(&then_scope, break_tag, cond_block, ZIR_REF_VOID_VALUE, 5737 AST_NODE_OFFSET_NONE); 5738 } 5739 5740 // Else scope: break loop with void (AstGen.zig:6785-6788). 5741 GenZir else_scope = makeSubBlock(gz, &cond_scope.base); 5742 { 5743 ZirInstTag break_tag 5744 = is_inline ? ZIR_INST_BREAK_INLINE : ZIR_INST_BREAK; 5745 addBreak(&else_scope, break_tag, loop_inst, ZIR_REF_VOID_VALUE, 5746 AST_NODE_OFFSET_NONE); 5747 } 5748 5749 // Wire up condbr (AstGen.zig:6795). 5750 setCondBrPayload(ag, condbr, cond, &then_scope, &else_scope); 5751 5752 uint32_t result = loop_inst + ZIR_REF_START_INDEX; 5753 5754 // Emit ensure_result_used when used as statement (AstGen.zig:6812-6813). 5755 if (is_statement) { 5756 addUnNode(gz, ZIR_INST_ENSURE_RESULT_USED, result, node); 5757 } 5758 5759 return result; 5760 } 5761 5762 // --- switchExpr (AstGen.zig:7625-8117) --- 5763 // Handles switch and switch_comma expressions. 5764 // Encoding: switch_block pl_node with SwitchBlock extra payload. 5765 5766 static uint32_t switchExpr( 5767 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 5768 AstGenCtx* ag = gz->astgen; 5769 const Ast* tree = ag->tree; 5770 bool need_rl = nodesNeedRlContains(ag, node); 5771 ResultLoc break_rl = breakResultInfo(gz, rl, node, need_rl); 5772 AstData nd = tree->nodes.datas[node]; 5773 5774 // AST_NODE_SWITCH: lhs = condition node, rhs = extra index for SubRange. 5775 // SubRange[rhs] = { cases_start, cases_end }. 5776 // Case nodes are at extra_data[cases_start..cases_end]. 5777 uint32_t cond_node = nd.lhs; 5778 uint32_t extra_idx = nd.rhs; 5779 uint32_t cases_start = tree->extra_data.arr[extra_idx]; 5780 uint32_t cases_end = tree->extra_data.arr[extra_idx + 1]; 5781 const uint32_t* case_nodes_arr = tree->extra_data.arr + cases_start; 5782 uint32_t case_count = cases_end - cases_start; 5783 5784 // Save operand source location before evaluating (AstGen.zig:7774-7775). 5785 advanceSourceCursorToNode(ag, cond_node); 5786 uint32_t operand_lc_line = ag->source_line - gz->decl_line; 5787 uint32_t operand_lc_col = ag->source_column; 5788 5789 // Evaluate switch operand (AstGen.zig:7777). 5790 uint32_t cond_ref = expr(gz, scope, cond_node); 5791 5792 // --- First pass: categorize cases (AstGen.zig:7671-7762) --- 5793 uint32_t scalar_cases_len = 0; 5794 uint32_t multi_cases_len = 0; 5795 bool has_else = false; 5796 5797 for (uint32_t ci = 0; ci < case_count; ci++) { 5798 uint32_t cn = case_nodes_arr[ci]; 5799 AstNodeTag ct = tree->nodes.tags[cn]; 5800 AstData cd = tree->nodes.datas[cn]; 5801 5802 switch (ct) { 5803 case AST_NODE_SWITCH_CASE_ONE: 5804 case AST_NODE_SWITCH_CASE_INLINE_ONE: 5805 if (cd.lhs == 0) 5806 has_else = true; 5807 else if (tree->nodes.tags[cd.lhs] == AST_NODE_SWITCH_RANGE) 5808 multi_cases_len++; 5809 else 5810 scalar_cases_len++; 5811 break; 5812 case AST_NODE_SWITCH_CASE: 5813 case AST_NODE_SWITCH_CASE_INLINE: 5814 multi_cases_len++; 5815 break; 5816 default: 5817 break; 5818 } 5819 } 5820 5821 // Sema expects a dbg_stmt immediately before switch_block 5822 // (AstGen.zig:7806). 5823 emitDbgStmtForceCurrentIndex(gz, operand_lc_line, operand_lc_col); 5824 // --- Create switch_block instruction (AstGen.zig:7809) --- 5825 uint32_t switch_inst = makeBlockInst(ag, ZIR_INST_SWITCH_BLOCK, gz, node); 5826 5827 // --- Single-pass evaluation in source order (AstGen.zig:7849-8027) --- 5828 // Case table + payload buffer pattern (like upstream scratch). 5829 // Table layout: [else?] [scalar_0..N] [multi_0..N] 5830 // Each entry points to the start of that case's data in the buffer. 5831 uint32_t table_size 5832 = (has_else ? 1 : 0) + scalar_cases_len + multi_cases_len; 5833 uint32_t else_tbl = 0; 5834 uint32_t scalar_tbl = (has_else ? 1 : 0); 5835 uint32_t multi_tbl = scalar_tbl + scalar_cases_len; 5836 5837 uint32_t pay_cap = table_size + case_count * 16; 5838 uint32_t* pay = malloc(pay_cap * sizeof(uint32_t)); 5839 uint32_t pay_len = table_size; 5840 5841 uint32_t scalar_ci = 0; 5842 uint32_t multi_ci = 0; 5843 5844 for (uint32_t ci = 0; ci < case_count; ci++) { 5845 uint32_t cn = case_nodes_arr[ci]; 5846 AstNodeTag ct = tree->nodes.tags[cn]; 5847 AstData cd = tree->nodes.datas[cn]; 5848 uint32_t hdr = pay_len; 5849 uint32_t prong_info_slot = 0; 5850 5851 // Ensure capacity for items (generous estimate). 5852 if (pay_len + 32 > pay_cap) { 5853 pay_cap *= 2; 5854 uint32_t* p = realloc(pay, pay_cap * sizeof(uint32_t)); 5855 if (!p) 5856 abort(); 5857 pay = p; 5858 } 5859 5860 switch (ct) { 5861 case AST_NODE_SWITCH_CASE_ONE: 5862 case AST_NODE_SWITCH_CASE_INLINE_ONE: 5863 if (cd.lhs == 0) { 5864 // Else: [prong_info, body...] 5865 pay[else_tbl] = hdr; 5866 prong_info_slot = pay_len++; 5867 } else if (tree->nodes.tags[cd.lhs] == AST_NODE_SWITCH_RANGE) { 5868 // Single range → multi case: 5869 // [items_len=0, ranges_len=1, prong_info, first, last] 5870 pay[multi_tbl + multi_ci++] = hdr; 5871 pay[pay_len++] = 0; 5872 pay[pay_len++] = 1; 5873 prong_info_slot = pay_len++; 5874 AstData rng = tree->nodes.datas[cd.lhs]; 5875 pay[pay_len++] = comptimeExpr(gz, scope, RL_NONE_VAL, rng.lhs, 5876 COMPTIME_REASON_SWITCH_ITEM); 5877 pay[pay_len++] = comptimeExpr(gz, scope, RL_NONE_VAL, rng.rhs, 5878 COMPTIME_REASON_SWITCH_ITEM); 5879 } else { 5880 // Scalar: [item_ref, prong_info, body...] 5881 pay[scalar_tbl + scalar_ci++] = hdr; 5882 pay[pay_len++] = comptimeExpr(gz, scope, RL_NONE_VAL, cd.lhs, 5883 COMPTIME_REASON_SWITCH_ITEM); 5884 prong_info_slot = pay_len++; 5885 } 5886 break; 5887 case AST_NODE_SWITCH_CASE: 5888 case AST_NODE_SWITCH_CASE_INLINE: { 5889 // Multi-item: SubRange[lhs] of items, rhs = body. 5890 pay[multi_tbl + multi_ci++] = hdr; 5891 uint32_t ist = tree->extra_data.arr[cd.lhs]; 5892 uint32_t ien = tree->extra_data.arr[cd.lhs + 1]; 5893 uint32_t nitems = 0, nranges = 0; 5894 for (uint32_t j = ist; j < ien; j++) { 5895 if (tree->nodes.tags[tree->extra_data.arr[j]] 5896 == AST_NODE_SWITCH_RANGE) 5897 nranges++; 5898 else 5899 nitems++; 5900 } 5901 pay[pay_len++] = nitems; 5902 pay[pay_len++] = nranges; 5903 prong_info_slot = pay_len++; 5904 // Non-range items. 5905 for (uint32_t j = ist; j < ien; j++) { 5906 uint32_t item = tree->extra_data.arr[j]; 5907 if (tree->nodes.tags[item] != AST_NODE_SWITCH_RANGE) { 5908 if (pay_len + 2 > pay_cap) { 5909 pay_cap *= 2; 5910 uint32_t* p = realloc(pay, pay_cap * sizeof(uint32_t)); 5911 if (!p) 5912 abort(); 5913 pay = p; 5914 } 5915 pay[pay_len++] = comptimeExpr(gz, scope, RL_NONE_VAL, item, 5916 COMPTIME_REASON_SWITCH_ITEM); 5917 } 5918 } 5919 // Range pairs. 5920 for (uint32_t j = ist; j < ien; j++) { 5921 uint32_t item = tree->extra_data.arr[j]; 5922 if (tree->nodes.tags[item] == AST_NODE_SWITCH_RANGE) { 5923 AstData rng = tree->nodes.datas[item]; 5924 if (pay_len + 2 > pay_cap) { 5925 pay_cap *= 2; 5926 uint32_t* p = realloc(pay, pay_cap * sizeof(uint32_t)); 5927 if (!p) 5928 abort(); 5929 pay = p; 5930 } 5931 pay[pay_len++] = comptimeExpr(gz, scope, RL_NONE_VAL, 5932 rng.lhs, COMPTIME_REASON_SWITCH_ITEM); 5933 pay[pay_len++] = comptimeExpr(gz, scope, RL_NONE_VAL, 5934 rng.rhs, COMPTIME_REASON_SWITCH_ITEM); 5935 } 5936 } 5937 break; 5938 } 5939 default: 5940 continue; 5941 } 5942 5943 // Evaluate body (AstGen.zig:7997-8026). 5944 uint32_t body_node = cd.rhs; 5945 GenZir case_scope = makeSubBlock(gz, scope); 5946 5947 // Note: upstream regular switchExpr (AstGen.zig:7625) does NOT emit 5948 // save_err_ret_index. Only switchExprErrUnion (AstGen.zig:7524) does. 5949 5950 // Use fullBodyExpr to process body inline (AstGen.zig:8009). 5951 uint32_t result 5952 = fullBodyExpr(&case_scope, &case_scope.base, break_rl, body_node); 5953 if (!refIsNoReturn(gz, result)) { 5954 addBreak(&case_scope, ZIR_INST_BREAK, switch_inst, result, 5955 (int32_t)body_node - (int32_t)gz->decl_node_index); 5956 } 5957 uint32_t body_len = gzInstructionsLen(&case_scope); 5958 const uint32_t* body = gzInstructionsSlice(&case_scope); 5959 5960 pay[prong_info_slot] = body_len & 0x0FFFFFFFu; 5961 5962 if (pay_len + body_len > pay_cap) { 5963 while (pay_len + body_len > pay_cap) 5964 pay_cap *= 2; 5965 uint32_t* p = realloc(pay, pay_cap * sizeof(uint32_t)); 5966 if (!p) 5967 abort(); 5968 pay = p; 5969 } 5970 for (uint32_t i = 0; i < body_len; i++) 5971 pay[pay_len++] = body[i]; 5972 gzUnstack(&case_scope); 5973 } 5974 5975 // --- Serialize to extra in payload order (AstGen.zig:8036-8110) --- 5976 ensureExtraCapacity(ag, 5977 2 + (uint32_t)(multi_cases_len > 0 ? 1 : 0) + pay_len - table_size); 5978 uint32_t payload_index = ag->extra_len; 5979 5980 ag->extra[ag->extra_len++] = cond_ref; 5981 5982 uint32_t bits = 0; 5983 if (multi_cases_len > 0) 5984 bits |= 1u; 5985 if (has_else) 5986 bits |= (1u << 1); 5987 bits |= (scalar_cases_len & 0x1FFFFFFu) << 7; 5988 ag->extra[ag->extra_len++] = bits; 5989 5990 if (multi_cases_len > 0) 5991 ag->extra[ag->extra_len++] = multi_cases_len; 5992 5993 // Else prong. 5994 if (has_else) { 5995 uint32_t si = pay[else_tbl]; 5996 uint32_t bl = pay[si] & 0x0FFFFFFFu; 5997 for (uint32_t i = 0; i < 1 + bl; i++) 5998 ag->extra[ag->extra_len++] = pay[si + i]; 5999 } 6000 // Scalar cases. 6001 for (uint32_t i = 0; i < scalar_cases_len; i++) { 6002 uint32_t si = pay[scalar_tbl + i]; 6003 uint32_t bl = pay[si + 1] & 0x0FFFFFFFu; 6004 for (uint32_t j = 0; j < 2 + bl; j++) 6005 ag->extra[ag->extra_len++] = pay[si + j]; 6006 } 6007 // Multi cases. 6008 for (uint32_t i = 0; i < multi_cases_len; i++) { 6009 uint32_t si = pay[multi_tbl + i]; 6010 uint32_t ni = pay[si]; 6011 uint32_t nr = pay[si + 1]; 6012 uint32_t bl = pay[si + 2] & 0x0FFFFFFFu; 6013 uint32_t total = 3 + ni + nr * 2 + bl; 6014 for (uint32_t j = 0; j < total; j++) 6015 ag->extra[ag->extra_len++] = pay[si + j]; 6016 } 6017 6018 free(pay); 6019 6020 ag->inst_datas[switch_inst].pl_node.payload_index = payload_index; 6021 gzAppendInstruction(gz, switch_inst); 6022 6023 // AstGen.zig:8112-8115. 6024 bool need_result_rvalue = (break_rl.tag != rl.tag); 6025 if (need_result_rvalue) 6026 return rvalue(gz, rl, switch_inst + ZIR_REF_START_INDEX, node); 6027 return switch_inst + ZIR_REF_START_INDEX; 6028 } 6029 6030 // --- rvalue (AstGen.zig:11029) --- 6031 // Simplified: handles .none and .discard result locations. 6032 6033 static uint32_t rvalueDiscard(GenZir* gz, uint32_t result, uint32_t src_node) { 6034 // .discard => emit ensure_result_non_error, return .void_value 6035 // (AstGen.zig:11071-11074) 6036 ZirInstData data; 6037 data.un_node.src_node = (int32_t)src_node - (int32_t)gz->decl_node_index; 6038 data.un_node.operand = result; 6039 addInstruction(gz, ZIR_INST_ENSURE_RESULT_NON_ERROR, data); 6040 return ZIR_REF_VOID_VALUE; 6041 } 6042 6043 // --- emitDbgNode / emitDbgStmt (AstGen.zig:3422, 13713) --- 6044 6045 static void emitDbgStmt(GenZir* gz, uint32_t line, uint32_t column) { 6046 if (gz->is_comptime) 6047 return; 6048 // Check if last instruction is already dbg_stmt; if so, update it. 6049 // (AstGen.zig:13715-13724) 6050 AstGenCtx* ag = gz->astgen; 6051 uint32_t gz_len = gzInstructionsLen(gz); 6052 if (gz_len > 0) { 6053 uint32_t last = gzInstructionsSlice(gz)[gz_len - 1]; 6054 if (ag->inst_tags[last] == ZIR_INST_DBG_STMT) { 6055 ag->inst_datas[last].dbg_stmt.line = line; 6056 ag->inst_datas[last].dbg_stmt.column = column; 6057 return; 6058 } 6059 } 6060 ZirInstData data; 6061 data.dbg_stmt.line = line; 6062 data.dbg_stmt.column = column; 6063 addInstruction(gz, ZIR_INST_DBG_STMT, data); 6064 } 6065 6066 // Mirrors emitDbgStmtForceCurrentIndex (AstGen.zig:13739-13760). 6067 static void emitDbgStmtForceCurrentIndex( 6068 GenZir* gz, uint32_t line, uint32_t column) { 6069 AstGenCtx* ag = gz->astgen; 6070 uint32_t gz_len = gzInstructionsLen(gz); 6071 if (gz_len > 0 6072 && gzInstructionsSlice(gz)[gz_len - 1] == ag->inst_len - 1) { 6073 uint32_t last = ag->inst_len - 1; 6074 if (ag->inst_tags[last] == ZIR_INST_DBG_STMT) { 6075 ag->inst_datas[last].dbg_stmt.line = line; 6076 ag->inst_datas[last].dbg_stmt.column = column; 6077 return; 6078 } 6079 } 6080 ZirInstData data; 6081 data.dbg_stmt.line = line; 6082 data.dbg_stmt.column = column; 6083 addInstruction(gz, ZIR_INST_DBG_STMT, data); 6084 } 6085 6086 static void emitDbgNode(GenZir* gz, uint32_t node) { 6087 if (gz->is_comptime) 6088 return; 6089 AstGenCtx* ag = gz->astgen; 6090 advanceSourceCursorToNode(ag, node); 6091 uint32_t line = ag->source_line - gz->decl_line; 6092 uint32_t column = ag->source_column; 6093 emitDbgStmt(gz, line, column); 6094 } 6095 6096 // --- assign (AstGen.zig:3434) --- 6097 // Handles `_ = expr` discard pattern. 6098 6099 static void assignStmt(GenZir* gz, Scope* scope, uint32_t infix_node) { 6100 emitDbgNode(gz, infix_node); 6101 const AstGenCtx* ag = gz->astgen; 6102 const Ast* tree = ag->tree; 6103 6104 AstData nd = tree->nodes.datas[infix_node]; 6105 uint32_t lhs = nd.lhs; 6106 uint32_t rhs = nd.rhs; 6107 6108 // Check if LHS is `_` identifier for discard (AstGen.zig:3440-3446). 6109 if (tree->nodes.tags[lhs] == AST_NODE_IDENTIFIER) { 6110 uint32_t ident_tok = tree->nodes.main_tokens[lhs]; 6111 uint32_t tok_start = tree->tokens.starts[ident_tok]; 6112 if (tree->source[tok_start] == '_' 6113 && (tok_start + 1 >= tree->source_len 6114 || !((tree->source[tok_start + 1] >= 'a' 6115 && tree->source[tok_start + 1] <= 'z') 6116 || (tree->source[tok_start + 1] >= 'A' 6117 && tree->source[tok_start + 1] <= 'Z') 6118 || tree->source[tok_start + 1] == '_' 6119 || (tree->source[tok_start + 1] >= '0' 6120 && tree->source[tok_start + 1] <= '9')))) { 6121 // Discard: evaluate RHS with .discard result location. 6122 uint32_t result = expr(gz, scope, rhs); 6123 rvalueDiscard(gz, result, rhs); 6124 return; 6125 } 6126 } 6127 6128 // Non-discard assignment: evaluate LHS as lvalue, pass ptr rl to RHS. 6129 // (AstGen.zig:3448-3452). 6130 { 6131 uint32_t lhs_ptr = exprRl(gz, scope, RL_REF_VAL, lhs); 6132 ResultLoc ptr_rl 6133 = { .tag = RL_PTR, .data = lhs_ptr, .src_node = infix_node }; 6134 (void)exprRl(gz, scope, ptr_rl, rhs); 6135 } 6136 } 6137 6138 // --- assignOp (AstGen.zig:3731) --- 6139 // Handles compound assignment operators (+=, -=, *=, etc.). 6140 6141 static void assignOp( 6142 GenZir* gz, Scope* scope, uint32_t infix_node, ZirInstTag op_tag) { 6143 emitDbgNode(gz, infix_node); 6144 AstGenCtx* ag = gz->astgen; 6145 const Ast* tree = ag->tree; 6146 6147 AstData nd = tree->nodes.datas[infix_node]; 6148 uint32_t lhs_node = nd.lhs; 6149 uint32_t rhs_node = nd.rhs; 6150 6151 // Evaluate LHS as lvalue pointer (AstGen.zig:3742). 6152 uint32_t lhs_ptr = exprRl(gz, scope, RL_REF_VAL, lhs_node); 6153 6154 // Advance cursor for add/sub/mul/div/mod_rem (AstGen.zig:3744-3747). 6155 uint32_t cursor_line = 0, cursor_col = 0; 6156 bool need_dbg = false; 6157 if (op_tag == ZIR_INST_ADD || op_tag == ZIR_INST_SUB 6158 || op_tag == ZIR_INST_MUL || op_tag == ZIR_INST_DIV 6159 || op_tag == ZIR_INST_MOD_REM) { 6160 if (!gz->is_comptime) { 6161 advanceSourceCursorToMainToken(ag, gz, infix_node); 6162 } 6163 cursor_line = ag->source_line - gz->decl_line; 6164 cursor_col = ag->source_column; 6165 need_dbg = true; 6166 } 6167 6168 // Load current value (AstGen.zig:3748). 6169 uint32_t lhs = addUnNode(gz, ZIR_INST_LOAD, lhs_ptr, infix_node); 6170 6171 // Determine RHS result type (AstGen.zig:3750-3766). 6172 uint32_t rhs_res_ty; 6173 if (op_tag == ZIR_INST_ADD || op_tag == ZIR_INST_SUB) { 6174 // Emit inplace_arith_result_ty extended instruction. 6175 uint16_t inplace_op 6176 = (op_tag == ZIR_INST_ADD) ? 0 : 1; // add_eq=0, sub_eq=1 6177 ZirInstData ext_data; 6178 memset(&ext_data, 0, sizeof(ext_data)); 6179 ext_data.extended.opcode = (uint16_t)ZIR_EXT_INPLACE_ARITH_RESULT_TY; 6180 ext_data.extended.small = inplace_op; 6181 ext_data.extended.operand = lhs; 6182 rhs_res_ty = addInstruction(gz, ZIR_INST_EXTENDED, ext_data); 6183 } else { 6184 rhs_res_ty = addUnNode(gz, ZIR_INST_TYPEOF, lhs, infix_node); 6185 } 6186 6187 // Evaluate RHS with type coercion (AstGen.zig:3768). 6188 uint32_t rhs_raw = expr(gz, scope, rhs_node); 6189 uint32_t rhs 6190 = addPlNodeBin(gz, ZIR_INST_AS_NODE, rhs_node, rhs_res_ty, rhs_raw); 6191 6192 // Emit debug statement for arithmetic ops (AstGen.zig:3770-3775). 6193 if (need_dbg) { 6194 emitDbgStmt(gz, cursor_line, cursor_col); 6195 } 6196 6197 // Emit the operation (AstGen.zig:3776-3779). 6198 uint32_t result = addPlNodeBin(gz, op_tag, infix_node, lhs, rhs); 6199 6200 // Store result back (AstGen.zig:3780-3783). 6201 addPlNodeBin(gz, ZIR_INST_STORE_NODE, infix_node, lhs_ptr, result); 6202 } 6203 6204 // --- builtinEvalToError (BuiltinFn.zig) --- 6205 // Returns per-builtin eval_to_error. Default is .never; only a few are 6206 // .maybe or .always. Mirrors BuiltinFn.list lookup in AstGen.zig:10539. 6207 static int builtinEvalToError(const Ast* tree, uint32_t node) { 6208 uint32_t main_tok = tree->nodes.main_tokens[node]; 6209 uint32_t tok_start = tree->tokens.starts[main_tok]; 6210 const char* source = tree->source; 6211 uint32_t name_start = tok_start + 1; // skip '@' 6212 uint32_t name_end = name_start; 6213 while (name_end < tree->source_len 6214 && ((source[name_end] >= 'a' && source[name_end] <= 'z') 6215 || (source[name_end] >= 'A' && source[name_end] <= 'Z') 6216 || source[name_end] == '_')) { 6217 name_end++; 6218 } 6219 uint32_t name_len = name_end - name_start; 6220 const char* name = source + name_start; 6221 // clang-format off 6222 // .always: 6223 if (name_len == 12 && memcmp(name, "errorFromInt", 12) == 0) 6224 return 1; // EVAL_TO_ERROR_ALWAYS 6225 // .maybe: 6226 if (name_len == 2 && memcmp(name, "as", 2) == 0) return 2; 6227 if (name_len == 4 && memcmp(name, "call", 4) == 0) return 2; 6228 if (name_len == 5 && memcmp(name, "field", 5) == 0) return 2; 6229 if (name_len == 9 && memcmp(name, "errorCast", 9) == 0) return 2; 6230 // clang-format on 6231 // Default: .never 6232 return 0; 6233 } 6234 6235 // --- nodeMayEvalToError (AstGen.zig:10340) --- 6236 // Three-way result: 0=never, 1=always, 2=maybe. 6237 #define EVAL_TO_ERROR_NEVER 0 6238 #define EVAL_TO_ERROR_ALWAYS 1 6239 #define EVAL_TO_ERROR_MAYBE 2 6240 6241 static int nodeMayEvalToError(const Ast* tree, uint32_t node) { 6242 uint32_t n = node; 6243 while (true) { 6244 AstNodeTag tag = tree->nodes.tags[n]; 6245 switch (tag) { 6246 case AST_NODE_ERROR_VALUE: 6247 return EVAL_TO_ERROR_ALWAYS; 6248 // These may evaluate to errors. 6249 case AST_NODE_IDENTIFIER: 6250 case AST_NODE_FIELD_ACCESS: 6251 case AST_NODE_DEREF: 6252 case AST_NODE_ARRAY_ACCESS: 6253 case AST_NODE_WHILE_SIMPLE: 6254 case AST_NODE_WHILE_CONT: 6255 case AST_NODE_WHILE: 6256 case AST_NODE_FOR_SIMPLE: 6257 case AST_NODE_FOR: 6258 case AST_NODE_IF_SIMPLE: 6259 case AST_NODE_IF: 6260 case AST_NODE_SWITCH: 6261 case AST_NODE_SWITCH_COMMA: 6262 case AST_NODE_CALL_ONE: 6263 case AST_NODE_CALL_ONE_COMMA: 6264 case AST_NODE_CALL: 6265 case AST_NODE_CALL_COMMA: 6266 case AST_NODE_ASM_SIMPLE: 6267 case AST_NODE_ASM_LEGACY: 6268 case AST_NODE_ASM: 6269 case AST_NODE_CATCH: 6270 case AST_NODE_ORELSE: 6271 return EVAL_TO_ERROR_MAYBE; 6272 // Forward to sub-expression. 6273 case AST_NODE_TRY: 6274 case AST_NODE_COMPTIME: 6275 case AST_NODE_NOSUSPEND: 6276 n = tree->nodes.datas[n].lhs; 6277 continue; 6278 case AST_NODE_GROUPED_EXPRESSION: 6279 case AST_NODE_UNWRAP_OPTIONAL: 6280 n = tree->nodes.datas[n].lhs; 6281 continue; 6282 // Labeled blocks may need a memory location. 6283 case AST_NODE_BLOCK_TWO: 6284 case AST_NODE_BLOCK_TWO_SEMICOLON: 6285 case AST_NODE_BLOCK: 6286 case AST_NODE_BLOCK_SEMICOLON: { 6287 uint32_t lbrace = tree->nodes.main_tokens[n]; 6288 if (lbrace > 0 && tree->tokens.tags[lbrace - 1] == TOKEN_COLON) 6289 return EVAL_TO_ERROR_MAYBE; 6290 return EVAL_TO_ERROR_NEVER; 6291 } 6292 // Builtins: look up per-builtin eval_to_error 6293 // (AstGen.zig:10530-10541). 6294 case AST_NODE_BUILTIN_CALL: 6295 case AST_NODE_BUILTIN_CALL_COMMA: 6296 case AST_NODE_BUILTIN_CALL_TWO: 6297 case AST_NODE_BUILTIN_CALL_TWO_COMMA: 6298 return builtinEvalToError(tree, n); 6299 // Everything else: .never 6300 default: 6301 return EVAL_TO_ERROR_NEVER; 6302 } 6303 } 6304 } 6305 6306 // --- nodeMayAppendToErrorTrace (AstGen.zig:10315) --- 6307 // Returns true if the expression may append to the error return trace. 6308 static bool nodeMayAppendToErrorTrace(const Ast* tree, uint32_t node) { 6309 uint32_t n = node; 6310 while (true) { 6311 AstNodeTag tag = tree->nodes.tags[n]; 6312 switch (tag) { 6313 // These don't call runtime functions. 6314 case AST_NODE_ERROR_VALUE: 6315 case AST_NODE_IDENTIFIER: 6316 case AST_NODE_COMPTIME: 6317 return false; 6318 // Forward to sub-expression. 6319 case AST_NODE_TRY: 6320 case AST_NODE_NOSUSPEND: 6321 n = tree->nodes.datas[n].lhs; 6322 continue; 6323 case AST_NODE_GROUPED_EXPRESSION: 6324 case AST_NODE_UNWRAP_OPTIONAL: 6325 n = tree->nodes.datas[n].lhs; 6326 continue; 6327 // Anything else: check if it may eval to error. 6328 default: 6329 return nodeMayEvalToError(tree, n) != EVAL_TO_ERROR_NEVER; 6330 } 6331 } 6332 } 6333 6334 // --- addSaveErrRetIndex (AstGen.zig:12556) --- 6335 // Emits SAVE_ERR_RET_INDEX instruction. 6336 // operand is the init inst ref (or ZIR_REF_NONE for .always). 6337 static void addSaveErrRetIndex(GenZir* gz, uint32_t operand) { 6338 ZirInstData data; 6339 data.save_err_ret_index.operand = operand; 6340 data.save_err_ret_index._pad = 0; 6341 addInstruction(gz, ZIR_INST_SAVE_ERR_RET_INDEX, data); 6342 } 6343 6344 // --- addRestoreErrRetIndexBlock (AstGen.zig:12607-12614) --- 6345 // Emits extended RESTORE_ERR_RET_INDEX with block target (if_non_error 6346 // condition). Payload: src_node, block_ref, operand. 6347 static void addRestoreErrRetIndexBlock( 6348 GenZir* gz, uint32_t block_inst, uint32_t operand, uint32_t node) { 6349 AstGenCtx* ag = gz->astgen; 6350 ensureExtraCapacity(ag, 3); 6351 uint32_t payload_index = ag->extra_len; 6352 ag->extra[ag->extra_len++] 6353 = (uint32_t)((int32_t)node - (int32_t)gz->decl_node_index); 6354 ag->extra[ag->extra_len++] = block_inst + ZIR_REF_START_INDEX; 6355 ag->extra[ag->extra_len++] = operand; 6356 6357 ZirInstData ext_data; 6358 ext_data.extended.opcode = (uint16_t)ZIR_EXT_RESTORE_ERR_RET_INDEX; 6359 ext_data.extended.small = 0; 6360 ext_data.extended.operand = payload_index; 6361 addInstruction(gz, ZIR_INST_EXTENDED, ext_data); 6362 } 6363 6364 // --- restoreErrRetIndex (AstGen.zig:2121-2148) --- 6365 // Emits restore_err_ret_index for block target based on nodeMayEvalToError. 6366 static void restoreErrRetIndex(GenZir* gz, uint32_t block_inst, ResultLoc rl, 6367 uint32_t node, uint32_t result) { 6368 const Ast* tree = gz->astgen->tree; 6369 int eval = nodeMayEvalToError(tree, node); 6370 if (eval == EVAL_TO_ERROR_ALWAYS) 6371 return; // never restore/pop 6372 uint32_t op; 6373 if (eval == EVAL_TO_ERROR_NEVER) { 6374 op = ZIR_REF_NONE; // always restore/pop 6375 } else { 6376 // EVAL_TO_ERROR_MAYBE 6377 // Simplified: without ri.ctx, treat non-ptr RL as result 6378 // (AstGen.zig:2131-2144). 6379 if (rl.tag == RL_PTR) { 6380 op = addUnNode(gz, ZIR_INST_LOAD, rl.data, node); 6381 } else if (rl.tag == RL_INFERRED_PTR) { 6382 op = ZIR_REF_NONE; 6383 } else { 6384 op = result; 6385 } 6386 } 6387 addRestoreErrRetIndexBlock(gz, block_inst, op, node); 6388 } 6389 6390 // --- varDecl (AstGen.zig:3189) --- 6391 // Handles local const/var declarations. Returns new scope with the variable. 6392 // scope_out: set to new scope if variable is added; unchanged otherwise. 6393 6394 static void varDecl(GenZir* gz, Scope* scope, uint32_t node, 6395 ScopeLocalVal* val_out, ScopeLocalPtr* ptr_out, Scope** scope_out) { 6396 AstGenCtx* ag = gz->astgen; 6397 emitDbgNode(gz, node); // AstGen.zig:3196 6398 const Ast* tree = ag->tree; 6399 AstData nd = tree->nodes.datas[node]; 6400 AstNodeTag tag = tree->nodes.tags[node]; 6401 6402 uint32_t mut_token = tree->nodes.main_tokens[node]; 6403 uint32_t name_token = mut_token + 1; 6404 bool is_const = (tree->source[tree->tokens.starts[mut_token]] == 'c'); 6405 6406 uint32_t ident_name = identAsString(ag, name_token); 6407 6408 // Extract type_node and init_node based on variant. 6409 uint32_t type_node = 0; 6410 uint32_t init_node = 0; 6411 6412 if (tag == AST_NODE_SIMPLE_VAR_DECL) { 6413 // lhs = type (optional), rhs = init (optional). 6414 type_node = nd.lhs; 6415 init_node = nd.rhs; 6416 } else if (tag == AST_NODE_LOCAL_VAR_DECL) { 6417 // lhs = extra_data index, rhs = init. 6418 // extra: {type_node, align_node, addrspace_node, section_node} 6419 // Simplified: just extract type_node. 6420 uint32_t extra_idx = nd.lhs; 6421 type_node = tree->extra_data.arr[extra_idx]; // type_node 6422 init_node = nd.rhs; 6423 } else if (tag == AST_NODE_ALIGNED_VAR_DECL) { 6424 // lhs = align expr, rhs = init. 6425 // No type node in this variant. 6426 init_node = nd.rhs; 6427 } else { 6428 // global_var_decl or unknown — bail. 6429 SET_ERROR(ag); 6430 return; 6431 } 6432 6433 if (init_node == 0) { 6434 // Variables must be initialized (AstGen.zig:3228). 6435 SET_ERROR(ag); 6436 return; 6437 } 6438 6439 if (is_const) { 6440 // --- CONST path (AstGen.zig:3232-3340) --- 6441 if (!nodesNeedRlContains(ag, node)) { 6442 // Rvalue path (AstGen.zig:3246-3271). 6443 // Evaluate type annotation and build result_info 6444 // (AstGen.zig:3247-3250). 6445 ResultLoc result_info; 6446 if (type_node != 0) { 6447 uint32_t type_ref = typeExpr(gz, scope, type_node); 6448 result_info = (ResultLoc) { .tag = RL_TY, 6449 .data = type_ref, 6450 .src_node = 0, 6451 .ctx = RI_CTX_CONST_INIT }; 6452 } else { 6453 result_info = (ResultLoc) { .tag = RL_NONE, 6454 .data = 0, 6455 .src_node = 0, 6456 .ctx = RI_CTX_CONST_INIT }; 6457 } 6458 6459 // Evaluate init expression (AstGen.zig:3251-3252). 6460 uint32_t init_ref = exprRl(gz, scope, result_info, init_node); 6461 6462 if (ag->has_compile_errors) 6463 return; 6464 6465 // validate_const (AstGen.zig:3266). 6466 addUnNode(gz, ZIR_INST_VALIDATE_CONST, init_ref, init_node); 6467 6468 // dbg_var_val (AstGen.zig:3269). 6469 addDbgVar(gz, ZIR_INST_DBG_VAR_VAL, ident_name, init_ref); 6470 6471 // save_err_ret_index (AstGen.zig:3259-3260). 6472 if (nodeMayAppendToErrorTrace(tree, init_node)) 6473 addSaveErrRetIndex(gz, init_ref); 6474 6475 // Create ScopeLocalVal (AstGen.zig:3276-3284). 6476 val_out->base.tag = SCOPE_LOCAL_VAL; 6477 val_out->parent = *scope_out; 6478 val_out->gen_zir = gz; 6479 val_out->inst = init_ref; 6480 val_out->token_src = name_token; 6481 val_out->name = ident_name; 6482 *scope_out = &val_out->base; 6483 } else { 6484 // Alloc path (AstGen.zig:3277-3340). 6485 // The init expression needs a result pointer (nodes_need_rl). 6486 bool is_comptime_init = gz->is_comptime 6487 || tree->nodes.tags[init_node] == AST_NODE_COMPTIME; 6488 6489 uint32_t var_ptr; 6490 bool resolve_inferred; 6491 6492 if (type_node != 0) { 6493 // Typed const: alloc (AstGen.zig:3280). 6494 uint32_t type_ref = typeExpr(gz, scope, type_node); 6495 var_ptr = addUnNode(gz, ZIR_INST_ALLOC, type_ref, node); 6496 resolve_inferred = false; 6497 } else { 6498 // Inferred type: alloc_inferred (AstGen.zig:3291-3296). 6499 ZirInstTag alloc_tag = is_comptime_init 6500 ? ZIR_INST_ALLOC_INFERRED_COMPTIME 6501 : ZIR_INST_ALLOC_INFERRED; 6502 ZirInstData adata; 6503 adata.node = (int32_t)node - (int32_t)gz->decl_node_index; 6504 var_ptr = addInstruction(gz, alloc_tag, adata); 6505 resolve_inferred = true; 6506 } 6507 6508 // Evaluate init with RL pointing to alloc (AstGen.zig:3313-3316). 6509 ResultLoc init_rl; 6510 if (type_node != 0) { 6511 init_rl.tag = RL_PTR; 6512 init_rl.data = var_ptr; 6513 init_rl.src_node = 0; // upstream: .none (PtrResultLoc.src_node 6514 // defaults to null) 6515 } else { 6516 init_rl.tag = RL_INFERRED_PTR; 6517 init_rl.data = var_ptr; 6518 init_rl.src_node = 0; 6519 } 6520 init_rl.ctx = RI_CTX_CONST_INIT; 6521 uint32_t init_ref = exprRl(gz, scope, init_rl, init_node); 6522 6523 if (ag->has_compile_errors) 6524 return; 6525 6526 // save_err_ret_index (AstGen.zig:3320-3321). 6527 if (nodeMayAppendToErrorTrace(tree, init_node)) 6528 addSaveErrRetIndex(gz, init_ref); 6529 6530 // resolve_inferred_alloc or make_ptr_const (AstGen.zig:3323-3326). 6531 uint32_t const_ptr; 6532 if (resolve_inferred) 6533 const_ptr = addUnNode( 6534 gz, ZIR_INST_RESOLVE_INFERRED_ALLOC, var_ptr, node); 6535 else 6536 const_ptr 6537 = addUnNode(gz, ZIR_INST_MAKE_PTR_CONST, var_ptr, node); 6538 6539 // dbg_var_ptr (AstGen.zig:3328). 6540 addDbgVar(gz, ZIR_INST_DBG_VAR_PTR, ident_name, const_ptr); 6541 6542 // Create ScopeLocalPtr (AstGen.zig:3330-3340). 6543 ptr_out->base.tag = SCOPE_LOCAL_PTR; 6544 ptr_out->parent = *scope_out; 6545 ptr_out->gen_zir = gz; 6546 ptr_out->ptr = const_ptr; 6547 ptr_out->token_src = name_token; 6548 ptr_out->name = ident_name; 6549 ptr_out->maybe_comptime = true; 6550 *scope_out = &ptr_out->base; 6551 } 6552 } else { 6553 // --- VAR path (AstGen.zig:3342-3416) --- 6554 6555 uint32_t alloc_ref; 6556 bool resolve_inferred = false; 6557 6558 if (type_node != 0) { 6559 // Typed var: alloc_mut (AstGen.zig:3361-3375). 6560 uint32_t type_ref = typeExpr(gz, scope, type_node); 6561 ZirInstTag alloc_tag = gz->is_comptime 6562 ? ZIR_INST_ALLOC_COMPTIME_MUT 6563 : ZIR_INST_ALLOC_MUT; 6564 alloc_ref = addUnNode(gz, alloc_tag, type_ref, node); 6565 } else { 6566 // Inferred type var: alloc_inferred_mut 6567 // (AstGen.zig:3384-3392). 6568 ZirInstTag alloc_tag = gz->is_comptime 6569 ? ZIR_INST_ALLOC_INFERRED_COMPTIME_MUT 6570 : ZIR_INST_ALLOC_INFERRED_MUT; 6571 ZirInstData adata; 6572 adata.node = (int32_t)node - (int32_t)gz->decl_node_index; 6573 alloc_ref = addInstruction(gz, alloc_tag, adata); 6574 resolve_inferred = true; 6575 } 6576 6577 // Evaluate init with RL pointing to alloc (AstGen.zig:3395-3402). 6578 ResultLoc var_init_rl; 6579 if (type_node != 0) { 6580 var_init_rl.tag = RL_PTR; 6581 var_init_rl.data = alloc_ref; 6582 var_init_rl.src_node = 0; // upstream: .none (PtrResultLoc.src_node 6583 // defaults to null) 6584 } else { 6585 var_init_rl.tag = RL_INFERRED_PTR; 6586 var_init_rl.data = alloc_ref; 6587 var_init_rl.src_node = 0; 6588 } 6589 var_init_rl.ctx = RI_CTX_NONE; 6590 uint32_t init_ref = exprRl(gz, scope, var_init_rl, init_node); 6591 (void)init_ref; 6592 6593 if (ag->has_compile_errors) 6594 return; 6595 6596 // resolve_inferred_alloc if type was inferred 6597 // (AstGen.zig:3407-3408). 6598 uint32_t final_ptr = alloc_ref; 6599 if (resolve_inferred) 6600 final_ptr = addUnNode( 6601 gz, ZIR_INST_RESOLVE_INFERRED_ALLOC, alloc_ref, node); 6602 6603 // dbg_var_ptr (AstGen.zig:3411). 6604 addDbgVar(gz, ZIR_INST_DBG_VAR_PTR, ident_name, final_ptr); 6605 6606 // Create ScopeLocalPtr (AstGen.zig:3413-3422). 6607 ptr_out->base.tag = SCOPE_LOCAL_PTR; 6608 ptr_out->parent = *scope_out; 6609 ptr_out->gen_zir = gz; 6610 ptr_out->ptr = final_ptr; 6611 ptr_out->token_src = name_token; 6612 ptr_out->name = ident_name; 6613 ptr_out->maybe_comptime = gz->is_comptime; 6614 *scope_out = &ptr_out->base; 6615 } 6616 } 6617 6618 // --- addEnsureResult (AstGen.zig:2649) --- 6619 // After evaluating an expression as a statement, optionally emits 6620 // ensure_result_used. For call/field_call, sets flag in extra data instead. 6621 // Returns true if the result is noreturn (AstGen.zig:2909). 6622 static bool addEnsureResult( 6623 GenZir* gz, uint32_t maybe_unused_result, uint32_t statement) { 6624 AstGenCtx* ag = gz->astgen; 6625 bool elide_check; 6626 bool is_noreturn = false; 6627 if (maybe_unused_result >= ZIR_REF_START_INDEX) { 6628 uint32_t inst = maybe_unused_result - ZIR_REF_START_INDEX; 6629 ZirInstTag tag = ag->inst_tags[inst]; 6630 switch (tag) { 6631 // For call/field_call: set ensure_result_used flag 6632 // (bit 3 of flags at offset 0). Flags *must* be at offset 0 6633 // (AstGen.zig:2658-2665, Zir.zig:3022). 6634 case ZIR_INST_CALL: 6635 case ZIR_INST_FIELD_CALL: { 6636 uint32_t pi = ag->inst_datas[inst].pl_node.payload_index; 6637 ag->extra[pi] |= (1u << 3); // ensure_result_used 6638 elide_check = true; 6639 break; 6640 } 6641 // For builtin_call: ensure_result_used is at bit 1, not bit 3. 6642 case ZIR_INST_BUILTIN_CALL: { 6643 uint32_t pi = ag->inst_datas[inst].pl_node.payload_index; 6644 ag->extra[pi] |= (1u << 1); // ensure_result_used 6645 elide_check = true; 6646 break; 6647 } 6648 // Always noreturn → elide (AstGen.zig:2909). 6649 case ZIR_INST_BREAK: 6650 case ZIR_INST_BREAK_INLINE: 6651 case ZIR_INST_CONDBR: 6652 case ZIR_INST_CONDBR_INLINE: 6653 case ZIR_INST_RET_NODE: 6654 case ZIR_INST_RET_LOAD: 6655 case ZIR_INST_RET_IMPLICIT: 6656 case ZIR_INST_RET_ERR_VALUE: 6657 case ZIR_INST_UNREACHABLE: 6658 case ZIR_INST_REPEAT: 6659 case ZIR_INST_REPEAT_INLINE: 6660 case ZIR_INST_PANIC: 6661 case ZIR_INST_TRAP: 6662 case ZIR_INST_CHECK_COMPTIME_CONTROL_FLOW: 6663 case ZIR_INST_SWITCH_CONTINUE: 6664 case ZIR_INST_COMPILE_ERROR: 6665 is_noreturn = true; 6666 elide_check = true; 6667 break; 6668 // Always void → elide. 6669 case ZIR_INST_DBG_STMT: 6670 case ZIR_INST_DBG_VAR_PTR: 6671 case ZIR_INST_DBG_VAR_VAL: 6672 case ZIR_INST_ENSURE_RESULT_USED: 6673 case ZIR_INST_ENSURE_RESULT_NON_ERROR: 6674 case ZIR_INST_ENSURE_ERR_UNION_PAYLOAD_VOID: 6675 case ZIR_INST_EXPORT: 6676 case ZIR_INST_SET_EVAL_BRANCH_QUOTA: 6677 case ZIR_INST_ATOMIC_STORE: 6678 case ZIR_INST_STORE_NODE: 6679 case ZIR_INST_STORE_TO_INFERRED_PTR: 6680 case ZIR_INST_RESOLVE_INFERRED_ALLOC: 6681 case ZIR_INST_SET_RUNTIME_SAFETY: 6682 case ZIR_INST_MEMCPY: 6683 case ZIR_INST_MEMSET: 6684 case ZIR_INST_MEMMOVE: 6685 case ZIR_INST_VALIDATE_DEREF: 6686 case ZIR_INST_VALIDATE_DESTRUCTURE: 6687 case ZIR_INST_SAVE_ERR_RET_INDEX: 6688 case ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL: 6689 case ZIR_INST_RESTORE_ERR_RET_INDEX_FN_ENTRY: 6690 case ZIR_INST_VALIDATE_STRUCT_INIT_TY: 6691 case ZIR_INST_VALIDATE_STRUCT_INIT_RESULT_TY: 6692 case ZIR_INST_VALIDATE_PTR_STRUCT_INIT: 6693 case ZIR_INST_VALIDATE_ARRAY_INIT_TY: 6694 case ZIR_INST_VALIDATE_ARRAY_INIT_RESULT_TY: 6695 case ZIR_INST_VALIDATE_PTR_ARRAY_INIT: 6696 case ZIR_INST_VALIDATE_REF_TY: 6697 case ZIR_INST_VALIDATE_CONST: 6698 elide_check = true; 6699 break; 6700 // Extended: check opcode. 6701 case ZIR_INST_EXTENDED: { 6702 uint32_t opcode = ag->inst_datas[inst].extended.opcode; 6703 elide_check = (opcode == ZIR_EXT_BREAKPOINT 6704 || opcode == ZIR_EXT_BRANCH_HINT 6705 || opcode == ZIR_EXT_SET_FLOAT_MODE 6706 || opcode == ZIR_EXT_DISABLE_INSTRUMENTATION 6707 || opcode == ZIR_EXT_DISABLE_INTRINSICS); 6708 break; 6709 } 6710 // Everything else: might produce non-void result → emit check. 6711 default: 6712 elide_check = false; 6713 break; 6714 } 6715 } else { 6716 // Named ref constant. 6717 is_noreturn = (maybe_unused_result == ZIR_REF_UNREACHABLE_VALUE); 6718 elide_check 6719 = (is_noreturn || maybe_unused_result == ZIR_REF_VOID_VALUE); 6720 } 6721 if (!elide_check) { 6722 addUnNode( 6723 gz, ZIR_INST_ENSURE_RESULT_USED, maybe_unused_result, statement); 6724 } 6725 return is_noreturn; 6726 } 6727 6728 // --- countDefers (AstGen.zig:2966) --- 6729 // Walk scope chain and count defer types. 6730 6731 static DeferCounts countDefers(const Scope* outer_scope, Scope* inner_scope) { 6732 DeferCounts c = { false, false, false, false }; 6733 Scope* s = inner_scope; 6734 while (s != outer_scope) { 6735 switch (s->tag) { 6736 case SCOPE_GEN_ZIR: 6737 s = ((GenZir*)s)->parent; 6738 break; 6739 case SCOPE_LOCAL_VAL: 6740 s = ((ScopeLocalVal*)s)->parent; 6741 break; 6742 case SCOPE_LOCAL_PTR: 6743 s = ((ScopeLocalPtr*)s)->parent; 6744 break; 6745 case SCOPE_DEFER_NORMAL: { 6746 ScopeDefer* d = (ScopeDefer*)s; 6747 s = d->parent; 6748 c.have_normal = true; 6749 break; 6750 } 6751 case SCOPE_DEFER_ERROR: { 6752 ScopeDefer* d = (ScopeDefer*)s; 6753 s = d->parent; 6754 c.have_err = true; 6755 // need_err_code if remapped_err_code exists (we don't 6756 // implement err capture yet, so always false). 6757 break; 6758 } 6759 default: 6760 return c; 6761 } 6762 } 6763 c.have_any = c.have_normal || c.have_err; 6764 return c; 6765 } 6766 6767 // --- genDefers (AstGen.zig:3014) --- 6768 // Walk scope chain from inner to outer, emitting .defer instructions. 6769 // which: DEFER_NORMAL_ONLY or DEFER_BOTH_SANS_ERR. 6770 6771 static void genDefers( 6772 GenZir* gz, const Scope* outer_scope, Scope* inner_scope, int which) { 6773 Scope* s = inner_scope; 6774 while (s != outer_scope) { 6775 switch (s->tag) { 6776 case SCOPE_GEN_ZIR: { 6777 GenZir* g = (GenZir*)s; 6778 s = g->parent; 6779 break; 6780 } 6781 case SCOPE_LOCAL_VAL: { 6782 ScopeLocalVal* lv = (ScopeLocalVal*)s; 6783 s = lv->parent; 6784 break; 6785 } 6786 case SCOPE_LOCAL_PTR: { 6787 ScopeLocalPtr* lp = (ScopeLocalPtr*)s; 6788 s = lp->parent; 6789 break; 6790 } 6791 case SCOPE_DEFER_NORMAL: { 6792 ScopeDefer* d = (ScopeDefer*)s; 6793 s = d->parent; 6794 // Emit ZIR_INST_DEFER (AstGen.zig:3031). 6795 ZirInstData data; 6796 data.defer_data.index = d->index; 6797 data.defer_data.len = d->len; 6798 addInstruction(gz, ZIR_INST_DEFER, data); 6799 break; 6800 } 6801 case SCOPE_DEFER_ERROR: { 6802 ScopeDefer* d = (ScopeDefer*)s; 6803 s = d->parent; 6804 if (which == DEFER_BOTH_SANS_ERR) { 6805 // Emit regular DEFER for error defers too (AstGen.zig:3038). 6806 ZirInstData data; 6807 data.defer_data.index = d->index; 6808 data.defer_data.len = d->len; 6809 addInstruction(gz, ZIR_INST_DEFER, data); 6810 } 6811 // DEFER_NORMAL_ONLY: skip error defers (AstGen.zig:3063). 6812 break; 6813 } 6814 case SCOPE_LABEL: { 6815 // Labels store parent in the GenZir they're attached to. 6816 // Just skip by going to the parent scope stored in parent. 6817 // Actually labels don't have a separate parent pointer in our 6818 // representation; they're part of GenZir. This case shouldn't 6819 // appear when walking from blockExprStmts scope. 6820 return; 6821 } 6822 case SCOPE_NAMESPACE: 6823 case SCOPE_TOP: 6824 default: 6825 return; 6826 } 6827 } 6828 } 6829 6830 // --- blockExprStmts (AstGen.zig:2538) --- 6831 // Processes block statements sequentially, threading scope. 6832 6833 static void blockExprStmts(GenZir* gz, Scope* scope, 6834 const uint32_t* statements, uint32_t stmt_count) { 6835 AstGenCtx* ag = gz->astgen; 6836 // Stack-allocated scope storage for local variables and defers. 6837 // Max 64 local variable declarations and 64 defers per block. 6838 ScopeLocalVal val_scopes[64]; 6839 ScopeLocalPtr ptr_scopes[64]; 6840 ScopeDefer defer_scopes[64]; 6841 uint32_t val_idx = 0; 6842 uint32_t ptr_idx = 0; 6843 uint32_t defer_idx = 0; 6844 Scope* cur_scope = scope; 6845 bool noreturn_stmt = false; 6846 6847 for (uint32_t i = 0; i < stmt_count; i++) { 6848 if (ag->has_compile_errors) 6849 return; 6850 uint32_t stmt = statements[i]; 6851 AstNodeTag tag = ag->tree->nodes.tags[stmt]; 6852 switch (tag) { 6853 case AST_NODE_ASSIGN: 6854 assignStmt(gz, cur_scope, stmt); 6855 break; 6856 // Compound assignment operators (AstGen.zig:2588-2607). 6857 case AST_NODE_ASSIGN_ADD: 6858 assignOp(gz, cur_scope, stmt, ZIR_INST_ADD); 6859 break; 6860 case AST_NODE_ASSIGN_SUB: 6861 assignOp(gz, cur_scope, stmt, ZIR_INST_SUB); 6862 break; 6863 case AST_NODE_ASSIGN_MUL: 6864 assignOp(gz, cur_scope, stmt, ZIR_INST_MUL); 6865 break; 6866 case AST_NODE_ASSIGN_DIV: 6867 assignOp(gz, cur_scope, stmt, ZIR_INST_DIV); 6868 break; 6869 case AST_NODE_ASSIGN_MOD: 6870 assignOp(gz, cur_scope, stmt, ZIR_INST_MOD_REM); 6871 break; 6872 case AST_NODE_ASSIGN_BIT_AND: 6873 assignOp(gz, cur_scope, stmt, ZIR_INST_BIT_AND); 6874 break; 6875 case AST_NODE_ASSIGN_BIT_OR: 6876 assignOp(gz, cur_scope, stmt, ZIR_INST_BIT_OR); 6877 break; 6878 case AST_NODE_ASSIGN_BIT_XOR: 6879 assignOp(gz, cur_scope, stmt, ZIR_INST_XOR); 6880 break; 6881 case AST_NODE_ASSIGN_ADD_WRAP: 6882 assignOp(gz, cur_scope, stmt, ZIR_INST_ADDWRAP); 6883 break; 6884 case AST_NODE_ASSIGN_SUB_WRAP: 6885 assignOp(gz, cur_scope, stmt, ZIR_INST_SUBWRAP); 6886 break; 6887 case AST_NODE_ASSIGN_MUL_WRAP: 6888 assignOp(gz, cur_scope, stmt, ZIR_INST_MULWRAP); 6889 break; 6890 case AST_NODE_ASSIGN_ADD_SAT: 6891 assignOp(gz, cur_scope, stmt, ZIR_INST_ADD_SAT); 6892 break; 6893 case AST_NODE_ASSIGN_SUB_SAT: 6894 assignOp(gz, cur_scope, stmt, ZIR_INST_SUB_SAT); 6895 break; 6896 case AST_NODE_ASSIGN_MUL_SAT: 6897 assignOp(gz, cur_scope, stmt, ZIR_INST_MUL_SAT); 6898 break; 6899 case AST_NODE_SIMPLE_VAR_DECL: 6900 case AST_NODE_LOCAL_VAR_DECL: 6901 case AST_NODE_ALIGNED_VAR_DECL: 6902 if (val_idx < 64 && ptr_idx < 64) { 6903 varDecl(gz, cur_scope, stmt, &val_scopes[val_idx], 6904 &ptr_scopes[ptr_idx], &cur_scope); 6905 // Check which one was used: if scope now points to 6906 // val_scopes[val_idx], advance val_idx; same for ptr. 6907 if (cur_scope == &val_scopes[val_idx].base) 6908 val_idx++; 6909 else if (cur_scope == &ptr_scopes[ptr_idx].base) 6910 ptr_idx++; 6911 } else { 6912 SET_ERROR(ag); 6913 } 6914 break; 6915 // defer/errdefer (AstGen.zig:2580-2581). 6916 case AST_NODE_DEFER: 6917 case AST_NODE_ERRDEFER: { 6918 if (defer_idx >= 64) { 6919 SET_ERROR(ag); 6920 break; 6921 } 6922 ScopeTag scope_tag = (tag == AST_NODE_DEFER) ? SCOPE_DEFER_NORMAL 6923 : SCOPE_DEFER_ERROR; 6924 // Create sub-block for defer body (AstGen.zig:3123-3126). 6925 GenZir defer_gen = makeSubBlock(gz, cur_scope); 6926 6927 // Evaluate deferred expression (AstGen.zig:3165). 6928 // DEFER: lhs is the deferred expression, rhs = 0. 6929 // ERRDEFER: lhs is optional error capture token, rhs is expr. 6930 AstData dnd = ag->tree->nodes.datas[stmt]; 6931 uint32_t expr_node; 6932 if (tag == AST_NODE_DEFER) { 6933 expr_node = dnd.lhs; 6934 } else { 6935 expr_node = dnd.rhs; 6936 } 6937 // unusedResultExpr pattern (AstGen.zig:3165, 2641-2646). 6938 emitDbgNode(&defer_gen, expr_node); 6939 uint32_t defer_result 6940 = expr(&defer_gen, &defer_gen.base, expr_node); 6941 addEnsureResult(&defer_gen, defer_result, expr_node); 6942 6943 // Add break_inline at end (AstGen.zig:3167). 6944 addBreak(&defer_gen, ZIR_INST_BREAK_INLINE, 0, ZIR_REF_VOID_VALUE, 6945 AST_NODE_OFFSET_NONE); 6946 6947 // Write body to extra (AstGen.zig:3173-3175). 6948 uint32_t raw_body_len = gzInstructionsLen(&defer_gen); 6949 const uint32_t* body = gzInstructionsSlice(&defer_gen); 6950 uint32_t extra_index = ag->extra_len; 6951 uint32_t fixup_len 6952 = countBodyLenAfterFixups(ag, body, raw_body_len); 6953 ensureExtraCapacity(ag, fixup_len); 6954 for (uint32_t b = 0; b < raw_body_len; b++) 6955 appendPossiblyRefdBodyInst(ag, body[b]); 6956 gzUnstack(&defer_gen); 6957 6958 // Create scope (AstGen.zig:3179-3185). 6959 defer_scopes[defer_idx] = (ScopeDefer) { 6960 .base = { .tag = scope_tag }, 6961 .parent = cur_scope, 6962 .index = extra_index, 6963 .len = fixup_len, 6964 }; 6965 cur_scope = &defer_scopes[defer_idx].base; 6966 defer_idx++; 6967 break; 6968 } 6969 // while/for as statements (AstGen.zig:2605-2610). 6970 // These do NOT get emitDbgNode; they emit their own dbg_stmt. 6971 case AST_NODE_WHILE_SIMPLE: 6972 case AST_NODE_WHILE_CONT: 6973 case AST_NODE_WHILE: 6974 (void)whileExpr(gz, cur_scope, stmt, true); 6975 break; 6976 case AST_NODE_FOR_SIMPLE: 6977 case AST_NODE_FOR: 6978 (void)forExpr(gz, cur_scope, stmt, true); 6979 break; 6980 default: { 6981 // Expression statement (AstGen.zig:2627 unusedResultExpr). 6982 emitDbgNode(gz, stmt); 6983 uint32_t result = expr(gz, cur_scope, stmt); 6984 noreturn_stmt = addEnsureResult(gz, result, stmt); 6985 break; 6986 } 6987 } 6988 } 6989 // Emit normal defers at block exit (AstGen.zig:2633-2634). 6990 if (!noreturn_stmt) { 6991 genDefers(gz, scope, cur_scope, DEFER_NORMAL_ONLY); 6992 } 6993 } 6994 6995 // --- fullBodyExpr (AstGen.zig:2358) --- 6996 // Processes a body expression. If it's an unlabeled block, processes 6997 // statements inline without creating a BLOCK instruction (unlike blockExprExpr 6998 // which wraps in BLOCK). Returns the result ref. 6999 7000 static uint32_t fullBodyExpr( 7001 GenZir* gz, Scope* scope, ResultLoc rl, uint32_t node) { 7002 const Ast* tree = gz->astgen->tree; 7003 AstNodeTag tag = tree->nodes.tags[node]; 7004 7005 // Extract block statements (AstGen.zig:2368). 7006 AstData nd = tree->nodes.datas[node]; 7007 uint32_t stmt_buf[2]; 7008 const uint32_t* statements = NULL; 7009 uint32_t stmt_count = 0; 7010 7011 switch (tag) { 7012 case AST_NODE_BLOCK_TWO: 7013 case AST_NODE_BLOCK_TWO_SEMICOLON: { 7014 uint32_t idx = 0; 7015 if (nd.lhs != 0) 7016 stmt_buf[idx++] = nd.lhs; 7017 if (nd.rhs != 0) 7018 stmt_buf[idx++] = nd.rhs; 7019 statements = stmt_buf; 7020 stmt_count = idx; 7021 break; 7022 } 7023 case AST_NODE_BLOCK: 7024 case AST_NODE_BLOCK_SEMICOLON: { 7025 uint32_t start = nd.lhs; 7026 uint32_t end = nd.rhs; 7027 statements = tree->extra_data.arr + start; 7028 stmt_count = end - start; 7029 break; 7030 } 7031 default: 7032 // Not a block — treat as single expression (AstGen.zig:2369). 7033 return exprRl(gz, scope, rl, node); 7034 } 7035 7036 // Check if labeled (AstGen.zig:2373-2377). 7037 uint32_t lbrace = tree->nodes.main_tokens[node]; 7038 bool is_labeled 7039 = (lbrace >= 2 && tree->tokens.tags[lbrace - 1] == TOKEN_COLON 7040 && tree->tokens.tags[lbrace - 2] == TOKEN_IDENTIFIER); 7041 if (is_labeled) { 7042 // Labeled blocks need a proper block instruction. 7043 return blockExprExpr(gz, scope, rl, node); 7044 } 7045 7046 // Unlabeled block: process statements inline (AstGen.zig:2380-2383). 7047 GenZir sub_gz = makeSubBlock(gz, scope); 7048 blockExprStmts(&sub_gz, &sub_gz.base, statements, stmt_count); 7049 return rvalue(gz, rl, ZIR_REF_VOID_VALUE, node); 7050 } 7051 7052 // --- lastToken (Ast.zig:874) --- 7053 // Mechanical port of Ast.lastToken. Uses iterative end_offset accumulation. 7054 7055 static uint32_t lastToken(const Ast* tree, uint32_t node) { 7056 uint32_t n = node; 7057 uint32_t end_offset = 0; 7058 while (1) { 7059 AstNodeTag tag = tree->nodes.tags[n]; 7060 AstData nd = tree->nodes.datas[n]; 7061 switch (tag) { 7062 case AST_NODE_ROOT: 7063 return tree->tokens.len - 1; 7064 7065 // Binary ops: recurse into RHS (Ast.zig:893-948). 7066 case AST_NODE_ASSIGN: 7067 case AST_NODE_ADD: 7068 case AST_NODE_SUB: 7069 case AST_NODE_MUL: 7070 case AST_NODE_DIV: 7071 case AST_NODE_MOD: 7072 case AST_NODE_BIT_AND: 7073 case AST_NODE_BIT_OR: 7074 case AST_NODE_BIT_XOR: 7075 case AST_NODE_SHL: 7076 case AST_NODE_SHR: 7077 case AST_NODE_ARRAY_CAT: 7078 case AST_NODE_ARRAY_MULT: 7079 case AST_NODE_ADD_WRAP: 7080 case AST_NODE_SUB_WRAP: 7081 case AST_NODE_ADD_SAT: 7082 case AST_NODE_SUB_SAT: 7083 case AST_NODE_MUL_WRAP: 7084 case AST_NODE_MUL_SAT: 7085 case AST_NODE_MERGE_ERROR_SETS: 7086 case AST_NODE_EQUAL_EQUAL: 7087 case AST_NODE_BANG_EQUAL: 7088 case AST_NODE_LESS_THAN: 7089 case AST_NODE_GREATER_THAN: 7090 case AST_NODE_LESS_OR_EQUAL: 7091 case AST_NODE_GREATER_OR_EQUAL: 7092 case AST_NODE_BOOL_AND: 7093 case AST_NODE_BOOL_OR: 7094 case AST_NODE_ORELSE: 7095 case AST_NODE_CATCH: 7096 case AST_NODE_ERROR_UNION: 7097 case AST_NODE_SHL_SAT: 7098 n = nd.rhs; 7099 continue; 7100 7101 // field_access: return field token + end_offset (Ast.zig:979). 7102 case AST_NODE_FIELD_ACCESS: 7103 return nd.rhs + end_offset; 7104 7105 // test_decl: recurse into body node (Ast.zig:950). 7106 case AST_NODE_TEST_DECL: 7107 n = nd.rhs; 7108 continue; 7109 7110 // defer: recurse into body (lhs) (Ast.zig:951). 7111 case AST_NODE_DEFER: 7112 n = nd.lhs; 7113 continue; 7114 7115 // errdefer: recurse into body (rhs) (Ast.zig:950). 7116 case AST_NODE_ERRDEFER: 7117 n = nd.rhs; 7118 continue; 7119 7120 // block (Ast.zig:1085): end_offset += 1 (rbrace), recurse into last. 7121 case AST_NODE_BLOCK: { 7122 uint32_t start = nd.lhs; 7123 uint32_t end = nd.rhs; 7124 assert(start != end); 7125 end_offset += 1; 7126 n = tree->extra_data.arr[end - 1]; 7127 continue; 7128 } 7129 7130 // block_semicolon (Ast.zig:1097): += 2 (semicolon + rbrace). 7131 case AST_NODE_BLOCK_SEMICOLON: { 7132 uint32_t start = nd.lhs; 7133 uint32_t end = nd.rhs; 7134 assert(start != end); 7135 end_offset += 2; 7136 n = tree->extra_data.arr[end - 1]; 7137 continue; 7138 } 7139 7140 // block_two (Ast.zig:1117): if rhs, recurse rhs +1; if lhs, +1; else 7141 // +1. Note: C parser uses 0 for "none" (OptionalIndex), not 7142 // UINT32_MAX. 7143 case AST_NODE_BLOCK_TWO: { 7144 if (nd.rhs != 0) { 7145 end_offset += 1; 7146 n = nd.rhs; 7147 } else if (nd.lhs != 0) { 7148 end_offset += 1; 7149 n = nd.lhs; 7150 } else { 7151 end_offset += 1; 7152 return tree->nodes.main_tokens[n] + end_offset; 7153 } 7154 continue; 7155 } 7156 7157 // block_two_semicolon (Ast.zig:1153). 7158 case AST_NODE_BLOCK_TWO_SEMICOLON: { 7159 if (nd.rhs != 0) { 7160 end_offset += 2; 7161 n = nd.rhs; 7162 } else if (nd.lhs != 0) { 7163 end_offset += 2; 7164 n = nd.lhs; 7165 } else { 7166 end_offset += 1; 7167 return tree->nodes.main_tokens[n] + end_offset; 7168 } 7169 continue; 7170 } 7171 7172 // builtin_call_two (Ast.zig:1118): recurse into args + rparen. 7173 case AST_NODE_BUILTIN_CALL_TWO: { 7174 if (nd.rhs != 0) { 7175 end_offset += 1; 7176 n = nd.rhs; 7177 } else if (nd.lhs != 0) { 7178 end_offset += 1; 7179 n = nd.lhs; 7180 } else { 7181 end_offset += 2; // lparen + rparen 7182 return tree->nodes.main_tokens[n] + end_offset; 7183 } 7184 continue; 7185 } 7186 7187 case AST_NODE_BUILTIN_CALL_TWO_COMMA: { 7188 if (nd.rhs != 0) { 7189 end_offset += 2; // comma + rparen 7190 n = nd.rhs; 7191 } else if (nd.lhs != 0) { 7192 end_offset += 2; 7193 n = nd.lhs; 7194 } else { 7195 end_offset += 1; 7196 return tree->nodes.main_tokens[n] + end_offset; 7197 } 7198 continue; 7199 } 7200 7201 // Unary ops: recurse into lhs (Ast.zig:895-910). 7202 case AST_NODE_BOOL_NOT: 7203 case AST_NODE_BIT_NOT: 7204 case AST_NODE_NEGATION: 7205 case AST_NODE_NEGATION_WRAP: 7206 case AST_NODE_ADDRESS_OF: 7207 case AST_NODE_TRY: 7208 case AST_NODE_AWAIT: 7209 case AST_NODE_OPTIONAL_TYPE: 7210 case AST_NODE_COMPTIME: 7211 case AST_NODE_NOSUSPEND: 7212 case AST_NODE_RESUME: 7213 n = nd.lhs; 7214 continue; 7215 7216 // return: optional operand (Ast.zig:998-1002). 7217 case AST_NODE_RETURN: 7218 if (nd.lhs != 0) { 7219 n = nd.lhs; 7220 continue; 7221 } 7222 return tree->nodes.main_tokens[n] + end_offset; 7223 7224 // deref: main_token is the dot, +1 for '*' (Ast.zig:974). 7225 case AST_NODE_DEREF: 7226 return tree->nodes.main_tokens[n] + 1 + end_offset; 7227 7228 // unwrap_optional: +1 for '?' (Ast.zig:971). 7229 case AST_NODE_UNWRAP_OPTIONAL: 7230 return tree->nodes.main_tokens[n] + 1 + end_offset; 7231 7232 // for_range: recurse into rhs if present, else lhs. 7233 case AST_NODE_FOR_RANGE: 7234 if (nd.rhs != 0) { 7235 n = nd.rhs; 7236 } else { 7237 // Unbounded range: last token is the '..' operator. 7238 // main_token + 1 (the second dot of ..) 7239 return tree->nodes.main_tokens[n] + 1 + end_offset; 7240 } 7241 continue; 7242 7243 // error_value: main_token is `error`, last token is name (+2) 7244 // (Ast.zig:986). 7245 case AST_NODE_ERROR_VALUE: 7246 return tree->nodes.main_tokens[n] + 2 + end_offset; 7247 7248 // Terminals: return main_token + end_offset (Ast.zig:988-996). 7249 case AST_NODE_NUMBER_LITERAL: 7250 case AST_NODE_STRING_LITERAL: 7251 case AST_NODE_IDENTIFIER: 7252 case AST_NODE_ENUM_LITERAL: 7253 case AST_NODE_CHAR_LITERAL: 7254 case AST_NODE_UNREACHABLE_LITERAL: 7255 case AST_NODE_ANYFRAME_LITERAL: 7256 return tree->nodes.main_tokens[n] + end_offset; 7257 7258 // call_one: recurse into lhs, +1 for ')'. 7259 case AST_NODE_CALL_ONE: 7260 end_offset += 1; // rparen 7261 if (nd.rhs != 0) { 7262 n = nd.rhs; 7263 } else { 7264 n = nd.lhs; 7265 } 7266 continue; 7267 case AST_NODE_CALL_ONE_COMMA: 7268 end_offset += 2; // comma + rparen 7269 if (nd.rhs != 0) { 7270 n = nd.rhs; 7271 } else { 7272 n = nd.lhs; 7273 } 7274 continue; 7275 7276 // array_access: end_offset += 1 (rbracket), recurse rhs. 7277 case AST_NODE_ARRAY_ACCESS: 7278 end_offset += 1; 7279 n = nd.rhs; 7280 continue; 7281 7282 // simple_var_decl: recurse into init/type (Ast.zig:1169-1178). 7283 case AST_NODE_SIMPLE_VAR_DECL: 7284 if (nd.rhs != 0) { 7285 n = nd.rhs; // init expr 7286 } else if (nd.lhs != 0) { 7287 n = nd.lhs; // type expr 7288 } else { 7289 end_offset += 1; // from mut token to name 7290 return tree->nodes.main_tokens[n] + end_offset; 7291 } 7292 continue; 7293 7294 // aligned_var_decl: recurse into init/align (Ast.zig:1180-1187). 7295 case AST_NODE_ALIGNED_VAR_DECL: 7296 if (nd.rhs != 0) { 7297 n = nd.rhs; // init expr 7298 } else { 7299 end_offset += 1; // rparen 7300 n = nd.lhs; // align expr 7301 } 7302 continue; 7303 7304 // local_var_decl (Ast.zig:1209-1217). 7305 case AST_NODE_LOCAL_VAR_DECL: 7306 if (nd.rhs != 0) { 7307 n = nd.rhs; // init expr 7308 } else { 7309 // extra[lhs] has align_node 7310 end_offset += 1; // rparen 7311 n = tree->extra_data.arr[nd.lhs]; // align_node 7312 } 7313 continue; 7314 7315 // global_var_decl (Ast.zig:1189-1207). 7316 case AST_NODE_GLOBAL_VAR_DECL: 7317 if (nd.rhs != 0) { 7318 n = nd.rhs; // init expr 7319 } else { 7320 // extra[lhs] = {type_node, align_node, ...} 7321 // complex; approximate by using main_token 7322 end_offset += 1; 7323 return tree->nodes.main_tokens[n] + end_offset; 7324 } 7325 continue; 7326 7327 // slice_open: end_offset += 2 (ellipsis2 + rbracket), recurse rhs 7328 // (Ast.zig:1245-1248). 7329 case AST_NODE_SLICE_OPEN: 7330 end_offset += 2; 7331 n = nd.rhs; 7332 continue; 7333 7334 // grouped_expression: end_offset += 1 (rparen), recurse lhs. 7335 case AST_NODE_GROUPED_EXPRESSION: 7336 end_offset += 1; 7337 n = nd.lhs; 7338 continue; 7339 7340 // if_simple: recurse into body (rhs) (Ast.zig:942). 7341 case AST_NODE_IF_SIMPLE: 7342 case AST_NODE_WHILE_SIMPLE: 7343 case AST_NODE_FOR_SIMPLE: 7344 case AST_NODE_FN_DECL: 7345 case AST_NODE_ARRAY_TYPE: 7346 n = nd.rhs; 7347 continue; 7348 7349 // if: recurse into else_expr (Ast.zig:1295). 7350 case AST_NODE_IF: { 7351 // If[rhs]: { then_expr, else_expr } 7352 n = tree->extra_data.arr[nd.rhs + 1]; // else_expr 7353 continue; 7354 } 7355 7356 // while: recurse into else_expr (Ast.zig:1290). 7357 case AST_NODE_WHILE: { 7358 // While[rhs]: { cont_expr, then_expr, else_expr } 7359 n = tree->extra_data.arr[nd.rhs + 2]; // else_expr 7360 continue; 7361 } 7362 7363 // while_cont: recurse into then_expr (Ast.zig:943-like). 7364 case AST_NODE_WHILE_CONT: { 7365 // WhileCont[rhs]: { cont_expr, then_expr } 7366 n = tree->extra_data.arr[nd.rhs + 1]; // then_expr 7367 continue; 7368 } 7369 7370 // switch: recurse into last case (Ast.zig:1031-1041). 7371 case AST_NODE_SWITCH: { 7372 uint32_t ei = nd.rhs; 7373 uint32_t cs = tree->extra_data.arr[ei]; 7374 uint32_t ce = tree->extra_data.arr[ei + 1]; 7375 if (cs == ce) { 7376 end_offset += 3; // rparen, lbrace, rbrace 7377 n = nd.lhs; 7378 } else { 7379 end_offset += 1; // rbrace 7380 n = tree->extra_data.arr[ce - 1]; 7381 } 7382 continue; 7383 } 7384 case AST_NODE_SWITCH_COMMA: { 7385 uint32_t ei = nd.rhs; 7386 uint32_t cs = tree->extra_data.arr[ei]; 7387 uint32_t ce = tree->extra_data.arr[ei + 1]; 7388 assert(cs != ce); 7389 end_offset += 2; // comma + rbrace 7390 n = tree->extra_data.arr[ce - 1]; 7391 continue; 7392 } 7393 7394 // switch_case_one: recurse into rhs (body) (Ast.zig:942). 7395 case AST_NODE_SWITCH_CASE_ONE: 7396 case AST_NODE_SWITCH_CASE_INLINE_ONE: 7397 case AST_NODE_SWITCH_CASE: 7398 case AST_NODE_SWITCH_CASE_INLINE: 7399 n = nd.rhs; 7400 continue; 7401 7402 // switch_range: recurse into rhs (Ast.zig: binary op pattern). 7403 case AST_NODE_SWITCH_RANGE: 7404 n = nd.rhs; 7405 continue; 7406 7407 // struct_init_one: recurse into field if present, +1. 7408 case AST_NODE_STRUCT_INIT_ONE: 7409 end_offset += 1; // rbrace 7410 if (nd.rhs != 0) { 7411 n = nd.rhs; 7412 } else { 7413 return tree->nodes.main_tokens[n] + end_offset; 7414 } 7415 continue; 7416 case AST_NODE_STRUCT_INIT_ONE_COMMA: 7417 end_offset += 2; // comma + rbrace 7418 n = nd.rhs; 7419 continue; 7420 7421 // struct_init_dot_two: similar to block_two. 7422 case AST_NODE_STRUCT_INIT_DOT_TWO: 7423 if (nd.rhs != 0) { 7424 end_offset += 1; 7425 n = nd.rhs; 7426 } else if (nd.lhs != 0) { 7427 end_offset += 1; 7428 n = nd.lhs; 7429 } else { 7430 end_offset += 1; // rbrace 7431 return tree->nodes.main_tokens[n] + end_offset; 7432 } 7433 continue; 7434 case AST_NODE_STRUCT_INIT_DOT_TWO_COMMA: 7435 end_offset += 2; 7436 if (nd.rhs != 0) { 7437 n = nd.rhs; 7438 } else { 7439 n = nd.lhs; 7440 } 7441 continue; 7442 7443 // struct_init_dot: SubRange pattern. 7444 case AST_NODE_STRUCT_INIT_DOT: 7445 assert(nd.lhs != nd.rhs); 7446 end_offset += 1; 7447 n = tree->extra_data.arr[nd.rhs - 1]; 7448 continue; 7449 7450 // struct_init: node_and_extra SubRange pattern. 7451 case AST_NODE_STRUCT_INIT: { 7452 uint32_t si = tree->extra_data.arr[nd.rhs]; 7453 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7454 assert(si != se); 7455 end_offset += 1; 7456 n = tree->extra_data.arr[se - 1]; 7457 continue; 7458 } 7459 7460 // call: SubRange pattern. 7461 case AST_NODE_CALL: { 7462 uint32_t si = tree->extra_data.arr[nd.rhs]; 7463 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7464 assert(si != se); 7465 end_offset += 1; 7466 n = tree->extra_data.arr[se - 1]; 7467 continue; 7468 } 7469 case AST_NODE_CALL_COMMA: { 7470 uint32_t si = tree->extra_data.arr[nd.rhs]; 7471 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7472 assert(si != se); 7473 end_offset += 2; 7474 n = tree->extra_data.arr[se - 1]; 7475 continue; 7476 } 7477 7478 // fn_proto_simple: recurse into rhs (return type). 7479 case AST_NODE_FN_PROTO_SIMPLE: 7480 case AST_NODE_FN_PROTO_ONE: 7481 case AST_NODE_FN_PROTO_MULTI: 7482 case AST_NODE_FN_PROTO: 7483 n = nd.rhs; 7484 continue; 7485 7486 // error_set_decl: rhs is the closing rbrace token. 7487 case AST_NODE_ERROR_SET_DECL: 7488 return nd.rhs + end_offset; 7489 7490 // ptr_type variants: recurse into rhs (child type). 7491 case AST_NODE_PTR_TYPE_ALIGNED: 7492 case AST_NODE_PTR_TYPE_SENTINEL: 7493 case AST_NODE_PTR_TYPE: 7494 case AST_NODE_PTR_TYPE_BIT_RANGE: 7495 n = nd.rhs; 7496 continue; 7497 7498 // container_decl: extra_range pattern. 7499 case AST_NODE_CONTAINER_DECL: 7500 case AST_NODE_TAGGED_UNION: 7501 assert(nd.lhs != nd.rhs); 7502 end_offset += 1; 7503 n = tree->extra_data.arr[nd.rhs - 1]; 7504 continue; 7505 case AST_NODE_CONTAINER_DECL_TRAILING: 7506 case AST_NODE_TAGGED_UNION_TRAILING: 7507 assert(nd.lhs != nd.rhs); 7508 end_offset += 2; 7509 n = tree->extra_data.arr[nd.rhs - 1]; 7510 continue; 7511 7512 // container_decl_two: like block_two. 7513 case AST_NODE_CONTAINER_DECL_TWO: 7514 case AST_NODE_TAGGED_UNION_TWO: 7515 if (nd.rhs != 0) { 7516 end_offset += 1; 7517 n = nd.rhs; 7518 } else if (nd.lhs != 0) { 7519 end_offset += 1; 7520 n = nd.lhs; 7521 } else { 7522 end_offset += 2; // lbrace + rbrace 7523 return tree->nodes.main_tokens[n] + end_offset; 7524 } 7525 continue; 7526 case AST_NODE_CONTAINER_DECL_TWO_TRAILING: 7527 case AST_NODE_TAGGED_UNION_TWO_TRAILING: 7528 end_offset += 2; 7529 if (nd.rhs != 0) { 7530 n = nd.rhs; 7531 } else { 7532 n = nd.lhs; 7533 } 7534 continue; 7535 7536 // container_decl_arg: node_and_extra SubRange. 7537 case AST_NODE_CONTAINER_DECL_ARG: { 7538 uint32_t si = tree->extra_data.arr[nd.rhs]; 7539 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7540 if (si == se) { 7541 end_offset += 3; // rparen + lbrace + rbrace 7542 n = nd.lhs; 7543 } else { 7544 end_offset += 1; 7545 n = tree->extra_data.arr[se - 1]; 7546 } 7547 continue; 7548 } 7549 case AST_NODE_CONTAINER_DECL_ARG_TRAILING: { 7550 uint32_t si = tree->extra_data.arr[nd.rhs]; 7551 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7552 assert(si != se); 7553 end_offset += 2; 7554 n = tree->extra_data.arr[se - 1]; 7555 continue; 7556 } 7557 7558 // slice: extra data pattern. 7559 case AST_NODE_SLICE: { 7560 // Slice[rhs]: { start, end } 7561 end_offset += 1; 7562 n = tree->extra_data.arr[nd.rhs + 1]; // end 7563 continue; 7564 } 7565 case AST_NODE_SLICE_SENTINEL: { 7566 // SliceSentinel[rhs]: { start, end, sentinel } 7567 end_offset += 1; 7568 n = tree->extra_data.arr[nd.rhs + 2]; // sentinel 7569 continue; 7570 } 7571 7572 // array_type_sentinel: extra data. 7573 case AST_NODE_ARRAY_TYPE_SENTINEL: { 7574 // ArrayTypeSentinel[rhs]: { sentinel, elem_type } 7575 n = tree->extra_data.arr[nd.rhs + 1]; // elem_type 7576 continue; 7577 } 7578 7579 // multiline_string_literal: main_token + end_offset. 7580 case AST_NODE_MULTILINE_STRING_LITERAL: 7581 return nd.rhs + end_offset; 7582 7583 // break/continue (Ast.zig:1275-1283). 7584 // lhs is opt_token (null_token = UINT32_MAX), rhs is opt_node (0 = 7585 // none). 7586 case AST_NODE_BREAK: 7587 case AST_NODE_CONTINUE: 7588 if (nd.rhs != 0) { 7589 n = nd.rhs; // optional rhs expression 7590 } else if (nd.lhs != UINT32_MAX) { 7591 return nd.lhs + end_offset; // label token 7592 } else { 7593 return tree->nodes.main_tokens[n] + end_offset; 7594 } 7595 continue; 7596 7597 // array_init_one: end_offset += 1 (rbrace), recurse rhs 7598 // (Ast.zig:1224-1230). 7599 case AST_NODE_ARRAY_INIT_ONE: 7600 end_offset += 1; 7601 n = nd.rhs; 7602 continue; 7603 7604 case AST_NODE_ARRAY_INIT_ONE_COMMA: 7605 end_offset += 2; // comma + rbrace 7606 n = nd.rhs; 7607 continue; 7608 7609 // struct_init_dot_comma: SubRange pattern. 7610 case AST_NODE_STRUCT_INIT_DOT_COMMA: 7611 assert(nd.lhs != nd.rhs); 7612 end_offset += 2; // comma + rbrace 7613 n = tree->extra_data.arr[nd.rhs - 1]; 7614 continue; 7615 7616 // struct_init_comma: node_and_extra SubRange. 7617 case AST_NODE_STRUCT_INIT_COMMA: { 7618 uint32_t si = tree->extra_data.arr[nd.rhs]; 7619 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7620 assert(si != se); 7621 end_offset += 2; 7622 n = tree->extra_data.arr[se - 1]; 7623 continue; 7624 } 7625 7626 // array_init variants. 7627 case AST_NODE_ARRAY_INIT: { 7628 uint32_t si = tree->extra_data.arr[nd.rhs]; 7629 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7630 assert(si != se); 7631 end_offset += 1; 7632 n = tree->extra_data.arr[se - 1]; 7633 continue; 7634 } 7635 case AST_NODE_ARRAY_INIT_COMMA: { 7636 uint32_t si = tree->extra_data.arr[nd.rhs]; 7637 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7638 assert(si != se); 7639 end_offset += 2; 7640 n = tree->extra_data.arr[se - 1]; 7641 continue; 7642 } 7643 7644 // array_init_dot variants. 7645 case AST_NODE_ARRAY_INIT_DOT_TWO: 7646 if (nd.rhs != 0) { 7647 end_offset += 1; 7648 n = nd.rhs; 7649 } else if (nd.lhs != 0) { 7650 end_offset += 1; 7651 n = nd.lhs; 7652 } else { 7653 end_offset += 1; 7654 return tree->nodes.main_tokens[n] + end_offset; 7655 } 7656 continue; 7657 case AST_NODE_ARRAY_INIT_DOT_TWO_COMMA: 7658 end_offset += 2; 7659 if (nd.rhs != 0) { 7660 n = nd.rhs; 7661 } else { 7662 n = nd.lhs; 7663 } 7664 continue; 7665 case AST_NODE_ARRAY_INIT_DOT: 7666 assert(nd.lhs != nd.rhs); 7667 end_offset += 1; 7668 n = tree->extra_data.arr[nd.rhs - 1]; 7669 continue; 7670 case AST_NODE_ARRAY_INIT_DOT_COMMA: 7671 assert(nd.lhs != nd.rhs); 7672 end_offset += 2; 7673 n = tree->extra_data.arr[nd.rhs - 1]; 7674 continue; 7675 7676 // builtin_call (Ast.zig:1083-1105). 7677 case AST_NODE_BUILTIN_CALL: { 7678 uint32_t si = tree->extra_data.arr[nd.rhs]; 7679 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7680 assert(si != se); 7681 end_offset += 1; 7682 n = tree->extra_data.arr[se - 1]; 7683 continue; 7684 } 7685 case AST_NODE_BUILTIN_CALL_COMMA: { 7686 uint32_t si = tree->extra_data.arr[nd.rhs]; 7687 uint32_t se = tree->extra_data.arr[nd.rhs + 1]; 7688 assert(si != se); 7689 end_offset += 2; 7690 n = tree->extra_data.arr[se - 1]; 7691 continue; 7692 } 7693 7694 // for (Ast.zig:1300-1303): complex extra data. 7695 case AST_NODE_FOR: { 7696 // lhs = span.start (extra_data index), 7697 // rhs = packed(inputs:u31, has_else:u1 at bit 31). 7698 // extra[lhs..] = input nodes, then_body, [else_body]. 7699 uint32_t span_start = nd.lhs; 7700 uint32_t for_packed = nd.rhs; 7701 uint32_t inputs = for_packed & 0x7FFFFFFFu; 7702 bool has_else = (for_packed >> 31) != 0; 7703 uint32_t last_idx = span_start + inputs + (has_else ? 1 : 0); 7704 n = tree->extra_data.arr[last_idx]; 7705 continue; 7706 } 7707 7708 default: 7709 // Fallback: return main_token + end_offset. 7710 return tree->nodes.main_tokens[n] + end_offset; 7711 } 7712 } 7713 } 7714 7715 // --- addParam (AstGen.zig:12390) --- 7716 // Creates a param instruction with pl_tok data and type body in extra. 7717 7718 static uint32_t addParam(GenZir* gz, GenZir* param_gz, ZirInstTag tag, 7719 uint32_t abs_tok_index, uint32_t name) { 7720 AstGenCtx* ag = gz->astgen; 7721 7722 uint32_t body_len = gzInstructionsLen(param_gz); 7723 const uint32_t* param_body = gzInstructionsSlice(param_gz); 7724 7725 // Param payload: name, type{body_len:u31|is_generic:u1} 7726 ensureExtraCapacity(ag, 2 + body_len); 7727 uint32_t payload_index = ag->extra_len; 7728 ag->extra[ag->extra_len++] = name; 7729 ag->extra[ag->extra_len++] = body_len & 0x7FFFFFFFu; // is_generic = false 7730 for (uint32_t i = 0; i < body_len; i++) { 7731 ag->extra[ag->extra_len++] = param_body[i]; 7732 } 7733 gzUnstack(param_gz); 7734 7735 // Emit the param instruction. 7736 ensureInstCapacity(ag, 1); 7737 uint32_t idx = ag->inst_len; 7738 ag->inst_tags[idx] = tag; 7739 ZirInstData data; 7740 data.pl_tok.src_tok = tokenIndexToRelative(gz, abs_tok_index); 7741 data.pl_tok.payload_index = payload_index; 7742 ag->inst_datas[idx] = data; 7743 ag->inst_len++; 7744 gzAppendInstruction(gz, idx); 7745 return idx; 7746 } 7747 7748 // --- addDbgVar (AstGen.zig:13196) --- 7749 7750 static void addDbgVar( 7751 GenZir* gz, ZirInstTag tag, uint32_t name, uint32_t inst) { 7752 if (gz->is_comptime) 7753 return; 7754 ZirInstData data; 7755 data.str_op.str = name; 7756 data.str_op.operand = inst; 7757 addInstruction(gz, tag, data); 7758 } 7759 7760 // --- addFunc (AstGen.zig:12023) --- 7761 // Handles non-fancy func/func_inferred instructions. 7762 // ret_body/ret_body_len: instructions for the return type sub-block (may be 7763 // 0). ret_ref: if ret_body_len==0, the return type as a simple Ref. 7764 7765 static uint32_t addFunc(GenZir* gz, uint32_t src_node, uint32_t block_node, 7766 uint32_t param_block, uint32_t ret_ref, const uint32_t* ret_body, 7767 uint32_t ret_body_len, const uint32_t* body, uint32_t body_len, 7768 const uint32_t* param_insts, uint32_t param_insts_len, 7769 uint32_t lbrace_line, uint32_t lbrace_column, bool is_inferred_error) { 7770 AstGenCtx* ag = gz->astgen; 7771 const Ast* tree = ag->tree; 7772 uint32_t rbrace_tok = lastToken(tree, block_node); 7773 uint32_t rbrace_start = tree->tokens.starts[rbrace_tok]; 7774 advanceSourceCursor(ag, rbrace_start); 7775 uint32_t rbrace_line = ag->source_line - gz->decl_line; 7776 uint32_t rbrace_column = ag->source_column; 7777 7778 // Build Func payload (Zir.Inst.Func: ret_ty, param_block, body_len). 7779 // (AstGen.zig:12187-12194) 7780 uint32_t ret_ty_packed_len; 7781 if (ret_body_len > 0) { 7782 ret_ty_packed_len = ret_body_len; // body-based return type 7783 } else if (ret_ref != ZIR_REF_NONE) { 7784 ret_ty_packed_len = 1; // simple Ref 7785 } else { 7786 ret_ty_packed_len = 0; // void return 7787 } 7788 // Pack RetTy: body_len:u31 | is_generic:bool(u1) = just body_len. 7789 uint32_t ret_ty_packed 7790 = ret_ty_packed_len & 0x7FFFFFFFu; // is_generic=false 7791 7792 uint32_t fixup_body_len = countBodyLenAfterFixupsExtraRefs( 7793 ag, body, body_len, param_insts, param_insts_len); 7794 ensureExtraCapacity(ag, 3 + ret_ty_packed_len + fixup_body_len + 7); 7795 uint32_t payload_index = ag->extra_len; 7796 ag->extra[ag->extra_len++] = ret_ty_packed; // Func.ret_ty 7797 ag->extra[ag->extra_len++] = param_block; // Func.param_block 7798 ag->extra[ag->extra_len++] = fixup_body_len; // Func.body_len 7799 7800 // Trailing ret_ty: either body instructions or a single ref. 7801 if (ret_body_len > 0) { 7802 for (uint32_t i = 0; i < ret_body_len; i++) 7803 ag->extra[ag->extra_len++] = ret_body[i]; 7804 } else if (ret_ref != ZIR_REF_NONE) { 7805 ag->extra[ag->extra_len++] = ret_ref; 7806 } 7807 7808 // Body instructions with extra_refs for param_insts 7809 // (AstGen.zig:12206). 7810 appendBodyWithFixupsExtraRefs( 7811 ag, body, body_len, param_insts, param_insts_len); 7812 7813 // SrcLocs (AstGen.zig:12098-12106). 7814 uint32_t columns = (lbrace_column & 0xFFFFu) | (rbrace_column << 16); 7815 ag->extra[ag->extra_len++] = lbrace_line; 7816 ag->extra[ag->extra_len++] = rbrace_line; 7817 ag->extra[ag->extra_len++] = columns; 7818 // proto_hash (4 words): zero for now. 7819 ag->extra[ag->extra_len++] = 0; 7820 ag->extra[ag->extra_len++] = 0; 7821 ag->extra[ag->extra_len++] = 0; 7822 ag->extra[ag->extra_len++] = 0; 7823 7824 // Emit the func instruction (AstGen.zig:12220-12226). 7825 ZirInstTag tag 7826 = is_inferred_error ? ZIR_INST_FUNC_INFERRED : ZIR_INST_FUNC; 7827 ZirInstData data; 7828 data.pl_node.src_node = (int32_t)src_node - (int32_t)gz->decl_node_index; 7829 data.pl_node.payload_index = payload_index; 7830 return addInstruction(gz, tag, data); 7831 } 7832 7833 // --- testDecl (AstGen.zig:4708) --- 7834 7835 static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, 7836 uint32_t* decl_idx, uint32_t node) { 7837 const Ast* tree = ag->tree; 7838 AstData nd = tree->nodes.datas[node]; 7839 uint32_t body_node = nd.rhs; 7840 7841 // makeDeclaration before advanceSourceCursorToNode (AstGen.zig:4726-4729). 7842 uint32_t decl_inst = makeDeclaration(ag, node); 7843 wip_decl_insts[*decl_idx] = decl_inst; 7844 (*decl_idx)++; 7845 advanceSourceCursorToNode(ag, node); 7846 7847 uint32_t decl_line = ag->source_line; 7848 uint32_t decl_column = ag->source_column; 7849 7850 // Extract test name (AstGen.zig:4748-4835). 7851 uint32_t test_token = tree->nodes.main_tokens[node]; 7852 uint32_t test_name_token = test_token + 1; 7853 uint32_t test_name = 0; // NullTerminatedString.empty 7854 DeclFlagsId decl_id = DECL_ID_UNNAMED_TEST; 7855 7856 // Check if the token after 'test' is a string literal. 7857 // We identify string literals by checking the source character. 7858 uint32_t name_tok_start = tree->tokens.starts[test_name_token]; 7859 if (name_tok_start < tree->source_len 7860 && tree->source[name_tok_start] == '"') { 7861 // String literal name. 7862 uint32_t name_len; 7863 strLitAsString(ag, test_name_token, &test_name, &name_len); 7864 decl_id = DECL_ID_TEST; 7865 } 7866 // TODO: handle identifier test names (decltest). 7867 7868 // Set up decl_block GenZir (AstGen.zig:4735-4743). 7869 GenZir decl_block; 7870 memset(&decl_block, 0, sizeof(decl_block)); 7871 decl_block.base.tag = SCOPE_GEN_ZIR; 7872 decl_block.parent = NULL; 7873 decl_block.astgen = ag; 7874 decl_block.decl_node_index = node; 7875 decl_block.decl_line = decl_line; 7876 decl_block.is_comptime = true; 7877 decl_block.instructions_top = ag->scratch_inst_len; 7878 decl_block.break_block = UINT32_MAX; 7879 7880 // Set up fn_block GenZir (AstGen.zig:4837-4845). 7881 GenZir fn_block; 7882 memset(&fn_block, 0, sizeof(fn_block)); 7883 fn_block.base.tag = SCOPE_GEN_ZIR; 7884 fn_block.parent = &decl_block.base; 7885 fn_block.astgen = ag; 7886 fn_block.decl_node_index = node; 7887 fn_block.decl_line = decl_line; 7888 fn_block.is_comptime = false; 7889 fn_block.instructions_top = ag->scratch_inst_len; 7890 fn_block.break_block = UINT32_MAX; 7891 7892 // Set fn_block and fn_ret_ty for the body (AstGen.zig:4849-4853). 7893 void* prev_fn_block = ag->fn_block; 7894 uint32_t prev_fn_ret_ty = ag->fn_ret_ty; 7895 setFnBlock(ag, &fn_block); 7896 ag->fn_ret_ty = ZIR_REF_ANYERROR_VOID_ERROR_UNION_TYPE; 7897 7898 // Compute lbrace source location (AstGen.zig:4860-4862). 7899 advanceSourceCursorToNode(ag, body_node); 7900 uint32_t lbrace_line = ag->source_line - decl_line; 7901 uint32_t lbrace_column = ag->source_column; 7902 7903 // Process test body (AstGen.zig:4864). 7904 uint32_t block_result 7905 = fullBodyExpr(&fn_block, &fn_block.base, RL_NONE_VAL, body_node); 7906 7907 ag->fn_block = prev_fn_block; 7908 ag->fn_ret_ty = prev_fn_ret_ty; 7909 7910 // If we hit unimplemented features, bail out. 7911 if (ag->has_compile_errors) 7912 return; 7913 7914 // Add restore_err_ret_index + ret_implicit (AstGen.zig:4865-4871). 7915 if (gzInstructionsLen(&fn_block) == 0 7916 || !refIsNoReturn(&fn_block, block_result)) { 7917 ZirInstData rdata; 7918 rdata.un_node.operand = ZIR_REF_NONE; // .none for .ret 7919 rdata.un_node.src_node 7920 = (int32_t)node - (int32_t)fn_block.decl_node_index; 7921 addInstruction( 7922 &fn_block, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); 7923 7924 uint32_t body_last_tok = lastToken(tree, body_node); 7925 ZirInstData rdata2; 7926 rdata2.un_tok.operand = ZIR_REF_VOID_VALUE; 7927 rdata2.un_tok.src_tok = tokenIndexToRelative(&fn_block, body_last_tok); 7928 addInstruction(&fn_block, ZIR_INST_RET_IMPLICIT, rdata2); 7929 } 7930 7931 // Read fn_block body before unstacking (AstGen.zig:4874). 7932 // Upstream unstacks fn_block inside addFunc before appending the func 7933 // instruction to decl_block. We must unstack fn_block first so that 7934 // addFunc's addInstruction goes into decl_block's range. 7935 const uint32_t* fn_body = gzInstructionsSlice(&fn_block); 7936 uint32_t fn_body_len = gzInstructionsLen(&fn_block); 7937 gzUnstack(&fn_block); 7938 7939 // Create func instruction (AstGen.zig:4874-4897). 7940 uint32_t func_ref = addFunc(&decl_block, node, body_node, decl_inst, 7941 ZIR_REF_ANYERROR_VOID_ERROR_UNION_TYPE, NULL, 0, fn_body, fn_body_len, 7942 NULL, 0, lbrace_line, lbrace_column, false); 7943 7944 // break_inline returning func to declaration (AstGen.zig:4899). 7945 makeBreakInline(&decl_block, decl_inst, func_ref, AST_NODE_OFFSET_NONE); 7946 7947 // setDeclaration (AstGen.zig:4903-4923). 7948 setDeclaration(ag, decl_inst, 7949 (SetDeclArgs) { .src_line = decl_line, 7950 .src_column = decl_column, 7951 .id = decl_id, 7952 .name = test_name, 7953 .lib_name = UINT32_MAX, 7954 .value_body = gzInstructionsSlice(&decl_block), 7955 .value_body_len = gzInstructionsLen(&decl_block) }); 7956 gzUnstack(&decl_block); 7957 7958 (void)gz; 7959 } 7960 7961 // --- fnDecl (AstGen.zig:4067) / fnDeclInner (AstGen.zig:4228) --- 7962 // Handles non-extern function declarations with bodies, including params. 7963 7964 static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, 7965 uint32_t* decl_idx, uint32_t node) { 7966 const Ast* tree = ag->tree; 7967 AstData nd = tree->nodes.datas[node]; 7968 7969 // For fn_decl: data.lhs = fn_proto node, data.rhs = body node. 7970 uint32_t proto_node = nd.lhs; 7971 uint32_t body_node = nd.rhs; 7972 7973 // Get function name token (main_token of proto + 1 = fn name). 7974 uint32_t fn_token = tree->nodes.main_tokens[proto_node]; 7975 uint32_t fn_name_token = fn_token + 1; 7976 7977 // Check for 'pub' modifier (Ast.zig:2003-2025). 7978 bool is_pub = (fn_token > 0 7979 && tree->tokens.tags[fn_token - 1] == TOKEN_KEYWORD_PUB); 7980 7981 // makeDeclaration on fn_proto node (AstGen.zig:4090). 7982 uint32_t decl_inst = makeDeclaration(ag, proto_node); 7983 wip_decl_insts[*decl_idx] = decl_inst; 7984 (*decl_idx)++; 7985 7986 advanceSourceCursorToNode(ag, node); 7987 uint32_t decl_line = ag->source_line; 7988 uint32_t decl_column = ag->source_column; 7989 7990 // Save source cursor for restoring after ret_gz (AstGen.zig:4387-4388). 7991 uint32_t saved_source_offset = ag->source_offset; 7992 uint32_t saved_source_line = ag->source_line; 7993 uint32_t saved_source_column = ag->source_column; 7994 7995 AstNodeTag proto_tag = tree->nodes.tags[proto_node]; 7996 AstData proto_data = tree->nodes.datas[proto_node]; 7997 7998 // Extract return type node (rhs for all fn_proto variants). 7999 uint32_t return_type_node = proto_data.rhs; 8000 8001 // Detect inferred error set: token before return type is '!' 8002 // (AstGen.zig:4249-4251). 8003 bool is_inferred_error = false; 8004 if (return_type_node != 0) { 8005 uint32_t ret_first_tok = firstToken(tree, return_type_node); 8006 if (ret_first_tok > 0) { 8007 uint32_t maybe_bang = ret_first_tok - 1; 8008 uint32_t bang_start = tree->tokens.starts[maybe_bang]; 8009 if (tree->source[bang_start] == '!') 8010 is_inferred_error = true; 8011 } 8012 } 8013 8014 // Extract param type nodes from proto variant (AstGen.zig:4253-4254). 8015 uint32_t param_nodes_buf[1]; // buffer for fn_proto_simple/fn_proto_one 8016 const uint32_t* param_nodes = NULL; 8017 uint32_t params_len = 0; 8018 8019 if (proto_tag == AST_NODE_FN_PROTO_SIMPLE) { 8020 // data.lhs = optional param node, data.rhs = return type. 8021 if (proto_data.lhs != 0) { 8022 param_nodes_buf[0] = proto_data.lhs; 8023 param_nodes = param_nodes_buf; 8024 params_len = 1; 8025 } 8026 } else if (proto_tag == AST_NODE_FN_PROTO_ONE) { 8027 // data.lhs = extra_data index → AstFnProtoOne. 8028 uint32_t extra_idx = proto_data.lhs; 8029 uint32_t param 8030 = tree->extra_data.arr[extra_idx]; // AstFnProtoOne.param 8031 if (param != 0) { 8032 param_nodes_buf[0] = param; 8033 param_nodes = param_nodes_buf; 8034 params_len = 1; 8035 } 8036 } else if (proto_tag == AST_NODE_FN_PROTO_MULTI) { 8037 // data.lhs = extra_data index → SubRange{start, end}. 8038 uint32_t extra_idx = proto_data.lhs; 8039 uint32_t range_start = tree->extra_data.arr[extra_idx]; 8040 uint32_t range_end = tree->extra_data.arr[extra_idx + 1]; 8041 param_nodes = tree->extra_data.arr + range_start; 8042 params_len = range_end - range_start; 8043 } else if (proto_tag == AST_NODE_FN_PROTO) { 8044 // data.lhs = extra_data index → AstFnProto{params_start, params_end, 8045 // ...}. 8046 uint32_t extra_idx = proto_data.lhs; 8047 uint32_t pstart = tree->extra_data.arr[extra_idx]; // params_start 8048 uint32_t pend = tree->extra_data.arr[extra_idx + 1]; // params_end 8049 param_nodes = tree->extra_data.arr + pstart; 8050 params_len = pend - pstart; 8051 } 8052 8053 // decl_gz (called value_gz in caller, decl_gz in fnDeclInner) 8054 // (AstGen.zig:4194-4201). 8055 GenZir decl_gz; 8056 memset(&decl_gz, 0, sizeof(decl_gz)); 8057 decl_gz.base.tag = SCOPE_GEN_ZIR; 8058 decl_gz.parent = NULL; 8059 decl_gz.astgen = ag; 8060 decl_gz.decl_node_index = proto_node; 8061 decl_gz.decl_line = decl_line; 8062 decl_gz.is_comptime = true; 8063 decl_gz.instructions_top = ag->scratch_inst_len; 8064 decl_gz.break_block = UINT32_MAX; 8065 8066 // --- Parameter iteration (AstGen.zig:4260-4363) --- 8067 // Walk params, creating param instructions and ScopeLocalVal entries. 8068 // We keep param scopes on the C stack (max 32 params like upstream). 8069 Scope* params_scope = &decl_gz.base; 8070 ScopeLocalVal param_scopes[32]; 8071 uint32_t param_scope_count = 0; 8072 // Collect param instruction indices (AstGen.zig:4254, 4360). 8073 uint32_t param_insts[32]; 8074 uint32_t param_insts_len = 0; 8075 8076 for (uint32_t param_i = 0; param_i < params_len; param_i++) { 8077 uint32_t param_type_node = param_nodes[param_i]; 8078 8079 // Find param name token by scanning backwards from firstToken of 8080 // type expression (mirrors FnProto.Iterator.next, Ast.zig:2687). 8081 // Layout: [comptime] [name] [:] type_expr 8082 // So: type_first_tok - 1 is ':', type_first_tok - 2 is name. 8083 uint32_t type_first_tok = firstToken(tree, param_type_node); 8084 uint32_t name_token = 0; // 0 = no name found 8085 bool is_comptime_param = false; 8086 if (type_first_tok >= 2 8087 && tree->tokens.tags[type_first_tok - 1] == TOKEN_COLON) { 8088 // Named parameter: name is at type_first_tok - 2. 8089 uint32_t maybe_name = type_first_tok - 2; 8090 uint32_t name_start = tree->tokens.starts[maybe_name]; 8091 char ch = tree->source[name_start]; 8092 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') 8093 || ch == '_' || ch == '@') { 8094 // Could be name or comptime/noalias keyword. 8095 if (name_start + 8 <= tree->source_len 8096 && memcmp(tree->source + name_start, "comptime", 8) == 0) { 8097 is_comptime_param = true; 8098 } else if (name_start + 7 <= tree->source_len 8099 && memcmp(tree->source + name_start, "noalias", 7) == 0) { 8100 // noalias keyword, not a name. 8101 } else { 8102 name_token = maybe_name; 8103 // Check for preceding comptime keyword. 8104 if (maybe_name > 0) { 8105 uint32_t prev = maybe_name - 1; 8106 uint32_t prev_start = tree->tokens.starts[prev]; 8107 if (prev_start + 8 <= tree->source_len 8108 && memcmp(tree->source + prev_start, "comptime", 8) 8109 == 0) 8110 is_comptime_param = true; 8111 } 8112 } 8113 } 8114 } 8115 8116 // Determine param name string (AstGen.zig:4283-4321). 8117 // Must be resolved BEFORE type expression to match upstream string 8118 // table ordering. 8119 uint32_t param_name_str = 0; // NullTerminatedString.empty 8120 if (name_token != 0) { 8121 uint32_t name_start = tree->tokens.starts[name_token]; 8122 char nch = tree->source[name_start]; 8123 // Skip "_" params (AstGen.zig:4285-4286). 8124 if (nch == '_') { 8125 uint32_t next_start = tree->tokens.starts[name_token + 1]; 8126 if (next_start == name_start + 1) { 8127 // Single underscore: empty name. 8128 param_name_str = 0; 8129 } else { 8130 param_name_str = identAsString(ag, name_token); 8131 } 8132 } else { 8133 param_name_str = identAsString(ag, name_token); 8134 } 8135 } 8136 8137 // Evaluate param type expression in a sub-block 8138 // (AstGen.zig:4333-4337). 8139 GenZir param_gz = makeSubBlock(&decl_gz, params_scope); 8140 uint32_t param_type_ref 8141 = expr(¶m_gz, params_scope, param_type_node); 8142 8143 if (ag->has_compile_errors) 8144 return; 8145 8146 // The break_inline target is the param instruction we're about to 8147 // create (AstGen.zig:4336-4337). 8148 uint32_t param_inst_expected = ag->inst_len + 1; 8149 // +1 because: the break_inline is emitted first (uses inst_len), 8150 // then addParam emits the param instruction at inst_len. 8151 // Actually, addParam emits the param after break_inline. The 8152 // break_inline's block_inst field should point to the param inst. 8153 // We know it will be at ag->inst_len after the break_inline. 8154 makeBreakInline(¶m_gz, param_inst_expected, param_type_ref, 8155 (int32_t)param_type_node - (int32_t)param_gz.decl_node_index); 8156 8157 // Create param instruction (AstGen.zig:4341-4343). 8158 ZirInstTag param_tag 8159 = is_comptime_param ? ZIR_INST_PARAM_COMPTIME : ZIR_INST_PARAM; 8160 uint32_t name_tok_for_src = name_token != 0 8161 ? name_token 8162 : tree->nodes.main_tokens[param_type_node]; 8163 uint32_t param_inst = addParam( 8164 &decl_gz, ¶m_gz, param_tag, name_tok_for_src, param_name_str); 8165 (void)param_inst_expected; 8166 // Record param instruction index (AstGen.zig:4360). 8167 if (param_insts_len < 32) 8168 param_insts[param_insts_len++] = param_inst; 8169 8170 // Create ScopeLocalVal for this param (AstGen.zig:4349-4359). 8171 if (param_name_str != 0 && param_scope_count < 32) { 8172 ScopeLocalVal* lv = ¶m_scopes[param_scope_count++]; 8173 lv->base.tag = SCOPE_LOCAL_VAL; 8174 lv->parent = params_scope; 8175 lv->gen_zir = &decl_gz; 8176 lv->inst = param_inst + ZIR_REF_START_INDEX; // toRef() 8177 lv->token_src = name_token; 8178 lv->name = param_name_str; 8179 params_scope = &lv->base; 8180 } 8181 } 8182 8183 // --- Return type (AstGen.zig:4369-4383) --- 8184 GenZir ret_gz = makeSubBlock(&decl_gz, params_scope); 8185 uint32_t ret_ref = ZIR_REF_NONE; 8186 if (return_type_node != 0) { 8187 ret_ref = expr(&ret_gz, params_scope, return_type_node); 8188 if (ag->has_compile_errors) 8189 return; 8190 // If ret_gz produced instructions, add break_inline 8191 // (AstGen.zig:4377-4381). 8192 if (gzInstructionsLen(&ret_gz) > 0) { 8193 // break_inline targets the func instruction (which doesn't 8194 // exist yet). We use 0 as placeholder and patch later. 8195 makeBreakInline(&ret_gz, 0, ret_ref, AST_NODE_OFFSET_NONE); 8196 } 8197 } 8198 // Map void_type → .none (AstGen.zig:12054). 8199 if (ret_ref == ZIR_REF_VOID_TYPE) 8200 ret_ref = ZIR_REF_NONE; 8201 8202 uint32_t ret_body_len = gzInstructionsLen(&ret_gz); 8203 // Copy ret_body before unstacking: body_gz reuses the same scratch area. 8204 uint32_t* ret_body = NULL; 8205 if (ret_body_len > 0) { 8206 ret_body = malloc(ret_body_len * sizeof(uint32_t)); 8207 if (!ret_body) 8208 abort(); 8209 memcpy(ret_body, gzInstructionsSlice(&ret_gz), 8210 ret_body_len * sizeof(uint32_t)); 8211 } 8212 gzUnstack(&ret_gz); 8213 8214 // Restore source cursor (AstGen.zig:4387-4388). 8215 ag->source_offset = saved_source_offset; 8216 ag->source_line = saved_source_line; 8217 ag->source_column = saved_source_column; 8218 8219 // --- Body (AstGen.zig:4415-4424) --- 8220 GenZir body_gz; 8221 memset(&body_gz, 0, sizeof(body_gz)); 8222 body_gz.base.tag = SCOPE_GEN_ZIR; 8223 body_gz.parent = params_scope; 8224 body_gz.astgen = ag; 8225 body_gz.decl_node_index = proto_node; 8226 body_gz.decl_line = decl_line; 8227 body_gz.is_comptime = false; 8228 body_gz.instructions_top = ag->scratch_inst_len; 8229 8230 // Set fn_block and fn_ret_ty for the body (AstGen.zig:4442-4455). 8231 void* prev_fn_block = ag->fn_block; 8232 setFnBlock(ag, &body_gz); 8233 uint32_t prev_fn_ret_ty = ag->fn_ret_ty; 8234 if (is_inferred_error || ret_ref == ZIR_REF_NONE) { 8235 // Non-void non-trivial return type: emit ret_type instruction. 8236 if (ret_body_len > 0 || is_inferred_error) { 8237 ZirInstData rtdata; 8238 memset(&rtdata, 0, sizeof(rtdata)); 8239 rtdata.node = (int32_t)node - (int32_t)body_gz.decl_node_index; 8240 ag->fn_ret_ty 8241 = addInstruction(&body_gz, ZIR_INST_RET_TYPE, rtdata); 8242 } else { 8243 ag->fn_ret_ty = ret_ref; // void 8244 } 8245 } else { 8246 // ret_ref is a simple ref (not void, not inferred error). 8247 // Still need ret_type instruction if it resolved to an inst. 8248 if (ret_ref >= ZIR_REF_START_INDEX) { 8249 ZirInstData rtdata; 8250 memset(&rtdata, 0, sizeof(rtdata)); 8251 rtdata.node = (int32_t)node - (int32_t)body_gz.decl_node_index; 8252 ag->fn_ret_ty 8253 = addInstruction(&body_gz, ZIR_INST_RET_TYPE, rtdata); 8254 } else { 8255 ag->fn_ret_ty = ret_ref; 8256 } 8257 } 8258 8259 // Process function body (AstGen.zig:4461-4465). 8260 advanceSourceCursorToNode(ag, body_node); 8261 uint32_t lbrace_line = ag->source_line - decl_line; 8262 uint32_t lbrace_column = ag->source_column; 8263 8264 fullBodyExpr(&body_gz, &body_gz.base, RL_NONE_VAL, body_node); 8265 8266 ag->fn_block = prev_fn_block; 8267 ag->fn_ret_ty = prev_fn_ret_ty; 8268 8269 if (ag->has_compile_errors) { 8270 free(ret_body); 8271 return; 8272 } 8273 8274 // Add implicit return at end of function body 8275 // (AstGen.zig:4465-4871). 8276 if (!endsWithNoReturn(&body_gz)) { 8277 ZirInstData rdata; 8278 rdata.un_node.operand = ZIR_REF_NONE; 8279 rdata.un_node.src_node 8280 = (int32_t)node - (int32_t)body_gz.decl_node_index; 8281 addInstruction( 8282 &body_gz, ZIR_INST_RESTORE_ERR_RET_INDEX_UNCONDITIONAL, rdata); 8283 8284 uint32_t body_last_tok = lastToken(tree, body_node); 8285 ZirInstData rdata2; 8286 rdata2.un_tok.operand = ZIR_REF_VOID_VALUE; 8287 rdata2.un_tok.src_tok = tokenIndexToRelative(&body_gz, body_last_tok); 8288 addInstruction(&body_gz, ZIR_INST_RET_IMPLICIT, rdata2); 8289 } 8290 8291 // Read body before unstacking (AstGen.zig:12215-12218). 8292 const uint32_t* fn_body = gzInstructionsSlice(&body_gz); 8293 uint32_t fn_body_len = gzInstructionsLen(&body_gz); 8294 gzUnstack(&body_gz); 8295 8296 // Create func instruction (AstGen.zig:4476-4494). 8297 uint32_t func_ref = addFunc(&decl_gz, node, body_node, decl_inst, ret_ref, 8298 ret_body, ret_body_len, fn_body, fn_body_len, param_insts, 8299 param_insts_len, lbrace_line, lbrace_column, is_inferred_error); 8300 8301 // Patch ret_body break_inline to point to func instruction 8302 // (AstGen.zig:12199-12202). 8303 if (ret_body_len > 0) { 8304 uint32_t break_inst = ret_body[ret_body_len - 1]; 8305 // The break_inline payload is at payload_index; block_inst is at 8306 // offset 1 in the Break struct. 8307 uint32_t break_payload 8308 = ag->inst_datas[break_inst].break_data.payload_index; 8309 ag->extra[break_payload + 1] = func_ref - ZIR_REF_START_INDEX; 8310 } 8311 free(ret_body); 8312 8313 // break_inline returning func to declaration (AstGen.zig:4495). 8314 // nodeIndexToRelative(decl_node) = node - decl_gz.decl_node_index. 8315 makeBreakInline( 8316 &decl_gz, decl_inst, func_ref, (int32_t)node - (int32_t)proto_node); 8317 8318 // setDeclaration (AstGen.zig:4208-4225). 8319 DeclFlagsId decl_id 8320 = is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE; 8321 uint32_t name_str = identAsString(ag, fn_name_token); 8322 setDeclaration(ag, decl_inst, 8323 (SetDeclArgs) { .src_line = decl_line, 8324 .src_column = decl_column, 8325 .id = decl_id, 8326 .name = name_str, 8327 .lib_name = UINT32_MAX, 8328 .value_body = gzInstructionsSlice(&decl_gz), 8329 .value_body_len = gzInstructionsLen(&decl_gz) }); 8330 gzUnstack(&decl_gz); 8331 8332 (void)gz; 8333 } 8334 8335 // --- comptimeDecl (AstGen.zig:4645) --- 8336 8337 static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, 8338 uint32_t* decl_idx, uint32_t node) { 8339 // makeDeclaration before advanceSourceCursorToNode (AstGen.zig:4663-4665). 8340 uint32_t decl_inst = makeDeclaration(ag, node); 8341 wip_decl_insts[*decl_idx] = decl_inst; 8342 (*decl_idx)++; 8343 8344 advanceSourceCursorToNode(ag, node); 8345 8346 uint32_t decl_line = ag->source_line; 8347 uint32_t decl_column = ag->source_column; 8348 8349 // Value sub-block (AstGen.zig:4675-4686). 8350 GenZir value_gz; 8351 memset(&value_gz, 0, sizeof(value_gz)); 8352 value_gz.base.tag = SCOPE_GEN_ZIR; 8353 value_gz.parent = NULL; 8354 value_gz.astgen = ag; 8355 value_gz.decl_node_index = node; 8356 value_gz.decl_line = decl_line; 8357 value_gz.is_comptime = true; 8358 value_gz.instructions_top = ag->scratch_inst_len; 8359 8360 // For comptime {}: body is empty block → no instructions generated. 8361 // comptime_gz.isEmpty() == true → addBreak(.break_inline, decl_inst, 8362 // .void_value) (AstGen.zig:4685-4686) 8363 makeBreakInline( 8364 &value_gz, decl_inst, ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); 8365 8366 setDeclaration(ag, decl_inst, 8367 (SetDeclArgs) { .src_line = decl_line, 8368 .src_column = decl_column, 8369 .id = DECL_ID_COMPTIME, 8370 .name = 0, 8371 .lib_name = UINT32_MAX, 8372 .value_body = gzInstructionsSlice(&value_gz), 8373 .value_body_len = gzInstructionsLen(&value_gz) }); 8374 gzUnstack(&value_gz); 8375 8376 (void)gz; 8377 } 8378 8379 // --- globalVarDecl (AstGen.zig:4498) --- 8380 8381 // Extract VarDecl fields from an AST node (Ast.zig:1326-1380). 8382 typedef struct { 8383 uint32_t mut_token; 8384 uint32_t type_node; // 0 = none 8385 uint32_t align_node; // 0 = none 8386 uint32_t addrspace_node; // 0 = none 8387 uint32_t section_node; // 0 = none 8388 uint32_t init_node; // UINT32_MAX = none 8389 bool is_pub; 8390 bool is_extern; 8391 bool is_export; 8392 bool is_mutable; 8393 bool is_threadlocal; 8394 uint32_t lib_name_token; // UINT32_MAX = none 8395 } VarDeclInfo; 8396 8397 static VarDeclInfo extractVarDecl(const Ast* tree, uint32_t node) { 8398 AstNodeTag tag = tree->nodes.tags[node]; 8399 AstData nd = tree->nodes.datas[node]; 8400 uint32_t mut_token = tree->nodes.main_tokens[node]; 8401 VarDeclInfo info; 8402 memset(&info, 0, sizeof(info)); 8403 info.mut_token = mut_token; 8404 info.init_node = UINT32_MAX; 8405 info.lib_name_token = UINT32_MAX; 8406 8407 switch (tag) { 8408 case AST_NODE_SIMPLE_VAR_DECL: 8409 // lhs = type_node (optional), rhs = init_node (optional) 8410 info.type_node = nd.lhs; 8411 info.init_node = nd.rhs; 8412 break; 8413 case AST_NODE_ALIGNED_VAR_DECL: 8414 // lhs = align_node, rhs = init_node (optional) 8415 info.align_node = nd.lhs; 8416 info.init_node = nd.rhs; 8417 break; 8418 case AST_NODE_GLOBAL_VAR_DECL: { 8419 // lhs = extra_data index, rhs = init_node (optional) 8420 uint32_t ei = nd.lhs; 8421 info.type_node = tree->extra_data.arr[ei + 0]; 8422 info.align_node = tree->extra_data.arr[ei + 1]; 8423 info.addrspace_node = tree->extra_data.arr[ei + 2]; 8424 info.section_node = tree->extra_data.arr[ei + 3]; 8425 info.init_node = nd.rhs; 8426 break; 8427 } 8428 case AST_NODE_LOCAL_VAR_DECL: { 8429 // lhs = extra_data index, rhs = init_node (optional) 8430 uint32_t ei = nd.lhs; 8431 info.type_node = tree->extra_data.arr[ei + 0]; 8432 info.align_node = tree->extra_data.arr[ei + 1]; 8433 info.init_node = nd.rhs; 8434 break; 8435 } 8436 default: 8437 break; 8438 } 8439 8440 // Scan backwards from mut_token to find modifiers (Ast.zig:2003-2025). 8441 info.is_mutable = (tree->tokens.tags[mut_token] == TOKEN_KEYWORD_VAR); 8442 for (uint32_t i = mut_token; i > 0;) { 8443 i--; 8444 TokenizerTag ttag = tree->tokens.tags[i]; 8445 if (ttag == TOKEN_KEYWORD_EXTERN) 8446 info.is_extern = true; 8447 else if (ttag == TOKEN_KEYWORD_EXPORT) 8448 info.is_export = true; 8449 else if (ttag == TOKEN_KEYWORD_PUB) 8450 info.is_pub = true; 8451 else if (ttag == TOKEN_KEYWORD_THREADLOCAL) 8452 info.is_threadlocal = true; 8453 else if (ttag == TOKEN_STRING_LITERAL) 8454 info.lib_name_token = i; 8455 else 8456 break; 8457 } 8458 return info; 8459 } 8460 8461 // Compute DeclFlagsId from VarDecl properties (AstGen.zig:13916-13972). 8462 static DeclFlagsId computeVarDeclId(bool is_mutable, bool is_pub, 8463 bool is_extern, bool is_export, bool is_threadlocal, bool has_type_body, 8464 bool has_special_body, bool has_lib_name) { 8465 if (!is_mutable) { 8466 // const 8467 if (is_extern) { 8468 if (is_pub) { 8469 if (has_lib_name || has_special_body) 8470 return DECL_ID_PUB_EXTERN_CONST; 8471 return DECL_ID_PUB_EXTERN_CONST_SIMPLE; 8472 } 8473 if (has_lib_name || has_special_body) 8474 return DECL_ID_EXTERN_CONST; 8475 return DECL_ID_EXTERN_CONST_SIMPLE; 8476 } 8477 if (is_export) 8478 return is_pub ? DECL_ID_PUB_EXPORT_CONST : DECL_ID_EXPORT_CONST; 8479 if (is_pub) { 8480 if (has_special_body) 8481 return DECL_ID_PUB_CONST; 8482 if (has_type_body) 8483 return DECL_ID_PUB_CONST_TYPED; 8484 return DECL_ID_PUB_CONST_SIMPLE; 8485 } 8486 if (has_special_body) 8487 return DECL_ID_CONST; 8488 if (has_type_body) 8489 return DECL_ID_CONST_TYPED; 8490 return DECL_ID_CONST_SIMPLE; 8491 } 8492 // var 8493 if (is_extern) { 8494 if (is_pub) { 8495 if (is_threadlocal) 8496 return DECL_ID_PUB_EXTERN_VAR_THREADLOCAL; 8497 return DECL_ID_PUB_EXTERN_VAR; 8498 } 8499 if (is_threadlocal) 8500 return DECL_ID_EXTERN_VAR_THREADLOCAL; 8501 return DECL_ID_EXTERN_VAR; 8502 } 8503 if (is_export) { 8504 if (is_pub) { 8505 if (is_threadlocal) 8506 return DECL_ID_PUB_EXPORT_VAR_THREADLOCAL; 8507 return DECL_ID_PUB_EXPORT_VAR; 8508 } 8509 if (is_threadlocal) 8510 return DECL_ID_EXPORT_VAR_THREADLOCAL; 8511 return DECL_ID_EXPORT_VAR; 8512 } 8513 if (is_pub) { 8514 if (is_threadlocal) 8515 return DECL_ID_PUB_VAR_THREADLOCAL; 8516 if (has_special_body || has_type_body) 8517 return DECL_ID_PUB_VAR; 8518 return DECL_ID_PUB_VAR_SIMPLE; 8519 } 8520 if (is_threadlocal) 8521 return DECL_ID_VAR_THREADLOCAL; 8522 if (has_special_body || has_type_body) 8523 return DECL_ID_VAR; 8524 return DECL_ID_VAR_SIMPLE; 8525 } 8526 8527 static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, 8528 uint32_t* decl_idx, uint32_t node) { 8529 const Ast* tree = ag->tree; 8530 VarDeclInfo vd = extractVarDecl(tree, node); 8531 uint32_t name_token = vd.mut_token + 1; 8532 8533 // advanceSourceCursorToNode before makeDeclaration (AstGen.zig:4542-4546). 8534 advanceSourceCursorToNode(ag, node); 8535 uint32_t decl_column = ag->source_column; 8536 8537 uint32_t decl_inst = makeDeclaration(ag, node); 8538 wip_decl_insts[*decl_idx] = decl_inst; 8539 (*decl_idx)++; 8540 8541 // Set up type sub-block (AstGen.zig:4574-4582). 8542 GenZir type_gz; 8543 memset(&type_gz, 0, sizeof(type_gz)); 8544 type_gz.base.tag = SCOPE_GEN_ZIR; 8545 type_gz.astgen = ag; 8546 type_gz.decl_node_index = node; 8547 type_gz.instructions_top = ag->scratch_inst_len; 8548 type_gz.decl_line = ag->source_line; 8549 type_gz.is_comptime = true; 8550 8551 if (vd.type_node != 0) { 8552 uint32_t type_inst = typeExpr(&type_gz, &type_gz.base, vd.type_node); 8553 makeBreakInline(&type_gz, decl_inst, type_inst, 0); 8554 } 8555 8556 // Record type_gz boundary for slicing. 8557 uint32_t type_top = ag->scratch_inst_len; 8558 8559 // Align sub-block (AstGen.zig:4592-4596). 8560 GenZir align_gz; 8561 memset(&align_gz, 0, sizeof(align_gz)); 8562 align_gz.base.tag = SCOPE_GEN_ZIR; 8563 align_gz.astgen = ag; 8564 align_gz.decl_node_index = node; 8565 align_gz.instructions_top = type_top; 8566 align_gz.decl_line = ag->source_line; 8567 align_gz.is_comptime = true; 8568 8569 if (vd.align_node != 0) { 8570 uint32_t align_inst = expr(&align_gz, &align_gz.base, vd.align_node); 8571 makeBreakInline(&align_gz, decl_inst, align_inst, 0); 8572 } 8573 8574 uint32_t align_top = ag->scratch_inst_len; 8575 8576 // Linksection sub-block (AstGen.zig:4598-4602). 8577 GenZir linksection_gz; 8578 memset(&linksection_gz, 0, sizeof(linksection_gz)); 8579 linksection_gz.base.tag = SCOPE_GEN_ZIR; 8580 linksection_gz.astgen = ag; 8581 linksection_gz.decl_node_index = node; 8582 linksection_gz.instructions_top = align_top; 8583 linksection_gz.decl_line = ag->source_line; 8584 linksection_gz.is_comptime = true; 8585 8586 if (vd.section_node != 0) { 8587 uint32_t ls_inst 8588 = expr(&linksection_gz, &linksection_gz.base, vd.section_node); 8589 makeBreakInline(&linksection_gz, decl_inst, ls_inst, 0); 8590 } 8591 8592 uint32_t linksection_top = ag->scratch_inst_len; 8593 8594 // Addrspace sub-block (AstGen.zig:4604-4608). 8595 GenZir addrspace_gz; 8596 memset(&addrspace_gz, 0, sizeof(addrspace_gz)); 8597 addrspace_gz.base.tag = SCOPE_GEN_ZIR; 8598 addrspace_gz.astgen = ag; 8599 addrspace_gz.decl_node_index = node; 8600 addrspace_gz.instructions_top = linksection_top; 8601 addrspace_gz.decl_line = ag->source_line; 8602 addrspace_gz.is_comptime = true; 8603 8604 if (vd.addrspace_node != 0) { 8605 uint32_t as_inst 8606 = expr(&addrspace_gz, &addrspace_gz.base, vd.addrspace_node); 8607 makeBreakInline(&addrspace_gz, decl_inst, as_inst, 0); 8608 } 8609 8610 uint32_t addrspace_top = ag->scratch_inst_len; 8611 8612 // Value sub-block (AstGen.zig:4610-4620). 8613 GenZir value_gz; 8614 memset(&value_gz, 0, sizeof(value_gz)); 8615 value_gz.base.tag = SCOPE_GEN_ZIR; 8616 value_gz.astgen = ag; 8617 value_gz.decl_node_index = node; 8618 value_gz.instructions_top = addrspace_top; 8619 value_gz.decl_line = ag->source_line; 8620 value_gz.is_comptime = true; 8621 8622 if (vd.init_node != UINT32_MAX && vd.init_node != 0) { 8623 uint32_t init_ref = expr(&value_gz, &value_gz.base, vd.init_node); 8624 makeBreakInline(&value_gz, decl_inst, init_ref, 0); 8625 } 8626 8627 // Compute body slices (instructionsSliceUpto). 8628 const uint32_t* type_body 8629 = ag->scratch_instructions + type_gz.instructions_top; 8630 uint32_t type_body_len = type_top - type_gz.instructions_top; 8631 const uint32_t* align_body 8632 = ag->scratch_instructions + align_gz.instructions_top; 8633 uint32_t align_body_len = align_top - align_gz.instructions_top; 8634 const uint32_t* ls_body 8635 = ag->scratch_instructions + linksection_gz.instructions_top; 8636 uint32_t ls_body_len = linksection_top - linksection_gz.instructions_top; 8637 const uint32_t* as_body 8638 = ag->scratch_instructions + addrspace_gz.instructions_top; 8639 uint32_t as_body_len = addrspace_top - addrspace_gz.instructions_top; 8640 const uint32_t* val_body = gzInstructionsSlice(&value_gz); 8641 uint32_t val_body_len = gzInstructionsLen(&value_gz); 8642 8643 bool has_type_body = (type_body_len > 0); 8644 bool has_special_body 8645 = (align_body_len > 0 || ls_body_len > 0 || as_body_len > 0); 8646 bool has_lib_name = (vd.lib_name_token != UINT32_MAX); 8647 8648 uint32_t name_str = identAsString(ag, name_token); 8649 8650 DeclFlagsId decl_id = computeVarDeclId(vd.is_mutable, vd.is_pub, 8651 vd.is_extern, vd.is_export, vd.is_threadlocal, has_type_body, 8652 has_special_body, has_lib_name); 8653 8654 // Compute lib_name string index. 8655 uint32_t lib_name = UINT32_MAX; 8656 if (has_lib_name) { 8657 uint32_t li, ll; 8658 strLitAsString(ag, vd.lib_name_token, &li, &ll); 8659 lib_name = li; 8660 } 8661 8662 setDeclaration(ag, decl_inst, 8663 (SetDeclArgs) { .src_line = ag->source_line, 8664 .src_column = decl_column, 8665 .id = decl_id, 8666 .name = name_str, 8667 .lib_name = lib_name, 8668 .type_body = type_body, 8669 .type_body_len = type_body_len, 8670 .align_body = align_body, 8671 .align_body_len = align_body_len, 8672 .linksection_body = ls_body, 8673 .linksection_body_len = ls_body_len, 8674 .addrspace_body = as_body, 8675 .addrspace_body_len = as_body_len, 8676 .value_body = val_body, 8677 .value_body_len = val_body_len }); 8678 8679 gzUnstack(&value_gz); 8680 8681 (void)gz; 8682 } 8683 8684 // --- nodeImpliesMoreThanOnePossibleValue (AstGen.zig:10548) --- 8685 // Check if an identifier is a primitive type with more than one value. 8686 static bool identImpliesMoreThanOnePossibleValue( 8687 const Ast* tree, uint32_t main_token) { 8688 uint32_t start = tree->tokens.starts[main_token]; 8689 const char* src = tree->source + start; 8690 // Match known primitive types that have more than one possible value. 8691 // (AstGen.zig:10729-10766) 8692 if (src[0] == 'u' || src[0] == 'i') { 8693 // u8, u16, u32, u64, u128, u1, u29, usize, i8, i16, i32, i64, i128, 8694 // isize 8695 char c1 = src[1]; 8696 if (c1 >= '0' && c1 <= '9') 8697 return true; 8698 if (c1 == 's') // usize, isize 8699 return (src[2] == 'i' && src[3] == 'z' && src[4] == 'e'); 8700 } 8701 if (src[0] == 'f') { 8702 // f16, f32, f64, f80, f128 8703 char c1 = src[1]; 8704 if (c1 >= '0' && c1 <= '9') 8705 return true; 8706 } 8707 if (src[0] == 'b' && src[1] == 'o' && src[2] == 'o' && src[3] == 'l' 8708 && !(src[4] >= 'a' && src[4] <= 'z') 8709 && !(src[4] >= 'A' && src[4] <= 'Z') 8710 && !(src[4] >= '0' && src[4] <= '9') && src[4] != '_') 8711 return true; 8712 if (src[0] == 'c' && src[1] == '_') 8713 return true; // c_int, c_long, etc. 8714 if (src[0] == 'a' && src[1] == 'n' && src[2] == 'y') { 8715 // anyerror, anyframe, anyopaque 8716 return true; 8717 } 8718 if (src[0] == 'c' && src[1] == 'o' && src[2] == 'm' && src[3] == 'p' 8719 && src[4] == 't' && src[5] == 'i' && src[6] == 'm' && src[7] == 'e') 8720 return true; // comptime_float, comptime_int 8721 if (src[0] == 't' && src[1] == 'y' && src[2] == 'p' && src[3] == 'e' 8722 && !(src[4] >= 'a' && src[4] <= 'z') 8723 && !(src[4] >= 'A' && src[4] <= 'Z') 8724 && !(src[4] >= '0' && src[4] <= '9') && src[4] != '_') 8725 return true; 8726 return false; 8727 } 8728 8729 static bool nodeImpliesMoreThanOnePossibleValue( 8730 const Ast* tree, uint32_t node) { 8731 uint32_t cur = node; 8732 while (1) { 8733 AstNodeTag tag = tree->nodes.tags[cur]; 8734 switch (tag) { 8735 // Pointer/optional/array/anyframe types → true 8736 // (AstGen.zig:10718-10725) 8737 case AST_NODE_PTR_TYPE_ALIGNED: 8738 case AST_NODE_PTR_TYPE_SENTINEL: 8739 case AST_NODE_PTR_TYPE: 8740 case AST_NODE_PTR_TYPE_BIT_RANGE: 8741 case AST_NODE_OPTIONAL_TYPE: 8742 case AST_NODE_ANYFRAME_TYPE: 8743 case AST_NODE_ARRAY_TYPE_SENTINEL: 8744 return true; 8745 // Forward to LHS: try, comptime, nosuspend 8746 // (AstGen.zig:10710-10713) 8747 case AST_NODE_TRY: 8748 case AST_NODE_COMPTIME: 8749 case AST_NODE_NOSUSPEND: 8750 cur = tree->nodes.datas[cur].lhs; 8751 continue; 8752 // Forward to LHS: grouped_expression, unwrap_optional 8753 // (AstGen.zig:10714-10716) 8754 case AST_NODE_GROUPED_EXPRESSION: 8755 case AST_NODE_UNWRAP_OPTIONAL: 8756 cur = tree->nodes.datas[cur].lhs; 8757 continue; 8758 // Identifier: check primitives (AstGen.zig:10727-10780) 8759 case AST_NODE_IDENTIFIER: 8760 return identImpliesMoreThanOnePossibleValue( 8761 tree, tree->nodes.main_tokens[cur]); 8762 default: 8763 return false; 8764 } 8765 } 8766 } 8767 8768 // --- nodeImpliesComptimeOnly (AstGen.zig:10787) --- 8769 8770 static bool identImpliesComptimeOnly(const Ast* tree, uint32_t main_token) { 8771 uint32_t start = tree->tokens.starts[main_token]; 8772 const char* src = tree->source + start; 8773 // Only comptime_float, comptime_int, type → true 8774 // (AstGen.zig:11010-11013) 8775 if (src[0] == 'c' && src[1] == 'o' && src[2] == 'm' && src[3] == 'p' 8776 && src[4] == 't' && src[5] == 'i' && src[6] == 'm' && src[7] == 'e') 8777 return true; // comptime_float, comptime_int 8778 if (src[0] == 't' && src[1] == 'y' && src[2] == 'p' && src[3] == 'e' 8779 && !(src[4] >= 'a' && src[4] <= 'z') 8780 && !(src[4] >= 'A' && src[4] <= 'Z') 8781 && !(src[4] >= '0' && src[4] <= '9') && src[4] != '_') 8782 return true; 8783 return false; 8784 } 8785 8786 static bool nodeImpliesComptimeOnly(const Ast* tree, uint32_t node) { 8787 uint32_t cur = node; 8788 while (1) { 8789 AstNodeTag tag = tree->nodes.tags[cur]; 8790 switch (tag) { 8791 // Function prototypes → true (AstGen.zig:10950-10955) 8792 case AST_NODE_FN_PROTO_SIMPLE: 8793 case AST_NODE_FN_PROTO_MULTI: 8794 case AST_NODE_FN_PROTO_ONE: 8795 case AST_NODE_FN_PROTO: 8796 return true; 8797 // Forward to LHS: try, comptime, nosuspend 8798 case AST_NODE_TRY: 8799 case AST_NODE_COMPTIME: 8800 case AST_NODE_NOSUSPEND: 8801 cur = tree->nodes.datas[cur].lhs; 8802 continue; 8803 case AST_NODE_GROUPED_EXPRESSION: 8804 case AST_NODE_UNWRAP_OPTIONAL: 8805 cur = tree->nodes.datas[cur].lhs; 8806 continue; 8807 // Identifier: check primitives 8808 case AST_NODE_IDENTIFIER: 8809 return identImpliesComptimeOnly( 8810 tree, tree->nodes.main_tokens[cur]); 8811 default: 8812 return false; 8813 } 8814 } 8815 } 8816 8817 // --- WipMembers (AstGen.zig:3989) --- 8818 // Tracks decl indices, field bit-flags, and per-field data during container 8819 // processing. All data lives in a single malloc'd array laid out as: 8820 // [decls (decl_count)] [field_bits (ceil)] [fields (up to field_count*max)] 8821 // Bodies are tracked separately in a dynamic array. 8822 8823 typedef struct { 8824 uint32_t* payload; // malloc'd array 8825 uint32_t payload_top; // always 0 (start of decls region) 8826 uint32_t field_bits_start; 8827 uint32_t fields_start; 8828 uint32_t fields_end; 8829 uint32_t decl_index; 8830 uint32_t field_index; 8831 // Bodies scratch: dynamically grown array for field type/align/init 8832 // bodies. 8833 uint32_t* bodies; 8834 uint32_t bodies_len; 8835 uint32_t bodies_cap; 8836 } WipMembers; 8837 8838 static WipMembers wipMembersInit(uint32_t decl_count, uint32_t field_count) { 8839 // bits_per_field = 4, max_field_size = 5 8840 uint32_t fields_per_u32 = 8; // 32 / 4 8841 uint32_t field_bits_start = decl_count; 8842 uint32_t bit_words = field_count > 0 8843 ? (field_count + fields_per_u32 - 1) / fields_per_u32 8844 : 0; 8845 uint32_t fields_start = field_bits_start + bit_words; 8846 uint32_t payload_end = fields_start + field_count * 5; 8847 uint32_t alloc_size = payload_end > 0 ? payload_end : 1; 8848 uint32_t* payload = calloc(alloc_size, sizeof(uint32_t)); 8849 if (!payload) 8850 exit(1); 8851 WipMembers wm; 8852 memset(&wm, 0, sizeof(wm)); 8853 wm.payload = payload; 8854 wm.payload_top = 0; 8855 wm.field_bits_start = field_bits_start; 8856 wm.fields_start = fields_start; 8857 wm.fields_end = fields_start; 8858 wm.decl_index = 0; 8859 wm.field_index = 0; 8860 wm.bodies = NULL; 8861 wm.bodies_len = 0; 8862 wm.bodies_cap = 0; 8863 return wm; 8864 } 8865 8866 static void wipMembersDeinit(WipMembers* wm) { 8867 free(wm->payload); 8868 free(wm->bodies); 8869 } 8870 8871 static void wipMembersNextDecl(WipMembers* wm, uint32_t decl_inst) { 8872 wm->payload[wm->payload_top + wm->decl_index] = decl_inst; 8873 wm->decl_index++; 8874 } 8875 8876 // bits_per_field = 4: bits[0]=have_align, bits[1]=have_value, 8877 // bits[2]=is_comptime, bits[3]=have_type_body 8878 static void wipMembersNextField(WipMembers* wm, bool bits[4]) { 8879 uint32_t fields_per_u32 = 8; // 32 / 4 8880 uint32_t index = wm->field_bits_start + wm->field_index / fields_per_u32; 8881 uint32_t bit_bag 8882 = (wm->field_index % fields_per_u32 == 0) ? 0 : wm->payload[index]; 8883 bit_bag >>= 4; 8884 for (int i = 0; i < 4; i++) { 8885 bit_bag |= ((uint32_t)(bits[i] ? 1 : 0)) << (32 - 4 + i); 8886 } 8887 wm->payload[index] = bit_bag; 8888 wm->field_index++; 8889 } 8890 8891 static void wipMembersAppendToField(WipMembers* wm, uint32_t data) { 8892 wm->payload[wm->fields_end] = data; 8893 wm->fields_end++; 8894 } 8895 8896 static void wipMembersFinishBits(WipMembers* wm) { 8897 uint32_t fields_per_u32 = 8; // 32 / 4 8898 uint32_t empty_field_slots 8899 = fields_per_u32 - (wm->field_index % fields_per_u32); 8900 if (wm->field_index > 0 && empty_field_slots < fields_per_u32) { 8901 uint32_t index 8902 = wm->field_bits_start + wm->field_index / fields_per_u32; 8903 wm->payload[index] >>= (empty_field_slots * 4); 8904 } 8905 } 8906 8907 // Returns pointer to decls region and its length. 8908 static const uint32_t* wipMembersDeclsSlice( 8909 const WipMembers* wm, uint32_t* out_len) { 8910 *out_len = wm->decl_index; 8911 return wm->payload + wm->payload_top; 8912 } 8913 8914 // Returns pointer to fields region (field_bits + field_data) and its length. 8915 static const uint32_t* wipMembersFieldsSlice( 8916 const WipMembers* wm, uint32_t* out_len) { 8917 *out_len = wm->fields_end - wm->field_bits_start; 8918 return wm->payload + wm->field_bits_start; 8919 } 8920 8921 // Append body instructions to the WipMembers bodies scratch. 8922 static void wipMembersBodiesAppend( 8923 WipMembers* wm, const uint32_t* data, uint32_t len) { 8924 if (wm->bodies_len + len > wm->bodies_cap) { 8925 uint32_t new_cap = wm->bodies_cap == 0 ? 64 : wm->bodies_cap * 2; 8926 while (new_cap < wm->bodies_len + len) 8927 new_cap *= 2; 8928 wm->bodies = realloc(wm->bodies, new_cap * sizeof(uint32_t)); 8929 if (!wm->bodies) 8930 exit(1); 8931 wm->bodies_cap = new_cap; 8932 } 8933 memcpy(wm->bodies + wm->bodies_len, data, len * sizeof(uint32_t)); 8934 wm->bodies_len += len; 8935 } 8936 8937 // Append body instructions with ref_table fixups to wm->bodies. 8938 static void wipMembersBodiesAppendWithFixups( 8939 WipMembers* wm, AstGenCtx* ag, const uint32_t* body, uint32_t body_len) { 8940 for (uint32_t i = 0; i < body_len; i++) { 8941 uint32_t inst = body[i]; 8942 // Grow if needed. 8943 if (wm->bodies_len + 1 > wm->bodies_cap) { 8944 uint32_t new_cap = wm->bodies_cap == 0 ? 64 : wm->bodies_cap * 2; 8945 wm->bodies = realloc(wm->bodies, new_cap * sizeof(uint32_t)); 8946 if (!wm->bodies) 8947 exit(1); 8948 wm->bodies_cap = new_cap; 8949 } 8950 wm->bodies[wm->bodies_len++] = inst; 8951 // Check for ref fixup. 8952 uint32_t ref_inst; 8953 while (refTableFetchRemove(ag, inst, &ref_inst)) { 8954 if (wm->bodies_len + 1 > wm->bodies_cap) { 8955 uint32_t new_cap = wm->bodies_cap * 2; 8956 wm->bodies = realloc(wm->bodies, new_cap * sizeof(uint32_t)); 8957 if (!wm->bodies) 8958 exit(1); 8959 wm->bodies_cap = new_cap; 8960 } 8961 wm->bodies[wm->bodies_len++] = ref_inst; 8962 inst = ref_inst; 8963 } 8964 } 8965 } 8966 8967 // --- containerDecl (AstGen.zig:5468) --- 8968 // Handles container declarations as expressions (struct{}, enum{}, etc.). 8969 8970 static uint32_t containerDecl(GenZir* gz, Scope* scope, uint32_t node) { 8971 AstGenCtx* ag = gz->astgen; 8972 const Ast* tree = ag->tree; 8973 AstNodeTag tag = tree->nodes.tags[node]; 8974 AstData nd = tree->nodes.datas[node]; 8975 8976 // Extract members based on node type (Ast.zig:2459-2470). 8977 uint32_t members_buf[2]; 8978 const uint32_t* members; 8979 uint32_t members_len; 8980 8981 switch (tag) { 8982 case AST_NODE_CONTAINER_DECL_TWO: 8983 case AST_NODE_CONTAINER_DECL_TWO_TRAILING: 8984 case AST_NODE_TAGGED_UNION_TWO: 8985 case AST_NODE_TAGGED_UNION_TWO_TRAILING: { 8986 // lhs and rhs are optional member nodes (0 = none). 8987 members_len = 0; 8988 if (nd.lhs != 0) 8989 members_buf[members_len++] = nd.lhs; 8990 if (nd.rhs != 0) 8991 members_buf[members_len++] = nd.rhs; 8992 members = members_buf; 8993 break; 8994 } 8995 case AST_NODE_CONTAINER_DECL: 8996 case AST_NODE_CONTAINER_DECL_TRAILING: 8997 case AST_NODE_TAGGED_UNION: 8998 case AST_NODE_TAGGED_UNION_TRAILING: { 8999 // extra_data[lhs..rhs] contains members. 9000 members = tree->extra_data.arr + nd.lhs; 9001 members_len = nd.rhs - nd.lhs; 9002 break; 9003 } 9004 case AST_NODE_CONTAINER_DECL_ARG: 9005 case AST_NODE_CONTAINER_DECL_ARG_TRAILING: 9006 case AST_NODE_TAGGED_UNION_ENUM_TAG: 9007 case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: { 9008 // lhs is arg node, rhs is extra index → SubRange(start, end). 9009 uint32_t start = tree->extra_data.arr[nd.rhs]; 9010 uint32_t end = tree->extra_data.arr[nd.rhs + 1]; 9011 members = tree->extra_data.arr + start; 9012 members_len = end - start; 9013 break; 9014 } 9015 default: 9016 SET_ERROR(ag); 9017 return ZIR_REF_VOID_VALUE; 9018 } 9019 9020 // Save/clear fn_block for nested containers (AstGen.zig:5480-5482). 9021 void* prev_fn_block = ag->fn_block; 9022 ag->fn_block = NULL; 9023 9024 // Dispatch based on container keyword (AstGen.zig:5485-5536). 9025 uint32_t main_token = tree->nodes.main_tokens[node]; 9026 TokenizerTag kw_tag = tree->tokens.tags[main_token]; 9027 uint32_t decl_inst; 9028 switch (kw_tag) { 9029 case TOKEN_KEYWORD_STRUCT: 9030 decl_inst = structDeclInner(ag, gz, node, members, members_len); 9031 break; 9032 case TOKEN_KEYWORD_ENUM: 9033 decl_inst = enumDeclInner(ag, gz, node, members, members_len); 9034 break; 9035 default: 9036 // union/opaque: fall back to struct for now. 9037 decl_inst = structDeclInner(ag, gz, node, members, members_len); 9038 break; 9039 } 9040 (void)scope; 9041 9042 ag->fn_block = prev_fn_block; 9043 return decl_inst + ZIR_REF_START_INDEX; 9044 } 9045 9046 // --- EnumDecl.Small packing (Zir.zig EnumDecl.Small) --- 9047 9048 typedef struct { 9049 bool has_tag_type; 9050 bool has_captures_len; 9051 bool has_body_len; 9052 bool has_fields_len; 9053 bool has_decls_len; 9054 uint8_t name_strategy; // 2 bits 9055 bool nonexhaustive; 9056 } EnumDeclSmall; 9057 9058 static uint16_t packEnumDeclSmall(EnumDeclSmall s) { 9059 uint16_t r = 0; 9060 if (s.has_tag_type) 9061 r |= (1u << 0); 9062 if (s.has_captures_len) 9063 r |= (1u << 1); 9064 if (s.has_body_len) 9065 r |= (1u << 2); 9066 if (s.has_fields_len) 9067 r |= (1u << 3); 9068 if (s.has_decls_len) 9069 r |= (1u << 4); 9070 r |= (uint16_t)(s.name_strategy & 0x3u) << 5; 9071 if (s.nonexhaustive) 9072 r |= (1u << 7); 9073 return r; 9074 } 9075 9076 // Mirrors GenZir.setEnum (AstGen.zig:13080). 9077 static void setEnum(AstGenCtx* ag, uint32_t inst, uint32_t src_node, 9078 EnumDeclSmall small, uint32_t fields_len, uint32_t decls_len) { 9079 ensureExtraCapacity(ag, 6 + 3); 9080 9081 uint32_t payload_index = ag->extra_len; 9082 9083 // fields_hash (4 words): zero-filled. 9084 ag->extra[ag->extra_len++] = 0; 9085 ag->extra[ag->extra_len++] = 0; 9086 ag->extra[ag->extra_len++] = 0; 9087 ag->extra[ag->extra_len++] = 0; 9088 9089 ag->extra[ag->extra_len++] = ag->source_line; 9090 ag->extra[ag->extra_len++] = src_node; 9091 9092 if (small.has_fields_len) 9093 ag->extra[ag->extra_len++] = fields_len; 9094 if (small.has_decls_len) 9095 ag->extra[ag->extra_len++] = decls_len; 9096 9097 ag->inst_tags[inst] = ZIR_INST_EXTENDED; 9098 ZirInstData data; 9099 memset(&data, 0, sizeof(data)); 9100 data.extended.opcode = (uint16_t)ZIR_EXT_ENUM_DECL; 9101 data.extended.small = packEnumDeclSmall(small); 9102 data.extended.operand = payload_index; 9103 ag->inst_datas[inst] = data; 9104 } 9105 9106 // --- enumDeclInner (AstGen.zig:5508) --- 9107 9108 static uint32_t enumDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, 9109 const uint32_t* members, uint32_t members_len) { 9110 const Ast* tree = ag->tree; 9111 uint32_t decl_inst = reserveInstructionIndex(ag); 9112 gzAppendInstruction(gz, decl_inst); 9113 9114 if (members_len == 0) { 9115 EnumDeclSmall small; 9116 memset(&small, 0, sizeof(small)); 9117 setEnum(ag, decl_inst, node, small, 0, 0); 9118 return decl_inst; 9119 } 9120 9121 advanceSourceCursorToNode(ag, node); 9122 9123 uint32_t decl_count = scanContainer(ag, members, members_len); 9124 uint32_t field_count = members_len - decl_count; 9125 9126 // Use WipMembers for decls and field data. 9127 // Enum fields: 1 bit per field (has_value), max 2 words per field 9128 // (name + value). 9129 WipMembers wm = wipMembersInit(decl_count, field_count); 9130 9131 // Enum fields use 1 bit per field: has_value. 9132 // We use the same WipMembers but with 1-bit fields. 9133 // Actually, upstream uses bits_per_field=1, max_field_size=2. 9134 // Re-init with correct params would be better but let's reuse. 9135 // For simplicity: track field data manually. 9136 uint32_t* field_names = NULL; 9137 uint32_t field_names_len = 0; 9138 uint32_t field_names_cap = 0; 9139 9140 for (uint32_t i = 0; i < members_len; i++) { 9141 uint32_t member_node = members[i]; 9142 AstNodeTag mtag = tree->nodes.tags[member_node]; 9143 switch (mtag) { 9144 case AST_NODE_COMPTIME: 9145 comptimeDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9146 break; 9147 case AST_NODE_SIMPLE_VAR_DECL: 9148 case AST_NODE_GLOBAL_VAR_DECL: 9149 case AST_NODE_LOCAL_VAR_DECL: 9150 case AST_NODE_ALIGNED_VAR_DECL: 9151 globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9152 break; 9153 case AST_NODE_FN_DECL: 9154 fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9155 break; 9156 case AST_NODE_TEST_DECL: 9157 testDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9158 break; 9159 case AST_NODE_CONTAINER_FIELD_INIT: 9160 case AST_NODE_CONTAINER_FIELD_ALIGN: 9161 case AST_NODE_CONTAINER_FIELD: { 9162 // Enum field: just a name (AstGen.zig:5617-5670). 9163 uint32_t main_token = tree->nodes.main_tokens[member_node]; 9164 uint32_t field_name = identAsString(ag, main_token); 9165 // Grow field_names array. 9166 if (field_names_len >= field_names_cap) { 9167 uint32_t new_cap 9168 = field_names_cap == 0 ? 8 : field_names_cap * 2; 9169 field_names = realloc(field_names, new_cap * sizeof(uint32_t)); 9170 if (!field_names) 9171 exit(1); 9172 field_names_cap = new_cap; 9173 } 9174 field_names[field_names_len++] = field_name; 9175 break; 9176 } 9177 default: 9178 SET_ERROR(ag); 9179 break; 9180 } 9181 } 9182 9183 EnumDeclSmall small; 9184 memset(&small, 0, sizeof(small)); 9185 small.has_fields_len = (field_count > 0); 9186 small.has_decls_len = (decl_count > 0); 9187 setEnum(ag, decl_inst, node, small, field_count, decl_count); 9188 9189 // Append: decls, field_bits, field_names (AstGen.zig:5724-5729). 9190 uint32_t decls_len_out; 9191 const uint32_t* decls_slice = wipMembersDeclsSlice(&wm, &decls_len_out); 9192 9193 // Field bits: 1 bit per field (has_value = false for simple enums). 9194 uint32_t fields_per_u32 = 32; 9195 uint32_t bit_words = field_count > 0 9196 ? (field_count + fields_per_u32 - 1) / fields_per_u32 9197 : 0; 9198 9199 ensureExtraCapacity(ag, decls_len_out + bit_words + field_names_len); 9200 for (uint32_t i = 0; i < decls_len_out; i++) 9201 ag->extra[ag->extra_len++] = decls_slice[i]; 9202 // Field bits: all zero (no values). 9203 for (uint32_t i = 0; i < bit_words; i++) 9204 ag->extra[ag->extra_len++] = 0; 9205 // Field names. 9206 for (uint32_t i = 0; i < field_names_len; i++) 9207 ag->extra[ag->extra_len++] = field_names[i]; 9208 9209 free(field_names); 9210 wipMembersDeinit(&wm); 9211 return decl_inst; 9212 } 9213 9214 // --- structDeclInner (AstGen.zig:4926) --- 9215 9216 static uint32_t structDeclInner(AstGenCtx* ag, GenZir* gz, uint32_t node, 9217 const uint32_t* members, uint32_t members_len) { 9218 const Ast* tree = ag->tree; 9219 uint32_t decl_inst = reserveInstructionIndex(ag); 9220 gzAppendInstruction(gz, decl_inst); 9221 9222 // Fast path: no members, no backing int (AstGen.zig:4954-4970). 9223 if (members_len == 0) { 9224 StructDeclSmall small; 9225 memset(&small, 0, sizeof(small)); 9226 setStruct(ag, decl_inst, node, small, 0, 0, 0); 9227 return decl_inst; 9228 } 9229 9230 // Non-empty container (AstGen.zig:4973-5189). 9231 advanceSourceCursorToNode(ag, node); 9232 9233 uint32_t decl_count = scanContainer(ag, members, members_len); 9234 uint32_t field_count = members_len - decl_count; 9235 9236 WipMembers wm = wipMembersInit(decl_count, field_count); 9237 9238 // Set up block_scope for field type/align/init expressions. 9239 // (AstGen.zig:4983-4992) 9240 GenZir block_scope; 9241 memset(&block_scope, 0, sizeof(block_scope)); 9242 block_scope.base.tag = SCOPE_GEN_ZIR; 9243 block_scope.parent = NULL; 9244 block_scope.astgen = ag; 9245 block_scope.decl_node_index = node; 9246 block_scope.decl_line = ag->source_line; 9247 block_scope.is_comptime = true; 9248 block_scope.instructions_top = ag->scratch_inst_len; 9249 9250 bool known_non_opv = false; 9251 bool known_comptime_only = false; 9252 bool any_comptime_fields = false; 9253 bool any_aligned_fields = false; 9254 bool any_default_inits = false; 9255 9256 // Process each member (AstGen.zig:5060-5147). 9257 for (uint32_t i = 0; i < members_len; i++) { 9258 uint32_t member_node = members[i]; 9259 AstNodeTag mtag = tree->nodes.tags[member_node]; 9260 switch (mtag) { 9261 case AST_NODE_COMPTIME: 9262 comptimeDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9263 break; 9264 case AST_NODE_SIMPLE_VAR_DECL: 9265 globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9266 break; 9267 case AST_NODE_TEST_DECL: 9268 testDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9269 break; 9270 case AST_NODE_FN_DECL: 9271 fnDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9272 break; 9273 case AST_NODE_USINGNAMESPACE: 9274 case AST_NODE_GLOBAL_VAR_DECL: 9275 case AST_NODE_LOCAL_VAR_DECL: 9276 case AST_NODE_ALIGNED_VAR_DECL: 9277 globalVarDecl(ag, gz, wm.payload, &wm.decl_index, member_node); 9278 break; 9279 case AST_NODE_CONTAINER_FIELD_INIT: 9280 case AST_NODE_CONTAINER_FIELD_ALIGN: 9281 case AST_NODE_CONTAINER_FIELD: { 9282 // Extract field info from AST node (Ast.zig:1413-1454). 9283 uint32_t main_token = tree->nodes.main_tokens[member_node]; 9284 AstData nd = tree->nodes.datas[member_node]; 9285 uint32_t type_node = nd.lhs; 9286 uint32_t align_node = 0; 9287 uint32_t value_node = 0; 9288 bool has_comptime_token = false; 9289 9290 switch (mtag) { 9291 case AST_NODE_CONTAINER_FIELD_INIT: 9292 // lhs = type_expr, rhs = value_expr (optional, 0=none) 9293 value_node = nd.rhs; 9294 break; 9295 case AST_NODE_CONTAINER_FIELD_ALIGN: 9296 // lhs = type_expr, rhs = align_expr 9297 align_node = nd.rhs; 9298 break; 9299 case AST_NODE_CONTAINER_FIELD: 9300 // lhs = type_expr, rhs = extra index to {align, value} 9301 if (nd.rhs != 0) { 9302 align_node = tree->extra_data.arr[nd.rhs]; 9303 value_node = tree->extra_data.arr[nd.rhs + 1]; 9304 } 9305 break; 9306 default: 9307 break; 9308 } 9309 9310 // Check for comptime token preceding main_token 9311 // (Ast.zig:2071-2082). 9312 if (main_token > 0 9313 && tree->tokens.tags[main_token - 1] 9314 == TOKEN_KEYWORD_COMPTIME) { 9315 has_comptime_token = true; 9316 } 9317 9318 // Field name (AstGen.zig:5080). 9319 uint32_t field_name = identAsString(ag, main_token); 9320 wipMembersAppendToField(&wm, field_name); 9321 9322 // Type expression (AstGen.zig:5089-5109). 9323 bool have_type_body = false; 9324 uint32_t field_type = 0; 9325 if (type_node != 0) { 9326 field_type 9327 = typeExpr(&block_scope, &block_scope.base, type_node); 9328 have_type_body = (gzInstructionsLen(&block_scope) > 0); 9329 } 9330 9331 bool have_align = (align_node != 0); 9332 bool have_value = (value_node != 0); 9333 bool is_comptime = has_comptime_token; 9334 9335 if (is_comptime) { 9336 any_comptime_fields = true; 9337 } else { 9338 // (AstGen.zig:5106-5109) 9339 if (type_node != 0) { 9340 known_non_opv = known_non_opv 9341 || nodeImpliesMoreThanOnePossibleValue( 9342 tree, type_node); 9343 known_comptime_only = known_comptime_only 9344 || nodeImpliesComptimeOnly(tree, type_node); 9345 } 9346 } 9347 9348 bool field_bits[4] 9349 = { have_align, have_value, is_comptime, have_type_body }; 9350 wipMembersNextField(&wm, field_bits); 9351 9352 if (have_type_body) { 9353 // Emit break_inline to carry the type value 9354 // (AstGen.zig:5097-5099). 9355 if (!endsWithNoReturn(&block_scope)) { 9356 makeBreakInline(&block_scope, decl_inst, field_type, 9357 AST_NODE_OFFSET_NONE); 9358 } 9359 uint32_t raw_len = gzInstructionsLen(&block_scope); 9360 const uint32_t* body = gzInstructionsSlice(&block_scope); 9361 uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_len); 9362 uint32_t bodies_before = wm.bodies_len; 9363 wipMembersBodiesAppendWithFixups(&wm, ag, body, raw_len); 9364 (void)bodies_before; 9365 wipMembersAppendToField(&wm, body_len); 9366 // Reset block_scope. 9367 ag->scratch_inst_len = block_scope.instructions_top; 9368 } else { 9369 wipMembersAppendToField(&wm, field_type); 9370 } 9371 9372 if (have_align) { 9373 any_aligned_fields = true; 9374 uint32_t align_ref 9375 = expr(&block_scope, &block_scope.base, align_node); 9376 if (!endsWithNoReturn(&block_scope)) { 9377 makeBreakInline(&block_scope, decl_inst, align_ref, 9378 AST_NODE_OFFSET_NONE); 9379 } 9380 uint32_t raw_len = gzInstructionsLen(&block_scope); 9381 const uint32_t* body = gzInstructionsSlice(&block_scope); 9382 uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_len); 9383 wipMembersBodiesAppendWithFixups(&wm, ag, body, raw_len); 9384 wipMembersAppendToField(&wm, body_len); 9385 ag->scratch_inst_len = block_scope.instructions_top; 9386 } 9387 9388 if (have_value) { 9389 any_default_inits = true; 9390 uint32_t default_ref 9391 = expr(&block_scope, &block_scope.base, value_node); 9392 if (!endsWithNoReturn(&block_scope)) { 9393 makeBreakInline(&block_scope, decl_inst, default_ref, 9394 AST_NODE_OFFSET_NONE); 9395 } 9396 uint32_t raw_len = gzInstructionsLen(&block_scope); 9397 const uint32_t* body = gzInstructionsSlice(&block_scope); 9398 uint32_t body_len = countBodyLenAfterFixups(ag, body, raw_len); 9399 wipMembersBodiesAppendWithFixups(&wm, ag, body, raw_len); 9400 wipMembersAppendToField(&wm, body_len); 9401 ag->scratch_inst_len = block_scope.instructions_top; 9402 } 9403 break; 9404 } 9405 default: 9406 SET_ERROR(ag); 9407 break; 9408 } 9409 } 9410 9411 wipMembersFinishBits(&wm); 9412 9413 // setStruct (AstGen.zig:5152-5166). 9414 StructDeclSmall small; 9415 memset(&small, 0, sizeof(small)); 9416 small.has_decls_len = (decl_count > 0); 9417 small.has_fields_len = (field_count > 0); 9418 small.known_non_opv = known_non_opv; 9419 small.known_comptime_only = known_comptime_only; 9420 small.any_comptime_fields = any_comptime_fields; 9421 small.any_default_inits = any_default_inits; 9422 small.any_aligned_fields = any_aligned_fields; 9423 setStruct(ag, decl_inst, node, small, 0, field_count, decl_count); 9424 9425 // Append: captures (none), backing_int (none), decls, fields, bodies 9426 // (AstGen.zig:5176-5189). 9427 uint32_t decls_len; 9428 const uint32_t* decls_slice = wipMembersDeclsSlice(&wm, &decls_len); 9429 uint32_t fields_len; 9430 const uint32_t* fields_slice = wipMembersFieldsSlice(&wm, &fields_len); 9431 9432 ensureExtraCapacity(ag, decls_len + fields_len + wm.bodies_len); 9433 for (uint32_t i = 0; i < decls_len; i++) 9434 ag->extra[ag->extra_len++] = decls_slice[i]; 9435 for (uint32_t i = 0; i < fields_len; i++) 9436 ag->extra[ag->extra_len++] = fields_slice[i]; 9437 for (uint32_t i = 0; i < wm.bodies_len; i++) 9438 ag->extra[ag->extra_len++] = wm.bodies[i]; 9439 9440 gzUnstack(&block_scope); 9441 wipMembersDeinit(&wm); 9442 return decl_inst; 9443 } 9444 9445 // --- AstRlAnnotate (AstRlAnnotate.zig) --- 9446 // Pre-pass to determine which AST nodes need result locations. 9447 9448 typedef struct { 9449 bool have_type; 9450 bool have_ptr; 9451 } RlResultInfo; 9452 9453 #define RL_RI_NONE ((RlResultInfo) { false, false }) 9454 #define RL_RI_TYPED_PTR ((RlResultInfo) { true, true }) 9455 #define RL_RI_INFERRED_PTR ((RlResultInfo) { false, true }) 9456 #define RL_RI_TYPE_ONLY ((RlResultInfo) { true, false }) 9457 9458 // Block for label tracking (AstRlAnnotate.zig:56-62). 9459 typedef struct RlBlock { 9460 struct RlBlock* parent; 9461 uint32_t label_token; // UINT32_MAX = no label 9462 bool is_loop; 9463 RlResultInfo ri; 9464 bool consumes_res_ptr; 9465 } RlBlock; 9466 9467 static void nodesNeedRlAdd(AstGenCtx* ag, uint32_t node) { 9468 if (ag->nodes_need_rl_len >= ag->nodes_need_rl_cap) { 9469 uint32_t new_cap 9470 = ag->nodes_need_rl_cap == 0 ? 16 : ag->nodes_need_rl_cap * 2; 9471 ag->nodes_need_rl 9472 = realloc(ag->nodes_need_rl, new_cap * sizeof(uint32_t)); 9473 ag->nodes_need_rl_cap = new_cap; 9474 } 9475 ag->nodes_need_rl[ag->nodes_need_rl_len++] = node; 9476 } 9477 9478 static bool nodesNeedRlContains(const AstGenCtx* ag, uint32_t node) { 9479 for (uint32_t i = 0; i < ag->nodes_need_rl_len; i++) { 9480 if (ag->nodes_need_rl[i] == node) 9481 return true; 9482 } 9483 return false; 9484 } 9485 9486 // Compare two identifier tokens by their source text. 9487 static bool rlTokenIdentEqual( 9488 const Ast* tree, uint32_t tok_a, uint32_t tok_b) { 9489 const char* src = tree->source; 9490 uint32_t a_start = tree->tokens.starts[tok_a]; 9491 uint32_t b_start = tree->tokens.starts[tok_b]; 9492 for (uint32_t i = 0;; i++) { 9493 char ca = src[a_start + i]; 9494 char cb = src[b_start + i]; 9495 bool a_id = (ca >= 'a' && ca <= 'z') || (ca >= 'A' && ca <= 'Z') 9496 || (ca >= '0' && ca <= '9') || ca == '_'; 9497 bool b_id = (cb >= 'a' && cb <= 'z') || (cb >= 'A' && cb <= 'Z') 9498 || (cb >= '0' && cb <= '9') || cb == '_'; 9499 if (!a_id && !b_id) 9500 return true; 9501 if (!a_id || !b_id) 9502 return false; 9503 if (ca != cb) 9504 return false; 9505 } 9506 } 9507 9508 // Forward declarations. 9509 static bool rlExpr( 9510 AstGenCtx* ag, uint32_t node, RlBlock* block, RlResultInfo ri); 9511 static void rlContainerDecl(AstGenCtx* ag, RlBlock* block, uint32_t node); 9512 static bool rlBlockExpr(AstGenCtx* ag, RlBlock* parent_block, RlResultInfo ri, 9513 uint32_t node, const uint32_t* stmts, uint32_t count); 9514 static bool rlBuiltinCall(AstGenCtx* ag, RlBlock* block, uint32_t node, 9515 const uint32_t* args, uint32_t nargs); 9516 9517 // containerDecl (AstRlAnnotate.zig:89-127). 9518 static void rlContainerDecl(AstGenCtx* ag, RlBlock* block, uint32_t node) { 9519 const Ast* tree = ag->tree; 9520 AstNodeTag tag = tree->nodes.tags[node]; 9521 AstData nd = tree->nodes.datas[node]; 9522 9523 // Extract arg and members depending on variant. 9524 // All container decls: recurse arg with type_only, members with none. 9525 // (The keyword type — struct/union/enum/opaque — doesn't matter for RL.) 9526 uint32_t member_buf[2]; 9527 const uint32_t* members = NULL; 9528 uint32_t members_len = 0; 9529 uint32_t arg_node = 0; // 0 = no arg 9530 9531 switch (tag) { 9532 case AST_NODE_CONTAINER_DECL_TWO: 9533 case AST_NODE_CONTAINER_DECL_TWO_TRAILING: 9534 case AST_NODE_TAGGED_UNION_TWO: 9535 case AST_NODE_TAGGED_UNION_TWO_TRAILING: { 9536 uint32_t idx = 0; 9537 if (nd.lhs != 0) 9538 member_buf[idx++] = nd.lhs; 9539 if (nd.rhs != 0) 9540 member_buf[idx++] = nd.rhs; 9541 members = member_buf; 9542 members_len = idx; 9543 break; 9544 } 9545 case AST_NODE_CONTAINER_DECL: 9546 case AST_NODE_CONTAINER_DECL_TRAILING: 9547 case AST_NODE_TAGGED_UNION: 9548 case AST_NODE_TAGGED_UNION_TRAILING: 9549 members = tree->extra_data.arr + nd.lhs; 9550 members_len = nd.rhs - nd.lhs; 9551 break; 9552 case AST_NODE_CONTAINER_DECL_ARG: 9553 case AST_NODE_CONTAINER_DECL_ARG_TRAILING: 9554 case AST_NODE_TAGGED_UNION_ENUM_TAG: 9555 case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: { 9556 arg_node = nd.lhs; 9557 uint32_t extra_idx = nd.rhs; 9558 uint32_t start = tree->extra_data.arr[extra_idx]; 9559 uint32_t end = tree->extra_data.arr[extra_idx + 1]; 9560 members = tree->extra_data.arr + start; 9561 members_len = end - start; 9562 break; 9563 } 9564 default: 9565 return; 9566 } 9567 9568 if (arg_node != 0) 9569 (void)rlExpr(ag, arg_node, block, RL_RI_TYPE_ONLY); 9570 for (uint32_t i = 0; i < members_len; i++) 9571 (void)rlExpr(ag, members[i], block, RL_RI_NONE); 9572 } 9573 9574 // blockExpr (AstRlAnnotate.zig:787-814). 9575 static bool rlBlockExpr(AstGenCtx* ag, RlBlock* parent_block, RlResultInfo ri, 9576 uint32_t node, const uint32_t* stmts, uint32_t count) { 9577 const Ast* tree = ag->tree; 9578 uint32_t lbrace = tree->nodes.main_tokens[node]; 9579 bool is_labeled 9580 = (lbrace >= 2 && tree->tokens.tags[lbrace - 1] == TOKEN_COLON 9581 && tree->tokens.tags[lbrace - 2] == TOKEN_IDENTIFIER); 9582 9583 if (is_labeled) { 9584 RlBlock new_block; 9585 new_block.parent = parent_block; 9586 new_block.label_token = lbrace - 2; 9587 new_block.is_loop = false; 9588 new_block.ri = ri; 9589 new_block.consumes_res_ptr = false; 9590 for (uint32_t i = 0; i < count; i++) 9591 (void)rlExpr(ag, stmts[i], &new_block, RL_RI_NONE); 9592 if (new_block.consumes_res_ptr) 9593 nodesNeedRlAdd(ag, node); 9594 return new_block.consumes_res_ptr; 9595 } else { 9596 for (uint32_t i = 0; i < count; i++) 9597 (void)rlExpr(ag, stmts[i], parent_block, RL_RI_NONE); 9598 return false; 9599 } 9600 } 9601 9602 // builtinCall (AstRlAnnotate.zig:816-1100). 9603 // Simplified: no builtin currently consumes its result location, 9604 // so we just recurse into all args with RL_RI_NONE. 9605 static bool rlBuiltinCall(AstGenCtx* ag, RlBlock* block, uint32_t node, 9606 const uint32_t* args, uint32_t nargs) { 9607 (void)node; 9608 for (uint32_t i = 0; i < nargs; i++) 9609 (void)rlExpr(ag, args[i], block, RL_RI_NONE); 9610 return false; 9611 } 9612 9613 // expr (AstRlAnnotate.zig:130-771). 9614 static bool rlExpr( 9615 AstGenCtx* ag, uint32_t node, RlBlock* block, RlResultInfo ri) { 9616 const Ast* tree = ag->tree; 9617 AstNodeTag tag = tree->nodes.tags[node]; 9618 AstData nd = tree->nodes.datas[node]; 9619 9620 switch (tag) { 9621 // Unreachable nodes (AstRlAnnotate.zig:133-142). 9622 case AST_NODE_ROOT: 9623 case AST_NODE_SWITCH_CASE_ONE: 9624 case AST_NODE_SWITCH_CASE_INLINE_ONE: 9625 case AST_NODE_SWITCH_CASE: 9626 case AST_NODE_SWITCH_CASE_INLINE: 9627 case AST_NODE_SWITCH_RANGE: 9628 case AST_NODE_FOR_RANGE: 9629 case AST_NODE_ASM_OUTPUT: 9630 case AST_NODE_ASM_INPUT: 9631 return false; // unreachable in upstream 9632 9633 // errdefer (AstRlAnnotate.zig:144-147). 9634 case AST_NODE_ERRDEFER: 9635 (void)rlExpr(ag, nd.rhs, block, RL_RI_NONE); 9636 return false; 9637 9638 // defer (AstRlAnnotate.zig:148-151). 9639 case AST_NODE_DEFER: 9640 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9641 return false; 9642 9643 // container_field (AstRlAnnotate.zig:153-167). 9644 case AST_NODE_CONTAINER_FIELD_INIT: { 9645 // lhs = type_expr, rhs = value_expr 9646 if (nd.lhs != 0) 9647 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 9648 if (nd.rhs != 0) 9649 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 9650 return false; 9651 } 9652 case AST_NODE_CONTAINER_FIELD_ALIGN: { 9653 // lhs = type_expr, rhs = align_expr 9654 if (nd.lhs != 0) 9655 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 9656 if (nd.rhs != 0) 9657 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 9658 return false; 9659 } 9660 case AST_NODE_CONTAINER_FIELD: { 9661 // lhs = type_expr, rhs = extra index to {align_expr, value_expr} 9662 if (nd.lhs != 0) 9663 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 9664 if (nd.rhs != 0) { 9665 uint32_t align_node = tree->extra_data.arr[nd.rhs]; 9666 uint32_t value_node = tree->extra_data.arr[nd.rhs + 1]; 9667 if (align_node != 0) 9668 (void)rlExpr(ag, align_node, block, RL_RI_TYPE_ONLY); 9669 if (value_node != 0) 9670 (void)rlExpr(ag, value_node, block, RL_RI_TYPE_ONLY); 9671 } 9672 return false; 9673 } 9674 9675 // test_decl (AstRlAnnotate.zig:168-171). 9676 case AST_NODE_TEST_DECL: 9677 (void)rlExpr(ag, nd.rhs, block, RL_RI_NONE); 9678 return false; 9679 9680 // var_decl (AstRlAnnotate.zig:172-202). 9681 case AST_NODE_GLOBAL_VAR_DECL: 9682 case AST_NODE_LOCAL_VAR_DECL: 9683 case AST_NODE_SIMPLE_VAR_DECL: 9684 case AST_NODE_ALIGNED_VAR_DECL: { 9685 uint32_t type_node = 0; 9686 uint32_t init_node = 0; 9687 uint32_t mut_token = tree->nodes.main_tokens[node]; 9688 if (tag == AST_NODE_SIMPLE_VAR_DECL) { 9689 type_node = nd.lhs; 9690 init_node = nd.rhs; 9691 } else if (tag == AST_NODE_LOCAL_VAR_DECL 9692 || tag == AST_NODE_GLOBAL_VAR_DECL) { 9693 type_node = tree->extra_data.arr[nd.lhs]; 9694 init_node = nd.rhs; 9695 } else { // ALIGNED_VAR_DECL 9696 init_node = nd.rhs; 9697 } 9698 RlResultInfo init_ri; 9699 if (type_node != 0) { 9700 (void)rlExpr(ag, type_node, block, RL_RI_TYPE_ONLY); 9701 init_ri = RL_RI_TYPED_PTR; 9702 } else { 9703 init_ri = RL_RI_INFERRED_PTR; 9704 } 9705 if (init_node == 0) 9706 return false; 9707 bool is_const = (tree->source[tree->tokens.starts[mut_token]] == 'c'); 9708 if (is_const) { 9709 bool init_consumes_rl = rlExpr(ag, init_node, block, init_ri); 9710 if (init_consumes_rl) 9711 nodesNeedRlAdd(ag, node); 9712 return false; 9713 } else { 9714 (void)rlExpr(ag, init_node, block, init_ri); 9715 return false; 9716 } 9717 } 9718 9719 // assign (AstRlAnnotate.zig:212-217). 9720 case AST_NODE_ASSIGN: 9721 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9722 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPED_PTR); 9723 return false; 9724 9725 // compound assign (AstRlAnnotate.zig:218-240). 9726 case AST_NODE_ASSIGN_SHL: 9727 case AST_NODE_ASSIGN_SHL_SAT: 9728 case AST_NODE_ASSIGN_SHR: 9729 case AST_NODE_ASSIGN_BIT_AND: 9730 case AST_NODE_ASSIGN_BIT_OR: 9731 case AST_NODE_ASSIGN_BIT_XOR: 9732 case AST_NODE_ASSIGN_DIV: 9733 case AST_NODE_ASSIGN_SUB: 9734 case AST_NODE_ASSIGN_SUB_WRAP: 9735 case AST_NODE_ASSIGN_SUB_SAT: 9736 case AST_NODE_ASSIGN_MOD: 9737 case AST_NODE_ASSIGN_ADD: 9738 case AST_NODE_ASSIGN_ADD_WRAP: 9739 case AST_NODE_ASSIGN_ADD_SAT: 9740 case AST_NODE_ASSIGN_MUL: 9741 case AST_NODE_ASSIGN_MUL_WRAP: 9742 case AST_NODE_ASSIGN_MUL_SAT: 9743 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9744 (void)rlExpr(ag, nd.rhs, block, RL_RI_NONE); 9745 return false; 9746 9747 // shl/shr (AstRlAnnotate.zig:241-246). 9748 case AST_NODE_SHL: 9749 case AST_NODE_SHR: 9750 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9751 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 9752 return false; 9753 9754 // binary arithmetic/comparison (AstRlAnnotate.zig:247-274). 9755 case AST_NODE_ADD: 9756 case AST_NODE_ADD_WRAP: 9757 case AST_NODE_ADD_SAT: 9758 case AST_NODE_SUB: 9759 case AST_NODE_SUB_WRAP: 9760 case AST_NODE_SUB_SAT: 9761 case AST_NODE_MUL: 9762 case AST_NODE_MUL_WRAP: 9763 case AST_NODE_MUL_SAT: 9764 case AST_NODE_DIV: 9765 case AST_NODE_MOD: 9766 case AST_NODE_SHL_SAT: 9767 case AST_NODE_BIT_AND: 9768 case AST_NODE_BIT_OR: 9769 case AST_NODE_BIT_XOR: 9770 case AST_NODE_BANG_EQUAL: 9771 case AST_NODE_EQUAL_EQUAL: 9772 case AST_NODE_GREATER_THAN: 9773 case AST_NODE_GREATER_OR_EQUAL: 9774 case AST_NODE_LESS_THAN: 9775 case AST_NODE_LESS_OR_EQUAL: 9776 case AST_NODE_ARRAY_CAT: 9777 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9778 (void)rlExpr(ag, nd.rhs, block, RL_RI_NONE); 9779 return false; 9780 9781 // array_mult (AstRlAnnotate.zig:276-281). 9782 case AST_NODE_ARRAY_MULT: 9783 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9784 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 9785 return false; 9786 9787 // error_union, merge_error_sets (AstRlAnnotate.zig:282-287). 9788 case AST_NODE_ERROR_UNION: 9789 case AST_NODE_MERGE_ERROR_SETS: 9790 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9791 (void)rlExpr(ag, nd.rhs, block, RL_RI_NONE); 9792 return false; 9793 9794 // bool_and, bool_or (AstRlAnnotate.zig:288-295). 9795 case AST_NODE_BOOL_AND: 9796 case AST_NODE_BOOL_OR: 9797 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 9798 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 9799 return false; 9800 9801 // bool_not (AstRlAnnotate.zig:296-299). 9802 case AST_NODE_BOOL_NOT: 9803 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 9804 return false; 9805 9806 // bit_not, negation, negation_wrap (AstRlAnnotate.zig:300-303). 9807 case AST_NODE_BIT_NOT: 9808 case AST_NODE_NEGATION: 9809 case AST_NODE_NEGATION_WRAP: 9810 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9811 return false; 9812 9813 // Leaves (AstRlAnnotate.zig:305-320). 9814 case AST_NODE_IDENTIFIER: 9815 case AST_NODE_STRING_LITERAL: 9816 case AST_NODE_MULTILINE_STRING_LITERAL: 9817 case AST_NODE_NUMBER_LITERAL: 9818 case AST_NODE_UNREACHABLE_LITERAL: 9819 case AST_NODE_ASM_SIMPLE: 9820 case AST_NODE_ASM: 9821 case AST_NODE_ASM_LEGACY: 9822 case AST_NODE_ENUM_LITERAL: 9823 case AST_NODE_ERROR_VALUE: 9824 case AST_NODE_ANYFRAME_LITERAL: 9825 case AST_NODE_CONTINUE: 9826 case AST_NODE_CHAR_LITERAL: 9827 case AST_NODE_ERROR_SET_DECL: 9828 return false; 9829 9830 // builtin_call (AstRlAnnotate.zig:322-330). 9831 case AST_NODE_BUILTIN_CALL_TWO: 9832 case AST_NODE_BUILTIN_CALL_TWO_COMMA: { 9833 uint32_t args[2]; 9834 uint32_t nargs = 0; 9835 if (nd.lhs != 0) 9836 args[nargs++] = nd.lhs; 9837 if (nd.rhs != 0) 9838 args[nargs++] = nd.rhs; 9839 return rlBuiltinCall(ag, block, node, args, nargs); 9840 } 9841 case AST_NODE_BUILTIN_CALL: 9842 case AST_NODE_BUILTIN_CALL_COMMA: { 9843 uint32_t start = nd.lhs; 9844 uint32_t end = nd.rhs; 9845 return rlBuiltinCall( 9846 ag, block, node, tree->extra_data.arr + start, end - start); 9847 } 9848 9849 // call (AstRlAnnotate.zig:332-351). 9850 case AST_NODE_CALL_ONE: 9851 case AST_NODE_CALL_ONE_COMMA: { 9852 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9853 if (nd.rhs != 0) 9854 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 9855 return false; 9856 } 9857 case AST_NODE_CALL: 9858 case AST_NODE_CALL_COMMA: { 9859 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9860 uint32_t start = tree->extra_data.arr[nd.rhs]; 9861 uint32_t end = tree->extra_data.arr[nd.rhs + 1]; 9862 for (uint32_t i = start; i < end; i++) 9863 (void)rlExpr(ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY); 9864 return false; 9865 } 9866 9867 // return (AstRlAnnotate.zig:353-361). 9868 case AST_NODE_RETURN: 9869 if (nd.lhs != 0) { 9870 bool ret_consumes_rl = rlExpr(ag, nd.lhs, block, RL_RI_TYPED_PTR); 9871 if (ret_consumes_rl) 9872 nodesNeedRlAdd(ag, node); 9873 } 9874 return false; 9875 9876 // field_access (AstRlAnnotate.zig:363-367). 9877 case AST_NODE_FIELD_ACCESS: 9878 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 9879 return false; 9880 9881 // if_simple, if (AstRlAnnotate.zig:369-387). 9882 case AST_NODE_IF_SIMPLE: 9883 case AST_NODE_IF: { 9884 uint32_t cond_node = nd.lhs; 9885 uint32_t then_node, else_node = 0; 9886 if (tag == AST_NODE_IF_SIMPLE) { 9887 then_node = nd.rhs; 9888 } else { 9889 then_node = tree->extra_data.arr[nd.rhs]; 9890 else_node = tree->extra_data.arr[nd.rhs + 1]; 9891 } 9892 // Detect payload/error token. 9893 uint32_t last_cond_tok = lastToken(tree, cond_node); 9894 uint32_t pipe_tok = last_cond_tok + 2; 9895 bool has_payload = (pipe_tok < tree->tokens.len 9896 && tree->tokens.tags[pipe_tok] == TOKEN_PIPE); 9897 bool has_error = false; 9898 if (else_node != 0) { 9899 uint32_t else_tok = lastToken(tree, then_node) + 1; 9900 has_error = (else_tok + 1 < tree->tokens.len 9901 && tree->tokens.tags[else_tok + 1] == TOKEN_PIPE); 9902 } 9903 if (has_error || has_payload) 9904 (void)rlExpr(ag, cond_node, block, RL_RI_NONE); 9905 else 9906 (void)rlExpr(ag, cond_node, block, RL_RI_TYPE_ONLY); 9907 9908 if (else_node != 0) { 9909 bool then_uses = rlExpr(ag, then_node, block, ri); 9910 bool else_uses = rlExpr(ag, else_node, block, ri); 9911 bool uses_rl = then_uses || else_uses; 9912 if (uses_rl) 9913 nodesNeedRlAdd(ag, node); 9914 return uses_rl; 9915 } else { 9916 (void)rlExpr(ag, then_node, block, RL_RI_NONE); 9917 return false; 9918 } 9919 } 9920 9921 // while (AstRlAnnotate.zig:389-419). 9922 case AST_NODE_WHILE_SIMPLE: 9923 case AST_NODE_WHILE_CONT: 9924 case AST_NODE_WHILE: { 9925 uint32_t cond_node = nd.lhs; 9926 uint32_t body_node, cont_node = 0, else_node = 0; 9927 if (tag == AST_NODE_WHILE_SIMPLE) { 9928 body_node = nd.rhs; 9929 } else if (tag == AST_NODE_WHILE_CONT) { 9930 cont_node = tree->extra_data.arr[nd.rhs]; 9931 body_node = tree->extra_data.arr[nd.rhs + 1]; 9932 } else { 9933 cont_node = tree->extra_data.arr[nd.rhs]; 9934 body_node = tree->extra_data.arr[nd.rhs + 1]; 9935 else_node = tree->extra_data.arr[nd.rhs + 2]; 9936 } 9937 uint32_t main_tok = tree->nodes.main_tokens[node]; 9938 bool is_labeled 9939 = (main_tok >= 2 && tree->tokens.tags[main_tok - 1] == TOKEN_COLON 9940 && tree->tokens.tags[main_tok - 2] == TOKEN_IDENTIFIER); 9941 uint32_t label_token = is_labeled ? main_tok - 2 : UINT32_MAX; 9942 9943 // Detect payload/error. 9944 uint32_t last_cond_tok = lastToken(tree, cond_node); 9945 uint32_t pipe_tok = last_cond_tok + 2; 9946 bool has_payload = (pipe_tok < tree->tokens.len 9947 && tree->tokens.tags[pipe_tok] == TOKEN_PIPE); 9948 // Error token detection for while: check for else |err|. 9949 bool has_error = false; 9950 if (else_node != 0) { 9951 uint32_t else_tok = lastToken(tree, body_node) + 1; 9952 has_error = (else_tok + 1 < tree->tokens.len 9953 && tree->tokens.tags[else_tok + 1] == TOKEN_PIPE); 9954 } 9955 if (has_error || has_payload) 9956 (void)rlExpr(ag, cond_node, block, RL_RI_NONE); 9957 else 9958 (void)rlExpr(ag, cond_node, block, RL_RI_TYPE_ONLY); 9959 9960 RlBlock new_block; 9961 new_block.parent = block; 9962 new_block.label_token = label_token; 9963 new_block.is_loop = true; 9964 new_block.ri = ri; 9965 new_block.consumes_res_ptr = false; 9966 9967 if (cont_node != 0) 9968 (void)rlExpr(ag, cont_node, &new_block, RL_RI_NONE); 9969 (void)rlExpr(ag, body_node, &new_block, RL_RI_NONE); 9970 bool else_consumes = false; 9971 if (else_node != 0) 9972 else_consumes = rlExpr(ag, else_node, block, ri); 9973 if (new_block.consumes_res_ptr || else_consumes) { 9974 nodesNeedRlAdd(ag, node); 9975 return true; 9976 } 9977 return false; 9978 } 9979 9980 // for (AstRlAnnotate.zig:421-454). 9981 case AST_NODE_FOR_SIMPLE: 9982 case AST_NODE_FOR: { 9983 uint32_t input_buf[16]; 9984 const uint32_t* inputs = NULL; 9985 uint32_t num_inputs = 0; 9986 uint32_t body_node = 0; 9987 uint32_t else_node = 0; 9988 9989 if (tag == AST_NODE_FOR_SIMPLE) { 9990 input_buf[0] = nd.lhs; 9991 inputs = input_buf; 9992 num_inputs = 1; 9993 body_node = nd.rhs; 9994 } else { 9995 AstFor for_data; 9996 memcpy(&for_data, &nd.rhs, sizeof(AstFor)); 9997 num_inputs = for_data.inputs; 9998 if (num_inputs > 16) 9999 num_inputs = 16; 10000 for (uint32_t i = 0; i < num_inputs; i++) 10001 input_buf[i] = tree->extra_data.arr[nd.lhs + i]; 10002 inputs = input_buf; 10003 body_node = tree->extra_data.arr[nd.lhs + num_inputs]; 10004 if (for_data.has_else) 10005 else_node = tree->extra_data.arr[nd.lhs + num_inputs + 1]; 10006 } 10007 10008 uint32_t main_tok = tree->nodes.main_tokens[node]; 10009 bool is_labeled 10010 = (main_tok >= 2 && tree->tokens.tags[main_tok - 1] == TOKEN_COLON 10011 && tree->tokens.tags[main_tok - 2] == TOKEN_IDENTIFIER); 10012 uint32_t label_token = is_labeled ? main_tok - 2 : UINT32_MAX; 10013 10014 for (uint32_t i = 0; i < num_inputs; i++) { 10015 uint32_t input = inputs[i]; 10016 if (tree->nodes.tags[input] == AST_NODE_FOR_RANGE) { 10017 AstData range_nd = tree->nodes.datas[input]; 10018 (void)rlExpr(ag, range_nd.lhs, block, RL_RI_TYPE_ONLY); 10019 if (range_nd.rhs != 0) 10020 (void)rlExpr(ag, range_nd.rhs, block, RL_RI_TYPE_ONLY); 10021 } else { 10022 (void)rlExpr(ag, input, block, RL_RI_NONE); 10023 } 10024 } 10025 10026 RlBlock new_block; 10027 new_block.parent = block; 10028 new_block.label_token = label_token; 10029 new_block.is_loop = true; 10030 new_block.ri = ri; 10031 new_block.consumes_res_ptr = false; 10032 10033 (void)rlExpr(ag, body_node, &new_block, RL_RI_NONE); 10034 bool else_consumes = false; 10035 if (else_node != 0) 10036 else_consumes = rlExpr(ag, else_node, block, ri); 10037 if (new_block.consumes_res_ptr || else_consumes) { 10038 nodesNeedRlAdd(ag, node); 10039 return true; 10040 } 10041 return false; 10042 } 10043 10044 // slice (AstRlAnnotate.zig:456-480). 10045 case AST_NODE_SLICE_OPEN: 10046 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10047 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10048 return false; 10049 case AST_NODE_SLICE: { 10050 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10051 uint32_t start = tree->extra_data.arr[nd.rhs]; 10052 uint32_t end = tree->extra_data.arr[nd.rhs + 1]; 10053 (void)rlExpr(ag, start, block, RL_RI_TYPE_ONLY); 10054 (void)rlExpr(ag, end, block, RL_RI_TYPE_ONLY); 10055 return false; 10056 } 10057 case AST_NODE_SLICE_SENTINEL: { 10058 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10059 AstSliceSentinel ss; 10060 ss.start = tree->extra_data.arr[nd.rhs]; 10061 ss.end = tree->extra_data.arr[nd.rhs + 1]; 10062 ss.sentinel = tree->extra_data.arr[nd.rhs + 2]; 10063 (void)rlExpr(ag, ss.start, block, RL_RI_TYPE_ONLY); 10064 if (ss.end != 0) 10065 (void)rlExpr(ag, ss.end, block, RL_RI_TYPE_ONLY); 10066 (void)rlExpr(ag, ss.sentinel, block, RL_RI_NONE); 10067 return false; 10068 } 10069 10070 // deref (AstRlAnnotate.zig:481-484). 10071 case AST_NODE_DEREF: 10072 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10073 return false; 10074 10075 // address_of (AstRlAnnotate.zig:485-488). 10076 case AST_NODE_ADDRESS_OF: 10077 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10078 return false; 10079 10080 // optional_type (AstRlAnnotate.zig:489-492). 10081 case AST_NODE_OPTIONAL_TYPE: 10082 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 10083 return false; 10084 10085 // try, nosuspend (AstRlAnnotate.zig:493-495). 10086 case AST_NODE_TRY: 10087 case AST_NODE_NOSUSPEND: 10088 return rlExpr(ag, nd.lhs, block, ri); 10089 10090 // grouped_expression, unwrap_optional (AstRlAnnotate.zig:496-498). 10091 case AST_NODE_GROUPED_EXPRESSION: 10092 case AST_NODE_UNWRAP_OPTIONAL: 10093 return rlExpr(ag, nd.lhs, block, ri); 10094 10095 // block (AstRlAnnotate.zig:500-508). 10096 case AST_NODE_BLOCK_TWO: 10097 case AST_NODE_BLOCK_TWO_SEMICOLON: { 10098 uint32_t stmts[2]; 10099 uint32_t count = 0; 10100 if (nd.lhs != 0) 10101 stmts[count++] = nd.lhs; 10102 if (nd.rhs != 0) 10103 stmts[count++] = nd.rhs; 10104 return rlBlockExpr(ag, block, ri, node, stmts, count); 10105 } 10106 case AST_NODE_BLOCK: 10107 case AST_NODE_BLOCK_SEMICOLON: 10108 return rlBlockExpr(ag, block, ri, node, tree->extra_data.arr + nd.lhs, 10109 nd.rhs - nd.lhs); 10110 10111 // anyframe_type (AstRlAnnotate.zig:509-513). 10112 case AST_NODE_ANYFRAME_TYPE: 10113 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10114 return false; 10115 10116 // catch/orelse (AstRlAnnotate.zig:514-522). 10117 case AST_NODE_CATCH: 10118 case AST_NODE_ORELSE: { 10119 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10120 bool rhs_consumes = rlExpr(ag, nd.rhs, block, ri); 10121 if (rhs_consumes) 10122 nodesNeedRlAdd(ag, node); 10123 return rhs_consumes; 10124 } 10125 10126 // ptr_type (AstRlAnnotate.zig:524-546). 10127 case AST_NODE_PTR_TYPE_ALIGNED: 10128 if (nd.lhs != 0) 10129 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 10130 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10131 return false; 10132 case AST_NODE_PTR_TYPE_SENTINEL: 10133 if (nd.lhs != 0) 10134 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 10135 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10136 return false; 10137 case AST_NODE_PTR_TYPE: { 10138 AstPtrType pt; 10139 pt.sentinel = tree->extra_data.arr[nd.lhs]; 10140 pt.align_node = tree->extra_data.arr[nd.lhs + 1]; 10141 pt.addrspace_node = tree->extra_data.arr[nd.lhs + 2]; 10142 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10143 if (pt.sentinel != 0) 10144 (void)rlExpr(ag, pt.sentinel, block, RL_RI_TYPE_ONLY); 10145 if (pt.align_node != 0) 10146 (void)rlExpr(ag, pt.align_node, block, RL_RI_TYPE_ONLY); 10147 if (pt.addrspace_node != 0) 10148 (void)rlExpr(ag, pt.addrspace_node, block, RL_RI_TYPE_ONLY); 10149 return false; 10150 } 10151 case AST_NODE_PTR_TYPE_BIT_RANGE: { 10152 AstPtrTypeBitRange pt; 10153 pt.sentinel = tree->extra_data.arr[nd.lhs]; 10154 pt.align_node = tree->extra_data.arr[nd.lhs + 1]; 10155 pt.addrspace_node = tree->extra_data.arr[nd.lhs + 2]; 10156 pt.bit_range_start = tree->extra_data.arr[nd.lhs + 3]; 10157 pt.bit_range_end = tree->extra_data.arr[nd.lhs + 4]; 10158 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10159 if (pt.sentinel != 0) 10160 (void)rlExpr(ag, pt.sentinel, block, RL_RI_TYPE_ONLY); 10161 if (pt.align_node != 0) 10162 (void)rlExpr(ag, pt.align_node, block, RL_RI_TYPE_ONLY); 10163 if (pt.addrspace_node != 0) 10164 (void)rlExpr(ag, pt.addrspace_node, block, RL_RI_TYPE_ONLY); 10165 if (pt.bit_range_start != 0) { 10166 (void)rlExpr(ag, pt.bit_range_start, block, RL_RI_TYPE_ONLY); 10167 (void)rlExpr(ag, pt.bit_range_end, block, RL_RI_TYPE_ONLY); 10168 } 10169 return false; 10170 } 10171 10172 // container_decl (AstRlAnnotate.zig:548-564). 10173 case AST_NODE_CONTAINER_DECL: 10174 case AST_NODE_CONTAINER_DECL_TRAILING: 10175 case AST_NODE_CONTAINER_DECL_ARG: 10176 case AST_NODE_CONTAINER_DECL_ARG_TRAILING: 10177 case AST_NODE_CONTAINER_DECL_TWO: 10178 case AST_NODE_CONTAINER_DECL_TWO_TRAILING: 10179 case AST_NODE_TAGGED_UNION: 10180 case AST_NODE_TAGGED_UNION_TRAILING: 10181 case AST_NODE_TAGGED_UNION_ENUM_TAG: 10182 case AST_NODE_TAGGED_UNION_ENUM_TAG_TRAILING: 10183 case AST_NODE_TAGGED_UNION_TWO: 10184 case AST_NODE_TAGGED_UNION_TWO_TRAILING: 10185 rlContainerDecl(ag, block, node); 10186 return false; 10187 10188 // break (AstRlAnnotate.zig:566-596). 10189 case AST_NODE_BREAK: { 10190 uint32_t opt_label_tok = nd.lhs; // 0 = no label 10191 uint32_t rhs_node = nd.rhs; // 0 = void break 10192 if (rhs_node == 0) 10193 return false; 10194 10195 RlBlock* opt_cur_block = block; 10196 if (opt_label_tok != 0) { 10197 // Labeled break: find matching block. 10198 while (opt_cur_block != NULL) { 10199 if (opt_cur_block->label_token != UINT32_MAX 10200 && rlTokenIdentEqual( 10201 tree, opt_cur_block->label_token, opt_label_tok)) 10202 break; 10203 opt_cur_block = opt_cur_block->parent; 10204 } 10205 } else { 10206 // No label: breaking from innermost loop. 10207 while (opt_cur_block != NULL) { 10208 if (opt_cur_block->is_loop) 10209 break; 10210 opt_cur_block = opt_cur_block->parent; 10211 } 10212 } 10213 10214 if (opt_cur_block != NULL) { 10215 bool consumes = rlExpr(ag, rhs_node, block, opt_cur_block->ri); 10216 if (consumes) 10217 opt_cur_block->consumes_res_ptr = true; 10218 } else { 10219 (void)rlExpr(ag, rhs_node, block, RL_RI_NONE); 10220 } 10221 return false; 10222 } 10223 10224 // array_type (AstRlAnnotate.zig:598-611). 10225 case AST_NODE_ARRAY_TYPE: 10226 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 10227 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10228 return false; 10229 case AST_NODE_ARRAY_TYPE_SENTINEL: { 10230 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 10231 uint32_t elem_type = tree->extra_data.arr[nd.rhs + 1]; 10232 uint32_t sentinel = tree->extra_data.arr[nd.rhs]; 10233 (void)rlExpr(ag, elem_type, block, RL_RI_TYPE_ONLY); 10234 (void)rlExpr(ag, sentinel, block, RL_RI_TYPE_ONLY); 10235 return false; 10236 } 10237 10238 // array_access (AstRlAnnotate.zig:612-617). 10239 case AST_NODE_ARRAY_ACCESS: 10240 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10241 (void)rlExpr(ag, nd.rhs, block, RL_RI_TYPE_ONLY); 10242 return false; 10243 10244 // comptime (AstRlAnnotate.zig:618-623). 10245 case AST_NODE_COMPTIME: 10246 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10247 return false; 10248 10249 // switch (AstRlAnnotate.zig:624-650). 10250 case AST_NODE_SWITCH: 10251 case AST_NODE_SWITCH_COMMA: { 10252 uint32_t cond_node = nd.lhs; 10253 uint32_t extra_idx = nd.rhs; 10254 uint32_t cases_start = tree->extra_data.arr[extra_idx]; 10255 uint32_t cases_end = tree->extra_data.arr[extra_idx + 1]; 10256 10257 (void)rlExpr(ag, cond_node, block, RL_RI_NONE); 10258 10259 bool any_consumed = false; 10260 for (uint32_t ci = cases_start; ci < cases_end; ci++) { 10261 uint32_t case_node = tree->extra_data.arr[ci]; 10262 AstNodeTag ct = tree->nodes.tags[case_node]; 10263 AstData cd = tree->nodes.datas[case_node]; 10264 10265 // Process case values. 10266 if (ct == AST_NODE_SWITCH_CASE_ONE 10267 || ct == AST_NODE_SWITCH_CASE_INLINE_ONE) { 10268 if (cd.lhs != 0) { 10269 if (tree->nodes.tags[cd.lhs] == AST_NODE_SWITCH_RANGE) { 10270 AstData rd = tree->nodes.datas[cd.lhs]; 10271 (void)rlExpr(ag, rd.lhs, block, RL_RI_NONE); 10272 (void)rlExpr(ag, rd.rhs, block, RL_RI_NONE); 10273 } else { 10274 (void)rlExpr(ag, cd.lhs, block, RL_RI_NONE); 10275 } 10276 } 10277 } else { 10278 // SWITCH_CASE / SWITCH_CASE_INLINE: SubRange[lhs] 10279 uint32_t items_start = tree->extra_data.arr[cd.lhs]; 10280 uint32_t items_end = tree->extra_data.arr[cd.lhs + 1]; 10281 for (uint32_t ii = items_start; ii < items_end; ii++) { 10282 uint32_t item = tree->extra_data.arr[ii]; 10283 if (tree->nodes.tags[item] == AST_NODE_SWITCH_RANGE) { 10284 AstData rd = tree->nodes.datas[item]; 10285 (void)rlExpr(ag, rd.lhs, block, RL_RI_NONE); 10286 (void)rlExpr(ag, rd.rhs, block, RL_RI_NONE); 10287 } else { 10288 (void)rlExpr(ag, item, block, RL_RI_NONE); 10289 } 10290 } 10291 } 10292 // Process case target expr. 10293 if (rlExpr(ag, cd.rhs, block, ri)) 10294 any_consumed = true; 10295 } 10296 if (any_consumed) 10297 nodesNeedRlAdd(ag, node); 10298 return any_consumed; 10299 } 10300 10301 // suspend (AstRlAnnotate.zig:651-654). 10302 case AST_NODE_SUSPEND: 10303 if (nd.lhs != 0) 10304 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10305 return false; 10306 10307 // resume (AstRlAnnotate.zig:655-658). 10308 case AST_NODE_RESUME: 10309 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10310 return false; 10311 10312 // array_init (AstRlAnnotate.zig:660-695). 10313 case AST_NODE_ARRAY_INIT_ONE: 10314 case AST_NODE_ARRAY_INIT_ONE_COMMA: 10315 case AST_NODE_ARRAY_INIT_DOT_TWO: 10316 case AST_NODE_ARRAY_INIT_DOT_TWO_COMMA: 10317 case AST_NODE_ARRAY_INIT_DOT: 10318 case AST_NODE_ARRAY_INIT_DOT_COMMA: 10319 case AST_NODE_ARRAY_INIT: 10320 case AST_NODE_ARRAY_INIT_COMMA: { 10321 // Extract type_expr and elements. 10322 uint32_t type_expr = 0; 10323 uint32_t elem_buf[2]; 10324 const uint32_t* elems = NULL; 10325 uint32_t nelem = 0; 10326 switch (tag) { 10327 case AST_NODE_ARRAY_INIT_ONE: 10328 case AST_NODE_ARRAY_INIT_ONE_COMMA: 10329 type_expr = nd.lhs; 10330 if (nd.rhs != 0) { 10331 elem_buf[0] = nd.rhs; 10332 elems = elem_buf; 10333 nelem = 1; 10334 } 10335 break; 10336 case AST_NODE_ARRAY_INIT_DOT_TWO: 10337 case AST_NODE_ARRAY_INIT_DOT_TWO_COMMA: { 10338 uint32_t idx = 0; 10339 if (nd.lhs != 0) 10340 elem_buf[idx++] = nd.lhs; 10341 if (nd.rhs != 0) 10342 elem_buf[idx++] = nd.rhs; 10343 elems = elem_buf; 10344 nelem = idx; 10345 break; 10346 } 10347 case AST_NODE_ARRAY_INIT_DOT: 10348 case AST_NODE_ARRAY_INIT_DOT_COMMA: 10349 elems = tree->extra_data.arr + nd.lhs; 10350 nelem = nd.rhs - nd.lhs; 10351 break; 10352 case AST_NODE_ARRAY_INIT: 10353 case AST_NODE_ARRAY_INIT_COMMA: { 10354 type_expr = nd.lhs; 10355 uint32_t start = tree->extra_data.arr[nd.rhs]; 10356 uint32_t end = tree->extra_data.arr[nd.rhs + 1]; 10357 elems = tree->extra_data.arr + start; 10358 nelem = end - start; 10359 break; 10360 } 10361 default: 10362 break; 10363 } 10364 if (type_expr != 0) { 10365 (void)rlExpr(ag, type_expr, block, RL_RI_NONE); 10366 for (uint32_t i = 0; i < nelem; i++) 10367 (void)rlExpr(ag, elems[i], block, RL_RI_TYPE_ONLY); 10368 return false; 10369 } 10370 if (ri.have_type) { 10371 for (uint32_t i = 0; i < nelem; i++) 10372 (void)rlExpr(ag, elems[i], block, ri); 10373 return ri.have_ptr; 10374 } else { 10375 for (uint32_t i = 0; i < nelem; i++) 10376 (void)rlExpr(ag, elems[i], block, RL_RI_NONE); 10377 return false; 10378 } 10379 } 10380 10381 // struct_init (AstRlAnnotate.zig:697-732). 10382 case AST_NODE_STRUCT_INIT_ONE: 10383 case AST_NODE_STRUCT_INIT_ONE_COMMA: 10384 case AST_NODE_STRUCT_INIT_DOT_TWO: 10385 case AST_NODE_STRUCT_INIT_DOT_TWO_COMMA: 10386 case AST_NODE_STRUCT_INIT_DOT: 10387 case AST_NODE_STRUCT_INIT_DOT_COMMA: 10388 case AST_NODE_STRUCT_INIT: 10389 case AST_NODE_STRUCT_INIT_COMMA: { 10390 uint32_t type_expr = 0; 10391 uint32_t field_buf[2]; 10392 const uint32_t* fields = NULL; 10393 uint32_t nfields = 0; 10394 switch (tag) { 10395 case AST_NODE_STRUCT_INIT_ONE: 10396 case AST_NODE_STRUCT_INIT_ONE_COMMA: 10397 type_expr = nd.lhs; 10398 if (nd.rhs != 0) { 10399 field_buf[0] = nd.rhs; 10400 fields = field_buf; 10401 nfields = 1; 10402 } 10403 break; 10404 case AST_NODE_STRUCT_INIT_DOT_TWO: 10405 case AST_NODE_STRUCT_INIT_DOT_TWO_COMMA: { 10406 uint32_t idx = 0; 10407 if (nd.lhs != 0) 10408 field_buf[idx++] = nd.lhs; 10409 if (nd.rhs != 0) 10410 field_buf[idx++] = nd.rhs; 10411 fields = field_buf; 10412 nfields = idx; 10413 break; 10414 } 10415 case AST_NODE_STRUCT_INIT_DOT: 10416 case AST_NODE_STRUCT_INIT_DOT_COMMA: 10417 fields = tree->extra_data.arr + nd.lhs; 10418 nfields = nd.rhs - nd.lhs; 10419 break; 10420 case AST_NODE_STRUCT_INIT: 10421 case AST_NODE_STRUCT_INIT_COMMA: { 10422 type_expr = nd.lhs; 10423 uint32_t start = tree->extra_data.arr[nd.rhs]; 10424 uint32_t end = tree->extra_data.arr[nd.rhs + 1]; 10425 fields = tree->extra_data.arr + start; 10426 nfields = end - start; 10427 break; 10428 } 10429 default: 10430 break; 10431 } 10432 if (type_expr != 0) { 10433 (void)rlExpr(ag, type_expr, block, RL_RI_NONE); 10434 for (uint32_t i = 0; i < nfields; i++) 10435 (void)rlExpr(ag, fields[i], block, RL_RI_TYPE_ONLY); 10436 return false; 10437 } 10438 if (ri.have_type) { 10439 for (uint32_t i = 0; i < nfields; i++) 10440 (void)rlExpr(ag, fields[i], block, ri); 10441 return ri.have_ptr; 10442 } else { 10443 for (uint32_t i = 0; i < nfields; i++) 10444 (void)rlExpr(ag, fields[i], block, RL_RI_NONE); 10445 return false; 10446 } 10447 } 10448 10449 // fn_proto, fn_decl (AstRlAnnotate.zig:734-770). 10450 case AST_NODE_FN_PROTO_SIMPLE: 10451 case AST_NODE_FN_PROTO_MULTI: 10452 case AST_NODE_FN_PROTO_ONE: 10453 case AST_NODE_FN_PROTO: 10454 case AST_NODE_FN_DECL: { 10455 // Extract return type and body. 10456 uint32_t return_type = 0; 10457 uint32_t body_node = 0; 10458 10459 if (tag == AST_NODE_FN_DECL) { 10460 body_node = nd.rhs; 10461 // fn_proto is nd.lhs 10462 uint32_t proto = nd.lhs; 10463 AstNodeTag ptag = tree->nodes.tags[proto]; 10464 AstData pnd = tree->nodes.datas[proto]; 10465 if (ptag == AST_NODE_FN_PROTO_SIMPLE) { 10466 return_type = pnd.rhs; 10467 if (pnd.lhs != 0) 10468 (void)rlExpr(ag, pnd.lhs, block, RL_RI_TYPE_ONLY); 10469 } else if (ptag == AST_NODE_FN_PROTO_MULTI) { 10470 return_type = pnd.rhs; 10471 uint32_t ps = tree->extra_data.arr[pnd.lhs]; 10472 uint32_t pe = tree->extra_data.arr[pnd.lhs + 1]; 10473 for (uint32_t i = ps; i < pe; i++) 10474 (void)rlExpr( 10475 ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY); 10476 } else if (ptag == AST_NODE_FN_PROTO_ONE) { 10477 return_type = pnd.rhs; 10478 AstFnProtoOne fp; 10479 fp.param = tree->extra_data.arr[pnd.lhs]; 10480 fp.align_expr = tree->extra_data.arr[pnd.lhs + 1]; 10481 fp.addrspace_expr = tree->extra_data.arr[pnd.lhs + 2]; 10482 fp.section_expr = tree->extra_data.arr[pnd.lhs + 3]; 10483 fp.callconv_expr = tree->extra_data.arr[pnd.lhs + 4]; 10484 if (fp.param != 0) 10485 (void)rlExpr(ag, fp.param, block, RL_RI_TYPE_ONLY); 10486 if (fp.align_expr != 0) 10487 (void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY); 10488 if (fp.addrspace_expr != 0) 10489 (void)rlExpr( 10490 ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY); 10491 if (fp.section_expr != 0) 10492 (void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY); 10493 if (fp.callconv_expr != 0) 10494 (void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY); 10495 } else if (ptag == AST_NODE_FN_PROTO) { 10496 return_type = pnd.rhs; 10497 AstFnProto fp; 10498 fp.params_start = tree->extra_data.arr[pnd.lhs]; 10499 fp.params_end = tree->extra_data.arr[pnd.lhs + 1]; 10500 fp.align_expr = tree->extra_data.arr[pnd.lhs + 2]; 10501 fp.addrspace_expr = tree->extra_data.arr[pnd.lhs + 3]; 10502 fp.section_expr = tree->extra_data.arr[pnd.lhs + 4]; 10503 fp.callconv_expr = tree->extra_data.arr[pnd.lhs + 5]; 10504 for (uint32_t i = fp.params_start; i < fp.params_end; i++) 10505 (void)rlExpr( 10506 ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY); 10507 if (fp.align_expr != 0) 10508 (void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY); 10509 if (fp.addrspace_expr != 0) 10510 (void)rlExpr( 10511 ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY); 10512 if (fp.section_expr != 0) 10513 (void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY); 10514 if (fp.callconv_expr != 0) 10515 (void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY); 10516 } 10517 } else { 10518 // Standalone fn_proto (no body). 10519 if (tag == AST_NODE_FN_PROTO_SIMPLE) { 10520 return_type = nd.rhs; 10521 if (nd.lhs != 0) 10522 (void)rlExpr(ag, nd.lhs, block, RL_RI_TYPE_ONLY); 10523 } else if (tag == AST_NODE_FN_PROTO_MULTI) { 10524 return_type = nd.rhs; 10525 uint32_t ps = tree->extra_data.arr[nd.lhs]; 10526 uint32_t pe = tree->extra_data.arr[nd.lhs + 1]; 10527 for (uint32_t i = ps; i < pe; i++) 10528 (void)rlExpr( 10529 ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY); 10530 } else if (tag == AST_NODE_FN_PROTO_ONE) { 10531 return_type = nd.rhs; 10532 AstFnProtoOne fp; 10533 fp.param = tree->extra_data.arr[nd.lhs]; 10534 fp.align_expr = tree->extra_data.arr[nd.lhs + 1]; 10535 fp.addrspace_expr = tree->extra_data.arr[nd.lhs + 2]; 10536 fp.section_expr = tree->extra_data.arr[nd.lhs + 3]; 10537 fp.callconv_expr = tree->extra_data.arr[nd.lhs + 4]; 10538 if (fp.param != 0) 10539 (void)rlExpr(ag, fp.param, block, RL_RI_TYPE_ONLY); 10540 if (fp.align_expr != 0) 10541 (void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY); 10542 if (fp.addrspace_expr != 0) 10543 (void)rlExpr( 10544 ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY); 10545 if (fp.section_expr != 0) 10546 (void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY); 10547 if (fp.callconv_expr != 0) 10548 (void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY); 10549 } else if (tag == AST_NODE_FN_PROTO) { 10550 return_type = nd.rhs; 10551 AstFnProto fp; 10552 fp.params_start = tree->extra_data.arr[nd.lhs]; 10553 fp.params_end = tree->extra_data.arr[nd.lhs + 1]; 10554 fp.align_expr = tree->extra_data.arr[nd.lhs + 2]; 10555 fp.addrspace_expr = tree->extra_data.arr[nd.lhs + 3]; 10556 fp.section_expr = tree->extra_data.arr[nd.lhs + 4]; 10557 fp.callconv_expr = tree->extra_data.arr[nd.lhs + 5]; 10558 for (uint32_t i = fp.params_start; i < fp.params_end; i++) 10559 (void)rlExpr( 10560 ag, tree->extra_data.arr[i], block, RL_RI_TYPE_ONLY); 10561 if (fp.align_expr != 0) 10562 (void)rlExpr(ag, fp.align_expr, block, RL_RI_TYPE_ONLY); 10563 if (fp.addrspace_expr != 0) 10564 (void)rlExpr( 10565 ag, fp.addrspace_expr, block, RL_RI_TYPE_ONLY); 10566 if (fp.section_expr != 0) 10567 (void)rlExpr(ag, fp.section_expr, block, RL_RI_TYPE_ONLY); 10568 if (fp.callconv_expr != 0) 10569 (void)rlExpr(ag, fp.callconv_expr, block, RL_RI_TYPE_ONLY); 10570 } 10571 } 10572 10573 if (return_type != 0) 10574 (void)rlExpr(ag, return_type, block, RL_RI_TYPE_ONLY); 10575 if (body_node != 0) 10576 (void)rlExpr(ag, body_node, block, RL_RI_NONE); 10577 return false; 10578 } 10579 10580 // Remaining: usingnamespace, await, assign_destructure, async calls. 10581 case AST_NODE_USINGNAMESPACE: 10582 return false; 10583 case AST_NODE_AWAIT: 10584 (void)rlExpr(ag, nd.lhs, block, RL_RI_NONE); 10585 return false; 10586 case AST_NODE_ASSIGN_DESTRUCTURE: 10587 return false; // TODO if needed 10588 case AST_NODE_ASYNC_CALL_ONE: 10589 case AST_NODE_ASYNC_CALL_ONE_COMMA: 10590 case AST_NODE_ASYNC_CALL: 10591 case AST_NODE_ASYNC_CALL_COMMA: 10592 return false; // async not relevant 10593 10594 default: 10595 return false; 10596 } 10597 } 10598 10599 // astRlAnnotate (AstRlAnnotate.zig:64-83). 10600 // Entry point: run the RL annotation pre-pass. 10601 static void astRlAnnotate(AstGenCtx* ag) { 10602 const Ast* tree = ag->tree; 10603 if (tree->has_error) 10604 return; 10605 10606 // Get root container members (same as in astGen). 10607 AstData root_data = tree->nodes.datas[0]; 10608 uint32_t members_start = root_data.lhs; 10609 uint32_t members_end = root_data.rhs; 10610 const uint32_t* members = tree->extra_data.arr + members_start; 10611 uint32_t members_len = members_end - members_start; 10612 10613 for (uint32_t i = 0; i < members_len; i++) 10614 (void)rlExpr(ag, members[i], NULL, RL_RI_NONE); 10615 } 10616 10617 // --- Public API: astGen (AstGen.zig:144) --- 10618 10619 Zir astGen(const Ast* ast) { 10620 AstGenCtx ag; 10621 memset(&ag, 0, sizeof(ag)); 10622 ag.tree = ast; 10623 10624 // Initial allocations (AstGen.zig:162-172). 10625 uint32_t nodes_len = ast->nodes.len; 10626 uint32_t init_cap = nodes_len > 8 ? nodes_len : 8; 10627 10628 ag.inst_cap = init_cap; 10629 ag.inst_tags = ARR_INIT(ZirInstTag, ag.inst_cap); 10630 ag.inst_datas = ARR_INIT(ZirInstData, ag.inst_cap); 10631 10632 ag.extra_cap = init_cap + ZIR_EXTRA_RESERVED_COUNT; 10633 ag.extra = ARR_INIT(uint32_t, ag.extra_cap); 10634 10635 ag.string_bytes_cap = 16; 10636 ag.string_bytes = ARR_INIT(uint8_t, ag.string_bytes_cap); 10637 10638 // String table index 0 is reserved for NullTerminatedString.empty 10639 // (AstGen.zig:163). 10640 ag.string_bytes[0] = 0; 10641 ag.string_bytes_len = 1; 10642 10643 // Reserve extra[0..1] (AstGen.zig:170-172). 10644 ag.extra[ZIR_EXTRA_COMPILE_ERRORS] = 0; 10645 ag.extra[ZIR_EXTRA_IMPORTS] = 0; 10646 ag.extra_len = ZIR_EXTRA_RESERVED_COUNT; 10647 10648 // Run AstRlAnnotate pre-pass (AstGen.zig:150-151). 10649 astRlAnnotate(&ag); 10650 10651 // Set up root GenZir scope (AstGen.zig:176-185). 10652 GenZir gen_scope; 10653 memset(&gen_scope, 0, sizeof(gen_scope)); 10654 gen_scope.base.tag = SCOPE_GEN_ZIR; 10655 gen_scope.parent = NULL; 10656 gen_scope.astgen = &ag; 10657 gen_scope.is_comptime = true; 10658 gen_scope.decl_node_index = 0; // root 10659 gen_scope.decl_line = 0; 10660 gen_scope.break_block = UINT32_MAX; 10661 10662 // Get root container members: containerDeclRoot (AstGen.zig:191-195). 10663 AstData root_data = ast->nodes.datas[0]; 10664 uint32_t members_start = root_data.lhs; 10665 uint32_t members_end = root_data.rhs; 10666 const uint32_t* members = ast->extra_data.arr + members_start; 10667 uint32_t members_len = members_end - members_start; 10668 10669 structDeclInner(&ag, &gen_scope, 0, members, members_len); 10670 10671 // Write imports list (AstGen.zig:227-244). 10672 writeImports(&ag); 10673 10674 // Build output Zir (AstGen.zig:211-239). 10675 Zir zir; 10676 zir.inst_len = ag.inst_len; 10677 zir.inst_cap = ag.inst_cap; 10678 zir.inst_tags = ag.inst_tags; 10679 zir.inst_datas = ag.inst_datas; 10680 zir.extra_len = ag.extra_len; 10681 zir.extra_cap = ag.extra_cap; 10682 zir.extra = ag.extra; 10683 zir.string_bytes_len = ag.string_bytes_len; 10684 zir.string_bytes_cap = ag.string_bytes_cap; 10685 zir.string_bytes = ag.string_bytes; 10686 zir.has_compile_errors = ag.has_compile_errors; 10687 10688 free(ag.imports); 10689 free(ag.decl_names); 10690 free(ag.decl_nodes); 10691 free(ag.scratch_instructions); 10692 free(ag.scratch_extra); 10693 free(ag.ref_table_keys); 10694 free(ag.ref_table_vals); 10695 free(ag.nodes_need_rl); 10696 free(ag.string_table); 10697 10698 return zir; 10699 }