blob 4e571ffd (494619B) - Raw
1 //! Ingests an AST and produces ZIR code. 2 const AstGen = @This(); 3 4 const std = @import("std"); 5 const Ast = std.zig.Ast; 6 const mem = std.mem; 7 const Allocator = std.mem.Allocator; 8 const assert = std.debug.assert; 9 const ArrayListUnmanaged = std.ArrayListUnmanaged; 10 const StringIndexAdapter = std.hash_map.StringIndexAdapter; 11 const StringIndexContext = std.hash_map.StringIndexContext; 12 13 const isPrimitive = std.zig.primitives.isPrimitive; 14 15 const Zir = @import("Zir.zig"); 16 const refToIndex = Zir.refToIndex; 17 const indexToRef = Zir.indexToRef; 18 const trace = @import("tracy.zig").trace; 19 const BuiltinFn = @import("BuiltinFn.zig"); 20 21 gpa: Allocator, 22 tree: *const Ast, 23 instructions: std.MultiArrayList(Zir.Inst) = .{}, 24 extra: ArrayListUnmanaged(u32) = .{}, 25 string_bytes: ArrayListUnmanaged(u8) = .{}, 26 /// Tracks the current byte offset within the source file. 27 /// Used to populate line deltas in the ZIR. AstGen maintains 28 /// this "cursor" throughout the entire AST lowering process in order 29 /// to avoid starting over the line/column scan for every declaration, which 30 /// would be O(N^2). 31 source_offset: u32 = 0, 32 /// Tracks the corresponding line of `source_offset`. 33 /// This value is absolute. 34 source_line: u32 = 0, 35 /// Tracks the corresponding column of `source_offset`. 36 /// This value is absolute. 37 source_column: u32 = 0, 38 /// Used for temporary allocations; freed after AstGen is complete. 39 /// The resulting ZIR code has no references to anything in this arena. 40 arena: Allocator, 41 string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, 42 compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, 43 /// The topmost block of the current function. 44 fn_block: ?*GenZir = null, 45 /// Maps string table indexes to the first `@import` ZIR instruction 46 /// that uses this string as the operand. 47 imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{}, 48 /// Used for temporary storage when building payloads. 49 scratch: std.ArrayListUnmanaged(u32) = .{}, 50 /// Whenever a `ref` instruction is needed, it is created and saved in this 51 /// table instead of being immediately appended to the current block body. 52 /// Then, when the instruction is being added to the parent block (typically from 53 /// setBlockBody), if it has a ref_table entry, then the ref instruction is added 54 /// there. This makes sure two properties are upheld: 55 /// 1. All pointers to the same locals return the same address. This is required 56 /// to be compliant with the language specification. 57 /// 2. `ref` instructions will dominate their uses. This is a required property 58 /// of ZIR. 59 /// The key is the ref operand; the value is the ref instruction. 60 ref_table: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 61 62 const InnerError = error{ OutOfMemory, AnalysisFail }; 63 64 fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { 65 const fields = std.meta.fields(@TypeOf(extra)); 66 try astgen.extra.ensureUnusedCapacity(astgen.gpa, fields.len); 67 return addExtraAssumeCapacity(astgen, extra); 68 } 69 70 fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { 71 const fields = std.meta.fields(@TypeOf(extra)); 72 const result = @intCast(u32, astgen.extra.items.len); 73 astgen.extra.items.len += fields.len; 74 setExtra(astgen, result, extra); 75 return result; 76 } 77 78 fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void { 79 const fields = std.meta.fields(@TypeOf(extra)); 80 var i = index; 81 inline for (fields) |field| { 82 astgen.extra.items[i] = switch (field.field_type) { 83 u32 => @field(extra, field.name), 84 Zir.Inst.Ref => @enumToInt(@field(extra, field.name)), 85 i32 => @bitCast(u32, @field(extra, field.name)), 86 Zir.Inst.Call.Flags => @bitCast(u32, @field(extra, field.name)), 87 Zir.Inst.BuiltinCall.Flags => @bitCast(u32, @field(extra, field.name)), 88 Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)), 89 Zir.Inst.FuncFancy.Bits => @bitCast(u32, @field(extra, field.name)), 90 else => @compileError("bad field type"), 91 }; 92 i += 1; 93 } 94 } 95 96 fn reserveExtra(astgen: *AstGen, size: usize) Allocator.Error!u32 { 97 const result = @intCast(u32, astgen.extra.items.len); 98 try astgen.extra.resize(astgen.gpa, result + size); 99 return result; 100 } 101 102 fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void { 103 const coerced = @ptrCast([]const u32, refs); 104 return astgen.extra.appendSlice(astgen.gpa, coerced); 105 } 106 107 fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { 108 const coerced = @ptrCast([]const u32, refs); 109 astgen.extra.appendSliceAssumeCapacity(coerced); 110 } 111 112 pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir { 113 var arena = std.heap.ArenaAllocator.init(gpa); 114 defer arena.deinit(); 115 116 var astgen: AstGen = .{ 117 .gpa = gpa, 118 .arena = arena.allocator(), 119 .tree = &tree, 120 }; 121 defer astgen.deinit(gpa); 122 123 // String table indexes 0, 1, 2 are reserved for special meaning. 124 try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0, 0 }); 125 126 // We expect at least as many ZIR instructions and extra data items 127 // as AST nodes. 128 try astgen.instructions.ensureTotalCapacity(gpa, tree.nodes.len); 129 130 // First few indexes of extra are reserved and set at the end. 131 const reserved_count = @typeInfo(Zir.ExtraIndex).Enum.fields.len; 132 try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count); 133 astgen.extra.items.len += reserved_count; 134 135 var top_scope: Scope.Top = .{}; 136 137 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{}; 138 var gen_scope: GenZir = .{ 139 .force_comptime = true, 140 .parent = &top_scope.base, 141 .anon_name_strategy = .parent, 142 .decl_node_index = 0, 143 .decl_line = 0, 144 .astgen = &astgen, 145 .instructions = &gz_instructions, 146 .instructions_top = 0, 147 }; 148 defer gz_instructions.deinit(gpa); 149 150 if (AstGen.structDeclInner( 151 &gen_scope, 152 &gen_scope.base, 153 0, 154 tree.containerDeclRoot(), 155 .Auto, 156 0, 157 )) |struct_decl_ref| { 158 assert(refToIndex(struct_decl_ref).? == 0); 159 } else |err| switch (err) { 160 error.OutOfMemory => return error.OutOfMemory, 161 error.AnalysisFail => {}, // Handled via compile_errors below. 162 } 163 164 const err_index = @enumToInt(Zir.ExtraIndex.compile_errors); 165 if (astgen.compile_errors.items.len == 0) { 166 astgen.extra.items[err_index] = 0; 167 } else { 168 try astgen.extra.ensureUnusedCapacity(gpa, 1 + astgen.compile_errors.items.len * 169 @typeInfo(Zir.Inst.CompileErrors.Item).Struct.fields.len); 170 171 astgen.extra.items[err_index] = astgen.addExtraAssumeCapacity(Zir.Inst.CompileErrors{ 172 .items_len = @intCast(u32, astgen.compile_errors.items.len), 173 }); 174 175 for (astgen.compile_errors.items) |item| { 176 _ = astgen.addExtraAssumeCapacity(item); 177 } 178 } 179 180 const imports_index = @enumToInt(Zir.ExtraIndex.imports); 181 if (astgen.imports.count() == 0) { 182 astgen.extra.items[imports_index] = 0; 183 } else { 184 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Imports).Struct.fields.len + 185 astgen.imports.count() * @typeInfo(Zir.Inst.Imports.Item).Struct.fields.len); 186 187 astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{ 188 .imports_len = @intCast(u32, astgen.imports.count()), 189 }); 190 191 var it = astgen.imports.iterator(); 192 while (it.next()) |entry| { 193 _ = astgen.addExtraAssumeCapacity(Zir.Inst.Imports.Item{ 194 .name = entry.key_ptr.*, 195 .token = entry.value_ptr.*, 196 }); 197 } 198 } 199 200 return Zir{ 201 .instructions = astgen.instructions.toOwnedSlice(), 202 .string_bytes = try astgen.string_bytes.toOwnedSlice(gpa), 203 .extra = try astgen.extra.toOwnedSlice(gpa), 204 }; 205 } 206 207 pub fn deinit(astgen: *AstGen, gpa: Allocator) void { 208 astgen.instructions.deinit(gpa); 209 astgen.extra.deinit(gpa); 210 astgen.string_table.deinit(gpa); 211 astgen.string_bytes.deinit(gpa); 212 astgen.compile_errors.deinit(gpa); 213 astgen.imports.deinit(gpa); 214 astgen.scratch.deinit(gpa); 215 astgen.ref_table.deinit(gpa); 216 } 217 218 pub const ResultInfo = struct { 219 /// The semantics requested for the result location 220 rl: Loc, 221 222 /// The "operator" consuming the result location 223 ctx: Context = .none, 224 225 /// Turns a `coerced_ty` back into a `ty`. Should be called at branch points 226 /// such as if and switch expressions. 227 fn br(ri: ResultInfo) ResultInfo { 228 return switch (ri.rl) { 229 .coerced_ty => |ty| .{ 230 .rl = .{ .ty = ty }, 231 .ctx = ri.ctx, 232 }, 233 else => ri, 234 }; 235 } 236 237 fn zirTag(ri: ResultInfo) Zir.Inst.Tag { 238 switch (ri.rl) { 239 .ty => return switch (ri.ctx) { 240 .shift_op => .as_shift_operand, 241 else => .as_node, 242 }, 243 else => unreachable, 244 } 245 } 246 247 pub const Loc = union(enum) { 248 /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the 249 /// expression should be generated. The result instruction from the expression must 250 /// be ignored. 251 discard, 252 /// The expression has an inferred type, and it will be evaluated as an rvalue. 253 none, 254 /// The expression must generate a pointer rather than a value. For example, the left hand side 255 /// of an assignment uses this kind of result location. 256 ref, 257 /// The expression will be coerced into this type, but it will be evaluated as an rvalue. 258 ty: Zir.Inst.Ref, 259 /// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion, 260 /// so no `as` instruction needs to be emitted. 261 coerced_ty: Zir.Inst.Ref, 262 /// The expression must store its result into this typed pointer. The result instruction 263 /// from the expression must be ignored. 264 ptr: PtrResultLoc, 265 /// The expression must store its result into this allocation, which has an inferred type. 266 /// The result instruction from the expression must be ignored. 267 /// Always an instruction with tag `alloc_inferred`. 268 inferred_ptr: Zir.Inst.Ref, 269 /// There is a pointer for the expression to store its result into, however, its type 270 /// is inferred based on peer type resolution for a `Zir.Inst.Block`. 271 /// The result instruction from the expression must be ignored. 272 block_ptr: *GenZir, 273 274 const PtrResultLoc = struct { 275 inst: Zir.Inst.Ref, 276 src_node: ?Ast.Node.Index = null, 277 }; 278 279 pub const Strategy = struct { 280 elide_store_to_block_ptr_instructions: bool, 281 tag: Tag, 282 283 pub const Tag = enum { 284 /// Both branches will use break_void; result location is used to communicate the 285 /// result instruction. 286 break_void, 287 /// Use break statements to pass the block result value, and call rvalue() at 288 /// the end depending on rl. Also elide the store_to_block_ptr instructions 289 /// depending on rl. 290 break_operand, 291 }; 292 }; 293 294 fn strategy(rl: Loc, block_scope: *GenZir) Strategy { 295 switch (rl) { 296 // In this branch there will not be any store_to_block_ptr instructions. 297 .none, .ty, .coerced_ty, .ref => return .{ 298 .tag = .break_operand, 299 .elide_store_to_block_ptr_instructions = false, 300 }, 301 .discard => return .{ 302 .tag = .break_void, 303 .elide_store_to_block_ptr_instructions = false, 304 }, 305 // The pointer got passed through to the sub-expressions, so we will use 306 // break_void here. 307 // In this branch there will not be any store_to_block_ptr instructions. 308 .ptr => return .{ 309 .tag = .break_void, 310 .elide_store_to_block_ptr_instructions = false, 311 }, 312 .inferred_ptr, .block_ptr => { 313 if (block_scope.rvalue_rl_count == block_scope.break_count) { 314 // Neither prong of the if consumed the result location, so we can 315 // use break instructions to create an rvalue. 316 return .{ 317 .tag = .break_operand, 318 .elide_store_to_block_ptr_instructions = true, 319 }; 320 } else { 321 // Allow the store_to_block_ptr instructions to remain so that 322 // semantic analysis can turn them into bitcasts. 323 return .{ 324 .tag = .break_void, 325 .elide_store_to_block_ptr_instructions = false, 326 }; 327 } 328 }, 329 } 330 } 331 }; 332 333 pub const Context = enum { 334 /// The expression is the operand to a return expression. 335 @"return", 336 /// The expression is the input to an error-handling operator (if-else, try, or catch). 337 error_handling_expr, 338 /// The expression is the right-hand side of a shift operation. 339 shift_op, 340 /// The expression is an argument in a function call. 341 fn_arg, 342 /// The expression is the right-hand side of an initializer for a `const` variable 343 const_init, 344 /// The expression is the right-hand side of an assignment expression. 345 assignment, 346 /// No specific operator in particular. 347 none, 348 }; 349 }; 350 351 pub const align_ri: ResultInfo = .{ .rl = .{ .ty = .u29_type } }; 352 pub const coerced_align_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .u29_type } }; 353 pub const bool_ri: ResultInfo = .{ .rl = .{ .ty = .bool_type } }; 354 pub const type_ri: ResultInfo = .{ .rl = .{ .ty = .type_type } }; 355 pub const coerced_type_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .type_type } }; 356 357 fn typeExpr(gz: *GenZir, scope: *Scope, type_node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 358 const prev_force_comptime = gz.force_comptime; 359 gz.force_comptime = true; 360 defer gz.force_comptime = prev_force_comptime; 361 362 return expr(gz, scope, coerced_type_ri, type_node); 363 } 364 365 fn reachableTypeExpr( 366 gz: *GenZir, 367 scope: *Scope, 368 type_node: Ast.Node.Index, 369 reachable_node: Ast.Node.Index, 370 ) InnerError!Zir.Inst.Ref { 371 const prev_force_comptime = gz.force_comptime; 372 gz.force_comptime = true; 373 defer gz.force_comptime = prev_force_comptime; 374 375 return reachableExpr(gz, scope, coerced_type_ri, type_node, reachable_node); 376 } 377 378 /// Same as `expr` but fails with a compile error if the result type is `noreturn`. 379 fn reachableExpr( 380 gz: *GenZir, 381 scope: *Scope, 382 ri: ResultInfo, 383 node: Ast.Node.Index, 384 reachable_node: Ast.Node.Index, 385 ) InnerError!Zir.Inst.Ref { 386 return reachableExprComptime(gz, scope, ri, node, reachable_node, false); 387 } 388 389 fn reachableExprComptime( 390 gz: *GenZir, 391 scope: *Scope, 392 ri: ResultInfo, 393 node: Ast.Node.Index, 394 reachable_node: Ast.Node.Index, 395 force_comptime: bool, 396 ) InnerError!Zir.Inst.Ref { 397 const prev_force_comptime = gz.force_comptime; 398 gz.force_comptime = prev_force_comptime or force_comptime; 399 defer gz.force_comptime = prev_force_comptime; 400 401 const result_inst = try expr(gz, scope, ri, node); 402 if (gz.refIsNoReturn(result_inst)) { 403 try gz.astgen.appendErrorNodeNotes(reachable_node, "unreachable code", .{}, &[_]u32{ 404 try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}), 405 }); 406 } 407 return result_inst; 408 } 409 410 fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 411 const astgen = gz.astgen; 412 const tree = astgen.tree; 413 const node_tags = tree.nodes.items(.tag); 414 const main_tokens = tree.nodes.items(.main_token); 415 switch (node_tags[node]) { 416 .root => unreachable, 417 .@"usingnamespace" => unreachable, 418 .test_decl => unreachable, 419 .global_var_decl => unreachable, 420 .local_var_decl => unreachable, 421 .simple_var_decl => unreachable, 422 .aligned_var_decl => unreachable, 423 .switch_case => unreachable, 424 .switch_case_inline => unreachable, 425 .switch_case_one => unreachable, 426 .switch_case_inline_one => unreachable, 427 .container_field_init => unreachable, 428 .container_field_align => unreachable, 429 .container_field => unreachable, 430 .asm_output => unreachable, 431 .asm_input => unreachable, 432 433 .assign, 434 .assign_bit_and, 435 .assign_bit_or, 436 .assign_shl, 437 .assign_shl_sat, 438 .assign_shr, 439 .assign_bit_xor, 440 .assign_div, 441 .assign_sub, 442 .assign_sub_wrap, 443 .assign_sub_sat, 444 .assign_mod, 445 .assign_add, 446 .assign_add_wrap, 447 .assign_add_sat, 448 .assign_mul, 449 .assign_mul_wrap, 450 .assign_mul_sat, 451 .add, 452 .add_wrap, 453 .add_sat, 454 .sub, 455 .sub_wrap, 456 .sub_sat, 457 .mul, 458 .mul_wrap, 459 .mul_sat, 460 .div, 461 .mod, 462 .bit_and, 463 .bit_or, 464 .shl, 465 .shl_sat, 466 .shr, 467 .bit_xor, 468 .bang_equal, 469 .equal_equal, 470 .greater_than, 471 .greater_or_equal, 472 .less_than, 473 .less_or_equal, 474 .array_cat, 475 .array_mult, 476 .bool_and, 477 .bool_or, 478 .@"asm", 479 .asm_simple, 480 .string_literal, 481 .number_literal, 482 .call, 483 .call_comma, 484 .async_call, 485 .async_call_comma, 486 .call_one, 487 .call_one_comma, 488 .async_call_one, 489 .async_call_one_comma, 490 .unreachable_literal, 491 .@"return", 492 .@"if", 493 .if_simple, 494 .@"while", 495 .while_simple, 496 .while_cont, 497 .bool_not, 498 .address_of, 499 .optional_type, 500 .block, 501 .block_semicolon, 502 .block_two, 503 .block_two_semicolon, 504 .@"break", 505 .ptr_type_aligned, 506 .ptr_type_sentinel, 507 .ptr_type, 508 .ptr_type_bit_range, 509 .array_type, 510 .array_type_sentinel, 511 .enum_literal, 512 .multiline_string_literal, 513 .char_literal, 514 .@"defer", 515 .@"errdefer", 516 .@"catch", 517 .error_union, 518 .merge_error_sets, 519 .switch_range, 520 .@"await", 521 .bit_not, 522 .negation, 523 .negation_wrap, 524 .@"resume", 525 .@"try", 526 .slice, 527 .slice_open, 528 .slice_sentinel, 529 .array_init_one, 530 .array_init_one_comma, 531 .array_init_dot_two, 532 .array_init_dot_two_comma, 533 .array_init_dot, 534 .array_init_dot_comma, 535 .array_init, 536 .array_init_comma, 537 .struct_init_one, 538 .struct_init_one_comma, 539 .struct_init_dot_two, 540 .struct_init_dot_two_comma, 541 .struct_init_dot, 542 .struct_init_dot_comma, 543 .struct_init, 544 .struct_init_comma, 545 .@"switch", 546 .switch_comma, 547 .@"for", 548 .for_simple, 549 .@"suspend", 550 .@"continue", 551 .fn_proto_simple, 552 .fn_proto_multi, 553 .fn_proto_one, 554 .fn_proto, 555 .fn_decl, 556 .anyframe_type, 557 .anyframe_literal, 558 .error_set_decl, 559 .container_decl, 560 .container_decl_trailing, 561 .container_decl_two, 562 .container_decl_two_trailing, 563 .container_decl_arg, 564 .container_decl_arg_trailing, 565 .tagged_union, 566 .tagged_union_trailing, 567 .tagged_union_two, 568 .tagged_union_two_trailing, 569 .tagged_union_enum_tag, 570 .tagged_union_enum_tag_trailing, 571 .@"comptime", 572 .@"nosuspend", 573 .error_value, 574 => return astgen.failNode(node, "invalid left-hand side to assignment", .{}), 575 576 .builtin_call, 577 .builtin_call_comma, 578 .builtin_call_two, 579 .builtin_call_two_comma, 580 => { 581 const builtin_token = main_tokens[node]; 582 const builtin_name = tree.tokenSlice(builtin_token); 583 // If the builtin is an invalid name, we don't cause an error here; instead 584 // let it pass, and the error will be "invalid builtin function" later. 585 if (BuiltinFn.list.get(builtin_name)) |info| { 586 if (!info.allows_lvalue) { 587 return astgen.failNode(node, "invalid left-hand side to assignment", .{}); 588 } 589 } 590 }, 591 592 // These can be assigned to. 593 .unwrap_optional, 594 .deref, 595 .field_access, 596 .array_access, 597 .identifier, 598 .grouped_expression, 599 .@"orelse", 600 => {}, 601 } 602 return expr(gz, scope, .{ .rl = .ref }, node); 603 } 604 605 /// Turn Zig AST into untyped ZIR instructions. 606 /// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the 607 /// result instruction can be used to inspect whether it is isNoReturn() but that is it, 608 /// it must otherwise not be used. 609 fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 610 const astgen = gz.astgen; 611 const tree = astgen.tree; 612 const main_tokens = tree.nodes.items(.main_token); 613 const token_tags = tree.tokens.items(.tag); 614 const node_datas = tree.nodes.items(.data); 615 const node_tags = tree.nodes.items(.tag); 616 617 const prev_anon_name_strategy = gz.anon_name_strategy; 618 defer gz.anon_name_strategy = prev_anon_name_strategy; 619 if (!nodeUsesAnonNameStrategy(tree, node)) { 620 gz.anon_name_strategy = .anon; 621 } 622 623 switch (node_tags[node]) { 624 .root => unreachable, // Top-level declaration. 625 .@"usingnamespace" => unreachable, // Top-level declaration. 626 .test_decl => unreachable, // Top-level declaration. 627 .container_field_init => unreachable, // Top-level declaration. 628 .container_field_align => unreachable, // Top-level declaration. 629 .container_field => unreachable, // Top-level declaration. 630 .fn_decl => unreachable, // Top-level declaration. 631 632 .global_var_decl => unreachable, // Handled in `blockExpr`. 633 .local_var_decl => unreachable, // Handled in `blockExpr`. 634 .simple_var_decl => unreachable, // Handled in `blockExpr`. 635 .aligned_var_decl => unreachable, // Handled in `blockExpr`. 636 .@"defer" => unreachable, // Handled in `blockExpr`. 637 .@"errdefer" => unreachable, // Handled in `blockExpr`. 638 639 .switch_case => unreachable, // Handled in `switchExpr`. 640 .switch_case_inline => unreachable, // Handled in `switchExpr`. 641 .switch_case_one => unreachable, // Handled in `switchExpr`. 642 .switch_case_inline_one => unreachable, // Handled in `switchExpr`. 643 .switch_range => unreachable, // Handled in `switchExpr`. 644 645 .asm_output => unreachable, // Handled in `asmExpr`. 646 .asm_input => unreachable, // Handled in `asmExpr`. 647 648 .assign => { 649 try assign(gz, scope, node); 650 return rvalue(gz, ri, .void_value, node); 651 }, 652 653 .assign_shl => { 654 try assignShift(gz, scope, node, .shl); 655 return rvalue(gz, ri, .void_value, node); 656 }, 657 .assign_shl_sat => { 658 try assignShiftSat(gz, scope, node); 659 return rvalue(gz, ri, .void_value, node); 660 }, 661 .assign_shr => { 662 try assignShift(gz, scope, node, .shr); 663 return rvalue(gz, ri, .void_value, node); 664 }, 665 666 .assign_bit_and => { 667 try assignOp(gz, scope, node, .bit_and); 668 return rvalue(gz, ri, .void_value, node); 669 }, 670 .assign_bit_or => { 671 try assignOp(gz, scope, node, .bit_or); 672 return rvalue(gz, ri, .void_value, node); 673 }, 674 .assign_bit_xor => { 675 try assignOp(gz, scope, node, .xor); 676 return rvalue(gz, ri, .void_value, node); 677 }, 678 .assign_div => { 679 try assignOp(gz, scope, node, .div); 680 return rvalue(gz, ri, .void_value, node); 681 }, 682 .assign_sub => { 683 try assignOp(gz, scope, node, .sub); 684 return rvalue(gz, ri, .void_value, node); 685 }, 686 .assign_sub_wrap => { 687 try assignOp(gz, scope, node, .subwrap); 688 return rvalue(gz, ri, .void_value, node); 689 }, 690 .assign_sub_sat => { 691 try assignOp(gz, scope, node, .sub_sat); 692 return rvalue(gz, ri, .void_value, node); 693 }, 694 .assign_mod => { 695 try assignOp(gz, scope, node, .mod_rem); 696 return rvalue(gz, ri, .void_value, node); 697 }, 698 .assign_add => { 699 try assignOp(gz, scope, node, .add); 700 return rvalue(gz, ri, .void_value, node); 701 }, 702 .assign_add_wrap => { 703 try assignOp(gz, scope, node, .addwrap); 704 return rvalue(gz, ri, .void_value, node); 705 }, 706 .assign_add_sat => { 707 try assignOp(gz, scope, node, .add_sat); 708 return rvalue(gz, ri, .void_value, node); 709 }, 710 .assign_mul => { 711 try assignOp(gz, scope, node, .mul); 712 return rvalue(gz, ri, .void_value, node); 713 }, 714 .assign_mul_wrap => { 715 try assignOp(gz, scope, node, .mulwrap); 716 return rvalue(gz, ri, .void_value, node); 717 }, 718 .assign_mul_sat => { 719 try assignOp(gz, scope, node, .mul_sat); 720 return rvalue(gz, ri, .void_value, node); 721 }, 722 723 // zig fmt: off 724 .shl => return shiftOp(gz, scope, ri, node, node_datas[node].lhs, node_datas[node].rhs, .shl), 725 .shr => return shiftOp(gz, scope, ri, node, node_datas[node].lhs, node_datas[node].rhs, .shr), 726 727 .add => return simpleBinOp(gz, scope, ri, node, .add), 728 .add_wrap => return simpleBinOp(gz, scope, ri, node, .addwrap), 729 .add_sat => return simpleBinOp(gz, scope, ri, node, .add_sat), 730 .sub => return simpleBinOp(gz, scope, ri, node, .sub), 731 .sub_wrap => return simpleBinOp(gz, scope, ri, node, .subwrap), 732 .sub_sat => return simpleBinOp(gz, scope, ri, node, .sub_sat), 733 .mul => return simpleBinOp(gz, scope, ri, node, .mul), 734 .mul_wrap => return simpleBinOp(gz, scope, ri, node, .mulwrap), 735 .mul_sat => return simpleBinOp(gz, scope, ri, node, .mul_sat), 736 .div => return simpleBinOp(gz, scope, ri, node, .div), 737 .mod => return simpleBinOp(gz, scope, ri, node, .mod_rem), 738 .shl_sat => return simpleBinOp(gz, scope, ri, node, .shl_sat), 739 740 .bit_and => return simpleBinOp(gz, scope, ri, node, .bit_and), 741 .bit_or => return simpleBinOp(gz, scope, ri, node, .bit_or), 742 .bit_xor => return simpleBinOp(gz, scope, ri, node, .xor), 743 .bang_equal => return simpleBinOp(gz, scope, ri, node, .cmp_neq), 744 .equal_equal => return simpleBinOp(gz, scope, ri, node, .cmp_eq), 745 .greater_than => return simpleBinOp(gz, scope, ri, node, .cmp_gt), 746 .greater_or_equal => return simpleBinOp(gz, scope, ri, node, .cmp_gte), 747 .less_than => return simpleBinOp(gz, scope, ri, node, .cmp_lt), 748 .less_or_equal => return simpleBinOp(gz, scope, ri, node, .cmp_lte), 749 .array_cat => return simpleBinOp(gz, scope, ri, node, .array_cat), 750 751 .array_mult => { 752 const result = try gz.addPlNode(.array_mul, node, Zir.Inst.Bin{ 753 .lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs), 754 .rhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs), 755 }); 756 return rvalue(gz, ri, result, node); 757 }, 758 759 .error_union => return simpleBinOp(gz, scope, ri, node, .error_union_type), 760 .merge_error_sets => return simpleBinOp(gz, scope, ri, node, .merge_error_sets), 761 762 .bool_and => return boolBinOp(gz, scope, ri, node, .bool_br_and), 763 .bool_or => return boolBinOp(gz, scope, ri, node, .bool_br_or), 764 765 .bool_not => return simpleUnOp(gz, scope, ri, node, bool_ri, node_datas[node].lhs, .bool_not), 766 .bit_not => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, node_datas[node].lhs, .bit_not), 767 768 .negation => return negation(gz, scope, ri, node), 769 .negation_wrap => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, node_datas[node].lhs, .negate_wrap), 770 771 .identifier => return identifier(gz, scope, ri, node), 772 773 .asm_simple => return asmExpr(gz, scope, ri, node, tree.asmSimple(node)), 774 .@"asm" => return asmExpr(gz, scope, ri, node, tree.asmFull(node)), 775 776 .string_literal => return stringLiteral(gz, ri, node), 777 .multiline_string_literal => return multilineStringLiteral(gz, ri, node), 778 779 .number_literal => return numberLiteral(gz, ri, node, node, .positive), 780 // zig fmt: on 781 782 .builtin_call_two, .builtin_call_two_comma => { 783 if (node_datas[node].lhs == 0) { 784 const params = [_]Ast.Node.Index{}; 785 return builtinCall(gz, scope, ri, node, ¶ms); 786 } else if (node_datas[node].rhs == 0) { 787 const params = [_]Ast.Node.Index{node_datas[node].lhs}; 788 return builtinCall(gz, scope, ri, node, ¶ms); 789 } else { 790 const params = [_]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; 791 return builtinCall(gz, scope, ri, node, ¶ms); 792 } 793 }, 794 .builtin_call, .builtin_call_comma => { 795 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 796 return builtinCall(gz, scope, ri, node, params); 797 }, 798 799 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => { 800 var params: [1]Ast.Node.Index = undefined; 801 return callExpr(gz, scope, ri, node, tree.callOne(¶ms, node)); 802 }, 803 .call, .call_comma, .async_call, .async_call_comma => { 804 return callExpr(gz, scope, ri, node, tree.callFull(node)); 805 }, 806 807 .unreachable_literal => { 808 try emitDbgNode(gz, node); 809 _ = try gz.addAsIndex(.{ 810 .tag = .@"unreachable", 811 .data = .{ .@"unreachable" = .{ 812 .force_comptime = gz.force_comptime, 813 .src_node = gz.nodeIndexToRelative(node), 814 } }, 815 }); 816 return Zir.Inst.Ref.unreachable_value; 817 }, 818 .@"return" => return ret(gz, scope, node), 819 .field_access => return fieldAccess(gz, scope, ri, node), 820 821 .if_simple => return ifExpr(gz, scope, ri.br(), node, tree.ifSimple(node)), 822 .@"if" => return ifExpr(gz, scope, ri.br(), node, tree.ifFull(node)), 823 824 .while_simple => return whileExpr(gz, scope, ri.br(), node, tree.whileSimple(node), false), 825 .while_cont => return whileExpr(gz, scope, ri.br(), node, tree.whileCont(node), false), 826 .@"while" => return whileExpr(gz, scope, ri.br(), node, tree.whileFull(node), false), 827 828 .for_simple => return forExpr(gz, scope, ri.br(), node, tree.forSimple(node), false), 829 .@"for" => return forExpr(gz, scope, ri.br(), node, tree.forFull(node), false), 830 831 .slice_open => { 832 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); 833 834 maybeAdvanceSourceCursorToMainToken(gz, node); 835 const line = gz.astgen.source_line - gz.decl_line; 836 const column = gz.astgen.source_column; 837 838 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs); 839 try emitDbgStmt(gz, line, column); 840 const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{ 841 .lhs = lhs, 842 .start = start, 843 }); 844 return rvalue(gz, ri, result, node); 845 }, 846 .slice => { 847 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); 848 849 maybeAdvanceSourceCursorToMainToken(gz, node); 850 const line = gz.astgen.source_line - gz.decl_line; 851 const column = gz.astgen.source_column; 852 853 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice); 854 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start); 855 const end = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end); 856 try emitDbgStmt(gz, line, column); 857 const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{ 858 .lhs = lhs, 859 .start = start, 860 .end = end, 861 }); 862 return rvalue(gz, ri, result, node); 863 }, 864 .slice_sentinel => { 865 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); 866 867 maybeAdvanceSourceCursorToMainToken(gz, node); 868 const line = gz.astgen.source_line - gz.decl_line; 869 const column = gz.astgen.source_column; 870 871 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel); 872 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start); 873 const end = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none; 874 const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel); 875 try emitDbgStmt(gz, line, column); 876 const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{ 877 .lhs = lhs, 878 .start = start, 879 .end = end, 880 .sentinel = sentinel, 881 }); 882 return rvalue(gz, ri, result, node); 883 }, 884 885 .deref => { 886 const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs); 887 _ = try gz.addUnNode(.validate_deref, lhs, node); 888 switch (ri.rl) { 889 .ref => return lhs, 890 else => { 891 const result = try gz.addUnNode(.load, lhs, node); 892 return rvalue(gz, ri, result, node); 893 }, 894 } 895 }, 896 .address_of => { 897 const result = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); 898 return rvalue(gz, ri, result, node); 899 }, 900 .optional_type => { 901 const operand = try typeExpr(gz, scope, node_datas[node].lhs); 902 const result = try gz.addUnNode(.optional_type, operand, node); 903 return rvalue(gz, ri, result, node); 904 }, 905 .unwrap_optional => switch (ri.rl) { 906 .ref => { 907 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); 908 909 maybeAdvanceSourceCursorToMainToken(gz, node); 910 const line = gz.astgen.source_line - gz.decl_line; 911 const column = gz.astgen.source_column; 912 try emitDbgStmt(gz, line, column); 913 914 return gz.addUnNode(.optional_payload_safe_ptr, lhs, node); 915 }, 916 else => { 917 const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs); 918 919 maybeAdvanceSourceCursorToMainToken(gz, node); 920 const line = gz.astgen.source_line - gz.decl_line; 921 const column = gz.astgen.source_column; 922 try emitDbgStmt(gz, line, column); 923 924 return rvalue(gz, ri, try gz.addUnNode(.optional_payload_safe, lhs, node), node); 925 }, 926 }, 927 .block_two, .block_two_semicolon => { 928 const statements = [2]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; 929 if (node_datas[node].lhs == 0) { 930 return blockExpr(gz, scope, ri, node, statements[0..0]); 931 } else if (node_datas[node].rhs == 0) { 932 return blockExpr(gz, scope, ri, node, statements[0..1]); 933 } else { 934 return blockExpr(gz, scope, ri, node, statements[0..2]); 935 } 936 }, 937 .block, .block_semicolon => { 938 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 939 return blockExpr(gz, scope, ri, node, statements); 940 }, 941 .enum_literal => return simpleStrTok(gz, ri, main_tokens[node], node, .enum_literal), 942 .error_value => return simpleStrTok(gz, ri, node_datas[node].rhs, node, .error_value), 943 // TODO restore this when implementing https://github.com/ziglang/zig/issues/6025 944 // .anyframe_literal => return rvalue(gz, ri, .anyframe_type, node), 945 .anyframe_literal => { 946 const result = try gz.addUnNode(.anyframe_type, .void_type, node); 947 return rvalue(gz, ri, result, node); 948 }, 949 .anyframe_type => { 950 const return_type = try typeExpr(gz, scope, node_datas[node].rhs); 951 const result = try gz.addUnNode(.anyframe_type, return_type, node); 952 return rvalue(gz, ri, result, node); 953 }, 954 .@"catch" => { 955 const catch_token = main_tokens[node]; 956 const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) 957 catch_token + 2 958 else 959 null; 960 switch (ri.rl) { 961 .ref => return orelseCatchExpr( 962 gz, 963 scope, 964 ri, 965 node, 966 node_datas[node].lhs, 967 .is_non_err_ptr, 968 .err_union_payload_unsafe_ptr, 969 .err_union_code_ptr, 970 node_datas[node].rhs, 971 payload_token, 972 ), 973 else => return orelseCatchExpr( 974 gz, 975 scope, 976 ri, 977 node, 978 node_datas[node].lhs, 979 .is_non_err, 980 .err_union_payload_unsafe, 981 .err_union_code, 982 node_datas[node].rhs, 983 payload_token, 984 ), 985 } 986 }, 987 .@"orelse" => switch (ri.rl) { 988 .ref => return orelseCatchExpr( 989 gz, 990 scope, 991 ri, 992 node, 993 node_datas[node].lhs, 994 .is_non_null_ptr, 995 .optional_payload_unsafe_ptr, 996 undefined, 997 node_datas[node].rhs, 998 null, 999 ), 1000 else => return orelseCatchExpr( 1001 gz, 1002 scope, 1003 ri, 1004 node, 1005 node_datas[node].lhs, 1006 .is_non_null, 1007 .optional_payload_unsafe, 1008 undefined, 1009 node_datas[node].rhs, 1010 null, 1011 ), 1012 }, 1013 1014 .ptr_type_aligned => return ptrType(gz, scope, ri, node, tree.ptrTypeAligned(node)), 1015 .ptr_type_sentinel => return ptrType(gz, scope, ri, node, tree.ptrTypeSentinel(node)), 1016 .ptr_type => return ptrType(gz, scope, ri, node, tree.ptrType(node)), 1017 .ptr_type_bit_range => return ptrType(gz, scope, ri, node, tree.ptrTypeBitRange(node)), 1018 1019 .container_decl, 1020 .container_decl_trailing, 1021 => return containerDecl(gz, scope, ri, node, tree.containerDecl(node)), 1022 .container_decl_two, .container_decl_two_trailing => { 1023 var buffer: [2]Ast.Node.Index = undefined; 1024 return containerDecl(gz, scope, ri, node, tree.containerDeclTwo(&buffer, node)); 1025 }, 1026 .container_decl_arg, 1027 .container_decl_arg_trailing, 1028 => return containerDecl(gz, scope, ri, node, tree.containerDeclArg(node)), 1029 1030 .tagged_union, 1031 .tagged_union_trailing, 1032 => return containerDecl(gz, scope, ri, node, tree.taggedUnion(node)), 1033 .tagged_union_two, .tagged_union_two_trailing => { 1034 var buffer: [2]Ast.Node.Index = undefined; 1035 return containerDecl(gz, scope, ri, node, tree.taggedUnionTwo(&buffer, node)); 1036 }, 1037 .tagged_union_enum_tag, 1038 .tagged_union_enum_tag_trailing, 1039 => return containerDecl(gz, scope, ri, node, tree.taggedUnionEnumTag(node)), 1040 1041 .@"break" => return breakExpr(gz, scope, node), 1042 .@"continue" => return continueExpr(gz, scope, node), 1043 .grouped_expression => return expr(gz, scope, ri, node_datas[node].lhs), 1044 .array_type => return arrayType(gz, scope, ri, node), 1045 .array_type_sentinel => return arrayTypeSentinel(gz, scope, ri, node), 1046 .char_literal => return charLiteral(gz, ri, node), 1047 .error_set_decl => return errorSetDecl(gz, ri, node), 1048 .array_access => return arrayAccess(gz, scope, ri, node), 1049 .@"comptime" => return comptimeExprAst(gz, scope, ri, node), 1050 .@"switch", .switch_comma => return switchExpr(gz, scope, ri.br(), node), 1051 1052 .@"nosuspend" => return nosuspendExpr(gz, scope, ri, node), 1053 .@"suspend" => return suspendExpr(gz, scope, node), 1054 .@"await" => return awaitExpr(gz, scope, ri, node), 1055 .@"resume" => return resumeExpr(gz, scope, ri, node), 1056 1057 .@"try" => return tryExpr(gz, scope, ri, node, node_datas[node].lhs), 1058 1059 .array_init_one, .array_init_one_comma => { 1060 var elements: [1]Ast.Node.Index = undefined; 1061 return arrayInitExpr(gz, scope, ri, node, tree.arrayInitOne(&elements, node)); 1062 }, 1063 .array_init_dot_two, .array_init_dot_two_comma => { 1064 var elements: [2]Ast.Node.Index = undefined; 1065 return arrayInitExpr(gz, scope, ri, node, tree.arrayInitDotTwo(&elements, node)); 1066 }, 1067 .array_init_dot, 1068 .array_init_dot_comma, 1069 => return arrayInitExpr(gz, scope, ri, node, tree.arrayInitDot(node)), 1070 .array_init, 1071 .array_init_comma, 1072 => return arrayInitExpr(gz, scope, ri, node, tree.arrayInit(node)), 1073 1074 .struct_init_one, .struct_init_one_comma => { 1075 var fields: [1]Ast.Node.Index = undefined; 1076 return structInitExpr(gz, scope, ri, node, tree.structInitOne(&fields, node)); 1077 }, 1078 .struct_init_dot_two, .struct_init_dot_two_comma => { 1079 var fields: [2]Ast.Node.Index = undefined; 1080 return structInitExpr(gz, scope, ri, node, tree.structInitDotTwo(&fields, node)); 1081 }, 1082 .struct_init_dot, 1083 .struct_init_dot_comma, 1084 => return structInitExpr(gz, scope, ri, node, tree.structInitDot(node)), 1085 .struct_init, 1086 .struct_init_comma, 1087 => return structInitExpr(gz, scope, ri, node, tree.structInit(node)), 1088 1089 .fn_proto_simple => { 1090 var params: [1]Ast.Node.Index = undefined; 1091 return fnProtoExpr(gz, scope, ri, node, tree.fnProtoSimple(¶ms, node)); 1092 }, 1093 .fn_proto_multi => { 1094 return fnProtoExpr(gz, scope, ri, node, tree.fnProtoMulti(node)); 1095 }, 1096 .fn_proto_one => { 1097 var params: [1]Ast.Node.Index = undefined; 1098 return fnProtoExpr(gz, scope, ri, node, tree.fnProtoOne(¶ms, node)); 1099 }, 1100 .fn_proto => { 1101 return fnProtoExpr(gz, scope, ri, node, tree.fnProto(node)); 1102 }, 1103 } 1104 } 1105 1106 fn nosuspendExpr( 1107 gz: *GenZir, 1108 scope: *Scope, 1109 ri: ResultInfo, 1110 node: Ast.Node.Index, 1111 ) InnerError!Zir.Inst.Ref { 1112 const astgen = gz.astgen; 1113 const tree = astgen.tree; 1114 const node_datas = tree.nodes.items(.data); 1115 const body_node = node_datas[node].lhs; 1116 assert(body_node != 0); 1117 if (gz.nosuspend_node != 0) { 1118 try astgen.appendErrorNodeNotes(node, "redundant nosuspend block", .{}, &[_]u32{ 1119 try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}), 1120 }); 1121 } 1122 gz.nosuspend_node = node; 1123 defer gz.nosuspend_node = 0; 1124 return expr(gz, scope, ri, body_node); 1125 } 1126 1127 fn suspendExpr( 1128 gz: *GenZir, 1129 scope: *Scope, 1130 node: Ast.Node.Index, 1131 ) InnerError!Zir.Inst.Ref { 1132 const astgen = gz.astgen; 1133 const gpa = astgen.gpa; 1134 const tree = astgen.tree; 1135 const node_datas = tree.nodes.items(.data); 1136 const body_node = node_datas[node].lhs; 1137 1138 if (gz.nosuspend_node != 0) { 1139 return astgen.failNodeNotes(node, "suspend inside nosuspend block", .{}, &[_]u32{ 1140 try astgen.errNoteNode(gz.nosuspend_node, "nosuspend block here", .{}), 1141 }); 1142 } 1143 if (gz.suspend_node != 0) { 1144 return astgen.failNodeNotes(node, "cannot suspend inside suspend block", .{}, &[_]u32{ 1145 try astgen.errNoteNode(gz.suspend_node, "other suspend block here", .{}), 1146 }); 1147 } 1148 assert(body_node != 0); 1149 1150 const suspend_inst = try gz.makeBlockInst(.suspend_block, node); 1151 try gz.instructions.append(gpa, suspend_inst); 1152 1153 var suspend_scope = gz.makeSubBlock(scope); 1154 suspend_scope.suspend_node = node; 1155 defer suspend_scope.unstack(); 1156 1157 const body_result = try expr(&suspend_scope, &suspend_scope.base, .{ .rl = .none }, body_node); 1158 if (!gz.refIsNoReturn(body_result)) { 1159 _ = try suspend_scope.addBreak(.break_inline, suspend_inst, .void_value); 1160 } 1161 try suspend_scope.setBlockBody(suspend_inst); 1162 1163 return indexToRef(suspend_inst); 1164 } 1165 1166 fn awaitExpr( 1167 gz: *GenZir, 1168 scope: *Scope, 1169 ri: ResultInfo, 1170 node: Ast.Node.Index, 1171 ) InnerError!Zir.Inst.Ref { 1172 const astgen = gz.astgen; 1173 const tree = astgen.tree; 1174 const node_datas = tree.nodes.items(.data); 1175 const rhs_node = node_datas[node].lhs; 1176 1177 if (gz.suspend_node != 0) { 1178 return astgen.failNodeNotes(node, "cannot await inside suspend block", .{}, &[_]u32{ 1179 try astgen.errNoteNode(gz.suspend_node, "suspend block here", .{}), 1180 }); 1181 } 1182 const operand = try expr(gz, scope, .{ .rl = .none }, rhs_node); 1183 const result = if (gz.nosuspend_node != 0) 1184 try gz.addExtendedPayload(.await_nosuspend, Zir.Inst.UnNode{ 1185 .node = gz.nodeIndexToRelative(node), 1186 .operand = operand, 1187 }) 1188 else 1189 try gz.addUnNode(.@"await", operand, node); 1190 1191 return rvalue(gz, ri, result, node); 1192 } 1193 1194 fn resumeExpr( 1195 gz: *GenZir, 1196 scope: *Scope, 1197 ri: ResultInfo, 1198 node: Ast.Node.Index, 1199 ) InnerError!Zir.Inst.Ref { 1200 const astgen = gz.astgen; 1201 const tree = astgen.tree; 1202 const node_datas = tree.nodes.items(.data); 1203 const rhs_node = node_datas[node].lhs; 1204 const operand = try expr(gz, scope, .{ .rl = .none }, rhs_node); 1205 const result = try gz.addUnNode(.@"resume", operand, node); 1206 return rvalue(gz, ri, result, node); 1207 } 1208 1209 fn fnProtoExpr( 1210 gz: *GenZir, 1211 scope: *Scope, 1212 ri: ResultInfo, 1213 node: Ast.Node.Index, 1214 fn_proto: Ast.full.FnProto, 1215 ) InnerError!Zir.Inst.Ref { 1216 const astgen = gz.astgen; 1217 const tree = astgen.tree; 1218 const token_tags = tree.tokens.items(.tag); 1219 1220 if (fn_proto.name_token) |some| { 1221 return astgen.failTok(some, "function type cannot have a name", .{}); 1222 } 1223 1224 const is_extern = blk: { 1225 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; 1226 break :blk token_tags[maybe_extern_token] == .keyword_extern; 1227 }; 1228 assert(!is_extern); 1229 1230 var block_scope = gz.makeSubBlock(scope); 1231 defer block_scope.unstack(); 1232 1233 const block_inst = try gz.makeBlockInst(.block_inline, node); 1234 1235 var noalias_bits: u32 = 0; 1236 const is_var_args = is_var_args: { 1237 var param_type_i: usize = 0; 1238 var it = fn_proto.iterate(tree); 1239 while (it.next()) |param| : (param_type_i += 1) { 1240 const is_comptime = if (param.comptime_noalias) |token| switch (token_tags[token]) { 1241 .keyword_noalias => is_comptime: { 1242 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse 1243 return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); 1244 break :is_comptime false; 1245 }, 1246 .keyword_comptime => true, 1247 else => false, 1248 } else false; 1249 1250 const is_anytype = if (param.anytype_ellipsis3) |token| blk: { 1251 switch (token_tags[token]) { 1252 .keyword_anytype => break :blk true, 1253 .ellipsis3 => break :is_var_args true, 1254 else => unreachable, 1255 } 1256 } else false; 1257 1258 const param_name: u32 = if (param.name_token) |name_token| blk: { 1259 if (mem.eql(u8, "_", tree.tokenSlice(name_token))) 1260 break :blk 0; 1261 1262 break :blk try astgen.identAsString(name_token); 1263 } else 0; 1264 1265 if (is_anytype) { 1266 const name_token = param.name_token orelse param.anytype_ellipsis3.?; 1267 1268 const tag: Zir.Inst.Tag = if (is_comptime) 1269 .param_anytype_comptime 1270 else 1271 .param_anytype; 1272 _ = try block_scope.addStrTok(tag, param_name, name_token); 1273 } else { 1274 const param_type_node = param.type_expr; 1275 assert(param_type_node != 0); 1276 var param_gz = block_scope.makeSubBlock(scope); 1277 defer param_gz.unstack(); 1278 const param_type = try expr(¶m_gz, scope, coerced_type_ri, param_type_node); 1279 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); 1280 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); 1281 const main_tokens = tree.nodes.items(.main_token); 1282 const name_token = param.name_token orelse main_tokens[param_type_node]; 1283 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; 1284 const param_inst = try block_scope.addParam(¶m_gz, tag, name_token, param_name, param.first_doc_comment); 1285 assert(param_inst_expected == param_inst); 1286 } 1287 } 1288 break :is_var_args false; 1289 }; 1290 1291 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { 1292 break :inst try expr(&block_scope, scope, align_ri, fn_proto.ast.align_expr); 1293 }; 1294 1295 if (fn_proto.ast.addrspace_expr != 0) { 1296 return astgen.failNode(fn_proto.ast.addrspace_expr, "addrspace not allowed on function prototypes", .{}); 1297 } 1298 1299 if (fn_proto.ast.section_expr != 0) { 1300 return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); 1301 } 1302 1303 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) 1304 try expr( 1305 &block_scope, 1306 scope, 1307 .{ .rl = .{ .ty = .calling_convention_type } }, 1308 fn_proto.ast.callconv_expr, 1309 ) 1310 else 1311 Zir.Inst.Ref.none; 1312 1313 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; 1314 const is_inferred_error = token_tags[maybe_bang] == .bang; 1315 if (is_inferred_error) { 1316 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); 1317 } 1318 const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type); 1319 1320 const result = try block_scope.addFunc(.{ 1321 .src_node = fn_proto.ast.proto_node, 1322 1323 .cc_ref = cc, 1324 .cc_gz = null, 1325 .align_ref = align_ref, 1326 .align_gz = null, 1327 .ret_ref = ret_ty, 1328 .ret_gz = null, 1329 .section_ref = .none, 1330 .section_gz = null, 1331 .addrspace_ref = .none, 1332 .addrspace_gz = null, 1333 1334 .param_block = block_inst, 1335 .body_gz = null, 1336 .lib_name = 0, 1337 .is_var_args = is_var_args, 1338 .is_inferred_error = false, 1339 .is_test = false, 1340 .is_extern = false, 1341 .is_noinline = false, 1342 .noalias_bits = noalias_bits, 1343 }); 1344 1345 _ = try block_scope.addBreak(.break_inline, block_inst, result); 1346 try block_scope.setBlockBody(block_inst); 1347 try gz.instructions.append(astgen.gpa, block_inst); 1348 1349 return rvalue(gz, ri, indexToRef(block_inst), fn_proto.ast.proto_node); 1350 } 1351 1352 fn arrayInitExpr( 1353 gz: *GenZir, 1354 scope: *Scope, 1355 ri: ResultInfo, 1356 node: Ast.Node.Index, 1357 array_init: Ast.full.ArrayInit, 1358 ) InnerError!Zir.Inst.Ref { 1359 const astgen = gz.astgen; 1360 const tree = astgen.tree; 1361 const node_tags = tree.nodes.items(.tag); 1362 const main_tokens = tree.nodes.items(.main_token); 1363 1364 assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init. 1365 1366 const types: struct { 1367 array: Zir.Inst.Ref, 1368 elem: Zir.Inst.Ref, 1369 } = inst: { 1370 if (array_init.ast.type_expr == 0) break :inst .{ 1371 .array = .none, 1372 .elem = .none, 1373 }; 1374 1375 infer: { 1376 const array_type: Ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) { 1377 .array_type => tree.arrayType(array_init.ast.type_expr), 1378 .array_type_sentinel => tree.arrayTypeSentinel(array_init.ast.type_expr), 1379 else => break :infer, 1380 }; 1381 // This intentionally does not support `@"_"` syntax. 1382 if (node_tags[array_type.ast.elem_count] == .identifier and 1383 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_")) 1384 { 1385 const len_inst = try gz.addInt(array_init.ast.elements.len); 1386 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); 1387 if (array_type.ast.sentinel == 0) { 1388 const array_type_inst = try gz.addPlNode(.array_type, array_init.ast.type_expr, Zir.Inst.Bin{ 1389 .lhs = len_inst, 1390 .rhs = elem_type, 1391 }); 1392 break :inst .{ 1393 .array = array_type_inst, 1394 .elem = elem_type, 1395 }; 1396 } else { 1397 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, array_type.ast.sentinel); 1398 const array_type_inst = try gz.addPlNode( 1399 .array_type_sentinel, 1400 array_init.ast.type_expr, 1401 Zir.Inst.ArrayTypeSentinel{ 1402 .len = len_inst, 1403 .elem_type = elem_type, 1404 .sentinel = sentinel, 1405 }, 1406 ); 1407 break :inst .{ 1408 .array = array_type_inst, 1409 .elem = elem_type, 1410 }; 1411 } 1412 } 1413 } 1414 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); 1415 _ = try gz.addPlNode(.validate_array_init_ty, node, Zir.Inst.ArrayInit{ 1416 .ty = array_type_inst, 1417 .init_count = @intCast(u32, array_init.ast.elements.len), 1418 }); 1419 break :inst .{ 1420 .array = array_type_inst, 1421 .elem = .none, 1422 }; 1423 }; 1424 1425 switch (ri.rl) { 1426 .discard => { 1427 // TODO elements should still be coerced if type is provided 1428 for (array_init.ast.elements) |elem_init| { 1429 _ = try expr(gz, scope, .{ .rl = .discard }, elem_init); 1430 } 1431 return Zir.Inst.Ref.void_value; 1432 }, 1433 .ref => { 1434 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref; 1435 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1436 }, 1437 .none => { 1438 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; 1439 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1440 }, 1441 .ty, .coerced_ty => { 1442 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; 1443 const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); 1444 return rvalue(gz, ri, result, node); 1445 }, 1446 .ptr => |ptr_res| { 1447 return arrayInitExprRlPtr(gz, scope, ri, node, ptr_res.inst, array_init.ast.elements, types.array); 1448 }, 1449 .inferred_ptr => |ptr_inst| { 1450 if (types.array == .none) { 1451 // We treat this case differently so that we don't get a crash when 1452 // analyzing array_base_ptr against an alloc_inferred_mut. 1453 // See corresponding logic in structInitExpr. 1454 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); 1455 return rvalue(gz, ri, result, node); 1456 } else { 1457 return arrayInitExprRlPtr(gz, scope, ri, node, ptr_inst, array_init.ast.elements, types.array); 1458 } 1459 }, 1460 .block_ptr => |block_gz| { 1461 // This condition is here for the same reason as the above condition in `inferred_ptr`. 1462 // See corresponding logic in structInitExpr. 1463 if (types.array == .none and astgen.isInferred(block_gz.rl_ptr)) { 1464 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); 1465 return rvalue(gz, ri, result, node); 1466 } 1467 return arrayInitExprRlPtr(gz, scope, ri, node, block_gz.rl_ptr, array_init.ast.elements, types.array); 1468 }, 1469 } 1470 } 1471 1472 fn arrayInitExprRlNone( 1473 gz: *GenZir, 1474 scope: *Scope, 1475 node: Ast.Node.Index, 1476 elements: []const Ast.Node.Index, 1477 tag: Zir.Inst.Tag, 1478 ) InnerError!Zir.Inst.Ref { 1479 const astgen = gz.astgen; 1480 1481 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ 1482 .operands_len = @intCast(u32, elements.len), 1483 }); 1484 var extra_index = try reserveExtra(astgen, elements.len); 1485 1486 for (elements) |elem_init| { 1487 const elem_ref = try expr(gz, scope, .{ .rl = .none }, elem_init); 1488 astgen.extra.items[extra_index] = @enumToInt(elem_ref); 1489 extra_index += 1; 1490 } 1491 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1492 } 1493 1494 fn arrayInitExprInner( 1495 gz: *GenZir, 1496 scope: *Scope, 1497 node: Ast.Node.Index, 1498 elements: []const Ast.Node.Index, 1499 array_ty_inst: Zir.Inst.Ref, 1500 elem_ty: Zir.Inst.Ref, 1501 tag: Zir.Inst.Tag, 1502 ) InnerError!Zir.Inst.Ref { 1503 const astgen = gz.astgen; 1504 1505 const len = elements.len + @boolToInt(array_ty_inst != .none); 1506 const payload_index = try addExtra(astgen, Zir.Inst.MultiOp{ 1507 .operands_len = @intCast(u32, len), 1508 }); 1509 var extra_index = try reserveExtra(astgen, len); 1510 if (array_ty_inst != .none) { 1511 astgen.extra.items[extra_index] = @enumToInt(array_ty_inst); 1512 extra_index += 1; 1513 } 1514 1515 for (elements) |elem_init, i| { 1516 const ri = if (elem_ty != .none) 1517 ResultInfo{ .rl = .{ .coerced_ty = elem_ty } } 1518 else if (array_ty_inst != .none and nodeMayNeedMemoryLocation(astgen.tree, elem_init, true)) ri: { 1519 const ty_expr = try gz.add(.{ 1520 .tag = .elem_type_index, 1521 .data = .{ .bin = .{ 1522 .lhs = array_ty_inst, 1523 .rhs = @intToEnum(Zir.Inst.Ref, i), 1524 } }, 1525 }); 1526 break :ri ResultInfo{ .rl = .{ .coerced_ty = ty_expr } }; 1527 } else ResultInfo{ .rl = .{ .none = {} } }; 1528 1529 const elem_ref = try expr(gz, scope, ri, elem_init); 1530 astgen.extra.items[extra_index] = @enumToInt(elem_ref); 1531 extra_index += 1; 1532 } 1533 1534 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1535 } 1536 1537 fn arrayInitExprRlPtr( 1538 gz: *GenZir, 1539 scope: *Scope, 1540 ri: ResultInfo, 1541 node: Ast.Node.Index, 1542 result_ptr: Zir.Inst.Ref, 1543 elements: []const Ast.Node.Index, 1544 array_ty: Zir.Inst.Ref, 1545 ) InnerError!Zir.Inst.Ref { 1546 if (array_ty == .none) { 1547 const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node); 1548 return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements); 1549 } 1550 1551 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr, node); 1552 defer as_scope.unstack(); 1553 1554 const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements); 1555 return as_scope.finishCoercion(gz, ri, node, result, array_ty); 1556 } 1557 1558 fn arrayInitExprRlPtrInner( 1559 gz: *GenZir, 1560 scope: *Scope, 1561 node: Ast.Node.Index, 1562 result_ptr: Zir.Inst.Ref, 1563 elements: []const Ast.Node.Index, 1564 ) InnerError!Zir.Inst.Ref { 1565 const astgen = gz.astgen; 1566 1567 const payload_index = try addExtra(astgen, Zir.Inst.Block{ 1568 .body_len = @intCast(u32, elements.len), 1569 }); 1570 var extra_index = try reserveExtra(astgen, elements.len); 1571 1572 for (elements) |elem_init, i| { 1573 const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{ 1574 .ptr = result_ptr, 1575 .index = @intCast(u32, i), 1576 }); 1577 astgen.extra.items[extra_index] = refToIndex(elem_ptr).?; 1578 extra_index += 1; 1579 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = elem_ptr } } }, elem_init); 1580 } 1581 1582 const tag: Zir.Inst.Tag = if (gz.force_comptime) 1583 .validate_array_init_comptime 1584 else 1585 .validate_array_init; 1586 1587 _ = try gz.addPlNodePayloadIndex(tag, node, payload_index); 1588 return .void_value; 1589 } 1590 1591 fn structInitExpr( 1592 gz: *GenZir, 1593 scope: *Scope, 1594 ri: ResultInfo, 1595 node: Ast.Node.Index, 1596 struct_init: Ast.full.StructInit, 1597 ) InnerError!Zir.Inst.Ref { 1598 const astgen = gz.astgen; 1599 const tree = astgen.tree; 1600 1601 if (struct_init.ast.type_expr == 0) { 1602 if (struct_init.ast.fields.len == 0) { 1603 return rvalue(gz, ri, .empty_struct, node); 1604 } 1605 } else array: { 1606 const node_tags = tree.nodes.items(.tag); 1607 const main_tokens = tree.nodes.items(.main_token); 1608 const array_type: Ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { 1609 .array_type => tree.arrayType(struct_init.ast.type_expr), 1610 .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), 1611 else => { 1612 if (struct_init.ast.fields.len == 0) { 1613 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1614 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); 1615 return rvalue(gz, ri, result, node); 1616 } 1617 break :array; 1618 }, 1619 }; 1620 const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and 1621 // This intentionally does not support `@"_"` syntax. 1622 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_"); 1623 if (struct_init.ast.fields.len == 0) { 1624 if (is_inferred_array_len) { 1625 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); 1626 const array_type_inst = if (array_type.ast.sentinel == 0) blk: { 1627 break :blk try gz.addPlNode(.array_type, struct_init.ast.type_expr, Zir.Inst.Bin{ 1628 .lhs = .zero_usize, 1629 .rhs = elem_type, 1630 }); 1631 } else blk: { 1632 const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, array_type.ast.sentinel); 1633 break :blk try gz.addPlNode( 1634 .array_type_sentinel, 1635 struct_init.ast.type_expr, 1636 Zir.Inst.ArrayTypeSentinel{ 1637 .len = .zero_usize, 1638 .elem_type = elem_type, 1639 .sentinel = sentinel, 1640 }, 1641 ); 1642 }; 1643 const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node); 1644 return rvalue(gz, ri, result, node); 1645 } 1646 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1647 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); 1648 return rvalue(gz, ri, result, node); 1649 } else { 1650 return astgen.failNode( 1651 struct_init.ast.type_expr, 1652 "initializing array with struct syntax", 1653 .{}, 1654 ); 1655 } 1656 } 1657 1658 switch (ri.rl) { 1659 .discard => { 1660 if (struct_init.ast.type_expr != 0) { 1661 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1662 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1663 _ = try structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); 1664 } else { 1665 _ = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1666 } 1667 return Zir.Inst.Ref.void_value; 1668 }, 1669 .ref => { 1670 if (struct_init.ast.type_expr != 0) { 1671 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1672 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1673 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); 1674 } else { 1675 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref); 1676 } 1677 }, 1678 .none => { 1679 if (struct_init.ast.type_expr != 0) { 1680 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1681 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1682 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); 1683 } else { 1684 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1685 } 1686 }, 1687 .ty, .coerced_ty => |ty_inst| { 1688 if (struct_init.ast.type_expr == 0) { 1689 const result = try structInitExprRlNone(gz, scope, node, struct_init, ty_inst, .struct_init_anon); 1690 return rvalue(gz, ri, result, node); 1691 } 1692 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1693 _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node); 1694 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init); 1695 return rvalue(gz, ri, result, node); 1696 }, 1697 .ptr => |ptr_res| return structInitExprRlPtr(gz, scope, ri, node, struct_init, ptr_res.inst), 1698 .inferred_ptr => |ptr_inst| { 1699 if (struct_init.ast.type_expr == 0) { 1700 // We treat this case differently so that we don't get a crash when 1701 // analyzing field_base_ptr against an alloc_inferred_mut. 1702 // See corresponding logic in arrayInitExpr. 1703 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1704 return rvalue(gz, ri, result, node); 1705 } else { 1706 return structInitExprRlPtr(gz, scope, ri, node, struct_init, ptr_inst); 1707 } 1708 }, 1709 .block_ptr => |block_gz| { 1710 // This condition is here for the same reason as the above condition in `inferred_ptr`. 1711 // See corresponding logic in arrayInitExpr. 1712 if (struct_init.ast.type_expr == 0 and astgen.isInferred(block_gz.rl_ptr)) { 1713 const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); 1714 return rvalue(gz, ri, result, node); 1715 } 1716 1717 return structInitExprRlPtr(gz, scope, ri, node, struct_init, block_gz.rl_ptr); 1718 }, 1719 } 1720 } 1721 1722 fn structInitExprRlNone( 1723 gz: *GenZir, 1724 scope: *Scope, 1725 node: Ast.Node.Index, 1726 struct_init: Ast.full.StructInit, 1727 ty_inst: Zir.Inst.Ref, 1728 tag: Zir.Inst.Tag, 1729 ) InnerError!Zir.Inst.Ref { 1730 const astgen = gz.astgen; 1731 const tree = astgen.tree; 1732 1733 const payload_index = try addExtra(astgen, Zir.Inst.StructInitAnon{ 1734 .fields_len = @intCast(u32, struct_init.ast.fields.len), 1735 }); 1736 const field_size = @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len; 1737 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size); 1738 1739 for (struct_init.ast.fields) |field_init| { 1740 const name_token = tree.firstToken(field_init) - 2; 1741 const str_index = try astgen.identAsString(name_token); 1742 const sub_ri: ResultInfo = if (ty_inst != .none) 1743 ResultInfo{ .rl = .{ .ty = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ 1744 .container_type = ty_inst, 1745 .name_start = str_index, 1746 }) } } 1747 else .{ .rl = .none }; 1748 setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{ 1749 .field_name = str_index, 1750 .init = try expr(gz, scope, sub_ri, field_init), 1751 }); 1752 extra_index += field_size; 1753 } 1754 1755 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1756 } 1757 1758 fn structInitExprRlPtr( 1759 gz: *GenZir, 1760 scope: *Scope, 1761 ri: ResultInfo, 1762 node: Ast.Node.Index, 1763 struct_init: Ast.full.StructInit, 1764 result_ptr: Zir.Inst.Ref, 1765 ) InnerError!Zir.Inst.Ref { 1766 if (struct_init.ast.type_expr == 0) { 1767 const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node); 1768 return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr); 1769 } 1770 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1771 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); 1772 1773 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr, node); 1774 defer as_scope.unstack(); 1775 1776 const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr); 1777 return as_scope.finishCoercion(gz, ri, node, result, ty_inst); 1778 } 1779 1780 fn structInitExprRlPtrInner( 1781 gz: *GenZir, 1782 scope: *Scope, 1783 node: Ast.Node.Index, 1784 struct_init: Ast.full.StructInit, 1785 result_ptr: Zir.Inst.Ref, 1786 ) InnerError!Zir.Inst.Ref { 1787 const astgen = gz.astgen; 1788 const tree = astgen.tree; 1789 1790 const payload_index = try addExtra(astgen, Zir.Inst.Block{ 1791 .body_len = @intCast(u32, struct_init.ast.fields.len), 1792 }); 1793 var extra_index = try reserveExtra(astgen, struct_init.ast.fields.len); 1794 1795 for (struct_init.ast.fields) |field_init| { 1796 const name_token = tree.firstToken(field_init) - 2; 1797 const str_index = try astgen.identAsString(name_token); 1798 const field_ptr = try gz.addPlNode(.field_ptr_init, field_init, Zir.Inst.Field{ 1799 .lhs = result_ptr, 1800 .field_name_start = str_index, 1801 }); 1802 astgen.extra.items[extra_index] = refToIndex(field_ptr).?; 1803 extra_index += 1; 1804 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ .inst = field_ptr } } }, field_init); 1805 } 1806 1807 const tag: Zir.Inst.Tag = if (gz.force_comptime) 1808 .validate_struct_init_comptime 1809 else 1810 .validate_struct_init; 1811 1812 _ = try gz.addPlNodePayloadIndex(tag, node, payload_index); 1813 return Zir.Inst.Ref.void_value; 1814 } 1815 1816 fn structInitExprRlTy( 1817 gz: *GenZir, 1818 scope: *Scope, 1819 node: Ast.Node.Index, 1820 struct_init: Ast.full.StructInit, 1821 ty_inst: Zir.Inst.Ref, 1822 tag: Zir.Inst.Tag, 1823 ) InnerError!Zir.Inst.Ref { 1824 const astgen = gz.astgen; 1825 const tree = astgen.tree; 1826 1827 const payload_index = try addExtra(astgen, Zir.Inst.StructInit{ 1828 .fields_len = @intCast(u32, struct_init.ast.fields.len), 1829 }); 1830 const field_size = @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len; 1831 var extra_index: usize = try reserveExtra(astgen, struct_init.ast.fields.len * field_size); 1832 1833 for (struct_init.ast.fields) |field_init| { 1834 const name_token = tree.firstToken(field_init) - 2; 1835 const str_index = try astgen.identAsString(name_token); 1836 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ 1837 .container_type = ty_inst, 1838 .name_start = str_index, 1839 }); 1840 setExtra(astgen, extra_index, Zir.Inst.StructInit.Item{ 1841 .field_type = refToIndex(field_ty_inst).?, 1842 .init = try expr(gz, scope, .{ .rl = .{ .ty = field_ty_inst } }, field_init), 1843 }); 1844 extra_index += field_size; 1845 } 1846 1847 return try gz.addPlNodePayloadIndex(tag, node, payload_index); 1848 } 1849 1850 /// This calls expr in a comptime scope, and is intended to be called as a helper function. 1851 /// The one that corresponds to `comptime` expression syntax is `comptimeExprAst`. 1852 fn comptimeExpr( 1853 gz: *GenZir, 1854 scope: *Scope, 1855 ri: ResultInfo, 1856 node: Ast.Node.Index, 1857 ) InnerError!Zir.Inst.Ref { 1858 const prev_force_comptime = gz.force_comptime; 1859 gz.force_comptime = true; 1860 defer gz.force_comptime = prev_force_comptime; 1861 1862 return expr(gz, scope, ri, node); 1863 } 1864 1865 /// This one is for an actual `comptime` syntax, and will emit a compile error if 1866 /// the scope already has `force_comptime=true`. 1867 /// See `comptimeExpr` for the helper function for calling expr in a comptime scope. 1868 fn comptimeExprAst( 1869 gz: *GenZir, 1870 scope: *Scope, 1871 ri: ResultInfo, 1872 node: Ast.Node.Index, 1873 ) InnerError!Zir.Inst.Ref { 1874 const astgen = gz.astgen; 1875 if (gz.force_comptime) { 1876 return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); 1877 } 1878 const tree = astgen.tree; 1879 const node_datas = tree.nodes.items(.data); 1880 const body_node = node_datas[node].lhs; 1881 gz.force_comptime = true; 1882 const result = try expr(gz, scope, ri, body_node); 1883 gz.force_comptime = false; 1884 return result; 1885 } 1886 1887 /// Restore the error return trace index. Performs the restore only if the result is a non-error or 1888 /// if the result location is a non-error-handling expression. 1889 fn restoreErrRetIndex( 1890 gz: *GenZir, 1891 bt: GenZir.BranchTarget, 1892 ri: ResultInfo, 1893 node: Ast.Node.Index, 1894 result: Zir.Inst.Ref, 1895 ) !void { 1896 const op = switch (nodeMayEvalToError(gz.astgen.tree, node)) { 1897 .always => return, // never restore/pop 1898 .never => .none, // always restore/pop 1899 .maybe => switch (ri.ctx) { 1900 .error_handling_expr, .@"return", .fn_arg, .const_init => switch (ri.rl) { 1901 .ptr => |ptr_res| try gz.addUnNode(.load, ptr_res.inst, node), 1902 .inferred_ptr => |ptr| try gz.addUnNode(.load, ptr, node), 1903 .block_ptr => |block_scope| if (block_scope.rvalue_rl_count != block_scope.break_count) b: { 1904 // The result location may have been used by this expression, in which case 1905 // the operand is not the result and we need to load the rl ptr. 1906 switch (gz.astgen.instructions.items(.tag)[Zir.refToIndex(block_scope.rl_ptr).?]) { 1907 .alloc_inferred, .alloc_inferred_mut => { 1908 // This is a terrible workaround for Sema's inability to load from a .alloc_inferred ptr 1909 // before its type has been resolved. The operand we use here instead is not guaranteed 1910 // to be valid, and when it's not, we will pop error traces prematurely. 1911 // 1912 // TODO: Update this to do a proper load from the rl_ptr, once Sema can support it. 1913 break :b result; 1914 }, 1915 else => break :b try gz.addUnNode(.load, block_scope.rl_ptr, node), 1916 } 1917 } else result, 1918 else => result, 1919 }, 1920 else => .none, // always restore/pop 1921 }, 1922 }; 1923 _ = try gz.addRestoreErrRetIndex(bt, .{ .if_non_error = op }); 1924 } 1925 1926 fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 1927 const astgen = parent_gz.astgen; 1928 const tree = astgen.tree; 1929 const node_datas = tree.nodes.items(.data); 1930 const break_label = node_datas[node].lhs; 1931 const rhs = node_datas[node].rhs; 1932 1933 // Look for the label in the scope. 1934 var scope = parent_scope; 1935 while (true) { 1936 switch (scope.tag) { 1937 .gen_zir => { 1938 const block_gz = scope.cast(GenZir).?; 1939 1940 if (block_gz.cur_defer_node != 0) { 1941 // We are breaking out of a `defer` block. 1942 return astgen.failNodeNotes(node, "cannot break out of defer expression", .{}, &.{ 1943 try astgen.errNoteNode( 1944 block_gz.cur_defer_node, 1945 "defer expression here", 1946 .{}, 1947 ), 1948 }); 1949 } 1950 1951 const block_inst = blk: { 1952 if (break_label != 0) { 1953 if (block_gz.label) |*label| { 1954 if (try astgen.tokenIdentEql(label.token, break_label)) { 1955 label.used = true; 1956 break :blk label.block_inst; 1957 } 1958 } 1959 } else if (block_gz.break_block != 0) { 1960 break :blk block_gz.break_block; 1961 } 1962 // If not the target, start over with the parent 1963 scope = block_gz.parent; 1964 continue; 1965 }; 1966 // If we made it here, this block is the target of the break expr 1967 1968 const break_tag: Zir.Inst.Tag = if (block_gz.is_inline or block_gz.force_comptime) 1969 .break_inline 1970 else 1971 .@"break"; 1972 1973 if (rhs == 0) { 1974 try genDefers(parent_gz, scope, parent_scope, .normal_only); 1975 1976 // As our last action before the break, "pop" the error trace if needed 1977 if (!block_gz.force_comptime) 1978 _ = try parent_gz.addRestoreErrRetIndex(.{ .block = block_inst }, .always); 1979 1980 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 1981 return Zir.Inst.Ref.unreachable_value; 1982 } 1983 block_gz.break_count += 1; 1984 1985 const operand = try reachableExpr(parent_gz, parent_scope, block_gz.break_result_info, rhs, node); 1986 const search_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 1987 1988 try genDefers(parent_gz, scope, parent_scope, .normal_only); 1989 1990 // As our last action before the break, "pop" the error trace if needed 1991 if (!block_gz.force_comptime) 1992 try restoreErrRetIndex(parent_gz, .{ .block = block_inst }, block_gz.break_result_info, rhs, operand); 1993 1994 switch (block_gz.break_result_info.rl) { 1995 .block_ptr => { 1996 const br = try parent_gz.addBreak(break_tag, block_inst, operand); 1997 try block_gz.labeled_breaks.append(astgen.gpa, .{ .br = br, .search = search_index }); 1998 }, 1999 .ptr => { 2000 // In this case we don't have any mechanism to intercept it; 2001 // we assume the result location is written, and we break with void. 2002 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 2003 }, 2004 .discard => { 2005 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); 2006 }, 2007 else => { 2008 _ = try parent_gz.addBreak(break_tag, block_inst, operand); 2009 }, 2010 } 2011 return Zir.Inst.Ref.unreachable_value; 2012 }, 2013 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2014 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2015 .namespace => break, 2016 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2017 .top => unreachable, 2018 } 2019 } 2020 if (break_label != 0) { 2021 const label_name = try astgen.identifierTokenString(break_label); 2022 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 2023 } else { 2024 return astgen.failNode(node, "break expression outside loop", .{}); 2025 } 2026 } 2027 2028 fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 2029 const astgen = parent_gz.astgen; 2030 const tree = astgen.tree; 2031 const node_datas = tree.nodes.items(.data); 2032 const break_label = node_datas[node].lhs; 2033 2034 // Look for the label in the scope. 2035 var scope = parent_scope; 2036 while (true) { 2037 switch (scope.tag) { 2038 .gen_zir => { 2039 const gen_zir = scope.cast(GenZir).?; 2040 2041 if (gen_zir.cur_defer_node != 0) { 2042 return astgen.failNodeNotes(node, "cannot continue out of defer expression", .{}, &.{ 2043 try astgen.errNoteNode( 2044 gen_zir.cur_defer_node, 2045 "defer expression here", 2046 .{}, 2047 ), 2048 }); 2049 } 2050 const continue_block = gen_zir.continue_block; 2051 if (continue_block == 0) { 2052 scope = gen_zir.parent; 2053 continue; 2054 } 2055 if (break_label != 0) blk: { 2056 if (gen_zir.label) |*label| { 2057 if (try astgen.tokenIdentEql(label.token, break_label)) { 2058 label.used = true; 2059 break :blk; 2060 } 2061 } 2062 // found continue but either it has a different label, or no label 2063 scope = gen_zir.parent; 2064 continue; 2065 } 2066 2067 const break_tag: Zir.Inst.Tag = if (gen_zir.is_inline or gen_zir.force_comptime) 2068 .break_inline 2069 else 2070 .@"break"; 2071 if (break_tag == .break_inline) { 2072 _ = try parent_gz.addUnNode(.check_comptime_control_flow, Zir.indexToRef(continue_block), node); 2073 } 2074 2075 // As our last action before the continue, "pop" the error trace if needed 2076 if (!gen_zir.force_comptime) 2077 _ = try parent_gz.addRestoreErrRetIndex(.{ .block = continue_block }, .always); 2078 2079 _ = try parent_gz.addBreak(break_tag, continue_block, .void_value); 2080 return Zir.Inst.Ref.unreachable_value; 2081 }, 2082 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2083 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2084 .defer_normal => { 2085 const defer_scope = scope.cast(Scope.Defer).?; 2086 scope = defer_scope.parent; 2087 try parent_gz.addDefer(defer_scope.index, defer_scope.len); 2088 }, 2089 .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2090 .namespace => break, 2091 .top => unreachable, 2092 } 2093 } 2094 if (break_label != 0) { 2095 const label_name = try astgen.identifierTokenString(break_label); 2096 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 2097 } else { 2098 return astgen.failNode(node, "continue expression outside loop", .{}); 2099 } 2100 } 2101 2102 fn blockExpr( 2103 gz: *GenZir, 2104 scope: *Scope, 2105 ri: ResultInfo, 2106 block_node: Ast.Node.Index, 2107 statements: []const Ast.Node.Index, 2108 ) InnerError!Zir.Inst.Ref { 2109 const tracy = trace(@src()); 2110 defer tracy.end(); 2111 2112 const astgen = gz.astgen; 2113 const tree = astgen.tree; 2114 const main_tokens = tree.nodes.items(.main_token); 2115 const token_tags = tree.tokens.items(.tag); 2116 2117 const lbrace = main_tokens[block_node]; 2118 if (token_tags[lbrace - 1] == .colon and 2119 token_tags[lbrace - 2] == .identifier) 2120 { 2121 return labeledBlockExpr(gz, scope, ri, block_node, statements); 2122 } 2123 2124 if (!gz.force_comptime) { 2125 // Since this block is unlabeled, its control flow is effectively linear and we 2126 // can *almost* get away with inlining the block here. However, we actually need 2127 // to preserve the .block for Sema, to properly pop the error return trace. 2128 2129 const block_tag: Zir.Inst.Tag = .block; 2130 const block_inst = try gz.makeBlockInst(block_tag, block_node); 2131 try gz.instructions.append(astgen.gpa, block_inst); 2132 2133 var block_scope = gz.makeSubBlock(scope); 2134 defer block_scope.unstack(); 2135 2136 try blockExprStmts(&block_scope, &block_scope.base, statements); 2137 2138 if (!block_scope.endsWithNoReturn()) { 2139 // As our last action before the break, "pop" the error trace if needed 2140 _ = try gz.addRestoreErrRetIndex(.{ .block = block_inst }, .always); 2141 2142 const break_tag: Zir.Inst.Tag = if (block_scope.force_comptime) .break_inline else .@"break"; 2143 _ = try block_scope.addBreak(break_tag, block_inst, .void_value); 2144 } 2145 2146 try block_scope.setBlockBody(block_inst); 2147 } else { 2148 var sub_gz = gz.makeSubBlock(scope); 2149 try blockExprStmts(&sub_gz, &sub_gz.base, statements); 2150 } 2151 2152 return rvalue(gz, ri, .void_value, block_node); 2153 } 2154 2155 fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.TokenIndex) !void { 2156 // Look for the label in the scope. 2157 var scope = parent_scope; 2158 while (true) { 2159 switch (scope.tag) { 2160 .gen_zir => { 2161 const gen_zir = scope.cast(GenZir).?; 2162 if (gen_zir.label) |prev_label| { 2163 if (try astgen.tokenIdentEql(label, prev_label.token)) { 2164 const label_name = try astgen.identifierTokenString(label); 2165 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{ 2166 label_name, 2167 }, &[_]u32{ 2168 try astgen.errNoteTok( 2169 prev_label.token, 2170 "previous definition here", 2171 .{}, 2172 ), 2173 }); 2174 } 2175 } 2176 scope = gen_zir.parent; 2177 }, 2178 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2179 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2180 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2181 .namespace => break, 2182 .top => unreachable, 2183 } 2184 } 2185 } 2186 2187 fn labeledBlockExpr( 2188 gz: *GenZir, 2189 parent_scope: *Scope, 2190 ri: ResultInfo, 2191 block_node: Ast.Node.Index, 2192 statements: []const Ast.Node.Index, 2193 ) InnerError!Zir.Inst.Ref { 2194 const tracy = trace(@src()); 2195 defer tracy.end(); 2196 2197 const astgen = gz.astgen; 2198 const tree = astgen.tree; 2199 const main_tokens = tree.nodes.items(.main_token); 2200 const token_tags = tree.tokens.items(.tag); 2201 2202 const lbrace = main_tokens[block_node]; 2203 const label_token = lbrace - 2; 2204 assert(token_tags[label_token] == .identifier); 2205 2206 try astgen.checkLabelRedefinition(parent_scope, label_token); 2207 2208 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct 2209 // so that break statements can reference it. 2210 const block_tag: Zir.Inst.Tag = if (gz.force_comptime) .block_inline else .block; 2211 const block_inst = try gz.makeBlockInst(block_tag, block_node); 2212 try gz.instructions.append(astgen.gpa, block_inst); 2213 2214 var block_scope = gz.makeSubBlock(parent_scope); 2215 block_scope.label = GenZir.Label{ 2216 .token = label_token, 2217 .block_inst = block_inst, 2218 }; 2219 block_scope.setBreakResultInfo(ri); 2220 defer block_scope.unstack(); 2221 defer block_scope.labeled_breaks.deinit(astgen.gpa); 2222 2223 try blockExprStmts(&block_scope, &block_scope.base, statements); 2224 if (!block_scope.endsWithNoReturn()) { 2225 // As our last action before the return, "pop" the error trace if needed 2226 _ = try gz.addRestoreErrRetIndex(.{ .block = block_inst }, .always); 2227 2228 const break_tag: Zir.Inst.Tag = if (block_scope.force_comptime) .break_inline else .@"break"; 2229 _ = try block_scope.addBreak(break_tag, block_inst, .void_value); 2230 } 2231 2232 if (!block_scope.label.?.used) { 2233 try astgen.appendErrorTok(label_token, "unused block label", .{}); 2234 } 2235 2236 const zir_datas = gz.astgen.instructions.items(.data); 2237 const zir_tags = gz.astgen.instructions.items(.tag); 2238 const strat = ri.rl.strategy(&block_scope); 2239 switch (strat.tag) { 2240 .break_void => { 2241 // The code took advantage of the result location as a pointer. 2242 // Turn the break instruction operands into void. 2243 for (block_scope.labeled_breaks.items) |br| { 2244 zir_datas[br.br].@"break".operand = .void_value; 2245 } 2246 try block_scope.setBlockBody(block_inst); 2247 2248 return indexToRef(block_inst); 2249 }, 2250 .break_operand => { 2251 // All break operands are values that did not use the result location pointer 2252 // (except for a single .store_to_block_ptr inst which we re-write here). 2253 // The break instructions need to have their operands coerced if the 2254 // block's result location is a `ty`. In this case we overwrite the 2255 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 2256 // it as the break operand. 2257 // This corresponds to similar code in `setCondBrPayloadElideBlockStorePtr`. 2258 if (block_scope.rl_ty_inst != .none) { 2259 for (block_scope.labeled_breaks.items) |br| { 2260 // We expect the `store_to_block_ptr` to be created between 1-3 instructions 2261 // prior to the break. 2262 var search_index = br.search -| 3; 2263 while (search_index < br.search) : (search_index += 1) { 2264 if (zir_tags[search_index] == .store_to_block_ptr and 2265 zir_datas[search_index].bin.lhs == block_scope.rl_ptr) 2266 { 2267 zir_tags[search_index] = .as; 2268 zir_datas[search_index].bin = .{ 2269 .lhs = block_scope.rl_ty_inst, 2270 .rhs = zir_datas[br.br].@"break".operand, 2271 }; 2272 zir_datas[br.br].@"break".operand = indexToRef(search_index); 2273 break; 2274 } 2275 } else unreachable; 2276 } 2277 } 2278 try block_scope.setBlockBody(block_inst); 2279 const block_ref = indexToRef(block_inst); 2280 switch (ri.rl) { 2281 .ref => return block_ref, 2282 else => return rvalue(gz, ri, block_ref, block_node), 2283 } 2284 }, 2285 } 2286 } 2287 2288 fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Node.Index) !void { 2289 const astgen = gz.astgen; 2290 const tree = astgen.tree; 2291 const node_tags = tree.nodes.items(.tag); 2292 const node_data = tree.nodes.items(.data); 2293 2294 if (statements.len == 0) return; 2295 2296 try gz.addDbgBlockBegin(); 2297 2298 var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa); 2299 defer block_arena.deinit(); 2300 const block_arena_allocator = block_arena.allocator(); 2301 2302 var noreturn_src_node: Ast.Node.Index = 0; 2303 var scope = parent_scope; 2304 for (statements) |statement| { 2305 if (noreturn_src_node != 0) { 2306 try astgen.appendErrorNodeNotes( 2307 statement, 2308 "unreachable code", 2309 .{}, 2310 &[_]u32{ 2311 try astgen.errNoteNode( 2312 noreturn_src_node, 2313 "control flow is diverted here", 2314 .{}, 2315 ), 2316 }, 2317 ); 2318 } 2319 var inner_node = statement; 2320 while (true) { 2321 switch (node_tags[inner_node]) { 2322 // zig fmt: off 2323 .global_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.globalVarDecl(statement)), 2324 .local_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.localVarDecl(statement)), 2325 .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)), 2326 .aligned_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.alignedVarDecl(statement)), 2327 2328 .@"defer" => scope = try deferStmt(gz, scope, statement, block_arena_allocator, .defer_normal), 2329 .@"errdefer" => scope = try deferStmt(gz, scope, statement, block_arena_allocator, .defer_error), 2330 2331 .assign => try assign(gz, scope, statement), 2332 2333 .assign_shl => try assignShift(gz, scope, statement, .shl), 2334 .assign_shr => try assignShift(gz, scope, statement, .shr), 2335 2336 .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), 2337 .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), 2338 .assign_bit_xor => try assignOp(gz, scope, statement, .xor), 2339 .assign_div => try assignOp(gz, scope, statement, .div), 2340 .assign_sub => try assignOp(gz, scope, statement, .sub), 2341 .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap), 2342 .assign_mod => try assignOp(gz, scope, statement, .mod_rem), 2343 .assign_add => try assignOp(gz, scope, statement, .add), 2344 .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), 2345 .assign_mul => try assignOp(gz, scope, statement, .mul), 2346 .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), 2347 2348 .grouped_expression => { 2349 inner_node = node_data[statement].lhs; 2350 continue; 2351 }, 2352 2353 .while_simple => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.whileSimple(inner_node), true), 2354 .while_cont => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.whileCont(inner_node), true), 2355 .@"while" => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.whileFull(inner_node), true), 2356 2357 .for_simple => _ = try forExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.forSimple(inner_node), true), 2358 .@"for" => _ = try forExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.forFull(inner_node), true), 2359 2360 else => noreturn_src_node = try unusedResultExpr(gz, scope, inner_node), 2361 // zig fmt: on 2362 } 2363 break; 2364 } 2365 } 2366 2367 try gz.addDbgBlockEnd(); 2368 2369 try genDefers(gz, parent_scope, scope, .normal_only); 2370 try checkUsed(gz, parent_scope, scope); 2371 } 2372 2373 /// Returns AST source node of the thing that is noreturn if the statement is 2374 /// definitely `noreturn`. Otherwise returns 0. 2375 fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index { 2376 try emitDbgNode(gz, statement); 2377 // We need to emit an error if the result is not `noreturn` or `void`, but 2378 // we want to avoid adding the ZIR instruction if possible for performance. 2379 const maybe_unused_result = try expr(gz, scope, .{ .rl = .none }, statement); 2380 return addEnsureResult(gz, maybe_unused_result, statement); 2381 } 2382 2383 fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: Ast.Node.Index) InnerError!Ast.Node.Index { 2384 var noreturn_src_node: Ast.Node.Index = 0; 2385 const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { 2386 // Note that this array becomes invalid after appending more items to it 2387 // in the above while loop. 2388 const zir_tags = gz.astgen.instructions.items(.tag); 2389 switch (zir_tags[inst]) { 2390 // For some instructions, modify the zir data 2391 // so we can avoid a separate ensure_result_used instruction. 2392 .call => { 2393 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index; 2394 const slot = &gz.astgen.extra.items[extra_index]; 2395 var flags = @bitCast(Zir.Inst.Call.Flags, slot.*); 2396 flags.ensure_result_used = true; 2397 slot.* = @bitCast(u32, flags); 2398 break :b true; 2399 }, 2400 .builtin_call => { 2401 const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index; 2402 const slot = &gz.astgen.extra.items[extra_index]; 2403 var flags = @bitCast(Zir.Inst.BuiltinCall.Flags, slot.*); 2404 flags.ensure_result_used = true; 2405 slot.* = @bitCast(u32, flags); 2406 break :b true; 2407 }, 2408 2409 // ZIR instructions that might be a type other than `noreturn` or `void`. 2410 .add, 2411 .addwrap, 2412 .add_sat, 2413 .param, 2414 .param_comptime, 2415 .param_anytype, 2416 .param_anytype_comptime, 2417 .alloc, 2418 .alloc_mut, 2419 .alloc_comptime_mut, 2420 .alloc_inferred, 2421 .alloc_inferred_mut, 2422 .alloc_inferred_comptime, 2423 .alloc_inferred_comptime_mut, 2424 .make_ptr_const, 2425 .array_cat, 2426 .array_mul, 2427 .array_type, 2428 .array_type_sentinel, 2429 .elem_type_index, 2430 .vector_type, 2431 .indexable_ptr_len, 2432 .anyframe_type, 2433 .as, 2434 .as_node, 2435 .as_shift_operand, 2436 .bit_and, 2437 .bitcast, 2438 .bit_or, 2439 .block, 2440 .block_inline, 2441 .suspend_block, 2442 .loop, 2443 .bool_br_and, 2444 .bool_br_or, 2445 .bool_not, 2446 .cmp_lt, 2447 .cmp_lte, 2448 .cmp_eq, 2449 .cmp_gte, 2450 .cmp_gt, 2451 .cmp_neq, 2452 .coerce_result_ptr, 2453 .decl_ref, 2454 .decl_val, 2455 .load, 2456 .div, 2457 .elem_ptr, 2458 .elem_val, 2459 .elem_ptr_node, 2460 .elem_ptr_imm, 2461 .elem_val_node, 2462 .field_ptr, 2463 .field_ptr_init, 2464 .field_val, 2465 .field_call_bind, 2466 .field_ptr_named, 2467 .field_val_named, 2468 .func, 2469 .func_inferred, 2470 .func_fancy, 2471 .int, 2472 .int_big, 2473 .float, 2474 .float128, 2475 .int_type, 2476 .is_non_null, 2477 .is_non_null_ptr, 2478 .is_non_err, 2479 .is_non_err_ptr, 2480 .mod_rem, 2481 .mul, 2482 .mulwrap, 2483 .mul_sat, 2484 .ref, 2485 .shl, 2486 .shl_sat, 2487 .shr, 2488 .str, 2489 .sub, 2490 .subwrap, 2491 .sub_sat, 2492 .negate, 2493 .negate_wrap, 2494 .typeof, 2495 .typeof_builtin, 2496 .xor, 2497 .optional_type, 2498 .optional_payload_safe, 2499 .optional_payload_unsafe, 2500 .optional_payload_safe_ptr, 2501 .optional_payload_unsafe_ptr, 2502 .err_union_payload_unsafe, 2503 .err_union_payload_unsafe_ptr, 2504 .err_union_code, 2505 .err_union_code_ptr, 2506 .ptr_type, 2507 .overflow_arithmetic_ptr, 2508 .enum_literal, 2509 .merge_error_sets, 2510 .error_union_type, 2511 .bit_not, 2512 .error_value, 2513 .slice_start, 2514 .slice_end, 2515 .slice_sentinel, 2516 .import, 2517 .switch_block, 2518 .switch_cond, 2519 .switch_cond_ref, 2520 .switch_capture, 2521 .switch_capture_ref, 2522 .switch_capture_multi, 2523 .switch_capture_multi_ref, 2524 .switch_capture_tag, 2525 .struct_init_empty, 2526 .struct_init, 2527 .struct_init_ref, 2528 .struct_init_anon, 2529 .struct_init_anon_ref, 2530 .array_init, 2531 .array_init_anon, 2532 .array_init_ref, 2533 .array_init_anon_ref, 2534 .union_init, 2535 .field_type, 2536 .field_type_ref, 2537 .error_set_decl, 2538 .error_set_decl_anon, 2539 .error_set_decl_func, 2540 .int_to_enum, 2541 .enum_to_int, 2542 .type_info, 2543 .size_of, 2544 .bit_size_of, 2545 .log2_int_type, 2546 .typeof_log2_int_type, 2547 .ptr_to_int, 2548 .align_of, 2549 .bool_to_int, 2550 .embed_file, 2551 .error_name, 2552 .sqrt, 2553 .sin, 2554 .cos, 2555 .tan, 2556 .exp, 2557 .exp2, 2558 .log, 2559 .log2, 2560 .log10, 2561 .fabs, 2562 .floor, 2563 .ceil, 2564 .trunc, 2565 .round, 2566 .tag_name, 2567 .type_name, 2568 .frame_type, 2569 .frame_size, 2570 .float_to_int, 2571 .int_to_float, 2572 .int_to_ptr, 2573 .float_cast, 2574 .int_cast, 2575 .ptr_cast, 2576 .truncate, 2577 .align_cast, 2578 .has_decl, 2579 .has_field, 2580 .clz, 2581 .ctz, 2582 .pop_count, 2583 .byte_swap, 2584 .bit_reverse, 2585 .div_exact, 2586 .div_floor, 2587 .div_trunc, 2588 .mod, 2589 .rem, 2590 .shl_exact, 2591 .shr_exact, 2592 .bit_offset_of, 2593 .offset_of, 2594 .splat, 2595 .reduce, 2596 .shuffle, 2597 .atomic_load, 2598 .atomic_rmw, 2599 .mul_add, 2600 .field_parent_ptr, 2601 .max, 2602 .min, 2603 .c_import, 2604 .@"resume", 2605 .@"await", 2606 .ret_err_value_code, 2607 .closure_get, 2608 .array_base_ptr, 2609 .field_base_ptr, 2610 .ret_ptr, 2611 .ret_type, 2612 .@"try", 2613 .try_ptr, 2614 //.try_inline, 2615 //.try_ptr_inline, 2616 => break :b false, 2617 2618 .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) { 2619 .breakpoint, 2620 .fence, 2621 .set_align_stack, 2622 .set_float_mode, 2623 => break :b true, 2624 else => break :b false, 2625 }, 2626 2627 // ZIR instructions that are always `noreturn`. 2628 .@"break", 2629 .break_inline, 2630 .condbr, 2631 .condbr_inline, 2632 .compile_error, 2633 .ret_node, 2634 .ret_load, 2635 .ret_implicit, 2636 .ret_err_value, 2637 .@"unreachable", 2638 .repeat, 2639 .repeat_inline, 2640 .panic, 2641 .panic_comptime, 2642 .check_comptime_control_flow, 2643 => { 2644 noreturn_src_node = statement; 2645 break :b true; 2646 }, 2647 2648 // ZIR instructions that are always `void`. 2649 .dbg_stmt, 2650 .dbg_var_ptr, 2651 .dbg_var_val, 2652 .dbg_block_begin, 2653 .dbg_block_end, 2654 .ensure_result_used, 2655 .ensure_result_non_error, 2656 .ensure_err_union_payload_void, 2657 .@"export", 2658 .export_value, 2659 .set_eval_branch_quota, 2660 .atomic_store, 2661 .store, 2662 .store_node, 2663 .store_to_block_ptr, 2664 .store_to_inferred_ptr, 2665 .resolve_inferred_alloc, 2666 .validate_struct_init, 2667 .validate_struct_init_comptime, 2668 .validate_array_init, 2669 .validate_array_init_comptime, 2670 .set_cold, 2671 .set_runtime_safety, 2672 .closure_capture, 2673 .memcpy, 2674 .memset, 2675 .validate_array_init_ty, 2676 .validate_struct_init_ty, 2677 .validate_deref, 2678 .save_err_ret_index, 2679 .restore_err_ret_index, 2680 => break :b true, 2681 2682 .@"defer" => unreachable, 2683 .defer_err_code => unreachable, 2684 } 2685 } else switch (maybe_unused_result) { 2686 .none => unreachable, 2687 2688 .unreachable_value => b: { 2689 noreturn_src_node = statement; 2690 break :b true; 2691 }, 2692 2693 .void_value => true, 2694 2695 else => false, 2696 }; 2697 if (!elide_check) { 2698 _ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement); 2699 } 2700 return noreturn_src_node; 2701 } 2702 2703 fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct { 2704 have_any: bool, 2705 have_normal: bool, 2706 have_err: bool, 2707 need_err_code: bool, 2708 } { 2709 var have_normal = false; 2710 var have_err = false; 2711 var need_err_code = false; 2712 var scope = inner_scope; 2713 while (scope != outer_scope) { 2714 switch (scope.tag) { 2715 .gen_zir => scope = scope.cast(GenZir).?.parent, 2716 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2717 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2718 .defer_normal => { 2719 const defer_scope = scope.cast(Scope.Defer).?; 2720 scope = defer_scope.parent; 2721 2722 have_normal = true; 2723 }, 2724 .defer_error => { 2725 const defer_scope = scope.cast(Scope.Defer).?; 2726 scope = defer_scope.parent; 2727 2728 have_err = true; 2729 2730 const have_err_payload = defer_scope.remapped_err_code != 0; 2731 need_err_code = need_err_code or have_err_payload; 2732 }, 2733 .namespace => unreachable, 2734 .top => unreachable, 2735 } 2736 } 2737 return .{ 2738 .have_any = have_normal or have_err, 2739 .have_normal = have_normal, 2740 .have_err = have_err, 2741 .need_err_code = need_err_code, 2742 }; 2743 } 2744 2745 const DefersToEmit = union(enum) { 2746 both: Zir.Inst.Ref, // err code 2747 both_sans_err, 2748 normal_only, 2749 }; 2750 2751 fn genDefers( 2752 gz: *GenZir, 2753 outer_scope: *Scope, 2754 inner_scope: *Scope, 2755 which_ones: DefersToEmit, 2756 ) InnerError!void { 2757 const gpa = gz.astgen.gpa; 2758 2759 var scope = inner_scope; 2760 while (scope != outer_scope) { 2761 switch (scope.tag) { 2762 .gen_zir => scope = scope.cast(GenZir).?.parent, 2763 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2764 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2765 .defer_normal => { 2766 const defer_scope = scope.cast(Scope.Defer).?; 2767 scope = defer_scope.parent; 2768 try gz.addDefer(defer_scope.index, defer_scope.len); 2769 }, 2770 .defer_error => { 2771 const defer_scope = scope.cast(Scope.Defer).?; 2772 scope = defer_scope.parent; 2773 switch (which_ones) { 2774 .both_sans_err => { 2775 try gz.addDefer(defer_scope.index, defer_scope.len); 2776 }, 2777 .both => |err_code| { 2778 if (defer_scope.remapped_err_code == 0) { 2779 try gz.addDefer(defer_scope.index, defer_scope.len); 2780 } else { 2781 try gz.instructions.ensureUnusedCapacity(gpa, 1); 2782 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 2783 2784 const payload_index = try gz.astgen.addExtra(Zir.Inst.DeferErrCode{ 2785 .remapped_err_code = defer_scope.remapped_err_code, 2786 .index = defer_scope.index, 2787 .len = defer_scope.len, 2788 }); 2789 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 2790 gz.astgen.instructions.appendAssumeCapacity(.{ 2791 .tag = .defer_err_code, 2792 .data = .{ .defer_err_code = .{ 2793 .err_code = err_code, 2794 .payload_index = payload_index, 2795 } }, 2796 }); 2797 gz.instructions.appendAssumeCapacity(new_index); 2798 } 2799 }, 2800 .normal_only => continue, 2801 } 2802 }, 2803 .namespace => unreachable, 2804 .top => unreachable, 2805 } 2806 } 2807 } 2808 2809 fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!void { 2810 const astgen = gz.astgen; 2811 2812 var scope = inner_scope; 2813 while (scope != outer_scope) { 2814 switch (scope.tag) { 2815 .gen_zir => scope = scope.cast(GenZir).?.parent, 2816 .local_val => { 2817 const s = scope.cast(Scope.LocalVal).?; 2818 if (s.used == 0 and s.discarded == 0) { 2819 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2820 } else if (s.used != 0 and s.discarded != 0) { 2821 try astgen.appendErrorTokNotes(s.discarded, "pointless discard of {s}", .{@tagName(s.id_cat)}, &[_]u32{ 2822 try gz.astgen.errNoteTok(s.used, "used here", .{}), 2823 }); 2824 } 2825 scope = s.parent; 2826 }, 2827 .local_ptr => { 2828 const s = scope.cast(Scope.LocalPtr).?; 2829 if (s.used == 0 and s.discarded == 0) { 2830 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2831 } else if (s.used != 0 and s.discarded != 0) { 2832 try astgen.appendErrorTokNotes(s.discarded, "pointless discard of {s}", .{@tagName(s.id_cat)}, &[_]u32{ 2833 try gz.astgen.errNoteTok(s.used, "used here", .{}), 2834 }); 2835 } 2836 scope = s.parent; 2837 }, 2838 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2839 .namespace => unreachable, 2840 .top => unreachable, 2841 } 2842 } 2843 } 2844 2845 fn deferStmt( 2846 gz: *GenZir, 2847 scope: *Scope, 2848 node: Ast.Node.Index, 2849 block_arena: Allocator, 2850 scope_tag: Scope.Tag, 2851 ) InnerError!*Scope { 2852 var defer_gen = gz.makeSubBlock(scope); 2853 defer_gen.cur_defer_node = node; 2854 defer_gen.any_defer_node = node; 2855 defer defer_gen.unstack(); 2856 2857 const tree = gz.astgen.tree; 2858 const node_datas = tree.nodes.items(.data); 2859 const expr_node = node_datas[node].rhs; 2860 2861 const payload_token = node_datas[node].lhs; 2862 var local_val_scope: Scope.LocalVal = undefined; 2863 var remapped_err_code: Zir.Inst.Index = 0; 2864 const have_err_code = scope_tag == .defer_error and payload_token != 0; 2865 const sub_scope = if (!have_err_code) &defer_gen.base else blk: { 2866 try gz.addDbgBlockBegin(); 2867 const ident_name = try gz.astgen.identAsString(payload_token); 2868 remapped_err_code = @intCast(u32, try gz.astgen.instructions.addOne(gz.astgen.gpa)); 2869 const remapped_err_code_ref = Zir.indexToRef(remapped_err_code); 2870 local_val_scope = .{ 2871 .parent = &defer_gen.base, 2872 .gen_zir = gz, 2873 .name = ident_name, 2874 .inst = remapped_err_code_ref, 2875 .token_src = payload_token, 2876 .id_cat = .capture, 2877 }; 2878 try gz.addDbgVar(.dbg_var_val, ident_name, remapped_err_code_ref); 2879 break :blk &local_val_scope.base; 2880 }; 2881 _ = try unusedResultExpr(&defer_gen, sub_scope, expr_node); 2882 try checkUsed(gz, scope, sub_scope); 2883 if (have_err_code) try gz.addDbgBlockEnd(); 2884 _ = try defer_gen.addBreak(.break_inline, 0, .void_value); 2885 2886 const body = defer_gen.instructionsSlice(); 2887 const body_len = gz.astgen.countBodyLenAfterFixups(body); 2888 2889 const index = @intCast(u32, gz.astgen.extra.items.len); 2890 try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len); 2891 gz.astgen.appendBodyWithFixups(body); 2892 2893 const defer_scope = try block_arena.create(Scope.Defer); 2894 2895 defer_scope.* = .{ 2896 .base = .{ .tag = scope_tag }, 2897 .parent = scope, 2898 .index = index, 2899 .len = body_len, 2900 .remapped_err_code = remapped_err_code, 2901 }; 2902 return &defer_scope.base; 2903 } 2904 2905 fn varDecl( 2906 gz: *GenZir, 2907 scope: *Scope, 2908 node: Ast.Node.Index, 2909 block_arena: Allocator, 2910 var_decl: Ast.full.VarDecl, 2911 ) InnerError!*Scope { 2912 try emitDbgNode(gz, node); 2913 const astgen = gz.astgen; 2914 const tree = astgen.tree; 2915 const token_tags = tree.tokens.items(.tag); 2916 const main_tokens = tree.nodes.items(.main_token); 2917 2918 const name_token = var_decl.ast.mut_token + 1; 2919 const ident_name_raw = tree.tokenSlice(name_token); 2920 if (mem.eql(u8, ident_name_raw, "_")) { 2921 return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{}); 2922 } 2923 const ident_name = try astgen.identAsString(name_token); 2924 2925 try astgen.detectLocalShadowing( 2926 scope, 2927 ident_name, 2928 name_token, 2929 ident_name_raw, 2930 if (token_tags[var_decl.ast.mut_token] == .keyword_const) .@"local constant" else .@"local variable", 2931 ); 2932 2933 if (var_decl.ast.init_node == 0) { 2934 return astgen.failNode(node, "variables must be initialized", .{}); 2935 } 2936 2937 if (var_decl.ast.addrspace_node != 0) { 2938 return astgen.failTok(main_tokens[var_decl.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ident_name_raw}); 2939 } 2940 2941 if (var_decl.ast.section_node != 0) { 2942 return astgen.failTok(main_tokens[var_decl.ast.section_node], "cannot set section of local variable '{s}'", .{ident_name_raw}); 2943 } 2944 2945 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0) 2946 try expr(gz, scope, align_ri, var_decl.ast.align_node) 2947 else 2948 .none; 2949 2950 switch (token_tags[var_decl.ast.mut_token]) { 2951 .keyword_const => { 2952 if (var_decl.comptime_token) |comptime_token| { 2953 try astgen.appendErrorTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); 2954 } 2955 2956 // Depending on the type of AST the initialization expression is, we may need an lvalue 2957 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as 2958 // the variable, no memory location needed. 2959 const type_node = var_decl.ast.type_node; 2960 if (align_inst == .none and 2961 !nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node, type_node != 0)) 2962 { 2963 const result_info: ResultInfo = if (type_node != 0) .{ 2964 .rl = .{ .ty = try typeExpr(gz, scope, type_node) }, 2965 .ctx = .const_init, 2966 } else .{ .rl = .none, .ctx = .const_init }; 2967 const prev_anon_name_strategy = gz.anon_name_strategy; 2968 gz.anon_name_strategy = .dbg_var; 2969 const init_inst = try reachableExpr(gz, scope, result_info, var_decl.ast.init_node, node); 2970 gz.anon_name_strategy = prev_anon_name_strategy; 2971 2972 try gz.addDbgVar(.dbg_var_val, ident_name, init_inst); 2973 2974 // The const init expression may have modified the error return trace, so signal 2975 // to Sema that it should save the new index for restoring later. 2976 if (nodeMayAppendToErrorTrace(tree, var_decl.ast.init_node)) 2977 _ = try gz.addSaveErrRetIndex(.{ .if_of_error_type = init_inst }); 2978 2979 const sub_scope = try block_arena.create(Scope.LocalVal); 2980 sub_scope.* = .{ 2981 .parent = scope, 2982 .gen_zir = gz, 2983 .name = ident_name, 2984 .inst = init_inst, 2985 .token_src = name_token, 2986 .id_cat = .@"local constant", 2987 }; 2988 return &sub_scope.base; 2989 } 2990 2991 const is_comptime = gz.force_comptime or 2992 tree.nodes.items(.tag)[var_decl.ast.init_node] == .@"comptime"; 2993 2994 // Detect whether the initialization expression actually uses the 2995 // result location pointer. 2996 var init_scope = gz.makeSubBlock(scope); 2997 // we may add more instructions to gz before stacking init_scope 2998 init_scope.instructions_top = GenZir.unstacked_top; 2999 init_scope.anon_name_strategy = .dbg_var; 3000 defer init_scope.unstack(); 3001 3002 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 3003 var opt_type_inst: Zir.Inst.Ref = .none; 3004 if (type_node != 0) { 3005 const type_inst = try typeExpr(gz, &init_scope.base, type_node); 3006 opt_type_inst = type_inst; 3007 if (align_inst == .none) { 3008 init_scope.instructions_top = gz.instructions.items.len; 3009 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); 3010 } else { 3011 init_scope.rl_ptr = try gz.addAllocExtended(.{ 3012 .node = node, 3013 .type_inst = type_inst, 3014 .align_inst = align_inst, 3015 .is_const = true, 3016 .is_comptime = is_comptime, 3017 }); 3018 init_scope.instructions_top = gz.instructions.items.len; 3019 } 3020 init_scope.rl_ty_inst = type_inst; 3021 } else { 3022 const alloc = if (align_inst == .none) alloc: { 3023 init_scope.instructions_top = gz.instructions.items.len; 3024 const tag: Zir.Inst.Tag = if (is_comptime) 3025 .alloc_inferred_comptime 3026 else 3027 .alloc_inferred; 3028 break :alloc try init_scope.addNode(tag, node); 3029 } else alloc: { 3030 const ref = try gz.addAllocExtended(.{ 3031 .node = node, 3032 .type_inst = .none, 3033 .align_inst = align_inst, 3034 .is_const = true, 3035 .is_comptime = is_comptime, 3036 }); 3037 init_scope.instructions_top = gz.instructions.items.len; 3038 break :alloc ref; 3039 }; 3040 resolve_inferred_alloc = alloc; 3041 init_scope.rl_ptr = alloc; 3042 init_scope.rl_ty_inst = .none; 3043 } 3044 const init_result_info: ResultInfo = .{ .rl = .{ .block_ptr = &init_scope }, .ctx = .const_init }; 3045 const init_inst = try reachableExpr(&init_scope, &init_scope.base, init_result_info, var_decl.ast.init_node, node); 3046 3047 // The const init expression may have modified the error return trace, so signal 3048 // to Sema that it should save the new index for restoring later. 3049 if (nodeMayAppendToErrorTrace(tree, var_decl.ast.init_node)) 3050 _ = try init_scope.addSaveErrRetIndex(.{ .if_of_error_type = init_inst }); 3051 3052 const zir_tags = astgen.instructions.items(.tag); 3053 const zir_datas = astgen.instructions.items(.data); 3054 3055 if (align_inst == .none and init_scope.rvalue_rl_count == 1) { 3056 // Result location pointer not used. We don't need an alloc for this 3057 // const local, and type inference becomes trivial. 3058 // Implicitly move the init_scope instructions into the parent scope, 3059 // then elide the alloc instruction and the store_to_block_ptr instruction. 3060 var src = init_scope.instructions_top; 3061 var dst = src; 3062 init_scope.instructions_top = GenZir.unstacked_top; 3063 while (src < gz.instructions.items.len) : (src += 1) { 3064 const src_inst = gz.instructions.items[src]; 3065 if (indexToRef(src_inst) == init_scope.rl_ptr) continue; 3066 if (zir_tags[src_inst] == .store_to_block_ptr) { 3067 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue; 3068 } 3069 gz.instructions.items[dst] = src_inst; 3070 dst += 1; 3071 } 3072 gz.instructions.items.len = dst; 3073 3074 // In case the result location did not do the coercion 3075 // for us so we must do it here. 3076 const coerced_init = if (opt_type_inst != .none) 3077 try gz.addBin(.as, opt_type_inst, init_inst) 3078 else 3079 init_inst; 3080 3081 try gz.addDbgVar(.dbg_var_val, ident_name, coerced_init); 3082 3083 const sub_scope = try block_arena.create(Scope.LocalVal); 3084 sub_scope.* = .{ 3085 .parent = scope, 3086 .gen_zir = gz, 3087 .name = ident_name, 3088 .inst = coerced_init, 3089 .token_src = name_token, 3090 .id_cat = .@"local constant", 3091 }; 3092 return &sub_scope.base; 3093 } 3094 // The initialization expression took advantage of the result location 3095 // of the const local. In this case we will create an alloc and a LocalPtr for it. 3096 // Implicitly move the init_scope instructions into the parent scope, then swap 3097 // store_to_block_ptr for store_to_inferred_ptr. 3098 3099 var src = init_scope.instructions_top; 3100 init_scope.instructions_top = GenZir.unstacked_top; 3101 while (src < gz.instructions.items.len) : (src += 1) { 3102 const src_inst = gz.instructions.items[src]; 3103 if (zir_tags[src_inst] == .store_to_block_ptr) { 3104 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { 3105 if (type_node != 0) { 3106 zir_tags[src_inst] = .store; 3107 } else { 3108 zir_tags[src_inst] = .store_to_inferred_ptr; 3109 } 3110 } 3111 } 3112 } 3113 if (resolve_inferred_alloc != .none) { 3114 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 3115 } 3116 const const_ptr = try gz.addUnNode(.make_ptr_const, init_scope.rl_ptr, node); 3117 3118 try gz.addDbgVar(.dbg_var_ptr, ident_name, const_ptr); 3119 3120 const sub_scope = try block_arena.create(Scope.LocalPtr); 3121 sub_scope.* = .{ 3122 .parent = scope, 3123 .gen_zir = gz, 3124 .name = ident_name, 3125 .ptr = const_ptr, 3126 .token_src = name_token, 3127 .maybe_comptime = true, 3128 .id_cat = .@"local constant", 3129 }; 3130 return &sub_scope.base; 3131 }, 3132 .keyword_var => { 3133 const old_rl_ty_inst = gz.rl_ty_inst; 3134 defer gz.rl_ty_inst = old_rl_ty_inst; 3135 3136 const is_comptime = var_decl.comptime_token != null or gz.force_comptime; 3137 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 3138 const var_data: struct { 3139 result_info: ResultInfo, 3140 alloc: Zir.Inst.Ref, 3141 } = if (var_decl.ast.type_node != 0) a: { 3142 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); 3143 const alloc = alloc: { 3144 if (align_inst == .none) { 3145 const tag: Zir.Inst.Tag = if (is_comptime) 3146 .alloc_comptime_mut 3147 else 3148 .alloc_mut; 3149 break :alloc try gz.addUnNode(tag, type_inst, node); 3150 } else { 3151 break :alloc try gz.addAllocExtended(.{ 3152 .node = node, 3153 .type_inst = type_inst, 3154 .align_inst = align_inst, 3155 .is_const = false, 3156 .is_comptime = is_comptime, 3157 }); 3158 } 3159 }; 3160 gz.rl_ty_inst = type_inst; 3161 break :a .{ .alloc = alloc, .result_info = .{ .rl = .{ .ptr = .{ .inst = alloc } } } }; 3162 } else a: { 3163 const alloc = alloc: { 3164 if (align_inst == .none) { 3165 const tag: Zir.Inst.Tag = if (is_comptime) 3166 .alloc_inferred_comptime_mut 3167 else 3168 .alloc_inferred_mut; 3169 break :alloc try gz.addNode(tag, node); 3170 } else { 3171 break :alloc try gz.addAllocExtended(.{ 3172 .node = node, 3173 .type_inst = .none, 3174 .align_inst = align_inst, 3175 .is_const = false, 3176 .is_comptime = is_comptime, 3177 }); 3178 } 3179 }; 3180 gz.rl_ty_inst = .none; 3181 resolve_inferred_alloc = alloc; 3182 break :a .{ .alloc = alloc, .result_info = .{ .rl = .{ .inferred_ptr = alloc } } }; 3183 }; 3184 const prev_anon_name_strategy = gz.anon_name_strategy; 3185 gz.anon_name_strategy = .dbg_var; 3186 _ = try reachableExprComptime(gz, scope, var_data.result_info, var_decl.ast.init_node, node, is_comptime); 3187 gz.anon_name_strategy = prev_anon_name_strategy; 3188 if (resolve_inferred_alloc != .none) { 3189 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 3190 } 3191 3192 try gz.addDbgVar(.dbg_var_ptr, ident_name, var_data.alloc); 3193 3194 const sub_scope = try block_arena.create(Scope.LocalPtr); 3195 sub_scope.* = .{ 3196 .parent = scope, 3197 .gen_zir = gz, 3198 .name = ident_name, 3199 .ptr = var_data.alloc, 3200 .token_src = name_token, 3201 .maybe_comptime = is_comptime, 3202 .id_cat = .@"local variable", 3203 }; 3204 return &sub_scope.base; 3205 }, 3206 else => unreachable, 3207 } 3208 } 3209 3210 fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void { 3211 // The instruction emitted here is for debugging runtime code. 3212 // If the current block will be evaluated only during semantic analysis 3213 // then no dbg_stmt ZIR instruction is needed. 3214 if (gz.force_comptime) return; 3215 3216 const astgen = gz.astgen; 3217 astgen.advanceSourceCursorToNode(node); 3218 const line = astgen.source_line - gz.decl_line; 3219 const column = astgen.source_column; 3220 3221 if (gz.instructions.items.len > 0) { 3222 const last = gz.instructions.items[gz.instructions.items.len - 1]; 3223 const zir_tags = astgen.instructions.items(.tag); 3224 if (zir_tags[last] == .dbg_stmt) { 3225 const zir_datas = astgen.instructions.items(.data); 3226 zir_datas[last].dbg_stmt = .{ 3227 .line = line, 3228 .column = column, 3229 }; 3230 return; 3231 } 3232 } 3233 3234 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 3235 .dbg_stmt = .{ 3236 .line = line, 3237 .column = column, 3238 }, 3239 } }); 3240 } 3241 3242 fn assign(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!void { 3243 try emitDbgNode(gz, infix_node); 3244 const astgen = gz.astgen; 3245 const tree = astgen.tree; 3246 const node_datas = tree.nodes.items(.data); 3247 const main_tokens = tree.nodes.items(.main_token); 3248 const node_tags = tree.nodes.items(.tag); 3249 3250 const lhs = node_datas[infix_node].lhs; 3251 const rhs = node_datas[infix_node].rhs; 3252 if (node_tags[lhs] == .identifier) { 3253 // This intentionally does not support `@"_"` syntax. 3254 const ident_name = tree.tokenSlice(main_tokens[lhs]); 3255 if (mem.eql(u8, ident_name, "_")) { 3256 _ = try expr(gz, scope, .{ .rl = .discard, .ctx = .assignment }, rhs); 3257 return; 3258 } 3259 } 3260 const lvalue = try lvalExpr(gz, scope, lhs); 3261 _ = try expr(gz, scope, .{ .rl = .{ .ptr = .{ 3262 .inst = lvalue, 3263 .src_node = infix_node, 3264 } } }, rhs); 3265 } 3266 3267 fn assignOp( 3268 gz: *GenZir, 3269 scope: *Scope, 3270 infix_node: Ast.Node.Index, 3271 op_inst_tag: Zir.Inst.Tag, 3272 ) InnerError!void { 3273 try emitDbgNode(gz, infix_node); 3274 const astgen = gz.astgen; 3275 const tree = astgen.tree; 3276 const node_datas = tree.nodes.items(.data); 3277 3278 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3279 3280 var line: u32 = undefined; 3281 var column: u32 = undefined; 3282 switch (op_inst_tag) { 3283 .add, .sub, .mul, .div, .mod_rem => { 3284 maybeAdvanceSourceCursorToMainToken(gz, infix_node); 3285 line = gz.astgen.source_line - gz.decl_line; 3286 column = gz.astgen.source_column; 3287 }, 3288 else => {}, 3289 } 3290 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3291 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node); 3292 const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = lhs_type } }, node_datas[infix_node].rhs); 3293 3294 switch (op_inst_tag) { 3295 .add, .sub, .mul, .div, .mod_rem => { 3296 try emitDbgStmt(gz, line, column); 3297 }, 3298 else => {}, 3299 } 3300 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 3301 .lhs = lhs, 3302 .rhs = rhs, 3303 }); 3304 _ = try gz.addBin(.store, lhs_ptr, result); 3305 } 3306 3307 fn assignShift( 3308 gz: *GenZir, 3309 scope: *Scope, 3310 infix_node: Ast.Node.Index, 3311 op_inst_tag: Zir.Inst.Tag, 3312 ) InnerError!void { 3313 try emitDbgNode(gz, infix_node); 3314 const astgen = gz.astgen; 3315 const tree = astgen.tree; 3316 const node_datas = tree.nodes.items(.data); 3317 3318 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3319 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3320 const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node); 3321 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = rhs_type } }, node_datas[infix_node].rhs); 3322 3323 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 3324 .lhs = lhs, 3325 .rhs = rhs, 3326 }); 3327 _ = try gz.addBin(.store, lhs_ptr, result); 3328 } 3329 3330 fn assignShiftSat(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!void { 3331 try emitDbgNode(gz, infix_node); 3332 const astgen = gz.astgen; 3333 const tree = astgen.tree; 3334 const node_datas = tree.nodes.items(.data); 3335 3336 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 3337 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 3338 // Saturating shift-left allows any integer type for both the LHS and RHS. 3339 const rhs = try expr(gz, scope, .{ .rl = .none }, node_datas[infix_node].rhs); 3340 3341 const result = try gz.addPlNode(.shl_sat, infix_node, Zir.Inst.Bin{ 3342 .lhs = lhs, 3343 .rhs = rhs, 3344 }); 3345 _ = try gz.addBin(.store, lhs_ptr, result); 3346 } 3347 3348 fn ptrType( 3349 gz: *GenZir, 3350 scope: *Scope, 3351 ri: ResultInfo, 3352 node: Ast.Node.Index, 3353 ptr_info: Ast.full.PtrType, 3354 ) InnerError!Zir.Inst.Ref { 3355 if (ptr_info.size == .C and ptr_info.allowzero_token != null) { 3356 return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{}); 3357 } 3358 3359 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); 3360 3361 var sentinel_ref: Zir.Inst.Ref = .none; 3362 var align_ref: Zir.Inst.Ref = .none; 3363 var addrspace_ref: Zir.Inst.Ref = .none; 3364 var bit_start_ref: Zir.Inst.Ref = .none; 3365 var bit_end_ref: Zir.Inst.Ref = .none; 3366 var trailing_count: u32 = 0; 3367 3368 if (ptr_info.ast.sentinel != 0) { 3369 sentinel_ref = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, ptr_info.ast.sentinel); 3370 trailing_count += 1; 3371 } 3372 if (ptr_info.ast.align_node != 0) { 3373 align_ref = try expr(gz, scope, coerced_align_ri, ptr_info.ast.align_node); 3374 trailing_count += 1; 3375 } 3376 if (ptr_info.ast.addrspace_node != 0) { 3377 addrspace_ref = try expr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, ptr_info.ast.addrspace_node); 3378 trailing_count += 1; 3379 } 3380 if (ptr_info.ast.bit_range_start != 0) { 3381 assert(ptr_info.ast.bit_range_end != 0); 3382 bit_start_ref = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_start); 3383 bit_end_ref = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_end); 3384 trailing_count += 2; 3385 } 3386 3387 const gpa = gz.astgen.gpa; 3388 try gz.instructions.ensureUnusedCapacity(gpa, 1); 3389 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 3390 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len + 3391 trailing_count); 3392 3393 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ 3394 .elem_type = elem_type, 3395 .src_node = gz.nodeIndexToRelative(node), 3396 }); 3397 if (sentinel_ref != .none) { 3398 gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref)); 3399 } 3400 if (align_ref != .none) { 3401 gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref)); 3402 } 3403 if (addrspace_ref != .none) { 3404 gz.astgen.extra.appendAssumeCapacity(@enumToInt(addrspace_ref)); 3405 } 3406 if (bit_start_ref != .none) { 3407 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref)); 3408 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref)); 3409 } 3410 3411 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 3412 const result = indexToRef(new_index); 3413 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{ 3414 .ptr_type = .{ 3415 .flags = .{ 3416 .is_allowzero = ptr_info.allowzero_token != null, 3417 .is_mutable = ptr_info.const_token == null, 3418 .is_volatile = ptr_info.volatile_token != null, 3419 .has_sentinel = sentinel_ref != .none, 3420 .has_align = align_ref != .none, 3421 .has_addrspace = addrspace_ref != .none, 3422 .has_bit_range = bit_start_ref != .none, 3423 }, 3424 .size = ptr_info.size, 3425 .payload_index = payload_index, 3426 }, 3427 } }); 3428 gz.instructions.appendAssumeCapacity(new_index); 3429 3430 return rvalue(gz, ri, result, node); 3431 } 3432 3433 fn arrayType(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) !Zir.Inst.Ref { 3434 const astgen = gz.astgen; 3435 const tree = astgen.tree; 3436 const node_datas = tree.nodes.items(.data); 3437 const node_tags = tree.nodes.items(.tag); 3438 const main_tokens = tree.nodes.items(.main_token); 3439 3440 const len_node = node_datas[node].lhs; 3441 if (node_tags[len_node] == .identifier and 3442 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 3443 { 3444 return astgen.failNode(len_node, "unable to infer array size", .{}); 3445 } 3446 const len = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node); 3447 const elem_type = try typeExpr(gz, scope, node_datas[node].rhs); 3448 3449 const result = try gz.addPlNode(.array_type, node, Zir.Inst.Bin{ 3450 .lhs = len, 3451 .rhs = elem_type, 3452 }); 3453 return rvalue(gz, ri, result, node); 3454 } 3455 3456 fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) !Zir.Inst.Ref { 3457 const astgen = gz.astgen; 3458 const tree = astgen.tree; 3459 const node_datas = tree.nodes.items(.data); 3460 const node_tags = tree.nodes.items(.tag); 3461 const main_tokens = tree.nodes.items(.main_token); 3462 const extra = tree.extraData(node_datas[node].rhs, Ast.Node.ArrayTypeSentinel); 3463 3464 const len_node = node_datas[node].lhs; 3465 if (node_tags[len_node] == .identifier and 3466 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 3467 { 3468 return astgen.failNode(len_node, "unable to infer array size", .{}); 3469 } 3470 const len = try reachableExpr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, len_node, node); 3471 const elem_type = try typeExpr(gz, scope, extra.elem_type); 3472 const sentinel = try reachableExpr(gz, scope, .{ .rl = .{ .coerced_ty = elem_type } }, extra.sentinel, node); 3473 3474 const result = try gz.addPlNode(.array_type_sentinel, node, Zir.Inst.ArrayTypeSentinel{ 3475 .len = len, 3476 .elem_type = elem_type, 3477 .sentinel = sentinel, 3478 }); 3479 return rvalue(gz, ri, result, node); 3480 } 3481 3482 const WipMembers = struct { 3483 payload: *ArrayListUnmanaged(u32), 3484 payload_top: usize, 3485 decls_start: u32, 3486 decls_end: u32, 3487 field_bits_start: u32, 3488 fields_start: u32, 3489 fields_end: u32, 3490 decl_index: u32 = 0, 3491 field_index: u32 = 0, 3492 3493 const Self = @This(); 3494 /// struct, union, enum, and opaque decls all use same 4 bits per decl 3495 const bits_per_decl = 4; 3496 const decls_per_u32 = 32 / bits_per_decl; 3497 /// struct, union, enum, and opaque decls all have maximum size of 11 u32 slots 3498 /// (4 for src_hash + line + name + value + doc_comment + align + link_section + address_space ) 3499 const max_decl_size = 11; 3500 3501 pub fn init(gpa: Allocator, payload: *ArrayListUnmanaged(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self { 3502 const payload_top = @intCast(u32, payload.items.len); 3503 const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32; 3504 const field_bits_start = decls_start + decl_count * max_decl_size; 3505 const fields_start = field_bits_start + if (bits_per_field > 0) blk: { 3506 const fields_per_u32 = 32 / bits_per_field; 3507 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32; 3508 } else 0; 3509 const payload_end = fields_start + field_count * max_field_size; 3510 try payload.resize(gpa, payload_end); 3511 return Self{ 3512 .payload = payload, 3513 .payload_top = payload_top, 3514 .decls_start = decls_start, 3515 .field_bits_start = field_bits_start, 3516 .fields_start = fields_start, 3517 .decls_end = decls_start, 3518 .fields_end = fields_start, 3519 }; 3520 } 3521 3522 pub fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void { 3523 const index = self.payload_top + self.decl_index / decls_per_u32; 3524 assert(index < self.decls_start); 3525 const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload.items[index]; 3526 self.payload.items[index] = (bit_bag >> bits_per_decl) | 3527 (@as(u32, @boolToInt(is_pub)) << 28) | 3528 (@as(u32, @boolToInt(is_export)) << 29) | 3529 (@as(u32, @boolToInt(has_align)) << 30) | 3530 (@as(u32, @boolToInt(has_section_or_addrspace)) << 31); 3531 self.decl_index += 1; 3532 } 3533 3534 pub fn nextField(self: *Self, comptime bits_per_field: u32, bits: [bits_per_field]bool) void { 3535 const fields_per_u32 = 32 / bits_per_field; 3536 const index = self.field_bits_start + self.field_index / fields_per_u32; 3537 assert(index < self.fields_start); 3538 var bit_bag: u32 = if (self.field_index % fields_per_u32 == 0) 0 else self.payload.items[index]; 3539 bit_bag >>= bits_per_field; 3540 comptime var i = 0; 3541 inline while (i < bits_per_field) : (i += 1) { 3542 bit_bag |= @as(u32, @boolToInt(bits[i])) << (32 - bits_per_field + i); 3543 } 3544 self.payload.items[index] = bit_bag; 3545 self.field_index += 1; 3546 } 3547 3548 pub fn appendToDecl(self: *Self, data: u32) void { 3549 assert(self.decls_end < self.field_bits_start); 3550 self.payload.items[self.decls_end] = data; 3551 self.decls_end += 1; 3552 } 3553 3554 pub fn appendToDeclSlice(self: *Self, data: []const u32) void { 3555 assert(self.decls_end + data.len <= self.field_bits_start); 3556 mem.copy(u32, self.payload.items[self.decls_end..], data); 3557 self.decls_end += @intCast(u32, data.len); 3558 } 3559 3560 pub fn appendToField(self: *Self, data: u32) void { 3561 assert(self.fields_end < self.payload.items.len); 3562 self.payload.items[self.fields_end] = data; 3563 self.fields_end += 1; 3564 } 3565 3566 pub fn finishBits(self: *Self, comptime bits_per_field: u32) void { 3567 const empty_decl_slots = decls_per_u32 - (self.decl_index % decls_per_u32); 3568 if (self.decl_index > 0 and empty_decl_slots < decls_per_u32) { 3569 const index = self.payload_top + self.decl_index / decls_per_u32; 3570 self.payload.items[index] >>= @intCast(u5, empty_decl_slots * bits_per_decl); 3571 } 3572 if (bits_per_field > 0) { 3573 const fields_per_u32 = 32 / bits_per_field; 3574 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32); 3575 if (self.field_index > 0 and empty_field_slots < fields_per_u32) { 3576 const index = self.field_bits_start + self.field_index / fields_per_u32; 3577 self.payload.items[index] >>= @intCast(u5, empty_field_slots * bits_per_field); 3578 } 3579 } 3580 } 3581 3582 pub fn declsSlice(self: *Self) []u32 { 3583 return self.payload.items[self.payload_top..self.decls_end]; 3584 } 3585 3586 pub fn fieldsSlice(self: *Self) []u32 { 3587 return self.payload.items[self.field_bits_start..self.fields_end]; 3588 } 3589 3590 pub fn deinit(self: *Self) void { 3591 self.payload.items.len = self.payload_top; 3592 } 3593 }; 3594 3595 fn fnDecl( 3596 astgen: *AstGen, 3597 gz: *GenZir, 3598 scope: *Scope, 3599 wip_members: *WipMembers, 3600 decl_node: Ast.Node.Index, 3601 body_node: Ast.Node.Index, 3602 fn_proto: Ast.full.FnProto, 3603 ) InnerError!void { 3604 const tree = astgen.tree; 3605 const token_tags = tree.tokens.items(.tag); 3606 3607 // missing function name already happened in scanDecls() 3608 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; 3609 const fn_name_str_index = try astgen.identAsString(fn_name_token); 3610 3611 // We insert this at the beginning so that its instruction index marks the 3612 // start of the top level declaration. 3613 const block_inst = try gz.makeBlockInst(.block_inline, fn_proto.ast.proto_node); 3614 astgen.advanceSourceCursorToNode(decl_node); 3615 3616 var decl_gz: GenZir = .{ 3617 .force_comptime = true, 3618 .decl_node_index = fn_proto.ast.proto_node, 3619 .decl_line = astgen.source_line, 3620 .parent = scope, 3621 .astgen = astgen, 3622 .instructions = gz.instructions, 3623 .instructions_top = gz.instructions.items.len, 3624 }; 3625 defer decl_gz.unstack(); 3626 3627 var fn_gz: GenZir = .{ 3628 .force_comptime = false, 3629 .decl_node_index = fn_proto.ast.proto_node, 3630 .decl_line = decl_gz.decl_line, 3631 .parent = &decl_gz.base, 3632 .astgen = astgen, 3633 .instructions = gz.instructions, 3634 .instructions_top = GenZir.unstacked_top, 3635 }; 3636 defer fn_gz.unstack(); 3637 3638 const is_pub = fn_proto.visib_token != null; 3639 const is_export = blk: { 3640 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false; 3641 break :blk token_tags[maybe_export_token] == .keyword_export; 3642 }; 3643 const is_extern = blk: { 3644 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; 3645 break :blk token_tags[maybe_extern_token] == .keyword_extern; 3646 }; 3647 const has_inline_keyword = blk: { 3648 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false; 3649 break :blk token_tags[maybe_inline_token] == .keyword_inline; 3650 }; 3651 const is_noinline = blk: { 3652 const maybe_noinline_token = fn_proto.extern_export_inline_token orelse break :blk false; 3653 break :blk token_tags[maybe_noinline_token] == .keyword_noinline; 3654 }; 3655 3656 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken()); 3657 3658 // align, linksection, and addrspace is passed in the func instruction in this case. 3659 wip_members.nextDecl(is_pub, is_export, false, false); 3660 3661 var noalias_bits: u32 = 0; 3662 var params_scope = &fn_gz.base; 3663 const is_var_args = is_var_args: { 3664 var param_type_i: usize = 0; 3665 var it = fn_proto.iterate(tree); 3666 while (it.next()) |param| : (param_type_i += 1) { 3667 const is_comptime = if (param.comptime_noalias) |token| switch (token_tags[token]) { 3668 .keyword_noalias => is_comptime: { 3669 noalias_bits |= @as(u32, 1) << (std.math.cast(u5, param_type_i) orelse 3670 return astgen.failTok(token, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); 3671 break :is_comptime false; 3672 }, 3673 .keyword_comptime => true, 3674 else => false, 3675 } else false; 3676 3677 const is_anytype = if (param.anytype_ellipsis3) |token| blk: { 3678 switch (token_tags[token]) { 3679 .keyword_anytype => break :blk true, 3680 .ellipsis3 => break :is_var_args true, 3681 else => unreachable, 3682 } 3683 } else false; 3684 3685 const param_name: u32 = if (param.name_token) |name_token| blk: { 3686 const name_bytes = tree.tokenSlice(name_token); 3687 if (mem.eql(u8, "_", name_bytes)) 3688 break :blk 0; 3689 3690 const param_name = try astgen.identAsString(name_token); 3691 if (!is_extern) { 3692 try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes, .@"function parameter"); 3693 } 3694 break :blk param_name; 3695 } else if (!is_extern) { 3696 if (param.anytype_ellipsis3) |tok| { 3697 return astgen.failTok(tok, "missing parameter name", .{}); 3698 } else { 3699 ambiguous: { 3700 if (tree.nodes.items(.tag)[param.type_expr] != .identifier) break :ambiguous; 3701 const main_token = tree.nodes.items(.main_token)[param.type_expr]; 3702 const identifier_str = tree.tokenSlice(main_token); 3703 if (isPrimitive(identifier_str)) break :ambiguous; 3704 return astgen.failNodeNotes( 3705 param.type_expr, 3706 "missing parameter name or type", 3707 .{}, 3708 &[_]u32{ 3709 try astgen.errNoteNode( 3710 param.type_expr, 3711 "if this is a name, annotate its type '{s}: T'", 3712 .{identifier_str}, 3713 ), 3714 try astgen.errNoteNode( 3715 param.type_expr, 3716 "if this is a type, give it a name '<name>: {s}'", 3717 .{identifier_str}, 3718 ), 3719 }, 3720 ); 3721 } 3722 return astgen.failNode(param.type_expr, "missing parameter name", .{}); 3723 } 3724 } else 0; 3725 3726 const param_inst = if (is_anytype) param: { 3727 const name_token = param.name_token orelse param.anytype_ellipsis3.?; 3728 const tag: Zir.Inst.Tag = if (is_comptime) 3729 .param_anytype_comptime 3730 else 3731 .param_anytype; 3732 break :param try decl_gz.addStrTok(tag, param_name, name_token); 3733 } else param: { 3734 const param_type_node = param.type_expr; 3735 assert(param_type_node != 0); 3736 var param_gz = decl_gz.makeSubBlock(scope); 3737 defer param_gz.unstack(); 3738 const param_type = try expr(¶m_gz, params_scope, coerced_type_ri, param_type_node); 3739 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); 3740 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); 3741 3742 const main_tokens = tree.nodes.items(.main_token); 3743 const name_token = param.name_token orelse main_tokens[param_type_node]; 3744 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; 3745 const param_inst = try decl_gz.addParam(¶m_gz, tag, name_token, param_name, param.first_doc_comment); 3746 assert(param_inst_expected == param_inst); 3747 break :param indexToRef(param_inst); 3748 }; 3749 3750 if (param_name == 0 or is_extern) continue; 3751 3752 const sub_scope = try astgen.arena.create(Scope.LocalVal); 3753 sub_scope.* = .{ 3754 .parent = params_scope, 3755 .gen_zir = &decl_gz, 3756 .name = param_name, 3757 .inst = param_inst, 3758 .token_src = param.name_token.?, 3759 .id_cat = .@"function parameter", 3760 }; 3761 params_scope = &sub_scope.base; 3762 } 3763 break :is_var_args false; 3764 }; 3765 3766 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: { 3767 const lib_name_str = try astgen.strLitAsString(lib_name_token); 3768 const lib_name_slice = astgen.string_bytes.items[lib_name_str.index..][0..lib_name_str.len]; 3769 if (mem.indexOfScalar(u8, lib_name_slice, 0) != null) { 3770 return astgen.failTok(lib_name_token, "library name cannot contain null bytes", .{}); 3771 } else if (lib_name_str.len == 0) { 3772 return astgen.failTok(lib_name_token, "library name cannot be empty", .{}); 3773 } 3774 break :blk lib_name_str.index; 3775 } else 0; 3776 3777 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; 3778 const is_inferred_error = token_tags[maybe_bang] == .bang; 3779 3780 // After creating the function ZIR instruction, it will need to update the break 3781 // instructions inside the expression blocks for align, addrspace, cc, and ret_ty 3782 // to use the function instruction as the "block" to break from. 3783 3784 var align_gz = decl_gz.makeSubBlock(params_scope); 3785 defer align_gz.unstack(); 3786 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { 3787 const inst = try expr(&decl_gz, params_scope, coerced_align_ri, fn_proto.ast.align_expr); 3788 if (align_gz.instructionsSlice().len == 0) { 3789 // In this case we will send a len=0 body which can be encoded more efficiently. 3790 break :inst inst; 3791 } 3792 _ = try align_gz.addBreak(.break_inline, 0, inst); 3793 break :inst inst; 3794 }; 3795 3796 var addrspace_gz = decl_gz.makeSubBlock(params_scope); 3797 defer addrspace_gz.unstack(); 3798 const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: { 3799 const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .address_space_type } }, fn_proto.ast.addrspace_expr); 3800 if (addrspace_gz.instructionsSlice().len == 0) { 3801 // In this case we will send a len=0 body which can be encoded more efficiently. 3802 break :inst inst; 3803 } 3804 _ = try addrspace_gz.addBreak(.break_inline, 0, inst); 3805 break :inst inst; 3806 }; 3807 3808 var section_gz = decl_gz.makeSubBlock(params_scope); 3809 defer section_gz.unstack(); 3810 const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { 3811 const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .const_slice_u8_type } }, fn_proto.ast.section_expr); 3812 if (section_gz.instructionsSlice().len == 0) { 3813 // In this case we will send a len=0 body which can be encoded more efficiently. 3814 break :inst inst; 3815 } 3816 _ = try section_gz.addBreak(.break_inline, 0, inst); 3817 break :inst inst; 3818 }; 3819 3820 var cc_gz = decl_gz.makeSubBlock(params_scope); 3821 defer cc_gz.unstack(); 3822 const cc_ref: Zir.Inst.Ref = blk: { 3823 if (fn_proto.ast.callconv_expr != 0) { 3824 if (has_inline_keyword) { 3825 return astgen.failNode( 3826 fn_proto.ast.callconv_expr, 3827 "explicit callconv incompatible with inline keyword", 3828 .{}, 3829 ); 3830 } 3831 const inst = try expr( 3832 &decl_gz, 3833 params_scope, 3834 .{ .rl = .{ .coerced_ty = .calling_convention_type } }, 3835 fn_proto.ast.callconv_expr, 3836 ); 3837 if (cc_gz.instructionsSlice().len == 0) { 3838 // In this case we will send a len=0 body which can be encoded more efficiently. 3839 break :blk inst; 3840 } 3841 _ = try cc_gz.addBreak(.break_inline, 0, inst); 3842 break :blk inst; 3843 } else if (is_extern) { 3844 // note: https://github.com/ziglang/zig/issues/5269 3845 break :blk .calling_convention_c; 3846 } else if (has_inline_keyword) { 3847 break :blk .calling_convention_inline; 3848 } else { 3849 break :blk .none; 3850 } 3851 }; 3852 3853 var ret_gz = decl_gz.makeSubBlock(params_scope); 3854 defer ret_gz.unstack(); 3855 const ret_ref: Zir.Inst.Ref = inst: { 3856 const inst = try expr(&ret_gz, params_scope, coerced_type_ri, fn_proto.ast.return_type); 3857 if (ret_gz.instructionsSlice().len == 0) { 3858 // In this case we will send a len=0 body which can be encoded more efficiently. 3859 break :inst inst; 3860 } 3861 _ = try ret_gz.addBreak(.break_inline, 0, inst); 3862 break :inst inst; 3863 }; 3864 3865 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { 3866 if (!is_extern) { 3867 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{}); 3868 } 3869 if (is_inferred_error) { 3870 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); 3871 } 3872 break :func try decl_gz.addFunc(.{ 3873 .src_node = decl_node, 3874 .cc_ref = cc_ref, 3875 .cc_gz = &cc_gz, 3876 .align_ref = align_ref, 3877 .align_gz = &align_gz, 3878 .ret_ref = ret_ref, 3879 .ret_gz = &ret_gz, 3880 .section_ref = section_ref, 3881 .section_gz = §ion_gz, 3882 .addrspace_ref = addrspace_ref, 3883 .addrspace_gz = &addrspace_gz, 3884 .param_block = block_inst, 3885 .body_gz = null, 3886 .lib_name = lib_name, 3887 .is_var_args = is_var_args, 3888 .is_inferred_error = false, 3889 .is_test = false, 3890 .is_extern = true, 3891 .is_noinline = is_noinline, 3892 .noalias_bits = noalias_bits, 3893 }); 3894 } else func: { 3895 if (is_var_args) { 3896 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); 3897 } 3898 3899 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz 3900 fn_gz.instructions_top = ret_gz.instructions.items.len; 3901 3902 const prev_fn_block = astgen.fn_block; 3903 astgen.fn_block = &fn_gz; 3904 defer astgen.fn_block = prev_fn_block; 3905 3906 astgen.advanceSourceCursorToNode(body_node); 3907 const lbrace_line = astgen.source_line - decl_gz.decl_line; 3908 const lbrace_column = astgen.source_column; 3909 3910 _ = try expr(&fn_gz, params_scope, .{ .rl = .none }, body_node); 3911 try checkUsed(gz, &fn_gz.base, params_scope); 3912 3913 if (!fn_gz.endsWithNoReturn()) { 3914 // As our last action before the return, "pop" the error trace if needed 3915 _ = try gz.addRestoreErrRetIndex(.ret, .always); 3916 3917 // Add implicit return at end of function. 3918 _ = try fn_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node)); 3919 } 3920 3921 break :func try decl_gz.addFunc(.{ 3922 .src_node = decl_node, 3923 .cc_ref = cc_ref, 3924 .cc_gz = &cc_gz, 3925 .align_ref = align_ref, 3926 .align_gz = &align_gz, 3927 .ret_ref = ret_ref, 3928 .ret_gz = &ret_gz, 3929 .section_ref = section_ref, 3930 .section_gz = §ion_gz, 3931 .addrspace_ref = addrspace_ref, 3932 .addrspace_gz = &addrspace_gz, 3933 .lbrace_line = lbrace_line, 3934 .lbrace_column = lbrace_column, 3935 .param_block = block_inst, 3936 .body_gz = &fn_gz, 3937 .lib_name = lib_name, 3938 .is_var_args = is_var_args, 3939 .is_inferred_error = is_inferred_error, 3940 .is_test = false, 3941 .is_extern = false, 3942 .is_noinline = is_noinline, 3943 .noalias_bits = noalias_bits, 3944 }); 3945 }; 3946 3947 // We add this at the end so that its instruction index marks the end range 3948 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz. 3949 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); 3950 try decl_gz.setBlockBody(block_inst); 3951 3952 { 3953 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); 3954 const casted = @bitCast([4]u32, contents_hash); 3955 wip_members.appendToDeclSlice(&casted); 3956 } 3957 { 3958 const line_delta = decl_gz.decl_line - gz.decl_line; 3959 wip_members.appendToDecl(line_delta); 3960 } 3961 wip_members.appendToDecl(fn_name_str_index); 3962 wip_members.appendToDecl(block_inst); 3963 wip_members.appendToDecl(doc_comment_index); 3964 } 3965 3966 fn globalVarDecl( 3967 astgen: *AstGen, 3968 gz: *GenZir, 3969 scope: *Scope, 3970 wip_members: *WipMembers, 3971 node: Ast.Node.Index, 3972 var_decl: Ast.full.VarDecl, 3973 ) InnerError!void { 3974 const tree = astgen.tree; 3975 const token_tags = tree.tokens.items(.tag); 3976 3977 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; 3978 // We do this at the beginning so that the instruction index marks the range start 3979 // of the top level declaration. 3980 const block_inst = try gz.makeBlockInst(.block_inline, node); 3981 3982 const name_token = var_decl.ast.mut_token + 1; 3983 const name_str_index = try astgen.identAsString(name_token); 3984 astgen.advanceSourceCursorToNode(node); 3985 3986 var block_scope: GenZir = .{ 3987 .parent = scope, 3988 .decl_node_index = node, 3989 .decl_line = astgen.source_line, 3990 .astgen = astgen, 3991 .force_comptime = true, 3992 .anon_name_strategy = .parent, 3993 .instructions = gz.instructions, 3994 .instructions_top = gz.instructions.items.len, 3995 }; 3996 defer block_scope.unstack(); 3997 3998 const is_pub = var_decl.visib_token != null; 3999 const is_export = blk: { 4000 const maybe_export_token = var_decl.extern_export_token orelse break :blk false; 4001 break :blk token_tags[maybe_export_token] == .keyword_export; 4002 }; 4003 const is_extern = blk: { 4004 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; 4005 break :blk token_tags[maybe_extern_token] == .keyword_extern; 4006 }; 4007 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: { 4008 break :inst try expr(&block_scope, &block_scope.base, align_ri, var_decl.ast.align_node); 4009 }; 4010 const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: { 4011 break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node); 4012 }; 4013 const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { 4014 break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .const_slice_u8_type } }, var_decl.ast.section_node); 4015 }; 4016 const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; 4017 wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace); 4018 4019 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: { 4020 if (!is_mutable) { 4021 return astgen.failTok(tok, "threadlocal variable cannot be constant", .{}); 4022 } 4023 break :blk true; 4024 } else false; 4025 4026 const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: { 4027 const lib_name_str = try astgen.strLitAsString(lib_name_token); 4028 const lib_name_slice = astgen.string_bytes.items[lib_name_str.index..][0..lib_name_str.len]; 4029 if (mem.indexOfScalar(u8, lib_name_slice, 0) != null) { 4030 return astgen.failTok(lib_name_token, "library name cannot contain null bytes", .{}); 4031 } else if (lib_name_str.len == 0) { 4032 return astgen.failTok(lib_name_token, "library name cannot be empty", .{}); 4033 } 4034 break :blk lib_name_str.index; 4035 } else 0; 4036 4037 const doc_comment_index = try astgen.docCommentAsString(var_decl.firstToken()); 4038 4039 assert(var_decl.comptime_token == null); // handled by parser 4040 4041 const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: { 4042 if (is_extern) { 4043 return astgen.failNode( 4044 var_decl.ast.init_node, 4045 "extern variables have no initializers", 4046 .{}, 4047 ); 4048 } 4049 4050 const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0) 4051 try expr( 4052 &block_scope, 4053 &block_scope.base, 4054 .{ .rl = .{ .ty = .type_type } }, 4055 var_decl.ast.type_node, 4056 ) 4057 else 4058 .none; 4059 4060 const init_inst = try expr( 4061 &block_scope, 4062 &block_scope.base, 4063 if (type_inst != .none) .{ .rl = .{ .ty = type_inst } } else .{ .rl = .none }, 4064 var_decl.ast.init_node, 4065 ); 4066 4067 if (is_mutable) { 4068 const var_inst = try block_scope.addVar(.{ 4069 .var_type = type_inst, 4070 .lib_name = 0, 4071 .align_inst = .none, // passed via the decls data 4072 .init = init_inst, 4073 .is_extern = false, 4074 .is_threadlocal = is_threadlocal, 4075 }); 4076 break :vi var_inst; 4077 } else { 4078 break :vi init_inst; 4079 } 4080 } else if (!is_extern) { 4081 return astgen.failNode(node, "variables must be initialized", .{}); 4082 } else if (var_decl.ast.type_node != 0) vi: { 4083 // Extern variable which has an explicit type. 4084 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node); 4085 4086 const var_inst = try block_scope.addVar(.{ 4087 .var_type = type_inst, 4088 .lib_name = lib_name, 4089 .align_inst = .none, // passed via the decls data 4090 .init = .none, 4091 .is_extern = true, 4092 .is_threadlocal = is_threadlocal, 4093 }); 4094 break :vi var_inst; 4095 } else { 4096 return astgen.failNode(node, "unable to infer variable type", .{}); 4097 }; 4098 // We do this at the end so that the instruction index marks the end 4099 // range of a top level declaration. 4100 _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); 4101 try block_scope.setBlockBody(block_inst); 4102 4103 { 4104 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 4105 const casted = @bitCast([4]u32, contents_hash); 4106 wip_members.appendToDeclSlice(&casted); 4107 } 4108 { 4109 const line_delta = block_scope.decl_line - gz.decl_line; 4110 wip_members.appendToDecl(line_delta); 4111 } 4112 wip_members.appendToDecl(name_str_index); 4113 wip_members.appendToDecl(block_inst); 4114 wip_members.appendToDecl(doc_comment_index); // doc_comment wip 4115 if (align_inst != .none) { 4116 wip_members.appendToDecl(@enumToInt(align_inst)); 4117 } 4118 if (has_section_or_addrspace) { 4119 wip_members.appendToDecl(@enumToInt(section_inst)); 4120 wip_members.appendToDecl(@enumToInt(addrspace_inst)); 4121 } 4122 } 4123 4124 fn comptimeDecl( 4125 astgen: *AstGen, 4126 gz: *GenZir, 4127 scope: *Scope, 4128 wip_members: *WipMembers, 4129 node: Ast.Node.Index, 4130 ) InnerError!void { 4131 const tree = astgen.tree; 4132 const node_datas = tree.nodes.items(.data); 4133 const body_node = node_datas[node].lhs; 4134 4135 // Up top so the ZIR instruction index marks the start range of this 4136 // top-level declaration. 4137 const block_inst = try gz.makeBlockInst(.block_inline, node); 4138 wip_members.nextDecl(false, false, false, false); 4139 astgen.advanceSourceCursorToNode(node); 4140 4141 var decl_block: GenZir = .{ 4142 .force_comptime = true, 4143 .decl_node_index = node, 4144 .decl_line = astgen.source_line, 4145 .parent = scope, 4146 .astgen = astgen, 4147 .instructions = gz.instructions, 4148 .instructions_top = gz.instructions.items.len, 4149 }; 4150 defer decl_block.unstack(); 4151 4152 const block_result = try expr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node); 4153 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) { 4154 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value); 4155 } 4156 try decl_block.setBlockBody(block_inst); 4157 4158 { 4159 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 4160 const casted = @bitCast([4]u32, contents_hash); 4161 wip_members.appendToDeclSlice(&casted); 4162 } 4163 { 4164 const line_delta = decl_block.decl_line - gz.decl_line; 4165 wip_members.appendToDecl(line_delta); 4166 } 4167 wip_members.appendToDecl(0); 4168 wip_members.appendToDecl(block_inst); 4169 wip_members.appendToDecl(0); // no doc comments on comptime decls 4170 } 4171 4172 fn usingnamespaceDecl( 4173 astgen: *AstGen, 4174 gz: *GenZir, 4175 scope: *Scope, 4176 wip_members: *WipMembers, 4177 node: Ast.Node.Index, 4178 ) InnerError!void { 4179 const tree = astgen.tree; 4180 const node_datas = tree.nodes.items(.data); 4181 4182 const type_expr = node_datas[node].lhs; 4183 const is_pub = blk: { 4184 const main_tokens = tree.nodes.items(.main_token); 4185 const token_tags = tree.tokens.items(.tag); 4186 const main_token = main_tokens[node]; 4187 break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub); 4188 }; 4189 // Up top so the ZIR instruction index marks the start range of this 4190 // top-level declaration. 4191 const block_inst = try gz.makeBlockInst(.block_inline, node); 4192 wip_members.nextDecl(is_pub, true, false, false); 4193 astgen.advanceSourceCursorToNode(node); 4194 4195 var decl_block: GenZir = .{ 4196 .force_comptime = true, 4197 .decl_node_index = node, 4198 .decl_line = astgen.source_line, 4199 .parent = scope, 4200 .astgen = astgen, 4201 .instructions = gz.instructions, 4202 .instructions_top = gz.instructions.items.len, 4203 }; 4204 defer decl_block.unstack(); 4205 4206 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr); 4207 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst); 4208 try decl_block.setBlockBody(block_inst); 4209 4210 { 4211 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 4212 const casted = @bitCast([4]u32, contents_hash); 4213 wip_members.appendToDeclSlice(&casted); 4214 } 4215 { 4216 const line_delta = decl_block.decl_line - gz.decl_line; 4217 wip_members.appendToDecl(line_delta); 4218 } 4219 wip_members.appendToDecl(0); 4220 wip_members.appendToDecl(block_inst); 4221 wip_members.appendToDecl(0); // no doc comments on usingnamespace decls 4222 } 4223 4224 fn testDecl( 4225 astgen: *AstGen, 4226 gz: *GenZir, 4227 scope: *Scope, 4228 wip_members: *WipMembers, 4229 node: Ast.Node.Index, 4230 ) InnerError!void { 4231 const tree = astgen.tree; 4232 const node_datas = tree.nodes.items(.data); 4233 const body_node = node_datas[node].rhs; 4234 4235 // Up top so the ZIR instruction index marks the start range of this 4236 // top-level declaration. 4237 const block_inst = try gz.makeBlockInst(.block_inline, node); 4238 4239 wip_members.nextDecl(false, false, false, false); 4240 astgen.advanceSourceCursorToNode(node); 4241 4242 var decl_block: GenZir = .{ 4243 .force_comptime = true, 4244 .decl_node_index = node, 4245 .decl_line = astgen.source_line, 4246 .parent = scope, 4247 .astgen = astgen, 4248 .instructions = gz.instructions, 4249 .instructions_top = gz.instructions.items.len, 4250 }; 4251 defer decl_block.unstack(); 4252 4253 const main_tokens = tree.nodes.items(.main_token); 4254 const token_tags = tree.tokens.items(.tag); 4255 const test_token = main_tokens[node]; 4256 const test_name_token = test_token + 1; 4257 const test_name_token_tag = token_tags[test_name_token]; 4258 const is_decltest = test_name_token_tag == .identifier; 4259 const test_name: u32 = blk: { 4260 if (test_name_token_tag == .string_literal) { 4261 break :blk try astgen.testNameString(test_name_token); 4262 } else if (test_name_token_tag == .identifier) { 4263 const ident_name_raw = tree.tokenSlice(test_name_token); 4264 4265 if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{}); 4266 4267 // if not @"" syntax, just use raw token slice 4268 if (ident_name_raw[0] != '@') { 4269 if (isPrimitive(ident_name_raw)) return astgen.failTok(test_name_token, "cannot test a primitive", .{}); 4270 } 4271 4272 // Local variables, including function parameters. 4273 const name_str_index = try astgen.identAsString(test_name_token); 4274 var s = scope; 4275 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 4276 var num_namespaces_out: u32 = 0; 4277 var capturing_namespace: ?*Scope.Namespace = null; 4278 while (true) switch (s.tag) { 4279 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope 4280 .gen_zir => s = s.cast(GenZir).?.parent, 4281 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 4282 .namespace => { 4283 const ns = s.cast(Scope.Namespace).?; 4284 if (ns.decls.get(name_str_index)) |i| { 4285 if (found_already) |f| { 4286 return astgen.failTokNotes(test_name_token, "ambiguous reference", .{}, &.{ 4287 try astgen.errNoteNode(f, "declared here", .{}), 4288 try astgen.errNoteNode(i, "also declared here", .{}), 4289 }); 4290 } 4291 // We found a match but must continue looking for ambiguous references to decls. 4292 found_already = i; 4293 } 4294 num_namespaces_out += 1; 4295 capturing_namespace = ns; 4296 s = ns.parent; 4297 }, 4298 .top => break, 4299 }; 4300 if (found_already == null) { 4301 const ident_name = try astgen.identifierTokenString(test_name_token); 4302 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name}); 4303 } 4304 4305 break :blk name_str_index; 4306 } 4307 // String table index 1 has a special meaning here of test decl with no name. 4308 break :blk 1; 4309 }; 4310 4311 var fn_block: GenZir = .{ 4312 .force_comptime = false, 4313 .decl_node_index = node, 4314 .decl_line = decl_block.decl_line, 4315 .parent = &decl_block.base, 4316 .astgen = astgen, 4317 .instructions = decl_block.instructions, 4318 .instructions_top = decl_block.instructions.items.len, 4319 }; 4320 defer fn_block.unstack(); 4321 4322 const prev_fn_block = astgen.fn_block; 4323 astgen.fn_block = &fn_block; 4324 defer astgen.fn_block = prev_fn_block; 4325 4326 astgen.advanceSourceCursorToNode(body_node); 4327 const lbrace_line = astgen.source_line - decl_block.decl_line; 4328 const lbrace_column = astgen.source_column; 4329 4330 const block_result = try expr(&fn_block, &fn_block.base, .{ .rl = .none }, body_node); 4331 if (fn_block.isEmpty() or !fn_block.refIsNoReturn(block_result)) { 4332 4333 // As our last action before the return, "pop" the error trace if needed 4334 _ = try gz.addRestoreErrRetIndex(.ret, .always); 4335 4336 // Add implicit return at end of function. 4337 _ = try fn_block.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node)); 4338 } 4339 4340 const func_inst = try decl_block.addFunc(.{ 4341 .src_node = node, 4342 4343 .cc_ref = .none, 4344 .cc_gz = null, 4345 .align_ref = .none, 4346 .align_gz = null, 4347 .ret_ref = .void_type, 4348 .ret_gz = null, 4349 .section_ref = .none, 4350 .section_gz = null, 4351 .addrspace_ref = .none, 4352 .addrspace_gz = null, 4353 4354 .lbrace_line = lbrace_line, 4355 .lbrace_column = lbrace_column, 4356 .param_block = block_inst, 4357 .body_gz = &fn_block, 4358 .lib_name = 0, 4359 .is_var_args = false, 4360 .is_inferred_error = true, 4361 .is_test = true, 4362 .is_extern = false, 4363 .is_noinline = false, 4364 .noalias_bits = 0, 4365 }); 4366 4367 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); 4368 try decl_block.setBlockBody(block_inst); 4369 4370 { 4371 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 4372 const casted = @bitCast([4]u32, contents_hash); 4373 wip_members.appendToDeclSlice(&casted); 4374 } 4375 { 4376 const line_delta = decl_block.decl_line - gz.decl_line; 4377 wip_members.appendToDecl(line_delta); 4378 } 4379 if (is_decltest) 4380 wip_members.appendToDecl(2) // 2 here means that it is a decltest, look at doc comment for name 4381 else 4382 wip_members.appendToDecl(test_name); 4383 wip_members.appendToDecl(block_inst); 4384 if (is_decltest) 4385 wip_members.appendToDecl(test_name) // the doc comment on a decltest represents it's name 4386 else 4387 wip_members.appendToDecl(0); // no doc comments on test decls 4388 } 4389 4390 fn structDeclInner( 4391 gz: *GenZir, 4392 scope: *Scope, 4393 node: Ast.Node.Index, 4394 container_decl: Ast.full.ContainerDecl, 4395 layout: std.builtin.Type.ContainerLayout, 4396 backing_int_node: Ast.Node.Index, 4397 ) InnerError!Zir.Inst.Ref { 4398 const decl_inst = try gz.reserveInstructionIndex(); 4399 4400 if (container_decl.ast.members.len == 0 and backing_int_node == 0) { 4401 try gz.setStruct(decl_inst, .{ 4402 .src_node = node, 4403 .layout = layout, 4404 .fields_len = 0, 4405 .decls_len = 0, 4406 .backing_int_ref = .none, 4407 .backing_int_body_len = 0, 4408 .known_non_opv = false, 4409 .known_comptime_only = false, 4410 .is_tuple = false, 4411 }); 4412 return indexToRef(decl_inst); 4413 } 4414 4415 const astgen = gz.astgen; 4416 const gpa = astgen.gpa; 4417 const tree = astgen.tree; 4418 4419 var namespace: Scope.Namespace = .{ 4420 .parent = scope, 4421 .node = node, 4422 .inst = decl_inst, 4423 .declaring_gz = gz, 4424 }; 4425 defer namespace.deinit(gpa); 4426 4427 // The struct_decl instruction introduces a scope in which the decls of the struct 4428 // are in scope, so that field types, alignments, and default value expressions 4429 // can refer to decls within the struct itself. 4430 astgen.advanceSourceCursorToNode(node); 4431 var block_scope: GenZir = .{ 4432 .parent = &namespace.base, 4433 .decl_node_index = node, 4434 .decl_line = gz.decl_line, 4435 .astgen = astgen, 4436 .force_comptime = true, 4437 .instructions = gz.instructions, 4438 .instructions_top = gz.instructions.items.len, 4439 }; 4440 defer block_scope.unstack(); 4441 4442 const scratch_top = astgen.scratch.items.len; 4443 defer astgen.scratch.items.len = scratch_top; 4444 4445 var backing_int_body_len: usize = 0; 4446 const backing_int_ref: Zir.Inst.Ref = blk: { 4447 if (backing_int_node != 0) { 4448 if (layout != .Packed) { 4449 return astgen.failNode(backing_int_node, "non-packed struct does not support backing integer type", .{}); 4450 } else { 4451 const backing_int_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node); 4452 if (!block_scope.isEmpty()) { 4453 if (!block_scope.endsWithNoReturn()) { 4454 _ = try block_scope.addBreak(.break_inline, decl_inst, backing_int_ref); 4455 } 4456 4457 const body = block_scope.instructionsSlice(); 4458 const old_scratch_len = astgen.scratch.items.len; 4459 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); 4460 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 4461 backing_int_body_len = astgen.scratch.items.len - old_scratch_len; 4462 block_scope.instructions.items.len = block_scope.instructions_top; 4463 } 4464 break :blk backing_int_ref; 4465 } 4466 } else { 4467 break :blk .none; 4468 } 4469 }; 4470 4471 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); 4472 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count); 4473 4474 const bits_per_field = 4; 4475 const max_field_size = 5; 4476 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); 4477 defer wip_members.deinit(); 4478 4479 // We will use the scratch buffer, starting here, for the bodies: 4480 // bodies: { // for every fields_len 4481 // field_type_body_inst: Inst, // for each field_type_body_len 4482 // align_body_inst: Inst, // for each align_body_len 4483 // init_body_inst: Inst, // for each init_body_len 4484 // } 4485 // Note that the scratch buffer is simultaneously being used by WipMembers, however 4486 // it will not access any elements beyond this point in the ArrayList. It also 4487 // accesses via the ArrayList items field so it can handle the scratch buffer being 4488 // reallocated. 4489 // No defer needed here because it is handled by `wip_members.deinit()` above. 4490 const bodies_start = astgen.scratch.items.len; 4491 4492 var is_tuple = false; 4493 const node_tags = tree.nodes.items(.tag); 4494 for (container_decl.ast.members) |member_node| { 4495 switch (node_tags[member_node]) { 4496 .container_field_init => is_tuple = tree.containerFieldInit(member_node).ast.tuple_like, 4497 .container_field_align => is_tuple = tree.containerFieldAlign(member_node).ast.tuple_like, 4498 .container_field => is_tuple = tree.containerField(member_node).ast.tuple_like, 4499 else => continue, 4500 } 4501 if (is_tuple) break; 4502 } 4503 if (is_tuple) for (container_decl.ast.members) |member_node| { 4504 switch (node_tags[member_node]) { 4505 .container_field_init, 4506 .container_field_align, 4507 .container_field, 4508 .@"comptime", 4509 => continue, 4510 else => { 4511 return astgen.failNode(member_node, "tuple declarations cannot contain declarations", .{}); 4512 }, 4513 } 4514 }; 4515 4516 var known_non_opv = false; 4517 var known_comptime_only = false; 4518 for (container_decl.ast.members) |member_node| { 4519 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { 4520 .decl => continue, 4521 .field => |field| field, 4522 }; 4523 4524 if (!is_tuple) { 4525 member.convertToNonTupleLike(astgen.tree.nodes); 4526 assert(!member.ast.tuple_like); 4527 4528 const field_name = try astgen.identAsString(member.ast.main_token); 4529 wip_members.appendToField(field_name); 4530 } else if (!member.ast.tuple_like) { 4531 return astgen.failTok(member.ast.main_token, "tuple field has a name", .{}); 4532 } 4533 4534 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4535 wip_members.appendToField(doc_comment_index); 4536 4537 if (member.ast.type_expr == 0) { 4538 return astgen.failTok(member.ast.main_token, "struct field missing type", .{}); 4539 } 4540 4541 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 4542 const have_type_body = !block_scope.isEmpty(); 4543 const have_align = member.ast.align_expr != 0; 4544 const have_value = member.ast.value_expr != 0; 4545 const is_comptime = member.comptime_token != null; 4546 4547 if (is_comptime and layout == .Packed) { 4548 return astgen.failTok(member.comptime_token.?, "packed struct fields cannot be marked comptime", .{}); 4549 } else if (is_comptime and layout == .Extern) { 4550 return astgen.failTok(member.comptime_token.?, "extern struct fields cannot be marked comptime", .{}); 4551 } 4552 4553 if (!is_comptime) { 4554 known_non_opv = known_non_opv or 4555 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr); 4556 known_comptime_only = known_comptime_only or 4557 nodeImpliesComptimeOnly(tree, member.ast.type_expr); 4558 } 4559 wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, have_type_body }); 4560 4561 if (have_type_body) { 4562 if (!block_scope.endsWithNoReturn()) { 4563 _ = try block_scope.addBreak(.break_inline, decl_inst, field_type); 4564 } 4565 const body = block_scope.instructionsSlice(); 4566 const old_scratch_len = astgen.scratch.items.len; 4567 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); 4568 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 4569 wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len)); 4570 block_scope.instructions.items.len = block_scope.instructions_top; 4571 } else { 4572 wip_members.appendToField(@enumToInt(field_type)); 4573 } 4574 4575 if (have_align) { 4576 if (layout == .Packed) { 4577 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{}); 4578 } 4579 const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, member.ast.align_expr); 4580 if (!block_scope.endsWithNoReturn()) { 4581 _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref); 4582 } 4583 const body = block_scope.instructionsSlice(); 4584 const old_scratch_len = astgen.scratch.items.len; 4585 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); 4586 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 4587 wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len)); 4588 block_scope.instructions.items.len = block_scope.instructions_top; 4589 } 4590 4591 if (have_value) { 4592 const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = field_type } }; 4593 4594 const default_inst = try expr(&block_scope, &namespace.base, ri, member.ast.value_expr); 4595 if (!block_scope.endsWithNoReturn()) { 4596 _ = try block_scope.addBreak(.break_inline, decl_inst, default_inst); 4597 } 4598 const body = block_scope.instructionsSlice(); 4599 const old_scratch_len = astgen.scratch.items.len; 4600 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body)); 4601 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 4602 wip_members.appendToField(@intCast(u32, astgen.scratch.items.len - old_scratch_len)); 4603 block_scope.instructions.items.len = block_scope.instructions_top; 4604 } else if (member.comptime_token) |comptime_token| { 4605 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{}); 4606 } 4607 } 4608 4609 try gz.setStruct(decl_inst, .{ 4610 .src_node = node, 4611 .layout = layout, 4612 .fields_len = field_count, 4613 .decls_len = decl_count, 4614 .backing_int_ref = backing_int_ref, 4615 .backing_int_body_len = @intCast(u32, backing_int_body_len), 4616 .known_non_opv = known_non_opv, 4617 .known_comptime_only = known_comptime_only, 4618 .is_tuple = is_tuple, 4619 }); 4620 4621 wip_members.finishBits(bits_per_field); 4622 const decls_slice = wip_members.declsSlice(); 4623 const fields_slice = wip_members.fieldsSlice(); 4624 const bodies_slice = astgen.scratch.items[bodies_start..]; 4625 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + 4626 decls_slice.len + fields_slice.len + bodies_slice.len); 4627 astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]); 4628 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4629 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4630 astgen.extra.appendSliceAssumeCapacity(bodies_slice); 4631 4632 block_scope.unstack(); 4633 try gz.addNamespaceCaptures(&namespace); 4634 return indexToRef(decl_inst); 4635 } 4636 4637 fn unionDeclInner( 4638 gz: *GenZir, 4639 scope: *Scope, 4640 node: Ast.Node.Index, 4641 members: []const Ast.Node.Index, 4642 layout: std.builtin.Type.ContainerLayout, 4643 arg_node: Ast.Node.Index, 4644 auto_enum_tok: ?Ast.TokenIndex, 4645 ) InnerError!Zir.Inst.Ref { 4646 const decl_inst = try gz.reserveInstructionIndex(); 4647 4648 const astgen = gz.astgen; 4649 const gpa = astgen.gpa; 4650 4651 var namespace: Scope.Namespace = .{ 4652 .parent = scope, 4653 .node = node, 4654 .inst = decl_inst, 4655 .declaring_gz = gz, 4656 }; 4657 defer namespace.deinit(gpa); 4658 4659 // The union_decl instruction introduces a scope in which the decls of the union 4660 // are in scope, so that field types, alignments, and default value expressions 4661 // can refer to decls within the union itself. 4662 astgen.advanceSourceCursorToNode(node); 4663 var block_scope: GenZir = .{ 4664 .parent = &namespace.base, 4665 .decl_node_index = node, 4666 .decl_line = gz.decl_line, 4667 .astgen = astgen, 4668 .force_comptime = true, 4669 .instructions = gz.instructions, 4670 .instructions_top = gz.instructions.items.len, 4671 }; 4672 defer block_scope.unstack(); 4673 4674 const decl_count = try astgen.scanDecls(&namespace, members); 4675 const field_count = @intCast(u32, members.len - decl_count); 4676 4677 if (layout != .Auto and (auto_enum_tok != null or arg_node != 0)) { 4678 const layout_str = if (layout == .Extern) "extern" else "packed"; 4679 if (arg_node != 0) { 4680 return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{layout_str}); 4681 } else { 4682 return astgen.failTok(auto_enum_tok.?, "{s} union does not support enum tag type", .{layout_str}); 4683 } 4684 } 4685 4686 const arg_inst: Zir.Inst.Ref = if (arg_node != 0) 4687 try typeExpr(&block_scope, &namespace.base, arg_node) 4688 else 4689 .none; 4690 4691 const bits_per_field = 4; 4692 const max_field_size = 5; 4693 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); 4694 defer wip_members.deinit(); 4695 4696 for (members) |member_node| { 4697 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { 4698 .decl => continue, 4699 .field => |field| field, 4700 }; 4701 member.convertToNonTupleLike(astgen.tree.nodes); 4702 if (member.ast.tuple_like) { 4703 return astgen.failTok(member.ast.main_token, "union field missing name", .{}); 4704 } 4705 if (member.comptime_token) |comptime_token| { 4706 return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); 4707 } 4708 4709 const field_name = try astgen.identAsString(member.ast.main_token); 4710 wip_members.appendToField(field_name); 4711 4712 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4713 wip_members.appendToField(doc_comment_index); 4714 4715 const have_type = member.ast.type_expr != 0; 4716 const have_align = member.ast.align_expr != 0; 4717 const have_value = member.ast.value_expr != 0; 4718 const unused = false; 4719 wip_members.nextField(bits_per_field, .{ have_type, have_align, have_value, unused }); 4720 4721 if (have_type) { 4722 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 4723 wip_members.appendToField(@enumToInt(field_type)); 4724 } else if (arg_inst == .none and auto_enum_tok == null) { 4725 return astgen.failNode(member_node, "union field missing type", .{}); 4726 } 4727 if (have_align) { 4728 const align_inst = try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .u32_type } }, member.ast.align_expr); 4729 wip_members.appendToField(@enumToInt(align_inst)); 4730 } 4731 if (have_value) { 4732 if (arg_inst == .none) { 4733 return astgen.failNodeNotes( 4734 node, 4735 "explicitly valued tagged union missing integer tag type", 4736 .{}, 4737 &[_]u32{ 4738 try astgen.errNoteNode( 4739 member.ast.value_expr, 4740 "tag value specified here", 4741 .{}, 4742 ), 4743 }, 4744 ); 4745 } 4746 if (auto_enum_tok == null) { 4747 return astgen.failNodeNotes( 4748 node, 4749 "explicitly valued tagged union requires inferred enum tag type", 4750 .{}, 4751 &[_]u32{ 4752 try astgen.errNoteNode( 4753 member.ast.value_expr, 4754 "tag value specified here", 4755 .{}, 4756 ), 4757 }, 4758 ); 4759 } 4760 const tag_value = try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr); 4761 wip_members.appendToField(@enumToInt(tag_value)); 4762 } 4763 } 4764 4765 if (!block_scope.isEmpty()) { 4766 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4767 } 4768 4769 const body = block_scope.instructionsSlice(); 4770 const body_len = astgen.countBodyLenAfterFixups(body); 4771 4772 try gz.setUnion(decl_inst, .{ 4773 .src_node = node, 4774 .layout = layout, 4775 .tag_type = arg_inst, 4776 .body_len = body_len, 4777 .fields_len = field_count, 4778 .decls_len = decl_count, 4779 .auto_enum_tag = auto_enum_tok != null, 4780 }); 4781 4782 wip_members.finishBits(bits_per_field); 4783 const decls_slice = wip_members.declsSlice(); 4784 const fields_slice = wip_members.fieldsSlice(); 4785 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len); 4786 astgen.extra.appendSliceAssumeCapacity(decls_slice); 4787 astgen.appendBodyWithFixups(body); 4788 astgen.extra.appendSliceAssumeCapacity(fields_slice); 4789 4790 block_scope.unstack(); 4791 try gz.addNamespaceCaptures(&namespace); 4792 return indexToRef(decl_inst); 4793 } 4794 4795 fn containerDecl( 4796 gz: *GenZir, 4797 scope: *Scope, 4798 ri: ResultInfo, 4799 node: Ast.Node.Index, 4800 container_decl: Ast.full.ContainerDecl, 4801 ) InnerError!Zir.Inst.Ref { 4802 const astgen = gz.astgen; 4803 const gpa = astgen.gpa; 4804 const tree = astgen.tree; 4805 const token_tags = tree.tokens.items(.tag); 4806 const node_tags = tree.nodes.items(.tag); 4807 4808 const prev_fn_block = astgen.fn_block; 4809 astgen.fn_block = null; 4810 defer astgen.fn_block = prev_fn_block; 4811 4812 // We must not create any types until Sema. Here the goal is only to generate 4813 // ZIR for all the field types, alignments, and default value expressions. 4814 4815 switch (token_tags[container_decl.ast.main_token]) { 4816 .keyword_struct => { 4817 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4818 .keyword_packed => std.builtin.Type.ContainerLayout.Packed, 4819 .keyword_extern => std.builtin.Type.ContainerLayout.Extern, 4820 else => unreachable, 4821 } else std.builtin.Type.ContainerLayout.Auto; 4822 4823 const result = try structDeclInner(gz, scope, node, container_decl, layout, container_decl.ast.arg); 4824 return rvalue(gz, ri, result, node); 4825 }, 4826 .keyword_union => { 4827 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4828 .keyword_packed => std.builtin.Type.ContainerLayout.Packed, 4829 .keyword_extern => std.builtin.Type.ContainerLayout.Extern, 4830 else => unreachable, 4831 } else std.builtin.Type.ContainerLayout.Auto; 4832 4833 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, container_decl.ast.enum_token); 4834 return rvalue(gz, ri, result, node); 4835 }, 4836 .keyword_enum => { 4837 if (container_decl.layout_token) |t| { 4838 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{}); 4839 } 4840 // Count total fields as well as how many have explicitly provided tag values. 4841 const counts = blk: { 4842 var values: usize = 0; 4843 var total_fields: usize = 0; 4844 var decls: usize = 0; 4845 var nonexhaustive_node: Ast.Node.Index = 0; 4846 var nonfinal_nonexhaustive = false; 4847 for (container_decl.ast.members) |member_node| { 4848 var member = switch (node_tags[member_node]) { 4849 .container_field_init => tree.containerFieldInit(member_node), 4850 .container_field_align => tree.containerFieldAlign(member_node), 4851 .container_field => tree.containerField(member_node), 4852 else => { 4853 decls += 1; 4854 continue; 4855 }, 4856 }; 4857 member.convertToNonTupleLike(astgen.tree.nodes); 4858 if (member.ast.tuple_like) { 4859 return astgen.failTok(member.ast.main_token, "enum field missing name", .{}); 4860 } 4861 if (member.comptime_token) |comptime_token| { 4862 return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{}); 4863 } 4864 if (member.ast.type_expr != 0) { 4865 return astgen.failNodeNotes( 4866 member.ast.type_expr, 4867 "enum fields do not have types", 4868 .{}, 4869 &[_]u32{ 4870 try astgen.errNoteNode( 4871 node, 4872 "consider 'union(enum)' here to make it a tagged union", 4873 .{}, 4874 ), 4875 }, 4876 ); 4877 } 4878 if (member.ast.align_expr != 0) { 4879 return astgen.failNode(member.ast.align_expr, "enum fields cannot be aligned", .{}); 4880 } 4881 4882 const name_token = member.ast.main_token; 4883 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { 4884 if (nonexhaustive_node != 0) { 4885 return astgen.failNodeNotes( 4886 member_node, 4887 "redundant non-exhaustive enum mark", 4888 .{}, 4889 &[_]u32{ 4890 try astgen.errNoteNode( 4891 nonexhaustive_node, 4892 "other mark here", 4893 .{}, 4894 ), 4895 }, 4896 ); 4897 } 4898 nonexhaustive_node = member_node; 4899 if (member.ast.value_expr != 0) { 4900 return astgen.failNode(member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{}); 4901 } 4902 continue; 4903 } else if (nonexhaustive_node != 0) { 4904 nonfinal_nonexhaustive = true; 4905 } 4906 total_fields += 1; 4907 if (member.ast.value_expr != 0) { 4908 if (container_decl.ast.arg == 0) { 4909 return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{}); 4910 } 4911 values += 1; 4912 } 4913 } 4914 if (nonfinal_nonexhaustive) { 4915 return astgen.failNode(nonexhaustive_node, "'_' field of non-exhaustive enum must be last", .{}); 4916 } 4917 break :blk .{ 4918 .total_fields = total_fields, 4919 .values = values, 4920 .decls = decls, 4921 .nonexhaustive_node = nonexhaustive_node, 4922 }; 4923 }; 4924 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { 4925 try astgen.appendErrorNodeNotes( 4926 node, 4927 "non-exhaustive enum missing integer tag type", 4928 .{}, 4929 &[_]u32{ 4930 try astgen.errNoteNode( 4931 counts.nonexhaustive_node, 4932 "marked non-exhaustive here", 4933 .{}, 4934 ), 4935 }, 4936 ); 4937 } 4938 // In this case we must generate ZIR code for the tag values, similar to 4939 // how structs are handled above. 4940 const nonexhaustive = counts.nonexhaustive_node != 0; 4941 4942 const decl_inst = try gz.reserveInstructionIndex(); 4943 4944 var namespace: Scope.Namespace = .{ 4945 .parent = scope, 4946 .node = node, 4947 .inst = decl_inst, 4948 .declaring_gz = gz, 4949 }; 4950 defer namespace.deinit(gpa); 4951 4952 // The enum_decl instruction introduces a scope in which the decls of the enum 4953 // are in scope, so that tag values can refer to decls within the enum itself. 4954 astgen.advanceSourceCursorToNode(node); 4955 var block_scope: GenZir = .{ 4956 .parent = &namespace.base, 4957 .decl_node_index = node, 4958 .decl_line = gz.decl_line, 4959 .astgen = astgen, 4960 .force_comptime = true, 4961 .instructions = gz.instructions, 4962 .instructions_top = gz.instructions.items.len, 4963 }; 4964 defer block_scope.unstack(); 4965 4966 _ = try astgen.scanDecls(&namespace, container_decl.ast.members); 4967 4968 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) 4969 try comptimeExpr(&block_scope, &namespace.base, .{ .rl = .{ .ty = .type_type } }, container_decl.ast.arg) 4970 else 4971 .none; 4972 4973 const bits_per_field = 1; 4974 const max_field_size = 3; 4975 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(u32, counts.decls), @intCast(u32, counts.total_fields), bits_per_field, max_field_size); 4976 defer wip_members.deinit(); 4977 4978 for (container_decl.ast.members) |member_node| { 4979 if (member_node == counts.nonexhaustive_node) 4980 continue; 4981 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { 4982 .decl => continue, 4983 .field => |field| field, 4984 }; 4985 member.convertToNonTupleLike(astgen.tree.nodes); 4986 assert(member.comptime_token == null); 4987 assert(member.ast.type_expr == 0); 4988 assert(member.ast.align_expr == 0); 4989 4990 const field_name = try astgen.identAsString(member.ast.main_token); 4991 wip_members.appendToField(field_name); 4992 4993 const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); 4994 wip_members.appendToField(doc_comment_index); 4995 4996 const have_value = member.ast.value_expr != 0; 4997 wip_members.nextField(bits_per_field, .{have_value}); 4998 4999 if (have_value) { 5000 if (arg_inst == .none) { 5001 return astgen.failNodeNotes( 5002 node, 5003 "explicitly valued enum missing integer tag type", 5004 .{}, 5005 &[_]u32{ 5006 try astgen.errNoteNode( 5007 member.ast.value_expr, 5008 "tag value specified here", 5009 .{}, 5010 ), 5011 }, 5012 ); 5013 } 5014 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr); 5015 wip_members.appendToField(@enumToInt(tag_value_inst)); 5016 } 5017 } 5018 5019 if (!block_scope.isEmpty()) { 5020 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 5021 } 5022 5023 const body = block_scope.instructionsSlice(); 5024 const body_len = astgen.countBodyLenAfterFixups(body); 5025 5026 try gz.setEnum(decl_inst, .{ 5027 .src_node = node, 5028 .nonexhaustive = nonexhaustive, 5029 .tag_type = arg_inst, 5030 .body_len = body_len, 5031 .fields_len = @intCast(u32, counts.total_fields), 5032 .decls_len = @intCast(u32, counts.decls), 5033 }); 5034 5035 wip_members.finishBits(bits_per_field); 5036 const decls_slice = wip_members.declsSlice(); 5037 const fields_slice = wip_members.fieldsSlice(); 5038 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body_len + fields_slice.len); 5039 astgen.extra.appendSliceAssumeCapacity(decls_slice); 5040 astgen.appendBodyWithFixups(body); 5041 astgen.extra.appendSliceAssumeCapacity(fields_slice); 5042 5043 block_scope.unstack(); 5044 try gz.addNamespaceCaptures(&namespace); 5045 return rvalue(gz, ri, indexToRef(decl_inst), node); 5046 }, 5047 .keyword_opaque => { 5048 assert(container_decl.ast.arg == 0); 5049 5050 const decl_inst = try gz.reserveInstructionIndex(); 5051 5052 var namespace: Scope.Namespace = .{ 5053 .parent = scope, 5054 .node = node, 5055 .inst = decl_inst, 5056 .declaring_gz = gz, 5057 }; 5058 defer namespace.deinit(gpa); 5059 5060 astgen.advanceSourceCursorToNode(node); 5061 var block_scope: GenZir = .{ 5062 .parent = &namespace.base, 5063 .decl_node_index = node, 5064 .decl_line = gz.decl_line, 5065 .astgen = astgen, 5066 .force_comptime = true, 5067 .instructions = gz.instructions, 5068 .instructions_top = gz.instructions.items.len, 5069 }; 5070 defer block_scope.unstack(); 5071 5072 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); 5073 5074 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); 5075 defer wip_members.deinit(); 5076 5077 for (container_decl.ast.members) |member_node| { 5078 const res = try containerMember(&block_scope, &namespace.base, &wip_members, member_node); 5079 if (res == .field) { 5080 return astgen.failNode(member_node, "opaque types cannot have fields", .{}); 5081 } 5082 } 5083 5084 try gz.setOpaque(decl_inst, .{ 5085 .src_node = node, 5086 .decls_len = decl_count, 5087 }); 5088 5089 wip_members.finishBits(0); 5090 const decls_slice = wip_members.declsSlice(); 5091 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len); 5092 astgen.extra.appendSliceAssumeCapacity(decls_slice); 5093 5094 block_scope.unstack(); 5095 try gz.addNamespaceCaptures(&namespace); 5096 return rvalue(gz, ri, indexToRef(decl_inst), node); 5097 }, 5098 else => unreachable, 5099 } 5100 } 5101 5102 const ContainerMemberResult = union(enum) { decl, field: Ast.full.ContainerField }; 5103 5104 fn containerMember( 5105 gz: *GenZir, 5106 scope: *Scope, 5107 wip_members: *WipMembers, 5108 member_node: Ast.Node.Index, 5109 ) InnerError!ContainerMemberResult { 5110 const astgen = gz.astgen; 5111 const tree = astgen.tree; 5112 const node_tags = tree.nodes.items(.tag); 5113 const node_datas = tree.nodes.items(.data); 5114 switch (node_tags[member_node]) { 5115 .container_field_init => return ContainerMemberResult{ .field = tree.containerFieldInit(member_node) }, 5116 .container_field_align => return ContainerMemberResult{ .field = tree.containerFieldAlign(member_node) }, 5117 .container_field => return ContainerMemberResult{ .field = tree.containerField(member_node) }, 5118 5119 .fn_decl => { 5120 const fn_proto = node_datas[member_node].lhs; 5121 const body = node_datas[member_node].rhs; 5122 switch (node_tags[fn_proto]) { 5123 .fn_proto_simple => { 5124 var params: [1]Ast.Node.Index = undefined; 5125 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { 5126 error.OutOfMemory => return error.OutOfMemory, 5127 error.AnalysisFail => {}, 5128 }; 5129 }, 5130 .fn_proto_multi => { 5131 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { 5132 error.OutOfMemory => return error.OutOfMemory, 5133 error.AnalysisFail => {}, 5134 }; 5135 }, 5136 .fn_proto_one => { 5137 var params: [1]Ast.Node.Index = undefined; 5138 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { 5139 error.OutOfMemory => return error.OutOfMemory, 5140 error.AnalysisFail => {}, 5141 }; 5142 }, 5143 .fn_proto => { 5144 astgen.fnDecl(gz, scope, wip_members, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { 5145 error.OutOfMemory => return error.OutOfMemory, 5146 error.AnalysisFail => {}, 5147 }; 5148 }, 5149 else => unreachable, 5150 } 5151 }, 5152 .fn_proto_simple => { 5153 var params: [1]Ast.Node.Index = undefined; 5154 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { 5155 error.OutOfMemory => return error.OutOfMemory, 5156 error.AnalysisFail => {}, 5157 }; 5158 }, 5159 .fn_proto_multi => { 5160 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { 5161 error.OutOfMemory => return error.OutOfMemory, 5162 error.AnalysisFail => {}, 5163 }; 5164 }, 5165 .fn_proto_one => { 5166 var params: [1]Ast.Node.Index = undefined; 5167 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { 5168 error.OutOfMemory => return error.OutOfMemory, 5169 error.AnalysisFail => {}, 5170 }; 5171 }, 5172 .fn_proto => { 5173 astgen.fnDecl(gz, scope, wip_members, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { 5174 error.OutOfMemory => return error.OutOfMemory, 5175 error.AnalysisFail => {}, 5176 }; 5177 }, 5178 5179 .global_var_decl => { 5180 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { 5181 error.OutOfMemory => return error.OutOfMemory, 5182 error.AnalysisFail => {}, 5183 }; 5184 }, 5185 .local_var_decl => { 5186 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { 5187 error.OutOfMemory => return error.OutOfMemory, 5188 error.AnalysisFail => {}, 5189 }; 5190 }, 5191 .simple_var_decl => { 5192 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { 5193 error.OutOfMemory => return error.OutOfMemory, 5194 error.AnalysisFail => {}, 5195 }; 5196 }, 5197 .aligned_var_decl => { 5198 astgen.globalVarDecl(gz, scope, wip_members, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { 5199 error.OutOfMemory => return error.OutOfMemory, 5200 error.AnalysisFail => {}, 5201 }; 5202 }, 5203 5204 .@"comptime" => { 5205 astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 5206 error.OutOfMemory => return error.OutOfMemory, 5207 error.AnalysisFail => {}, 5208 }; 5209 }, 5210 .@"usingnamespace" => { 5211 astgen.usingnamespaceDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 5212 error.OutOfMemory => return error.OutOfMemory, 5213 error.AnalysisFail => {}, 5214 }; 5215 }, 5216 .test_decl => { 5217 astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) { 5218 error.OutOfMemory => return error.OutOfMemory, 5219 error.AnalysisFail => {}, 5220 }; 5221 }, 5222 else => unreachable, 5223 } 5224 return .decl; 5225 } 5226 5227 fn errorSetDecl(gz: *GenZir, ri: ResultInfo, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 5228 const astgen = gz.astgen; 5229 const gpa = astgen.gpa; 5230 const tree = astgen.tree; 5231 const main_tokens = tree.nodes.items(.main_token); 5232 const token_tags = tree.tokens.items(.tag); 5233 5234 const payload_index = try reserveExtra(astgen, @typeInfo(Zir.Inst.ErrorSetDecl).Struct.fields.len); 5235 var fields_len: usize = 0; 5236 { 5237 var idents: std.AutoHashMapUnmanaged(u32, Ast.TokenIndex) = .{}; 5238 defer idents.deinit(gpa); 5239 5240 const error_token = main_tokens[node]; 5241 var tok_i = error_token + 2; 5242 while (true) : (tok_i += 1) { 5243 switch (token_tags[tok_i]) { 5244 .doc_comment, .comma => {}, 5245 .identifier => { 5246 const str_index = try astgen.identAsString(tok_i); 5247 const gop = try idents.getOrPut(gpa, str_index); 5248 if (gop.found_existing) { 5249 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(str_index))); 5250 defer gpa.free(name); 5251 return astgen.failTokNotes( 5252 tok_i, 5253 "duplicate error set field '{s}'", 5254 .{name}, 5255 &[_]u32{ 5256 try astgen.errNoteTok( 5257 gop.value_ptr.*, 5258 "previous declaration here", 5259 .{}, 5260 ), 5261 }, 5262 ); 5263 } 5264 gop.value_ptr.* = tok_i; 5265 5266 try astgen.extra.ensureUnusedCapacity(gpa, 2); 5267 astgen.extra.appendAssumeCapacity(str_index); 5268 const doc_comment_index = try astgen.docCommentAsString(tok_i); 5269 astgen.extra.appendAssumeCapacity(doc_comment_index); 5270 fields_len += 1; 5271 }, 5272 .r_brace => break, 5273 else => unreachable, 5274 } 5275 } 5276 } 5277 5278 setExtra(astgen, payload_index, Zir.Inst.ErrorSetDecl{ 5279 .fields_len = @intCast(u32, fields_len), 5280 }); 5281 const result = try gz.addPlNodePayloadIndex(.error_set_decl, node, payload_index); 5282 return rvalue(gz, ri, result, node); 5283 } 5284 5285 fn tryExpr( 5286 parent_gz: *GenZir, 5287 scope: *Scope, 5288 ri: ResultInfo, 5289 node: Ast.Node.Index, 5290 operand_node: Ast.Node.Index, 5291 ) InnerError!Zir.Inst.Ref { 5292 const astgen = parent_gz.astgen; 5293 5294 const fn_block = astgen.fn_block orelse { 5295 return astgen.failNode(node, "'try' outside function scope", .{}); 5296 }; 5297 5298 if (parent_gz.any_defer_node != 0) { 5299 return astgen.failNodeNotes(node, "'try' not allowed inside defer expression", .{}, &.{ 5300 try astgen.errNoteNode( 5301 parent_gz.any_defer_node, 5302 "defer expression here", 5303 .{}, 5304 ), 5305 }); 5306 } 5307 5308 // Ensure debug line/column information is emitted for this try expression. 5309 // Then we will save the line/column so that we can emit another one that goes 5310 // "backwards" because we want to evaluate the operand, but then put the debug 5311 // info back at the try keyword for error return tracing. 5312 if (!parent_gz.force_comptime) { 5313 try emitDbgNode(parent_gz, node); 5314 } 5315 const try_line = astgen.source_line - parent_gz.decl_line; 5316 const try_column = astgen.source_column; 5317 5318 const operand_ri: ResultInfo = switch (ri.rl) { 5319 .ref => .{ .rl = .ref, .ctx = .error_handling_expr }, 5320 else => .{ .rl = .none, .ctx = .error_handling_expr }, 5321 }; 5322 // This could be a pointer or value depending on the `ri` parameter. 5323 const operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, node); 5324 const is_inline = parent_gz.force_comptime; 5325 const is_inline_bit = @as(u2, @boolToInt(is_inline)); 5326 const is_ptr_bit = @as(u2, @boolToInt(operand_ri.rl == .ref)) << 1; 5327 const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) { 5328 0b00 => .@"try", 5329 0b01 => .@"try", 5330 //0b01 => .try_inline, 5331 0b10 => .try_ptr, 5332 0b11 => .try_ptr, 5333 //0b11 => .try_ptr_inline, 5334 }; 5335 const try_inst = try parent_gz.makeBlockInst(block_tag, node); 5336 try parent_gz.instructions.append(astgen.gpa, try_inst); 5337 5338 var else_scope = parent_gz.makeSubBlock(scope); 5339 defer else_scope.unstack(); 5340 5341 const err_tag = switch (ri.rl) { 5342 .ref => Zir.Inst.Tag.err_union_code_ptr, 5343 else => Zir.Inst.Tag.err_union_code, 5344 }; 5345 const err_code = try else_scope.addUnNode(err_tag, operand, node); 5346 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); 5347 try emitDbgStmt(&else_scope, try_line, try_column); 5348 _ = try else_scope.addUnNode(.ret_node, err_code, node); 5349 5350 try else_scope.setTryBody(try_inst, operand); 5351 const result = indexToRef(try_inst); 5352 switch (ri.rl) { 5353 .ref => return result, 5354 else => return rvalue(parent_gz, ri, result, node), 5355 } 5356 } 5357 5358 fn orelseCatchExpr( 5359 parent_gz: *GenZir, 5360 scope: *Scope, 5361 ri: ResultInfo, 5362 node: Ast.Node.Index, 5363 lhs: Ast.Node.Index, 5364 cond_op: Zir.Inst.Tag, 5365 unwrap_op: Zir.Inst.Tag, 5366 unwrap_code_op: Zir.Inst.Tag, 5367 rhs: Ast.Node.Index, 5368 payload_token: ?Ast.TokenIndex, 5369 ) InnerError!Zir.Inst.Ref { 5370 const astgen = parent_gz.astgen; 5371 const tree = astgen.tree; 5372 5373 const do_err_trace = astgen.fn_block != null and (cond_op == .is_non_err or cond_op == .is_non_err_ptr); 5374 5375 var block_scope = parent_gz.makeSubBlock(scope); 5376 block_scope.setBreakResultInfo(ri); 5377 defer block_scope.unstack(); 5378 5379 const operand_ri: ResultInfo = switch (block_scope.break_result_info.rl) { 5380 .ref => .{ .rl = .ref, .ctx = if (do_err_trace) .error_handling_expr else .none }, 5381 else => .{ .rl = .none, .ctx = if (do_err_trace) .error_handling_expr else .none }, 5382 }; 5383 block_scope.break_count += 1; 5384 // This could be a pointer or value depending on the `operand_ri` parameter. 5385 // We cannot use `block_scope.break_result_info` because that has the bare 5386 // type, whereas this expression has the optional type. Later we make 5387 // up for this fact by calling rvalue on the else branch. 5388 const operand = try reachableExpr(&block_scope, &block_scope.base, operand_ri, lhs, rhs); 5389 const cond = try block_scope.addUnNode(cond_op, operand, node); 5390 const condbr_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .condbr_inline else .condbr; 5391 const condbr = try block_scope.addCondBr(condbr_tag, node); 5392 5393 const block_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .block_inline else .block; 5394 const block = try parent_gz.makeBlockInst(block_tag, node); 5395 try block_scope.setBlockBody(block); 5396 // block_scope unstacked now, can add new instructions to parent_gz 5397 try parent_gz.instructions.append(astgen.gpa, block); 5398 5399 var then_scope = block_scope.makeSubBlock(scope); 5400 defer then_scope.unstack(); 5401 5402 // This could be a pointer or value depending on `unwrap_op`. 5403 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); 5404 const then_result = switch (ri.rl) { 5405 .ref => unwrapped_payload, 5406 else => try rvalue(&then_scope, block_scope.break_result_info, unwrapped_payload, node), 5407 }; 5408 5409 var else_scope = block_scope.makeSubBlock(scope); 5410 defer else_scope.unstack(); 5411 5412 // We know that the operand (almost certainly) modified the error return trace, 5413 // so signal to Sema that it should save the new index for restoring later. 5414 if (do_err_trace and nodeMayAppendToErrorTrace(tree, lhs)) 5415 _ = try else_scope.addSaveErrRetIndex(.always); 5416 5417 var err_val_scope: Scope.LocalVal = undefined; 5418 const else_sub_scope = blk: { 5419 const payload = payload_token orelse break :blk &else_scope.base; 5420 const err_str = tree.tokenSlice(payload); 5421 if (mem.eql(u8, err_str, "_")) { 5422 return astgen.failTok(payload, "discard of error capture; omit it instead", .{}); 5423 } 5424 const err_name = try astgen.identAsString(payload); 5425 5426 try astgen.detectLocalShadowing(scope, err_name, payload, err_str, .capture); 5427 5428 err_val_scope = .{ 5429 .parent = &else_scope.base, 5430 .gen_zir = &else_scope, 5431 .name = err_name, 5432 .inst = try else_scope.addUnNode(unwrap_code_op, operand, node), 5433 .token_src = payload, 5434 .id_cat = .capture, 5435 }; 5436 break :blk &err_val_scope.base; 5437 }; 5438 5439 const else_result = try expr(&else_scope, else_sub_scope, block_scope.break_result_info, rhs); 5440 if (!else_scope.endsWithNoReturn()) { 5441 block_scope.break_count += 1; 5442 5443 // As our last action before the break, "pop" the error trace if needed 5444 if (do_err_trace) 5445 try restoreErrRetIndex(&else_scope, .{ .block = block }, block_scope.break_result_info, rhs, else_result); 5446 } 5447 try checkUsed(parent_gz, &else_scope.base, else_sub_scope); 5448 5449 // We hold off on the break instructions as well as copying the then/else 5450 // instructions into place until we know whether to keep store_to_block_ptr 5451 // instructions or not. 5452 5453 const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; 5454 const result = try finishThenElseBlock( 5455 parent_gz, 5456 ri, 5457 node, 5458 &block_scope, 5459 &then_scope, 5460 &else_scope, 5461 condbr, 5462 cond, 5463 then_result, 5464 else_result, 5465 block, 5466 block, 5467 break_tag, 5468 ); 5469 return result; 5470 } 5471 5472 /// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`. 5473 fn finishThenElseBlock( 5474 parent_gz: *GenZir, 5475 ri: ResultInfo, 5476 node: Ast.Node.Index, 5477 block_scope: *GenZir, 5478 then_scope: *GenZir, 5479 else_scope: *GenZir, 5480 condbr: Zir.Inst.Index, 5481 cond: Zir.Inst.Ref, 5482 then_result: Zir.Inst.Ref, 5483 else_result: Zir.Inst.Ref, 5484 main_block: Zir.Inst.Index, 5485 then_break_block: Zir.Inst.Index, 5486 break_tag: Zir.Inst.Tag, 5487 ) InnerError!Zir.Inst.Ref { 5488 // We now have enough information to decide whether the result instruction should 5489 // be communicated via result location pointer or break instructions. 5490 const strat = ri.rl.strategy(block_scope); 5491 // else_scope may be stacked on then_scope, so check for no-return on then_scope manually 5492 const tags = parent_gz.astgen.instructions.items(.tag); 5493 const then_slice = then_scope.instructionsSliceUpto(else_scope); 5494 const then_no_return = then_slice.len > 0 and tags[then_slice[then_slice.len - 1]].isNoReturn(); 5495 const else_no_return = else_scope.endsWithNoReturn(); 5496 5497 switch (strat.tag) { 5498 .break_void => { 5499 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, .void_value) else 0; 5500 const else_break = if (!else_no_return) try else_scope.makeBreak(break_tag, main_block, .void_value) else 0; 5501 assert(!strat.elide_store_to_block_ptr_instructions); 5502 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break); 5503 return indexToRef(main_block); 5504 }, 5505 .break_operand => { 5506 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, then_result) else 0; 5507 const else_break = if (else_result == .none) 5508 try else_scope.makeBreak(break_tag, main_block, .void_value) 5509 else if (!else_no_return) 5510 try else_scope.makeBreak(break_tag, main_block, else_result) 5511 else 5512 0; 5513 5514 if (strat.elide_store_to_block_ptr_instructions) { 5515 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, then_break, else_scope, else_break, block_scope.rl_ptr); 5516 } else { 5517 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break); 5518 } 5519 const block_ref = indexToRef(main_block); 5520 switch (ri.rl) { 5521 .ref => return block_ref, 5522 else => return rvalue(parent_gz, ri, block_ref, node), 5523 } 5524 }, 5525 } 5526 } 5527 5528 /// Return whether the identifier names of two tokens are equal. Resolves @"" 5529 /// tokens without allocating. 5530 /// OK in theory it could do it without allocating. This implementation 5531 /// allocates when the @"" form is used. 5532 fn tokenIdentEql(astgen: *AstGen, token1: Ast.TokenIndex, token2: Ast.TokenIndex) !bool { 5533 const ident_name_1 = try astgen.identifierTokenString(token1); 5534 const ident_name_2 = try astgen.identifierTokenString(token2); 5535 return mem.eql(u8, ident_name_1, ident_name_2); 5536 } 5537 5538 fn fieldAccess( 5539 gz: *GenZir, 5540 scope: *Scope, 5541 ri: ResultInfo, 5542 node: Ast.Node.Index, 5543 ) InnerError!Zir.Inst.Ref { 5544 switch (ri.rl) { 5545 .ref => return addFieldAccess(.field_ptr, gz, scope, .{ .rl = .ref }, node), 5546 else => { 5547 const access = try addFieldAccess(.field_val, gz, scope, .{ .rl = .none }, node); 5548 return rvalue(gz, ri, access, node); 5549 }, 5550 } 5551 } 5552 5553 fn addFieldAccess( 5554 tag: Zir.Inst.Tag, 5555 gz: *GenZir, 5556 scope: *Scope, 5557 lhs_ri: ResultInfo, 5558 node: Ast.Node.Index, 5559 ) InnerError!Zir.Inst.Ref { 5560 const astgen = gz.astgen; 5561 const tree = astgen.tree; 5562 const main_tokens = tree.nodes.items(.main_token); 5563 const node_datas = tree.nodes.items(.data); 5564 5565 const object_node = node_datas[node].lhs; 5566 const dot_token = main_tokens[node]; 5567 const field_ident = dot_token + 1; 5568 const str_index = try astgen.identAsString(field_ident); 5569 const lhs = try expr(gz, scope, lhs_ri, object_node); 5570 5571 maybeAdvanceSourceCursorToMainToken(gz, node); 5572 const line = gz.astgen.source_line - gz.decl_line; 5573 const column = gz.astgen.source_column; 5574 try emitDbgStmt(gz, line, column); 5575 5576 return gz.addPlNode(tag, node, Zir.Inst.Field{ 5577 .lhs = lhs, 5578 .field_name_start = str_index, 5579 }); 5580 } 5581 5582 fn arrayAccess( 5583 gz: *GenZir, 5584 scope: *Scope, 5585 ri: ResultInfo, 5586 node: Ast.Node.Index, 5587 ) InnerError!Zir.Inst.Ref { 5588 const tree = gz.astgen.tree; 5589 const node_datas = tree.nodes.items(.data); 5590 switch (ri.rl) { 5591 .ref => { 5592 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs); 5593 5594 maybeAdvanceSourceCursorToMainToken(gz, node); 5595 const line = gz.astgen.source_line - gz.decl_line; 5596 const column = gz.astgen.source_column; 5597 5598 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = .usize_type } }, node_datas[node].rhs); 5599 try emitDbgStmt(gz, line, column); 5600 5601 return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }); 5602 }, 5603 else => { 5604 const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs); 5605 5606 maybeAdvanceSourceCursorToMainToken(gz, node); 5607 const line = gz.astgen.source_line - gz.decl_line; 5608 const column = gz.astgen.source_column; 5609 5610 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = .usize_type } }, node_datas[node].rhs); 5611 try emitDbgStmt(gz, line, column); 5612 5613 return rvalue(gz, ri, try gz.addPlNode(.elem_val_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }), node); 5614 }, 5615 } 5616 } 5617 5618 fn simpleBinOp( 5619 gz: *GenZir, 5620 scope: *Scope, 5621 ri: ResultInfo, 5622 node: Ast.Node.Index, 5623 op_inst_tag: Zir.Inst.Tag, 5624 ) InnerError!Zir.Inst.Ref { 5625 const astgen = gz.astgen; 5626 const tree = astgen.tree; 5627 const node_datas = tree.nodes.items(.data); 5628 5629 if (op_inst_tag == .cmp_neq or op_inst_tag == .cmp_eq) { 5630 const node_tags = tree.nodes.items(.tag); 5631 const str = if (op_inst_tag == .cmp_eq) "==" else "!="; 5632 if (node_tags[node_datas[node].lhs] == .string_literal or 5633 node_tags[node_datas[node].rhs] == .string_literal) 5634 return astgen.failNode(node, "cannot compare strings with {s}", .{str}); 5635 } 5636 5637 const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node); 5638 var line: u32 = undefined; 5639 var column: u32 = undefined; 5640 switch (op_inst_tag) { 5641 .add, .sub, .mul, .div, .mod_rem => { 5642 maybeAdvanceSourceCursorToMainToken(gz, node); 5643 line = gz.astgen.source_line - gz.decl_line; 5644 column = gz.astgen.source_column; 5645 }, 5646 else => {}, 5647 } 5648 const rhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].rhs, node); 5649 5650 switch (op_inst_tag) { 5651 .add, .sub, .mul, .div, .mod_rem => { 5652 try emitDbgStmt(gz, line, column); 5653 }, 5654 else => {}, 5655 } 5656 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }); 5657 return rvalue(gz, ri, result, node); 5658 } 5659 5660 fn simpleStrTok( 5661 gz: *GenZir, 5662 ri: ResultInfo, 5663 ident_token: Ast.TokenIndex, 5664 node: Ast.Node.Index, 5665 op_inst_tag: Zir.Inst.Tag, 5666 ) InnerError!Zir.Inst.Ref { 5667 const astgen = gz.astgen; 5668 const str_index = try astgen.identAsString(ident_token); 5669 const result = try gz.addStrTok(op_inst_tag, str_index, ident_token); 5670 return rvalue(gz, ri, result, node); 5671 } 5672 5673 fn boolBinOp( 5674 gz: *GenZir, 5675 scope: *Scope, 5676 ri: ResultInfo, 5677 node: Ast.Node.Index, 5678 zir_tag: Zir.Inst.Tag, 5679 ) InnerError!Zir.Inst.Ref { 5680 const astgen = gz.astgen; 5681 const tree = astgen.tree; 5682 const node_datas = tree.nodes.items(.data); 5683 5684 const lhs = try expr(gz, scope, bool_ri, node_datas[node].lhs); 5685 const bool_br = try gz.addBoolBr(zir_tag, lhs); 5686 5687 var rhs_scope = gz.makeSubBlock(scope); 5688 defer rhs_scope.unstack(); 5689 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_ri, node_datas[node].rhs); 5690 if (!gz.refIsNoReturn(rhs)) { 5691 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); 5692 } 5693 try rhs_scope.setBoolBrBody(bool_br); 5694 5695 const block_ref = indexToRef(bool_br); 5696 return rvalue(gz, ri, block_ref, node); 5697 } 5698 5699 fn ifExpr( 5700 parent_gz: *GenZir, 5701 scope: *Scope, 5702 ri: ResultInfo, 5703 node: Ast.Node.Index, 5704 if_full: Ast.full.If, 5705 ) InnerError!Zir.Inst.Ref { 5706 const astgen = parent_gz.astgen; 5707 const tree = astgen.tree; 5708 const token_tags = tree.tokens.items(.tag); 5709 5710 const do_err_trace = astgen.fn_block != null and if_full.error_token != null; 5711 5712 var block_scope = parent_gz.makeSubBlock(scope); 5713 block_scope.setBreakResultInfo(ri); 5714 defer block_scope.unstack(); 5715 5716 const payload_is_ref = if (if_full.payload_token) |payload_token| 5717 token_tags[payload_token] == .asterisk 5718 else 5719 false; 5720 5721 try emitDbgNode(parent_gz, if_full.ast.cond_expr); 5722 const cond: struct { 5723 inst: Zir.Inst.Ref, 5724 bool_bit: Zir.Inst.Ref, 5725 } = c: { 5726 if (if_full.error_token) |_| { 5727 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none, .ctx = .error_handling_expr }; 5728 const err_union = try expr(&block_scope, &block_scope.base, cond_ri, if_full.ast.cond_expr); 5729 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 5730 break :c .{ 5731 .inst = err_union, 5732 .bool_bit = try block_scope.addUnNode(tag, err_union, if_full.ast.cond_expr), 5733 }; 5734 } else if (if_full.payload_token) |_| { 5735 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; 5736 const optional = try expr(&block_scope, &block_scope.base, cond_ri, if_full.ast.cond_expr); 5737 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 5738 break :c .{ 5739 .inst = optional, 5740 .bool_bit = try block_scope.addUnNode(tag, optional, if_full.ast.cond_expr), 5741 }; 5742 } else { 5743 const cond = try expr(&block_scope, &block_scope.base, bool_ri, if_full.ast.cond_expr); 5744 break :c .{ 5745 .inst = cond, 5746 .bool_bit = cond, 5747 }; 5748 } 5749 }; 5750 5751 const condbr_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .condbr_inline else .condbr; 5752 const condbr = try block_scope.addCondBr(condbr_tag, node); 5753 5754 const block_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .block_inline else .block; 5755 const block = try parent_gz.makeBlockInst(block_tag, node); 5756 try block_scope.setBlockBody(block); 5757 // block_scope unstacked now, can add new instructions to parent_gz 5758 try parent_gz.instructions.append(astgen.gpa, block); 5759 5760 var then_scope = parent_gz.makeSubBlock(scope); 5761 defer then_scope.unstack(); 5762 5763 var payload_val_scope: Scope.LocalVal = undefined; 5764 5765 try then_scope.addDbgBlockBegin(); 5766 const then_sub_scope = s: { 5767 if (if_full.error_token != null) { 5768 if (if_full.payload_token) |payload_token| { 5769 const tag: Zir.Inst.Tag = if (payload_is_ref) 5770 .err_union_payload_unsafe_ptr 5771 else 5772 .err_union_payload_unsafe; 5773 const payload_inst = try then_scope.addUnNode(tag, cond.inst, if_full.ast.then_expr); 5774 const token_name_index = payload_token + @boolToInt(payload_is_ref); 5775 const ident_name = try astgen.identAsString(token_name_index); 5776 const token_name_str = tree.tokenSlice(token_name_index); 5777 if (mem.eql(u8, "_", token_name_str)) 5778 break :s &then_scope.base; 5779 try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index, token_name_str, .capture); 5780 payload_val_scope = .{ 5781 .parent = &then_scope.base, 5782 .gen_zir = &then_scope, 5783 .name = ident_name, 5784 .inst = payload_inst, 5785 .token_src = payload_token, 5786 .id_cat = .capture, 5787 }; 5788 try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5789 break :s &payload_val_scope.base; 5790 } else { 5791 _ = try then_scope.addUnNode(.ensure_err_union_payload_void, cond.inst, node); 5792 break :s &then_scope.base; 5793 } 5794 } else if (if_full.payload_token) |payload_token| { 5795 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5796 const tag: Zir.Inst.Tag = if (payload_is_ref) 5797 .optional_payload_unsafe_ptr 5798 else 5799 .optional_payload_unsafe; 5800 const ident_bytes = tree.tokenSlice(ident_token); 5801 if (mem.eql(u8, "_", ident_bytes)) 5802 break :s &then_scope.base; 5803 const payload_inst = try then_scope.addUnNode(tag, cond.inst, if_full.ast.then_expr); 5804 const ident_name = try astgen.identAsString(ident_token); 5805 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes, .capture); 5806 payload_val_scope = .{ 5807 .parent = &then_scope.base, 5808 .gen_zir = &then_scope, 5809 .name = ident_name, 5810 .inst = payload_inst, 5811 .token_src = ident_token, 5812 .id_cat = .capture, 5813 }; 5814 try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5815 break :s &payload_val_scope.base; 5816 } else { 5817 break :s &then_scope.base; 5818 } 5819 }; 5820 5821 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_info, if_full.ast.then_expr); 5822 if (!then_scope.endsWithNoReturn()) { 5823 block_scope.break_count += 1; 5824 } 5825 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5826 try then_scope.addDbgBlockEnd(); 5827 // We hold off on the break instructions as well as copying the then/else 5828 // instructions into place until we know whether to keep store_to_block_ptr 5829 // instructions or not. 5830 5831 var else_scope = parent_gz.makeSubBlock(scope); 5832 defer else_scope.unstack(); 5833 5834 // We know that the operand (almost certainly) modified the error return trace, 5835 // so signal to Sema that it should save the new index for restoring later. 5836 if (do_err_trace and nodeMayAppendToErrorTrace(tree, if_full.ast.cond_expr)) 5837 _ = try else_scope.addSaveErrRetIndex(.always); 5838 5839 const else_node = if_full.ast.else_expr; 5840 const else_info: struct { 5841 src: Ast.Node.Index, 5842 result: Zir.Inst.Ref, 5843 } = if (else_node != 0) blk: { 5844 try else_scope.addDbgBlockBegin(); 5845 const sub_scope = s: { 5846 if (if_full.error_token) |error_token| { 5847 const tag: Zir.Inst.Tag = if (payload_is_ref) 5848 .err_union_code_ptr 5849 else 5850 .err_union_code; 5851 const payload_inst = try else_scope.addUnNode(tag, cond.inst, if_full.ast.cond_expr); 5852 const ident_name = try astgen.identAsString(error_token); 5853 const error_token_str = tree.tokenSlice(error_token); 5854 if (mem.eql(u8, "_", error_token_str)) 5855 break :s &else_scope.base; 5856 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, error_token_str, .capture); 5857 payload_val_scope = .{ 5858 .parent = &else_scope.base, 5859 .gen_zir = &else_scope, 5860 .name = ident_name, 5861 .inst = payload_inst, 5862 .token_src = error_token, 5863 .id_cat = .capture, 5864 }; 5865 try else_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst); 5866 break :s &payload_val_scope.base; 5867 } else { 5868 break :s &else_scope.base; 5869 } 5870 }; 5871 const e = try expr(&else_scope, sub_scope, block_scope.break_result_info, else_node); 5872 if (!else_scope.endsWithNoReturn()) { 5873 block_scope.break_count += 1; 5874 5875 // As our last action before the break, "pop" the error trace if needed 5876 if (do_err_trace) 5877 try restoreErrRetIndex(&else_scope, .{ .block = block }, block_scope.break_result_info, else_node, e); 5878 } 5879 try checkUsed(parent_gz, &else_scope.base, sub_scope); 5880 try else_scope.addDbgBlockEnd(); 5881 break :blk .{ 5882 .src = else_node, 5883 .result = e, 5884 }; 5885 } else .{ 5886 .src = if_full.ast.then_expr, 5887 .result = switch (ri.rl) { 5888 // Explicitly store void to ptr result loc if there is no else branch 5889 .ptr, .block_ptr => try rvalue(&else_scope, ri, .void_value, node), 5890 else => .none, 5891 }, 5892 }; 5893 5894 const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; 5895 const result = try finishThenElseBlock( 5896 parent_gz, 5897 ri, 5898 node, 5899 &block_scope, 5900 &then_scope, 5901 &else_scope, 5902 condbr, 5903 cond.bool_bit, 5904 then_result, 5905 else_info.result, 5906 block, 5907 block, 5908 break_tag, 5909 ); 5910 return result; 5911 } 5912 5913 /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. 5914 fn setCondBrPayload( 5915 condbr: Zir.Inst.Index, 5916 cond: Zir.Inst.Ref, 5917 then_scope: *GenZir, 5918 then_break: Zir.Inst.Index, 5919 else_scope: *GenZir, 5920 else_break: Zir.Inst.Index, 5921 ) !void { 5922 defer then_scope.unstack(); 5923 defer else_scope.unstack(); 5924 const astgen = then_scope.astgen; 5925 const then_body = then_scope.instructionsSliceUpto(else_scope); 5926 const else_body = else_scope.instructionsSlice(); 5927 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(then_break != 0); 5928 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(else_break != 0); 5929 try astgen.extra.ensureUnusedCapacity( 5930 astgen.gpa, 5931 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len, 5932 ); 5933 5934 const zir_datas = astgen.instructions.items(.data); 5935 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5936 .condition = cond, 5937 .then_body_len = then_body_len, 5938 .else_body_len = else_body_len, 5939 }); 5940 astgen.appendBodyWithFixups(then_body); 5941 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break); 5942 astgen.appendBodyWithFixups(else_body); 5943 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break); 5944 } 5945 5946 /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. 5947 fn setCondBrPayloadElideBlockStorePtr( 5948 condbr: Zir.Inst.Index, 5949 cond: Zir.Inst.Ref, 5950 then_scope: *GenZir, 5951 then_break: Zir.Inst.Index, 5952 else_scope: *GenZir, 5953 else_break: Zir.Inst.Index, 5954 block_ptr: Zir.Inst.Ref, 5955 ) !void { 5956 defer then_scope.unstack(); 5957 defer else_scope.unstack(); 5958 const astgen = then_scope.astgen; 5959 const then_body = then_scope.instructionsSliceUpto(else_scope); 5960 const else_body = else_scope.instructionsSlice(); 5961 const has_then_break = then_break != 0; 5962 const has_else_break = else_break != 0; 5963 const then_body_len = astgen.countBodyLenAfterFixups(then_body) + @boolToInt(has_then_break); 5964 const else_body_len = astgen.countBodyLenAfterFixups(else_body) + @boolToInt(has_else_break); 5965 try astgen.extra.ensureUnusedCapacity( 5966 astgen.gpa, 5967 @typeInfo(Zir.Inst.CondBr).Struct.fields.len + then_body_len + else_body_len, 5968 ); 5969 5970 const zir_tags = astgen.instructions.items(.tag); 5971 const zir_datas = astgen.instructions.items(.data); 5972 5973 const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5974 .condition = cond, 5975 .then_body_len = then_body_len, 5976 .else_body_len = else_body_len, 5977 }); 5978 zir_datas[condbr].pl_node.payload_index = condbr_pl; 5979 const then_body_len_index = condbr_pl + 1; 5980 const else_body_len_index = condbr_pl + 2; 5981 5982 // The break instructions need to have their operands coerced if the 5983 // switch's result location is a `ty`. In this case we overwrite the 5984 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 5985 // it as the break operand. 5986 // This corresponds to similar code in `labeledBlockExpr`. 5987 for (then_body) |src_inst| { 5988 if (zir_tags[src_inst] == .store_to_block_ptr and 5989 zir_datas[src_inst].bin.lhs == block_ptr) 5990 { 5991 if (then_scope.rl_ty_inst != .none and has_then_break) { 5992 zir_tags[src_inst] = .as; 5993 zir_datas[src_inst].bin = .{ 5994 .lhs = then_scope.rl_ty_inst, 5995 .rhs = zir_datas[then_break].@"break".operand, 5996 }; 5997 zir_datas[then_break].@"break".operand = indexToRef(src_inst); 5998 } else { 5999 astgen.extra.items[then_body_len_index] -= 1; 6000 continue; 6001 } 6002 } 6003 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst); 6004 } 6005 if (has_then_break) astgen.extra.appendAssumeCapacity(then_break); 6006 6007 for (else_body) |src_inst| { 6008 if (zir_tags[src_inst] == .store_to_block_ptr and 6009 zir_datas[src_inst].bin.lhs == block_ptr) 6010 { 6011 if (else_scope.rl_ty_inst != .none and has_else_break) { 6012 zir_tags[src_inst] = .as; 6013 zir_datas[src_inst].bin = .{ 6014 .lhs = else_scope.rl_ty_inst, 6015 .rhs = zir_datas[else_break].@"break".operand, 6016 }; 6017 zir_datas[else_break].@"break".operand = indexToRef(src_inst); 6018 } else { 6019 astgen.extra.items[else_body_len_index] -= 1; 6020 continue; 6021 } 6022 } 6023 appendPossiblyRefdBodyInst(astgen, &astgen.extra, src_inst); 6024 } 6025 if (has_else_break) astgen.extra.appendAssumeCapacity(else_break); 6026 } 6027 6028 fn whileExpr( 6029 parent_gz: *GenZir, 6030 scope: *Scope, 6031 ri: ResultInfo, 6032 node: Ast.Node.Index, 6033 while_full: Ast.full.While, 6034 is_statement: bool, 6035 ) InnerError!Zir.Inst.Ref { 6036 const astgen = parent_gz.astgen; 6037 const tree = astgen.tree; 6038 const token_tags = tree.tokens.items(.tag); 6039 6040 if (while_full.label_token) |label_token| { 6041 try astgen.checkLabelRedefinition(scope, label_token); 6042 } 6043 6044 const is_inline = parent_gz.force_comptime or while_full.inline_token != null; 6045 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 6046 const loop_block = try parent_gz.makeBlockInst(loop_tag, node); 6047 try parent_gz.instructions.append(astgen.gpa, loop_block); 6048 6049 var loop_scope = parent_gz.makeSubBlock(scope); 6050 loop_scope.is_inline = is_inline; 6051 loop_scope.setBreakResultInfo(ri); 6052 defer loop_scope.unstack(); 6053 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 6054 6055 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); 6056 defer cond_scope.unstack(); 6057 6058 const payload_is_ref = if (while_full.payload_token) |payload_token| 6059 token_tags[payload_token] == .asterisk 6060 else 6061 false; 6062 6063 try emitDbgNode(parent_gz, while_full.ast.cond_expr); 6064 const cond: struct { 6065 inst: Zir.Inst.Ref, 6066 bool_bit: Zir.Inst.Ref, 6067 } = c: { 6068 if (while_full.error_token) |_| { 6069 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; 6070 const err_union = try expr(&cond_scope, &cond_scope.base, cond_ri, while_full.ast.cond_expr); 6071 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 6072 break :c .{ 6073 .inst = err_union, 6074 .bool_bit = try cond_scope.addUnNode(tag, err_union, while_full.ast.then_expr), 6075 }; 6076 } else if (while_full.payload_token) |_| { 6077 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; 6078 const optional = try expr(&cond_scope, &cond_scope.base, cond_ri, while_full.ast.cond_expr); 6079 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 6080 break :c .{ 6081 .inst = optional, 6082 .bool_bit = try cond_scope.addUnNode(tag, optional, while_full.ast.then_expr), 6083 }; 6084 } else { 6085 const cond = try expr(&cond_scope, &cond_scope.base, bool_ri, while_full.ast.cond_expr); 6086 break :c .{ 6087 .inst = cond, 6088 .bool_bit = cond, 6089 }; 6090 } 6091 }; 6092 6093 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 6094 const condbr = try cond_scope.addCondBr(condbr_tag, node); 6095 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 6096 const cond_block = try loop_scope.makeBlockInst(block_tag, node); 6097 try cond_scope.setBlockBody(cond_block); 6098 // cond_scope unstacked now, can add new instructions to loop_scope 6099 try loop_scope.instructions.append(astgen.gpa, cond_block); 6100 6101 // make scope now but don't stack on parent_gz until loop_scope 6102 // gets unstacked after cont_expr is emitted and added below 6103 var then_scope = parent_gz.makeSubBlock(&cond_scope.base); 6104 then_scope.instructions_top = GenZir.unstacked_top; 6105 defer then_scope.unstack(); 6106 6107 var dbg_var_name: ?u32 = null; 6108 var dbg_var_inst: Zir.Inst.Ref = undefined; 6109 var payload_inst: Zir.Inst.Index = 0; 6110 var payload_val_scope: Scope.LocalVal = undefined; 6111 const then_sub_scope = s: { 6112 if (while_full.error_token != null) { 6113 if (while_full.payload_token) |payload_token| { 6114 const tag: Zir.Inst.Tag = if (payload_is_ref) 6115 .err_union_payload_unsafe_ptr 6116 else 6117 .err_union_payload_unsafe; 6118 // will add this instruction to then_scope.instructions below 6119 payload_inst = try then_scope.makeUnNode(tag, cond.inst, while_full.ast.cond_expr); 6120 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 6121 const ident_bytes = tree.tokenSlice(ident_token); 6122 if (mem.eql(u8, "_", ident_bytes)) 6123 break :s &then_scope.base; 6124 const payload_name_loc = payload_token + @boolToInt(payload_is_ref); 6125 const ident_name = try astgen.identAsString(payload_name_loc); 6126 try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc, ident_bytes, .capture); 6127 payload_val_scope = .{ 6128 .parent = &then_scope.base, 6129 .gen_zir = &then_scope, 6130 .name = ident_name, 6131 .inst = indexToRef(payload_inst), 6132 .token_src = payload_token, 6133 .id_cat = .capture, 6134 }; 6135 dbg_var_name = ident_name; 6136 dbg_var_inst = indexToRef(payload_inst); 6137 break :s &payload_val_scope.base; 6138 } else { 6139 _ = try then_scope.addUnNode(.ensure_err_union_payload_void, cond.inst, node); 6140 break :s &then_scope.base; 6141 } 6142 } else if (while_full.payload_token) |payload_token| { 6143 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 6144 const tag: Zir.Inst.Tag = if (payload_is_ref) 6145 .optional_payload_unsafe_ptr 6146 else 6147 .optional_payload_unsafe; 6148 // will add this instruction to then_scope.instructions below 6149 payload_inst = try then_scope.makeUnNode(tag, cond.inst, while_full.ast.cond_expr); 6150 const ident_name = try astgen.identAsString(ident_token); 6151 const ident_bytes = tree.tokenSlice(ident_token); 6152 if (mem.eql(u8, "_", ident_bytes)) 6153 break :s &then_scope.base; 6154 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes, .capture); 6155 payload_val_scope = .{ 6156 .parent = &then_scope.base, 6157 .gen_zir = &then_scope, 6158 .name = ident_name, 6159 .inst = indexToRef(payload_inst), 6160 .token_src = ident_token, 6161 .id_cat = .capture, 6162 }; 6163 dbg_var_name = ident_name; 6164 dbg_var_inst = indexToRef(payload_inst); 6165 break :s &payload_val_scope.base; 6166 } else { 6167 break :s &then_scope.base; 6168 } 6169 }; 6170 6171 var continue_scope = parent_gz.makeSubBlock(then_sub_scope); 6172 continue_scope.instructions_top = GenZir.unstacked_top; 6173 defer continue_scope.unstack(); 6174 const continue_block = try then_scope.makeBlockInst(block_tag, node); 6175 6176 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 6177 _ = try loop_scope.addNode(repeat_tag, node); 6178 6179 try loop_scope.setBlockBody(loop_block); 6180 loop_scope.break_block = loop_block; 6181 loop_scope.continue_block = continue_block; 6182 if (while_full.label_token) |label_token| { 6183 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 6184 .token = label_token, 6185 .block_inst = loop_block, 6186 }); 6187 } 6188 6189 // done adding instructions to loop_scope, can now stack then_scope 6190 then_scope.instructions_top = then_scope.instructions.items.len; 6191 6192 try then_scope.addDbgBlockBegin(); 6193 if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst); 6194 if (dbg_var_name) |name| try then_scope.addDbgVar(.dbg_var_val, name, dbg_var_inst); 6195 try then_scope.instructions.append(astgen.gpa, continue_block); 6196 // This code could be improved to avoid emitting the continue expr when there 6197 // are no jumps to it. This happens when the last statement of a while body is noreturn 6198 // and there are no `continue` statements. 6199 // Tracking issue: https://github.com/ziglang/zig/issues/9185 6200 if (while_full.ast.cont_expr != 0) { 6201 _ = try unusedResultExpr(&then_scope, then_sub_scope, while_full.ast.cont_expr); 6202 } 6203 try then_scope.addDbgBlockEnd(); 6204 6205 continue_scope.instructions_top = continue_scope.instructions.items.len; 6206 _ = try unusedResultExpr(&continue_scope, &continue_scope.base, while_full.ast.then_expr); 6207 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 6208 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 6209 if (!continue_scope.endsWithNoReturn()) { 6210 const break_inst = try continue_scope.makeBreak(break_tag, continue_block, .void_value); 6211 try then_scope.instructions.append(astgen.gpa, break_inst); 6212 } 6213 try continue_scope.setBlockBody(continue_block); 6214 6215 var else_scope = parent_gz.makeSubBlock(&cond_scope.base); 6216 defer else_scope.unstack(); 6217 6218 const else_node = while_full.ast.else_expr; 6219 const else_info: struct { 6220 src: Ast.Node.Index, 6221 result: Zir.Inst.Ref, 6222 } = if (else_node != 0) blk: { 6223 try else_scope.addDbgBlockBegin(); 6224 const sub_scope = s: { 6225 if (while_full.error_token) |error_token| { 6226 const tag: Zir.Inst.Tag = if (payload_is_ref) 6227 .err_union_code_ptr 6228 else 6229 .err_union_code; 6230 const else_payload_inst = try else_scope.addUnNode(tag, cond.inst, while_full.ast.cond_expr); 6231 const ident_name = try astgen.identAsString(error_token); 6232 const ident_bytes = tree.tokenSlice(error_token); 6233 if (mem.eql(u8, ident_bytes, "_")) 6234 break :s &else_scope.base; 6235 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, ident_bytes, .capture); 6236 payload_val_scope = .{ 6237 .parent = &else_scope.base, 6238 .gen_zir = &else_scope, 6239 .name = ident_name, 6240 .inst = else_payload_inst, 6241 .token_src = error_token, 6242 .id_cat = .capture, 6243 }; 6244 try else_scope.addDbgVar(.dbg_var_val, ident_name, else_payload_inst); 6245 break :s &payload_val_scope.base; 6246 } else { 6247 break :s &else_scope.base; 6248 } 6249 }; 6250 // Remove the continue block and break block so that `continue` and `break` 6251 // control flow apply to outer loops; not this one. 6252 loop_scope.continue_block = 0; 6253 loop_scope.break_block = 0; 6254 const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_info, else_node); 6255 if (is_statement) { 6256 _ = try addEnsureResult(&else_scope, else_result, else_node); 6257 } 6258 6259 if (!else_scope.endsWithNoReturn()) { 6260 loop_scope.break_count += 1; 6261 } 6262 try checkUsed(parent_gz, &else_scope.base, sub_scope); 6263 try else_scope.addDbgBlockEnd(); 6264 break :blk .{ 6265 .src = else_node, 6266 .result = else_result, 6267 }; 6268 } else .{ 6269 .src = while_full.ast.then_expr, 6270 .result = .none, 6271 }; 6272 6273 if (loop_scope.label) |some| { 6274 if (!some.used) { 6275 try astgen.appendErrorTok(some.token, "unused while loop label", .{}); 6276 } 6277 } 6278 const result = try finishThenElseBlock( 6279 parent_gz, 6280 ri, 6281 node, 6282 &loop_scope, 6283 &then_scope, 6284 &else_scope, 6285 condbr, 6286 cond.bool_bit, 6287 .void_value, 6288 else_info.result, 6289 loop_block, 6290 cond_block, 6291 break_tag, 6292 ); 6293 if (is_statement) { 6294 _ = try parent_gz.addUnNode(.ensure_result_used, result, node); 6295 } 6296 return result; 6297 } 6298 6299 fn forExpr( 6300 parent_gz: *GenZir, 6301 scope: *Scope, 6302 ri: ResultInfo, 6303 node: Ast.Node.Index, 6304 for_full: Ast.full.While, 6305 is_statement: bool, 6306 ) InnerError!Zir.Inst.Ref { 6307 const astgen = parent_gz.astgen; 6308 6309 if (for_full.label_token) |label_token| { 6310 try astgen.checkLabelRedefinition(scope, label_token); 6311 } 6312 6313 // Set up variables and constants. 6314 const is_inline = parent_gz.force_comptime or for_full.inline_token != null; 6315 const tree = astgen.tree; 6316 const token_tags = tree.tokens.items(.tag); 6317 6318 const payload_is_ref = if (for_full.payload_token) |payload_token| 6319 token_tags[payload_token] == .asterisk 6320 else 6321 false; 6322 6323 try emitDbgNode(parent_gz, for_full.ast.cond_expr); 6324 6325 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none }; 6326 const array_ptr = try expr(parent_gz, scope, cond_ri, for_full.ast.cond_expr); 6327 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); 6328 6329 const index_ptr = blk: { 6330 const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc; 6331 const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node); 6332 // initialize to zero 6333 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); 6334 break :blk index_ptr; 6335 }; 6336 6337 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 6338 const loop_block = try parent_gz.makeBlockInst(loop_tag, node); 6339 try parent_gz.instructions.append(astgen.gpa, loop_block); 6340 6341 var loop_scope = parent_gz.makeSubBlock(scope); 6342 loop_scope.is_inline = is_inline; 6343 loop_scope.setBreakResultInfo(ri); 6344 defer loop_scope.unstack(); 6345 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 6346 6347 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); 6348 defer cond_scope.unstack(); 6349 6350 // check condition i < array_expr.len 6351 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 6352 const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, Zir.Inst.Bin{ 6353 .lhs = index, 6354 .rhs = len, 6355 }); 6356 6357 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 6358 const condbr = try cond_scope.addCondBr(condbr_tag, node); 6359 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 6360 const cond_block = try loop_scope.makeBlockInst(block_tag, node); 6361 try cond_scope.setBlockBody(cond_block); 6362 // cond_block unstacked now, can add new instructions to loop_scope 6363 try loop_scope.instructions.append(astgen.gpa, cond_block); 6364 6365 // Increment the index variable. 6366 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 6367 const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ 6368 .lhs = index_2, 6369 .rhs = .one_usize, 6370 }); 6371 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); 6372 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 6373 _ = try loop_scope.addNode(repeat_tag, node); 6374 6375 try loop_scope.setBlockBody(loop_block); 6376 loop_scope.break_block = loop_block; 6377 loop_scope.continue_block = cond_block; 6378 if (for_full.label_token) |label_token| { 6379 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 6380 .token = label_token, 6381 .block_inst = loop_block, 6382 }); 6383 } 6384 6385 var then_scope = parent_gz.makeSubBlock(&cond_scope.base); 6386 defer then_scope.unstack(); 6387 6388 try then_scope.addDbgBlockBegin(); 6389 var payload_val_scope: Scope.LocalVal = undefined; 6390 var index_scope: Scope.LocalPtr = undefined; 6391 const then_sub_scope = blk: { 6392 const payload_token = for_full.payload_token.?; 6393 const ident = if (token_tags[payload_token] == .asterisk) 6394 payload_token + 1 6395 else 6396 payload_token; 6397 const is_ptr = ident != payload_token; 6398 const value_name = tree.tokenSlice(ident); 6399 var payload_sub_scope: *Scope = undefined; 6400 if (!mem.eql(u8, value_name, "_")) { 6401 const name_str_index = try astgen.identAsString(ident); 6402 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; 6403 const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{ 6404 .lhs = array_ptr, 6405 .rhs = index, 6406 }); 6407 try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture); 6408 payload_val_scope = .{ 6409 .parent = &then_scope.base, 6410 .gen_zir = &then_scope, 6411 .name = name_str_index, 6412 .inst = payload_inst, 6413 .token_src = ident, 6414 .id_cat = .capture, 6415 }; 6416 try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst); 6417 payload_sub_scope = &payload_val_scope.base; 6418 } else if (is_ptr) { 6419 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 6420 } else { 6421 payload_sub_scope = &then_scope.base; 6422 } 6423 6424 const index_token = if (token_tags[ident + 1] == .comma) 6425 ident + 2 6426 else 6427 break :blk payload_sub_scope; 6428 const token_bytes = tree.tokenSlice(index_token); 6429 if (mem.eql(u8, token_bytes, "_")) { 6430 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{}); 6431 } 6432 const index_name = try astgen.identAsString(index_token); 6433 try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture"); 6434 index_scope = .{ 6435 .parent = payload_sub_scope, 6436 .gen_zir = &then_scope, 6437 .name = index_name, 6438 .ptr = index_ptr, 6439 .token_src = index_token, 6440 .maybe_comptime = is_inline, 6441 .id_cat = .@"loop index capture", 6442 }; 6443 try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr); 6444 break :blk &index_scope.base; 6445 }; 6446 6447 const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr); 6448 _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr); 6449 6450 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 6451 try then_scope.addDbgBlockEnd(); 6452 6453 var else_scope = parent_gz.makeSubBlock(&cond_scope.base); 6454 defer else_scope.unstack(); 6455 6456 const else_node = for_full.ast.else_expr; 6457 const else_info: struct { 6458 src: Ast.Node.Index, 6459 result: Zir.Inst.Ref, 6460 } = if (else_node != 0) blk: { 6461 const sub_scope = &else_scope.base; 6462 // Remove the continue block and break block so that `continue` and `break` 6463 // control flow apply to outer loops; not this one. 6464 loop_scope.continue_block = 0; 6465 loop_scope.break_block = 0; 6466 const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_info, else_node); 6467 if (is_statement) { 6468 _ = try addEnsureResult(&else_scope, else_result, else_node); 6469 } 6470 6471 if (!else_scope.endsWithNoReturn()) { 6472 loop_scope.break_count += 1; 6473 } 6474 break :blk .{ 6475 .src = else_node, 6476 .result = else_result, 6477 }; 6478 } else .{ 6479 .src = for_full.ast.then_expr, 6480 .result = .none, 6481 }; 6482 6483 if (loop_scope.label) |some| { 6484 if (!some.used) { 6485 try astgen.appendErrorTok(some.token, "unused for loop label", .{}); 6486 } 6487 } 6488 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 6489 const result = try finishThenElseBlock( 6490 parent_gz, 6491 ri, 6492 node, 6493 &loop_scope, 6494 &then_scope, 6495 &else_scope, 6496 condbr, 6497 cond, 6498 then_result, 6499 else_info.result, 6500 loop_block, 6501 cond_block, 6502 break_tag, 6503 ); 6504 if (is_statement) { 6505 _ = try parent_gz.addUnNode(.ensure_result_used, result, node); 6506 } 6507 return result; 6508 } 6509 6510 fn switchExpr( 6511 parent_gz: *GenZir, 6512 scope: *Scope, 6513 ri: ResultInfo, 6514 switch_node: Ast.Node.Index, 6515 ) InnerError!Zir.Inst.Ref { 6516 const astgen = parent_gz.astgen; 6517 const gpa = astgen.gpa; 6518 const tree = astgen.tree; 6519 const node_datas = tree.nodes.items(.data); 6520 const node_tags = tree.nodes.items(.tag); 6521 const main_tokens = tree.nodes.items(.main_token); 6522 const token_tags = tree.tokens.items(.tag); 6523 const operand_node = node_datas[switch_node].lhs; 6524 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); 6525 const case_nodes = tree.extra_data[extra.start..extra.end]; 6526 6527 // We perform two passes over the AST. This first pass is to collect information 6528 // for the following variables, make note of the special prong AST node index, 6529 // and bail out with a compile error if there are multiple special prongs present. 6530 var any_payload_is_ref = false; 6531 var scalar_cases_len: u32 = 0; 6532 var multi_cases_len: u32 = 0; 6533 var inline_cases_len: u32 = 0; 6534 var special_prong: Zir.SpecialProng = .none; 6535 var special_node: Ast.Node.Index = 0; 6536 var else_src: ?Ast.TokenIndex = null; 6537 var underscore_src: ?Ast.TokenIndex = null; 6538 for (case_nodes) |case_node| { 6539 const case = switch (node_tags[case_node]) { 6540 .switch_case_one, .switch_case_inline_one => tree.switchCaseOne(case_node), 6541 .switch_case, .switch_case_inline => tree.switchCase(case_node), 6542 else => unreachable, 6543 }; 6544 if (case.payload_token) |payload_token| { 6545 if (token_tags[payload_token] == .asterisk) { 6546 any_payload_is_ref = true; 6547 } 6548 } 6549 // Check for else/`_` prong. 6550 if (case.ast.values.len == 0) { 6551 const case_src = case.ast.arrow_token - 1; 6552 if (else_src) |src| { 6553 return astgen.failTokNotes( 6554 case_src, 6555 "multiple else prongs in switch expression", 6556 .{}, 6557 &[_]u32{ 6558 try astgen.errNoteTok( 6559 src, 6560 "previous else prong here", 6561 .{}, 6562 ), 6563 }, 6564 ); 6565 } else if (underscore_src) |some_underscore| { 6566 return astgen.failNodeNotes( 6567 switch_node, 6568 "else and '_' prong in switch expression", 6569 .{}, 6570 &[_]u32{ 6571 try astgen.errNoteTok( 6572 case_src, 6573 "else prong here", 6574 .{}, 6575 ), 6576 try astgen.errNoteTok( 6577 some_underscore, 6578 "'_' prong here", 6579 .{}, 6580 ), 6581 }, 6582 ); 6583 } 6584 special_node = case_node; 6585 special_prong = .@"else"; 6586 else_src = case_src; 6587 continue; 6588 } else if (case.ast.values.len == 1 and 6589 node_tags[case.ast.values[0]] == .identifier and 6590 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) 6591 { 6592 const case_src = case.ast.arrow_token - 1; 6593 if (underscore_src) |src| { 6594 return astgen.failTokNotes( 6595 case_src, 6596 "multiple '_' prongs in switch expression", 6597 .{}, 6598 &[_]u32{ 6599 try astgen.errNoteTok( 6600 src, 6601 "previous '_' prong here", 6602 .{}, 6603 ), 6604 }, 6605 ); 6606 } else if (else_src) |some_else| { 6607 return astgen.failNodeNotes( 6608 switch_node, 6609 "else and '_' prong in switch expression", 6610 .{}, 6611 &[_]u32{ 6612 try astgen.errNoteTok( 6613 some_else, 6614 "else prong here", 6615 .{}, 6616 ), 6617 try astgen.errNoteTok( 6618 case_src, 6619 "'_' prong here", 6620 .{}, 6621 ), 6622 }, 6623 ); 6624 } 6625 if (case.inline_token != null) { 6626 return astgen.failTok(case_src, "cannot inline '_' prong", .{}); 6627 } 6628 special_node = case_node; 6629 special_prong = .under; 6630 underscore_src = case_src; 6631 continue; 6632 } 6633 6634 for (case.ast.values) |val| { 6635 if (node_tags[val] == .string_literal) 6636 return astgen.failNode(val, "cannot switch on strings", .{}); 6637 } 6638 6639 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { 6640 scalar_cases_len += 1; 6641 } else { 6642 multi_cases_len += 1; 6643 } 6644 if (case.inline_token != null) { 6645 inline_cases_len += 1; 6646 } 6647 } 6648 6649 const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none }; 6650 astgen.advanceSourceCursorToNode(operand_node); 6651 const operand_line = astgen.source_line - parent_gz.decl_line; 6652 const operand_column = astgen.source_column; 6653 const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node); 6654 const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond; 6655 const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node); 6656 // Sema expects a dbg_stmt immediately after switch_cond(_ref) 6657 try emitDbgStmt(parent_gz, operand_line, operand_column); 6658 // We need the type of the operand to use as the result location for all the prong items. 6659 const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node); 6660 const item_ri: ResultInfo = .{ .rl = .{ .ty = cond_ty_inst } }; 6661 6662 // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti, 6663 // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with 6664 // the special case index coming first, then scalar_case_len indexes, then multi_cases_len indexes 6665 const payloads = &astgen.scratch; 6666 const scratch_top = astgen.scratch.items.len; 6667 const case_table_start = scratch_top; 6668 const scalar_case_table = case_table_start + @boolToInt(special_prong != .none); 6669 const multi_case_table = scalar_case_table + scalar_cases_len; 6670 const case_table_end = multi_case_table + multi_cases_len; 6671 try astgen.scratch.resize(gpa, case_table_end); 6672 defer astgen.scratch.items.len = scratch_top; 6673 6674 var block_scope = parent_gz.makeSubBlock(scope); 6675 // block_scope not used for collecting instructions 6676 block_scope.instructions_top = GenZir.unstacked_top; 6677 block_scope.setBreakResultInfo(ri); 6678 6679 // This gets added to the parent block later, after the item expressions. 6680 const switch_block = try parent_gz.makeBlockInst(.switch_block, switch_node); 6681 6682 // We re-use this same scope for all cases, including the special prong, if any. 6683 var case_scope = parent_gz.makeSubBlock(&block_scope.base); 6684 case_scope.instructions_top = GenZir.unstacked_top; 6685 6686 // In this pass we generate all the item and prong expressions. 6687 var multi_case_index: u32 = 0; 6688 var scalar_case_index: u32 = 0; 6689 for (case_nodes) |case_node| { 6690 const case = switch (node_tags[case_node]) { 6691 .switch_case_one, .switch_case_inline_one => tree.switchCaseOne(case_node), 6692 .switch_case, .switch_case_inline => tree.switchCase(case_node), 6693 else => unreachable, 6694 }; 6695 6696 const is_multi_case = case.ast.values.len > 1 or 6697 (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range); 6698 6699 var dbg_var_name: ?u32 = null; 6700 var dbg_var_inst: Zir.Inst.Ref = undefined; 6701 var dbg_var_tag_name: ?u32 = null; 6702 var dbg_var_tag_inst: Zir.Inst.Ref = undefined; 6703 var capture_inst: Zir.Inst.Index = 0; 6704 var tag_inst: Zir.Inst.Index = 0; 6705 var capture_val_scope: Scope.LocalVal = undefined; 6706 var tag_scope: Scope.LocalVal = undefined; 6707 const sub_scope = blk: { 6708 const payload_token = case.payload_token orelse break :blk &case_scope.base; 6709 const ident = if (token_tags[payload_token] == .asterisk) 6710 payload_token + 1 6711 else 6712 payload_token; 6713 const is_ptr = ident != payload_token; 6714 const ident_slice = tree.tokenSlice(ident); 6715 var payload_sub_scope: *Scope = undefined; 6716 if (mem.eql(u8, ident_slice, "_")) { 6717 if (is_ptr) { 6718 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 6719 } 6720 payload_sub_scope = &case_scope.base; 6721 } else { 6722 if (case_node == special_node) { 6723 const capture_tag: Zir.Inst.Tag = if (is_ptr) 6724 .switch_capture_ref 6725 else 6726 .switch_capture; 6727 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); 6728 try astgen.instructions.append(gpa, .{ 6729 .tag = capture_tag, 6730 .data = .{ 6731 .switch_capture = .{ 6732 .switch_inst = switch_block, 6733 // Max int communicates that this is the else/underscore prong. 6734 .prong_index = std.math.maxInt(u32), 6735 }, 6736 }, 6737 }); 6738 } else { 6739 const is_multi_case_bits: u2 = @boolToInt(is_multi_case); 6740 const is_ptr_bits: u2 = @boolToInt(is_ptr); 6741 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { 6742 0b00 => .switch_capture, 6743 0b01 => .switch_capture_ref, 6744 0b10 => .switch_capture_multi, 6745 0b11 => .switch_capture_multi_ref, 6746 }; 6747 const capture_index = if (is_multi_case) multi_case_index else scalar_case_index; 6748 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); 6749 try astgen.instructions.append(gpa, .{ 6750 .tag = capture_tag, 6751 .data = .{ .switch_capture = .{ 6752 .switch_inst = switch_block, 6753 .prong_index = capture_index, 6754 } }, 6755 }); 6756 } 6757 const capture_name = try astgen.identAsString(ident); 6758 try astgen.detectLocalShadowing(&case_scope.base, capture_name, ident, ident_slice, .capture); 6759 capture_val_scope = .{ 6760 .parent = &case_scope.base, 6761 .gen_zir = &case_scope, 6762 .name = capture_name, 6763 .inst = indexToRef(capture_inst), 6764 .token_src = payload_token, 6765 .id_cat = .capture, 6766 }; 6767 dbg_var_name = capture_name; 6768 dbg_var_inst = indexToRef(capture_inst); 6769 payload_sub_scope = &capture_val_scope.base; 6770 } 6771 6772 const tag_token = if (token_tags[ident + 1] == .comma) 6773 ident + 2 6774 else 6775 break :blk payload_sub_scope; 6776 const tag_slice = tree.tokenSlice(tag_token); 6777 if (mem.eql(u8, tag_slice, "_")) { 6778 return astgen.failTok(tag_token, "discard of tag capture; omit it instead", .{}); 6779 } else if (case.inline_token == null) { 6780 return astgen.failTok(tag_token, "tag capture on non-inline prong", .{}); 6781 } 6782 const tag_name = try astgen.identAsString(tag_token); 6783 try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture"); 6784 tag_inst = @intCast(Zir.Inst.Index, astgen.instructions.len); 6785 try astgen.instructions.append(gpa, .{ 6786 .tag = .switch_capture_tag, 6787 .data = .{ .un_tok = .{ 6788 .operand = cond, 6789 .src_tok = case_scope.tokenIndexToRelative(tag_token), 6790 } }, 6791 }); 6792 6793 tag_scope = .{ 6794 .parent = payload_sub_scope, 6795 .gen_zir = &case_scope, 6796 .name = tag_name, 6797 .inst = indexToRef(tag_inst), 6798 .token_src = tag_token, 6799 .id_cat = .@"switch tag capture", 6800 }; 6801 dbg_var_tag_name = tag_name; 6802 dbg_var_tag_inst = indexToRef(tag_inst); 6803 break :blk &tag_scope.base; 6804 }; 6805 6806 const header_index = @intCast(u32, payloads.items.len); 6807 const body_len_index = if (is_multi_case) blk: { 6808 payloads.items[multi_case_table + multi_case_index] = header_index; 6809 multi_case_index += 1; 6810 try payloads.resize(gpa, header_index + 3); // items_len, ranges_len, body_len 6811 6812 // items 6813 var items_len: u32 = 0; 6814 for (case.ast.values) |item_node| { 6815 if (node_tags[item_node] == .switch_range) continue; 6816 items_len += 1; 6817 6818 const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node); 6819 try payloads.append(gpa, @enumToInt(item_inst)); 6820 } 6821 6822 // ranges 6823 var ranges_len: u32 = 0; 6824 for (case.ast.values) |range| { 6825 if (node_tags[range] != .switch_range) continue; 6826 ranges_len += 1; 6827 6828 const first = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].lhs); 6829 const last = try comptimeExpr(parent_gz, scope, item_ri, node_datas[range].rhs); 6830 try payloads.appendSlice(gpa, &[_]u32{ 6831 @enumToInt(first), @enumToInt(last), 6832 }); 6833 } 6834 6835 payloads.items[header_index] = items_len; 6836 payloads.items[header_index + 1] = ranges_len; 6837 break :blk header_index + 2; 6838 } else if (case_node == special_node) blk: { 6839 payloads.items[case_table_start] = header_index; 6840 try payloads.resize(gpa, header_index + 1); // body_len 6841 break :blk header_index; 6842 } else blk: { 6843 payloads.items[scalar_case_table + scalar_case_index] = header_index; 6844 scalar_case_index += 1; 6845 try payloads.resize(gpa, header_index + 2); // item, body_len 6846 const item_node = case.ast.values[0]; 6847 const item_inst = try comptimeExpr(parent_gz, scope, item_ri, item_node); 6848 payloads.items[header_index] = @enumToInt(item_inst); 6849 break :blk header_index + 1; 6850 }; 6851 6852 { 6853 // temporarily stack case_scope on parent_gz 6854 case_scope.instructions_top = parent_gz.instructions.items.len; 6855 defer case_scope.unstack(); 6856 6857 if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst); 6858 if (tag_inst != 0) try case_scope.instructions.append(gpa, tag_inst); 6859 try case_scope.addDbgBlockBegin(); 6860 if (dbg_var_name) |some| { 6861 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); 6862 } 6863 if (dbg_var_tag_name) |some| { 6864 try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_tag_inst); 6865 } 6866 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, case.ast.target_expr); 6867 try checkUsed(parent_gz, &case_scope.base, sub_scope); 6868 try case_scope.addDbgBlockEnd(); 6869 if (!parent_gz.refIsNoReturn(case_result)) { 6870 block_scope.break_count += 1; 6871 _ = try case_scope.addBreak(.@"break", switch_block, case_result); 6872 } 6873 6874 const case_slice = case_scope.instructionsSlice(); 6875 const body_len = astgen.countBodyLenAfterFixups(case_slice); 6876 try payloads.ensureUnusedCapacity(gpa, body_len); 6877 const inline_bit = @as(u32, @boolToInt(case.inline_token != null)) << 31; 6878 payloads.items[body_len_index] = body_len | inline_bit; 6879 appendBodyWithFixupsArrayList(astgen, payloads, case_slice); 6880 } 6881 } 6882 // Now that the item expressions are generated we can add this. 6883 try parent_gz.instructions.append(gpa, switch_block); 6884 6885 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len + 6886 @boolToInt(multi_cases_len != 0) + 6887 payloads.items.len - case_table_end); 6888 6889 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{ 6890 .operand = cond, 6891 .bits = Zir.Inst.SwitchBlock.Bits{ 6892 .has_multi_cases = multi_cases_len != 0, 6893 .has_else = special_prong == .@"else", 6894 .has_under = special_prong == .under, 6895 .scalar_cases_len = @intCast(Zir.Inst.SwitchBlock.Bits.ScalarCasesLen, scalar_cases_len), 6896 }, 6897 }); 6898 6899 if (multi_cases_len != 0) { 6900 astgen.extra.appendAssumeCapacity(multi_cases_len); 6901 } 6902 6903 const zir_datas = astgen.instructions.items(.data); 6904 const zir_tags = astgen.instructions.items(.tag); 6905 6906 zir_datas[switch_block].pl_node.payload_index = payload_index; 6907 6908 const strat = ri.rl.strategy(&block_scope); 6909 for (payloads.items[case_table_start..case_table_end]) |start_index, i| { 6910 var body_len_index = start_index; 6911 var end_index = start_index; 6912 const table_index = case_table_start + i; 6913 if (table_index < scalar_case_table) { 6914 end_index += 1; 6915 } else if (table_index < multi_case_table) { 6916 body_len_index += 1; 6917 end_index += 2; 6918 } else { 6919 body_len_index += 2; 6920 const items_len = payloads.items[start_index]; 6921 const ranges_len = payloads.items[start_index + 1]; 6922 end_index += 3 + items_len + 2 * ranges_len; 6923 } 6924 6925 const body_len = @truncate(u31, payloads.items[body_len_index]); 6926 end_index += body_len; 6927 6928 switch (strat.tag) { 6929 .break_operand => blk: { 6930 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus 6931 // `elide_store_to_block_ptr_instructions` will either be true, 6932 // or all prongs are noreturn. 6933 if (!strat.elide_store_to_block_ptr_instructions) 6934 break :blk; 6935 6936 // There will necessarily be a store_to_block_ptr for 6937 // all prongs, except for prongs that ended with a noreturn instruction. 6938 // Elide all the `store_to_block_ptr` instructions. 6939 6940 // The break instructions need to have their operands coerced if the 6941 // switch's result location is a `ty`. In this case we overwrite the 6942 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 6943 // it as the break operand. 6944 if (body_len < 2) 6945 break :blk; 6946 const store_inst = payloads.items[end_index - 2]; 6947 if (zir_tags[store_inst] != .store_to_block_ptr or 6948 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) 6949 break :blk; 6950 const break_inst = payloads.items[end_index - 1]; 6951 if (block_scope.rl_ty_inst != .none) { 6952 zir_tags[store_inst] = .as; 6953 zir_datas[store_inst].bin = .{ 6954 .lhs = block_scope.rl_ty_inst, 6955 .rhs = zir_datas[break_inst].@"break".operand, 6956 }; 6957 zir_datas[break_inst].@"break".operand = indexToRef(store_inst); 6958 } else { 6959 payloads.items[body_len_index] -= 1; 6960 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index .. end_index - 2]); 6961 astgen.extra.appendAssumeCapacity(break_inst); 6962 continue; 6963 } 6964 }, 6965 .break_void => { 6966 assert(!strat.elide_store_to_block_ptr_instructions); 6967 const last_inst = payloads.items[end_index - 1]; 6968 if (zir_tags[last_inst] == .@"break" and 6969 zir_datas[last_inst].@"break".block_inst == switch_block) 6970 { 6971 zir_datas[last_inst].@"break".operand = .void_value; 6972 } 6973 }, 6974 } 6975 6976 astgen.extra.appendSliceAssumeCapacity(payloads.items[start_index..end_index]); 6977 } 6978 6979 const block_ref = indexToRef(switch_block); 6980 if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and ri.rl != .ref) 6981 return rvalue(parent_gz, ri, block_ref, switch_node); 6982 return block_ref; 6983 } 6984 6985 fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 6986 const astgen = gz.astgen; 6987 const tree = astgen.tree; 6988 const node_datas = tree.nodes.items(.data); 6989 const node_tags = tree.nodes.items(.tag); 6990 6991 if (astgen.fn_block == null) { 6992 return astgen.failNode(node, "'return' outside function scope", .{}); 6993 } 6994 6995 if (gz.any_defer_node != 0) { 6996 return astgen.failNodeNotes(node, "cannot return from defer expression", .{}, &.{ 6997 try astgen.errNoteNode( 6998 gz.any_defer_node, 6999 "defer expression here", 7000 .{}, 7001 ), 7002 }); 7003 } 7004 7005 // Ensure debug line/column information is emitted for this return expression. 7006 // Then we will save the line/column so that we can emit another one that goes 7007 // "backwards" because we want to evaluate the operand, but then put the debug 7008 // info back at the return keyword for error return tracing. 7009 if (!gz.force_comptime) { 7010 try emitDbgNode(gz, node); 7011 } 7012 const ret_line = astgen.source_line - gz.decl_line; 7013 const ret_column = astgen.source_column; 7014 7015 const defer_outer = &astgen.fn_block.?.base; 7016 7017 const operand_node = node_datas[node].lhs; 7018 if (operand_node == 0) { 7019 // Returning a void value; skip error defers. 7020 try genDefers(gz, defer_outer, scope, .normal_only); 7021 7022 // As our last action before the return, "pop" the error trace if needed 7023 _ = try gz.addRestoreErrRetIndex(.ret, .always); 7024 7025 _ = try gz.addUnNode(.ret_node, .void_value, node); 7026 return Zir.Inst.Ref.unreachable_value; 7027 } 7028 7029 if (node_tags[operand_node] == .error_value) { 7030 // Hot path for `return error.Foo`. This bypasses result location logic as well as logic 7031 // for detecting whether to add something to the function's inferred error set. 7032 const ident_token = node_datas[operand_node].rhs; 7033 const err_name_str_index = try astgen.identAsString(ident_token); 7034 const defer_counts = countDefers(defer_outer, scope); 7035 if (!defer_counts.need_err_code) { 7036 try genDefers(gz, defer_outer, scope, .both_sans_err); 7037 try emitDbgStmt(gz, ret_line, ret_column); 7038 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token); 7039 return Zir.Inst.Ref.unreachable_value; 7040 } 7041 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token); 7042 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 7043 try emitDbgStmt(gz, ret_line, ret_column); 7044 _ = try gz.addUnNode(.ret_node, err_code, node); 7045 return Zir.Inst.Ref.unreachable_value; 7046 } 7047 7048 const ri: ResultInfo = if (nodeMayNeedMemoryLocation(tree, operand_node, true)) .{ 7049 .rl = .{ .ptr = .{ .inst = try gz.addNode(.ret_ptr, node) } }, 7050 .ctx = .@"return", 7051 } else .{ 7052 .rl = .{ .ty = try gz.addNode(.ret_type, node) }, 7053 .ctx = .@"return", 7054 }; 7055 const prev_anon_name_strategy = gz.anon_name_strategy; 7056 gz.anon_name_strategy = .func; 7057 const operand = try reachableExpr(gz, scope, ri, operand_node, node); 7058 gz.anon_name_strategy = prev_anon_name_strategy; 7059 7060 switch (nodeMayEvalToError(tree, operand_node)) { 7061 .never => { 7062 // Returning a value that cannot be an error; skip error defers. 7063 try genDefers(gz, defer_outer, scope, .normal_only); 7064 7065 // As our last action before the return, "pop" the error trace if needed 7066 _ = try gz.addRestoreErrRetIndex(.ret, .always); 7067 7068 try emitDbgStmt(gz, ret_line, ret_column); 7069 try gz.addRet(ri, operand, node); 7070 return Zir.Inst.Ref.unreachable_value; 7071 }, 7072 .always => { 7073 // Value is always an error. Emit both error defers and regular defers. 7074 const err_code = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand; 7075 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 7076 try emitDbgStmt(gz, ret_line, ret_column); 7077 try gz.addRet(ri, operand, node); 7078 return Zir.Inst.Ref.unreachable_value; 7079 }, 7080 .maybe => { 7081 const defer_counts = countDefers(defer_outer, scope); 7082 if (!defer_counts.have_err) { 7083 // Only regular defers; no branch needed. 7084 try genDefers(gz, defer_outer, scope, .normal_only); 7085 try emitDbgStmt(gz, ret_line, ret_column); 7086 7087 // As our last action before the return, "pop" the error trace if needed 7088 const result = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand; 7089 _ = try gz.addRestoreErrRetIndex(.ret, .{ .if_non_error = result }); 7090 7091 try gz.addRet(ri, operand, node); 7092 return Zir.Inst.Ref.unreachable_value; 7093 } 7094 7095 // Emit conditional branch for generating errdefers. 7096 const result = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand; 7097 const is_non_err = try gz.addUnNode(.is_non_err, result, node); 7098 const condbr = try gz.addCondBr(.condbr, node); 7099 7100 var then_scope = gz.makeSubBlock(scope); 7101 defer then_scope.unstack(); 7102 7103 try genDefers(&then_scope, defer_outer, scope, .normal_only); 7104 7105 // As our last action before the return, "pop" the error trace if needed 7106 _ = try then_scope.addRestoreErrRetIndex(.ret, .always); 7107 7108 try emitDbgStmt(&then_scope, ret_line, ret_column); 7109 try then_scope.addRet(ri, operand, node); 7110 7111 var else_scope = gz.makeSubBlock(scope); 7112 defer else_scope.unstack(); 7113 7114 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{ 7115 .both = try else_scope.addUnNode(.err_union_code, result, node), 7116 }; 7117 try genDefers(&else_scope, defer_outer, scope, which_ones); 7118 try emitDbgStmt(&else_scope, ret_line, ret_column); 7119 try else_scope.addRet(ri, operand, node); 7120 7121 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); 7122 7123 return Zir.Inst.Ref.unreachable_value; 7124 }, 7125 } 7126 } 7127 7128 /// Parses the string `buf` as a base 10 integer of type `u16`. 7129 /// 7130 /// Unlike std.fmt.parseInt, does not allow the '_' character in `buf`. 7131 fn parseBitCount(buf: []const u8) std.fmt.ParseIntError!u16 { 7132 if (buf.len == 0) return error.InvalidCharacter; 7133 7134 var x: u16 = 0; 7135 7136 for (buf) |c| { 7137 const digit = switch (c) { 7138 '0'...'9' => c - '0', 7139 else => return error.InvalidCharacter, 7140 }; 7141 7142 if (x != 0) x = try std.math.mul(u16, x, 10); 7143 x = try std.math.add(u16, x, @as(u16, digit)); 7144 } 7145 7146 return x; 7147 } 7148 7149 fn identifier( 7150 gz: *GenZir, 7151 scope: *Scope, 7152 ri: ResultInfo, 7153 ident: Ast.Node.Index, 7154 ) InnerError!Zir.Inst.Ref { 7155 const tracy = trace(@src()); 7156 defer tracy.end(); 7157 7158 const astgen = gz.astgen; 7159 const tree = astgen.tree; 7160 const main_tokens = tree.nodes.items(.main_token); 7161 7162 const ident_token = main_tokens[ident]; 7163 const ident_name_raw = tree.tokenSlice(ident_token); 7164 if (mem.eql(u8, ident_name_raw, "_")) { 7165 return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{}); 7166 } 7167 7168 // if not @"" syntax, just use raw token slice 7169 if (ident_name_raw[0] != '@') { 7170 if (primitive_instrs.get(ident_name_raw)) |zir_const_ref| { 7171 return rvalue(gz, ri, zir_const_ref, ident); 7172 } 7173 7174 if (ident_name_raw.len >= 2) integer: { 7175 const first_c = ident_name_raw[0]; 7176 if (first_c == 'i' or first_c == 'u') { 7177 const signedness: std.builtin.Signedness = switch (first_c == 'i') { 7178 true => .signed, 7179 false => .unsigned, 7180 }; 7181 if (ident_name_raw.len >= 3 and ident_name_raw[1] == '0') { 7182 return astgen.failNode( 7183 ident, 7184 "primitive integer type '{s}' has leading zero", 7185 .{ident_name_raw}, 7186 ); 7187 } 7188 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { 7189 error.Overflow => return astgen.failNode( 7190 ident, 7191 "primitive integer type '{s}' exceeds maximum bit width of 65535", 7192 .{ident_name_raw}, 7193 ), 7194 error.InvalidCharacter => break :integer, 7195 }; 7196 const result = try gz.add(.{ 7197 .tag = .int_type, 7198 .data = .{ .int_type = .{ 7199 .src_node = gz.nodeIndexToRelative(ident), 7200 .signedness = signedness, 7201 .bit_count = bit_count, 7202 } }, 7203 }); 7204 return rvalue(gz, ri, result, ident); 7205 } 7206 } 7207 } 7208 7209 // Local variables, including function parameters. 7210 return localVarRef(gz, scope, ri, ident, ident_token); 7211 } 7212 7213 fn localVarRef( 7214 gz: *GenZir, 7215 scope: *Scope, 7216 ri: ResultInfo, 7217 ident: Ast.Node.Index, 7218 ident_token: Ast.TokenIndex, 7219 ) InnerError!Zir.Inst.Ref { 7220 const astgen = gz.astgen; 7221 const gpa = astgen.gpa; 7222 const name_str_index = try astgen.identAsString(ident_token); 7223 var s = scope; 7224 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 7225 var num_namespaces_out: u32 = 0; 7226 var capturing_namespace: ?*Scope.Namespace = null; 7227 while (true) switch (s.tag) { 7228 .local_val => { 7229 const local_val = s.cast(Scope.LocalVal).?; 7230 7231 if (local_val.name == name_str_index) { 7232 // Locals cannot shadow anything, so we do not need to look for ambiguous 7233 // references in this case. 7234 if (ri.rl == .discard and ri.ctx == .assignment) { 7235 local_val.discarded = ident_token; 7236 } else { 7237 local_val.used = ident_token; 7238 } 7239 7240 const value_inst = try tunnelThroughClosure( 7241 gz, 7242 ident, 7243 num_namespaces_out, 7244 capturing_namespace, 7245 local_val.inst, 7246 local_val.token_src, 7247 gpa, 7248 ); 7249 7250 return rvalue(gz, ri, value_inst, ident); 7251 } 7252 s = local_val.parent; 7253 }, 7254 .local_ptr => { 7255 const local_ptr = s.cast(Scope.LocalPtr).?; 7256 if (local_ptr.name == name_str_index) { 7257 if (ri.rl == .discard and ri.ctx == .assignment) { 7258 local_ptr.discarded = ident_token; 7259 } else { 7260 local_ptr.used = ident_token; 7261 } 7262 7263 // Can't close over a runtime variable 7264 if (num_namespaces_out != 0 and !local_ptr.maybe_comptime) { 7265 const ident_name = try astgen.identifierTokenString(ident_token); 7266 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{ 7267 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}), 7268 try astgen.errNoteNode(capturing_namespace.?.node, "crosses namespace boundary here", .{}), 7269 }); 7270 } 7271 7272 const ptr_inst = try tunnelThroughClosure( 7273 gz, 7274 ident, 7275 num_namespaces_out, 7276 capturing_namespace, 7277 local_ptr.ptr, 7278 local_ptr.token_src, 7279 gpa, 7280 ); 7281 7282 switch (ri.rl) { 7283 .ref => return ptr_inst, 7284 else => { 7285 const loaded = try gz.addUnNode(.load, ptr_inst, ident); 7286 return rvalue(gz, ri, loaded, ident); 7287 }, 7288 } 7289 } 7290 s = local_ptr.parent; 7291 }, 7292 .gen_zir => s = s.cast(GenZir).?.parent, 7293 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 7294 .namespace => { 7295 const ns = s.cast(Scope.Namespace).?; 7296 if (ns.decls.get(name_str_index)) |i| { 7297 if (found_already) |f| { 7298 return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{ 7299 try astgen.errNoteNode(f, "declared here", .{}), 7300 try astgen.errNoteNode(i, "also declared here", .{}), 7301 }); 7302 } 7303 // We found a match but must continue looking for ambiguous references to decls. 7304 found_already = i; 7305 } 7306 num_namespaces_out += 1; 7307 capturing_namespace = ns; 7308 s = ns.parent; 7309 }, 7310 .top => break, 7311 }; 7312 if (found_already == null) { 7313 const ident_name = try astgen.identifierTokenString(ident_token); 7314 return astgen.failNode(ident, "use of undeclared identifier '{s}'", .{ident_name}); 7315 } 7316 7317 // Decl references happen by name rather than ZIR index so that when unrelated 7318 // decls are modified, ZIR code containing references to them can be unmodified. 7319 switch (ri.rl) { 7320 .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), 7321 else => { 7322 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); 7323 return rvalue(gz, ri, result, ident); 7324 }, 7325 } 7326 } 7327 7328 /// Adds a capture to a namespace, if needed. 7329 /// Returns the index of the closure_capture instruction. 7330 fn tunnelThroughClosure( 7331 gz: *GenZir, 7332 inner_ref_node: Ast.Node.Index, 7333 num_tunnels: u32, 7334 ns: ?*Scope.Namespace, 7335 value: Zir.Inst.Ref, 7336 token: Ast.TokenIndex, 7337 gpa: Allocator, 7338 ) !Zir.Inst.Ref { 7339 // For trivial values, we don't need a tunnel. 7340 // Just return the ref. 7341 if (num_tunnels == 0 or refToIndex(value) == null) { 7342 return value; 7343 } 7344 7345 // Otherwise we need a tunnel. Check if this namespace 7346 // already has one for this value. 7347 const gop = try ns.?.captures.getOrPut(gpa, refToIndex(value).?); 7348 if (!gop.found_existing) { 7349 // Make a new capture for this value but don't add it to the declaring_gz yet 7350 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 7351 .tag = .closure_capture, 7352 .data = .{ .un_tok = .{ 7353 .operand = value, 7354 .src_tok = ns.?.declaring_gz.?.tokenIndexToRelative(token), 7355 } }, 7356 }); 7357 gop.value_ptr.* = @intCast(Zir.Inst.Index, gz.astgen.instructions.len - 1); 7358 } 7359 7360 // Add an instruction to get the value from the closure into 7361 // our current context 7362 return try gz.addInstNode(.closure_get, gop.value_ptr.*, inner_ref_node); 7363 } 7364 7365 fn stringLiteral( 7366 gz: *GenZir, 7367 ri: ResultInfo, 7368 node: Ast.Node.Index, 7369 ) InnerError!Zir.Inst.Ref { 7370 const astgen = gz.astgen; 7371 const tree = astgen.tree; 7372 const main_tokens = tree.nodes.items(.main_token); 7373 const str_lit_token = main_tokens[node]; 7374 const str = try astgen.strLitAsString(str_lit_token); 7375 const result = try gz.add(.{ 7376 .tag = .str, 7377 .data = .{ .str = .{ 7378 .start = str.index, 7379 .len = str.len, 7380 } }, 7381 }); 7382 return rvalue(gz, ri, result, node); 7383 } 7384 7385 fn multilineStringLiteral( 7386 gz: *GenZir, 7387 ri: ResultInfo, 7388 node: Ast.Node.Index, 7389 ) InnerError!Zir.Inst.Ref { 7390 const astgen = gz.astgen; 7391 const str = try astgen.strLitNodeAsString(node); 7392 const result = try gz.add(.{ 7393 .tag = .str, 7394 .data = .{ .str = .{ 7395 .start = str.index, 7396 .len = str.len, 7397 } }, 7398 }); 7399 return rvalue(gz, ri, result, node); 7400 } 7401 7402 fn charLiteral(gz: *GenZir, ri: ResultInfo, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { 7403 const astgen = gz.astgen; 7404 const tree = astgen.tree; 7405 const main_tokens = tree.nodes.items(.main_token); 7406 const main_token = main_tokens[node]; 7407 const slice = tree.tokenSlice(main_token); 7408 7409 switch (std.zig.parseCharLiteral(slice)) { 7410 .success => |codepoint| { 7411 const result = try gz.addInt(codepoint); 7412 return rvalue(gz, ri, result, node); 7413 }, 7414 .failure => |err| return astgen.failWithStrLitError(err, main_token, slice, 0), 7415 } 7416 } 7417 7418 const Sign = enum { negative, positive }; 7419 7420 fn numberLiteral(gz: *GenZir, ri: ResultInfo, node: Ast.Node.Index, source_node: Ast.Node.Index, sign: Sign) InnerError!Zir.Inst.Ref { 7421 const astgen = gz.astgen; 7422 const tree = astgen.tree; 7423 const main_tokens = tree.nodes.items(.main_token); 7424 const num_token = main_tokens[node]; 7425 const bytes = tree.tokenSlice(num_token); 7426 7427 const result: Zir.Inst.Ref = switch (std.zig.parseNumberLiteral(bytes)) { 7428 .int => |num| switch (num) { 7429 0 => .zero, 7430 1 => .one, 7431 else => try gz.addInt(num), 7432 }, 7433 .big_int => |base| big: { 7434 const gpa = astgen.gpa; 7435 var big_int = try std.math.big.int.Managed.init(gpa); 7436 defer big_int.deinit(); 7437 const prefix_offset = @as(u8, 2) * @boolToInt(base != .decimal); 7438 big_int.setString(@enumToInt(base), bytes[prefix_offset..]) catch |err| switch (err) { 7439 error.InvalidCharacter => unreachable, // caught in `parseNumberLiteral` 7440 error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above 7441 error.OutOfMemory => return error.OutOfMemory, 7442 }; 7443 7444 const limbs = big_int.limbs[0..big_int.len()]; 7445 assert(big_int.isPositive()); 7446 break :big try gz.addIntBig(limbs); 7447 }, 7448 .float => { 7449 const unsigned_float_number = std.fmt.parseFloat(f128, bytes) catch |err| switch (err) { 7450 error.InvalidCharacter => unreachable, // validated by tokenizer 7451 }; 7452 const float_number = switch (sign) { 7453 .negative => -unsigned_float_number, 7454 .positive => unsigned_float_number, 7455 }; 7456 // If the value fits into a f64 without losing any precision, store it that way. 7457 @setFloatMode(.Strict); 7458 const smaller_float = @floatCast(f64, float_number); 7459 const bigger_again: f128 = smaller_float; 7460 if (bigger_again == float_number) { 7461 const result = try gz.addFloat(smaller_float); 7462 return rvalue(gz, ri, result, source_node); 7463 } 7464 // We need to use 128 bits. Break the float into 4 u32 values so we can 7465 // put it into the `extra` array. 7466 const int_bits = @bitCast(u128, float_number); 7467 const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{ 7468 .piece0 = @truncate(u32, int_bits), 7469 .piece1 = @truncate(u32, int_bits >> 32), 7470 .piece2 = @truncate(u32, int_bits >> 64), 7471 .piece3 = @truncate(u32, int_bits >> 96), 7472 }); 7473 return rvalue(gz, ri, result, source_node); 7474 }, 7475 .failure => |err| return astgen.failWithNumberError(err, num_token, bytes), 7476 }; 7477 7478 if (sign == .positive) { 7479 return rvalue(gz, ri, result, source_node); 7480 } else { 7481 const negated = try gz.addUnNode(.negate, result, source_node); 7482 return rvalue(gz, ri, negated, source_node); 7483 } 7484 } 7485 7486 fn failWithNumberError(astgen: *AstGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) InnerError { 7487 const is_float = std.mem.indexOfScalar(u8, bytes, '.') != null; 7488 switch (err) { 7489 .leading_zero => if (is_float) { 7490 return astgen.failTok(token, "number '{s}' has leading zero", .{bytes}); 7491 } else { 7492 return astgen.failTokNotes(token, "number '{s}' has leading zero", .{bytes}, &.{ 7493 try astgen.errNoteTok(token, "use '0o' prefix for octal literals", .{}), 7494 }); 7495 }, 7496 .digit_after_base => return astgen.failTok(token, "expected a digit after base prefix", .{}), 7497 .upper_case_base => |i| return astgen.failOff(token, @intCast(u32, i), "base prefix must be lowercase", .{}), 7498 .invalid_float_base => |i| return astgen.failOff(token, @intCast(u32, i), "invalid base for float literal", .{}), 7499 .repeated_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "repeated digit separator", .{}), 7500 .invalid_underscore_after_special => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before digit separator", .{}), 7501 .invalid_digit => |info| return astgen.failOff(token, @intCast(u32, info.i), "invalid digit '{c}' for {s} base", .{ bytes[info.i], @tagName(info.base) }), 7502 .invalid_digit_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "invalid digit '{c}' in exponent", .{bytes[i]}), 7503 .duplicate_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "duplicate exponent", .{}), 7504 .invalid_hex_exponent => |i| return astgen.failOff(token, @intCast(u32, i), "hex exponent in decimal float", .{}), 7505 .exponent_after_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before exponent", .{}), 7506 .special_after_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit before '{c}'", .{bytes[i]}), 7507 .trailing_special => |i| return astgen.failOff(token, @intCast(u32, i), "expected digit after '{c}'", .{bytes[i - 1]}), 7508 .trailing_underscore => |i| return astgen.failOff(token, @intCast(u32, i), "trailing digit separator", .{}), 7509 .duplicate_period => unreachable, // Validated by tokenizer 7510 .invalid_character => unreachable, // Validated by tokenizer 7511 .invalid_exponent_sign => unreachable, // Validated by tokenizer 7512 } 7513 } 7514 7515 fn asmExpr( 7516 gz: *GenZir, 7517 scope: *Scope, 7518 ri: ResultInfo, 7519 node: Ast.Node.Index, 7520 full: Ast.full.Asm, 7521 ) InnerError!Zir.Inst.Ref { 7522 const astgen = gz.astgen; 7523 const tree = astgen.tree; 7524 const main_tokens = tree.nodes.items(.main_token); 7525 const node_datas = tree.nodes.items(.data); 7526 const node_tags = tree.nodes.items(.tag); 7527 const token_tags = tree.tokens.items(.tag); 7528 7529 const TagAndTmpl = struct { tag: Zir.Inst.Extended, tmpl: u32 }; 7530 const tag_and_tmpl: TagAndTmpl = switch (node_tags[full.ast.template]) { 7531 .string_literal => .{ 7532 .tag = .@"asm", 7533 .tmpl = (try astgen.strLitAsString(main_tokens[full.ast.template])).index, 7534 }, 7535 .multiline_string_literal => .{ 7536 .tag = .@"asm", 7537 .tmpl = (try astgen.strLitNodeAsString(full.ast.template)).index, 7538 }, 7539 else => .{ 7540 .tag = .asm_expr, 7541 .tmpl = @enumToInt(try comptimeExpr(gz, scope, .{ .rl = .none }, full.ast.template)), 7542 }, 7543 }; 7544 7545 // See https://github.com/ziglang/zig/issues/215 and related issues discussing 7546 // possible inline assembly improvements. Until then here is status quo AstGen 7547 // for assembly syntax. It's used by std lib crypto aesni.zig. 7548 const is_container_asm = astgen.fn_block == null; 7549 if (is_container_asm) { 7550 if (full.volatile_token) |t| 7551 return astgen.failTok(t, "volatile is meaningless on global assembly", .{}); 7552 if (full.outputs.len != 0 or full.inputs.len != 0 or full.first_clobber != null) 7553 return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{}); 7554 } else { 7555 if (full.outputs.len == 0 and full.volatile_token == null) { 7556 return astgen.failNode(node, "assembly expression with no output must be marked volatile", .{}); 7557 } 7558 } 7559 if (full.outputs.len > 32) { 7560 return astgen.failNode(full.outputs[32], "too many asm outputs", .{}); 7561 } 7562 var outputs_buffer: [32]Zir.Inst.Asm.Output = undefined; 7563 const outputs = outputs_buffer[0..full.outputs.len]; 7564 7565 var output_type_bits: u32 = 0; 7566 7567 for (full.outputs) |output_node, i| { 7568 const symbolic_name = main_tokens[output_node]; 7569 const name = try astgen.identAsString(symbolic_name); 7570 const constraint_token = symbolic_name + 2; 7571 const constraint = (try astgen.strLitAsString(constraint_token)).index; 7572 const has_arrow = token_tags[symbolic_name + 4] == .arrow; 7573 if (has_arrow) { 7574 if (output_type_bits != 0) { 7575 return astgen.failNode(output_node, "inline assembly allows up to one output value", .{}); 7576 } 7577 output_type_bits |= @as(u32, 1) << @intCast(u5, i); 7578 const out_type_node = node_datas[output_node].lhs; 7579 const out_type_inst = try typeExpr(gz, scope, out_type_node); 7580 outputs[i] = .{ 7581 .name = name, 7582 .constraint = constraint, 7583 .operand = out_type_inst, 7584 }; 7585 } else { 7586 const ident_token = symbolic_name + 4; 7587 // TODO have a look at #215 and related issues and decide how to 7588 // handle outputs. Do we want this to be identifiers? 7589 // Or maybe we want to force this to be expressions with a pointer type. 7590 outputs[i] = .{ 7591 .name = name, 7592 .constraint = constraint, 7593 .operand = try localVarRef(gz, scope, .{ .rl = .ref }, node, ident_token), 7594 }; 7595 } 7596 } 7597 7598 if (full.inputs.len > 32) { 7599 return astgen.failNode(full.inputs[32], "too many asm inputs", .{}); 7600 } 7601 var inputs_buffer: [32]Zir.Inst.Asm.Input = undefined; 7602 const inputs = inputs_buffer[0..full.inputs.len]; 7603 7604 for (full.inputs) |input_node, i| { 7605 const symbolic_name = main_tokens[input_node]; 7606 const name = try astgen.identAsString(symbolic_name); 7607 const constraint_token = symbolic_name + 2; 7608 const constraint = (try astgen.strLitAsString(constraint_token)).index; 7609 const operand = try expr(gz, scope, .{ .rl = .none }, node_datas[input_node].lhs); 7610 inputs[i] = .{ 7611 .name = name, 7612 .constraint = constraint, 7613 .operand = operand, 7614 }; 7615 } 7616 7617 var clobbers_buffer: [32]u32 = undefined; 7618 var clobber_i: usize = 0; 7619 if (full.first_clobber) |first_clobber| clobbers: { 7620 // asm ("foo" ::: "a", "b") 7621 // asm ("foo" ::: "a", "b",) 7622 var tok_i = first_clobber; 7623 while (true) : (tok_i += 1) { 7624 if (clobber_i >= clobbers_buffer.len) { 7625 return astgen.failTok(tok_i, "too many asm clobbers", .{}); 7626 } 7627 clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index; 7628 clobber_i += 1; 7629 tok_i += 1; 7630 switch (token_tags[tok_i]) { 7631 .r_paren => break :clobbers, 7632 .comma => { 7633 if (token_tags[tok_i + 1] == .r_paren) { 7634 break :clobbers; 7635 } else { 7636 continue; 7637 } 7638 }, 7639 else => unreachable, 7640 } 7641 } 7642 } 7643 7644 const result = try gz.addAsm(.{ 7645 .tag = tag_and_tmpl.tag, 7646 .node = node, 7647 .asm_source = tag_and_tmpl.tmpl, 7648 .is_volatile = full.volatile_token != null, 7649 .output_type_bits = output_type_bits, 7650 .outputs = outputs, 7651 .inputs = inputs, 7652 .clobbers = clobbers_buffer[0..clobber_i], 7653 }); 7654 return rvalue(gz, ri, result, node); 7655 } 7656 7657 fn as( 7658 gz: *GenZir, 7659 scope: *Scope, 7660 ri: ResultInfo, 7661 node: Ast.Node.Index, 7662 lhs: Ast.Node.Index, 7663 rhs: Ast.Node.Index, 7664 ) InnerError!Zir.Inst.Ref { 7665 const dest_type = try typeExpr(gz, scope, lhs); 7666 switch (ri.rl) { 7667 .none, .discard, .ref, .ty, .coerced_ty => { 7668 const result = try reachableExpr(gz, scope, .{ .rl = .{ .ty = dest_type } }, rhs, node); 7669 return rvalue(gz, ri, result, node); 7670 }, 7671 .ptr => |result_ptr| { 7672 return asRlPtr(gz, scope, ri, node, result_ptr.inst, rhs, dest_type); 7673 }, 7674 .inferred_ptr => |result_ptr| { 7675 return asRlPtr(gz, scope, ri, node, result_ptr, rhs, dest_type); 7676 }, 7677 .block_ptr => |block_scope| { 7678 return asRlPtr(gz, scope, ri, node, block_scope.rl_ptr, rhs, dest_type); 7679 }, 7680 } 7681 } 7682 7683 fn unionInit( 7684 gz: *GenZir, 7685 scope: *Scope, 7686 ri: ResultInfo, 7687 node: Ast.Node.Index, 7688 params: []const Ast.Node.Index, 7689 ) InnerError!Zir.Inst.Ref { 7690 const union_type = try typeExpr(gz, scope, params[0]); 7691 const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); 7692 const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ 7693 .container_type = union_type, 7694 .field_name = field_name, 7695 }); 7696 const init = try reachableExpr(gz, scope, .{ .rl = .{ .ty = field_type } }, params[2], node); 7697 const result = try gz.addPlNode(.union_init, node, Zir.Inst.UnionInit{ 7698 .union_type = union_type, 7699 .init = init, 7700 .field_name = field_name, 7701 }); 7702 return rvalue(gz, ri, result, node); 7703 } 7704 7705 fn asRlPtr( 7706 parent_gz: *GenZir, 7707 scope: *Scope, 7708 ri: ResultInfo, 7709 src_node: Ast.Node.Index, 7710 result_ptr: Zir.Inst.Ref, 7711 operand_node: Ast.Node.Index, 7712 dest_type: Zir.Inst.Ref, 7713 ) InnerError!Zir.Inst.Ref { 7714 var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr, src_node); 7715 defer as_scope.unstack(); 7716 7717 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .rl = .{ .block_ptr = &as_scope } }, operand_node, src_node); 7718 return as_scope.finishCoercion(parent_gz, ri, operand_node, result, dest_type); 7719 } 7720 7721 fn bitCast( 7722 gz: *GenZir, 7723 scope: *Scope, 7724 ri: ResultInfo, 7725 node: Ast.Node.Index, 7726 lhs: Ast.Node.Index, 7727 rhs: Ast.Node.Index, 7728 ) InnerError!Zir.Inst.Ref { 7729 const dest_type = try reachableTypeExpr(gz, scope, lhs, node); 7730 const operand = try reachableExpr(gz, scope, .{ .rl = .none }, rhs, node); 7731 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ 7732 .lhs = dest_type, 7733 .rhs = operand, 7734 }); 7735 return rvalue(gz, ri, result, node); 7736 } 7737 7738 fn typeOf( 7739 gz: *GenZir, 7740 scope: *Scope, 7741 ri: ResultInfo, 7742 node: Ast.Node.Index, 7743 args: []const Ast.Node.Index, 7744 ) InnerError!Zir.Inst.Ref { 7745 const astgen = gz.astgen; 7746 if (args.len < 1) { 7747 return astgen.failNode(node, "expected at least 1 argument, found 0", .{}); 7748 } 7749 const gpa = astgen.gpa; 7750 if (args.len == 1) { 7751 const typeof_inst = try gz.makeBlockInst(.typeof_builtin, node); 7752 7753 var typeof_scope = gz.makeSubBlock(scope); 7754 typeof_scope.force_comptime = false; 7755 typeof_scope.c_import = false; 7756 defer typeof_scope.unstack(); 7757 7758 const ty_expr = try reachableExpr(&typeof_scope, &typeof_scope.base, .{ .rl = .none }, args[0], node); 7759 if (!gz.refIsNoReturn(ty_expr)) { 7760 _ = try typeof_scope.addBreak(.break_inline, typeof_inst, ty_expr); 7761 } 7762 try typeof_scope.setBlockBody(typeof_inst); 7763 7764 // typeof_scope unstacked now, can add new instructions to gz 7765 try gz.instructions.append(gpa, typeof_inst); 7766 return rvalue(gz, ri, indexToRef(typeof_inst), node); 7767 } 7768 const payload_size: u32 = std.meta.fields(Zir.Inst.TypeOfPeer).len; 7769 const payload_index = try reserveExtra(astgen, payload_size + args.len); 7770 var args_index = payload_index + payload_size; 7771 7772 const typeof_inst = try gz.addExtendedMultiOpPayloadIndex(.typeof_peer, payload_index, args.len); 7773 7774 var typeof_scope = gz.makeSubBlock(scope); 7775 typeof_scope.force_comptime = false; 7776 7777 for (args) |arg, i| { 7778 const param_ref = try reachableExpr(&typeof_scope, &typeof_scope.base, .{ .rl = .none }, arg, node); 7779 astgen.extra.items[args_index + i] = @enumToInt(param_ref); 7780 } 7781 _ = try typeof_scope.addBreak(.break_inline, refToIndex(typeof_inst).?, .void_value); 7782 7783 const body = typeof_scope.instructionsSlice(); 7784 const body_len = astgen.countBodyLenAfterFixups(body); 7785 astgen.setExtra(payload_index, Zir.Inst.TypeOfPeer{ 7786 .body_len = @intCast(u32, body_len), 7787 .body_index = @intCast(u32, astgen.extra.items.len), 7788 .src_node = gz.nodeIndexToRelative(node), 7789 }); 7790 try astgen.extra.ensureUnusedCapacity(gpa, body_len); 7791 astgen.appendBodyWithFixups(body); 7792 typeof_scope.unstack(); 7793 7794 return rvalue(gz, ri, typeof_inst, node); 7795 } 7796 7797 fn builtinCall( 7798 gz: *GenZir, 7799 scope: *Scope, 7800 ri: ResultInfo, 7801 node: Ast.Node.Index, 7802 params: []const Ast.Node.Index, 7803 ) InnerError!Zir.Inst.Ref { 7804 const astgen = gz.astgen; 7805 const tree = astgen.tree; 7806 const main_tokens = tree.nodes.items(.main_token); 7807 7808 const builtin_token = main_tokens[node]; 7809 const builtin_name = tree.tokenSlice(builtin_token); 7810 7811 // We handle the different builtins manually because they have different semantics depending 7812 // on the function. For example, `@as` and others participate in result location semantics, 7813 // and `@cImport` creates a special scope that collects a .c source code text buffer. 7814 // Also, some builtins have a variable number of parameters. 7815 7816 const info = BuiltinFn.list.get(builtin_name) orelse { 7817 return astgen.failNode(node, "invalid builtin function: '{s}'", .{ 7818 builtin_name, 7819 }); 7820 }; 7821 if (info.param_count) |expected| { 7822 if (expected != params.len) { 7823 const s = if (expected == 1) "" else "s"; 7824 return astgen.failNode(node, "expected {d} argument{s}, found {d}", .{ 7825 expected, s, params.len, 7826 }); 7827 } 7828 } 7829 7830 switch (info.tag) { 7831 .import => { 7832 const node_tags = tree.nodes.items(.tag); 7833 const operand_node = params[0]; 7834 7835 if (node_tags[operand_node] != .string_literal) { 7836 // Spec reference: https://github.com/ziglang/zig/issues/2206 7837 return astgen.failNode(operand_node, "@import operand must be a string literal", .{}); 7838 } 7839 const str_lit_token = main_tokens[operand_node]; 7840 const str = try astgen.strLitAsString(str_lit_token); 7841 const str_slice = astgen.string_bytes.items[str.index..][0..str.len]; 7842 if (mem.indexOfScalar(u8, str_slice, 0) != null) { 7843 return astgen.failTok(str_lit_token, "import path cannot contain null bytes", .{}); 7844 } else if (str.len == 0) { 7845 return astgen.failTok(str_lit_token, "import path cannot be empty", .{}); 7846 } 7847 const result = try gz.addStrTok(.import, str.index, str_lit_token); 7848 const gop = try astgen.imports.getOrPut(astgen.gpa, str.index); 7849 if (!gop.found_existing) { 7850 gop.value_ptr.* = str_lit_token; 7851 } 7852 return rvalue(gz, ri, result, node); 7853 }, 7854 .compile_log => { 7855 const payload_index = try addExtra(gz.astgen, Zir.Inst.NodeMultiOp{ 7856 .src_node = gz.nodeIndexToRelative(node), 7857 }); 7858 var extra_index = try reserveExtra(gz.astgen, params.len); 7859 for (params) |param| { 7860 const param_ref = try expr(gz, scope, .{ .rl = .none }, param); 7861 astgen.extra.items[extra_index] = @enumToInt(param_ref); 7862 extra_index += 1; 7863 } 7864 const result = try gz.addExtendedMultiOpPayloadIndex(.compile_log, payload_index, params.len); 7865 return rvalue(gz, ri, result, node); 7866 }, 7867 .field => { 7868 if (ri.rl == .ref) { 7869 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ 7870 .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), 7871 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]), 7872 }); 7873 } 7874 const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ 7875 .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]), 7876 .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]), 7877 }); 7878 return rvalue(gz, ri, result, node); 7879 }, 7880 7881 // zig fmt: off 7882 .as => return as( gz, scope, ri, node, params[0], params[1]), 7883 .bit_cast => return bitCast( gz, scope, ri, node, params[0], params[1]), 7884 .TypeOf => return typeOf( gz, scope, ri, node, params), 7885 .union_init => return unionInit(gz, scope, ri, node, params), 7886 .c_import => return cImport( gz, scope, node, params[0]), 7887 // zig fmt: on 7888 7889 .@"export" => { 7890 const node_tags = tree.nodes.items(.tag); 7891 const node_datas = tree.nodes.items(.data); 7892 // This function causes a Decl to be exported. The first parameter is not an expression, 7893 // but an identifier of the Decl to be exported. 7894 var namespace: Zir.Inst.Ref = .none; 7895 var decl_name: u32 = 0; 7896 switch (node_tags[params[0]]) { 7897 .identifier => { 7898 const ident_token = main_tokens[params[0]]; 7899 decl_name = try astgen.identAsString(ident_token); 7900 7901 var s = scope; 7902 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already 7903 while (true) switch (s.tag) { 7904 .local_val => { 7905 const local_val = s.cast(Scope.LocalVal).?; 7906 if (local_val.name == decl_name) { 7907 local_val.used = ident_token; 7908 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ 7909 .operand = local_val.inst, 7910 .options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .export_options_type } }, params[1]), 7911 }); 7912 return rvalue(gz, ri, .void_value, node); 7913 } 7914 s = local_val.parent; 7915 }, 7916 .local_ptr => { 7917 const local_ptr = s.cast(Scope.LocalPtr).?; 7918 if (local_ptr.name == decl_name) { 7919 if (!local_ptr.maybe_comptime) 7920 return astgen.failNode(params[0], "unable to export runtime-known value", .{}); 7921 local_ptr.used = ident_token; 7922 const loaded = try gz.addUnNode(.load, local_ptr.ptr, node); 7923 _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ 7924 .operand = loaded, 7925 .options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .export_options_type } }, params[1]), 7926 }); 7927 return rvalue(gz, ri, .void_value, node); 7928 } 7929 s = local_ptr.parent; 7930 }, 7931 .gen_zir => s = s.cast(GenZir).?.parent, 7932 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 7933 .namespace => { 7934 const ns = s.cast(Scope.Namespace).?; 7935 if (ns.decls.get(decl_name)) |i| { 7936 if (found_already) |f| { 7937 return astgen.failNodeNotes(node, "ambiguous reference", .{}, &.{ 7938 try astgen.errNoteNode(f, "declared here", .{}), 7939 try astgen.errNoteNode(i, "also declared here", .{}), 7940 }); 7941 } 7942 // We found a match but must continue looking for ambiguous references to decls. 7943 found_already = i; 7944 } 7945 s = ns.parent; 7946 }, 7947 .top => break, 7948 }; 7949 }, 7950 .field_access => { 7951 const namespace_node = node_datas[params[0]].lhs; 7952 namespace = try typeExpr(gz, scope, namespace_node); 7953 const dot_token = main_tokens[params[0]]; 7954 const field_ident = dot_token + 1; 7955 decl_name = try astgen.identAsString(field_ident); 7956 }, 7957 else => return astgen.failNode(params[0], "symbol to export must identify a declaration", .{}), 7958 } 7959 const options = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .export_options_type } }, params[1]); 7960 _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ 7961 .namespace = namespace, 7962 .decl_name = decl_name, 7963 .options = options, 7964 }); 7965 return rvalue(gz, ri, .void_value, node); 7966 }, 7967 .@"extern" => { 7968 const type_inst = try typeExpr(gz, scope, params[0]); 7969 const options = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .extern_options_type } }, params[1]); 7970 const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{ 7971 .node = gz.nodeIndexToRelative(node), 7972 .lhs = type_inst, 7973 .rhs = options, 7974 }); 7975 return rvalue(gz, ri, result, node); 7976 }, 7977 .fence => { 7978 const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .atomic_order_type } }, params[0]); 7979 const result = try gz.addExtendedPayload(.fence, Zir.Inst.UnNode{ 7980 .node = gz.nodeIndexToRelative(node), 7981 .operand = order, 7982 }); 7983 return rvalue(gz, ri, result, node); 7984 }, 7985 .set_float_mode => { 7986 const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .float_mode_type } }, params[0]); 7987 const result = try gz.addExtendedPayload(.set_float_mode, Zir.Inst.UnNode{ 7988 .node = gz.nodeIndexToRelative(node), 7989 .operand = order, 7990 }); 7991 return rvalue(gz, ri, result, node); 7992 }, 7993 .set_align_stack => { 7994 const order = try expr(gz, scope, align_ri, params[0]); 7995 const result = try gz.addExtendedPayload(.set_align_stack, Zir.Inst.UnNode{ 7996 .node = gz.nodeIndexToRelative(node), 7997 .operand = order, 7998 }); 7999 return rvalue(gz, ri, result, node); 8000 }, 8001 8002 .src => { 8003 const token_starts = tree.tokens.items(.start); 8004 const node_start = token_starts[tree.firstToken(node)]; 8005 astgen.advanceSourceCursor(node_start); 8006 const result = try gz.addExtendedPayload(.builtin_src, Zir.Inst.Src{ 8007 .node = gz.nodeIndexToRelative(node), 8008 .line = astgen.source_line, 8009 .column = astgen.source_column, 8010 }); 8011 return rvalue(gz, ri, result, node); 8012 }, 8013 8014 // zig fmt: off 8015 .This => return rvalue(gz, ri, try gz.addNodeExtended(.this, node), node), 8016 .return_address => return rvalue(gz, ri, try gz.addNodeExtended(.ret_addr, node), node), 8017 .error_return_trace => return rvalue(gz, ri, try gz.addNodeExtended(.error_return_trace, node), node), 8018 .frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node), 8019 .frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node), 8020 .breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node), 8021 8022 .type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info), 8023 .size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of), 8024 .bit_size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .bit_size_of), 8025 .align_of => return simpleUnOpType(gz, scope, ri, node, params[0], .align_of), 8026 8027 .ptr_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ptr_to_int), 8028 .compile_error => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .compile_error), 8029 .set_eval_branch_quota => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .set_eval_branch_quota), 8030 .enum_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .enum_to_int), 8031 .bool_to_int => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .bool_to_int), 8032 .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .embed_file), 8033 .error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .anyerror_type } }, params[0], .error_name), 8034 .set_cold => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_cold), 8035 .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety), 8036 .sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt), 8037 .sin => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sin), 8038 .cos => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .cos), 8039 .tan => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .tan), 8040 .exp => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .exp), 8041 .exp2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .exp2), 8042 .log => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log), 8043 .log2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log2), 8044 .log10 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log10), 8045 .fabs => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .fabs), 8046 .floor => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .floor), 8047 .ceil => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ceil), 8048 .trunc => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .trunc), 8049 .round => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .round), 8050 .tag_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .tag_name), 8051 .type_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .type_name), 8052 .Frame => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_type), 8053 .frame_size => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_size), 8054 8055 .float_to_int => return typeCast(gz, scope, ri, node, params[0], params[1], .float_to_int), 8056 .int_to_float => return typeCast(gz, scope, ri, node, params[0], params[1], .int_to_float), 8057 .int_to_ptr => return typeCast(gz, scope, ri, node, params[0], params[1], .int_to_ptr), 8058 .int_to_enum => return typeCast(gz, scope, ri, node, params[0], params[1], .int_to_enum), 8059 .float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast), 8060 .int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast), 8061 .ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast), 8062 .truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate), 8063 // zig fmt: on 8064 8065 .Type => { 8066 const operand = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .type_info_type } }, params[0]); 8067 8068 const gpa = gz.astgen.gpa; 8069 8070 try gz.instructions.ensureUnusedCapacity(gpa, 1); 8071 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 8072 8073 const payload_index = try gz.astgen.addExtra(Zir.Inst.UnNode{ 8074 .node = gz.nodeIndexToRelative(node), 8075 .operand = operand, 8076 }); 8077 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 8078 gz.astgen.instructions.appendAssumeCapacity(.{ 8079 .tag = .extended, 8080 .data = .{ .extended = .{ 8081 .opcode = .reify, 8082 .small = @enumToInt(gz.anon_name_strategy), 8083 .operand = payload_index, 8084 } }, 8085 }); 8086 gz.instructions.appendAssumeCapacity(new_index); 8087 const result = indexToRef(new_index); 8088 return rvalue(gz, ri, result, node); 8089 }, 8090 .panic => { 8091 try emitDbgNode(gz, node); 8092 return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], if (gz.force_comptime) .panic_comptime else .panic); 8093 }, 8094 .error_to_int => { 8095 const operand = try expr(gz, scope, .{ .rl = .none }, params[0]); 8096 const result = try gz.addExtendedPayload(.error_to_int, Zir.Inst.UnNode{ 8097 .node = gz.nodeIndexToRelative(node), 8098 .operand = operand, 8099 }); 8100 return rvalue(gz, ri, result, node); 8101 }, 8102 .int_to_error => { 8103 const operand = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, params[0]); 8104 const result = try gz.addExtendedPayload(.int_to_error, Zir.Inst.UnNode{ 8105 .node = gz.nodeIndexToRelative(node), 8106 .operand = operand, 8107 }); 8108 return rvalue(gz, ri, result, node); 8109 }, 8110 .align_cast => { 8111 const dest_align = try comptimeExpr(gz, scope, align_ri, params[0]); 8112 const rhs = try expr(gz, scope, .{ .rl = .none }, params[1]); 8113 const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{ 8114 .lhs = dest_align, 8115 .rhs = rhs, 8116 }); 8117 return rvalue(gz, ri, result, node); 8118 }, 8119 .err_set_cast => { 8120 try emitDbgNode(gz, node); 8121 8122 const result = try gz.addExtendedPayload(.err_set_cast, Zir.Inst.BinNode{ 8123 .lhs = try typeExpr(gz, scope, params[0]), 8124 .rhs = try expr(gz, scope, .{ .rl = .none }, params[1]), 8125 .node = gz.nodeIndexToRelative(node), 8126 }); 8127 return rvalue(gz, ri, result, node); 8128 }, 8129 .addrspace_cast => { 8130 const result = try gz.addExtendedPayload(.addrspace_cast, Zir.Inst.BinNode{ 8131 .lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, params[0]), 8132 .rhs = try expr(gz, scope, .{ .rl = .none }, params[1]), 8133 .node = gz.nodeIndexToRelative(node), 8134 }); 8135 return rvalue(gz, ri, result, node); 8136 }, 8137 8138 // zig fmt: off 8139 .has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl), 8140 .has_field => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_field), 8141 8142 .clz => return bitBuiltin(gz, scope, ri, node, params[0], .clz), 8143 .ctz => return bitBuiltin(gz, scope, ri, node, params[0], .ctz), 8144 .pop_count => return bitBuiltin(gz, scope, ri, node, params[0], .pop_count), 8145 .byte_swap => return bitBuiltin(gz, scope, ri, node, params[0], .byte_swap), 8146 .bit_reverse => return bitBuiltin(gz, scope, ri, node, params[0], .bit_reverse), 8147 8148 .div_exact => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_exact), 8149 .div_floor => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_floor), 8150 .div_trunc => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_trunc), 8151 .mod => return divBuiltin(gz, scope, ri, node, params[0], params[1], .mod), 8152 .rem => return divBuiltin(gz, scope, ri, node, params[0], params[1], .rem), 8153 8154 .shl_exact => return shiftOp(gz, scope, ri, node, params[0], params[1], .shl_exact), 8155 .shr_exact => return shiftOp(gz, scope, ri, node, params[0], params[1], .shr_exact), 8156 8157 .bit_offset_of => return offsetOf(gz, scope, ri, node, params[0], params[1], .bit_offset_of), 8158 .offset_of => return offsetOf(gz, scope, ri, node, params[0], params[1], .offset_of), 8159 8160 .c_undef => return simpleCBuiltin(gz, scope, ri, node, params[0], .c_undef), 8161 .c_include => return simpleCBuiltin(gz, scope, ri, node, params[0], .c_include), 8162 8163 .cmpxchg_strong => return cmpxchg(gz, scope, ri, node, params, 1), 8164 .cmpxchg_weak => return cmpxchg(gz, scope, ri, node, params, 0), 8165 // zig fmt: on 8166 8167 .wasm_memory_size => { 8168 const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); 8169 const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ 8170 .node = gz.nodeIndexToRelative(node), 8171 .operand = operand, 8172 }); 8173 return rvalue(gz, ri, result, node); 8174 }, 8175 .wasm_memory_grow => { 8176 const index_arg = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); 8177 const delta_arg = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[1]); 8178 const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ 8179 .node = gz.nodeIndexToRelative(node), 8180 .lhs = index_arg, 8181 .rhs = delta_arg, 8182 }); 8183 return rvalue(gz, ri, result, node); 8184 }, 8185 .c_define => { 8186 if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); 8187 const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0]); 8188 const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); 8189 const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ 8190 .node = gz.nodeIndexToRelative(node), 8191 .lhs = name, 8192 .rhs = value, 8193 }); 8194 return rvalue(gz, ri, result, node); 8195 }, 8196 8197 .splat => { 8198 const len = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]); 8199 const scalar = try expr(gz, scope, .{ .rl = .none }, params[1]); 8200 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ 8201 .lhs = len, 8202 .rhs = scalar, 8203 }); 8204 return rvalue(gz, ri, result, node); 8205 }, 8206 .reduce => { 8207 const op = try expr(gz, scope, .{ .rl = .{ .ty = .reduce_op_type } }, params[0]); 8208 const scalar = try expr(gz, scope, .{ .rl = .none }, params[1]); 8209 const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{ 8210 .lhs = op, 8211 .rhs = scalar, 8212 }); 8213 return rvalue(gz, ri, result, node); 8214 }, 8215 8216 .max => { 8217 const a = try expr(gz, scope, .{ .rl = .none }, params[0]); 8218 const b = try expr(gz, scope, .{ .rl = .none }, params[1]); 8219 const result = try gz.addPlNode(.max, node, Zir.Inst.Bin{ 8220 .lhs = a, 8221 .rhs = b, 8222 }); 8223 return rvalue(gz, ri, result, node); 8224 }, 8225 .min => { 8226 const a = try expr(gz, scope, .{ .rl = .none }, params[0]); 8227 const b = try expr(gz, scope, .{ .rl = .none }, params[1]); 8228 const result = try gz.addPlNode(.min, node, Zir.Inst.Bin{ 8229 .lhs = a, 8230 .rhs = b, 8231 }); 8232 return rvalue(gz, ri, result, node); 8233 }, 8234 8235 .add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow), 8236 .sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow), 8237 .mul_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .mul_with_overflow), 8238 .shl_with_overflow => { 8239 const int_type = try typeExpr(gz, scope, params[0]); 8240 const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]); 8241 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]); 8242 const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]); 8243 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type } }, params[2]); 8244 const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]); 8245 const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{ 8246 .node = gz.nodeIndexToRelative(node), 8247 .lhs = lhs, 8248 .rhs = rhs, 8249 .ptr = ptr, 8250 }); 8251 return rvalue(gz, ri, result, node); 8252 }, 8253 8254 .atomic_load => { 8255 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{ 8256 // zig fmt: off 8257 .elem_type = try typeExpr(gz, scope, params[0]), 8258 .ptr = try expr (gz, scope, .{ .rl = .none }, params[1]), 8259 .ordering = try expr (gz, scope, .{ .rl = .{ .coerced_ty = .atomic_order_type } }, params[2]), 8260 // zig fmt: on 8261 }); 8262 return rvalue(gz, ri, result, node); 8263 }, 8264 .atomic_rmw => { 8265 const int_type = try typeExpr(gz, scope, params[0]); 8266 const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{ 8267 // zig fmt: off 8268 .ptr = try expr(gz, scope, .{ .rl = .none }, params[1]), 8269 .operation = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .atomic_rmw_op_type } }, params[2]), 8270 .operand = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[3]), 8271 .ordering = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .atomic_order_type } }, params[4]), 8272 // zig fmt: on 8273 }); 8274 return rvalue(gz, ri, result, node); 8275 }, 8276 .atomic_store => { 8277 const int_type = try typeExpr(gz, scope, params[0]); 8278 const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{ 8279 // zig fmt: off 8280 .ptr = try expr(gz, scope, .{ .rl = .none }, params[1]), 8281 .operand = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[2]), 8282 .ordering = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .atomic_order_type } }, params[3]), 8283 // zig fmt: on 8284 }); 8285 return rvalue(gz, ri, result, node); 8286 }, 8287 .mul_add => { 8288 const float_type = try typeExpr(gz, scope, params[0]); 8289 const mulend1 = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_type } }, params[1]); 8290 const mulend2 = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_type } }, params[2]); 8291 const addend = try expr(gz, scope, .{ .rl = .{ .ty = float_type } }, params[3]); 8292 const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{ 8293 .mulend1 = mulend1, 8294 .mulend2 = mulend2, 8295 .addend = addend, 8296 }); 8297 return rvalue(gz, ri, result, node); 8298 }, 8299 .call => { 8300 const options = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .call_options_type } }, params[0]); 8301 const callee = try calleeExpr(gz, scope, params[1]); 8302 const args = try expr(gz, scope, .{ .rl = .none }, params[2]); 8303 const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ 8304 .options = options, 8305 .callee = callee, 8306 .args = args, 8307 .flags = .{ 8308 .is_nosuspend = gz.nosuspend_node != 0, 8309 .is_comptime = gz.force_comptime, 8310 .ensure_result_used = false, 8311 }, 8312 }); 8313 return rvalue(gz, ri, result, node); 8314 }, 8315 .field_parent_ptr => { 8316 const parent_type = try typeExpr(gz, scope, params[0]); 8317 const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); 8318 const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ 8319 .parent_type = parent_type, 8320 .field_name = field_name, 8321 .field_ptr = try expr(gz, scope, .{ .rl = .none }, params[2]), 8322 }); 8323 return rvalue(gz, ri, result, node); 8324 }, 8325 .memcpy => { 8326 const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{ 8327 .dest = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .manyptr_u8_type } }, params[0]), 8328 .source = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .manyptr_const_u8_type } }, params[1]), 8329 .byte_count = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, params[2]), 8330 }); 8331 return rvalue(gz, ri, result, node); 8332 }, 8333 .memset => { 8334 const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{ 8335 .dest = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .manyptr_u8_type } }, params[0]), 8336 .byte = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u8_type } }, params[1]), 8337 .byte_count = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, params[2]), 8338 }); 8339 return rvalue(gz, ri, result, node); 8340 }, 8341 .shuffle => { 8342 const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{ 8343 .elem_type = try typeExpr(gz, scope, params[0]), 8344 .a = try expr(gz, scope, .{ .rl = .none }, params[1]), 8345 .b = try expr(gz, scope, .{ .rl = .none }, params[2]), 8346 .mask = try comptimeExpr(gz, scope, .{ .rl = .none }, params[3]), 8347 }); 8348 return rvalue(gz, ri, result, node); 8349 }, 8350 .select => { 8351 const result = try gz.addExtendedPayload(.select, Zir.Inst.Select{ 8352 .node = gz.nodeIndexToRelative(node), 8353 .elem_type = try typeExpr(gz, scope, params[0]), 8354 .pred = try expr(gz, scope, .{ .rl = .none }, params[1]), 8355 .a = try expr(gz, scope, .{ .rl = .none }, params[2]), 8356 .b = try expr(gz, scope, .{ .rl = .none }, params[3]), 8357 }); 8358 return rvalue(gz, ri, result, node); 8359 }, 8360 .async_call => { 8361 const result = try gz.addExtendedPayload(.builtin_async_call, Zir.Inst.AsyncCall{ 8362 .node = gz.nodeIndexToRelative(node), 8363 .frame_buffer = try expr(gz, scope, .{ .rl = .none }, params[0]), 8364 .result_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]), 8365 .fn_ptr = try expr(gz, scope, .{ .rl = .none }, params[2]), 8366 .args = try expr(gz, scope, .{ .rl = .none }, params[3]), 8367 }); 8368 return rvalue(gz, ri, result, node); 8369 }, 8370 .Vector => { 8371 const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{ 8372 .lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0]), 8373 .rhs = try typeExpr(gz, scope, params[1]), 8374 }); 8375 return rvalue(gz, ri, result, node); 8376 }, 8377 .prefetch => { 8378 const ptr = try expr(gz, scope, .{ .rl = .none }, params[0]); 8379 const options = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .prefetch_options_type } }, params[1]); 8380 const result = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{ 8381 .node = gz.nodeIndexToRelative(node), 8382 .lhs = ptr, 8383 .rhs = options, 8384 }); 8385 return rvalue(gz, ri, result, node); 8386 }, 8387 } 8388 } 8389 8390 fn simpleNoOpVoid( 8391 gz: *GenZir, 8392 ri: ResultInfo, 8393 node: Ast.Node.Index, 8394 tag: Zir.Inst.Tag, 8395 ) InnerError!Zir.Inst.Ref { 8396 _ = try gz.addNode(tag, node); 8397 return rvalue(gz, ri, .void_value, node); 8398 } 8399 8400 fn hasDeclOrField( 8401 gz: *GenZir, 8402 scope: *Scope, 8403 ri: ResultInfo, 8404 node: Ast.Node.Index, 8405 lhs_node: Ast.Node.Index, 8406 rhs_node: Ast.Node.Index, 8407 tag: Zir.Inst.Tag, 8408 ) InnerError!Zir.Inst.Ref { 8409 const container_type = try typeExpr(gz, scope, lhs_node); 8410 const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, rhs_node); 8411 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 8412 .lhs = container_type, 8413 .rhs = name, 8414 }); 8415 return rvalue(gz, ri, result, node); 8416 } 8417 8418 fn typeCast( 8419 gz: *GenZir, 8420 scope: *Scope, 8421 ri: ResultInfo, 8422 node: Ast.Node.Index, 8423 lhs_node: Ast.Node.Index, 8424 rhs_node: Ast.Node.Index, 8425 tag: Zir.Inst.Tag, 8426 ) InnerError!Zir.Inst.Ref { 8427 try emitDbgNode(gz, node); 8428 8429 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 8430 .lhs = try typeExpr(gz, scope, lhs_node), 8431 .rhs = try expr(gz, scope, .{ .rl = .none }, rhs_node), 8432 }); 8433 return rvalue(gz, ri, result, node); 8434 } 8435 8436 fn simpleUnOpType( 8437 gz: *GenZir, 8438 scope: *Scope, 8439 ri: ResultInfo, 8440 node: Ast.Node.Index, 8441 operand_node: Ast.Node.Index, 8442 tag: Zir.Inst.Tag, 8443 ) InnerError!Zir.Inst.Ref { 8444 const operand = try typeExpr(gz, scope, operand_node); 8445 const result = try gz.addUnNode(tag, operand, node); 8446 return rvalue(gz, ri, result, node); 8447 } 8448 8449 fn simpleUnOp( 8450 gz: *GenZir, 8451 scope: *Scope, 8452 ri: ResultInfo, 8453 node: Ast.Node.Index, 8454 operand_ri: ResultInfo, 8455 operand_node: Ast.Node.Index, 8456 tag: Zir.Inst.Tag, 8457 ) InnerError!Zir.Inst.Ref { 8458 switch (tag) { 8459 .tag_name, .error_name, .ptr_to_int => try emitDbgNode(gz, node), 8460 else => {}, 8461 } 8462 const operand = try expr(gz, scope, operand_ri, operand_node); 8463 const result = try gz.addUnNode(tag, operand, node); 8464 return rvalue(gz, ri, result, node); 8465 } 8466 8467 fn negation( 8468 gz: *GenZir, 8469 scope: *Scope, 8470 ri: ResultInfo, 8471 node: Ast.Node.Index, 8472 ) InnerError!Zir.Inst.Ref { 8473 const astgen = gz.astgen; 8474 const tree = astgen.tree; 8475 const node_tags = tree.nodes.items(.tag); 8476 const node_datas = tree.nodes.items(.data); 8477 8478 // Check for float literal as the sub-expression because we want to preserve 8479 // its negativity rather than having it go through comptime subtraction. 8480 const operand_node = node_datas[node].lhs; 8481 if (node_tags[operand_node] == .number_literal) { 8482 return numberLiteral(gz, ri, operand_node, node, .negative); 8483 } 8484 8485 const operand = try expr(gz, scope, .{ .rl = .none }, operand_node); 8486 const result = try gz.addUnNode(.negate, operand, node); 8487 return rvalue(gz, ri, result, node); 8488 } 8489 8490 fn cmpxchg( 8491 gz: *GenZir, 8492 scope: *Scope, 8493 ri: ResultInfo, 8494 node: Ast.Node.Index, 8495 params: []const Ast.Node.Index, 8496 small: u16, 8497 ) InnerError!Zir.Inst.Ref { 8498 const int_type = try typeExpr(gz, scope, params[0]); 8499 const result = try gz.addExtendedPayloadSmall(.cmpxchg, small, Zir.Inst.Cmpxchg{ 8500 // zig fmt: off 8501 .node = gz.nodeIndexToRelative(node), 8502 .ptr = try expr(gz, scope, .{ .rl = .none }, params[1]), 8503 .expected_value = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[2]), 8504 .new_value = try expr(gz, scope, .{ .rl = .{ .coerced_ty = int_type } }, params[3]), 8505 .success_order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .atomic_order_type } }, params[4]), 8506 .failure_order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .atomic_order_type } }, params[5]), 8507 // zig fmt: on 8508 }); 8509 return rvalue(gz, ri, result, node); 8510 } 8511 8512 fn bitBuiltin( 8513 gz: *GenZir, 8514 scope: *Scope, 8515 ri: ResultInfo, 8516 node: Ast.Node.Index, 8517 operand_node: Ast.Node.Index, 8518 tag: Zir.Inst.Tag, 8519 ) InnerError!Zir.Inst.Ref { 8520 const operand = try expr(gz, scope, .{ .rl = .none }, operand_node); 8521 const result = try gz.addUnNode(tag, operand, node); 8522 return rvalue(gz, ri, result, node); 8523 } 8524 8525 fn divBuiltin( 8526 gz: *GenZir, 8527 scope: *Scope, 8528 ri: ResultInfo, 8529 node: Ast.Node.Index, 8530 lhs_node: Ast.Node.Index, 8531 rhs_node: Ast.Node.Index, 8532 tag: Zir.Inst.Tag, 8533 ) InnerError!Zir.Inst.Ref { 8534 try emitDbgNode(gz, node); 8535 8536 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 8537 .lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node), 8538 .rhs = try expr(gz, scope, .{ .rl = .none }, rhs_node), 8539 }); 8540 return rvalue(gz, ri, result, node); 8541 } 8542 8543 fn simpleCBuiltin( 8544 gz: *GenZir, 8545 scope: *Scope, 8546 ri: ResultInfo, 8547 node: Ast.Node.Index, 8548 operand_node: Ast.Node.Index, 8549 tag: Zir.Inst.Extended, 8550 ) InnerError!Zir.Inst.Ref { 8551 const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; 8552 if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); 8553 const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, operand_node); 8554 _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ 8555 .node = gz.nodeIndexToRelative(node), 8556 .operand = operand, 8557 }); 8558 return rvalue(gz, ri, .void_value, node); 8559 } 8560 8561 fn offsetOf( 8562 gz: *GenZir, 8563 scope: *Scope, 8564 ri: ResultInfo, 8565 node: Ast.Node.Index, 8566 lhs_node: Ast.Node.Index, 8567 rhs_node: Ast.Node.Index, 8568 tag: Zir.Inst.Tag, 8569 ) InnerError!Zir.Inst.Ref { 8570 const type_inst = try typeExpr(gz, scope, lhs_node); 8571 const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, rhs_node); 8572 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 8573 .lhs = type_inst, 8574 .rhs = field_name, 8575 }); 8576 return rvalue(gz, ri, result, node); 8577 } 8578 8579 fn shiftOp( 8580 gz: *GenZir, 8581 scope: *Scope, 8582 ri: ResultInfo, 8583 node: Ast.Node.Index, 8584 lhs_node: Ast.Node.Index, 8585 rhs_node: Ast.Node.Index, 8586 tag: Zir.Inst.Tag, 8587 ) InnerError!Zir.Inst.Ref { 8588 var line = gz.astgen.source_line - gz.decl_line; 8589 var column = gz.astgen.source_column; 8590 const lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node); 8591 8592 switch (gz.astgen.tree.nodes.items(.tag)[node]) { 8593 .shl, .shr => { 8594 maybeAdvanceSourceCursorToMainToken(gz, node); 8595 line = gz.astgen.source_line - gz.decl_line; 8596 column = gz.astgen.source_column; 8597 }, 8598 else => {}, 8599 } 8600 8601 const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); 8602 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type }, .ctx = .shift_op }, rhs_node); 8603 8604 try emitDbgStmt(gz, line, column); 8605 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 8606 .lhs = lhs, 8607 .rhs = rhs, 8608 }); 8609 return rvalue(gz, ri, result, node); 8610 } 8611 8612 fn cImport( 8613 gz: *GenZir, 8614 scope: *Scope, 8615 node: Ast.Node.Index, 8616 body_node: Ast.Node.Index, 8617 ) InnerError!Zir.Inst.Ref { 8618 const astgen = gz.astgen; 8619 const gpa = astgen.gpa; 8620 8621 if (gz.c_import) return gz.astgen.failNode(node, "cannot nest @cImport", .{}); 8622 8623 var block_scope = gz.makeSubBlock(scope); 8624 block_scope.force_comptime = true; 8625 block_scope.c_import = true; 8626 defer block_scope.unstack(); 8627 8628 const block_inst = try gz.makeBlockInst(.c_import, node); 8629 const block_result = try expr(&block_scope, &block_scope.base, .{ .rl = .none }, body_node); 8630 _ = try gz.addUnNode(.ensure_result_used, block_result, node); 8631 if (!gz.refIsNoReturn(block_result)) { 8632 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value); 8633 } 8634 try block_scope.setBlockBody(block_inst); 8635 // block_scope unstacked now, can add new instructions to gz 8636 try gz.instructions.append(gpa, block_inst); 8637 8638 return indexToRef(block_inst); 8639 } 8640 8641 fn overflowArithmetic( 8642 gz: *GenZir, 8643 scope: *Scope, 8644 ri: ResultInfo, 8645 node: Ast.Node.Index, 8646 params: []const Ast.Node.Index, 8647 tag: Zir.Inst.Extended, 8648 ) InnerError!Zir.Inst.Ref { 8649 const int_type = try typeExpr(gz, scope, params[0]); 8650 const ptr_type = try gz.addUnNode(.overflow_arithmetic_ptr, int_type, params[0]); 8651 const lhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[1]); 8652 const rhs = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[2]); 8653 const ptr = try expr(gz, scope, .{ .rl = .{ .ty = ptr_type } }, params[3]); 8654 const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{ 8655 .node = gz.nodeIndexToRelative(node), 8656 .lhs = lhs, 8657 .rhs = rhs, 8658 .ptr = ptr, 8659 }); 8660 return rvalue(gz, ri, result, node); 8661 } 8662 8663 fn callExpr( 8664 gz: *GenZir, 8665 scope: *Scope, 8666 ri: ResultInfo, 8667 node: Ast.Node.Index, 8668 call: Ast.full.Call, 8669 ) InnerError!Zir.Inst.Ref { 8670 const astgen = gz.astgen; 8671 8672 const callee = try calleeExpr(gz, scope, call.ast.fn_expr); 8673 const modifier: std.builtin.CallOptions.Modifier = blk: { 8674 if (gz.force_comptime) { 8675 break :blk .compile_time; 8676 } 8677 if (call.async_token != null) { 8678 break :blk .async_kw; 8679 } 8680 if (gz.nosuspend_node != 0) { 8681 break :blk .no_async; 8682 } 8683 break :blk .auto; 8684 }; 8685 8686 { 8687 astgen.advanceSourceCursor(astgen.tree.tokens.items(.start)[call.ast.lparen]); 8688 const line = astgen.source_line - gz.decl_line; 8689 const column = astgen.source_column; 8690 8691 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 8692 .dbg_stmt = .{ 8693 .line = line, 8694 .column = column, 8695 }, 8696 } }); 8697 } 8698 8699 assert(callee != .none); 8700 assert(node != 0); 8701 8702 const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 8703 const call_inst = Zir.indexToRef(call_index); 8704 try gz.astgen.instructions.append(astgen.gpa, undefined); 8705 try gz.instructions.append(astgen.gpa, call_index); 8706 8707 const scratch_top = astgen.scratch.items.len; 8708 defer astgen.scratch.items.len = scratch_top; 8709 8710 var scratch_index = scratch_top; 8711 try astgen.scratch.resize(astgen.gpa, scratch_top + call.ast.params.len); 8712 8713 for (call.ast.params) |param_node| { 8714 var arg_block = gz.makeSubBlock(scope); 8715 defer arg_block.unstack(); 8716 8717 // `call_inst` is reused to provide the param type. 8718 const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node); 8719 _ = try arg_block.addBreak(.break_inline, call_index, arg_ref); 8720 8721 const body = arg_block.instructionsSlice(); 8722 try astgen.scratch.ensureUnusedCapacity(astgen.gpa, countBodyLenAfterFixups(astgen, body)); 8723 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); 8724 8725 astgen.scratch.items[scratch_index] = @intCast(u32, astgen.scratch.items.len - scratch_top); 8726 scratch_index += 1; 8727 } 8728 8729 // If our result location is a try/catch/error-union-if/return, a function argument, 8730 // or an initializer for a `const` variable, the error trace propagates. 8731 // Otherwise, it should always be popped (handled in Sema). 8732 const propagate_error_trace = switch (ri.ctx) { 8733 .error_handling_expr, .@"return", .fn_arg, .const_init => true, 8734 else => false, 8735 }; 8736 8737 const payload_index = try addExtra(astgen, Zir.Inst.Call{ 8738 .callee = callee, 8739 .flags = .{ 8740 .pop_error_return_trace = !propagate_error_trace, 8741 .packed_modifier = @intCast(Zir.Inst.Call.Flags.PackedModifier, @enumToInt(modifier)), 8742 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), 8743 }, 8744 }); 8745 if (call.ast.params.len != 0) { 8746 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]); 8747 } 8748 gz.astgen.instructions.set(call_index, .{ 8749 .tag = .call, 8750 .data = .{ .pl_node = .{ 8751 .src_node = gz.nodeIndexToRelative(node), 8752 .payload_index = payload_index, 8753 } }, 8754 }); 8755 return rvalue(gz, ri, call_inst, node); // TODO function call with result location 8756 } 8757 8758 /// calleeExpr generates the function part of a call expression (f in f(x)), or the 8759 /// callee argument to the @call() builtin. If the lhs is a field access or the 8760 /// @field() builtin, we need to generate a special field_call_bind instruction 8761 /// instead of the normal field_val or field_ptr. If this is a inst.func() call, 8762 /// this instruction will capture the value of the first argument before evaluating 8763 /// the other arguments. We need to use .ref here to guarantee we will be able to 8764 /// promote an lvalue to an address if the first parameter requires it. This 8765 /// unfortunately also means we need to take a reference to any types on the lhs. 8766 fn calleeExpr( 8767 gz: *GenZir, 8768 scope: *Scope, 8769 node: Ast.Node.Index, 8770 ) InnerError!Zir.Inst.Ref { 8771 const astgen = gz.astgen; 8772 const tree = astgen.tree; 8773 8774 const tag = tree.nodes.items(.tag)[node]; 8775 switch (tag) { 8776 .field_access => return addFieldAccess(.field_call_bind, gz, scope, .{ .rl = .ref }, node), 8777 8778 .builtin_call_two, 8779 .builtin_call_two_comma, 8780 .builtin_call, 8781 .builtin_call_comma, 8782 => { 8783 const node_datas = tree.nodes.items(.data); 8784 const main_tokens = tree.nodes.items(.main_token); 8785 const builtin_token = main_tokens[node]; 8786 const builtin_name = tree.tokenSlice(builtin_token); 8787 8788 var inline_params: [2]Ast.Node.Index = undefined; 8789 var params: []Ast.Node.Index = switch (tag) { 8790 .builtin_call, 8791 .builtin_call_comma, 8792 => tree.extra_data[node_datas[node].lhs..node_datas[node].rhs], 8793 8794 .builtin_call_two, 8795 .builtin_call_two_comma, 8796 => blk: { 8797 inline_params = .{ node_datas[node].lhs, node_datas[node].rhs }; 8798 const len: usize = if (inline_params[0] == 0) @as(usize, 0) else if (inline_params[1] == 0) @as(usize, 1) else @as(usize, 2); 8799 break :blk inline_params[0..len]; 8800 }, 8801 8802 else => unreachable, 8803 }; 8804 8805 // If anything is wrong, fall back to builtinCall. 8806 // It will emit any necessary compile errors and notes. 8807 if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) { 8808 const lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]); 8809 const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); 8810 return gz.addExtendedPayload(.field_call_bind_named, Zir.Inst.FieldNamedNode{ 8811 .node = gz.nodeIndexToRelative(node), 8812 .lhs = lhs, 8813 .field_name = field_name, 8814 }); 8815 } 8816 8817 return builtinCall(gz, scope, .{ .rl = .none }, node, params); 8818 }, 8819 else => return expr(gz, scope, .{ .rl = .none }, node), 8820 } 8821 } 8822 8823 const primitive_instrs = std.ComptimeStringMap(Zir.Inst.Ref, .{ 8824 .{ "anyerror", .anyerror_type }, 8825 .{ "anyframe", .anyframe_type }, 8826 .{ "anyopaque", .anyopaque_type }, 8827 .{ "bool", .bool_type }, 8828 .{ "c_int", .c_int_type }, 8829 .{ "c_long", .c_long_type }, 8830 .{ "c_longdouble", .c_longdouble_type }, 8831 .{ "c_longlong", .c_longlong_type }, 8832 .{ "c_short", .c_short_type }, 8833 .{ "c_uint", .c_uint_type }, 8834 .{ "c_ulong", .c_ulong_type }, 8835 .{ "c_ulonglong", .c_ulonglong_type }, 8836 .{ "c_ushort", .c_ushort_type }, 8837 .{ "comptime_float", .comptime_float_type }, 8838 .{ "comptime_int", .comptime_int_type }, 8839 .{ "f128", .f128_type }, 8840 .{ "f16", .f16_type }, 8841 .{ "f32", .f32_type }, 8842 .{ "f64", .f64_type }, 8843 .{ "f80", .f80_type }, 8844 .{ "false", .bool_false }, 8845 .{ "i16", .i16_type }, 8846 .{ "i32", .i32_type }, 8847 .{ "i64", .i64_type }, 8848 .{ "i128", .i128_type }, 8849 .{ "i8", .i8_type }, 8850 .{ "isize", .isize_type }, 8851 .{ "noreturn", .noreturn_type }, 8852 .{ "null", .null_value }, 8853 .{ "true", .bool_true }, 8854 .{ "type", .type_type }, 8855 .{ "u16", .u16_type }, 8856 .{ "u29", .u29_type }, 8857 .{ "u32", .u32_type }, 8858 .{ "u64", .u64_type }, 8859 .{ "u128", .u128_type }, 8860 .{ "u1", .u1_type }, 8861 .{ "u8", .u8_type }, 8862 .{ "undefined", .undef }, 8863 .{ "usize", .usize_type }, 8864 .{ "void", .void_type }, 8865 }); 8866 8867 comptime { 8868 // These checks ensure that std.zig.primitives stays in synce with the primitive->Zir map. 8869 const primitives = std.zig.primitives; 8870 for (primitive_instrs.kvs) |kv| { 8871 if (!primitives.isPrimitive(kv.key)) { 8872 @compileError("std.zig.isPrimitive() is not aware of Zir instr '" ++ @tagName(kv.value) ++ "'"); 8873 } 8874 } 8875 for (primitives.names.kvs) |kv| { 8876 if (primitive_instrs.get(kv.key) == null) { 8877 @compileError("std.zig.primitives entry '" ++ kv.key ++ "' does not have a corresponding Zir instr"); 8878 } 8879 } 8880 } 8881 8882 fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_res_ty: bool) bool { 8883 const node_tags = tree.nodes.items(.tag); 8884 const node_datas = tree.nodes.items(.data); 8885 const main_tokens = tree.nodes.items(.main_token); 8886 const token_tags = tree.tokens.items(.tag); 8887 8888 var node = start_node; 8889 while (true) { 8890 switch (node_tags[node]) { 8891 .root, 8892 .@"usingnamespace", 8893 .test_decl, 8894 .switch_case, 8895 .switch_case_inline, 8896 .switch_case_one, 8897 .switch_case_inline_one, 8898 .container_field_init, 8899 .container_field_align, 8900 .container_field, 8901 .asm_output, 8902 .asm_input, 8903 => unreachable, 8904 8905 .@"return", 8906 .@"break", 8907 .@"continue", 8908 .bit_not, 8909 .bool_not, 8910 .global_var_decl, 8911 .local_var_decl, 8912 .simple_var_decl, 8913 .aligned_var_decl, 8914 .@"defer", 8915 .@"errdefer", 8916 .address_of, 8917 .optional_type, 8918 .negation, 8919 .negation_wrap, 8920 .@"resume", 8921 .array_type, 8922 .array_type_sentinel, 8923 .ptr_type_aligned, 8924 .ptr_type_sentinel, 8925 .ptr_type, 8926 .ptr_type_bit_range, 8927 .@"suspend", 8928 .fn_proto_simple, 8929 .fn_proto_multi, 8930 .fn_proto_one, 8931 .fn_proto, 8932 .fn_decl, 8933 .anyframe_type, 8934 .anyframe_literal, 8935 .number_literal, 8936 .enum_literal, 8937 .string_literal, 8938 .multiline_string_literal, 8939 .char_literal, 8940 .unreachable_literal, 8941 .identifier, 8942 .error_set_decl, 8943 .container_decl, 8944 .container_decl_trailing, 8945 .container_decl_two, 8946 .container_decl_two_trailing, 8947 .container_decl_arg, 8948 .container_decl_arg_trailing, 8949 .tagged_union, 8950 .tagged_union_trailing, 8951 .tagged_union_two, 8952 .tagged_union_two_trailing, 8953 .tagged_union_enum_tag, 8954 .tagged_union_enum_tag_trailing, 8955 .@"asm", 8956 .asm_simple, 8957 .add, 8958 .add_wrap, 8959 .add_sat, 8960 .array_cat, 8961 .array_mult, 8962 .assign, 8963 .assign_bit_and, 8964 .assign_bit_or, 8965 .assign_shl, 8966 .assign_shl_sat, 8967 .assign_shr, 8968 .assign_bit_xor, 8969 .assign_div, 8970 .assign_sub, 8971 .assign_sub_wrap, 8972 .assign_sub_sat, 8973 .assign_mod, 8974 .assign_add, 8975 .assign_add_wrap, 8976 .assign_add_sat, 8977 .assign_mul, 8978 .assign_mul_wrap, 8979 .assign_mul_sat, 8980 .bang_equal, 8981 .bit_and, 8982 .bit_or, 8983 .shl, 8984 .shl_sat, 8985 .shr, 8986 .bit_xor, 8987 .bool_and, 8988 .bool_or, 8989 .div, 8990 .equal_equal, 8991 .error_union, 8992 .greater_or_equal, 8993 .greater_than, 8994 .less_or_equal, 8995 .less_than, 8996 .merge_error_sets, 8997 .mod, 8998 .mul, 8999 .mul_wrap, 9000 .mul_sat, 9001 .switch_range, 9002 .field_access, 9003 .sub, 9004 .sub_wrap, 9005 .sub_sat, 9006 .slice, 9007 .slice_open, 9008 .slice_sentinel, 9009 .deref, 9010 .array_access, 9011 .error_value, 9012 .while_simple, // This variant cannot have an else expression. 9013 .while_cont, // This variant cannot have an else expression. 9014 .for_simple, // This variant cannot have an else expression. 9015 .if_simple, // This variant cannot have an else expression. 9016 => return false, 9017 9018 // Forward the question to the LHS sub-expression. 9019 .grouped_expression, 9020 .@"try", 9021 .@"await", 9022 .@"comptime", 9023 .@"nosuspend", 9024 .unwrap_optional, 9025 => node = node_datas[node].lhs, 9026 9027 // Forward the question to the RHS sub-expression. 9028 .@"catch", 9029 .@"orelse", 9030 => node = node_datas[node].rhs, 9031 9032 // Array and struct init exprs write to result locs, but anon literals do not. 9033 .array_init_one, 9034 .array_init_one_comma, 9035 .struct_init_one, 9036 .struct_init_one_comma, 9037 .array_init, 9038 .array_init_comma, 9039 .struct_init, 9040 .struct_init_comma, 9041 => return have_res_ty or node_datas[node].lhs != 0, 9042 9043 // Anon literals do not need result location. 9044 .array_init_dot_two, 9045 .array_init_dot_two_comma, 9046 .array_init_dot, 9047 .array_init_dot_comma, 9048 .struct_init_dot_two, 9049 .struct_init_dot_two_comma, 9050 .struct_init_dot, 9051 .struct_init_dot_comma, 9052 => return have_res_ty, 9053 9054 // True because depending on comptime conditions, sub-expressions 9055 // may be the kind that need memory locations. 9056 .@"while", // This variant always has an else expression. 9057 .@"if", // This variant always has an else expression. 9058 .@"for", // This variant always has an else expression. 9059 .@"switch", 9060 .switch_comma, 9061 .call_one, 9062 .call_one_comma, 9063 .async_call_one, 9064 .async_call_one_comma, 9065 .call, 9066 .call_comma, 9067 .async_call, 9068 .async_call_comma, 9069 => return true, 9070 9071 .block_two, 9072 .block_two_semicolon, 9073 .block, 9074 .block_semicolon, 9075 => { 9076 const lbrace = main_tokens[node]; 9077 if (token_tags[lbrace - 1] == .colon) { 9078 // Labeled blocks may need a memory location to forward 9079 // to their break statements. 9080 return true; 9081 } else { 9082 return false; 9083 } 9084 }, 9085 9086 .builtin_call_two, .builtin_call_two_comma => { 9087 const builtin_token = main_tokens[node]; 9088 const builtin_name = tree.tokenSlice(builtin_token); 9089 // If the builtin is an invalid name, we don't cause an error here; instead 9090 // let it pass, and the error will be "invalid builtin function" later. 9091 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; 9092 switch (builtin_info.needs_mem_loc) { 9093 .never => return false, 9094 .always => return true, 9095 .forward1 => node = node_datas[node].rhs, 9096 } 9097 }, 9098 9099 .builtin_call, .builtin_call_comma => { 9100 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 9101 const builtin_token = main_tokens[node]; 9102 const builtin_name = tree.tokenSlice(builtin_token); 9103 // If the builtin is an invalid name, we don't cause an error here; instead 9104 // let it pass, and the error will be "invalid builtin function" later. 9105 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; 9106 switch (builtin_info.needs_mem_loc) { 9107 .never => return false, 9108 .always => return true, 9109 .forward1 => node = params[1], 9110 } 9111 }, 9112 } 9113 } 9114 } 9115 9116 fn nodeMayAppendToErrorTrace(tree: *const Ast, start_node: Ast.Node.Index) bool { 9117 const node_tags = tree.nodes.items(.tag); 9118 const node_datas = tree.nodes.items(.data); 9119 9120 var node = start_node; 9121 while (true) { 9122 switch (node_tags[node]) { 9123 // These don't have the opportunity to call any runtime functions. 9124 .error_value, 9125 .identifier, 9126 .@"comptime", 9127 => return false, 9128 9129 // Forward the question to the LHS sub-expression. 9130 .grouped_expression, 9131 .@"try", 9132 .@"nosuspend", 9133 .unwrap_optional, 9134 => node = node_datas[node].lhs, 9135 9136 // Anything that does not eval to an error is guaranteed to pop any 9137 // additions to the error trace, so it effectively does not append. 9138 else => return nodeMayEvalToError(tree, start_node) != .never, 9139 } 9140 } 9141 } 9142 9143 fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.EvalToError { 9144 const node_tags = tree.nodes.items(.tag); 9145 const node_datas = tree.nodes.items(.data); 9146 const main_tokens = tree.nodes.items(.main_token); 9147 const token_tags = tree.tokens.items(.tag); 9148 9149 var node = start_node; 9150 while (true) { 9151 switch (node_tags[node]) { 9152 .root, 9153 .@"usingnamespace", 9154 .test_decl, 9155 .switch_case, 9156 .switch_case_inline, 9157 .switch_case_one, 9158 .switch_case_inline_one, 9159 .container_field_init, 9160 .container_field_align, 9161 .container_field, 9162 .asm_output, 9163 .asm_input, 9164 => unreachable, 9165 9166 .error_value => return .always, 9167 9168 .@"asm", 9169 .asm_simple, 9170 .identifier, 9171 .field_access, 9172 .deref, 9173 .array_access, 9174 .while_simple, 9175 .while_cont, 9176 .for_simple, 9177 .if_simple, 9178 .@"while", 9179 .@"if", 9180 .@"for", 9181 .@"switch", 9182 .switch_comma, 9183 .call_one, 9184 .call_one_comma, 9185 .async_call_one, 9186 .async_call_one_comma, 9187 .call, 9188 .call_comma, 9189 .async_call, 9190 .async_call_comma, 9191 => return .maybe, 9192 9193 .@"return", 9194 .@"break", 9195 .@"continue", 9196 .bit_not, 9197 .bool_not, 9198 .global_var_decl, 9199 .local_var_decl, 9200 .simple_var_decl, 9201 .aligned_var_decl, 9202 .@"defer", 9203 .@"errdefer", 9204 .address_of, 9205 .optional_type, 9206 .negation, 9207 .negation_wrap, 9208 .@"resume", 9209 .array_type, 9210 .array_type_sentinel, 9211 .ptr_type_aligned, 9212 .ptr_type_sentinel, 9213 .ptr_type, 9214 .ptr_type_bit_range, 9215 .@"suspend", 9216 .fn_proto_simple, 9217 .fn_proto_multi, 9218 .fn_proto_one, 9219 .fn_proto, 9220 .fn_decl, 9221 .anyframe_type, 9222 .anyframe_literal, 9223 .number_literal, 9224 .enum_literal, 9225 .string_literal, 9226 .multiline_string_literal, 9227 .char_literal, 9228 .unreachable_literal, 9229 .error_set_decl, 9230 .container_decl, 9231 .container_decl_trailing, 9232 .container_decl_two, 9233 .container_decl_two_trailing, 9234 .container_decl_arg, 9235 .container_decl_arg_trailing, 9236 .tagged_union, 9237 .tagged_union_trailing, 9238 .tagged_union_two, 9239 .tagged_union_two_trailing, 9240 .tagged_union_enum_tag, 9241 .tagged_union_enum_tag_trailing, 9242 .add, 9243 .add_wrap, 9244 .add_sat, 9245 .array_cat, 9246 .array_mult, 9247 .assign, 9248 .assign_bit_and, 9249 .assign_bit_or, 9250 .assign_shl, 9251 .assign_shl_sat, 9252 .assign_shr, 9253 .assign_bit_xor, 9254 .assign_div, 9255 .assign_sub, 9256 .assign_sub_wrap, 9257 .assign_sub_sat, 9258 .assign_mod, 9259 .assign_add, 9260 .assign_add_wrap, 9261 .assign_add_sat, 9262 .assign_mul, 9263 .assign_mul_wrap, 9264 .assign_mul_sat, 9265 .bang_equal, 9266 .bit_and, 9267 .bit_or, 9268 .shl, 9269 .shl_sat, 9270 .shr, 9271 .bit_xor, 9272 .bool_and, 9273 .bool_or, 9274 .div, 9275 .equal_equal, 9276 .error_union, 9277 .greater_or_equal, 9278 .greater_than, 9279 .less_or_equal, 9280 .less_than, 9281 .merge_error_sets, 9282 .mod, 9283 .mul, 9284 .mul_wrap, 9285 .mul_sat, 9286 .switch_range, 9287 .sub, 9288 .sub_wrap, 9289 .sub_sat, 9290 .slice, 9291 .slice_open, 9292 .slice_sentinel, 9293 .array_init_one, 9294 .array_init_one_comma, 9295 .array_init_dot_two, 9296 .array_init_dot_two_comma, 9297 .array_init_dot, 9298 .array_init_dot_comma, 9299 .array_init, 9300 .array_init_comma, 9301 .struct_init_one, 9302 .struct_init_one_comma, 9303 .struct_init_dot_two, 9304 .struct_init_dot_two_comma, 9305 .struct_init_dot, 9306 .struct_init_dot_comma, 9307 .struct_init, 9308 .struct_init_comma, 9309 => return .never, 9310 9311 // Forward the question to the LHS sub-expression. 9312 .grouped_expression, 9313 .@"try", 9314 .@"await", 9315 .@"comptime", 9316 .@"nosuspend", 9317 .unwrap_optional, 9318 => node = node_datas[node].lhs, 9319 9320 // LHS sub-expression may still be an error under the outer optional or error union 9321 .@"catch", 9322 .@"orelse", 9323 => return .maybe, 9324 9325 .block_two, 9326 .block_two_semicolon, 9327 .block, 9328 .block_semicolon, 9329 => { 9330 const lbrace = main_tokens[node]; 9331 if (token_tags[lbrace - 1] == .colon) { 9332 // Labeled blocks may need a memory location to forward 9333 // to their break statements. 9334 return .maybe; 9335 } else { 9336 return .never; 9337 } 9338 }, 9339 9340 .builtin_call, 9341 .builtin_call_comma, 9342 .builtin_call_two, 9343 .builtin_call_two_comma, 9344 => { 9345 const builtin_token = main_tokens[node]; 9346 const builtin_name = tree.tokenSlice(builtin_token); 9347 // If the builtin is an invalid name, we don't cause an error here; instead 9348 // let it pass, and the error will be "invalid builtin function" later. 9349 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe; 9350 return builtin_info.eval_to_error; 9351 }, 9352 } 9353 } 9354 } 9355 9356 /// Returns `true` if it is known the type expression has more than one possible value; 9357 /// `false` otherwise. 9358 fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool { 9359 const node_tags = tree.nodes.items(.tag); 9360 const node_datas = tree.nodes.items(.data); 9361 9362 var node = start_node; 9363 while (true) { 9364 switch (node_tags[node]) { 9365 .root, 9366 .@"usingnamespace", 9367 .test_decl, 9368 .switch_case, 9369 .switch_case_inline, 9370 .switch_case_one, 9371 .switch_case_inline_one, 9372 .container_field_init, 9373 .container_field_align, 9374 .container_field, 9375 .asm_output, 9376 .asm_input, 9377 .global_var_decl, 9378 .local_var_decl, 9379 .simple_var_decl, 9380 .aligned_var_decl, 9381 => unreachable, 9382 9383 .@"return", 9384 .@"break", 9385 .@"continue", 9386 .bit_not, 9387 .bool_not, 9388 .@"defer", 9389 .@"errdefer", 9390 .address_of, 9391 .negation, 9392 .negation_wrap, 9393 .@"resume", 9394 .array_type, 9395 .@"suspend", 9396 .fn_decl, 9397 .anyframe_literal, 9398 .number_literal, 9399 .enum_literal, 9400 .string_literal, 9401 .multiline_string_literal, 9402 .char_literal, 9403 .unreachable_literal, 9404 .error_set_decl, 9405 .container_decl, 9406 .container_decl_trailing, 9407 .container_decl_two, 9408 .container_decl_two_trailing, 9409 .container_decl_arg, 9410 .container_decl_arg_trailing, 9411 .tagged_union, 9412 .tagged_union_trailing, 9413 .tagged_union_two, 9414 .tagged_union_two_trailing, 9415 .tagged_union_enum_tag, 9416 .tagged_union_enum_tag_trailing, 9417 .@"asm", 9418 .asm_simple, 9419 .add, 9420 .add_wrap, 9421 .add_sat, 9422 .array_cat, 9423 .array_mult, 9424 .assign, 9425 .assign_bit_and, 9426 .assign_bit_or, 9427 .assign_shl, 9428 .assign_shl_sat, 9429 .assign_shr, 9430 .assign_bit_xor, 9431 .assign_div, 9432 .assign_sub, 9433 .assign_sub_wrap, 9434 .assign_sub_sat, 9435 .assign_mod, 9436 .assign_add, 9437 .assign_add_wrap, 9438 .assign_add_sat, 9439 .assign_mul, 9440 .assign_mul_wrap, 9441 .assign_mul_sat, 9442 .bang_equal, 9443 .bit_and, 9444 .bit_or, 9445 .shl, 9446 .shl_sat, 9447 .shr, 9448 .bit_xor, 9449 .bool_and, 9450 .bool_or, 9451 .div, 9452 .equal_equal, 9453 .error_union, 9454 .greater_or_equal, 9455 .greater_than, 9456 .less_or_equal, 9457 .less_than, 9458 .merge_error_sets, 9459 .mod, 9460 .mul, 9461 .mul_wrap, 9462 .mul_sat, 9463 .switch_range, 9464 .field_access, 9465 .sub, 9466 .sub_wrap, 9467 .sub_sat, 9468 .slice, 9469 .slice_open, 9470 .slice_sentinel, 9471 .deref, 9472 .array_access, 9473 .error_value, 9474 .while_simple, 9475 .while_cont, 9476 .for_simple, 9477 .if_simple, 9478 .@"catch", 9479 .@"orelse", 9480 .array_init_one, 9481 .array_init_one_comma, 9482 .array_init_dot_two, 9483 .array_init_dot_two_comma, 9484 .array_init_dot, 9485 .array_init_dot_comma, 9486 .array_init, 9487 .array_init_comma, 9488 .struct_init_one, 9489 .struct_init_one_comma, 9490 .struct_init_dot_two, 9491 .struct_init_dot_two_comma, 9492 .struct_init_dot, 9493 .struct_init_dot_comma, 9494 .struct_init, 9495 .struct_init_comma, 9496 .@"while", 9497 .@"if", 9498 .@"for", 9499 .@"switch", 9500 .switch_comma, 9501 .call_one, 9502 .call_one_comma, 9503 .async_call_one, 9504 .async_call_one_comma, 9505 .call, 9506 .call_comma, 9507 .async_call, 9508 .async_call_comma, 9509 .block_two, 9510 .block_two_semicolon, 9511 .block, 9512 .block_semicolon, 9513 .builtin_call, 9514 .builtin_call_comma, 9515 .builtin_call_two, 9516 .builtin_call_two_comma, 9517 // these are function bodies, not pointers 9518 .fn_proto_simple, 9519 .fn_proto_multi, 9520 .fn_proto_one, 9521 .fn_proto, 9522 => return false, 9523 9524 // Forward the question to the LHS sub-expression. 9525 .grouped_expression, 9526 .@"try", 9527 .@"await", 9528 .@"comptime", 9529 .@"nosuspend", 9530 .unwrap_optional, 9531 => node = node_datas[node].lhs, 9532 9533 .ptr_type_aligned, 9534 .ptr_type_sentinel, 9535 .ptr_type, 9536 .ptr_type_bit_range, 9537 .optional_type, 9538 .anyframe_type, 9539 .array_type_sentinel, 9540 => return true, 9541 9542 .identifier => { 9543 const main_tokens = tree.nodes.items(.main_token); 9544 const ident_bytes = tree.tokenSlice(main_tokens[node]); 9545 if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) { 9546 .anyerror_type, 9547 .anyframe_type, 9548 .anyopaque_type, 9549 .bool_type, 9550 .c_int_type, 9551 .c_long_type, 9552 .c_longdouble_type, 9553 .c_longlong_type, 9554 .c_short_type, 9555 .c_uint_type, 9556 .c_ulong_type, 9557 .c_ulonglong_type, 9558 .c_ushort_type, 9559 .comptime_float_type, 9560 .comptime_int_type, 9561 .f16_type, 9562 .f32_type, 9563 .f64_type, 9564 .f80_type, 9565 .f128_type, 9566 .i16_type, 9567 .i32_type, 9568 .i64_type, 9569 .i128_type, 9570 .i8_type, 9571 .isize_type, 9572 .type_type, 9573 .u16_type, 9574 .u29_type, 9575 .u32_type, 9576 .u64_type, 9577 .u128_type, 9578 .u1_type, 9579 .u8_type, 9580 .usize_type, 9581 => return true, 9582 9583 .void_type, 9584 .bool_false, 9585 .bool_true, 9586 .null_value, 9587 .undef, 9588 .noreturn_type, 9589 => return false, 9590 9591 else => unreachable, // that's all the values from `primitives`. 9592 } else { 9593 return false; 9594 } 9595 }, 9596 } 9597 } 9598 } 9599 9600 /// Returns `true` if it is known the expression is a type that cannot be used at runtime; 9601 /// `false` otherwise. 9602 fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool { 9603 const node_tags = tree.nodes.items(.tag); 9604 const node_datas = tree.nodes.items(.data); 9605 9606 var node = start_node; 9607 while (true) { 9608 switch (node_tags[node]) { 9609 .root, 9610 .@"usingnamespace", 9611 .test_decl, 9612 .switch_case, 9613 .switch_case_inline, 9614 .switch_case_one, 9615 .switch_case_inline_one, 9616 .container_field_init, 9617 .container_field_align, 9618 .container_field, 9619 .asm_output, 9620 .asm_input, 9621 .global_var_decl, 9622 .local_var_decl, 9623 .simple_var_decl, 9624 .aligned_var_decl, 9625 => unreachable, 9626 9627 .@"return", 9628 .@"break", 9629 .@"continue", 9630 .bit_not, 9631 .bool_not, 9632 .@"defer", 9633 .@"errdefer", 9634 .address_of, 9635 .negation, 9636 .negation_wrap, 9637 .@"resume", 9638 .array_type, 9639 .@"suspend", 9640 .fn_decl, 9641 .anyframe_literal, 9642 .number_literal, 9643 .enum_literal, 9644 .string_literal, 9645 .multiline_string_literal, 9646 .char_literal, 9647 .unreachable_literal, 9648 .error_set_decl, 9649 .container_decl, 9650 .container_decl_trailing, 9651 .container_decl_two, 9652 .container_decl_two_trailing, 9653 .container_decl_arg, 9654 .container_decl_arg_trailing, 9655 .tagged_union, 9656 .tagged_union_trailing, 9657 .tagged_union_two, 9658 .tagged_union_two_trailing, 9659 .tagged_union_enum_tag, 9660 .tagged_union_enum_tag_trailing, 9661 .@"asm", 9662 .asm_simple, 9663 .add, 9664 .add_wrap, 9665 .add_sat, 9666 .array_cat, 9667 .array_mult, 9668 .assign, 9669 .assign_bit_and, 9670 .assign_bit_or, 9671 .assign_shl, 9672 .assign_shl_sat, 9673 .assign_shr, 9674 .assign_bit_xor, 9675 .assign_div, 9676 .assign_sub, 9677 .assign_sub_wrap, 9678 .assign_sub_sat, 9679 .assign_mod, 9680 .assign_add, 9681 .assign_add_wrap, 9682 .assign_add_sat, 9683 .assign_mul, 9684 .assign_mul_wrap, 9685 .assign_mul_sat, 9686 .bang_equal, 9687 .bit_and, 9688 .bit_or, 9689 .shl, 9690 .shl_sat, 9691 .shr, 9692 .bit_xor, 9693 .bool_and, 9694 .bool_or, 9695 .div, 9696 .equal_equal, 9697 .error_union, 9698 .greater_or_equal, 9699 .greater_than, 9700 .less_or_equal, 9701 .less_than, 9702 .merge_error_sets, 9703 .mod, 9704 .mul, 9705 .mul_wrap, 9706 .mul_sat, 9707 .switch_range, 9708 .field_access, 9709 .sub, 9710 .sub_wrap, 9711 .sub_sat, 9712 .slice, 9713 .slice_open, 9714 .slice_sentinel, 9715 .deref, 9716 .array_access, 9717 .error_value, 9718 .while_simple, 9719 .while_cont, 9720 .for_simple, 9721 .if_simple, 9722 .@"catch", 9723 .@"orelse", 9724 .array_init_one, 9725 .array_init_one_comma, 9726 .array_init_dot_two, 9727 .array_init_dot_two_comma, 9728 .array_init_dot, 9729 .array_init_dot_comma, 9730 .array_init, 9731 .array_init_comma, 9732 .struct_init_one, 9733 .struct_init_one_comma, 9734 .struct_init_dot_two, 9735 .struct_init_dot_two_comma, 9736 .struct_init_dot, 9737 .struct_init_dot_comma, 9738 .struct_init, 9739 .struct_init_comma, 9740 .@"while", 9741 .@"if", 9742 .@"for", 9743 .@"switch", 9744 .switch_comma, 9745 .call_one, 9746 .call_one_comma, 9747 .async_call_one, 9748 .async_call_one_comma, 9749 .call, 9750 .call_comma, 9751 .async_call, 9752 .async_call_comma, 9753 .block_two, 9754 .block_two_semicolon, 9755 .block, 9756 .block_semicolon, 9757 .builtin_call, 9758 .builtin_call_comma, 9759 .builtin_call_two, 9760 .builtin_call_two_comma, 9761 .ptr_type_aligned, 9762 .ptr_type_sentinel, 9763 .ptr_type, 9764 .ptr_type_bit_range, 9765 .optional_type, 9766 .anyframe_type, 9767 .array_type_sentinel, 9768 => return false, 9769 9770 // these are function bodies, not pointers 9771 .fn_proto_simple, 9772 .fn_proto_multi, 9773 .fn_proto_one, 9774 .fn_proto, 9775 => return true, 9776 9777 // Forward the question to the LHS sub-expression. 9778 .grouped_expression, 9779 .@"try", 9780 .@"await", 9781 .@"comptime", 9782 .@"nosuspend", 9783 .unwrap_optional, 9784 => node = node_datas[node].lhs, 9785 9786 .identifier => { 9787 const main_tokens = tree.nodes.items(.main_token); 9788 const ident_bytes = tree.tokenSlice(main_tokens[node]); 9789 if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) { 9790 .anyerror_type, 9791 .anyframe_type, 9792 .anyopaque_type, 9793 .bool_type, 9794 .c_int_type, 9795 .c_long_type, 9796 .c_longdouble_type, 9797 .c_longlong_type, 9798 .c_short_type, 9799 .c_uint_type, 9800 .c_ulong_type, 9801 .c_ulonglong_type, 9802 .c_ushort_type, 9803 .f16_type, 9804 .f32_type, 9805 .f64_type, 9806 .f80_type, 9807 .f128_type, 9808 .i16_type, 9809 .i32_type, 9810 .i64_type, 9811 .i128_type, 9812 .i8_type, 9813 .isize_type, 9814 .u16_type, 9815 .u29_type, 9816 .u32_type, 9817 .u64_type, 9818 .u128_type, 9819 .u1_type, 9820 .u8_type, 9821 .usize_type, 9822 .void_type, 9823 .bool_false, 9824 .bool_true, 9825 .null_value, 9826 .undef, 9827 .noreturn_type, 9828 => return false, 9829 9830 .comptime_float_type, 9831 .comptime_int_type, 9832 .type_type, 9833 => return true, 9834 9835 else => unreachable, // that's all the values from `primitives`. 9836 } else { 9837 return false; 9838 } 9839 }, 9840 } 9841 } 9842 } 9843 9844 /// Returns `true` if the node uses `gz.anon_name_strategy`. 9845 fn nodeUsesAnonNameStrategy(tree: *const Ast, node: Ast.Node.Index) bool { 9846 const node_tags = tree.nodes.items(.tag); 9847 switch (node_tags[node]) { 9848 .container_decl, 9849 .container_decl_trailing, 9850 .container_decl_two, 9851 .container_decl_two_trailing, 9852 .container_decl_arg, 9853 .container_decl_arg_trailing, 9854 .tagged_union, 9855 .tagged_union_trailing, 9856 .tagged_union_two, 9857 .tagged_union_two_trailing, 9858 .tagged_union_enum_tag, 9859 .tagged_union_enum_tag_trailing, 9860 => return true, 9861 .builtin_call_two, .builtin_call_two_comma, .builtin_call, .builtin_call_comma => { 9862 const builtin_token = tree.nodes.items(.main_token)[node]; 9863 const builtin_name = tree.tokenSlice(builtin_token); 9864 return std.mem.eql(u8, builtin_name, "@Type"); 9865 }, 9866 else => return false, 9867 } 9868 } 9869 9870 /// Applies `rl` semantics to `result`. Expressions which do not do their own handling of 9871 /// result locations must call this function on their result. 9872 /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. 9873 /// If the `ResultLoc` is `ty`, it will coerce the result to the type. 9874 /// Assumes nothing stacked on `gz`. 9875 fn rvalue( 9876 gz: *GenZir, 9877 ri: ResultInfo, 9878 raw_result: Zir.Inst.Ref, 9879 src_node: Ast.Node.Index, 9880 ) InnerError!Zir.Inst.Ref { 9881 const result = r: { 9882 if (refToIndex(raw_result)) |result_index| { 9883 const zir_tags = gz.astgen.instructions.items(.tag); 9884 const data = gz.astgen.instructions.items(.data)[result_index]; 9885 if (zir_tags[result_index].isAlwaysVoid(data)) { 9886 break :r Zir.Inst.Ref.void_value; 9887 } 9888 } 9889 break :r raw_result; 9890 }; 9891 if (gz.endsWithNoReturn()) return result; 9892 switch (ri.rl) { 9893 .none, .coerced_ty => return result, 9894 .discard => { 9895 // Emit a compile error for discarding error values. 9896 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); 9897 return result; 9898 }, 9899 .ref => { 9900 // We need a pointer but we have a value. 9901 // Unfortunately it's not quite as simple as directly emitting a ref 9902 // instruction here because we need subsequent address-of operator on 9903 // const locals to return the same address. 9904 const astgen = gz.astgen; 9905 const tree = astgen.tree; 9906 const src_token = tree.firstToken(src_node); 9907 const result_index = refToIndex(result) orelse 9908 return gz.addUnTok(.ref, result, src_token); 9909 const zir_tags = gz.astgen.instructions.items(.tag); 9910 if (zir_tags[result_index].isParam() or astgen.isInferred(result)) 9911 return gz.addUnTok(.ref, result, src_token); 9912 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index); 9913 if (!gop.found_existing) { 9914 gop.value_ptr.* = try gz.makeUnTok(.ref, result, src_token); 9915 } 9916 return indexToRef(gop.value_ptr.*); 9917 }, 9918 .ty => |ty_inst| { 9919 // Quickly eliminate some common, unnecessary type coercion. 9920 const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32; 9921 const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32; 9922 const as_bool = @as(u64, @enumToInt(Zir.Inst.Ref.bool_type)) << 32; 9923 const as_usize = @as(u64, @enumToInt(Zir.Inst.Ref.usize_type)) << 32; 9924 const as_void = @as(u64, @enumToInt(Zir.Inst.Ref.void_type)) << 32; 9925 switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) { 9926 as_ty | @enumToInt(Zir.Inst.Ref.u1_type), 9927 as_ty | @enumToInt(Zir.Inst.Ref.u8_type), 9928 as_ty | @enumToInt(Zir.Inst.Ref.i8_type), 9929 as_ty | @enumToInt(Zir.Inst.Ref.u16_type), 9930 as_ty | @enumToInt(Zir.Inst.Ref.u29_type), 9931 as_ty | @enumToInt(Zir.Inst.Ref.i16_type), 9932 as_ty | @enumToInt(Zir.Inst.Ref.u32_type), 9933 as_ty | @enumToInt(Zir.Inst.Ref.i32_type), 9934 as_ty | @enumToInt(Zir.Inst.Ref.u64_type), 9935 as_ty | @enumToInt(Zir.Inst.Ref.i64_type), 9936 as_ty | @enumToInt(Zir.Inst.Ref.usize_type), 9937 as_ty | @enumToInt(Zir.Inst.Ref.isize_type), 9938 as_ty | @enumToInt(Zir.Inst.Ref.c_short_type), 9939 as_ty | @enumToInt(Zir.Inst.Ref.c_ushort_type), 9940 as_ty | @enumToInt(Zir.Inst.Ref.c_int_type), 9941 as_ty | @enumToInt(Zir.Inst.Ref.c_uint_type), 9942 as_ty | @enumToInt(Zir.Inst.Ref.c_long_type), 9943 as_ty | @enumToInt(Zir.Inst.Ref.c_ulong_type), 9944 as_ty | @enumToInt(Zir.Inst.Ref.c_longlong_type), 9945 as_ty | @enumToInt(Zir.Inst.Ref.c_ulonglong_type), 9946 as_ty | @enumToInt(Zir.Inst.Ref.c_longdouble_type), 9947 as_ty | @enumToInt(Zir.Inst.Ref.f16_type), 9948 as_ty | @enumToInt(Zir.Inst.Ref.f32_type), 9949 as_ty | @enumToInt(Zir.Inst.Ref.f64_type), 9950 as_ty | @enumToInt(Zir.Inst.Ref.f80_type), 9951 as_ty | @enumToInt(Zir.Inst.Ref.f128_type), 9952 as_ty | @enumToInt(Zir.Inst.Ref.anyopaque_type), 9953 as_ty | @enumToInt(Zir.Inst.Ref.bool_type), 9954 as_ty | @enumToInt(Zir.Inst.Ref.void_type), 9955 as_ty | @enumToInt(Zir.Inst.Ref.type_type), 9956 as_ty | @enumToInt(Zir.Inst.Ref.anyerror_type), 9957 as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), 9958 as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), 9959 as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), 9960 as_ty | @enumToInt(Zir.Inst.Ref.null_type), 9961 as_ty | @enumToInt(Zir.Inst.Ref.undefined_type), 9962 as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type), 9963 as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type), 9964 as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type), 9965 as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type), 9966 as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), 9967 as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type), 9968 as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type), 9969 as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), 9970 as_comptime_int | @enumToInt(Zir.Inst.Ref.one), 9971 as_bool | @enumToInt(Zir.Inst.Ref.bool_true), 9972 as_bool | @enumToInt(Zir.Inst.Ref.bool_false), 9973 as_usize | @enumToInt(Zir.Inst.Ref.zero_usize), 9974 as_usize | @enumToInt(Zir.Inst.Ref.one_usize), 9975 as_void | @enumToInt(Zir.Inst.Ref.void_value), 9976 => return result, // type of result is already correct 9977 9978 // Need an explicit type coercion instruction. 9979 else => return gz.addPlNode(ri.zirTag(), src_node, Zir.Inst.As{ 9980 .dest_type = ty_inst, 9981 .operand = result, 9982 }), 9983 } 9984 }, 9985 .ptr => |ptr_res| { 9986 _ = try gz.addPlNode(.store_node, ptr_res.src_node orelse src_node, Zir.Inst.Bin{ 9987 .lhs = ptr_res.inst, 9988 .rhs = result, 9989 }); 9990 return result; 9991 }, 9992 .inferred_ptr => |alloc| { 9993 _ = try gz.addBin(.store_to_inferred_ptr, alloc, result); 9994 return result; 9995 }, 9996 .block_ptr => |block_scope| { 9997 block_scope.rvalue_rl_count += 1; 9998 _ = try gz.addBin(.store_to_block_ptr, block_scope.rl_ptr, result); 9999 return result; 10000 }, 10001 } 10002 } 10003 10004 /// Given an identifier token, obtain the string for it. 10005 /// If the token uses @"" syntax, parses as a string, reports errors if applicable, 10006 /// and allocates the result within `astgen.arena`. 10007 /// Otherwise, returns a reference to the source code bytes directly. 10008 /// See also `appendIdentStr` and `parseStrLit`. 10009 fn identifierTokenString(astgen: *AstGen, token: Ast.TokenIndex) InnerError![]const u8 { 10010 const tree = astgen.tree; 10011 const token_tags = tree.tokens.items(.tag); 10012 assert(token_tags[token] == .identifier); 10013 const ident_name = tree.tokenSlice(token); 10014 if (!mem.startsWith(u8, ident_name, "@")) { 10015 return ident_name; 10016 } 10017 var buf: ArrayListUnmanaged(u8) = .{}; 10018 defer buf.deinit(astgen.gpa); 10019 try astgen.parseStrLit(token, &buf, ident_name, 1); 10020 if (mem.indexOfScalar(u8, buf.items, 0) != null) { 10021 return astgen.failTok(token, "identifier cannot contain null bytes", .{}); 10022 } else if (buf.items.len == 0) { 10023 return astgen.failTok(token, "identifier cannot be empty", .{}); 10024 } 10025 const duped = try astgen.arena.dupe(u8, buf.items); 10026 return duped; 10027 } 10028 10029 /// Given an identifier token, obtain the string for it (possibly parsing as a string 10030 /// literal if it is @"" syntax), and append the string to `buf`. 10031 /// See also `identifierTokenString` and `parseStrLit`. 10032 fn appendIdentStr( 10033 astgen: *AstGen, 10034 token: Ast.TokenIndex, 10035 buf: *ArrayListUnmanaged(u8), 10036 ) InnerError!void { 10037 const tree = astgen.tree; 10038 const token_tags = tree.tokens.items(.tag); 10039 assert(token_tags[token] == .identifier); 10040 const ident_name = tree.tokenSlice(token); 10041 if (!mem.startsWith(u8, ident_name, "@")) { 10042 return buf.appendSlice(astgen.gpa, ident_name); 10043 } else { 10044 const start = buf.items.len; 10045 try astgen.parseStrLit(token, buf, ident_name, 1); 10046 const slice = buf.items[start..]; 10047 if (mem.indexOfScalar(u8, slice, 0) != null) { 10048 return astgen.failTok(token, "identifier cannot contain null bytes", .{}); 10049 } else if (slice.len == 0) { 10050 return astgen.failTok(token, "identifier cannot be empty", .{}); 10051 } 10052 } 10053 } 10054 10055 /// Appends the result to `buf`. 10056 fn parseStrLit( 10057 astgen: *AstGen, 10058 token: Ast.TokenIndex, 10059 buf: *ArrayListUnmanaged(u8), 10060 bytes: []const u8, 10061 offset: u32, 10062 ) InnerError!void { 10063 const raw_string = bytes[offset..]; 10064 var buf_managed = buf.toManaged(astgen.gpa); 10065 const result = std.zig.string_literal.parseWrite(buf_managed.writer(), raw_string); 10066 buf.* = buf_managed.moveToUnmanaged(); 10067 switch (try result) { 10068 .success => return, 10069 .failure => |err| return astgen.failWithStrLitError(err, token, bytes, offset), 10070 } 10071 } 10072 10073 fn failWithStrLitError(astgen: *AstGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, bytes: []const u8, offset: u32) InnerError { 10074 const raw_string = bytes[offset..]; 10075 switch (err) { 10076 .invalid_escape_character => |bad_index| { 10077 return astgen.failOff( 10078 token, 10079 offset + @intCast(u32, bad_index), 10080 "invalid escape character: '{c}'", 10081 .{raw_string[bad_index]}, 10082 ); 10083 }, 10084 .expected_hex_digit => |bad_index| { 10085 return astgen.failOff( 10086 token, 10087 offset + @intCast(u32, bad_index), 10088 "expected hex digit, found '{c}'", 10089 .{raw_string[bad_index]}, 10090 ); 10091 }, 10092 .empty_unicode_escape_sequence => |bad_index| { 10093 return astgen.failOff( 10094 token, 10095 offset + @intCast(u32, bad_index), 10096 "empty unicode escape sequence", 10097 .{}, 10098 ); 10099 }, 10100 .expected_hex_digit_or_rbrace => |bad_index| { 10101 return astgen.failOff( 10102 token, 10103 offset + @intCast(u32, bad_index), 10104 "expected hex digit or '}}', found '{c}'", 10105 .{raw_string[bad_index]}, 10106 ); 10107 }, 10108 .invalid_unicode_codepoint => |bad_index| { 10109 return astgen.failOff( 10110 token, 10111 offset + @intCast(u32, bad_index), 10112 "unicode escape does not correspond to a valid codepoint", 10113 .{}, 10114 ); 10115 }, 10116 .expected_lbrace => |bad_index| { 10117 return astgen.failOff( 10118 token, 10119 offset + @intCast(u32, bad_index), 10120 "expected '{{', found '{c}", 10121 .{raw_string[bad_index]}, 10122 ); 10123 }, 10124 .expected_rbrace => |bad_index| { 10125 return astgen.failOff( 10126 token, 10127 offset + @intCast(u32, bad_index), 10128 "expected '}}', found '{c}", 10129 .{raw_string[bad_index]}, 10130 ); 10131 }, 10132 .expected_single_quote => |bad_index| { 10133 return astgen.failOff( 10134 token, 10135 offset + @intCast(u32, bad_index), 10136 "expected single quote ('), found '{c}", 10137 .{raw_string[bad_index]}, 10138 ); 10139 }, 10140 .invalid_character => |bad_index| { 10141 return astgen.failOff( 10142 token, 10143 offset + @intCast(u32, bad_index), 10144 "invalid byte in string or character literal: '{c}'", 10145 .{raw_string[bad_index]}, 10146 ); 10147 }, 10148 } 10149 } 10150 10151 fn failNode( 10152 astgen: *AstGen, 10153 node: Ast.Node.Index, 10154 comptime format: []const u8, 10155 args: anytype, 10156 ) InnerError { 10157 return astgen.failNodeNotes(node, format, args, &[0]u32{}); 10158 } 10159 10160 fn appendErrorNode( 10161 astgen: *AstGen, 10162 node: Ast.Node.Index, 10163 comptime format: []const u8, 10164 args: anytype, 10165 ) Allocator.Error!void { 10166 try astgen.appendErrorNodeNotes(node, format, args, &[0]u32{}); 10167 } 10168 10169 fn appendErrorNodeNotes( 10170 astgen: *AstGen, 10171 node: Ast.Node.Index, 10172 comptime format: []const u8, 10173 args: anytype, 10174 notes: []const u32, 10175 ) Allocator.Error!void { 10176 @setCold(true); 10177 const string_bytes = &astgen.string_bytes; 10178 const msg = @intCast(u32, string_bytes.items.len); 10179 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 10180 const notes_index: u32 = if (notes.len != 0) blk: { 10181 const notes_start = astgen.extra.items.len; 10182 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 10183 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 10184 astgen.extra.appendSliceAssumeCapacity(notes); 10185 break :blk @intCast(u32, notes_start); 10186 } else 0; 10187 try astgen.compile_errors.append(astgen.gpa, .{ 10188 .msg = msg, 10189 .node = node, 10190 .token = 0, 10191 .byte_offset = 0, 10192 .notes = notes_index, 10193 }); 10194 } 10195 10196 fn failNodeNotes( 10197 astgen: *AstGen, 10198 node: Ast.Node.Index, 10199 comptime format: []const u8, 10200 args: anytype, 10201 notes: []const u32, 10202 ) InnerError { 10203 try appendErrorNodeNotes(astgen, node, format, args, notes); 10204 return error.AnalysisFail; 10205 } 10206 10207 fn failTok( 10208 astgen: *AstGen, 10209 token: Ast.TokenIndex, 10210 comptime format: []const u8, 10211 args: anytype, 10212 ) InnerError { 10213 return astgen.failTokNotes(token, format, args, &[0]u32{}); 10214 } 10215 10216 fn appendErrorTok( 10217 astgen: *AstGen, 10218 token: Ast.TokenIndex, 10219 comptime format: []const u8, 10220 args: anytype, 10221 ) !void { 10222 try astgen.appendErrorTokNotes(token, format, args, &[0]u32{}); 10223 } 10224 10225 fn failTokNotes( 10226 astgen: *AstGen, 10227 token: Ast.TokenIndex, 10228 comptime format: []const u8, 10229 args: anytype, 10230 notes: []const u32, 10231 ) InnerError { 10232 try appendErrorTokNotes(astgen, token, format, args, notes); 10233 return error.AnalysisFail; 10234 } 10235 10236 fn appendErrorTokNotes( 10237 astgen: *AstGen, 10238 token: Ast.TokenIndex, 10239 comptime format: []const u8, 10240 args: anytype, 10241 notes: []const u32, 10242 ) !void { 10243 @setCold(true); 10244 const string_bytes = &astgen.string_bytes; 10245 const msg = @intCast(u32, string_bytes.items.len); 10246 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 10247 const notes_index: u32 = if (notes.len != 0) blk: { 10248 const notes_start = astgen.extra.items.len; 10249 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 10250 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 10251 astgen.extra.appendSliceAssumeCapacity(notes); 10252 break :blk @intCast(u32, notes_start); 10253 } else 0; 10254 try astgen.compile_errors.append(astgen.gpa, .{ 10255 .msg = msg, 10256 .node = 0, 10257 .token = token, 10258 .byte_offset = 0, 10259 .notes = notes_index, 10260 }); 10261 } 10262 10263 /// Same as `fail`, except given an absolute byte offset. 10264 fn failOff( 10265 astgen: *AstGen, 10266 token: Ast.TokenIndex, 10267 byte_offset: u32, 10268 comptime format: []const u8, 10269 args: anytype, 10270 ) InnerError { 10271 try appendErrorOff(astgen, token, byte_offset, format, args); 10272 return error.AnalysisFail; 10273 } 10274 10275 fn appendErrorOff( 10276 astgen: *AstGen, 10277 token: Ast.TokenIndex, 10278 byte_offset: u32, 10279 comptime format: []const u8, 10280 args: anytype, 10281 ) Allocator.Error!void { 10282 @setCold(true); 10283 const string_bytes = &astgen.string_bytes; 10284 const msg = @intCast(u32, string_bytes.items.len); 10285 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 10286 try astgen.compile_errors.append(astgen.gpa, .{ 10287 .msg = msg, 10288 .node = 0, 10289 .token = token, 10290 .byte_offset = byte_offset, 10291 .notes = 0, 10292 }); 10293 } 10294 10295 fn errNoteTok( 10296 astgen: *AstGen, 10297 token: Ast.TokenIndex, 10298 comptime format: []const u8, 10299 args: anytype, 10300 ) Allocator.Error!u32 { 10301 @setCold(true); 10302 const string_bytes = &astgen.string_bytes; 10303 const msg = @intCast(u32, string_bytes.items.len); 10304 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 10305 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 10306 .msg = msg, 10307 .node = 0, 10308 .token = token, 10309 .byte_offset = 0, 10310 .notes = 0, 10311 }); 10312 } 10313 10314 fn errNoteNode( 10315 astgen: *AstGen, 10316 node: Ast.Node.Index, 10317 comptime format: []const u8, 10318 args: anytype, 10319 ) Allocator.Error!u32 { 10320 @setCold(true); 10321 const string_bytes = &astgen.string_bytes; 10322 const msg = @intCast(u32, string_bytes.items.len); 10323 try string_bytes.writer(astgen.gpa).print(format ++ "\x00", args); 10324 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 10325 .msg = msg, 10326 .node = node, 10327 .token = 0, 10328 .byte_offset = 0, 10329 .notes = 0, 10330 }); 10331 } 10332 10333 fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { 10334 const gpa = astgen.gpa; 10335 const string_bytes = &astgen.string_bytes; 10336 const str_index = @intCast(u32, string_bytes.items.len); 10337 try astgen.appendIdentStr(ident_token, string_bytes); 10338 const key = string_bytes.items[str_index..]; 10339 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 10340 .bytes = string_bytes, 10341 }, StringIndexContext{ 10342 .bytes = string_bytes, 10343 }); 10344 if (gop.found_existing) { 10345 string_bytes.shrinkRetainingCapacity(str_index); 10346 return gop.key_ptr.*; 10347 } else { 10348 gop.key_ptr.* = str_index; 10349 try string_bytes.append(gpa, 0); 10350 return str_index; 10351 } 10352 } 10353 10354 /// Adds a doc comment block to `string_bytes` by walking backwards from `end_token`. 10355 /// `end_token` must point at the first token after the last doc coment line. 10356 /// Returns 0 if no doc comment is present. 10357 fn docCommentAsString(astgen: *AstGen, end_token: Ast.TokenIndex) !u32 { 10358 if (end_token == 0) return @as(u32, 0); 10359 10360 const token_tags = astgen.tree.tokens.items(.tag); 10361 10362 var tok = end_token - 1; 10363 while (token_tags[tok] == .doc_comment) { 10364 if (tok == 0) break; 10365 tok -= 1; 10366 } else { 10367 tok += 1; 10368 } 10369 return docCommentAsStringFromFirst(astgen, end_token, tok); 10370 } 10371 10372 /// end_token must be > the index of the last doc comment. 10373 fn docCommentAsStringFromFirst( 10374 astgen: *AstGen, 10375 end_token: Ast.TokenIndex, 10376 start_token: Ast.TokenIndex, 10377 ) !u32 { 10378 if (start_token == end_token) return 0; 10379 10380 const gpa = astgen.gpa; 10381 const string_bytes = &astgen.string_bytes; 10382 const str_index = @intCast(u32, string_bytes.items.len); 10383 const token_starts = astgen.tree.tokens.items(.start); 10384 const token_tags = astgen.tree.tokens.items(.tag); 10385 10386 const total_bytes = token_starts[end_token] - token_starts[start_token]; 10387 try string_bytes.ensureUnusedCapacity(gpa, total_bytes); 10388 10389 var current_token = start_token; 10390 while (current_token < end_token) : (current_token += 1) { 10391 switch (token_tags[current_token]) { 10392 .doc_comment => { 10393 const tok_bytes = astgen.tree.tokenSlice(current_token)[3..]; 10394 string_bytes.appendSliceAssumeCapacity(tok_bytes); 10395 if (current_token != end_token - 1) { 10396 string_bytes.appendAssumeCapacity('\n'); 10397 } 10398 }, 10399 else => break, 10400 } 10401 } 10402 10403 const key = string_bytes.items[str_index..]; 10404 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 10405 .bytes = string_bytes, 10406 }, StringIndexContext{ 10407 .bytes = string_bytes, 10408 }); 10409 10410 if (gop.found_existing) { 10411 string_bytes.shrinkRetainingCapacity(str_index); 10412 return gop.key_ptr.*; 10413 } else { 10414 gop.key_ptr.* = str_index; 10415 try string_bytes.append(gpa, 0); 10416 return str_index; 10417 } 10418 } 10419 10420 const IndexSlice = struct { index: u32, len: u32 }; 10421 10422 fn strLitAsString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !IndexSlice { 10423 const gpa = astgen.gpa; 10424 const string_bytes = &astgen.string_bytes; 10425 const str_index = @intCast(u32, string_bytes.items.len); 10426 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 10427 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 10428 const key = string_bytes.items[str_index..]; 10429 const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ 10430 .bytes = string_bytes, 10431 }, StringIndexContext{ 10432 .bytes = string_bytes, 10433 }); 10434 if (gop.found_existing) { 10435 string_bytes.shrinkRetainingCapacity(str_index); 10436 return IndexSlice{ 10437 .index = gop.key_ptr.*, 10438 .len = @intCast(u32, key.len), 10439 }; 10440 } else { 10441 gop.key_ptr.* = str_index; 10442 // Still need a null byte because we are using the same table 10443 // to lookup null terminated strings, so if we get a match, it has to 10444 // be null terminated for that to work. 10445 try string_bytes.append(gpa, 0); 10446 return IndexSlice{ 10447 .index = str_index, 10448 .len = @intCast(u32, key.len), 10449 }; 10450 } 10451 } 10452 10453 fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice { 10454 const tree = astgen.tree; 10455 const node_datas = tree.nodes.items(.data); 10456 10457 const start = node_datas[node].lhs; 10458 const end = node_datas[node].rhs; 10459 10460 const gpa = astgen.gpa; 10461 const string_bytes = &astgen.string_bytes; 10462 const str_index = string_bytes.items.len; 10463 10464 // First line: do not append a newline. 10465 var tok_i = start; 10466 { 10467 const slice = tree.tokenSlice(tok_i); 10468 const line_bytes = slice[2 .. slice.len - 1]; 10469 try string_bytes.appendSlice(gpa, line_bytes); 10470 tok_i += 1; 10471 } 10472 // Following lines: each line prepends a newline. 10473 while (tok_i <= end) : (tok_i += 1) { 10474 const slice = tree.tokenSlice(tok_i); 10475 const line_bytes = slice[2 .. slice.len - 1]; 10476 try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1); 10477 string_bytes.appendAssumeCapacity('\n'); 10478 string_bytes.appendSliceAssumeCapacity(line_bytes); 10479 } 10480 const len = string_bytes.items.len - str_index; 10481 try string_bytes.append(gpa, 0); 10482 return IndexSlice{ 10483 .index = @intCast(u32, str_index), 10484 .len = @intCast(u32, len), 10485 }; 10486 } 10487 10488 fn testNameString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !u32 { 10489 const gpa = astgen.gpa; 10490 const string_bytes = &astgen.string_bytes; 10491 const str_index = @intCast(u32, string_bytes.items.len); 10492 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 10493 try string_bytes.append(gpa, 0); // Indicates this is a test. 10494 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 10495 const slice = string_bytes.items[str_index + 1 ..]; 10496 if (mem.indexOfScalar(u8, slice, 0) != null) { 10497 return astgen.failTok(str_lit_token, "test name cannot contain null bytes", .{}); 10498 } else if (slice.len == 0) { 10499 return astgen.failTok(str_lit_token, "empty test name must be omitted", .{}); 10500 } 10501 try string_bytes.append(gpa, 0); 10502 return str_index; 10503 } 10504 10505 const Scope = struct { 10506 tag: Tag, 10507 10508 fn cast(base: *Scope, comptime T: type) ?*T { 10509 if (T == Defer) { 10510 switch (base.tag) { 10511 .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base), 10512 else => return null, 10513 } 10514 } 10515 if (base.tag != T.base_tag) 10516 return null; 10517 10518 return @fieldParentPtr(T, "base", base); 10519 } 10520 10521 fn parent(base: *Scope) ?*Scope { 10522 return switch (base.tag) { 10523 .gen_zir => base.cast(GenZir).?.parent, 10524 .local_val => base.cast(LocalVal).?.parent, 10525 .local_ptr => base.cast(LocalPtr).?.parent, 10526 .defer_normal, .defer_error => base.cast(Defer).?.parent, 10527 .namespace => base.cast(Namespace).?.parent, 10528 .top => null, 10529 }; 10530 } 10531 10532 const Tag = enum { 10533 gen_zir, 10534 local_val, 10535 local_ptr, 10536 defer_normal, 10537 defer_error, 10538 namespace, 10539 top, 10540 }; 10541 10542 /// The category of identifier. These tag names are user-visible in compile errors. 10543 const IdCat = enum { 10544 @"function parameter", 10545 @"local constant", 10546 @"local variable", 10547 @"loop index capture", 10548 @"switch tag capture", 10549 capture, 10550 }; 10551 10552 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. 10553 /// This structure lives as long as the AST generation of the Block 10554 /// node that contains the variable. 10555 const LocalVal = struct { 10556 const base_tag: Tag = .local_val; 10557 base: Scope = Scope{ .tag = base_tag }, 10558 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 10559 parent: *Scope, 10560 gen_zir: *GenZir, 10561 inst: Zir.Inst.Ref, 10562 /// Source location of the corresponding variable declaration. 10563 token_src: Ast.TokenIndex, 10564 /// Track the first identifer where it is referenced. 10565 /// 0 means never referenced. 10566 used: Ast.TokenIndex = 0, 10567 /// Track the identifier where it is discarded, like this `_ = foo;`. 10568 /// 0 means never discarded. 10569 discarded: Ast.TokenIndex = 0, 10570 /// String table index. 10571 name: u32, 10572 id_cat: IdCat, 10573 }; 10574 10575 /// This could be a `const` or `var` local. It has a pointer instead of a value. 10576 /// This structure lives as long as the AST generation of the Block 10577 /// node that contains the variable. 10578 const LocalPtr = struct { 10579 const base_tag: Tag = .local_ptr; 10580 base: Scope = Scope{ .tag = base_tag }, 10581 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 10582 parent: *Scope, 10583 gen_zir: *GenZir, 10584 ptr: Zir.Inst.Ref, 10585 /// Source location of the corresponding variable declaration. 10586 token_src: Ast.TokenIndex, 10587 /// Track the first identifer where it is referenced. 10588 /// 0 means never referenced. 10589 used: Ast.TokenIndex = 0, 10590 /// Track the identifier where it is discarded, like this `_ = foo;`. 10591 /// 0 means never discarded. 10592 discarded: Ast.TokenIndex = 0, 10593 /// String table index. 10594 name: u32, 10595 id_cat: IdCat, 10596 /// true means we find out during Sema whether the value is comptime. 10597 /// false means it is already known at AstGen the value is runtime-known. 10598 maybe_comptime: bool, 10599 }; 10600 10601 const Defer = struct { 10602 base: Scope, 10603 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 10604 parent: *Scope, 10605 index: u32, 10606 len: u32, 10607 remapped_err_code: Zir.Inst.Index = 0, 10608 }; 10609 10610 /// Represents a global scope that has any number of declarations in it. 10611 /// Each declaration has this as the parent scope. 10612 const Namespace = struct { 10613 const base_tag: Tag = .namespace; 10614 base: Scope = Scope{ .tag = base_tag }, 10615 10616 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 10617 parent: *Scope, 10618 /// Maps string table index to the source location of declaration, 10619 /// for the purposes of reporting name shadowing compile errors. 10620 decls: std.AutoHashMapUnmanaged(u32, Ast.Node.Index) = .{}, 10621 node: Ast.Node.Index, 10622 inst: Zir.Inst.Index, 10623 10624 /// The astgen scope containing this namespace. 10625 /// Only valid during astgen. 10626 declaring_gz: ?*GenZir, 10627 10628 /// Map from the raw captured value to the instruction 10629 /// ref of the capture for decls in this namespace 10630 captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 10631 10632 pub fn deinit(self: *Namespace, gpa: Allocator) void { 10633 self.decls.deinit(gpa); 10634 self.captures.deinit(gpa); 10635 self.* = undefined; 10636 } 10637 }; 10638 10639 const Top = struct { 10640 const base_tag: Scope.Tag = .top; 10641 base: Scope = Scope{ .tag = base_tag }, 10642 }; 10643 }; 10644 10645 /// This is a temporary structure; references to it are valid only 10646 /// while constructing a `Zir`. 10647 const GenZir = struct { 10648 const base_tag: Scope.Tag = .gen_zir; 10649 base: Scope = Scope{ .tag = base_tag }, 10650 force_comptime: bool, 10651 /// This is set to true for inline loops; false otherwise. 10652 is_inline: bool = false, 10653 c_import: bool = false, 10654 /// How decls created in this scope should be named. 10655 anon_name_strategy: Zir.Inst.NameStrategy = .anon, 10656 /// The containing decl AST node. 10657 decl_node_index: Ast.Node.Index, 10658 /// The containing decl line index, absolute. 10659 decl_line: u32, 10660 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. 10661 parent: *Scope, 10662 /// All `GenZir` scopes for the same ZIR share this. 10663 astgen: *AstGen, 10664 /// Keeps track of the list of instructions in this scope. Possibly shared. 10665 /// Indexes to instructions in `astgen`. 10666 instructions: *ArrayListUnmanaged(Zir.Inst.Index), 10667 /// A sub-block may share its instructions ArrayList with containing GenZir, 10668 /// if use is strictly nested. This saves prior size of list for unstacking. 10669 instructions_top: usize, 10670 label: ?Label = null, 10671 break_block: Zir.Inst.Index = 0, 10672 continue_block: Zir.Inst.Index = 0, 10673 /// Only valid when setBreakResultInfo is called. 10674 break_result_info: AstGen.ResultInfo = undefined, 10675 /// When a block has a pointer result location, here it is. 10676 rl_ptr: Zir.Inst.Ref = .none, 10677 /// When a block has a type result location, here it is. 10678 rl_ty_inst: Zir.Inst.Ref = .none, 10679 /// Keeps track of how many branches of a block did not actually 10680 /// consume the result location. astgen uses this to figure out 10681 /// whether to rely on break instructions or writing to the result 10682 /// pointer for the result instruction. 10683 rvalue_rl_count: usize = 0, 10684 /// Keeps track of how many break instructions there are. When astgen is finished 10685 /// with a block, it can check this against rvalue_rl_count to find out whether 10686 /// the break instructions should be downgraded to break_void. 10687 break_count: usize = 0, 10688 /// Tracks `break :foo bar` instructions so they can possibly be elided later if 10689 /// the labeled block ends up not needing a result location pointer. 10690 labeled_breaks: ArrayListUnmanaged(struct { br: Zir.Inst.Index, search: Zir.Inst.Index }) = .{}, 10691 10692 suspend_node: Ast.Node.Index = 0, 10693 nosuspend_node: Ast.Node.Index = 0, 10694 /// Set if this GenZir is a defer. 10695 cur_defer_node: Ast.Node.Index = 0, 10696 // Set if this GenZir is a defer or it is inside a defer. 10697 any_defer_node: Ast.Node.Index = 0, 10698 10699 /// Namespace members are lazy. When executing a decl within a namespace, 10700 /// any references to external instructions need to be treated specially. 10701 /// This list tracks those references. See also .closure_capture and .closure_get. 10702 /// Keys are the raw instruction index, values are the closure_capture instruction. 10703 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, 10704 10705 const unstacked_top = std.math.maxInt(usize); 10706 /// Call unstack before adding any new instructions to containing GenZir. 10707 fn unstack(self: *GenZir) void { 10708 if (self.instructions_top != unstacked_top) { 10709 self.instructions.items.len = self.instructions_top; 10710 self.instructions_top = unstacked_top; 10711 } 10712 } 10713 10714 fn isEmpty(self: *const GenZir) bool { 10715 return (self.instructions_top == unstacked_top) or 10716 (self.instructions.items.len == self.instructions_top); 10717 } 10718 10719 fn instructionsSlice(self: *const GenZir) []Zir.Inst.Index { 10720 return if (self.instructions_top == unstacked_top) 10721 &[0]Zir.Inst.Index{} 10722 else 10723 self.instructions.items[self.instructions_top..]; 10724 } 10725 10726 fn instructionsSliceUpto(self: *const GenZir, stacked_gz: *GenZir) []Zir.Inst.Index { 10727 return if (self.instructions_top == unstacked_top) 10728 &[0]Zir.Inst.Index{} 10729 else if (self.instructions == stacked_gz.instructions and stacked_gz.instructions_top != unstacked_top) 10730 self.instructions.items[self.instructions_top..stacked_gz.instructions_top] 10731 else 10732 self.instructions.items[self.instructions_top..]; 10733 } 10734 10735 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { 10736 return .{ 10737 .force_comptime = gz.force_comptime, 10738 .c_import = gz.c_import, 10739 .decl_node_index = gz.decl_node_index, 10740 .decl_line = gz.decl_line, 10741 .parent = scope, 10742 .rl_ty_inst = gz.rl_ty_inst, 10743 .astgen = gz.astgen, 10744 .suspend_node = gz.suspend_node, 10745 .nosuspend_node = gz.nosuspend_node, 10746 .any_defer_node = gz.any_defer_node, 10747 .instructions = gz.instructions, 10748 .instructions_top = gz.instructions.items.len, 10749 }; 10750 } 10751 10752 fn makeCoercionScope( 10753 parent_gz: *GenZir, 10754 scope: *Scope, 10755 dest_type: Zir.Inst.Ref, 10756 result_ptr: Zir.Inst.Ref, 10757 src_node: Ast.Node.Index, 10758 ) !GenZir { 10759 // Detect whether this expr() call goes into rvalue() to store the result into the 10760 // result location. If it does, elide the coerce_result_ptr instruction 10761 // as well as the store instruction, instead passing the result as an rvalue. 10762 var as_scope = parent_gz.makeSubBlock(scope); 10763 errdefer as_scope.unstack(); 10764 as_scope.rl_ptr = try as_scope.addPlNode(.coerce_result_ptr, src_node, Zir.Inst.Bin{ .lhs = dest_type, .rhs = result_ptr }); 10765 10766 // `rl_ty_inst` needs to be set in case the stores to `rl_ptr` are eliminated. 10767 as_scope.rl_ty_inst = dest_type; 10768 10769 return as_scope; 10770 } 10771 10772 /// Assumes `as_scope` is stacked immediately on top of `parent_gz`. Unstacks `as_scope`. 10773 fn finishCoercion( 10774 as_scope: *GenZir, 10775 parent_gz: *GenZir, 10776 ri: ResultInfo, 10777 src_node: Ast.Node.Index, 10778 result: Zir.Inst.Ref, 10779 dest_type: Zir.Inst.Ref, 10780 ) InnerError!Zir.Inst.Ref { 10781 assert(as_scope.instructions == parent_gz.instructions); 10782 const astgen = as_scope.astgen; 10783 if (as_scope.rvalue_rl_count == 1) { 10784 // Busted! This expression didn't actually need a pointer. 10785 const zir_tags = astgen.instructions.items(.tag); 10786 const zir_datas = astgen.instructions.items(.data); 10787 var src: usize = as_scope.instructions_top; 10788 var dst: usize = src; 10789 while (src < as_scope.instructions.items.len) : (src += 1) { 10790 const src_inst = as_scope.instructions.items[src]; 10791 if (indexToRef(src_inst) == as_scope.rl_ptr) continue; 10792 if (zir_tags[src_inst] == .store_to_block_ptr) { 10793 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; 10794 } 10795 as_scope.instructions.items[dst] = src_inst; 10796 dst += 1; 10797 } 10798 parent_gz.instructions.items.len -= src - dst; 10799 as_scope.instructions_top = GenZir.unstacked_top; 10800 // as_scope now unstacked, can add new instructions to parent_gz 10801 const casted_result = try parent_gz.addBin(.as, dest_type, result); 10802 return rvalue(parent_gz, ri, casted_result, src_node); 10803 } else { 10804 // implicitly move all as_scope instructions to parent_gz 10805 as_scope.instructions_top = GenZir.unstacked_top; 10806 return result; 10807 } 10808 } 10809 10810 const Label = struct { 10811 token: Ast.TokenIndex, 10812 block_inst: Zir.Inst.Index, 10813 used: bool = false, 10814 }; 10815 10816 /// Assumes nothing stacked on `gz`. 10817 fn endsWithNoReturn(gz: GenZir) bool { 10818 if (gz.isEmpty()) return false; 10819 const tags = gz.astgen.instructions.items(.tag); 10820 const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; 10821 return tags[last_inst].isNoReturn(); 10822 } 10823 10824 /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`. 10825 fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { 10826 if (inst_ref == .unreachable_value) return true; 10827 if (refToIndex(inst_ref)) |inst_index| { 10828 return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn(); 10829 } 10830 return false; 10831 } 10832 10833 fn nodeIndexToRelative(gz: GenZir, node_index: Ast.Node.Index) i32 { 10834 return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); 10835 } 10836 10837 fn tokenIndexToRelative(gz: GenZir, token: Ast.TokenIndex) u32 { 10838 return token - gz.srcToken(); 10839 } 10840 10841 fn srcToken(gz: GenZir) Ast.TokenIndex { 10842 return gz.astgen.tree.firstToken(gz.decl_node_index); 10843 } 10844 10845 fn setBreakResultInfo(gz: *GenZir, parent_ri: AstGen.ResultInfo) void { 10846 // Depending on whether the result location is a pointer or value, different 10847 // ZIR needs to be generated. In the former case we rely on storing to the 10848 // pointer to communicate the result, and use breakvoid; in the latter case 10849 // the block break instructions will have the result values. 10850 // One more complication: when the result location is a pointer, we detect 10851 // the scenario where the result location is not consumed. In this case 10852 // we emit ZIR for the block break instructions to have the result values, 10853 // and then rvalue() on that to pass the value to the result location. 10854 switch (parent_ri.rl) { 10855 .ty, .coerced_ty => |ty_inst| { 10856 gz.rl_ty_inst = ty_inst; 10857 gz.break_result_info = parent_ri; 10858 }, 10859 10860 .none, .ref => { 10861 gz.rl_ty_inst = .none; 10862 gz.break_result_info = parent_ri; 10863 }, 10864 10865 .discard => { 10866 gz.rl_ty_inst = .none; 10867 gz.break_result_info = .{ .rl = .discard }; 10868 }, 10869 10870 .ptr => |ptr_res| { 10871 gz.rl_ty_inst = .none; 10872 gz.break_result_info = .{ .rl = .{ .ptr = .{ .inst = ptr_res.inst } }, .ctx = parent_ri.ctx }; 10873 }, 10874 10875 .inferred_ptr => |ptr| { 10876 gz.rl_ty_inst = .none; 10877 gz.rl_ptr = ptr; 10878 gz.break_result_info = .{ .rl = .{ .block_ptr = gz }, .ctx = parent_ri.ctx }; 10879 }, 10880 10881 .block_ptr => |parent_block_scope| { 10882 gz.rl_ty_inst = parent_block_scope.rl_ty_inst; 10883 gz.rl_ptr = parent_block_scope.rl_ptr; 10884 gz.break_result_info = .{ .rl = .{ .block_ptr = gz }, .ctx = parent_ri.ctx }; 10885 }, 10886 } 10887 } 10888 10889 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10890 fn setBoolBrBody(gz: *GenZir, inst: Zir.Inst.Index) !void { 10891 const astgen = gz.astgen; 10892 const gpa = astgen.gpa; 10893 const body = gz.instructionsSlice(); 10894 const body_len = astgen.countBodyLenAfterFixups(body); 10895 try astgen.extra.ensureUnusedCapacity( 10896 gpa, 10897 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len, 10898 ); 10899 const zir_datas = astgen.instructions.items(.data); 10900 zir_datas[inst].bool_br.payload_index = astgen.addExtraAssumeCapacity( 10901 Zir.Inst.Block{ .body_len = body_len }, 10902 ); 10903 astgen.appendBodyWithFixups(body); 10904 gz.unstack(); 10905 } 10906 10907 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10908 fn setBlockBody(gz: *GenZir, inst: Zir.Inst.Index) !void { 10909 const astgen = gz.astgen; 10910 const gpa = astgen.gpa; 10911 const body = gz.instructionsSlice(); 10912 const body_len = astgen.countBodyLenAfterFixups(body); 10913 try astgen.extra.ensureUnusedCapacity( 10914 gpa, 10915 @typeInfo(Zir.Inst.Block).Struct.fields.len + body_len, 10916 ); 10917 const zir_datas = astgen.instructions.items(.data); 10918 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity( 10919 Zir.Inst.Block{ .body_len = body_len }, 10920 ); 10921 astgen.appendBodyWithFixups(body); 10922 gz.unstack(); 10923 } 10924 10925 /// Assumes nothing stacked on `gz`. Unstacks `gz`. 10926 fn setTryBody(gz: *GenZir, inst: Zir.Inst.Index, operand: Zir.Inst.Ref) !void { 10927 const astgen = gz.astgen; 10928 const gpa = astgen.gpa; 10929 const body = gz.instructionsSlice(); 10930 const body_len = astgen.countBodyLenAfterFixups(body); 10931 try astgen.extra.ensureUnusedCapacity( 10932 gpa, 10933 @typeInfo(Zir.Inst.Try).Struct.fields.len + body_len, 10934 ); 10935 const zir_datas = astgen.instructions.items(.data); 10936 zir_datas[inst].pl_node.payload_index = astgen.addExtraAssumeCapacity( 10937 Zir.Inst.Try{ 10938 .operand = operand, 10939 .body_len = body_len, 10940 }, 10941 ); 10942 astgen.appendBodyWithFixups(body); 10943 gz.unstack(); 10944 } 10945 10946 /// Must be called with the following stack set up: 10947 /// * gz (bottom) 10948 /// * align_gz 10949 /// * addrspace_gz 10950 /// * section_gz 10951 /// * cc_gz 10952 /// * ret_gz 10953 /// * body_gz (top) 10954 /// Unstacks all of those except for `gz`. 10955 fn addFunc(gz: *GenZir, args: struct { 10956 src_node: Ast.Node.Index, 10957 lbrace_line: u32 = 0, 10958 lbrace_column: u32 = 0, 10959 param_block: Zir.Inst.Index, 10960 10961 align_gz: ?*GenZir, 10962 addrspace_gz: ?*GenZir, 10963 section_gz: ?*GenZir, 10964 cc_gz: ?*GenZir, 10965 ret_gz: ?*GenZir, 10966 body_gz: ?*GenZir, 10967 10968 align_ref: Zir.Inst.Ref, 10969 addrspace_ref: Zir.Inst.Ref, 10970 section_ref: Zir.Inst.Ref, 10971 cc_ref: Zir.Inst.Ref, 10972 ret_ref: Zir.Inst.Ref, 10973 10974 lib_name: u32, 10975 noalias_bits: u32, 10976 is_var_args: bool, 10977 is_inferred_error: bool, 10978 is_test: bool, 10979 is_extern: bool, 10980 is_noinline: bool, 10981 }) !Zir.Inst.Ref { 10982 assert(args.src_node != 0); 10983 const astgen = gz.astgen; 10984 const gpa = astgen.gpa; 10985 const ret_ref = if (args.ret_ref == .void_type) .none else args.ret_ref; 10986 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 10987 10988 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 10989 10990 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; 10991 var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; 10992 var src_locs_buffer: [3]u32 = undefined; 10993 var src_locs: []u32 = src_locs_buffer[0..0]; 10994 if (args.body_gz) |body_gz| { 10995 const tree = astgen.tree; 10996 const node_tags = tree.nodes.items(.tag); 10997 const node_datas = tree.nodes.items(.data); 10998 const token_starts = tree.tokens.items(.start); 10999 const fn_decl = args.src_node; 11000 assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); 11001 const block = node_datas[fn_decl].rhs; 11002 const rbrace_start = token_starts[tree.lastToken(block)]; 11003 astgen.advanceSourceCursor(rbrace_start); 11004 const rbrace_line = @intCast(u32, astgen.source_line - gz.decl_line); 11005 const rbrace_column = @intCast(u32, astgen.source_column); 11006 11007 const columns = args.lbrace_column | (rbrace_column << 16); 11008 src_locs_buffer[0] = args.lbrace_line; 11009 src_locs_buffer[1] = rbrace_line; 11010 src_locs_buffer[2] = columns; 11011 src_locs = &src_locs_buffer; 11012 11013 body = body_gz.instructionsSlice(); 11014 if (args.ret_gz) |ret_gz| 11015 ret_body = ret_gz.instructionsSliceUpto(body_gz); 11016 } else { 11017 if (args.ret_gz) |ret_gz| 11018 ret_body = ret_gz.instructionsSlice(); 11019 } 11020 const body_len = astgen.countBodyLenAfterFixups(body); 11021 11022 if (args.cc_ref != .none or args.lib_name != 0 or args.is_var_args or args.is_test or 11023 args.is_extern or args.align_ref != .none or args.section_ref != .none or 11024 args.addrspace_ref != .none or args.noalias_bits != 0 or args.is_noinline) 11025 { 11026 var align_body: []Zir.Inst.Index = &.{}; 11027 var addrspace_body: []Zir.Inst.Index = &.{}; 11028 var section_body: []Zir.Inst.Index = &.{}; 11029 var cc_body: []Zir.Inst.Index = &.{}; 11030 if (args.ret_gz != null) { 11031 align_body = args.align_gz.?.instructionsSliceUpto(args.addrspace_gz.?); 11032 addrspace_body = args.addrspace_gz.?.instructionsSliceUpto(args.section_gz.?); 11033 section_body = args.section_gz.?.instructionsSliceUpto(args.cc_gz.?); 11034 cc_body = args.cc_gz.?.instructionsSliceUpto(args.ret_gz.?); 11035 } 11036 11037 try astgen.extra.ensureUnusedCapacity( 11038 gpa, 11039 @typeInfo(Zir.Inst.FuncFancy).Struct.fields.len + 11040 fancyFnExprExtraLen(astgen, align_body, args.align_ref) + 11041 fancyFnExprExtraLen(astgen, addrspace_body, args.addrspace_ref) + 11042 fancyFnExprExtraLen(astgen, section_body, args.section_ref) + 11043 fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) + 11044 fancyFnExprExtraLen(astgen, ret_body, ret_ref) + 11045 body_len + src_locs.len + 11046 @boolToInt(args.lib_name != 0) + 11047 @boolToInt(args.noalias_bits != 0), 11048 ); 11049 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{ 11050 .param_block = args.param_block, 11051 .body_len = body_len, 11052 .bits = .{ 11053 .is_var_args = args.is_var_args, 11054 .is_inferred_error = args.is_inferred_error, 11055 .is_test = args.is_test, 11056 .is_extern = args.is_extern, 11057 .is_noinline = args.is_noinline, 11058 .has_lib_name = args.lib_name != 0, 11059 .has_any_noalias = args.noalias_bits != 0, 11060 11061 .has_align_ref = args.align_ref != .none, 11062 .has_addrspace_ref = args.addrspace_ref != .none, 11063 .has_section_ref = args.section_ref != .none, 11064 .has_cc_ref = args.cc_ref != .none, 11065 .has_ret_ty_ref = ret_ref != .none, 11066 11067 .has_align_body = align_body.len != 0, 11068 .has_addrspace_body = addrspace_body.len != 0, 11069 .has_section_body = section_body.len != 0, 11070 .has_cc_body = cc_body.len != 0, 11071 .has_ret_ty_body = ret_body.len != 0, 11072 }, 11073 }); 11074 if (args.lib_name != 0) { 11075 astgen.extra.appendAssumeCapacity(args.lib_name); 11076 } 11077 11078 const zir_datas = astgen.instructions.items(.data); 11079 if (align_body.len != 0) { 11080 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, align_body)); 11081 astgen.appendBodyWithFixups(align_body); 11082 zir_datas[align_body[align_body.len - 1]].@"break".block_inst = new_index; 11083 } else if (args.align_ref != .none) { 11084 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_ref)); 11085 } 11086 if (addrspace_body.len != 0) { 11087 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, addrspace_body)); 11088 astgen.appendBodyWithFixups(addrspace_body); 11089 zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".block_inst = new_index; 11090 } else if (args.addrspace_ref != .none) { 11091 astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_ref)); 11092 } 11093 if (section_body.len != 0) { 11094 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, section_body)); 11095 astgen.appendBodyWithFixups(section_body); 11096 zir_datas[section_body[section_body.len - 1]].@"break".block_inst = new_index; 11097 } else if (args.section_ref != .none) { 11098 astgen.extra.appendAssumeCapacity(@enumToInt(args.section_ref)); 11099 } 11100 if (cc_body.len != 0) { 11101 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, cc_body)); 11102 astgen.appendBodyWithFixups(cc_body); 11103 zir_datas[cc_body[cc_body.len - 1]].@"break".block_inst = new_index; 11104 } else if (args.cc_ref != .none) { 11105 astgen.extra.appendAssumeCapacity(@enumToInt(args.cc_ref)); 11106 } 11107 if (ret_body.len != 0) { 11108 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, ret_body)); 11109 astgen.appendBodyWithFixups(ret_body); 11110 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; 11111 } else if (ret_ref != .none) { 11112 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); 11113 } 11114 11115 if (args.noalias_bits != 0) { 11116 astgen.extra.appendAssumeCapacity(args.noalias_bits); 11117 } 11118 11119 astgen.appendBodyWithFixups(body); 11120 astgen.extra.appendSliceAssumeCapacity(src_locs); 11121 11122 // Order is important when unstacking. 11123 if (args.body_gz) |body_gz| body_gz.unstack(); 11124 if (args.ret_gz != null) { 11125 args.ret_gz.?.unstack(); 11126 args.cc_gz.?.unstack(); 11127 args.section_gz.?.unstack(); 11128 args.addrspace_gz.?.unstack(); 11129 args.align_gz.?.unstack(); 11130 } 11131 11132 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11133 11134 astgen.instructions.appendAssumeCapacity(.{ 11135 .tag = .func_fancy, 11136 .data = .{ .pl_node = .{ 11137 .src_node = gz.nodeIndexToRelative(args.src_node), 11138 .payload_index = payload_index, 11139 } }, 11140 }); 11141 gz.instructions.appendAssumeCapacity(new_index); 11142 return indexToRef(new_index); 11143 } else { 11144 try astgen.extra.ensureUnusedCapacity( 11145 gpa, 11146 @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 + 11147 fancyFnExprExtraLen(astgen, ret_body, ret_ref) + 11148 body_len + src_locs.len, 11149 ); 11150 11151 const ret_body_len = if (ret_body.len != 0) 11152 countBodyLenAfterFixups(astgen, ret_body) 11153 else 11154 @boolToInt(ret_ref != .none); 11155 11156 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{ 11157 .param_block = args.param_block, 11158 .ret_body_len = ret_body_len, 11159 .body_len = body_len, 11160 }); 11161 const zir_datas = astgen.instructions.items(.data); 11162 if (ret_body.len != 0) { 11163 astgen.appendBodyWithFixups(ret_body); 11164 zir_datas[ret_body[ret_body.len - 1]].@"break".block_inst = new_index; 11165 } else if (ret_ref != .none) { 11166 astgen.extra.appendAssumeCapacity(@enumToInt(ret_ref)); 11167 } 11168 astgen.appendBodyWithFixups(body); 11169 astgen.extra.appendSliceAssumeCapacity(src_locs); 11170 11171 // Order is important when unstacking. 11172 if (args.body_gz) |body_gz| body_gz.unstack(); 11173 if (args.ret_gz) |ret_gz| ret_gz.unstack(); 11174 if (args.cc_gz) |cc_gz| cc_gz.unstack(); 11175 if (args.section_gz) |section_gz| section_gz.unstack(); 11176 if (args.addrspace_gz) |addrspace_gz| addrspace_gz.unstack(); 11177 if (args.align_gz) |align_gz| align_gz.unstack(); 11178 11179 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11180 11181 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; 11182 astgen.instructions.appendAssumeCapacity(.{ 11183 .tag = tag, 11184 .data = .{ .pl_node = .{ 11185 .src_node = gz.nodeIndexToRelative(args.src_node), 11186 .payload_index = payload_index, 11187 } }, 11188 }); 11189 gz.instructions.appendAssumeCapacity(new_index); 11190 return indexToRef(new_index); 11191 } 11192 } 11193 11194 fn fancyFnExprExtraLen(astgen: *AstGen, body: []Zir.Inst.Index, ref: Zir.Inst.Ref) u32 { 11195 // In the case of non-empty body, there is one for the body length, 11196 // and then one for each instruction. 11197 return countBodyLenAfterFixups(astgen, body) + @boolToInt(ref != .none); 11198 } 11199 11200 fn addVar(gz: *GenZir, args: struct { 11201 align_inst: Zir.Inst.Ref, 11202 lib_name: u32, 11203 var_type: Zir.Inst.Ref, 11204 init: Zir.Inst.Ref, 11205 is_extern: bool, 11206 is_threadlocal: bool, 11207 }) !Zir.Inst.Ref { 11208 const astgen = gz.astgen; 11209 const gpa = astgen.gpa; 11210 11211 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11212 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 11213 11214 try astgen.extra.ensureUnusedCapacity( 11215 gpa, 11216 @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + 11217 @boolToInt(args.lib_name != 0) + 11218 @boolToInt(args.align_inst != .none) + 11219 @boolToInt(args.init != .none), 11220 ); 11221 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ 11222 .var_type = args.var_type, 11223 }); 11224 if (args.lib_name != 0) { 11225 astgen.extra.appendAssumeCapacity(args.lib_name); 11226 } 11227 if (args.align_inst != .none) { 11228 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 11229 } 11230 if (args.init != .none) { 11231 astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); 11232 } 11233 11234 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 11235 astgen.instructions.appendAssumeCapacity(.{ 11236 .tag = .extended, 11237 .data = .{ .extended = .{ 11238 .opcode = .variable, 11239 .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ 11240 .has_lib_name = args.lib_name != 0, 11241 .has_align = args.align_inst != .none, 11242 .has_init = args.init != .none, 11243 .is_extern = args.is_extern, 11244 .is_threadlocal = args.is_threadlocal, 11245 }), 11246 .operand = payload_index, 11247 } }, 11248 }); 11249 gz.instructions.appendAssumeCapacity(new_index); 11250 return indexToRef(new_index); 11251 } 11252 11253 /// Note that this returns a `Zir.Inst.Index` not a ref. 11254 /// Leaves the `payload_index` field undefined. 11255 fn addBoolBr( 11256 gz: *GenZir, 11257 tag: Zir.Inst.Tag, 11258 lhs: Zir.Inst.Ref, 11259 ) !Zir.Inst.Index { 11260 assert(lhs != .none); 11261 const gpa = gz.astgen.gpa; 11262 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11263 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11264 11265 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11266 gz.astgen.instructions.appendAssumeCapacity(.{ 11267 .tag = tag, 11268 .data = .{ .bool_br = .{ 11269 .lhs = lhs, 11270 .payload_index = undefined, 11271 } }, 11272 }); 11273 gz.instructions.appendAssumeCapacity(new_index); 11274 return new_index; 11275 } 11276 11277 fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { 11278 return gz.add(.{ 11279 .tag = .int, 11280 .data = .{ .int = integer }, 11281 }); 11282 } 11283 11284 fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref { 11285 const astgen = gz.astgen; 11286 const gpa = astgen.gpa; 11287 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11288 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 11289 try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len); 11290 11291 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 11292 astgen.instructions.appendAssumeCapacity(.{ 11293 .tag = .int_big, 11294 .data = .{ .str = .{ 11295 .start = @intCast(u32, astgen.string_bytes.items.len), 11296 .len = @intCast(u32, limbs.len), 11297 } }, 11298 }); 11299 gz.instructions.appendAssumeCapacity(new_index); 11300 astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs)); 11301 return indexToRef(new_index); 11302 } 11303 11304 fn addFloat(gz: *GenZir, number: f64) !Zir.Inst.Ref { 11305 return gz.add(.{ 11306 .tag = .float, 11307 .data = .{ .float = number }, 11308 }); 11309 } 11310 11311 fn addUnNode( 11312 gz: *GenZir, 11313 tag: Zir.Inst.Tag, 11314 operand: Zir.Inst.Ref, 11315 /// Absolute node index. This function does the conversion to offset from Decl. 11316 src_node: Ast.Node.Index, 11317 ) !Zir.Inst.Ref { 11318 assert(operand != .none); 11319 return gz.add(.{ 11320 .tag = tag, 11321 .data = .{ .un_node = .{ 11322 .operand = operand, 11323 .src_node = gz.nodeIndexToRelative(src_node), 11324 } }, 11325 }); 11326 } 11327 11328 fn makeUnNode( 11329 gz: *GenZir, 11330 tag: Zir.Inst.Tag, 11331 operand: Zir.Inst.Ref, 11332 /// Absolute node index. This function does the conversion to offset from Decl. 11333 src_node: Ast.Node.Index, 11334 ) !Zir.Inst.Index { 11335 assert(operand != .none); 11336 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11337 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 11338 .tag = tag, 11339 .data = .{ .un_node = .{ 11340 .operand = operand, 11341 .src_node = gz.nodeIndexToRelative(src_node), 11342 } }, 11343 }); 11344 return new_index; 11345 } 11346 11347 fn addPlNode( 11348 gz: *GenZir, 11349 tag: Zir.Inst.Tag, 11350 /// Absolute node index. This function does the conversion to offset from Decl. 11351 src_node: Ast.Node.Index, 11352 extra: anytype, 11353 ) !Zir.Inst.Ref { 11354 const gpa = gz.astgen.gpa; 11355 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11356 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11357 11358 const payload_index = try gz.astgen.addExtra(extra); 11359 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11360 gz.astgen.instructions.appendAssumeCapacity(.{ 11361 .tag = tag, 11362 .data = .{ .pl_node = .{ 11363 .src_node = gz.nodeIndexToRelative(src_node), 11364 .payload_index = payload_index, 11365 } }, 11366 }); 11367 gz.instructions.appendAssumeCapacity(new_index); 11368 return indexToRef(new_index); 11369 } 11370 11371 fn addPlNodePayloadIndex( 11372 gz: *GenZir, 11373 tag: Zir.Inst.Tag, 11374 /// Absolute node index. This function does the conversion to offset from Decl. 11375 src_node: Ast.Node.Index, 11376 payload_index: u32, 11377 ) !Zir.Inst.Ref { 11378 return try gz.add(.{ 11379 .tag = tag, 11380 .data = .{ .pl_node = .{ 11381 .src_node = gz.nodeIndexToRelative(src_node), 11382 .payload_index = payload_index, 11383 } }, 11384 }); 11385 } 11386 11387 /// Supports `param_gz` stacked on `gz`. Assumes nothing stacked on `param_gz`. Unstacks `param_gz`. 11388 fn addParam( 11389 gz: *GenZir, 11390 param_gz: *GenZir, 11391 tag: Zir.Inst.Tag, 11392 /// Absolute token index. This function does the conversion to Decl offset. 11393 abs_tok_index: Ast.TokenIndex, 11394 name: u32, 11395 first_doc_comment: ?Ast.TokenIndex, 11396 ) !Zir.Inst.Index { 11397 const gpa = gz.astgen.gpa; 11398 const param_body = param_gz.instructionsSlice(); 11399 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11400 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len + 11401 param_body.len); 11402 11403 const doc_comment_index = if (first_doc_comment) |first| 11404 try gz.astgen.docCommentAsStringFromFirst(abs_tok_index, first) 11405 else 11406 0; 11407 11408 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{ 11409 .name = name, 11410 .doc_comment = doc_comment_index, 11411 .body_len = @intCast(u32, param_body.len), 11412 }); 11413 gz.astgen.extra.appendSliceAssumeCapacity(param_body); 11414 param_gz.unstack(); 11415 11416 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11417 gz.astgen.instructions.appendAssumeCapacity(.{ 11418 .tag = tag, 11419 .data = .{ .pl_tok = .{ 11420 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 11421 .payload_index = payload_index, 11422 } }, 11423 }); 11424 gz.instructions.appendAssumeCapacity(new_index); 11425 return new_index; 11426 } 11427 11428 fn addExtendedPayload(gz: *GenZir, opcode: Zir.Inst.Extended, extra: anytype) !Zir.Inst.Ref { 11429 return addExtendedPayloadSmall(gz, opcode, undefined, extra); 11430 } 11431 11432 fn addExtendedPayloadSmall( 11433 gz: *GenZir, 11434 opcode: Zir.Inst.Extended, 11435 small: u16, 11436 extra: anytype, 11437 ) !Zir.Inst.Ref { 11438 const gpa = gz.astgen.gpa; 11439 11440 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11441 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 11442 11443 const payload_index = try gz.astgen.addExtra(extra); 11444 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11445 gz.astgen.instructions.appendAssumeCapacity(.{ 11446 .tag = .extended, 11447 .data = .{ .extended = .{ 11448 .opcode = opcode, 11449 .small = small, 11450 .operand = payload_index, 11451 } }, 11452 }); 11453 gz.instructions.appendAssumeCapacity(new_index); 11454 return indexToRef(new_index); 11455 } 11456 11457 fn addExtendedMultiOp( 11458 gz: *GenZir, 11459 opcode: Zir.Inst.Extended, 11460 node: Ast.Node.Index, 11461 operands: []const Zir.Inst.Ref, 11462 ) !Zir.Inst.Ref { 11463 const astgen = gz.astgen; 11464 const gpa = astgen.gpa; 11465 11466 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11467 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 11468 try astgen.extra.ensureUnusedCapacity( 11469 gpa, 11470 @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len, 11471 ); 11472 11473 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{ 11474 .src_node = gz.nodeIndexToRelative(node), 11475 }); 11476 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 11477 astgen.instructions.appendAssumeCapacity(.{ 11478 .tag = .extended, 11479 .data = .{ .extended = .{ 11480 .opcode = opcode, 11481 .small = @intCast(u16, operands.len), 11482 .operand = payload_index, 11483 } }, 11484 }); 11485 gz.instructions.appendAssumeCapacity(new_index); 11486 astgen.appendRefsAssumeCapacity(operands); 11487 return indexToRef(new_index); 11488 } 11489 11490 fn addExtendedMultiOpPayloadIndex( 11491 gz: *GenZir, 11492 opcode: Zir.Inst.Extended, 11493 payload_index: u32, 11494 trailing_len: usize, 11495 ) !Zir.Inst.Ref { 11496 const astgen = gz.astgen; 11497 const gpa = astgen.gpa; 11498 11499 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11500 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 11501 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 11502 astgen.instructions.appendAssumeCapacity(.{ 11503 .tag = .extended, 11504 .data = .{ .extended = .{ 11505 .opcode = opcode, 11506 .small = @intCast(u16, trailing_len), 11507 .operand = payload_index, 11508 } }, 11509 }); 11510 gz.instructions.appendAssumeCapacity(new_index); 11511 return indexToRef(new_index); 11512 } 11513 11514 fn addUnTok( 11515 gz: *GenZir, 11516 tag: Zir.Inst.Tag, 11517 operand: Zir.Inst.Ref, 11518 /// Absolute token index. This function does the conversion to Decl offset. 11519 abs_tok_index: Ast.TokenIndex, 11520 ) !Zir.Inst.Ref { 11521 assert(operand != .none); 11522 return gz.add(.{ 11523 .tag = tag, 11524 .data = .{ .un_tok = .{ 11525 .operand = operand, 11526 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 11527 } }, 11528 }); 11529 } 11530 11531 fn makeUnTok( 11532 gz: *GenZir, 11533 tag: Zir.Inst.Tag, 11534 operand: Zir.Inst.Ref, 11535 /// Absolute token index. This function does the conversion to Decl offset. 11536 abs_tok_index: Ast.TokenIndex, 11537 ) !Zir.Inst.Index { 11538 const astgen = gz.astgen; 11539 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 11540 assert(operand != .none); 11541 try astgen.instructions.append(astgen.gpa, .{ 11542 .tag = tag, 11543 .data = .{ .un_tok = .{ 11544 .operand = operand, 11545 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 11546 } }, 11547 }); 11548 return new_index; 11549 } 11550 11551 fn addStrTok( 11552 gz: *GenZir, 11553 tag: Zir.Inst.Tag, 11554 str_index: u32, 11555 /// Absolute token index. This function does the conversion to Decl offset. 11556 abs_tok_index: Ast.TokenIndex, 11557 ) !Zir.Inst.Ref { 11558 return gz.add(.{ 11559 .tag = tag, 11560 .data = .{ .str_tok = .{ 11561 .start = str_index, 11562 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 11563 } }, 11564 }); 11565 } 11566 11567 fn addSaveErrRetIndex( 11568 gz: *GenZir, 11569 cond: union(enum) { 11570 always: void, 11571 if_of_error_type: Zir.Inst.Ref, 11572 }, 11573 ) !Zir.Inst.Index { 11574 return gz.addAsIndex(.{ 11575 .tag = .save_err_ret_index, 11576 .data = .{ .save_err_ret_index = .{ 11577 .operand = if (cond == .if_of_error_type) cond.if_of_error_type else .none, 11578 } }, 11579 }); 11580 } 11581 11582 const BranchTarget = union(enum) { 11583 ret, 11584 block: Zir.Inst.Index, 11585 }; 11586 11587 fn addRestoreErrRetIndex( 11588 gz: *GenZir, 11589 bt: BranchTarget, 11590 cond: union(enum) { 11591 always: void, 11592 if_non_error: Zir.Inst.Ref, 11593 }, 11594 ) !Zir.Inst.Index { 11595 return gz.addAsIndex(.{ 11596 .tag = .restore_err_ret_index, 11597 .data = .{ .restore_err_ret_index = .{ 11598 .block = switch (bt) { 11599 .ret => .none, 11600 .block => |b| Zir.indexToRef(b), 11601 }, 11602 .operand = if (cond == .if_non_error) cond.if_non_error else .none, 11603 } }, 11604 }); 11605 } 11606 11607 fn addBreak( 11608 gz: *GenZir, 11609 tag: Zir.Inst.Tag, 11610 break_block: Zir.Inst.Index, 11611 operand: Zir.Inst.Ref, 11612 ) !Zir.Inst.Index { 11613 return gz.addAsIndex(.{ 11614 .tag = tag, 11615 .data = .{ .@"break" = .{ 11616 .block_inst = break_block, 11617 .operand = operand, 11618 } }, 11619 }); 11620 } 11621 11622 fn makeBreak( 11623 gz: *GenZir, 11624 tag: Zir.Inst.Tag, 11625 break_block: Zir.Inst.Index, 11626 operand: Zir.Inst.Ref, 11627 ) !Zir.Inst.Index { 11628 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11629 try gz.astgen.instructions.append(gz.astgen.gpa, .{ 11630 .tag = tag, 11631 .data = .{ .@"break" = .{ 11632 .block_inst = break_block, 11633 .operand = operand, 11634 } }, 11635 }); 11636 return new_index; 11637 } 11638 11639 fn addBin( 11640 gz: *GenZir, 11641 tag: Zir.Inst.Tag, 11642 lhs: Zir.Inst.Ref, 11643 rhs: Zir.Inst.Ref, 11644 ) !Zir.Inst.Ref { 11645 assert(lhs != .none); 11646 assert(rhs != .none); 11647 return gz.add(.{ 11648 .tag = tag, 11649 .data = .{ .bin = .{ 11650 .lhs = lhs, 11651 .rhs = rhs, 11652 } }, 11653 }); 11654 } 11655 11656 fn addDefer(gz: *GenZir, index: u32, len: u32) !void { 11657 _ = try gz.add(.{ 11658 .tag = .@"defer", 11659 .data = .{ .@"defer" = .{ 11660 .index = index, 11661 .len = len, 11662 } }, 11663 }); 11664 } 11665 11666 fn addDecl( 11667 gz: *GenZir, 11668 tag: Zir.Inst.Tag, 11669 decl_index: u32, 11670 src_node: Ast.Node.Index, 11671 ) !Zir.Inst.Ref { 11672 return gz.add(.{ 11673 .tag = tag, 11674 .data = .{ .pl_node = .{ 11675 .src_node = gz.nodeIndexToRelative(src_node), 11676 .payload_index = decl_index, 11677 } }, 11678 }); 11679 } 11680 11681 fn addNode( 11682 gz: *GenZir, 11683 tag: Zir.Inst.Tag, 11684 /// Absolute node index. This function does the conversion to offset from Decl. 11685 src_node: Ast.Node.Index, 11686 ) !Zir.Inst.Ref { 11687 return gz.add(.{ 11688 .tag = tag, 11689 .data = .{ .node = gz.nodeIndexToRelative(src_node) }, 11690 }); 11691 } 11692 11693 fn addInstNode( 11694 gz: *GenZir, 11695 tag: Zir.Inst.Tag, 11696 inst: Zir.Inst.Index, 11697 /// Absolute node index. This function does the conversion to offset from Decl. 11698 src_node: Ast.Node.Index, 11699 ) !Zir.Inst.Ref { 11700 return gz.add(.{ 11701 .tag = tag, 11702 .data = .{ .inst_node = .{ 11703 .inst = inst, 11704 .src_node = gz.nodeIndexToRelative(src_node), 11705 } }, 11706 }); 11707 } 11708 11709 fn addNodeExtended( 11710 gz: *GenZir, 11711 opcode: Zir.Inst.Extended, 11712 /// Absolute node index. This function does the conversion to offset from Decl. 11713 src_node: Ast.Node.Index, 11714 ) !Zir.Inst.Ref { 11715 return gz.add(.{ 11716 .tag = .extended, 11717 .data = .{ .extended = .{ 11718 .opcode = opcode, 11719 .small = undefined, 11720 .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)), 11721 } }, 11722 }); 11723 } 11724 11725 fn addAllocExtended( 11726 gz: *GenZir, 11727 args: struct { 11728 /// Absolute node index. This function does the conversion to offset from Decl. 11729 node: Ast.Node.Index, 11730 type_inst: Zir.Inst.Ref, 11731 align_inst: Zir.Inst.Ref, 11732 is_const: bool, 11733 is_comptime: bool, 11734 }, 11735 ) !Zir.Inst.Ref { 11736 const astgen = gz.astgen; 11737 const gpa = astgen.gpa; 11738 11739 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11740 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 11741 try astgen.extra.ensureUnusedCapacity( 11742 gpa, 11743 @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len + 11744 @as(usize, @boolToInt(args.type_inst != .none)) + 11745 @as(usize, @boolToInt(args.align_inst != .none)), 11746 ); 11747 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{ 11748 .src_node = gz.nodeIndexToRelative(args.node), 11749 }); 11750 if (args.type_inst != .none) { 11751 astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst)); 11752 } 11753 if (args.align_inst != .none) { 11754 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 11755 } 11756 11757 const has_type: u4 = @boolToInt(args.type_inst != .none); 11758 const has_align: u4 = @boolToInt(args.align_inst != .none); 11759 const is_const: u4 = @boolToInt(args.is_const); 11760 const is_comptime: u4 = @boolToInt(args.is_comptime); 11761 const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3); 11762 11763 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 11764 astgen.instructions.appendAssumeCapacity(.{ 11765 .tag = .extended, 11766 .data = .{ .extended = .{ 11767 .opcode = .alloc, 11768 .small = small, 11769 .operand = payload_index, 11770 } }, 11771 }); 11772 gz.instructions.appendAssumeCapacity(new_index); 11773 return indexToRef(new_index); 11774 } 11775 11776 fn addAsm( 11777 gz: *GenZir, 11778 args: struct { 11779 tag: Zir.Inst.Extended, 11780 /// Absolute node index. This function does the conversion to offset from Decl. 11781 node: Ast.Node.Index, 11782 asm_source: u32, 11783 output_type_bits: u32, 11784 is_volatile: bool, 11785 outputs: []const Zir.Inst.Asm.Output, 11786 inputs: []const Zir.Inst.Asm.Input, 11787 clobbers: []const u32, 11788 }, 11789 ) !Zir.Inst.Ref { 11790 const astgen = gz.astgen; 11791 const gpa = astgen.gpa; 11792 11793 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11794 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 11795 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len + 11796 args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len + 11797 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len + 11798 args.clobbers.len); 11799 11800 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{ 11801 .src_node = gz.nodeIndexToRelative(args.node), 11802 .asm_source = args.asm_source, 11803 .output_type_bits = args.output_type_bits, 11804 }); 11805 for (args.outputs) |output| { 11806 _ = gz.astgen.addExtraAssumeCapacity(output); 11807 } 11808 for (args.inputs) |input| { 11809 _ = gz.astgen.addExtraAssumeCapacity(input); 11810 } 11811 gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers); 11812 11813 // * 0b00000000_000XXXXX - `outputs_len`. 11814 // * 0b000000XX_XXX00000 - `inputs_len`. 11815 // * 0b0XXXXX00_00000000 - `clobbers_len`. 11816 // * 0bX0000000_00000000 - is volatile 11817 const small: u16 = @intCast(u16, args.outputs.len) | 11818 @intCast(u16, args.inputs.len << 5) | 11819 @intCast(u16, args.clobbers.len << 10) | 11820 (@as(u16, @boolToInt(args.is_volatile)) << 15); 11821 11822 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 11823 astgen.instructions.appendAssumeCapacity(.{ 11824 .tag = .extended, 11825 .data = .{ .extended = .{ 11826 .opcode = args.tag, 11827 .small = small, 11828 .operand = payload_index, 11829 } }, 11830 }); 11831 gz.instructions.appendAssumeCapacity(new_index); 11832 return indexToRef(new_index); 11833 } 11834 11835 /// Note that this returns a `Zir.Inst.Index` not a ref. 11836 /// Does *not* append the block instruction to the scope. 11837 /// Leaves the `payload_index` field undefined. 11838 fn makeBlockInst(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { 11839 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11840 const gpa = gz.astgen.gpa; 11841 try gz.astgen.instructions.append(gpa, .{ 11842 .tag = tag, 11843 .data = .{ .pl_node = .{ 11844 .src_node = gz.nodeIndexToRelative(node), 11845 .payload_index = undefined, 11846 } }, 11847 }); 11848 return new_index; 11849 } 11850 11851 /// Note that this returns a `Zir.Inst.Index` not a ref. 11852 /// Leaves the `payload_index` field undefined. 11853 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { 11854 const gpa = gz.astgen.gpa; 11855 try gz.instructions.ensureUnusedCapacity(gpa, 1); 11856 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 11857 try gz.astgen.instructions.append(gpa, .{ 11858 .tag = tag, 11859 .data = .{ .pl_node = .{ 11860 .src_node = gz.nodeIndexToRelative(node), 11861 .payload_index = undefined, 11862 } }, 11863 }); 11864 gz.instructions.appendAssumeCapacity(new_index); 11865 return new_index; 11866 } 11867 11868 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11869 src_node: Ast.Node.Index, 11870 fields_len: u32, 11871 decls_len: u32, 11872 backing_int_ref: Zir.Inst.Ref, 11873 backing_int_body_len: u32, 11874 layout: std.builtin.Type.ContainerLayout, 11875 known_non_opv: bool, 11876 known_comptime_only: bool, 11877 is_tuple: bool, 11878 }) !void { 11879 const astgen = gz.astgen; 11880 const gpa = astgen.gpa; 11881 11882 try astgen.extra.ensureUnusedCapacity(gpa, 6); 11883 const payload_index = @intCast(u32, astgen.extra.items.len); 11884 11885 if (args.src_node != 0) { 11886 const node_offset = gz.nodeIndexToRelative(args.src_node); 11887 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11888 } 11889 if (args.fields_len != 0) { 11890 astgen.extra.appendAssumeCapacity(args.fields_len); 11891 } 11892 if (args.decls_len != 0) { 11893 astgen.extra.appendAssumeCapacity(args.decls_len); 11894 } 11895 if (args.backing_int_ref != .none) { 11896 astgen.extra.appendAssumeCapacity(args.backing_int_body_len); 11897 if (args.backing_int_body_len == 0) { 11898 astgen.extra.appendAssumeCapacity(@enumToInt(args.backing_int_ref)); 11899 } 11900 } 11901 astgen.instructions.set(inst, .{ 11902 .tag = .extended, 11903 .data = .{ .extended = .{ 11904 .opcode = .struct_decl, 11905 .small = @bitCast(u16, Zir.Inst.StructDecl.Small{ 11906 .has_src_node = args.src_node != 0, 11907 .has_fields_len = args.fields_len != 0, 11908 .has_decls_len = args.decls_len != 0, 11909 .has_backing_int = args.backing_int_ref != .none, 11910 .known_non_opv = args.known_non_opv, 11911 .known_comptime_only = args.known_comptime_only, 11912 .is_tuple = args.is_tuple, 11913 .name_strategy = gz.anon_name_strategy, 11914 .layout = args.layout, 11915 }), 11916 .operand = payload_index, 11917 } }, 11918 }); 11919 } 11920 11921 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11922 src_node: Ast.Node.Index, 11923 tag_type: Zir.Inst.Ref, 11924 body_len: u32, 11925 fields_len: u32, 11926 decls_len: u32, 11927 layout: std.builtin.Type.ContainerLayout, 11928 auto_enum_tag: bool, 11929 }) !void { 11930 const astgen = gz.astgen; 11931 const gpa = astgen.gpa; 11932 11933 try astgen.extra.ensureUnusedCapacity(gpa, 5); 11934 const payload_index = @intCast(u32, astgen.extra.items.len); 11935 11936 if (args.src_node != 0) { 11937 const node_offset = gz.nodeIndexToRelative(args.src_node); 11938 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11939 } 11940 if (args.tag_type != .none) { 11941 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 11942 } 11943 if (args.body_len != 0) { 11944 astgen.extra.appendAssumeCapacity(args.body_len); 11945 } 11946 if (args.fields_len != 0) { 11947 astgen.extra.appendAssumeCapacity(args.fields_len); 11948 } 11949 if (args.decls_len != 0) { 11950 astgen.extra.appendAssumeCapacity(args.decls_len); 11951 } 11952 astgen.instructions.set(inst, .{ 11953 .tag = .extended, 11954 .data = .{ .extended = .{ 11955 .opcode = .union_decl, 11956 .small = @bitCast(u16, Zir.Inst.UnionDecl.Small{ 11957 .has_src_node = args.src_node != 0, 11958 .has_tag_type = args.tag_type != .none, 11959 .has_body_len = args.body_len != 0, 11960 .has_fields_len = args.fields_len != 0, 11961 .has_decls_len = args.decls_len != 0, 11962 .name_strategy = gz.anon_name_strategy, 11963 .layout = args.layout, 11964 .auto_enum_tag = args.auto_enum_tag, 11965 }), 11966 .operand = payload_index, 11967 } }, 11968 }); 11969 } 11970 11971 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 11972 src_node: Ast.Node.Index, 11973 tag_type: Zir.Inst.Ref, 11974 body_len: u32, 11975 fields_len: u32, 11976 decls_len: u32, 11977 nonexhaustive: bool, 11978 }) !void { 11979 const astgen = gz.astgen; 11980 const gpa = astgen.gpa; 11981 11982 try astgen.extra.ensureUnusedCapacity(gpa, 5); 11983 const payload_index = @intCast(u32, astgen.extra.items.len); 11984 11985 if (args.src_node != 0) { 11986 const node_offset = gz.nodeIndexToRelative(args.src_node); 11987 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 11988 } 11989 if (args.tag_type != .none) { 11990 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 11991 } 11992 if (args.body_len != 0) { 11993 astgen.extra.appendAssumeCapacity(args.body_len); 11994 } 11995 if (args.fields_len != 0) { 11996 astgen.extra.appendAssumeCapacity(args.fields_len); 11997 } 11998 if (args.decls_len != 0) { 11999 astgen.extra.appendAssumeCapacity(args.decls_len); 12000 } 12001 astgen.instructions.set(inst, .{ 12002 .tag = .extended, 12003 .data = .{ .extended = .{ 12004 .opcode = .enum_decl, 12005 .small = @bitCast(u16, Zir.Inst.EnumDecl.Small{ 12006 .has_src_node = args.src_node != 0, 12007 .has_tag_type = args.tag_type != .none, 12008 .has_body_len = args.body_len != 0, 12009 .has_fields_len = args.fields_len != 0, 12010 .has_decls_len = args.decls_len != 0, 12011 .name_strategy = gz.anon_name_strategy, 12012 .nonexhaustive = args.nonexhaustive, 12013 }), 12014 .operand = payload_index, 12015 } }, 12016 }); 12017 } 12018 12019 fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 12020 src_node: Ast.Node.Index, 12021 decls_len: u32, 12022 }) !void { 12023 const astgen = gz.astgen; 12024 const gpa = astgen.gpa; 12025 12026 try astgen.extra.ensureUnusedCapacity(gpa, 2); 12027 const payload_index = @intCast(u32, astgen.extra.items.len); 12028 12029 if (args.src_node != 0) { 12030 const node_offset = gz.nodeIndexToRelative(args.src_node); 12031 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 12032 } 12033 if (args.decls_len != 0) { 12034 astgen.extra.appendAssumeCapacity(args.decls_len); 12035 } 12036 astgen.instructions.set(inst, .{ 12037 .tag = .extended, 12038 .data = .{ .extended = .{ 12039 .opcode = .opaque_decl, 12040 .small = @bitCast(u16, Zir.Inst.OpaqueDecl.Small{ 12041 .has_src_node = args.src_node != 0, 12042 .has_decls_len = args.decls_len != 0, 12043 .name_strategy = gz.anon_name_strategy, 12044 }), 12045 .operand = payload_index, 12046 } }, 12047 }); 12048 } 12049 12050 fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref { 12051 return indexToRef(try gz.addAsIndex(inst)); 12052 } 12053 12054 fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index { 12055 const gpa = gz.astgen.gpa; 12056 try gz.instructions.ensureUnusedCapacity(gpa, 1); 12057 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 12058 12059 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 12060 gz.astgen.instructions.appendAssumeCapacity(inst); 12061 gz.instructions.appendAssumeCapacity(new_index); 12062 return new_index; 12063 } 12064 12065 fn reserveInstructionIndex(gz: *GenZir) !Zir.Inst.Index { 12066 const gpa = gz.astgen.gpa; 12067 try gz.instructions.ensureUnusedCapacity(gpa, 1); 12068 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 12069 12070 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 12071 gz.astgen.instructions.len += 1; 12072 gz.instructions.appendAssumeCapacity(new_index); 12073 return new_index; 12074 } 12075 12076 fn addRet(gz: *GenZir, ri: ResultInfo, operand: Zir.Inst.Ref, node: Ast.Node.Index) !void { 12077 switch (ri.rl) { 12078 .ptr => |ptr_res| _ = try gz.addUnNode(.ret_load, ptr_res.inst, node), 12079 .ty => _ = try gz.addUnNode(.ret_node, operand, node), 12080 else => unreachable, 12081 } 12082 } 12083 12084 fn addNamespaceCaptures(gz: *GenZir, namespace: *Scope.Namespace) !void { 12085 if (namespace.captures.count() > 0) { 12086 try gz.instructions.ensureUnusedCapacity(gz.astgen.gpa, namespace.captures.count()); 12087 for (namespace.captures.values()) |capture| { 12088 gz.instructions.appendAssumeCapacity(capture); 12089 } 12090 } 12091 } 12092 12093 fn addDbgVar(gz: *GenZir, tag: Zir.Inst.Tag, name: u32, inst: Zir.Inst.Ref) !void { 12094 if (gz.force_comptime) return; 12095 12096 _ = try gz.add(.{ .tag = tag, .data = .{ 12097 .str_op = .{ 12098 .str = name, 12099 .operand = inst, 12100 }, 12101 } }); 12102 } 12103 12104 fn addDbgBlockBegin(gz: *GenZir) !void { 12105 if (gz.force_comptime) return; 12106 12107 _ = try gz.add(.{ .tag = .dbg_block_begin, .data = undefined }); 12108 } 12109 12110 fn addDbgBlockEnd(gz: *GenZir) !void { 12111 if (gz.force_comptime) return; 12112 const gpa = gz.astgen.gpa; 12113 12114 const tags = gz.astgen.instructions.items(.tag); 12115 const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; 12116 // remove dbg_block_begin immediately followed by dbg_block_end 12117 if (tags[last_inst] == .dbg_block_begin) { 12118 _ = gz.instructions.pop(); 12119 return; 12120 } 12121 12122 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 12123 try gz.astgen.instructions.append(gpa, .{ .tag = .dbg_block_end, .data = undefined }); 12124 try gz.instructions.insert(gpa, gz.instructions.items.len - 1, new_index); 12125 } 12126 }; 12127 12128 /// This can only be for short-lived references; the memory becomes invalidated 12129 /// when another string is added. 12130 fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 { 12131 return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index; 12132 } 12133 12134 /// Local variables shadowing detection, including function parameters. 12135 fn detectLocalShadowing( 12136 astgen: *AstGen, 12137 scope: *Scope, 12138 ident_name: u32, 12139 name_token: Ast.TokenIndex, 12140 token_bytes: []const u8, 12141 id_cat: Scope.IdCat, 12142 ) !void { 12143 const gpa = astgen.gpa; 12144 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 12145 return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 12146 token_bytes, 12147 }, &[_]u32{ 12148 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 12149 token_bytes, 12150 }), 12151 }); 12152 } 12153 12154 var s = scope; 12155 var outer_scope = false; 12156 while (true) switch (s.tag) { 12157 .local_val => { 12158 const local_val = s.cast(Scope.LocalVal).?; 12159 if (local_val.name == ident_name) { 12160 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 12161 const name = try gpa.dupe(u8, name_slice); 12162 defer gpa.free(name); 12163 if (outer_scope) { 12164 return astgen.failTokNotes(name_token, "{s} '{s}' shadows {s} from outer scope", .{ 12165 @tagName(id_cat), name, @tagName(local_val.id_cat), 12166 }, &[_]u32{ 12167 try astgen.errNoteTok( 12168 local_val.token_src, 12169 "previous declaration here", 12170 .{}, 12171 ), 12172 }); 12173 } 12174 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 12175 @tagName(local_val.id_cat), name, 12176 }, &[_]u32{ 12177 try astgen.errNoteTok( 12178 local_val.token_src, 12179 "previous declaration here", 12180 .{}, 12181 ), 12182 }); 12183 } 12184 s = local_val.parent; 12185 }, 12186 .local_ptr => { 12187 const local_ptr = s.cast(Scope.LocalPtr).?; 12188 if (local_ptr.name == ident_name) { 12189 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 12190 const name = try gpa.dupe(u8, name_slice); 12191 defer gpa.free(name); 12192 if (outer_scope) { 12193 return astgen.failTokNotes(name_token, "{s} '{s}' shadows {s} from outer scope", .{ 12194 @tagName(id_cat), name, @tagName(local_ptr.id_cat), 12195 }, &[_]u32{ 12196 try astgen.errNoteTok( 12197 local_ptr.token_src, 12198 "previous declaration here", 12199 .{}, 12200 ), 12201 }); 12202 } 12203 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 12204 @tagName(local_ptr.id_cat), name, 12205 }, &[_]u32{ 12206 try astgen.errNoteTok( 12207 local_ptr.token_src, 12208 "previous declaration here", 12209 .{}, 12210 ), 12211 }); 12212 } 12213 s = local_ptr.parent; 12214 }, 12215 .namespace => { 12216 outer_scope = true; 12217 const ns = s.cast(Scope.Namespace).?; 12218 const decl_node = ns.decls.get(ident_name) orelse { 12219 s = ns.parent; 12220 continue; 12221 }; 12222 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 12223 const name = try gpa.dupe(u8, name_slice); 12224 defer gpa.free(name); 12225 return astgen.failTokNotes(name_token, "{s} shadows declaration of '{s}'", .{ 12226 @tagName(id_cat), name, 12227 }, &[_]u32{ 12228 try astgen.errNoteNode(decl_node, "declared here", .{}), 12229 }); 12230 }, 12231 .gen_zir => { 12232 s = s.cast(GenZir).?.parent; 12233 outer_scope = true; 12234 }, 12235 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 12236 .top => break, 12237 }; 12238 } 12239 12240 /// Advances the source cursor to the main token of `node` if not in comptime scope. 12241 /// Usually paired with `emitDbgStmt`. 12242 fn maybeAdvanceSourceCursorToMainToken(gz: *GenZir, node: Ast.Node.Index) void { 12243 if (gz.force_comptime) return; 12244 12245 const tree = gz.astgen.tree; 12246 const token_starts = tree.tokens.items(.start); 12247 const main_tokens = tree.nodes.items(.main_token); 12248 const node_start = token_starts[main_tokens[node]]; 12249 gz.astgen.advanceSourceCursor(node_start); 12250 } 12251 12252 /// Advances the source cursor to the beginning of `node`. 12253 fn advanceSourceCursorToNode(astgen: *AstGen, node: Ast.Node.Index) void { 12254 const tree = astgen.tree; 12255 const token_starts = tree.tokens.items(.start); 12256 const node_start = token_starts[tree.firstToken(node)]; 12257 astgen.advanceSourceCursor(node_start); 12258 } 12259 12260 /// Advances the source cursor to an absolute byte offset `end` in the file. 12261 fn advanceSourceCursor(astgen: *AstGen, end: usize) void { 12262 const source = astgen.tree.source; 12263 var i = astgen.source_offset; 12264 var line = astgen.source_line; 12265 var column = astgen.source_column; 12266 assert(i <= end); 12267 while (i < end) : (i += 1) { 12268 if (source[i] == '\n') { 12269 line += 1; 12270 column = 0; 12271 } else { 12272 column += 1; 12273 } 12274 } 12275 astgen.source_offset = i; 12276 astgen.source_line = line; 12277 astgen.source_column = column; 12278 } 12279 12280 fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !u32 { 12281 const gpa = astgen.gpa; 12282 const tree = astgen.tree; 12283 const node_tags = tree.nodes.items(.tag); 12284 const main_tokens = tree.nodes.items(.main_token); 12285 const token_tags = tree.tokens.items(.tag); 12286 var decl_count: u32 = 0; 12287 for (members) |member_node| { 12288 const name_token = switch (node_tags[member_node]) { 12289 .fn_proto_simple, 12290 .fn_proto_multi, 12291 .fn_proto_one, 12292 .fn_proto, 12293 .global_var_decl, 12294 .local_var_decl, 12295 .simple_var_decl, 12296 .aligned_var_decl, 12297 => blk: { 12298 decl_count += 1; 12299 break :blk main_tokens[member_node] + 1; 12300 }, 12301 12302 .fn_decl => blk: { 12303 decl_count += 1; 12304 const ident = main_tokens[member_node] + 1; 12305 if (token_tags[ident] != .identifier) { 12306 switch (astgen.failNode(member_node, "missing function name", .{})) { 12307 error.AnalysisFail => continue, 12308 error.OutOfMemory => return error.OutOfMemory, 12309 } 12310 } 12311 break :blk ident; 12312 }, 12313 12314 .@"comptime", .@"usingnamespace", .test_decl => { 12315 decl_count += 1; 12316 continue; 12317 }, 12318 12319 else => continue, 12320 }; 12321 12322 const token_bytes = astgen.tree.tokenSlice(name_token); 12323 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 12324 switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 12325 token_bytes, 12326 }, &[_]u32{ 12327 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 12328 token_bytes, 12329 }), 12330 })) { 12331 error.AnalysisFail => continue, 12332 error.OutOfMemory => return error.OutOfMemory, 12333 } 12334 } 12335 12336 const name_str_index = try astgen.identAsString(name_token); 12337 const gop = try namespace.decls.getOrPut(gpa, name_str_index); 12338 if (gop.found_existing) { 12339 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index))); 12340 defer gpa.free(name); 12341 switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{ 12342 name, 12343 }, &[_]u32{ 12344 try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}), 12345 })) { 12346 error.AnalysisFail => continue, 12347 error.OutOfMemory => return error.OutOfMemory, 12348 } 12349 } 12350 12351 var s = namespace.parent; 12352 while (true) switch (s.tag) { 12353 .local_val => { 12354 const local_val = s.cast(Scope.LocalVal).?; 12355 if (local_val.name == name_str_index) { 12356 return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ 12357 token_bytes, @tagName(local_val.id_cat), 12358 }, &[_]u32{ 12359 try astgen.errNoteTok( 12360 local_val.token_src, 12361 "previous declaration here", 12362 .{}, 12363 ), 12364 }); 12365 } 12366 s = local_val.parent; 12367 }, 12368 .local_ptr => { 12369 const local_ptr = s.cast(Scope.LocalPtr).?; 12370 if (local_ptr.name == name_str_index) { 12371 return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ 12372 token_bytes, @tagName(local_ptr.id_cat), 12373 }, &[_]u32{ 12374 try astgen.errNoteTok( 12375 local_ptr.token_src, 12376 "previous declaration here", 12377 .{}, 12378 ), 12379 }); 12380 } 12381 s = local_ptr.parent; 12382 }, 12383 .namespace => s = s.cast(Scope.Namespace).?.parent, 12384 .gen_zir => s = s.cast(GenZir).?.parent, 12385 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 12386 .top => break, 12387 }; 12388 gop.value_ptr.* = member_node; 12389 } 12390 return decl_count; 12391 } 12392 12393 fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool { 12394 const inst = refToIndex(ref) orelse return false; 12395 const zir_tags = astgen.instructions.items(.tag); 12396 return switch (zir_tags[inst]) { 12397 .alloc_inferred, 12398 .alloc_inferred_mut, 12399 .alloc_inferred_comptime, 12400 .alloc_inferred_comptime_mut, 12401 => true, 12402 12403 .extended => { 12404 const zir_data = astgen.instructions.items(.data); 12405 if (zir_data[inst].extended.opcode != .alloc) return false; 12406 const small = @bitCast(Zir.Inst.AllocExtended.Small, zir_data[inst].extended.small); 12407 return !small.has_type; 12408 }, 12409 12410 else => false, 12411 }; 12412 } 12413 12414 /// Assumes capacity for body has already been added. Needed capacity taking into 12415 /// account fixups can be found with `countBodyLenAfterFixups`. 12416 fn appendBodyWithFixups(astgen: *AstGen, body: []const Zir.Inst.Index) void { 12417 return appendBodyWithFixupsArrayList(astgen, &astgen.extra, body); 12418 } 12419 12420 fn appendBodyWithFixupsArrayList( 12421 astgen: *AstGen, 12422 list: *std.ArrayListUnmanaged(u32), 12423 body: []const Zir.Inst.Index, 12424 ) void { 12425 for (body) |body_inst| { 12426 appendPossiblyRefdBodyInst(astgen, list, body_inst); 12427 } 12428 } 12429 12430 fn appendPossiblyRefdBodyInst( 12431 astgen: *AstGen, 12432 list: *std.ArrayListUnmanaged(u32), 12433 body_inst: Zir.Inst.Index, 12434 ) void { 12435 list.appendAssumeCapacity(body_inst); 12436 const kv = astgen.ref_table.fetchRemove(body_inst) orelse return; 12437 const ref_inst = kv.value; 12438 return appendPossiblyRefdBodyInst(astgen, list, ref_inst); 12439 } 12440 12441 fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 { 12442 var count = body.len; 12443 for (body) |body_inst| { 12444 var check_inst = body_inst; 12445 while (astgen.ref_table.get(check_inst)) |ref_inst| { 12446 count += 1; 12447 check_inst = ref_inst; 12448 } 12449 } 12450 return @intCast(u32, count); 12451 } 12452 12453 fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void { 12454 if (gz.force_comptime) return; 12455 12456 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 12457 .dbg_stmt = .{ 12458 .line = line, 12459 .column = column, 12460 }, 12461 } }); 12462 }