blob b962f58b (402120B) - 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 11 const Zir = @import("Zir.zig"); 12 const trace = @import("tracy.zig").trace; 13 const BuiltinFn = @import("BuiltinFn.zig"); 14 15 gpa: *Allocator, 16 tree: *const ast.Tree, 17 instructions: std.MultiArrayList(Zir.Inst) = .{}, 18 extra: ArrayListUnmanaged(u32) = .{}, 19 string_bytes: ArrayListUnmanaged(u8) = .{}, 20 /// Tracks the current byte offset within the source file. 21 /// Used to populate line deltas in the ZIR. AstGen maintains 22 /// this "cursor" throughout the entire AST lowering process in order 23 /// to avoid starting over the line/column scan for every declaration, which 24 /// would be O(N^2). 25 source_offset: u32 = 0, 26 /// Tracks the current line of `source_offset`. 27 source_line: u32 = 0, 28 /// Tracks the current column of `source_offset`. 29 source_column: u32 = 0, 30 /// Used for temporary allocations; freed after AstGen is complete. 31 /// The resulting ZIR code has no references to anything in this arena. 32 arena: *Allocator, 33 string_table: std.StringHashMapUnmanaged(u32) = .{}, 34 compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, 35 /// The topmost block of the current function. 36 fn_block: ?*GenZir = null, 37 /// Maps string table indexes to the first `@import` ZIR instruction 38 /// that uses this string as the operand. 39 imports: std.AutoArrayHashMapUnmanaged(u32, ast.TokenIndex) = .{}, 40 41 const InnerError = error{ OutOfMemory, AnalysisFail }; 42 43 fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { 44 const fields = std.meta.fields(@TypeOf(extra)); 45 try astgen.extra.ensureUnusedCapacity(astgen.gpa, fields.len); 46 return addExtraAssumeCapacity(astgen, extra); 47 } 48 49 fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 { 50 const fields = std.meta.fields(@TypeOf(extra)); 51 const result = @intCast(u32, astgen.extra.items.len); 52 inline for (fields) |field| { 53 astgen.extra.appendAssumeCapacity(switch (field.field_type) { 54 u32 => @field(extra, field.name), 55 Zir.Inst.Ref => @enumToInt(@field(extra, field.name)), 56 i32 => @bitCast(u32, @field(extra, field.name)), 57 else => @compileError("bad field type"), 58 }); 59 } 60 return result; 61 } 62 63 fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void { 64 const coerced = @bitCast([]const u32, refs); 65 return astgen.extra.appendSlice(astgen.gpa, coerced); 66 } 67 68 fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { 69 const coerced = @bitCast([]const u32, refs); 70 astgen.extra.appendSliceAssumeCapacity(coerced); 71 } 72 73 pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir { 74 var arena = std.heap.ArenaAllocator.init(gpa); 75 defer arena.deinit(); 76 77 var astgen: AstGen = .{ 78 .gpa = gpa, 79 .arena = &arena.allocator, 80 .tree = &tree, 81 }; 82 defer astgen.deinit(gpa); 83 84 // String table indexes 0 and 1 are reserved for special meaning. 85 try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0 }); 86 87 // We expect at least as many ZIR instructions and extra data items 88 // as AST nodes. 89 try astgen.instructions.ensureTotalCapacity(gpa, tree.nodes.len); 90 91 // First few indexes of extra are reserved and set at the end. 92 const reserved_count = @typeInfo(Zir.ExtraIndex).Enum.fields.len; 93 try astgen.extra.ensureTotalCapacity(gpa, tree.nodes.len + reserved_count); 94 astgen.extra.items.len += reserved_count; 95 96 var top_scope: Scope.Top = .{}; 97 98 var gen_scope: GenZir = .{ 99 .force_comptime = true, 100 .in_defer = false, 101 .parent = &top_scope.base, 102 .anon_name_strategy = .parent, 103 .decl_node_index = 0, 104 .decl_line = 0, 105 .astgen = &astgen, 106 }; 107 defer gen_scope.instructions.deinit(gpa); 108 109 const container_decl: ast.full.ContainerDecl = .{ 110 .layout_token = null, 111 .ast = .{ 112 .main_token = undefined, 113 .enum_token = null, 114 .members = tree.rootDecls(), 115 .arg = 0, 116 }, 117 }; 118 if (AstGen.structDeclInner( 119 &gen_scope, 120 &gen_scope.base, 121 0, 122 container_decl, 123 .Auto, 124 )) |struct_decl_ref| { 125 astgen.extra.items[@enumToInt(Zir.ExtraIndex.main_struct)] = @enumToInt(struct_decl_ref); 126 } else |err| switch (err) { 127 error.OutOfMemory => return error.OutOfMemory, 128 error.AnalysisFail => {}, // Handled via compile_errors below. 129 } 130 131 const err_index = @enumToInt(Zir.ExtraIndex.compile_errors); 132 if (astgen.compile_errors.items.len == 0) { 133 astgen.extra.items[err_index] = 0; 134 } else { 135 try astgen.extra.ensureUnusedCapacity(gpa, 1 + astgen.compile_errors.items.len * 136 @typeInfo(Zir.Inst.CompileErrors.Item).Struct.fields.len); 137 138 astgen.extra.items[err_index] = astgen.addExtraAssumeCapacity(Zir.Inst.CompileErrors{ 139 .items_len = @intCast(u32, astgen.compile_errors.items.len), 140 }); 141 142 for (astgen.compile_errors.items) |item| { 143 _ = astgen.addExtraAssumeCapacity(item); 144 } 145 } 146 147 const imports_index = @enumToInt(Zir.ExtraIndex.imports); 148 if (astgen.imports.count() == 0) { 149 astgen.extra.items[imports_index] = 0; 150 } else { 151 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Imports).Struct.fields.len + 152 astgen.imports.count() * @typeInfo(Zir.Inst.Imports.Item).Struct.fields.len); 153 154 astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{ 155 .imports_len = @intCast(u32, astgen.imports.count()), 156 }); 157 158 var it = astgen.imports.iterator(); 159 while (it.next()) |entry| { 160 _ = astgen.addExtraAssumeCapacity(Zir.Inst.Imports.Item{ 161 .name = entry.key_ptr.*, 162 .token = entry.value_ptr.*, 163 }); 164 } 165 } 166 167 return Zir{ 168 .instructions = astgen.instructions.toOwnedSlice(), 169 .string_bytes = astgen.string_bytes.toOwnedSlice(gpa), 170 .extra = astgen.extra.toOwnedSlice(gpa), 171 }; 172 } 173 174 pub fn deinit(astgen: *AstGen, gpa: *Allocator) void { 175 astgen.instructions.deinit(gpa); 176 astgen.extra.deinit(gpa); 177 astgen.string_table.deinit(gpa); 178 astgen.string_bytes.deinit(gpa); 179 astgen.compile_errors.deinit(gpa); 180 astgen.imports.deinit(gpa); 181 } 182 183 pub const ResultLoc = union(enum) { 184 /// The expression is the right-hand side of assignment to `_`. Only the side-effects of the 185 /// expression should be generated. The result instruction from the expression must 186 /// be ignored. 187 discard, 188 /// The expression has an inferred type, and it will be evaluated as an rvalue. 189 none, 190 /// The expression must generate a pointer rather than a value. For example, the left hand side 191 /// of an assignment uses this kind of result location. 192 ref, 193 /// The callee will accept a ref, but it is not necessary, and the `ResultLoc` 194 /// may be treated as `none` instead. 195 none_or_ref, 196 /// The expression will be coerced into this type, but it will be evaluated as an rvalue. 197 ty: Zir.Inst.Ref, 198 /// Same as `ty` but it is guaranteed that Sema will additionall perform the coercion, 199 /// so no `as` instruction needs to be emitted. 200 coerced_ty: Zir.Inst.Ref, 201 /// The expression must store its result into this typed pointer. The result instruction 202 /// from the expression must be ignored. 203 ptr: Zir.Inst.Ref, 204 /// The expression must store its result into this allocation, which has an inferred type. 205 /// The result instruction from the expression must be ignored. 206 /// Always an instruction with tag `alloc_inferred`. 207 inferred_ptr: Zir.Inst.Ref, 208 /// There is a pointer for the expression to store its result into, however, its type 209 /// is inferred based on peer type resolution for a `Zir.Inst.Block`. 210 /// The result instruction from the expression must be ignored. 211 block_ptr: *GenZir, 212 213 pub const Strategy = struct { 214 elide_store_to_block_ptr_instructions: bool, 215 tag: Tag, 216 217 pub const Tag = enum { 218 /// Both branches will use break_void; result location is used to communicate the 219 /// result instruction. 220 break_void, 221 /// Use break statements to pass the block result value, and call rvalue() at 222 /// the end depending on rl. Also elide the store_to_block_ptr instructions 223 /// depending on rl. 224 break_operand, 225 }; 226 }; 227 228 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { 229 switch (rl) { 230 // In this branch there will not be any store_to_block_ptr instructions. 231 .discard, .none, .none_or_ref, .ty, .coerced_ty, .ref => return .{ 232 .tag = .break_operand, 233 .elide_store_to_block_ptr_instructions = false, 234 }, 235 // The pointer got passed through to the sub-expressions, so we will use 236 // break_void here. 237 // In this branch there will not be any store_to_block_ptr instructions. 238 .ptr => return .{ 239 .tag = .break_void, 240 .elide_store_to_block_ptr_instructions = false, 241 }, 242 .inferred_ptr, .block_ptr => { 243 if (block_scope.rvalue_rl_count == block_scope.break_count) { 244 // Neither prong of the if consumed the result location, so we can 245 // use break instructions to create an rvalue. 246 return .{ 247 .tag = .break_operand, 248 .elide_store_to_block_ptr_instructions = true, 249 }; 250 } else { 251 // Allow the store_to_block_ptr instructions to remain so that 252 // semantic analysis can turn them into bitcasts. 253 return .{ 254 .tag = .break_void, 255 .elide_store_to_block_ptr_instructions = false, 256 }; 257 } 258 }, 259 } 260 } 261 }; 262 263 pub const align_rl: ResultLoc = .{ .ty = .u16_type }; 264 pub const bool_rl: ResultLoc = .{ .ty = .bool_type }; 265 pub const type_rl: ResultLoc = .{ .ty = .type_type }; 266 pub const coerced_type_rl: ResultLoc = .{ .coerced_ty = .type_type }; 267 268 fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref { 269 const prev_force_comptime = gz.force_comptime; 270 gz.force_comptime = true; 271 defer gz.force_comptime = prev_force_comptime; 272 273 return expr(gz, scope, coerced_type_rl, type_node); 274 } 275 276 /// Same as `expr` but fails with a compile error if the result type is `noreturn`. 277 fn reachableExpr( 278 gz: *GenZir, 279 scope: *Scope, 280 rl: ResultLoc, 281 node: ast.Node.Index, 282 src_node: ast.Node.Index, 283 ) InnerError!Zir.Inst.Ref { 284 const result_inst = try expr(gz, scope, rl, node); 285 if (gz.refIsNoReturn(result_inst)) { 286 return gz.astgen.failNodeNotes(src_node, "unreachable code", .{}, &[_]u32{ 287 try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}), 288 }); 289 } 290 return result_inst; 291 } 292 293 fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 294 const astgen = gz.astgen; 295 const tree = astgen.tree; 296 const node_tags = tree.nodes.items(.tag); 297 const main_tokens = tree.nodes.items(.main_token); 298 switch (node_tags[node]) { 299 .root => unreachable, 300 .@"usingnamespace" => unreachable, 301 .test_decl => unreachable, 302 .global_var_decl => unreachable, 303 .local_var_decl => unreachable, 304 .simple_var_decl => unreachable, 305 .aligned_var_decl => unreachable, 306 .switch_case => unreachable, 307 .switch_case_one => unreachable, 308 .container_field_init => unreachable, 309 .container_field_align => unreachable, 310 .container_field => unreachable, 311 .asm_output => unreachable, 312 .asm_input => unreachable, 313 314 .assign, 315 .assign_bit_and, 316 .assign_bit_or, 317 .assign_bit_shift_left, 318 .assign_bit_shift_right, 319 .assign_bit_xor, 320 .assign_div, 321 .assign_sub, 322 .assign_sub_wrap, 323 .assign_mod, 324 .assign_add, 325 .assign_add_wrap, 326 .assign_mul, 327 .assign_mul_wrap, 328 .add, 329 .add_wrap, 330 .sub, 331 .sub_wrap, 332 .mul, 333 .mul_wrap, 334 .div, 335 .mod, 336 .bit_and, 337 .bit_or, 338 .bit_shift_left, 339 .bit_shift_right, 340 .bit_xor, 341 .bang_equal, 342 .equal_equal, 343 .greater_than, 344 .greater_or_equal, 345 .less_than, 346 .less_or_equal, 347 .array_cat, 348 .array_mult, 349 .bool_and, 350 .bool_or, 351 .@"asm", 352 .asm_simple, 353 .string_literal, 354 .integer_literal, 355 .call, 356 .call_comma, 357 .async_call, 358 .async_call_comma, 359 .call_one, 360 .call_one_comma, 361 .async_call_one, 362 .async_call_one_comma, 363 .unreachable_literal, 364 .@"return", 365 .@"if", 366 .if_simple, 367 .@"while", 368 .while_simple, 369 .while_cont, 370 .bool_not, 371 .address_of, 372 .float_literal, 373 .optional_type, 374 .block, 375 .block_semicolon, 376 .block_two, 377 .block_two_semicolon, 378 .@"break", 379 .ptr_type_aligned, 380 .ptr_type_sentinel, 381 .ptr_type, 382 .ptr_type_bit_range, 383 .array_type, 384 .array_type_sentinel, 385 .enum_literal, 386 .multiline_string_literal, 387 .char_literal, 388 .@"defer", 389 .@"errdefer", 390 .@"catch", 391 .error_union, 392 .merge_error_sets, 393 .switch_range, 394 .@"await", 395 .bit_not, 396 .negation, 397 .negation_wrap, 398 .@"resume", 399 .@"try", 400 .slice, 401 .slice_open, 402 .slice_sentinel, 403 .array_init_one, 404 .array_init_one_comma, 405 .array_init_dot_two, 406 .array_init_dot_two_comma, 407 .array_init_dot, 408 .array_init_dot_comma, 409 .array_init, 410 .array_init_comma, 411 .struct_init_one, 412 .struct_init_one_comma, 413 .struct_init_dot_two, 414 .struct_init_dot_two_comma, 415 .struct_init_dot, 416 .struct_init_dot_comma, 417 .struct_init, 418 .struct_init_comma, 419 .@"switch", 420 .switch_comma, 421 .@"for", 422 .for_simple, 423 .@"suspend", 424 .@"continue", 425 .@"anytype", 426 .fn_proto_simple, 427 .fn_proto_multi, 428 .fn_proto_one, 429 .fn_proto, 430 .fn_decl, 431 .anyframe_type, 432 .anyframe_literal, 433 .error_set_decl, 434 .container_decl, 435 .container_decl_trailing, 436 .container_decl_two, 437 .container_decl_two_trailing, 438 .container_decl_arg, 439 .container_decl_arg_trailing, 440 .tagged_union, 441 .tagged_union_trailing, 442 .tagged_union_two, 443 .tagged_union_two_trailing, 444 .tagged_union_enum_tag, 445 .tagged_union_enum_tag_trailing, 446 .@"comptime", 447 .@"nosuspend", 448 .error_value, 449 => return astgen.failNode(node, "invalid left-hand side to assignment", .{}), 450 451 .builtin_call, 452 .builtin_call_comma, 453 .builtin_call_two, 454 .builtin_call_two_comma, 455 => { 456 const builtin_token = main_tokens[node]; 457 const builtin_name = tree.tokenSlice(builtin_token); 458 // If the builtin is an invalid name, we don't cause an error here; instead 459 // let it pass, and the error will be "invalid builtin function" later. 460 if (BuiltinFn.list.get(builtin_name)) |info| { 461 if (!info.allows_lvalue) { 462 return astgen.failNode(node, "invalid left-hand side to assignment", .{}); 463 } 464 } 465 }, 466 467 // These can be assigned to. 468 .unwrap_optional, 469 .deref, 470 .field_access, 471 .array_access, 472 .identifier, 473 .grouped_expression, 474 .@"orelse", 475 => {}, 476 } 477 return expr(gz, scope, .ref, node); 478 } 479 480 /// Turn Zig AST into untyped ZIR istructions. 481 /// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the 482 /// result instruction can be used to inspect whether it is isNoReturn() but that is it, 483 /// it must otherwise not be used. 484 fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 485 const astgen = gz.astgen; 486 const tree = astgen.tree; 487 const main_tokens = tree.nodes.items(.main_token); 488 const token_tags = tree.tokens.items(.tag); 489 const node_datas = tree.nodes.items(.data); 490 const node_tags = tree.nodes.items(.tag); 491 492 switch (node_tags[node]) { 493 .root => unreachable, // Top-level declaration. 494 .@"usingnamespace" => unreachable, // Top-level declaration. 495 .test_decl => unreachable, // Top-level declaration. 496 .container_field_init => unreachable, // Top-level declaration. 497 .container_field_align => unreachable, // Top-level declaration. 498 .container_field => unreachable, // Top-level declaration. 499 .fn_decl => unreachable, // Top-level declaration. 500 501 .global_var_decl => unreachable, // Handled in `blockExpr`. 502 .local_var_decl => unreachable, // Handled in `blockExpr`. 503 .simple_var_decl => unreachable, // Handled in `blockExpr`. 504 .aligned_var_decl => unreachable, // Handled in `blockExpr`. 505 .@"defer" => unreachable, // Handled in `blockExpr`. 506 .@"errdefer" => unreachable, // Handled in `blockExpr`. 507 508 .switch_case => unreachable, // Handled in `switchExpr`. 509 .switch_case_one => unreachable, // Handled in `switchExpr`. 510 .switch_range => unreachable, // Handled in `switchExpr`. 511 512 .asm_output => unreachable, // Handled in `asmExpr`. 513 .asm_input => unreachable, // Handled in `asmExpr`. 514 515 .@"anytype" => unreachable, // Handled in `containerDecl`. 516 517 .assign => { 518 try assign(gz, scope, node); 519 return rvalue(gz, rl, .void_value, node); 520 }, 521 522 .assign_bit_shift_left => { 523 try assignShift(gz, scope, node, .shl); 524 return rvalue(gz, rl, .void_value, node); 525 }, 526 .assign_bit_shift_right => { 527 try assignShift(gz, scope, node, .shr); 528 return rvalue(gz, rl, .void_value, node); 529 }, 530 531 .assign_bit_and => { 532 try assignOp(gz, scope, node, .bit_and); 533 return rvalue(gz, rl, .void_value, node); 534 }, 535 .assign_bit_or => { 536 try assignOp(gz, scope, node, .bit_or); 537 return rvalue(gz, rl, .void_value, node); 538 }, 539 .assign_bit_xor => { 540 try assignOp(gz, scope, node, .xor); 541 return rvalue(gz, rl, .void_value, node); 542 }, 543 .assign_div => { 544 try assignOp(gz, scope, node, .div); 545 return rvalue(gz, rl, .void_value, node); 546 }, 547 .assign_sub => { 548 try assignOp(gz, scope, node, .sub); 549 return rvalue(gz, rl, .void_value, node); 550 }, 551 .assign_sub_wrap => { 552 try assignOp(gz, scope, node, .subwrap); 553 return rvalue(gz, rl, .void_value, node); 554 }, 555 .assign_mod => { 556 try assignOp(gz, scope, node, .mod_rem); 557 return rvalue(gz, rl, .void_value, node); 558 }, 559 .assign_add => { 560 try assignOp(gz, scope, node, .add); 561 return rvalue(gz, rl, .void_value, node); 562 }, 563 .assign_add_wrap => { 564 try assignOp(gz, scope, node, .addwrap); 565 return rvalue(gz, rl, .void_value, node); 566 }, 567 .assign_mul => { 568 try assignOp(gz, scope, node, .mul); 569 return rvalue(gz, rl, .void_value, node); 570 }, 571 .assign_mul_wrap => { 572 try assignOp(gz, scope, node, .mulwrap); 573 return rvalue(gz, rl, .void_value, node); 574 }, 575 576 // zig fmt: off 577 .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl), 578 .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr), 579 580 .add => return simpleBinOp(gz, scope, rl, node, .add), 581 .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap), 582 .sub => return simpleBinOp(gz, scope, rl, node, .sub), 583 .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap), 584 .mul => return simpleBinOp(gz, scope, rl, node, .mul), 585 .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap), 586 .div => return simpleBinOp(gz, scope, rl, node, .div), 587 .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), 588 .bit_and => { 589 const current_ampersand_token = main_tokens[node]; 590 if (token_tags[current_ampersand_token + 1] == .ampersand) { 591 const token_starts = tree.tokens.items(.start); 592 const current_token_offset = token_starts[current_ampersand_token]; 593 const next_token_offset = token_starts[current_ampersand_token + 1]; 594 if (current_token_offset + 1 == next_token_offset) { 595 return astgen.failTok( 596 current_ampersand_token, 597 "`&&` is invalid; note that `and` is boolean AND", 598 .{}, 599 ); 600 } 601 } 602 603 return simpleBinOp(gz, scope, rl, node, .bit_and); 604 }, 605 .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), 606 .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), 607 608 .bang_equal => return simpleBinOp(gz, scope, rl, node, .cmp_neq), 609 .equal_equal => return simpleBinOp(gz, scope, rl, node, .cmp_eq), 610 .greater_than => return simpleBinOp(gz, scope, rl, node, .cmp_gt), 611 .greater_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_gte), 612 .less_than => return simpleBinOp(gz, scope, rl, node, .cmp_lt), 613 .less_or_equal => return simpleBinOp(gz, scope, rl, node, .cmp_lte), 614 615 .array_cat => return simpleBinOp(gz, scope, rl, node, .array_cat), 616 .array_mult => return simpleBinOp(gz, scope, rl, node, .array_mul), 617 618 .error_union => return simpleBinOp(gz, scope, rl, node, .error_union_type), 619 .merge_error_sets => return simpleBinOp(gz, scope, rl, node, .merge_error_sets), 620 621 .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and), 622 .bool_or => return boolBinOp(gz, scope, rl, node, .bool_br_or), 623 624 .bool_not => return boolNot(gz, scope, rl, node), 625 .bit_not => return bitNot(gz, scope, rl, node), 626 627 .negation => return negation(gz, scope, rl, node, .negate), 628 .negation_wrap => return negation(gz, scope, rl, node, .negate_wrap), 629 630 .identifier => return identifier(gz, scope, rl, node), 631 632 .asm_simple => return asmExpr(gz, scope, rl, node, tree.asmSimple(node)), 633 .@"asm" => return asmExpr(gz, scope, rl, node, tree.asmFull(node)), 634 635 .string_literal => return stringLiteral(gz, rl, node), 636 .multiline_string_literal => return multilineStringLiteral(gz, rl, node), 637 638 .integer_literal => return integerLiteral(gz, rl, node), 639 // zig fmt: on 640 641 .builtin_call_two, .builtin_call_two_comma => { 642 if (node_datas[node].lhs == 0) { 643 const params = [_]ast.Node.Index{}; 644 return builtinCall(gz, scope, rl, node, ¶ms); 645 } else if (node_datas[node].rhs == 0) { 646 const params = [_]ast.Node.Index{node_datas[node].lhs}; 647 return builtinCall(gz, scope, rl, node, ¶ms); 648 } else { 649 const params = [_]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; 650 return builtinCall(gz, scope, rl, node, ¶ms); 651 } 652 }, 653 .builtin_call, .builtin_call_comma => { 654 const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 655 return builtinCall(gz, scope, rl, node, params); 656 }, 657 658 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => { 659 var params: [1]ast.Node.Index = undefined; 660 return callExpr(gz, scope, rl, node, tree.callOne(¶ms, node)); 661 }, 662 .call, .call_comma, .async_call, .async_call_comma => { 663 return callExpr(gz, scope, rl, node, tree.callFull(node)); 664 }, 665 666 .unreachable_literal => { 667 _ = try gz.addAsIndex(.{ 668 .tag = .@"unreachable", 669 .data = .{ .@"unreachable" = .{ 670 .safety = true, 671 .src_node = gz.nodeIndexToRelative(node), 672 } }, 673 }); 674 return Zir.Inst.Ref.unreachable_value; 675 }, 676 .@"return" => return ret(gz, scope, node), 677 .field_access => return fieldAccess(gz, scope, rl, node), 678 .float_literal => return floatLiteral(gz, rl, node), 679 680 .if_simple => return ifExpr(gz, scope, rl, node, tree.ifSimple(node)), 681 .@"if" => return ifExpr(gz, scope, rl, node, tree.ifFull(node)), 682 683 .while_simple => return whileExpr(gz, scope, rl, node, tree.whileSimple(node)), 684 .while_cont => return whileExpr(gz, scope, rl, node, tree.whileCont(node)), 685 .@"while" => return whileExpr(gz, scope, rl, node, tree.whileFull(node)), 686 687 .for_simple => return forExpr(gz, scope, rl, node, tree.forSimple(node)), 688 .@"for" => return forExpr(gz, scope, rl, node, tree.forFull(node)), 689 690 .slice_open => { 691 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); 692 const start = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs); 693 const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{ 694 .lhs = lhs, 695 .start = start, 696 }); 697 switch (rl) { 698 .ref, .none_or_ref => return result, 699 else => { 700 const dereffed = try gz.addUnNode(.load, result, node); 701 return rvalue(gz, rl, dereffed, node); 702 }, 703 } 704 }, 705 .slice => { 706 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); 707 const extra = tree.extraData(node_datas[node].rhs, ast.Node.Slice); 708 const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); 709 const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end); 710 const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{ 711 .lhs = lhs, 712 .start = start, 713 .end = end, 714 }); 715 switch (rl) { 716 .ref, .none_or_ref => return result, 717 else => { 718 const dereffed = try gz.addUnNode(.load, result, node); 719 return rvalue(gz, rl, dereffed, node); 720 }, 721 } 722 }, 723 .slice_sentinel => { 724 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); 725 const extra = tree.extraData(node_datas[node].rhs, ast.Node.SliceSentinel); 726 const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); 727 const end = if (extra.end != 0) try expr(gz, scope, .{ .ty = .usize_type }, extra.end) else .none; 728 const sentinel = try expr(gz, scope, .{ .ty = .usize_type }, extra.sentinel); 729 const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{ 730 .lhs = lhs, 731 .start = start, 732 .end = end, 733 .sentinel = sentinel, 734 }); 735 switch (rl) { 736 .ref, .none_or_ref => return result, 737 else => { 738 const dereffed = try gz.addUnNode(.load, result, node); 739 return rvalue(gz, rl, dereffed, node); 740 }, 741 } 742 }, 743 744 .deref => { 745 const lhs = try expr(gz, scope, .none, node_datas[node].lhs); 746 switch (rl) { 747 .ref, .none_or_ref => return lhs, 748 else => { 749 const result = try gz.addUnNode(.load, lhs, node); 750 return rvalue(gz, rl, result, node); 751 }, 752 } 753 }, 754 .address_of => { 755 const result = try expr(gz, scope, .ref, node_datas[node].lhs); 756 return rvalue(gz, rl, result, node); 757 }, 758 .optional_type => { 759 const operand = try typeExpr(gz, scope, node_datas[node].lhs); 760 const result = try gz.addUnNode(.optional_type, operand, node); 761 return rvalue(gz, rl, result, node); 762 }, 763 .unwrap_optional => switch (rl) { 764 .ref => return gz.addUnNode( 765 .optional_payload_safe_ptr, 766 try expr(gz, scope, .ref, node_datas[node].lhs), 767 node, 768 ), 769 else => return rvalue(gz, rl, try gz.addUnNode( 770 .optional_payload_safe, 771 try expr(gz, scope, .none, node_datas[node].lhs), 772 node, 773 ), node), 774 }, 775 .block_two, .block_two_semicolon => { 776 const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; 777 if (node_datas[node].lhs == 0) { 778 return blockExpr(gz, scope, rl, node, statements[0..0]); 779 } else if (node_datas[node].rhs == 0) { 780 return blockExpr(gz, scope, rl, node, statements[0..1]); 781 } else { 782 return blockExpr(gz, scope, rl, node, statements[0..2]); 783 } 784 }, 785 .block, .block_semicolon => { 786 const statements = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs]; 787 return blockExpr(gz, scope, rl, node, statements); 788 }, 789 .enum_literal => return simpleStrTok(gz, rl, main_tokens[node], node, .enum_literal), 790 .error_value => return simpleStrTok(gz, rl, node_datas[node].rhs, node, .error_value), 791 .anyframe_literal => return rvalue(gz, rl, .anyframe_type, node), 792 .anyframe_type => { 793 const return_type = try typeExpr(gz, scope, node_datas[node].rhs); 794 const result = try gz.addUnNode(.anyframe_type, return_type, node); 795 return rvalue(gz, rl, result, node); 796 }, 797 .@"catch" => { 798 const catch_token = main_tokens[node]; 799 const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) 800 catch_token + 2 801 else 802 null; 803 switch (rl) { 804 .ref => return orelseCatchExpr( 805 gz, 806 scope, 807 rl, 808 node, 809 node_datas[node].lhs, 810 .is_non_err_ptr, 811 .err_union_payload_unsafe_ptr, 812 .err_union_code_ptr, 813 node_datas[node].rhs, 814 payload_token, 815 ), 816 else => return orelseCatchExpr( 817 gz, 818 scope, 819 rl, 820 node, 821 node_datas[node].lhs, 822 .is_non_err, 823 .err_union_payload_unsafe, 824 .err_union_code, 825 node_datas[node].rhs, 826 payload_token, 827 ), 828 } 829 }, 830 .@"orelse" => switch (rl) { 831 .ref => return orelseCatchExpr( 832 gz, 833 scope, 834 rl, 835 node, 836 node_datas[node].lhs, 837 .is_non_null_ptr, 838 .optional_payload_unsafe_ptr, 839 undefined, 840 node_datas[node].rhs, 841 null, 842 ), 843 else => return orelseCatchExpr( 844 gz, 845 scope, 846 rl, 847 node, 848 node_datas[node].lhs, 849 .is_non_null, 850 .optional_payload_unsafe, 851 undefined, 852 node_datas[node].rhs, 853 null, 854 ), 855 }, 856 857 .ptr_type_aligned => return ptrType(gz, scope, rl, node, tree.ptrTypeAligned(node)), 858 .ptr_type_sentinel => return ptrType(gz, scope, rl, node, tree.ptrTypeSentinel(node)), 859 .ptr_type => return ptrType(gz, scope, rl, node, tree.ptrType(node)), 860 .ptr_type_bit_range => return ptrType(gz, scope, rl, node, tree.ptrTypeBitRange(node)), 861 862 .container_decl, 863 .container_decl_trailing, 864 => return containerDecl(gz, scope, rl, node, tree.containerDecl(node)), 865 .container_decl_two, .container_decl_two_trailing => { 866 var buffer: [2]ast.Node.Index = undefined; 867 return containerDecl(gz, scope, rl, node, tree.containerDeclTwo(&buffer, node)); 868 }, 869 .container_decl_arg, 870 .container_decl_arg_trailing, 871 => return containerDecl(gz, scope, rl, node, tree.containerDeclArg(node)), 872 873 .tagged_union, 874 .tagged_union_trailing, 875 => return containerDecl(gz, scope, rl, node, tree.taggedUnion(node)), 876 .tagged_union_two, .tagged_union_two_trailing => { 877 var buffer: [2]ast.Node.Index = undefined; 878 return containerDecl(gz, scope, rl, node, tree.taggedUnionTwo(&buffer, node)); 879 }, 880 .tagged_union_enum_tag, 881 .tagged_union_enum_tag_trailing, 882 => return containerDecl(gz, scope, rl, node, tree.taggedUnionEnumTag(node)), 883 884 .@"break" => return breakExpr(gz, scope, node), 885 .@"continue" => return continueExpr(gz, scope, node), 886 .grouped_expression => return expr(gz, scope, rl, node_datas[node].lhs), 887 .array_type => return arrayType(gz, scope, rl, node), 888 .array_type_sentinel => return arrayTypeSentinel(gz, scope, rl, node), 889 .char_literal => return charLiteral(gz, rl, node), 890 .error_set_decl => return errorSetDecl(gz, rl, node), 891 .array_access => return arrayAccess(gz, scope, rl, node), 892 .@"comptime" => return comptimeExprAst(gz, scope, rl, node), 893 .@"switch", .switch_comma => return switchExpr(gz, scope, rl, node), 894 895 .@"nosuspend" => return nosuspendExpr(gz, scope, rl, node), 896 .@"suspend" => return suspendExpr(gz, scope, node), 897 .@"await" => return awaitExpr(gz, scope, rl, node), 898 .@"resume" => return resumeExpr(gz, scope, rl, node), 899 900 .@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs), 901 902 .array_init_one, .array_init_one_comma => { 903 var elements: [1]ast.Node.Index = undefined; 904 return arrayInitExpr(gz, scope, rl, node, tree.arrayInitOne(&elements, node)); 905 }, 906 .array_init_dot_two, .array_init_dot_two_comma => { 907 var elements: [2]ast.Node.Index = undefined; 908 return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDotTwo(&elements, node)); 909 }, 910 .array_init_dot, 911 .array_init_dot_comma, 912 => return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDot(node)), 913 .array_init, 914 .array_init_comma, 915 => return arrayInitExpr(gz, scope, rl, node, tree.arrayInit(node)), 916 917 .struct_init_one, .struct_init_one_comma => { 918 var fields: [1]ast.Node.Index = undefined; 919 return structInitExpr(gz, scope, rl, node, tree.structInitOne(&fields, node)); 920 }, 921 .struct_init_dot_two, .struct_init_dot_two_comma => { 922 var fields: [2]ast.Node.Index = undefined; 923 return structInitExpr(gz, scope, rl, node, tree.structInitDotTwo(&fields, node)); 924 }, 925 .struct_init_dot, 926 .struct_init_dot_comma, 927 => return structInitExpr(gz, scope, rl, node, tree.structInitDot(node)), 928 .struct_init, 929 .struct_init_comma, 930 => return structInitExpr(gz, scope, rl, node, tree.structInit(node)), 931 932 .fn_proto_simple => { 933 var params: [1]ast.Node.Index = undefined; 934 return fnProtoExpr(gz, scope, rl, tree.fnProtoSimple(¶ms, node)); 935 }, 936 .fn_proto_multi => { 937 return fnProtoExpr(gz, scope, rl, tree.fnProtoMulti(node)); 938 }, 939 .fn_proto_one => { 940 var params: [1]ast.Node.Index = undefined; 941 return fnProtoExpr(gz, scope, rl, tree.fnProtoOne(¶ms, node)); 942 }, 943 .fn_proto => { 944 return fnProtoExpr(gz, scope, rl, tree.fnProto(node)); 945 }, 946 } 947 } 948 949 fn nosuspendExpr( 950 gz: *GenZir, 951 scope: *Scope, 952 rl: ResultLoc, 953 node: ast.Node.Index, 954 ) InnerError!Zir.Inst.Ref { 955 const astgen = gz.astgen; 956 const tree = astgen.tree; 957 const node_datas = tree.nodes.items(.data); 958 const body_node = node_datas[node].lhs; 959 assert(body_node != 0); 960 if (gz.nosuspend_node != 0) { 961 return astgen.failNodeNotes(node, "redundant nosuspend block", .{}, &[_]u32{ 962 try astgen.errNoteNode(gz.nosuspend_node, "other nosuspend block here", .{}), 963 }); 964 } 965 gz.nosuspend_node = node; 966 const result = try expr(gz, scope, rl, body_node); 967 gz.nosuspend_node = 0; 968 return rvalue(gz, rl, result, node); 969 } 970 971 fn suspendExpr( 972 gz: *GenZir, 973 scope: *Scope, 974 node: ast.Node.Index, 975 ) InnerError!Zir.Inst.Ref { 976 const astgen = gz.astgen; 977 const gpa = astgen.gpa; 978 const tree = astgen.tree; 979 const node_datas = tree.nodes.items(.data); 980 const body_node = node_datas[node].lhs; 981 982 if (gz.nosuspend_node != 0) { 983 return astgen.failNodeNotes(node, "suspend inside nosuspend block", .{}, &[_]u32{ 984 try astgen.errNoteNode(gz.nosuspend_node, "nosuspend block here", .{}), 985 }); 986 } 987 if (gz.suspend_node != 0) { 988 return astgen.failNodeNotes(node, "cannot suspend inside suspend block", .{}, &[_]u32{ 989 try astgen.errNoteNode(gz.suspend_node, "other suspend block here", .{}), 990 }); 991 } 992 assert(body_node != 0); 993 994 const suspend_inst = try gz.addBlock(.suspend_block, node); 995 try gz.instructions.append(gpa, suspend_inst); 996 997 var suspend_scope = gz.makeSubBlock(scope); 998 suspend_scope.suspend_node = node; 999 defer suspend_scope.instructions.deinit(gpa); 1000 1001 const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node); 1002 if (!gz.refIsNoReturn(body_result)) { 1003 _ = try suspend_scope.addBreak(.break_inline, suspend_inst, .void_value); 1004 } 1005 try suspend_scope.setBlockBody(suspend_inst); 1006 1007 return indexToRef(suspend_inst); 1008 } 1009 1010 fn awaitExpr( 1011 gz: *GenZir, 1012 scope: *Scope, 1013 rl: ResultLoc, 1014 node: ast.Node.Index, 1015 ) InnerError!Zir.Inst.Ref { 1016 const astgen = gz.astgen; 1017 const tree = astgen.tree; 1018 const node_datas = tree.nodes.items(.data); 1019 const rhs_node = node_datas[node].lhs; 1020 1021 if (gz.suspend_node != 0) { 1022 return astgen.failNodeNotes(node, "cannot await inside suspend block", .{}, &[_]u32{ 1023 try astgen.errNoteNode(gz.suspend_node, "suspend block here", .{}), 1024 }); 1025 } 1026 const operand = try expr(gz, scope, .none, rhs_node); 1027 const tag: Zir.Inst.Tag = if (gz.nosuspend_node != 0) .await_nosuspend else .@"await"; 1028 const result = try gz.addUnNode(tag, operand, node); 1029 return rvalue(gz, rl, result, node); 1030 } 1031 1032 fn resumeExpr( 1033 gz: *GenZir, 1034 scope: *Scope, 1035 rl: ResultLoc, 1036 node: ast.Node.Index, 1037 ) InnerError!Zir.Inst.Ref { 1038 const astgen = gz.astgen; 1039 const tree = astgen.tree; 1040 const node_datas = tree.nodes.items(.data); 1041 const rhs_node = node_datas[node].lhs; 1042 const operand = try expr(gz, scope, .none, rhs_node); 1043 const result = try gz.addUnNode(.@"resume", operand, node); 1044 return rvalue(gz, rl, result, node); 1045 } 1046 1047 fn fnProtoExpr( 1048 gz: *GenZir, 1049 scope: *Scope, 1050 rl: ResultLoc, 1051 fn_proto: ast.full.FnProto, 1052 ) InnerError!Zir.Inst.Ref { 1053 const astgen = gz.astgen; 1054 const gpa = astgen.gpa; 1055 const tree = astgen.tree; 1056 const token_tags = tree.tokens.items(.tag); 1057 1058 const is_extern = blk: { 1059 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; 1060 break :blk token_tags[maybe_extern_token] == .keyword_extern; 1061 }; 1062 assert(!is_extern); 1063 1064 const is_var_args = is_var_args: { 1065 var param_type_i: usize = 0; 1066 var it = fn_proto.iterate(tree.*); 1067 while (it.next()) |param| : (param_type_i += 1) { 1068 const is_comptime = if (param.comptime_noalias) |token| 1069 token_tags[token] == .keyword_comptime 1070 else 1071 false; 1072 1073 const is_anytype = if (param.anytype_ellipsis3) |token| blk: { 1074 switch (token_tags[token]) { 1075 .keyword_anytype => break :blk true, 1076 .ellipsis3 => break :is_var_args true, 1077 else => unreachable, 1078 } 1079 } else false; 1080 1081 const param_name: u32 = if (param.name_token) |name_token| blk: { 1082 if (mem.eql(u8, "_", tree.tokenSlice(name_token))) 1083 break :blk 0; 1084 1085 break :blk try astgen.identAsString(name_token); 1086 } else 0; 1087 1088 if (is_anytype) { 1089 const name_token = param.name_token orelse param.anytype_ellipsis3.?; 1090 1091 const tag: Zir.Inst.Tag = if (is_comptime) 1092 .param_anytype_comptime 1093 else 1094 .param_anytype; 1095 _ = try gz.addStrTok(tag, param_name, name_token); 1096 } else { 1097 const param_type_node = param.type_expr; 1098 assert(param_type_node != 0); 1099 var param_gz = gz.makeSubBlock(scope); 1100 defer param_gz.instructions.deinit(gpa); 1101 const param_type = try expr(¶m_gz, scope, coerced_type_rl, param_type_node); 1102 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); 1103 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); 1104 const main_tokens = tree.nodes.items(.main_token); 1105 const name_token = param.name_token orelse main_tokens[param_type_node]; 1106 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; 1107 const param_inst = try gz.addParam(tag, name_token, param_name, param_gz.instructions.items); 1108 assert(param_inst_expected == param_inst); 1109 } 1110 } 1111 break :is_var_args false; 1112 }; 1113 1114 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { 1115 break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr); 1116 }; 1117 if (fn_proto.ast.section_expr != 0) { 1118 return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); 1119 } 1120 1121 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; 1122 const is_inferred_error = token_tags[maybe_bang] == .bang; 1123 if (is_inferred_error) { 1124 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); 1125 } 1126 var ret_gz = gz.makeSubBlock(scope); 1127 defer ret_gz.instructions.deinit(gpa); 1128 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type); 1129 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty); 1130 1131 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) 1132 try expr( 1133 gz, 1134 scope, 1135 .{ .ty = .calling_convention_type }, 1136 fn_proto.ast.callconv_expr, 1137 ) 1138 else 1139 Zir.Inst.Ref.none; 1140 1141 const result = try gz.addFunc(.{ 1142 .src_node = fn_proto.ast.proto_node, 1143 .param_block = 0, 1144 .ret_ty = ret_gz.instructions.items, 1145 .ret_br = ret_br, 1146 .body = &[0]Zir.Inst.Index{}, 1147 .cc = cc, 1148 .align_inst = align_inst, 1149 .lib_name = 0, 1150 .is_var_args = is_var_args, 1151 .is_inferred_error = false, 1152 .is_test = false, 1153 .is_extern = false, 1154 }); 1155 return rvalue(gz, rl, result, fn_proto.ast.proto_node); 1156 } 1157 1158 fn arrayInitExpr( 1159 gz: *GenZir, 1160 scope: *Scope, 1161 rl: ResultLoc, 1162 node: ast.Node.Index, 1163 array_init: ast.full.ArrayInit, 1164 ) InnerError!Zir.Inst.Ref { 1165 const astgen = gz.astgen; 1166 const tree = astgen.tree; 1167 const node_tags = tree.nodes.items(.tag); 1168 const main_tokens = tree.nodes.items(.main_token); 1169 1170 assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init. 1171 1172 const types: struct { 1173 array: Zir.Inst.Ref, 1174 elem: Zir.Inst.Ref, 1175 } = inst: { 1176 if (array_init.ast.type_expr == 0) break :inst .{ 1177 .array = .none, 1178 .elem = .none, 1179 }; 1180 1181 infer: { 1182 const array_type: ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) { 1183 .array_type => tree.arrayType(array_init.ast.type_expr), 1184 .array_type_sentinel => tree.arrayTypeSentinel(array_init.ast.type_expr), 1185 else => break :infer, 1186 }; 1187 // This intentionally does not support `@"_"` syntax. 1188 if (node_tags[array_type.ast.elem_count] == .identifier and 1189 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_")) 1190 { 1191 const len_inst = try gz.addInt(array_init.ast.elements.len); 1192 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); 1193 if (array_type.ast.sentinel == 0) { 1194 const array_type_inst = try gz.addBin(.array_type, len_inst, elem_type); 1195 break :inst .{ 1196 .array = array_type_inst, 1197 .elem = elem_type, 1198 }; 1199 } else { 1200 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); 1201 const array_type_inst = try gz.addArrayTypeSentinel(len_inst, elem_type, sentinel); 1202 break :inst .{ 1203 .array = array_type_inst, 1204 .elem = elem_type, 1205 }; 1206 } 1207 } 1208 } 1209 const array_type_inst = try typeExpr(gz, scope, array_init.ast.type_expr); 1210 const elem_type = try gz.addUnNode(.elem_type, array_type_inst, array_init.ast.type_expr); 1211 break :inst .{ 1212 .array = array_type_inst, 1213 .elem = elem_type, 1214 }; 1215 }; 1216 1217 switch (rl) { 1218 .discard => { 1219 for (array_init.ast.elements) |elem_init| { 1220 _ = try expr(gz, scope, .discard, elem_init); 1221 } 1222 return Zir.Inst.Ref.void_value; 1223 }, 1224 .ref => { 1225 if (types.array != .none) { 1226 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init_ref); 1227 } else { 1228 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon_ref); 1229 } 1230 }, 1231 .none, .none_or_ref => { 1232 if (types.array != .none) { 1233 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init); 1234 } else { 1235 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); 1236 } 1237 }, 1238 .ty, .coerced_ty => |ty_inst| { 1239 if (types.array != .none) { 1240 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init); 1241 return rvalue(gz, rl, result, node); 1242 } else { 1243 const elem_type = try gz.addUnNode(.elem_type, ty_inst, node); 1244 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, .array_init); 1245 } 1246 }, 1247 .ptr, .inferred_ptr => |ptr_inst| { 1248 return arrayInitExprRlPtr(gz, scope, node, array_init.ast.elements, ptr_inst); 1249 }, 1250 .block_ptr => |block_gz| { 1251 return arrayInitExprRlPtr(gz, scope, node, array_init.ast.elements, block_gz.rl_ptr); 1252 }, 1253 } 1254 } 1255 1256 fn arrayInitExprRlNone( 1257 gz: *GenZir, 1258 scope: *Scope, 1259 node: ast.Node.Index, 1260 elements: []const ast.Node.Index, 1261 tag: Zir.Inst.Tag, 1262 ) InnerError!Zir.Inst.Ref { 1263 const astgen = gz.astgen; 1264 const gpa = astgen.gpa; 1265 const elem_list = try gpa.alloc(Zir.Inst.Ref, elements.len); 1266 defer gpa.free(elem_list); 1267 1268 for (elements) |elem_init, i| { 1269 elem_list[i] = try expr(gz, scope, .none, elem_init); 1270 } 1271 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.MultiOp{ 1272 .operands_len = @intCast(u32, elem_list.len), 1273 }); 1274 try astgen.appendRefs(elem_list); 1275 return init_inst; 1276 } 1277 1278 fn arrayInitExprRlTy( 1279 gz: *GenZir, 1280 scope: *Scope, 1281 node: ast.Node.Index, 1282 elements: []const ast.Node.Index, 1283 elem_ty_inst: Zir.Inst.Ref, 1284 tag: Zir.Inst.Tag, 1285 ) InnerError!Zir.Inst.Ref { 1286 const astgen = gz.astgen; 1287 const gpa = astgen.gpa; 1288 1289 const elem_list = try gpa.alloc(Zir.Inst.Ref, elements.len); 1290 defer gpa.free(elem_list); 1291 1292 const elem_rl: ResultLoc = .{ .ty = elem_ty_inst }; 1293 1294 for (elements) |elem_init, i| { 1295 elem_list[i] = try expr(gz, scope, elem_rl, elem_init); 1296 } 1297 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.MultiOp{ 1298 .operands_len = @intCast(u32, elem_list.len), 1299 }); 1300 try astgen.appendRefs(elem_list); 1301 return init_inst; 1302 } 1303 1304 fn arrayInitExprRlPtr( 1305 gz: *GenZir, 1306 scope: *Scope, 1307 node: ast.Node.Index, 1308 elements: []const ast.Node.Index, 1309 result_ptr: Zir.Inst.Ref, 1310 ) InnerError!Zir.Inst.Ref { 1311 const astgen = gz.astgen; 1312 const gpa = astgen.gpa; 1313 1314 const elem_ptr_list = try gpa.alloc(Zir.Inst.Index, elements.len); 1315 defer gpa.free(elem_ptr_list); 1316 1317 for (elements) |elem_init, i| { 1318 const index_inst = try gz.addInt(i); 1319 const elem_ptr = try gz.addPlNode(.elem_ptr_node, elem_init, Zir.Inst.Bin{ 1320 .lhs = result_ptr, 1321 .rhs = index_inst, 1322 }); 1323 elem_ptr_list[i] = refToIndex(elem_ptr).?; 1324 _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init); 1325 } 1326 _ = try gz.addPlNode(.validate_array_init_ptr, node, Zir.Inst.Block{ 1327 .body_len = @intCast(u32, elem_ptr_list.len), 1328 }); 1329 try astgen.extra.appendSlice(gpa, elem_ptr_list); 1330 return .void_value; 1331 } 1332 1333 fn structInitExpr( 1334 gz: *GenZir, 1335 scope: *Scope, 1336 rl: ResultLoc, 1337 node: ast.Node.Index, 1338 struct_init: ast.full.StructInit, 1339 ) InnerError!Zir.Inst.Ref { 1340 const astgen = gz.astgen; 1341 const tree = astgen.tree; 1342 1343 if (struct_init.ast.type_expr == 0) { 1344 if (struct_init.ast.fields.len == 0) { 1345 return rvalue(gz, rl, .empty_struct, node); 1346 } 1347 } else array: { 1348 const node_tags = tree.nodes.items(.tag); 1349 const main_tokens = tree.nodes.items(.main_token); 1350 const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { 1351 .array_type => tree.arrayType(struct_init.ast.type_expr), 1352 .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), 1353 else => break :array, 1354 }; 1355 const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and 1356 // This intentionally does not support `@"_"` syntax. 1357 mem.eql(u8, tree.tokenSlice(main_tokens[array_type.ast.elem_count]), "_"); 1358 if (struct_init.ast.fields.len == 0) { 1359 if (is_inferred_array_len) { 1360 const elem_type = try typeExpr(gz, scope, array_type.ast.elem_type); 1361 const array_type_inst = if (array_type.ast.sentinel == 0) blk: { 1362 break :blk try gz.addBin(.array_type, .zero_usize, elem_type); 1363 } else blk: { 1364 const sentinel = try comptimeExpr(gz, scope, .{ .ty = elem_type }, array_type.ast.sentinel); 1365 break :blk try gz.addArrayTypeSentinel(.zero_usize, elem_type, sentinel); 1366 }; 1367 const result = try gz.addUnNode(.struct_init_empty, array_type_inst, node); 1368 return rvalue(gz, rl, result, node); 1369 } 1370 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1371 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node); 1372 return rvalue(gz, rl, result, node); 1373 } else { 1374 return astgen.failNode( 1375 struct_init.ast.type_expr, 1376 "initializing array with struct syntax", 1377 .{}, 1378 ); 1379 } 1380 } 1381 1382 switch (rl) { 1383 .discard => { 1384 if (struct_init.ast.type_expr != 0) 1385 _ = try typeExpr(gz, scope, struct_init.ast.type_expr); 1386 for (struct_init.ast.fields) |field_init| { 1387 _ = try expr(gz, scope, .discard, field_init); 1388 } 1389 return Zir.Inst.Ref.void_value; 1390 }, 1391 .ref => { 1392 if (struct_init.ast.type_expr != 0) { 1393 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1394 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); 1395 } else { 1396 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref); 1397 } 1398 }, 1399 .none, .none_or_ref => { 1400 if (struct_init.ast.type_expr != 0) { 1401 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1402 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); 1403 } else { 1404 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon); 1405 } 1406 }, 1407 .ty, .coerced_ty => |ty_inst| { 1408 if (struct_init.ast.type_expr == 0) { 1409 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); 1410 } 1411 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); 1412 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init); 1413 return rvalue(gz, rl, result, node); 1414 }, 1415 .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, node, struct_init, ptr_inst), 1416 .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, node, struct_init, block_gz.rl_ptr), 1417 } 1418 } 1419 1420 fn structInitExprRlNone( 1421 gz: *GenZir, 1422 scope: *Scope, 1423 node: ast.Node.Index, 1424 struct_init: ast.full.StructInit, 1425 tag: Zir.Inst.Tag, 1426 ) InnerError!Zir.Inst.Ref { 1427 const astgen = gz.astgen; 1428 const gpa = astgen.gpa; 1429 const tree = astgen.tree; 1430 1431 const fields_list = try gpa.alloc(Zir.Inst.StructInitAnon.Item, struct_init.ast.fields.len); 1432 defer gpa.free(fields_list); 1433 1434 for (struct_init.ast.fields) |field_init, i| { 1435 const name_token = tree.firstToken(field_init) - 2; 1436 const str_index = try astgen.identAsString(name_token); 1437 1438 fields_list[i] = .{ 1439 .field_name = str_index, 1440 .init = try expr(gz, scope, .none, field_init), 1441 }; 1442 } 1443 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{ 1444 .fields_len = @intCast(u32, fields_list.len), 1445 }); 1446 try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len * 1447 @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len); 1448 for (fields_list) |field| { 1449 _ = gz.astgen.addExtraAssumeCapacity(field); 1450 } 1451 return init_inst; 1452 } 1453 1454 fn structInitExprRlPtr( 1455 gz: *GenZir, 1456 scope: *Scope, 1457 node: ast.Node.Index, 1458 struct_init: ast.full.StructInit, 1459 result_ptr: Zir.Inst.Ref, 1460 ) InnerError!Zir.Inst.Ref { 1461 const astgen = gz.astgen; 1462 const gpa = astgen.gpa; 1463 const tree = astgen.tree; 1464 1465 const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len); 1466 defer gpa.free(field_ptr_list); 1467 1468 if (struct_init.ast.type_expr != 0) 1469 _ = try typeExpr(gz, scope, struct_init.ast.type_expr); 1470 1471 for (struct_init.ast.fields) |field_init, i| { 1472 const name_token = tree.firstToken(field_init) - 2; 1473 const str_index = try astgen.identAsString(name_token); 1474 const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{ 1475 .lhs = result_ptr, 1476 .field_name_start = str_index, 1477 }); 1478 field_ptr_list[i] = refToIndex(field_ptr).?; 1479 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init); 1480 } 1481 _ = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{ 1482 .body_len = @intCast(u32, field_ptr_list.len), 1483 }); 1484 try astgen.extra.appendSlice(gpa, field_ptr_list); 1485 return .void_value; 1486 } 1487 1488 fn structInitExprRlTy( 1489 gz: *GenZir, 1490 scope: *Scope, 1491 node: ast.Node.Index, 1492 struct_init: ast.full.StructInit, 1493 ty_inst: Zir.Inst.Ref, 1494 tag: Zir.Inst.Tag, 1495 ) InnerError!Zir.Inst.Ref { 1496 const astgen = gz.astgen; 1497 const gpa = astgen.gpa; 1498 const tree = astgen.tree; 1499 1500 const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len); 1501 defer gpa.free(fields_list); 1502 1503 for (struct_init.ast.fields) |field_init, i| { 1504 const name_token = tree.firstToken(field_init) - 2; 1505 const str_index = try astgen.identAsString(name_token); 1506 1507 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ 1508 .container_type = ty_inst, 1509 .name_start = str_index, 1510 }); 1511 fields_list[i] = .{ 1512 .field_type = refToIndex(field_ty_inst).?, 1513 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init), 1514 }; 1515 } 1516 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{ 1517 .fields_len = @intCast(u32, fields_list.len), 1518 }); 1519 try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len * 1520 @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len); 1521 for (fields_list) |field| { 1522 _ = gz.astgen.addExtraAssumeCapacity(field); 1523 } 1524 return init_inst; 1525 } 1526 1527 /// This calls expr in a comptime scope, and is intended to be called as a helper function. 1528 /// The one that corresponds to `comptime` expression syntax is `comptimeExprAst`. 1529 fn comptimeExpr( 1530 gz: *GenZir, 1531 scope: *Scope, 1532 rl: ResultLoc, 1533 node: ast.Node.Index, 1534 ) InnerError!Zir.Inst.Ref { 1535 const prev_force_comptime = gz.force_comptime; 1536 gz.force_comptime = true; 1537 defer gz.force_comptime = prev_force_comptime; 1538 1539 return expr(gz, scope, rl, node); 1540 } 1541 1542 /// This one is for an actual `comptime` syntax, and will emit a compile error if 1543 /// the scope already has `force_comptime=true`. 1544 /// See `comptimeExpr` for the helper function for calling expr in a comptime scope. 1545 fn comptimeExprAst( 1546 gz: *GenZir, 1547 scope: *Scope, 1548 rl: ResultLoc, 1549 node: ast.Node.Index, 1550 ) InnerError!Zir.Inst.Ref { 1551 const astgen = gz.astgen; 1552 if (gz.force_comptime) { 1553 return astgen.failNode(node, "redundant comptime keyword in already comptime scope", .{}); 1554 } 1555 const tree = astgen.tree; 1556 const node_datas = tree.nodes.items(.data); 1557 const body_node = node_datas[node].lhs; 1558 gz.force_comptime = true; 1559 const result = try expr(gz, scope, rl, body_node); 1560 gz.force_comptime = false; 1561 return result; 1562 } 1563 1564 fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 1565 const astgen = parent_gz.astgen; 1566 const tree = astgen.tree; 1567 const node_datas = tree.nodes.items(.data); 1568 const break_label = node_datas[node].lhs; 1569 const rhs = node_datas[node].rhs; 1570 1571 // Look for the label in the scope. 1572 var scope = parent_scope; 1573 while (true) { 1574 switch (scope.tag) { 1575 .gen_zir => { 1576 const block_gz = scope.cast(GenZir).?; 1577 1578 const block_inst = blk: { 1579 if (break_label != 0) { 1580 if (block_gz.label) |*label| { 1581 if (try astgen.tokenIdentEql(label.token, break_label)) { 1582 label.used = true; 1583 break :blk label.block_inst; 1584 } 1585 } 1586 } else if (block_gz.break_block != 0) { 1587 break :blk block_gz.break_block; 1588 } 1589 scope = block_gz.parent; 1590 continue; 1591 }; 1592 1593 if (rhs == 0) { 1594 _ = try parent_gz.addBreak(.@"break", block_inst, .void_value); 1595 return Zir.Inst.Ref.unreachable_value; 1596 } 1597 block_gz.break_count += 1; 1598 const prev_rvalue_rl_count = block_gz.rvalue_rl_count; 1599 const operand = try expr(parent_gz, parent_scope, block_gz.break_result_loc, rhs); 1600 const have_store_to_block = block_gz.rvalue_rl_count != prev_rvalue_rl_count; 1601 1602 const br = try parent_gz.addBreak(.@"break", block_inst, operand); 1603 1604 if (block_gz.break_result_loc == .block_ptr) { 1605 try block_gz.labeled_breaks.append(astgen.gpa, br); 1606 1607 if (have_store_to_block) { 1608 const zir_tags = parent_gz.astgen.instructions.items(.tag); 1609 const zir_datas = parent_gz.astgen.instructions.items(.data); 1610 const store_inst = @intCast(u32, zir_tags.len - 2); 1611 assert(zir_tags[store_inst] == .store_to_block_ptr); 1612 assert(zir_datas[store_inst].bin.lhs == block_gz.rl_ptr); 1613 try block_gz.labeled_store_to_block_ptr_list.append(astgen.gpa, store_inst); 1614 } 1615 } 1616 return Zir.Inst.Ref.unreachable_value; 1617 }, 1618 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 1619 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 1620 .namespace => break, 1621 .defer_normal => { 1622 const defer_scope = scope.cast(Scope.Defer).?; 1623 scope = defer_scope.parent; 1624 const expr_node = node_datas[defer_scope.defer_node].rhs; 1625 _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); 1626 }, 1627 .defer_error => scope = scope.cast(Scope.Defer).?.parent, 1628 .top => unreachable, 1629 } 1630 } 1631 if (break_label != 0) { 1632 const label_name = try astgen.identifierTokenString(break_label); 1633 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 1634 } else { 1635 return astgen.failNode(node, "break expression outside loop", .{}); 1636 } 1637 } 1638 1639 fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 1640 const astgen = parent_gz.astgen; 1641 const tree = astgen.tree; 1642 const node_datas = tree.nodes.items(.data); 1643 const break_label = node_datas[node].lhs; 1644 1645 // Look for the label in the scope. 1646 var scope = parent_scope; 1647 while (true) { 1648 switch (scope.tag) { 1649 .gen_zir => { 1650 const gen_zir = scope.cast(GenZir).?; 1651 const continue_block = gen_zir.continue_block; 1652 if (continue_block == 0) { 1653 scope = gen_zir.parent; 1654 continue; 1655 } 1656 if (break_label != 0) blk: { 1657 if (gen_zir.label) |*label| { 1658 if (try astgen.tokenIdentEql(label.token, break_label)) { 1659 label.used = true; 1660 break :blk; 1661 } 1662 } 1663 // found continue but either it has a different label, or no label 1664 scope = gen_zir.parent; 1665 continue; 1666 } 1667 1668 // TODO emit a break_inline if the loop being continued is inline 1669 _ = try parent_gz.addBreak(.@"break", continue_block, .void_value); 1670 return Zir.Inst.Ref.unreachable_value; 1671 }, 1672 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 1673 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 1674 .defer_normal => { 1675 const defer_scope = scope.cast(Scope.Defer).?; 1676 scope = defer_scope.parent; 1677 const expr_node = node_datas[defer_scope.defer_node].rhs; 1678 _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); 1679 }, 1680 .defer_error => scope = scope.cast(Scope.Defer).?.parent, 1681 .namespace => break, 1682 .top => unreachable, 1683 } 1684 } 1685 if (break_label != 0) { 1686 const label_name = try astgen.identifierTokenString(break_label); 1687 return astgen.failTok(break_label, "label not found: '{s}'", .{label_name}); 1688 } else { 1689 return astgen.failNode(node, "continue expression outside loop", .{}); 1690 } 1691 } 1692 1693 fn blockExpr( 1694 gz: *GenZir, 1695 scope: *Scope, 1696 rl: ResultLoc, 1697 block_node: ast.Node.Index, 1698 statements: []const ast.Node.Index, 1699 ) InnerError!Zir.Inst.Ref { 1700 const tracy = trace(@src()); 1701 defer tracy.end(); 1702 1703 const astgen = gz.astgen; 1704 const tree = astgen.tree; 1705 const main_tokens = tree.nodes.items(.main_token); 1706 const token_tags = tree.tokens.items(.tag); 1707 1708 const lbrace = main_tokens[block_node]; 1709 if (token_tags[lbrace - 1] == .colon and 1710 token_tags[lbrace - 2] == .identifier) 1711 { 1712 return labeledBlockExpr(gz, scope, rl, block_node, statements, .block); 1713 } 1714 1715 try blockExprStmts(gz, scope, statements); 1716 return rvalue(gz, rl, .void_value, block_node); 1717 } 1718 1719 fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.TokenIndex) !void { 1720 // Look for the label in the scope. 1721 var scope = parent_scope; 1722 while (true) { 1723 switch (scope.tag) { 1724 .gen_zir => { 1725 const gen_zir = scope.cast(GenZir).?; 1726 if (gen_zir.label) |prev_label| { 1727 if (try astgen.tokenIdentEql(label, prev_label.token)) { 1728 const label_name = try astgen.identifierTokenString(label); 1729 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{ 1730 label_name, 1731 }, &[_]u32{ 1732 try astgen.errNoteTok( 1733 prev_label.token, 1734 "previous definition here", 1735 .{}, 1736 ), 1737 }); 1738 } 1739 } 1740 scope = gen_zir.parent; 1741 }, 1742 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 1743 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 1744 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 1745 .namespace => break, 1746 .top => unreachable, 1747 } 1748 } 1749 } 1750 1751 fn labeledBlockExpr( 1752 gz: *GenZir, 1753 parent_scope: *Scope, 1754 rl: ResultLoc, 1755 block_node: ast.Node.Index, 1756 statements: []const ast.Node.Index, 1757 zir_tag: Zir.Inst.Tag, 1758 ) InnerError!Zir.Inst.Ref { 1759 const tracy = trace(@src()); 1760 defer tracy.end(); 1761 1762 assert(zir_tag == .block); 1763 1764 const astgen = gz.astgen; 1765 const tree = astgen.tree; 1766 const main_tokens = tree.nodes.items(.main_token); 1767 const token_tags = tree.tokens.items(.tag); 1768 1769 const lbrace = main_tokens[block_node]; 1770 const label_token = lbrace - 2; 1771 assert(token_tags[label_token] == .identifier); 1772 1773 try astgen.checkLabelRedefinition(parent_scope, label_token); 1774 1775 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct 1776 // so that break statements can reference it. 1777 const block_inst = try gz.addBlock(zir_tag, block_node); 1778 try gz.instructions.append(astgen.gpa, block_inst); 1779 1780 var block_scope = gz.makeSubBlock(parent_scope); 1781 block_scope.label = GenZir.Label{ 1782 .token = label_token, 1783 .block_inst = block_inst, 1784 }; 1785 block_scope.setBreakResultLoc(rl); 1786 defer block_scope.instructions.deinit(astgen.gpa); 1787 defer block_scope.labeled_breaks.deinit(astgen.gpa); 1788 defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); 1789 1790 try blockExprStmts(&block_scope, &block_scope.base, statements); 1791 1792 if (!block_scope.label.?.used) { 1793 return astgen.failTok(label_token, "unused block label", .{}); 1794 } 1795 1796 const zir_tags = gz.astgen.instructions.items(.tag); 1797 const zir_datas = gz.astgen.instructions.items(.data); 1798 1799 const strat = rl.strategy(&block_scope); 1800 switch (strat.tag) { 1801 .break_void => { 1802 // The code took advantage of the result location as a pointer. 1803 // Turn the break instruction operands into void. 1804 for (block_scope.labeled_breaks.items) |br| { 1805 zir_datas[br].@"break".operand = .void_value; 1806 } 1807 try block_scope.setBlockBody(block_inst); 1808 1809 return indexToRef(block_inst); 1810 }, 1811 .break_operand => { 1812 // All break operands are values that did not use the result location pointer. 1813 if (strat.elide_store_to_block_ptr_instructions) { 1814 for (block_scope.labeled_store_to_block_ptr_list.items) |inst| { 1815 // Mark as elided for removal below. 1816 assert(zir_tags[inst] == .store_to_block_ptr); 1817 zir_datas[inst].bin.lhs = .none; 1818 } 1819 try block_scope.setBlockBodyEliding(block_inst); 1820 } else { 1821 try block_scope.setBlockBody(block_inst); 1822 } 1823 const block_ref = indexToRef(block_inst); 1824 switch (rl) { 1825 .ref => return block_ref, 1826 else => return rvalue(gz, rl, block_ref, block_node), 1827 } 1828 }, 1829 } 1830 } 1831 1832 fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Node.Index) !void { 1833 const astgen = gz.astgen; 1834 const tree = astgen.tree; 1835 const node_tags = tree.nodes.items(.tag); 1836 1837 var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa); 1838 defer block_arena.deinit(); 1839 1840 var noreturn_src_node: ast.Node.Index = 0; 1841 var scope = parent_scope; 1842 for (statements) |statement| { 1843 if (noreturn_src_node != 0) { 1844 return astgen.failNodeNotes( 1845 statement, 1846 "unreachable code", 1847 .{}, 1848 &[_]u32{ 1849 try astgen.errNoteNode( 1850 noreturn_src_node, 1851 "control flow is diverted here", 1852 .{}, 1853 ), 1854 }, 1855 ); 1856 } 1857 switch (node_tags[statement]) { 1858 // zig fmt: off 1859 .global_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)), 1860 .local_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)), 1861 .simple_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)), 1862 .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)), 1863 1864 .@"defer" => scope = try makeDeferScope(scope, statement, &block_arena.allocator, .defer_normal), 1865 .@"errdefer" => scope = try makeDeferScope(scope, statement, &block_arena.allocator, .defer_error), 1866 1867 .assign => try assign(gz, scope, statement), 1868 1869 .assign_bit_shift_left => try assignShift(gz, scope, statement, .shl), 1870 .assign_bit_shift_right => try assignShift(gz, scope, statement, .shr), 1871 1872 .assign_bit_and => try assignOp(gz, scope, statement, .bit_and), 1873 .assign_bit_or => try assignOp(gz, scope, statement, .bit_or), 1874 .assign_bit_xor => try assignOp(gz, scope, statement, .xor), 1875 .assign_div => try assignOp(gz, scope, statement, .div), 1876 .assign_sub => try assignOp(gz, scope, statement, .sub), 1877 .assign_sub_wrap => try assignOp(gz, scope, statement, .subwrap), 1878 .assign_mod => try assignOp(gz, scope, statement, .mod_rem), 1879 .assign_add => try assignOp(gz, scope, statement, .add), 1880 .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), 1881 .assign_mul => try assignOp(gz, scope, statement, .mul), 1882 .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), 1883 1884 else => noreturn_src_node = try unusedResultExpr(gz, scope, statement), 1885 // zig fmt: on 1886 } 1887 } 1888 1889 try genDefers(gz, parent_scope, scope, .normal_only); 1890 try checkUsed(gz, parent_scope, scope); 1891 } 1892 1893 /// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`. 1894 /// Otherwise returns 0. 1895 fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!ast.Node.Index { 1896 try emitDbgNode(gz, statement); 1897 // We need to emit an error if the result is not `noreturn` or `void`, but 1898 // we want to avoid adding the ZIR instruction if possible for performance. 1899 const maybe_unused_result = try expr(gz, scope, .none, statement); 1900 var noreturn_src_node: ast.Node.Index = 0; 1901 const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { 1902 // Note that this array becomes invalid after appending more items to it 1903 // in the above while loop. 1904 const zir_tags = gz.astgen.instructions.items(.tag); 1905 switch (zir_tags[inst]) { 1906 // For some instructions, swap in a slightly different ZIR tag 1907 // so we can avoid a separate ensure_result_used instruction. 1908 .call_chkused => unreachable, 1909 .call => { 1910 zir_tags[inst] = .call_chkused; 1911 break :b true; 1912 }, 1913 1914 // ZIR instructions that might be a type other than `noreturn` or `void`. 1915 .add, 1916 .addwrap, 1917 .param, 1918 .param_comptime, 1919 .param_anytype, 1920 .param_anytype_comptime, 1921 .alloc, 1922 .alloc_mut, 1923 .alloc_comptime, 1924 .alloc_inferred, 1925 .alloc_inferred_mut, 1926 .alloc_inferred_comptime, 1927 .array_cat, 1928 .array_mul, 1929 .array_type, 1930 .array_type_sentinel, 1931 .vector_type, 1932 .elem_type, 1933 .indexable_ptr_len, 1934 .anyframe_type, 1935 .as, 1936 .as_node, 1937 .bit_and, 1938 .bitcast, 1939 .bitcast_result_ptr, 1940 .bit_or, 1941 .block, 1942 .block_inline, 1943 .suspend_block, 1944 .loop, 1945 .bool_br_and, 1946 .bool_br_or, 1947 .bool_not, 1948 .call_compile_time, 1949 .call_nosuspend, 1950 .call_async, 1951 .cmp_lt, 1952 .cmp_lte, 1953 .cmp_eq, 1954 .cmp_gte, 1955 .cmp_gt, 1956 .cmp_neq, 1957 .coerce_result_ptr, 1958 .decl_ref, 1959 .decl_val, 1960 .load, 1961 .div, 1962 .elem_ptr, 1963 .elem_val, 1964 .elem_ptr_node, 1965 .elem_val_node, 1966 .field_ptr, 1967 .field_val, 1968 .field_ptr_named, 1969 .field_val_named, 1970 .func, 1971 .func_inferred, 1972 .int, 1973 .int_big, 1974 .float, 1975 .float128, 1976 .int_type, 1977 .is_non_null, 1978 .is_non_null_ptr, 1979 .is_non_err, 1980 .is_non_err_ptr, 1981 .mod_rem, 1982 .mul, 1983 .mulwrap, 1984 .param_type, 1985 .ref, 1986 .shl, 1987 .shr, 1988 .str, 1989 .sub, 1990 .subwrap, 1991 .negate, 1992 .negate_wrap, 1993 .typeof, 1994 .typeof_elem, 1995 .xor, 1996 .optional_type, 1997 .optional_payload_safe, 1998 .optional_payload_unsafe, 1999 .optional_payload_safe_ptr, 2000 .optional_payload_unsafe_ptr, 2001 .err_union_payload_safe, 2002 .err_union_payload_unsafe, 2003 .err_union_payload_safe_ptr, 2004 .err_union_payload_unsafe_ptr, 2005 .err_union_code, 2006 .err_union_code_ptr, 2007 .ptr_type, 2008 .ptr_type_simple, 2009 .enum_literal, 2010 .merge_error_sets, 2011 .error_union_type, 2012 .bit_not, 2013 .error_value, 2014 .error_to_int, 2015 .int_to_error, 2016 .slice_start, 2017 .slice_end, 2018 .slice_sentinel, 2019 .import, 2020 .switch_block, 2021 .switch_block_multi, 2022 .switch_block_else, 2023 .switch_block_else_multi, 2024 .switch_block_under, 2025 .switch_block_under_multi, 2026 .switch_block_ref, 2027 .switch_block_ref_multi, 2028 .switch_block_ref_else, 2029 .switch_block_ref_else_multi, 2030 .switch_block_ref_under, 2031 .switch_block_ref_under_multi, 2032 .switch_capture, 2033 .switch_capture_ref, 2034 .switch_capture_multi, 2035 .switch_capture_multi_ref, 2036 .switch_capture_else, 2037 .switch_capture_else_ref, 2038 .struct_init_empty, 2039 .struct_init, 2040 .struct_init_ref, 2041 .struct_init_anon, 2042 .struct_init_anon_ref, 2043 .array_init, 2044 .array_init_anon, 2045 .array_init_ref, 2046 .array_init_anon_ref, 2047 .union_init_ptr, 2048 .field_type, 2049 .field_type_ref, 2050 .opaque_decl, 2051 .opaque_decl_anon, 2052 .opaque_decl_func, 2053 .error_set_decl, 2054 .error_set_decl_anon, 2055 .error_set_decl_func, 2056 .int_to_enum, 2057 .enum_to_int, 2058 .type_info, 2059 .size_of, 2060 .bit_size_of, 2061 .log2_int_type, 2062 .typeof_log2_int_type, 2063 .ptr_to_int, 2064 .align_of, 2065 .bool_to_int, 2066 .embed_file, 2067 .error_name, 2068 .sqrt, 2069 .sin, 2070 .cos, 2071 .exp, 2072 .exp2, 2073 .log, 2074 .log2, 2075 .log10, 2076 .fabs, 2077 .floor, 2078 .ceil, 2079 .trunc, 2080 .round, 2081 .tag_name, 2082 .reify, 2083 .type_name, 2084 .frame_type, 2085 .frame_size, 2086 .float_to_int, 2087 .int_to_float, 2088 .int_to_ptr, 2089 .float_cast, 2090 .int_cast, 2091 .err_set_cast, 2092 .ptr_cast, 2093 .truncate, 2094 .align_cast, 2095 .has_decl, 2096 .has_field, 2097 .clz, 2098 .ctz, 2099 .pop_count, 2100 .byte_swap, 2101 .bit_reverse, 2102 .div_exact, 2103 .div_floor, 2104 .div_trunc, 2105 .mod, 2106 .rem, 2107 .shl_exact, 2108 .shr_exact, 2109 .bit_offset_of, 2110 .offset_of, 2111 .cmpxchg_strong, 2112 .cmpxchg_weak, 2113 .splat, 2114 .reduce, 2115 .shuffle, 2116 .select, 2117 .atomic_load, 2118 .atomic_rmw, 2119 .atomic_store, 2120 .mul_add, 2121 .builtin_call, 2122 .field_ptr_type, 2123 .field_parent_ptr, 2124 .maximum, 2125 .memcpy, 2126 .memset, 2127 .minimum, 2128 .builtin_async_call, 2129 .c_import, 2130 .@"resume", 2131 .@"await", 2132 .await_nosuspend, 2133 .ret_err_value_code, 2134 .extended, 2135 => break :b false, 2136 2137 // ZIR instructions that are always `noreturn`. 2138 .@"break", 2139 .break_inline, 2140 .condbr, 2141 .condbr_inline, 2142 .compile_error, 2143 .ret_node, 2144 .ret_load, 2145 .ret_coerce, 2146 .ret_err_value, 2147 .@"unreachable", 2148 .repeat, 2149 .repeat_inline, 2150 .panic, 2151 => { 2152 noreturn_src_node = statement; 2153 break :b true; 2154 }, 2155 2156 // ZIR instructions that are always `void`. 2157 .breakpoint, 2158 .fence, 2159 .dbg_stmt, 2160 .ensure_result_used, 2161 .ensure_result_non_error, 2162 .@"export", 2163 .set_eval_branch_quota, 2164 .ensure_err_payload_void, 2165 .store, 2166 .store_node, 2167 .store_to_block_ptr, 2168 .store_to_inferred_ptr, 2169 .resolve_inferred_alloc, 2170 .validate_struct_init_ptr, 2171 .validate_array_init_ptr, 2172 .set_align_stack, 2173 .set_cold, 2174 .set_float_mode, 2175 .set_runtime_safety, 2176 => break :b true, 2177 } 2178 } else switch (maybe_unused_result) { 2179 .none => unreachable, 2180 2181 .unreachable_value => b: { 2182 noreturn_src_node = statement; 2183 break :b true; 2184 }, 2185 2186 .void_value => true, 2187 2188 else => false, 2189 }; 2190 if (!elide_check) { 2191 _ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement); 2192 } 2193 return noreturn_src_node; 2194 } 2195 2196 fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct { 2197 have_any: bool, 2198 have_normal: bool, 2199 have_err: bool, 2200 need_err_code: bool, 2201 } { 2202 const tree = astgen.tree; 2203 const node_datas = tree.nodes.items(.data); 2204 2205 var have_normal = false; 2206 var have_err = false; 2207 var need_err_code = false; 2208 var scope = inner_scope; 2209 while (scope != outer_scope) { 2210 switch (scope.tag) { 2211 .gen_zir => scope = scope.cast(GenZir).?.parent, 2212 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2213 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2214 .defer_normal => { 2215 const defer_scope = scope.cast(Scope.Defer).?; 2216 scope = defer_scope.parent; 2217 2218 have_normal = true; 2219 }, 2220 .defer_error => { 2221 const defer_scope = scope.cast(Scope.Defer).?; 2222 scope = defer_scope.parent; 2223 2224 have_err = true; 2225 2226 const have_err_payload = node_datas[defer_scope.defer_node].lhs != 0; 2227 need_err_code = need_err_code or have_err_payload; 2228 }, 2229 .namespace => unreachable, 2230 .top => unreachable, 2231 } 2232 } 2233 return .{ 2234 .have_any = have_normal or have_err, 2235 .have_normal = have_normal, 2236 .have_err = have_err, 2237 .need_err_code = need_err_code, 2238 }; 2239 } 2240 2241 const DefersToEmit = union(enum) { 2242 both: Zir.Inst.Ref, // err code 2243 both_sans_err, 2244 normal_only, 2245 }; 2246 2247 fn genDefers( 2248 gz: *GenZir, 2249 outer_scope: *Scope, 2250 inner_scope: *Scope, 2251 which_ones: DefersToEmit, 2252 ) InnerError!void { 2253 const astgen = gz.astgen; 2254 const tree = astgen.tree; 2255 const node_datas = tree.nodes.items(.data); 2256 2257 var scope = inner_scope; 2258 while (scope != outer_scope) { 2259 switch (scope.tag) { 2260 .gen_zir => scope = scope.cast(GenZir).?.parent, 2261 .local_val => scope = scope.cast(Scope.LocalVal).?.parent, 2262 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, 2263 .defer_normal => { 2264 const defer_scope = scope.cast(Scope.Defer).?; 2265 scope = defer_scope.parent; 2266 const expr_node = node_datas[defer_scope.defer_node].rhs; 2267 const prev_in_defer = gz.in_defer; 2268 gz.in_defer = true; 2269 defer gz.in_defer = prev_in_defer; 2270 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node); 2271 }, 2272 .defer_error => { 2273 const defer_scope = scope.cast(Scope.Defer).?; 2274 scope = defer_scope.parent; 2275 switch (which_ones) { 2276 .both_sans_err => { 2277 const expr_node = node_datas[defer_scope.defer_node].rhs; 2278 const prev_in_defer = gz.in_defer; 2279 gz.in_defer = true; 2280 defer gz.in_defer = prev_in_defer; 2281 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node); 2282 }, 2283 .both => |err_code| { 2284 const expr_node = node_datas[defer_scope.defer_node].rhs; 2285 const payload_token = node_datas[defer_scope.defer_node].lhs; 2286 const prev_in_defer = gz.in_defer; 2287 gz.in_defer = true; 2288 defer gz.in_defer = prev_in_defer; 2289 var local_val_scope: Scope.LocalVal = undefined; 2290 const sub_scope = if (payload_token == 0) defer_scope.parent else blk: { 2291 const ident_name = try astgen.identAsString(payload_token); 2292 local_val_scope = .{ 2293 .parent = defer_scope.parent, 2294 .gen_zir = gz, 2295 .name = ident_name, 2296 .inst = err_code, 2297 .token_src = payload_token, 2298 .id_cat = .@"capture", 2299 }; 2300 break :blk &local_val_scope.base; 2301 }; 2302 _ = try unusedResultExpr(gz, sub_scope, expr_node); 2303 }, 2304 .normal_only => continue, 2305 } 2306 }, 2307 .namespace => unreachable, 2308 .top => unreachable, 2309 } 2310 } 2311 } 2312 2313 fn checkUsed( 2314 gz: *GenZir, 2315 outer_scope: *Scope, 2316 inner_scope: *Scope, 2317 ) InnerError!void { 2318 const astgen = gz.astgen; 2319 2320 var scope = inner_scope; 2321 while (scope != outer_scope) { 2322 switch (scope.tag) { 2323 .gen_zir => scope = scope.cast(GenZir).?.parent, 2324 .local_val => { 2325 const s = scope.cast(Scope.LocalVal).?; 2326 if (!s.used) { 2327 return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2328 } 2329 scope = s.parent; 2330 }, 2331 .local_ptr => { 2332 const s = scope.cast(Scope.LocalPtr).?; 2333 if (!s.used) { 2334 return astgen.failTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)}); 2335 } 2336 scope = s.parent; 2337 }, 2338 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, 2339 .namespace => unreachable, 2340 .top => unreachable, 2341 } 2342 } 2343 } 2344 2345 fn makeDeferScope( 2346 scope: *Scope, 2347 node: ast.Node.Index, 2348 block_arena: *Allocator, 2349 scope_tag: Scope.Tag, 2350 ) InnerError!*Scope { 2351 const defer_scope = try block_arena.create(Scope.Defer); 2352 defer_scope.* = .{ 2353 .base = .{ .tag = scope_tag }, 2354 .parent = scope, 2355 .defer_node = node, 2356 }; 2357 return &defer_scope.base; 2358 } 2359 2360 fn varDecl( 2361 gz: *GenZir, 2362 scope: *Scope, 2363 node: ast.Node.Index, 2364 block_arena: *Allocator, 2365 var_decl: ast.full.VarDecl, 2366 ) InnerError!*Scope { 2367 try emitDbgNode(gz, node); 2368 const astgen = gz.astgen; 2369 const gpa = astgen.gpa; 2370 const tree = astgen.tree; 2371 const token_tags = tree.tokens.items(.tag); 2372 2373 const name_token = var_decl.ast.mut_token + 1; 2374 const ident_name_raw = tree.tokenSlice(name_token); 2375 if (mem.eql(u8, ident_name_raw, "_")) { 2376 return astgen.failTok(name_token, "'_' used as an identifier without @\"_\" syntax", .{}); 2377 } 2378 const ident_name = try astgen.identAsString(name_token); 2379 2380 try astgen.detectLocalShadowing(scope, ident_name, name_token, ident_name_raw); 2381 2382 if (var_decl.ast.init_node == 0) { 2383 return astgen.failNode(node, "variables must be initialized", .{}); 2384 } 2385 2386 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0) 2387 try expr(gz, scope, align_rl, var_decl.ast.align_node) 2388 else 2389 .none; 2390 2391 switch (token_tags[var_decl.ast.mut_token]) { 2392 .keyword_const => { 2393 if (var_decl.comptime_token) |comptime_token| { 2394 return astgen.failTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{}); 2395 } 2396 2397 // Depending on the type of AST the initialization expression is, we may need an lvalue 2398 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as 2399 // the variable, no memory location needed. 2400 if (align_inst == .none and !nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node)) { 2401 const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{ 2402 .ty = try typeExpr(gz, scope, var_decl.ast.type_node), 2403 } else .none; 2404 const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node); 2405 2406 const sub_scope = try block_arena.create(Scope.LocalVal); 2407 sub_scope.* = .{ 2408 .parent = scope, 2409 .gen_zir = gz, 2410 .name = ident_name, 2411 .inst = init_inst, 2412 .token_src = name_token, 2413 .id_cat = .@"local constant", 2414 }; 2415 return &sub_scope.base; 2416 } 2417 2418 // Detect whether the initialization expression actually uses the 2419 // result location pointer. 2420 var init_scope = gz.makeSubBlock(scope); 2421 defer init_scope.instructions.deinit(gpa); 2422 2423 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 2424 var opt_type_inst: Zir.Inst.Ref = .none; 2425 if (var_decl.ast.type_node != 0) { 2426 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node); 2427 opt_type_inst = type_inst; 2428 if (align_inst == .none) { 2429 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); 2430 } else { 2431 init_scope.rl_ptr = try gz.addAllocExtended(.{ 2432 .node = node, 2433 .type_inst = type_inst, 2434 .align_inst = align_inst, 2435 .is_const = true, 2436 .is_comptime = false, 2437 }); 2438 } 2439 init_scope.rl_ty_inst = type_inst; 2440 } else { 2441 const alloc = if (align_inst == .none) 2442 try init_scope.addNode(.alloc_inferred, node) 2443 else 2444 try gz.addAllocExtended(.{ 2445 .node = node, 2446 .type_inst = .none, 2447 .align_inst = align_inst, 2448 .is_const = true, 2449 .is_comptime = false, 2450 }); 2451 resolve_inferred_alloc = alloc; 2452 init_scope.rl_ptr = alloc; 2453 } 2454 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope }; 2455 const init_inst = try reachableExpr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node, node); 2456 2457 const zir_tags = astgen.instructions.items(.tag); 2458 const zir_datas = astgen.instructions.items(.data); 2459 2460 const parent_zir = &gz.instructions; 2461 if (align_inst == .none and init_scope.rvalue_rl_count == 1) { 2462 // Result location pointer not used. We don't need an alloc for this 2463 // const local, and type inference becomes trivial. 2464 // Move the init_scope instructions into the parent scope, eliding 2465 // the alloc instruction and the store_to_block_ptr instruction. 2466 try parent_zir.ensureUnusedCapacity(gpa, init_scope.instructions.items.len); 2467 for (init_scope.instructions.items) |src_inst| { 2468 if (indexToRef(src_inst) == init_scope.rl_ptr) continue; 2469 if (zir_tags[src_inst] == .store_to_block_ptr) { 2470 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue; 2471 } 2472 parent_zir.appendAssumeCapacity(src_inst); 2473 } 2474 2475 const sub_scope = try block_arena.create(Scope.LocalVal); 2476 sub_scope.* = .{ 2477 .parent = scope, 2478 .gen_zir = gz, 2479 .name = ident_name, 2480 .inst = init_inst, 2481 .token_src = name_token, 2482 .id_cat = .@"local constant", 2483 }; 2484 return &sub_scope.base; 2485 } 2486 // The initialization expression took advantage of the result location 2487 // of the const local. In this case we will create an alloc and a LocalPtr for it. 2488 // Move the init_scope instructions into the parent scope, swapping 2489 // store_to_block_ptr for store_to_inferred_ptr. 2490 const expected_len = parent_zir.items.len + init_scope.instructions.items.len; 2491 try parent_zir.ensureTotalCapacity(gpa, expected_len); 2492 for (init_scope.instructions.items) |src_inst| { 2493 if (zir_tags[src_inst] == .store_to_block_ptr) { 2494 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { 2495 zir_tags[src_inst] = .store_to_inferred_ptr; 2496 } 2497 } 2498 parent_zir.appendAssumeCapacity(src_inst); 2499 } 2500 assert(parent_zir.items.len == expected_len); 2501 if (resolve_inferred_alloc != .none) { 2502 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 2503 } 2504 const sub_scope = try block_arena.create(Scope.LocalPtr); 2505 sub_scope.* = .{ 2506 .parent = scope, 2507 .gen_zir = gz, 2508 .name = ident_name, 2509 .ptr = init_scope.rl_ptr, 2510 .token_src = name_token, 2511 .maybe_comptime = true, 2512 .id_cat = .@"local constant", 2513 }; 2514 return &sub_scope.base; 2515 }, 2516 .keyword_var => { 2517 const is_comptime = var_decl.comptime_token != null or gz.force_comptime; 2518 var resolve_inferred_alloc: Zir.Inst.Ref = .none; 2519 const var_data: struct { 2520 result_loc: ResultLoc, 2521 alloc: Zir.Inst.Ref, 2522 } = if (var_decl.ast.type_node != 0) a: { 2523 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); 2524 const alloc = alloc: { 2525 if (align_inst == .none) { 2526 const tag: Zir.Inst.Tag = if (is_comptime) .alloc_comptime else .alloc_mut; 2527 break :alloc try gz.addUnNode(tag, type_inst, node); 2528 } else { 2529 break :alloc try gz.addAllocExtended(.{ 2530 .node = node, 2531 .type_inst = type_inst, 2532 .align_inst = align_inst, 2533 .is_const = false, 2534 .is_comptime = is_comptime, 2535 }); 2536 } 2537 }; 2538 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; 2539 } else a: { 2540 const alloc = alloc: { 2541 if (align_inst == .none) { 2542 const tag: Zir.Inst.Tag = if (is_comptime) .alloc_inferred_comptime else .alloc_inferred_mut; 2543 break :alloc try gz.addNode(tag, node); 2544 } else { 2545 break :alloc try gz.addAllocExtended(.{ 2546 .node = node, 2547 .type_inst = .none, 2548 .align_inst = align_inst, 2549 .is_const = false, 2550 .is_comptime = is_comptime, 2551 }); 2552 } 2553 }; 2554 resolve_inferred_alloc = alloc; 2555 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } }; 2556 }; 2557 _ = try reachableExpr(gz, scope, var_data.result_loc, var_decl.ast.init_node, node); 2558 if (resolve_inferred_alloc != .none) { 2559 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); 2560 } 2561 const sub_scope = try block_arena.create(Scope.LocalPtr); 2562 sub_scope.* = .{ 2563 .parent = scope, 2564 .gen_zir = gz, 2565 .name = ident_name, 2566 .ptr = var_data.alloc, 2567 .token_src = name_token, 2568 .maybe_comptime = is_comptime, 2569 .id_cat = .@"local variable", 2570 }; 2571 return &sub_scope.base; 2572 }, 2573 else => unreachable, 2574 } 2575 } 2576 2577 fn emitDbgNode(gz: *GenZir, node: ast.Node.Index) !void { 2578 // The instruction emitted here is for debugging runtime code. 2579 // If the current block will be evaluated only during semantic analysis 2580 // then no dbg_stmt ZIR instruction is needed. 2581 if (gz.force_comptime) return; 2582 2583 const astgen = gz.astgen; 2584 const tree = astgen.tree; 2585 const source = tree.source; 2586 const token_starts = tree.tokens.items(.start); 2587 const node_start = token_starts[tree.firstToken(node)]; 2588 2589 astgen.advanceSourceCursor(source, node_start); 2590 const line = @intCast(u32, astgen.source_line); 2591 const column = @intCast(u32, astgen.source_column); 2592 2593 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ 2594 .dbg_stmt = .{ 2595 .line = line, 2596 .column = column, 2597 }, 2598 } }); 2599 } 2600 2601 fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void { 2602 try emitDbgNode(gz, infix_node); 2603 const astgen = gz.astgen; 2604 const tree = astgen.tree; 2605 const node_datas = tree.nodes.items(.data); 2606 const main_tokens = tree.nodes.items(.main_token); 2607 const node_tags = tree.nodes.items(.tag); 2608 2609 const lhs = node_datas[infix_node].lhs; 2610 const rhs = node_datas[infix_node].rhs; 2611 if (node_tags[lhs] == .identifier) { 2612 // This intentionally does not support `@"_"` syntax. 2613 const ident_name = tree.tokenSlice(main_tokens[lhs]); 2614 if (mem.eql(u8, ident_name, "_")) { 2615 _ = try expr(gz, scope, .discard, rhs); 2616 return; 2617 } 2618 } 2619 const lvalue = try lvalExpr(gz, scope, lhs); 2620 _ = try expr(gz, scope, .{ .ptr = lvalue }, rhs); 2621 } 2622 2623 fn assignOp( 2624 gz: *GenZir, 2625 scope: *Scope, 2626 infix_node: ast.Node.Index, 2627 op_inst_tag: Zir.Inst.Tag, 2628 ) InnerError!void { 2629 try emitDbgNode(gz, infix_node); 2630 const astgen = gz.astgen; 2631 const tree = astgen.tree; 2632 const node_datas = tree.nodes.items(.data); 2633 2634 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 2635 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 2636 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node); 2637 const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs); 2638 2639 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 2640 .lhs = lhs, 2641 .rhs = rhs, 2642 }); 2643 _ = try gz.addBin(.store, lhs_ptr, result); 2644 } 2645 2646 fn assignShift( 2647 gz: *GenZir, 2648 scope: *Scope, 2649 infix_node: ast.Node.Index, 2650 op_inst_tag: Zir.Inst.Tag, 2651 ) InnerError!void { 2652 try emitDbgNode(gz, infix_node); 2653 const astgen = gz.astgen; 2654 const tree = astgen.tree; 2655 const node_datas = tree.nodes.items(.data); 2656 2657 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs); 2658 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node); 2659 const rhs_type = try gz.addUnNode(.typeof_log2_int_type, lhs, infix_node); 2660 const rhs = try expr(gz, scope, .{ .ty = rhs_type }, node_datas[infix_node].rhs); 2661 2662 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{ 2663 .lhs = lhs, 2664 .rhs = rhs, 2665 }); 2666 _ = try gz.addBin(.store, lhs_ptr, result); 2667 } 2668 2669 fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 2670 const astgen = gz.astgen; 2671 const tree = astgen.tree; 2672 const node_datas = tree.nodes.items(.data); 2673 2674 const operand = try expr(gz, scope, bool_rl, node_datas[node].lhs); 2675 const result = try gz.addUnNode(.bool_not, operand, node); 2676 return rvalue(gz, rl, result, node); 2677 } 2678 2679 fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 2680 const astgen = gz.astgen; 2681 const tree = astgen.tree; 2682 const node_datas = tree.nodes.items(.data); 2683 2684 const operand = try expr(gz, scope, .none, node_datas[node].lhs); 2685 const result = try gz.addUnNode(.bit_not, operand, node); 2686 return rvalue(gz, rl, result, node); 2687 } 2688 2689 fn negation( 2690 gz: *GenZir, 2691 scope: *Scope, 2692 rl: ResultLoc, 2693 node: ast.Node.Index, 2694 tag: Zir.Inst.Tag, 2695 ) InnerError!Zir.Inst.Ref { 2696 const astgen = gz.astgen; 2697 const tree = astgen.tree; 2698 const node_datas = tree.nodes.items(.data); 2699 2700 const operand = try expr(gz, scope, .none, node_datas[node].lhs); 2701 const result = try gz.addUnNode(tag, operand, node); 2702 return rvalue(gz, rl, result, node); 2703 } 2704 2705 fn ptrType( 2706 gz: *GenZir, 2707 scope: *Scope, 2708 rl: ResultLoc, 2709 node: ast.Node.Index, 2710 ptr_info: ast.full.PtrType, 2711 ) InnerError!Zir.Inst.Ref { 2712 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); 2713 2714 const simple = ptr_info.ast.align_node == 0 and 2715 ptr_info.ast.sentinel == 0 and 2716 ptr_info.ast.bit_range_start == 0; 2717 2718 if (simple) { 2719 const result = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 2720 .ptr_type_simple = .{ 2721 .is_allowzero = ptr_info.allowzero_token != null, 2722 .is_mutable = ptr_info.const_token == null, 2723 .is_volatile = ptr_info.volatile_token != null, 2724 .size = ptr_info.size, 2725 .elem_type = elem_type, 2726 }, 2727 } }); 2728 return rvalue(gz, rl, result, node); 2729 } 2730 2731 var sentinel_ref: Zir.Inst.Ref = .none; 2732 var align_ref: Zir.Inst.Ref = .none; 2733 var bit_start_ref: Zir.Inst.Ref = .none; 2734 var bit_end_ref: Zir.Inst.Ref = .none; 2735 var trailing_count: u32 = 0; 2736 2737 if (ptr_info.ast.sentinel != 0) { 2738 sentinel_ref = try expr(gz, scope, .{ .ty = elem_type }, ptr_info.ast.sentinel); 2739 trailing_count += 1; 2740 } 2741 if (ptr_info.ast.align_node != 0) { 2742 align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node); 2743 trailing_count += 1; 2744 } 2745 if (ptr_info.ast.bit_range_start != 0) { 2746 assert(ptr_info.ast.bit_range_end != 0); 2747 bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start); 2748 bit_end_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_end); 2749 trailing_count += 2; 2750 } 2751 2752 const gpa = gz.astgen.gpa; 2753 try gz.instructions.ensureUnusedCapacity(gpa, 1); 2754 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 2755 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len + 2756 trailing_count); 2757 2758 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type }); 2759 if (sentinel_ref != .none) { 2760 gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref)); 2761 } 2762 if (align_ref != .none) { 2763 gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref)); 2764 } 2765 if (bit_start_ref != .none) { 2766 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref)); 2767 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref)); 2768 } 2769 2770 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 2771 const result = indexToRef(new_index); 2772 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{ 2773 .ptr_type = .{ 2774 .flags = .{ 2775 .is_allowzero = ptr_info.allowzero_token != null, 2776 .is_mutable = ptr_info.const_token == null, 2777 .is_volatile = ptr_info.volatile_token != null, 2778 .has_sentinel = sentinel_ref != .none, 2779 .has_align = align_ref != .none, 2780 .has_bit_range = bit_start_ref != .none, 2781 }, 2782 .size = ptr_info.size, 2783 .payload_index = payload_index, 2784 }, 2785 } }); 2786 gz.instructions.appendAssumeCapacity(new_index); 2787 2788 return rvalue(gz, rl, result, node); 2789 } 2790 2791 fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { 2792 const astgen = gz.astgen; 2793 const tree = astgen.tree; 2794 const node_datas = tree.nodes.items(.data); 2795 const node_tags = tree.nodes.items(.tag); 2796 const main_tokens = tree.nodes.items(.main_token); 2797 2798 const len_node = node_datas[node].lhs; 2799 if (node_tags[len_node] == .identifier and 2800 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 2801 { 2802 return astgen.failNode(len_node, "unable to infer array size", .{}); 2803 } 2804 const len = try expr(gz, scope, .{ .coerced_ty = .usize_type }, len_node); 2805 const elem_type = try typeExpr(gz, scope, node_datas[node].rhs); 2806 2807 const result = try gz.addBin(.array_type, len, elem_type); 2808 return rvalue(gz, rl, result, node); 2809 } 2810 2811 fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { 2812 const astgen = gz.astgen; 2813 const tree = astgen.tree; 2814 const node_datas = tree.nodes.items(.data); 2815 const node_tags = tree.nodes.items(.tag); 2816 const main_tokens = tree.nodes.items(.main_token); 2817 const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel); 2818 2819 const len_node = node_datas[node].lhs; 2820 if (node_tags[len_node] == .identifier and 2821 mem.eql(u8, tree.tokenSlice(main_tokens[len_node]), "_")) 2822 { 2823 return astgen.failNode(len_node, "unable to infer array size", .{}); 2824 } 2825 const len = try expr(gz, scope, .{ .coerced_ty = .usize_type }, len_node); 2826 const elem_type = try typeExpr(gz, scope, extra.elem_type); 2827 const sentinel = try expr(gz, scope, .{ .coerced_ty = elem_type }, extra.sentinel); 2828 2829 const result = try gz.addArrayTypeSentinel(len, elem_type, sentinel); 2830 return rvalue(gz, rl, result, node); 2831 } 2832 2833 const WipDecls = struct { 2834 decl_index: usize = 0, 2835 cur_bit_bag: u32 = 0, 2836 bit_bag: ArrayListUnmanaged(u32) = .{}, 2837 payload: ArrayListUnmanaged(u32) = .{}, 2838 2839 const bits_per_field = 4; 2840 const fields_per_u32 = 32 / bits_per_field; 2841 2842 fn next( 2843 wip_decls: *WipDecls, 2844 gpa: *Allocator, 2845 is_pub: bool, 2846 is_export: bool, 2847 has_align: bool, 2848 has_section: bool, 2849 ) Allocator.Error!void { 2850 if (wip_decls.decl_index % fields_per_u32 == 0 and wip_decls.decl_index != 0) { 2851 try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag); 2852 wip_decls.cur_bit_bag = 0; 2853 } 2854 wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> bits_per_field) | 2855 (@as(u32, @boolToInt(is_pub)) << 28) | 2856 (@as(u32, @boolToInt(is_export)) << 29) | 2857 (@as(u32, @boolToInt(has_align)) << 30) | 2858 (@as(u32, @boolToInt(has_section)) << 31); 2859 wip_decls.decl_index += 1; 2860 } 2861 2862 fn deinit(wip_decls: *WipDecls, gpa: *Allocator) void { 2863 wip_decls.bit_bag.deinit(gpa); 2864 wip_decls.payload.deinit(gpa); 2865 } 2866 }; 2867 2868 fn fnDecl( 2869 astgen: *AstGen, 2870 gz: *GenZir, 2871 scope: *Scope, 2872 wip_decls: *WipDecls, 2873 decl_node: ast.Node.Index, 2874 body_node: ast.Node.Index, 2875 fn_proto: ast.full.FnProto, 2876 ) InnerError!void { 2877 const gpa = astgen.gpa; 2878 const tree = astgen.tree; 2879 const token_tags = tree.tokens.items(.tag); 2880 2881 const fn_name_token = fn_proto.name_token orelse { 2882 return astgen.failTok(fn_proto.ast.fn_token, "missing function name", .{}); 2883 }; 2884 const fn_name_str_index = try astgen.identAsString(fn_name_token); 2885 2886 // We insert this at the beginning so that its instruction index marks the 2887 // start of the top level declaration. 2888 const block_inst = try gz.addBlock(.block_inline, fn_proto.ast.proto_node); 2889 2890 var decl_gz: GenZir = .{ 2891 .force_comptime = true, 2892 .in_defer = false, 2893 .decl_node_index = fn_proto.ast.proto_node, 2894 .decl_line = gz.calcLine(decl_node), 2895 .parent = scope, 2896 .astgen = astgen, 2897 }; 2898 defer decl_gz.instructions.deinit(gpa); 2899 2900 var fn_gz: GenZir = .{ 2901 .force_comptime = false, 2902 .in_defer = false, 2903 .decl_node_index = fn_proto.ast.proto_node, 2904 .decl_line = decl_gz.decl_line, 2905 .parent = &decl_gz.base, 2906 .astgen = astgen, 2907 }; 2908 defer fn_gz.instructions.deinit(gpa); 2909 2910 // TODO: support noinline 2911 const is_pub = fn_proto.visib_token != null; 2912 const is_export = blk: { 2913 const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false; 2914 break :blk token_tags[maybe_export_token] == .keyword_export; 2915 }; 2916 const is_extern = blk: { 2917 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; 2918 break :blk token_tags[maybe_extern_token] == .keyword_extern; 2919 }; 2920 const has_inline_keyword = blk: { 2921 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false; 2922 break :blk token_tags[maybe_inline_token] == .keyword_inline; 2923 }; 2924 try wip_decls.next(gpa, is_pub, is_export, fn_proto.ast.align_expr != 0, fn_proto.ast.section_expr != 0); 2925 2926 var params_scope = &fn_gz.base; 2927 const is_var_args = is_var_args: { 2928 var param_type_i: usize = 0; 2929 var it = fn_proto.iterate(tree.*); 2930 while (it.next()) |param| : (param_type_i += 1) { 2931 const is_comptime = if (param.comptime_noalias) |token| 2932 token_tags[token] == .keyword_comptime 2933 else 2934 false; 2935 2936 const is_anytype = if (param.anytype_ellipsis3) |token| blk: { 2937 switch (token_tags[token]) { 2938 .keyword_anytype => break :blk true, 2939 .ellipsis3 => break :is_var_args true, 2940 else => unreachable, 2941 } 2942 } else false; 2943 2944 const param_name: u32 = if (param.name_token) |name_token| blk: { 2945 const name_bytes = tree.tokenSlice(name_token); 2946 if (mem.eql(u8, "_", name_bytes)) 2947 break :blk 0; 2948 2949 const param_name = try astgen.identAsString(name_token); 2950 if (!is_extern) { 2951 try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes); 2952 } 2953 break :blk param_name; 2954 } else if (!is_extern) { 2955 if (param.anytype_ellipsis3) |tok| { 2956 return astgen.failTok(tok, "missing parameter name", .{}); 2957 } else { 2958 return astgen.failNode(param.type_expr, "missing parameter name", .{}); 2959 } 2960 } else 0; 2961 2962 const param_inst = if (is_anytype) param: { 2963 const name_token = param.name_token orelse param.anytype_ellipsis3.?; 2964 const tag: Zir.Inst.Tag = if (is_comptime) 2965 .param_anytype_comptime 2966 else 2967 .param_anytype; 2968 break :param try decl_gz.addStrTok(tag, param_name, name_token); 2969 } else param: { 2970 const param_type_node = param.type_expr; 2971 assert(param_type_node != 0); 2972 var param_gz = decl_gz.makeSubBlock(scope); 2973 defer param_gz.instructions.deinit(gpa); 2974 const param_type = try expr(¶m_gz, params_scope, coerced_type_rl, param_type_node); 2975 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); 2976 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); 2977 2978 const main_tokens = tree.nodes.items(.main_token); 2979 const name_token = param.name_token orelse main_tokens[param_type_node]; 2980 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; 2981 const param_inst = try decl_gz.addParam(tag, name_token, param_name, param_gz.instructions.items); 2982 assert(param_inst_expected == param_inst); 2983 break :param indexToRef(param_inst); 2984 }; 2985 2986 if (param_name == 0) continue; 2987 2988 const sub_scope = try astgen.arena.create(Scope.LocalVal); 2989 sub_scope.* = .{ 2990 .parent = params_scope, 2991 .gen_zir = &decl_gz, 2992 .name = param_name, 2993 .inst = param_inst, 2994 .token_src = param.name_token.?, 2995 .id_cat = .@"function parameter", 2996 }; 2997 params_scope = &sub_scope.base; 2998 } 2999 break :is_var_args false; 3000 }; 3001 3002 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: { 3003 const lib_name_str = try astgen.strLitAsString(lib_name_token); 3004 break :blk lib_name_str.index; 3005 } else 0; 3006 3007 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; 3008 const is_inferred_error = token_tags[maybe_bang] == .bang; 3009 3010 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { 3011 break :inst try expr(&decl_gz, params_scope, align_rl, fn_proto.ast.align_expr); 3012 }; 3013 const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { 3014 break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr); 3015 }; 3016 3017 var ret_gz = decl_gz.makeSubBlock(params_scope); 3018 defer ret_gz.instructions.deinit(gpa); 3019 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type); 3020 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty); 3021 3022 const cc: Zir.Inst.Ref = blk: { 3023 if (fn_proto.ast.callconv_expr != 0) { 3024 if (has_inline_keyword) { 3025 return astgen.failNode( 3026 fn_proto.ast.callconv_expr, 3027 "explicit callconv incompatible with inline keyword", 3028 .{}, 3029 ); 3030 } 3031 break :blk try expr( 3032 &decl_gz, 3033 params_scope, 3034 .{ .ty = .calling_convention_type }, 3035 fn_proto.ast.callconv_expr, 3036 ); 3037 } else if (is_extern) { 3038 // note: https://github.com/ziglang/zig/issues/5269 3039 break :blk .calling_convention_c; 3040 } else if (has_inline_keyword) { 3041 break :blk .calling_convention_inline; 3042 } else { 3043 break :blk .none; 3044 } 3045 }; 3046 3047 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { 3048 if (!is_extern) { 3049 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{}); 3050 } 3051 if (is_inferred_error) { 3052 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); 3053 } 3054 break :func try decl_gz.addFunc(.{ 3055 .src_node = decl_node, 3056 .ret_ty = ret_gz.instructions.items, 3057 .ret_br = ret_br, 3058 .param_block = block_inst, 3059 .body = &[0]Zir.Inst.Index{}, 3060 .cc = cc, 3061 .align_inst = .none, // passed in the per-decl data 3062 .lib_name = lib_name, 3063 .is_var_args = is_var_args, 3064 .is_inferred_error = false, 3065 .is_test = false, 3066 .is_extern = true, 3067 }); 3068 } else func: { 3069 if (is_var_args) { 3070 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); 3071 } 3072 3073 const prev_fn_block = astgen.fn_block; 3074 astgen.fn_block = &fn_gz; 3075 defer astgen.fn_block = prev_fn_block; 3076 3077 _ = try expr(&fn_gz, params_scope, .none, body_node); 3078 try checkUsed(gz, &fn_gz.base, params_scope); 3079 3080 const need_implicit_ret = blk: { 3081 if (fn_gz.instructions.items.len == 0) 3082 break :blk true; 3083 const last = fn_gz.instructions.items[fn_gz.instructions.items.len - 1]; 3084 const zir_tags = astgen.instructions.items(.tag); 3085 break :blk !zir_tags[last].isNoReturn(); 3086 }; 3087 if (need_implicit_ret) { 3088 // Since we are adding the return instruction here, we must handle the coercion. 3089 // We do this by using the `ret_coerce` instruction. 3090 _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node)); 3091 } 3092 3093 break :func try decl_gz.addFunc(.{ 3094 .src_node = decl_node, 3095 .param_block = block_inst, 3096 .ret_ty = ret_gz.instructions.items, 3097 .ret_br = ret_br, 3098 .body = fn_gz.instructions.items, 3099 .cc = cc, 3100 .align_inst = .none, // passed in the per-decl data 3101 .lib_name = lib_name, 3102 .is_var_args = is_var_args, 3103 .is_inferred_error = is_inferred_error, 3104 .is_test = false, 3105 .is_extern = false, 3106 }); 3107 }; 3108 3109 // We add this at the end so that its instruction index marks the end range 3110 // of the top level declaration. 3111 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); 3112 try decl_gz.setBlockBody(block_inst); 3113 3114 try wip_decls.payload.ensureUnusedCapacity(gpa, 9); 3115 { 3116 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); 3117 const casted = @bitCast([4]u32, contents_hash); 3118 wip_decls.payload.appendSliceAssumeCapacity(&casted); 3119 } 3120 { 3121 const line_delta = decl_gz.decl_line - gz.decl_line; 3122 wip_decls.payload.appendAssumeCapacity(line_delta); 3123 } 3124 wip_decls.payload.appendAssumeCapacity(fn_name_str_index); 3125 wip_decls.payload.appendAssumeCapacity(block_inst); 3126 if (align_inst != .none) { 3127 wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); 3128 } 3129 if (section_inst != .none) { 3130 wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); 3131 } 3132 } 3133 3134 fn globalVarDecl( 3135 astgen: *AstGen, 3136 gz: *GenZir, 3137 scope: *Scope, 3138 wip_decls: *WipDecls, 3139 node: ast.Node.Index, 3140 var_decl: ast.full.VarDecl, 3141 ) InnerError!void { 3142 const gpa = astgen.gpa; 3143 const tree = astgen.tree; 3144 const token_tags = tree.tokens.items(.tag); 3145 3146 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; 3147 // We do this at the beginning so that the instruction index marks the range start 3148 // of the top level declaration. 3149 const block_inst = try gz.addBlock(.block_inline, node); 3150 3151 const name_token = var_decl.ast.mut_token + 1; 3152 const name_str_index = try astgen.identAsString(name_token); 3153 3154 var block_scope: GenZir = .{ 3155 .parent = scope, 3156 .decl_node_index = node, 3157 .decl_line = gz.calcLine(node), 3158 .astgen = astgen, 3159 .force_comptime = true, 3160 .in_defer = false, 3161 .anon_name_strategy = .parent, 3162 }; 3163 defer block_scope.instructions.deinit(gpa); 3164 3165 const is_pub = var_decl.visib_token != null; 3166 const is_export = blk: { 3167 const maybe_export_token = var_decl.extern_export_token orelse break :blk false; 3168 break :blk token_tags[maybe_export_token] == .keyword_export; 3169 }; 3170 const is_extern = blk: { 3171 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; 3172 break :blk token_tags[maybe_extern_token] == .keyword_extern; 3173 }; 3174 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: { 3175 break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node); 3176 }; 3177 const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { 3178 break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node); 3179 }; 3180 try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none); 3181 3182 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: { 3183 if (!is_mutable) { 3184 return astgen.failTok(tok, "threadlocal variable cannot be constant", .{}); 3185 } 3186 break :blk true; 3187 } else false; 3188 3189 const lib_name: u32 = if (var_decl.lib_name) |lib_name_token| blk: { 3190 const lib_name_str = try astgen.strLitAsString(lib_name_token); 3191 break :blk lib_name_str.index; 3192 } else 0; 3193 3194 assert(var_decl.comptime_token == null); // handled by parser 3195 3196 const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: { 3197 if (is_extern) { 3198 return astgen.failNode( 3199 var_decl.ast.init_node, 3200 "extern variables have no initializers", 3201 .{}, 3202 ); 3203 } 3204 3205 const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0) 3206 try expr( 3207 &block_scope, 3208 &block_scope.base, 3209 .{ .ty = .type_type }, 3210 var_decl.ast.type_node, 3211 ) 3212 else 3213 .none; 3214 3215 const init_inst = try expr( 3216 &block_scope, 3217 &block_scope.base, 3218 if (type_inst != .none) .{ .ty = type_inst } else .none, 3219 var_decl.ast.init_node, 3220 ); 3221 3222 if (is_mutable) { 3223 const var_inst = try block_scope.addVar(.{ 3224 .var_type = type_inst, 3225 .lib_name = 0, 3226 .align_inst = .none, // passed via the decls data 3227 .init = init_inst, 3228 .is_extern = false, 3229 .is_threadlocal = is_threadlocal, 3230 }); 3231 break :vi var_inst; 3232 } else { 3233 break :vi init_inst; 3234 } 3235 } else if (!is_extern) { 3236 return astgen.failNode(node, "variables must be initialized", .{}); 3237 } else if (var_decl.ast.type_node != 0) vi: { 3238 // Extern variable which has an explicit type. 3239 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node); 3240 3241 const var_inst = try block_scope.addVar(.{ 3242 .var_type = type_inst, 3243 .lib_name = lib_name, 3244 .align_inst = .none, // passed via the decls data 3245 .init = .none, 3246 .is_extern = true, 3247 .is_threadlocal = is_threadlocal, 3248 }); 3249 break :vi var_inst; 3250 } else { 3251 return astgen.failNode(node, "unable to infer variable type", .{}); 3252 }; 3253 // We do this at the end so that the instruction index marks the end 3254 // range of a top level declaration. 3255 _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); 3256 try block_scope.setBlockBody(block_inst); 3257 3258 try wip_decls.payload.ensureUnusedCapacity(gpa, 9); 3259 { 3260 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3261 const casted = @bitCast([4]u32, contents_hash); 3262 wip_decls.payload.appendSliceAssumeCapacity(&casted); 3263 } 3264 { 3265 const line_delta = block_scope.decl_line - gz.decl_line; 3266 wip_decls.payload.appendAssumeCapacity(line_delta); 3267 } 3268 wip_decls.payload.appendAssumeCapacity(name_str_index); 3269 wip_decls.payload.appendAssumeCapacity(block_inst); 3270 if (align_inst != .none) { 3271 wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); 3272 } 3273 if (section_inst != .none) { 3274 wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); 3275 } 3276 } 3277 3278 fn comptimeDecl( 3279 astgen: *AstGen, 3280 gz: *GenZir, 3281 scope: *Scope, 3282 wip_decls: *WipDecls, 3283 node: ast.Node.Index, 3284 ) InnerError!void { 3285 const gpa = astgen.gpa; 3286 const tree = astgen.tree; 3287 const node_datas = tree.nodes.items(.data); 3288 const body_node = node_datas[node].lhs; 3289 3290 // Up top so the ZIR instruction index marks the start range of this 3291 // top-level declaration. 3292 const block_inst = try gz.addBlock(.block_inline, node); 3293 try wip_decls.next(gpa, false, false, false, false); 3294 3295 var decl_block: GenZir = .{ 3296 .force_comptime = true, 3297 .in_defer = false, 3298 .decl_node_index = node, 3299 .decl_line = gz.calcLine(node), 3300 .parent = scope, 3301 .astgen = astgen, 3302 }; 3303 defer decl_block.instructions.deinit(gpa); 3304 3305 const block_result = try expr(&decl_block, &decl_block.base, .none, body_node); 3306 if (decl_block.instructions.items.len == 0 or !decl_block.refIsNoReturn(block_result)) { 3307 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value); 3308 } 3309 try decl_block.setBlockBody(block_inst); 3310 3311 try wip_decls.payload.ensureUnusedCapacity(gpa, 7); 3312 { 3313 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3314 const casted = @bitCast([4]u32, contents_hash); 3315 wip_decls.payload.appendSliceAssumeCapacity(&casted); 3316 } 3317 { 3318 const line_delta = decl_block.decl_line - gz.decl_line; 3319 wip_decls.payload.appendAssumeCapacity(line_delta); 3320 } 3321 wip_decls.payload.appendAssumeCapacity(0); 3322 wip_decls.payload.appendAssumeCapacity(block_inst); 3323 } 3324 3325 fn usingnamespaceDecl( 3326 astgen: *AstGen, 3327 gz: *GenZir, 3328 scope: *Scope, 3329 wip_decls: *WipDecls, 3330 node: ast.Node.Index, 3331 ) InnerError!void { 3332 const gpa = astgen.gpa; 3333 const tree = astgen.tree; 3334 const node_datas = tree.nodes.items(.data); 3335 3336 const type_expr = node_datas[node].lhs; 3337 const is_pub = blk: { 3338 const main_tokens = tree.nodes.items(.main_token); 3339 const token_tags = tree.tokens.items(.tag); 3340 const main_token = main_tokens[node]; 3341 break :blk (main_token > 0 and token_tags[main_token - 1] == .keyword_pub); 3342 }; 3343 // Up top so the ZIR instruction index marks the start range of this 3344 // top-level declaration. 3345 const block_inst = try gz.addBlock(.block_inline, node); 3346 try wip_decls.next(gpa, is_pub, true, false, false); 3347 3348 var decl_block: GenZir = .{ 3349 .force_comptime = true, 3350 .in_defer = false, 3351 .decl_node_index = node, 3352 .decl_line = gz.calcLine(node), 3353 .parent = scope, 3354 .astgen = astgen, 3355 }; 3356 defer decl_block.instructions.deinit(gpa); 3357 3358 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr); 3359 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst); 3360 try decl_block.setBlockBody(block_inst); 3361 3362 try wip_decls.payload.ensureUnusedCapacity(gpa, 7); 3363 { 3364 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3365 const casted = @bitCast([4]u32, contents_hash); 3366 wip_decls.payload.appendSliceAssumeCapacity(&casted); 3367 } 3368 { 3369 const line_delta = decl_block.decl_line - gz.decl_line; 3370 wip_decls.payload.appendAssumeCapacity(line_delta); 3371 } 3372 wip_decls.payload.appendAssumeCapacity(0); 3373 wip_decls.payload.appendAssumeCapacity(block_inst); 3374 } 3375 3376 fn testDecl( 3377 astgen: *AstGen, 3378 gz: *GenZir, 3379 scope: *Scope, 3380 wip_decls: *WipDecls, 3381 node: ast.Node.Index, 3382 ) InnerError!void { 3383 const gpa = astgen.gpa; 3384 const tree = astgen.tree; 3385 const node_datas = tree.nodes.items(.data); 3386 const body_node = node_datas[node].rhs; 3387 3388 // Up top so the ZIR instruction index marks the start range of this 3389 // top-level declaration. 3390 const block_inst = try gz.addBlock(.block_inline, node); 3391 3392 try wip_decls.next(gpa, false, false, false, false); 3393 3394 var decl_block: GenZir = .{ 3395 .force_comptime = true, 3396 .in_defer = false, 3397 .decl_node_index = node, 3398 .decl_line = gz.calcLine(node), 3399 .parent = scope, 3400 .astgen = astgen, 3401 }; 3402 defer decl_block.instructions.deinit(gpa); 3403 3404 const test_name: u32 = blk: { 3405 const main_tokens = tree.nodes.items(.main_token); 3406 const token_tags = tree.tokens.items(.tag); 3407 const test_token = main_tokens[node]; 3408 const str_lit_token = test_token + 1; 3409 if (token_tags[str_lit_token] == .string_literal) { 3410 break :blk try astgen.testNameString(str_lit_token); 3411 } 3412 // String table index 1 has a special meaning here of test decl with no name. 3413 break :blk 1; 3414 }; 3415 3416 var fn_block: GenZir = .{ 3417 .force_comptime = false, 3418 .in_defer = false, 3419 .decl_node_index = node, 3420 .decl_line = decl_block.decl_line, 3421 .parent = &decl_block.base, 3422 .astgen = astgen, 3423 }; 3424 defer fn_block.instructions.deinit(gpa); 3425 3426 const prev_fn_block = astgen.fn_block; 3427 astgen.fn_block = &fn_block; 3428 defer astgen.fn_block = prev_fn_block; 3429 3430 const block_result = try expr(&fn_block, &fn_block.base, .none, body_node); 3431 if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) { 3432 // Since we are adding the return instruction here, we must handle the coercion. 3433 // We do this by using the `ret_coerce` instruction. 3434 _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node)); 3435 } 3436 3437 const func_inst = try decl_block.addFunc(.{ 3438 .src_node = node, 3439 .param_block = block_inst, 3440 .ret_ty = &.{}, 3441 .ret_br = 0, 3442 .body = fn_block.instructions.items, 3443 .cc = .none, 3444 .align_inst = .none, 3445 .lib_name = 0, 3446 .is_var_args = false, 3447 .is_inferred_error = true, 3448 .is_test = true, 3449 .is_extern = false, 3450 }); 3451 3452 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); 3453 try decl_block.setBlockBody(block_inst); 3454 3455 try wip_decls.payload.ensureUnusedCapacity(gpa, 7); 3456 { 3457 const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); 3458 const casted = @bitCast([4]u32, contents_hash); 3459 wip_decls.payload.appendSliceAssumeCapacity(&casted); 3460 } 3461 { 3462 const line_delta = decl_block.decl_line - gz.decl_line; 3463 wip_decls.payload.appendAssumeCapacity(line_delta); 3464 } 3465 wip_decls.payload.appendAssumeCapacity(test_name); 3466 wip_decls.payload.appendAssumeCapacity(block_inst); 3467 } 3468 3469 fn structDeclInner( 3470 gz: *GenZir, 3471 scope: *Scope, 3472 node: ast.Node.Index, 3473 container_decl: ast.full.ContainerDecl, 3474 layout: std.builtin.TypeInfo.ContainerLayout, 3475 ) InnerError!Zir.Inst.Ref { 3476 if (container_decl.ast.members.len == 0) { 3477 const decl_inst = try gz.reserveInstructionIndex(); 3478 try gz.setStruct(decl_inst, .{ 3479 .src_node = node, 3480 .layout = layout, 3481 .fields_len = 0, 3482 .body_len = 0, 3483 .decls_len = 0, 3484 .known_has_bits = false, 3485 }); 3486 return indexToRef(decl_inst); 3487 } 3488 3489 const astgen = gz.astgen; 3490 const gpa = astgen.gpa; 3491 const tree = astgen.tree; 3492 const node_tags = tree.nodes.items(.tag); 3493 const node_datas = tree.nodes.items(.data); 3494 3495 // The struct_decl instruction introduces a scope in which the decls of the struct 3496 // are in scope, so that field types, alignments, and default value expressions 3497 // can refer to decls within the struct itself. 3498 var block_scope: GenZir = .{ 3499 .parent = scope, 3500 .decl_node_index = node, 3501 .decl_line = gz.calcLine(node), 3502 .astgen = astgen, 3503 .force_comptime = true, 3504 .in_defer = false, 3505 }; 3506 defer block_scope.instructions.deinit(gpa); 3507 3508 var namespace: Scope.Namespace = .{ .parent = scope, .node = node }; 3509 defer namespace.decls.deinit(gpa); 3510 3511 try astgen.scanDecls(&namespace, container_decl.ast.members); 3512 3513 var wip_decls: WipDecls = .{}; 3514 defer wip_decls.deinit(gpa); 3515 3516 // We don't know which members are fields until we iterate, so cannot do 3517 // an accurate ensureCapacity yet. 3518 var fields_data = ArrayListUnmanaged(u32){}; 3519 defer fields_data.deinit(gpa); 3520 3521 const bits_per_field = 4; 3522 const fields_per_u32 = 32 / bits_per_field; 3523 // We only need this if there are greater than fields_per_u32 fields. 3524 var bit_bag = ArrayListUnmanaged(u32){}; 3525 defer bit_bag.deinit(gpa); 3526 3527 var known_has_bits = false; 3528 var cur_bit_bag: u32 = 0; 3529 var field_index: usize = 0; 3530 for (container_decl.ast.members) |member_node| { 3531 const member = switch (node_tags[member_node]) { 3532 .container_field_init => tree.containerFieldInit(member_node), 3533 .container_field_align => tree.containerFieldAlign(member_node), 3534 .container_field => tree.containerField(member_node), 3535 3536 .fn_decl => { 3537 const fn_proto = node_datas[member_node].lhs; 3538 const body = node_datas[member_node].rhs; 3539 switch (node_tags[fn_proto]) { 3540 .fn_proto_simple => { 3541 var params: [1]ast.Node.Index = undefined; 3542 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { 3543 error.OutOfMemory => return error.OutOfMemory, 3544 error.AnalysisFail => {}, 3545 }; 3546 continue; 3547 }, 3548 .fn_proto_multi => { 3549 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { 3550 error.OutOfMemory => return error.OutOfMemory, 3551 error.AnalysisFail => {}, 3552 }; 3553 continue; 3554 }, 3555 .fn_proto_one => { 3556 var params: [1]ast.Node.Index = undefined; 3557 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { 3558 error.OutOfMemory => return error.OutOfMemory, 3559 error.AnalysisFail => {}, 3560 }; 3561 continue; 3562 }, 3563 .fn_proto => { 3564 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { 3565 error.OutOfMemory => return error.OutOfMemory, 3566 error.AnalysisFail => {}, 3567 }; 3568 continue; 3569 }, 3570 else => unreachable, 3571 } 3572 }, 3573 .fn_proto_simple => { 3574 var params: [1]ast.Node.Index = undefined; 3575 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { 3576 error.OutOfMemory => return error.OutOfMemory, 3577 error.AnalysisFail => {}, 3578 }; 3579 continue; 3580 }, 3581 .fn_proto_multi => { 3582 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { 3583 error.OutOfMemory => return error.OutOfMemory, 3584 error.AnalysisFail => {}, 3585 }; 3586 continue; 3587 }, 3588 .fn_proto_one => { 3589 var params: [1]ast.Node.Index = undefined; 3590 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { 3591 error.OutOfMemory => return error.OutOfMemory, 3592 error.AnalysisFail => {}, 3593 }; 3594 continue; 3595 }, 3596 .fn_proto => { 3597 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { 3598 error.OutOfMemory => return error.OutOfMemory, 3599 error.AnalysisFail => {}, 3600 }; 3601 continue; 3602 }, 3603 3604 .global_var_decl => { 3605 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { 3606 error.OutOfMemory => return error.OutOfMemory, 3607 error.AnalysisFail => {}, 3608 }; 3609 continue; 3610 }, 3611 .local_var_decl => { 3612 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { 3613 error.OutOfMemory => return error.OutOfMemory, 3614 error.AnalysisFail => {}, 3615 }; 3616 continue; 3617 }, 3618 .simple_var_decl => { 3619 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { 3620 error.OutOfMemory => return error.OutOfMemory, 3621 error.AnalysisFail => {}, 3622 }; 3623 continue; 3624 }, 3625 .aligned_var_decl => { 3626 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { 3627 error.OutOfMemory => return error.OutOfMemory, 3628 error.AnalysisFail => {}, 3629 }; 3630 continue; 3631 }, 3632 3633 .@"comptime" => { 3634 astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 3635 error.OutOfMemory => return error.OutOfMemory, 3636 error.AnalysisFail => {}, 3637 }; 3638 continue; 3639 }, 3640 .@"usingnamespace" => { 3641 astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 3642 error.OutOfMemory => return error.OutOfMemory, 3643 error.AnalysisFail => {}, 3644 }; 3645 continue; 3646 }, 3647 .test_decl => { 3648 astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 3649 error.OutOfMemory => return error.OutOfMemory, 3650 error.AnalysisFail => {}, 3651 }; 3652 continue; 3653 }, 3654 else => unreachable, 3655 }; 3656 if (field_index % fields_per_u32 == 0 and field_index != 0) { 3657 try bit_bag.append(gpa, cur_bit_bag); 3658 cur_bit_bag = 0; 3659 } 3660 try fields_data.ensureUnusedCapacity(gpa, 4); 3661 3662 const field_name = try astgen.identAsString(member.ast.name_token); 3663 fields_data.appendAssumeCapacity(field_name); 3664 3665 if (member.ast.type_expr == 0) { 3666 return astgen.failTok(member.ast.name_token, "struct field missing type", .{}); 3667 } 3668 3669 const field_type: Zir.Inst.Ref = if (node_tags[member.ast.type_expr] == .@"anytype") 3670 .none 3671 else 3672 try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 3673 fields_data.appendAssumeCapacity(@enumToInt(field_type)); 3674 3675 known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr); 3676 3677 const have_align = member.ast.align_expr != 0; 3678 const have_value = member.ast.value_expr != 0; 3679 const is_comptime = member.comptime_token != null; 3680 const unused = false; 3681 cur_bit_bag = (cur_bit_bag >> bits_per_field) | 3682 (@as(u32, @boolToInt(have_align)) << 28) | 3683 (@as(u32, @boolToInt(have_value)) << 29) | 3684 (@as(u32, @boolToInt(is_comptime)) << 30) | 3685 (@as(u32, @boolToInt(unused)) << 31); 3686 3687 if (have_align) { 3688 const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr); 3689 fields_data.appendAssumeCapacity(@enumToInt(align_inst)); 3690 } 3691 if (have_value) { 3692 const rl: ResultLoc = if (field_type == .none) .none else .{ .ty = field_type }; 3693 3694 const default_inst = try expr(&block_scope, &namespace.base, rl, member.ast.value_expr); 3695 fields_data.appendAssumeCapacity(@enumToInt(default_inst)); 3696 } else if (member.comptime_token) |comptime_token| { 3697 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{}); 3698 } 3699 3700 field_index += 1; 3701 } 3702 { 3703 const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32); 3704 if (empty_slot_count < fields_per_u32) { 3705 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field); 3706 } 3707 } 3708 { 3709 const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); 3710 if (empty_slot_count < WipDecls.fields_per_u32) { 3711 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); 3712 } 3713 } 3714 3715 const decl_inst = try gz.reserveInstructionIndex(); 3716 if (block_scope.instructions.items.len != 0) { 3717 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 3718 } 3719 3720 try gz.setStruct(decl_inst, .{ 3721 .src_node = node, 3722 .layout = layout, 3723 .body_len = @intCast(u32, block_scope.instructions.items.len), 3724 .fields_len = @intCast(u32, field_index), 3725 .decls_len = @intCast(u32, wip_decls.decl_index), 3726 .known_has_bits = known_has_bits, 3727 }); 3728 3729 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len + 3730 @boolToInt(field_index != 0) + fields_data.items.len + 3731 block_scope.instructions.items.len + 3732 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + 3733 wip_decls.payload.items.len); 3734 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. 3735 if (wip_decls.decl_index != 0) { 3736 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); 3737 } 3738 astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); 3739 3740 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); 3741 3742 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. 3743 if (field_index != 0) { 3744 astgen.extra.appendAssumeCapacity(cur_bit_bag); 3745 } 3746 astgen.extra.appendSliceAssumeCapacity(fields_data.items); 3747 3748 return indexToRef(decl_inst); 3749 } 3750 3751 fn unionDeclInner( 3752 gz: *GenZir, 3753 scope: *Scope, 3754 node: ast.Node.Index, 3755 members: []const ast.Node.Index, 3756 layout: std.builtin.TypeInfo.ContainerLayout, 3757 arg_node: ast.Node.Index, 3758 have_auto_enum: bool, 3759 ) InnerError!Zir.Inst.Ref { 3760 const astgen = gz.astgen; 3761 const gpa = astgen.gpa; 3762 const tree = astgen.tree; 3763 const node_tags = tree.nodes.items(.tag); 3764 const node_datas = tree.nodes.items(.data); 3765 3766 // The union_decl instruction introduces a scope in which the decls of the union 3767 // are in scope, so that field types, alignments, and default value expressions 3768 // can refer to decls within the union itself. 3769 var block_scope: GenZir = .{ 3770 .parent = scope, 3771 .decl_node_index = node, 3772 .decl_line = gz.calcLine(node), 3773 .astgen = astgen, 3774 .force_comptime = true, 3775 .in_defer = false, 3776 }; 3777 defer block_scope.instructions.deinit(gpa); 3778 3779 var namespace: Scope.Namespace = .{ .parent = scope, .node = node }; 3780 defer namespace.decls.deinit(gpa); 3781 3782 try astgen.scanDecls(&namespace, members); 3783 3784 const arg_inst: Zir.Inst.Ref = if (arg_node != 0) 3785 try typeExpr(gz, &namespace.base, arg_node) 3786 else 3787 .none; 3788 3789 var wip_decls: WipDecls = .{}; 3790 defer wip_decls.deinit(gpa); 3791 3792 // We don't know which members are fields until we iterate, so cannot do 3793 // an accurate ensureCapacity yet. 3794 var fields_data = ArrayListUnmanaged(u32){}; 3795 defer fields_data.deinit(gpa); 3796 3797 const bits_per_field = 4; 3798 const fields_per_u32 = 32 / bits_per_field; 3799 // We only need this if there are greater than fields_per_u32 fields. 3800 var bit_bag = ArrayListUnmanaged(u32){}; 3801 defer bit_bag.deinit(gpa); 3802 3803 var cur_bit_bag: u32 = 0; 3804 var field_index: usize = 0; 3805 for (members) |member_node| { 3806 const member = switch (node_tags[member_node]) { 3807 .container_field_init => tree.containerFieldInit(member_node), 3808 .container_field_align => tree.containerFieldAlign(member_node), 3809 .container_field => tree.containerField(member_node), 3810 3811 .fn_decl => { 3812 const fn_proto = node_datas[member_node].lhs; 3813 const body = node_datas[member_node].rhs; 3814 switch (node_tags[fn_proto]) { 3815 .fn_proto_simple => { 3816 var params: [1]ast.Node.Index = undefined; 3817 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { 3818 error.OutOfMemory => return error.OutOfMemory, 3819 error.AnalysisFail => {}, 3820 }; 3821 continue; 3822 }, 3823 .fn_proto_multi => { 3824 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { 3825 error.OutOfMemory => return error.OutOfMemory, 3826 error.AnalysisFail => {}, 3827 }; 3828 continue; 3829 }, 3830 .fn_proto_one => { 3831 var params: [1]ast.Node.Index = undefined; 3832 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { 3833 error.OutOfMemory => return error.OutOfMemory, 3834 error.AnalysisFail => {}, 3835 }; 3836 continue; 3837 }, 3838 .fn_proto => { 3839 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { 3840 error.OutOfMemory => return error.OutOfMemory, 3841 error.AnalysisFail => {}, 3842 }; 3843 continue; 3844 }, 3845 else => unreachable, 3846 } 3847 }, 3848 .fn_proto_simple => { 3849 var params: [1]ast.Node.Index = undefined; 3850 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { 3851 error.OutOfMemory => return error.OutOfMemory, 3852 error.AnalysisFail => {}, 3853 }; 3854 continue; 3855 }, 3856 .fn_proto_multi => { 3857 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { 3858 error.OutOfMemory => return error.OutOfMemory, 3859 error.AnalysisFail => {}, 3860 }; 3861 continue; 3862 }, 3863 .fn_proto_one => { 3864 var params: [1]ast.Node.Index = undefined; 3865 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { 3866 error.OutOfMemory => return error.OutOfMemory, 3867 error.AnalysisFail => {}, 3868 }; 3869 continue; 3870 }, 3871 .fn_proto => { 3872 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { 3873 error.OutOfMemory => return error.OutOfMemory, 3874 error.AnalysisFail => {}, 3875 }; 3876 continue; 3877 }, 3878 3879 .global_var_decl => { 3880 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { 3881 error.OutOfMemory => return error.OutOfMemory, 3882 error.AnalysisFail => {}, 3883 }; 3884 continue; 3885 }, 3886 .local_var_decl => { 3887 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { 3888 error.OutOfMemory => return error.OutOfMemory, 3889 error.AnalysisFail => {}, 3890 }; 3891 continue; 3892 }, 3893 .simple_var_decl => { 3894 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { 3895 error.OutOfMemory => return error.OutOfMemory, 3896 error.AnalysisFail => {}, 3897 }; 3898 continue; 3899 }, 3900 .aligned_var_decl => { 3901 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { 3902 error.OutOfMemory => return error.OutOfMemory, 3903 error.AnalysisFail => {}, 3904 }; 3905 continue; 3906 }, 3907 3908 .@"comptime" => { 3909 astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 3910 error.OutOfMemory => return error.OutOfMemory, 3911 error.AnalysisFail => {}, 3912 }; 3913 continue; 3914 }, 3915 .@"usingnamespace" => { 3916 astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 3917 error.OutOfMemory => return error.OutOfMemory, 3918 error.AnalysisFail => {}, 3919 }; 3920 continue; 3921 }, 3922 .test_decl => { 3923 astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 3924 error.OutOfMemory => return error.OutOfMemory, 3925 error.AnalysisFail => {}, 3926 }; 3927 continue; 3928 }, 3929 else => unreachable, 3930 }; 3931 if (field_index % fields_per_u32 == 0 and field_index != 0) { 3932 try bit_bag.append(gpa, cur_bit_bag); 3933 cur_bit_bag = 0; 3934 } 3935 if (member.comptime_token) |comptime_token| { 3936 return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{}); 3937 } 3938 try fields_data.ensureUnusedCapacity(gpa, if (node_tags[member.ast.type_expr] != .@"anytype") 4 else 3); 3939 3940 const field_name = try astgen.identAsString(member.ast.name_token); 3941 fields_data.appendAssumeCapacity(field_name); 3942 3943 const have_type = member.ast.type_expr != 0; 3944 const have_align = member.ast.align_expr != 0; 3945 const have_value = member.ast.value_expr != 0; 3946 const unused = false; 3947 cur_bit_bag = (cur_bit_bag >> bits_per_field) | 3948 (@as(u32, @boolToInt(have_type)) << 28) | 3949 (@as(u32, @boolToInt(have_align)) << 29) | 3950 (@as(u32, @boolToInt(have_value)) << 30) | 3951 (@as(u32, @boolToInt(unused)) << 31); 3952 3953 if (have_type and node_tags[member.ast.type_expr] != .@"anytype") { 3954 const field_type = try typeExpr(&block_scope, &namespace.base, member.ast.type_expr); 3955 fields_data.appendAssumeCapacity(@enumToInt(field_type)); 3956 } 3957 if (have_align) { 3958 const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr); 3959 fields_data.appendAssumeCapacity(@enumToInt(align_inst)); 3960 } 3961 if (have_value) { 3962 if (arg_inst == .none) { 3963 return astgen.failNodeNotes( 3964 node, 3965 "explicitly valued tagged union missing integer tag type", 3966 .{}, 3967 &[_]u32{ 3968 try astgen.errNoteNode( 3969 member.ast.value_expr, 3970 "tag value specified here", 3971 .{}, 3972 ), 3973 }, 3974 ); 3975 } 3976 const tag_value = try expr(&block_scope, &block_scope.base, .{ .ty = arg_inst }, member.ast.value_expr); 3977 fields_data.appendAssumeCapacity(@enumToInt(tag_value)); 3978 } 3979 3980 field_index += 1; 3981 } 3982 if (field_index == 0) { 3983 return astgen.failNode(node, "union declarations must have at least one tag", .{}); 3984 } 3985 { 3986 const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32); 3987 if (empty_slot_count < fields_per_u32) { 3988 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field); 3989 } 3990 } 3991 { 3992 const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); 3993 if (empty_slot_count < WipDecls.fields_per_u32) { 3994 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); 3995 } 3996 } 3997 3998 const decl_inst = try gz.reserveInstructionIndex(); 3999 if (block_scope.instructions.items.len != 0) { 4000 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4001 } 4002 4003 try gz.setUnion(decl_inst, .{ 4004 .src_node = node, 4005 .layout = layout, 4006 .tag_type = arg_inst, 4007 .body_len = @intCast(u32, block_scope.instructions.items.len), 4008 .fields_len = @intCast(u32, field_index), 4009 .decls_len = @intCast(u32, wip_decls.decl_index), 4010 .auto_enum_tag = have_auto_enum, 4011 }); 4012 4013 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len + 4014 1 + fields_data.items.len + 4015 block_scope.instructions.items.len + 4016 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + 4017 wip_decls.payload.items.len); 4018 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. 4019 if (wip_decls.decl_index != 0) { 4020 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); 4021 } 4022 astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); 4023 4024 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); 4025 4026 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. 4027 astgen.extra.appendAssumeCapacity(cur_bit_bag); 4028 astgen.extra.appendSliceAssumeCapacity(fields_data.items); 4029 4030 return indexToRef(decl_inst); 4031 } 4032 4033 fn containerDecl( 4034 gz: *GenZir, 4035 scope: *Scope, 4036 rl: ResultLoc, 4037 node: ast.Node.Index, 4038 container_decl: ast.full.ContainerDecl, 4039 ) InnerError!Zir.Inst.Ref { 4040 const astgen = gz.astgen; 4041 const gpa = astgen.gpa; 4042 const tree = astgen.tree; 4043 const token_tags = tree.tokens.items(.tag); 4044 const node_tags = tree.nodes.items(.tag); 4045 const node_datas = tree.nodes.items(.data); 4046 4047 const prev_fn_block = astgen.fn_block; 4048 astgen.fn_block = null; 4049 defer astgen.fn_block = prev_fn_block; 4050 4051 // We must not create any types until Sema. Here the goal is only to generate 4052 // ZIR for all the field types, alignments, and default value expressions. 4053 4054 switch (token_tags[container_decl.ast.main_token]) { 4055 .keyword_struct => { 4056 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4057 .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed, 4058 .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern, 4059 else => unreachable, 4060 } else std.builtin.TypeInfo.ContainerLayout.Auto; 4061 4062 assert(container_decl.ast.arg == 0); 4063 4064 const result = try structDeclInner(gz, scope, node, container_decl, layout); 4065 return rvalue(gz, rl, result, node); 4066 }, 4067 .keyword_union => { 4068 const layout = if (container_decl.layout_token) |t| switch (token_tags[t]) { 4069 .keyword_packed => std.builtin.TypeInfo.ContainerLayout.Packed, 4070 .keyword_extern => std.builtin.TypeInfo.ContainerLayout.Extern, 4071 else => unreachable, 4072 } else std.builtin.TypeInfo.ContainerLayout.Auto; 4073 4074 const have_auto_enum = container_decl.ast.enum_token != null; 4075 4076 const result = try unionDeclInner(gz, scope, node, container_decl.ast.members, layout, container_decl.ast.arg, have_auto_enum); 4077 return rvalue(gz, rl, result, node); 4078 }, 4079 .keyword_enum => { 4080 if (container_decl.layout_token) |t| { 4081 return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{}); 4082 } 4083 // Count total fields as well as how many have explicitly provided tag values. 4084 const counts = blk: { 4085 var values: usize = 0; 4086 var total_fields: usize = 0; 4087 var decls: usize = 0; 4088 var nonexhaustive_node: ast.Node.Index = 0; 4089 for (container_decl.ast.members) |member_node| { 4090 const member = switch (node_tags[member_node]) { 4091 .container_field_init => tree.containerFieldInit(member_node), 4092 .container_field_align => tree.containerFieldAlign(member_node), 4093 .container_field => tree.containerField(member_node), 4094 else => { 4095 decls += 1; 4096 continue; 4097 }, 4098 }; 4099 if (member.comptime_token) |comptime_token| { 4100 return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{}); 4101 } 4102 if (member.ast.type_expr != 0) { 4103 return astgen.failNodeNotes( 4104 member.ast.type_expr, 4105 "enum fields do not have types", 4106 .{}, 4107 &[_]u32{ 4108 try astgen.errNoteNode( 4109 node, 4110 "consider 'union(enum)' here to make it a tagged union", 4111 .{}, 4112 ), 4113 }, 4114 ); 4115 } 4116 // Alignment expressions in enums are caught by the parser. 4117 assert(member.ast.align_expr == 0); 4118 4119 const name_token = member.ast.name_token; 4120 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) { 4121 if (nonexhaustive_node != 0) { 4122 return astgen.failNodeNotes( 4123 member_node, 4124 "redundant non-exhaustive enum mark", 4125 .{}, 4126 &[_]u32{ 4127 try astgen.errNoteNode( 4128 nonexhaustive_node, 4129 "other mark here", 4130 .{}, 4131 ), 4132 }, 4133 ); 4134 } 4135 nonexhaustive_node = member_node; 4136 if (member.ast.value_expr != 0) { 4137 return astgen.failNode(member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{}); 4138 } 4139 continue; 4140 } 4141 total_fields += 1; 4142 if (member.ast.value_expr != 0) { 4143 if (container_decl.ast.arg == 0) { 4144 return astgen.failNode(member.ast.value_expr, "value assigned to enum tag with inferred tag type", .{}); 4145 } 4146 values += 1; 4147 } 4148 } 4149 break :blk .{ 4150 .total_fields = total_fields, 4151 .values = values, 4152 .decls = decls, 4153 .nonexhaustive_node = nonexhaustive_node, 4154 }; 4155 }; 4156 if (counts.total_fields == 0 and counts.nonexhaustive_node == 0) { 4157 // One can construct an enum with no tags, and it functions the same as `noreturn`. But 4158 // this is only useful for generic code; when explicitly using `enum {}` syntax, there 4159 // must be at least one tag. 4160 return astgen.failNode(node, "enum declarations must have at least one tag", .{}); 4161 } 4162 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) { 4163 return astgen.failNodeNotes( 4164 node, 4165 "non-exhaustive enum missing integer tag type", 4166 .{}, 4167 &[_]u32{ 4168 try astgen.errNoteNode( 4169 counts.nonexhaustive_node, 4170 "marked non-exhaustive here", 4171 .{}, 4172 ), 4173 }, 4174 ); 4175 } 4176 // In this case we must generate ZIR code for the tag values, similar to 4177 // how structs are handled above. 4178 const nonexhaustive = counts.nonexhaustive_node != 0; 4179 4180 // The enum_decl instruction introduces a scope in which the decls of the enum 4181 // are in scope, so that tag values can refer to decls within the enum itself. 4182 var block_scope: GenZir = .{ 4183 .parent = scope, 4184 .decl_node_index = node, 4185 .decl_line = gz.calcLine(node), 4186 .astgen = astgen, 4187 .force_comptime = true, 4188 .in_defer = false, 4189 }; 4190 defer block_scope.instructions.deinit(gpa); 4191 4192 var namespace: Scope.Namespace = .{ .parent = scope, .node = node }; 4193 defer namespace.decls.deinit(gpa); 4194 4195 try astgen.scanDecls(&namespace, container_decl.ast.members); 4196 4197 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) 4198 try comptimeExpr(gz, &namespace.base, .{ .ty = .type_type }, container_decl.ast.arg) 4199 else 4200 .none; 4201 4202 var wip_decls: WipDecls = .{}; 4203 defer wip_decls.deinit(gpa); 4204 4205 var fields_data = ArrayListUnmanaged(u32){}; 4206 defer fields_data.deinit(gpa); 4207 4208 try fields_data.ensureTotalCapacity(gpa, counts.total_fields + counts.values); 4209 4210 // We only need this if there are greater than 32 fields. 4211 var bit_bag = ArrayListUnmanaged(u32){}; 4212 defer bit_bag.deinit(gpa); 4213 4214 var cur_bit_bag: u32 = 0; 4215 var field_index: usize = 0; 4216 for (container_decl.ast.members) |member_node| { 4217 if (member_node == counts.nonexhaustive_node) 4218 continue; 4219 const member = switch (node_tags[member_node]) { 4220 .container_field_init => tree.containerFieldInit(member_node), 4221 .container_field_align => tree.containerFieldAlign(member_node), 4222 .container_field => tree.containerField(member_node), 4223 4224 .fn_decl => { 4225 const fn_proto = node_datas[member_node].lhs; 4226 const body = node_datas[member_node].rhs; 4227 switch (node_tags[fn_proto]) { 4228 .fn_proto_simple => { 4229 var params: [1]ast.Node.Index = undefined; 4230 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { 4231 error.OutOfMemory => return error.OutOfMemory, 4232 error.AnalysisFail => {}, 4233 }; 4234 continue; 4235 }, 4236 .fn_proto_multi => { 4237 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { 4238 error.OutOfMemory => return error.OutOfMemory, 4239 error.AnalysisFail => {}, 4240 }; 4241 continue; 4242 }, 4243 .fn_proto_one => { 4244 var params: [1]ast.Node.Index = undefined; 4245 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { 4246 error.OutOfMemory => return error.OutOfMemory, 4247 error.AnalysisFail => {}, 4248 }; 4249 continue; 4250 }, 4251 .fn_proto => { 4252 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { 4253 error.OutOfMemory => return error.OutOfMemory, 4254 error.AnalysisFail => {}, 4255 }; 4256 continue; 4257 }, 4258 else => unreachable, 4259 } 4260 }, 4261 .fn_proto_simple => { 4262 var params: [1]ast.Node.Index = undefined; 4263 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { 4264 error.OutOfMemory => return error.OutOfMemory, 4265 error.AnalysisFail => {}, 4266 }; 4267 continue; 4268 }, 4269 .fn_proto_multi => { 4270 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { 4271 error.OutOfMemory => return error.OutOfMemory, 4272 error.AnalysisFail => {}, 4273 }; 4274 continue; 4275 }, 4276 .fn_proto_one => { 4277 var params: [1]ast.Node.Index = undefined; 4278 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { 4279 error.OutOfMemory => return error.OutOfMemory, 4280 error.AnalysisFail => {}, 4281 }; 4282 continue; 4283 }, 4284 .fn_proto => { 4285 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { 4286 error.OutOfMemory => return error.OutOfMemory, 4287 error.AnalysisFail => {}, 4288 }; 4289 continue; 4290 }, 4291 4292 .global_var_decl => { 4293 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { 4294 error.OutOfMemory => return error.OutOfMemory, 4295 error.AnalysisFail => {}, 4296 }; 4297 continue; 4298 }, 4299 .local_var_decl => { 4300 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { 4301 error.OutOfMemory => return error.OutOfMemory, 4302 error.AnalysisFail => {}, 4303 }; 4304 continue; 4305 }, 4306 .simple_var_decl => { 4307 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { 4308 error.OutOfMemory => return error.OutOfMemory, 4309 error.AnalysisFail => {}, 4310 }; 4311 continue; 4312 }, 4313 .aligned_var_decl => { 4314 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { 4315 error.OutOfMemory => return error.OutOfMemory, 4316 error.AnalysisFail => {}, 4317 }; 4318 continue; 4319 }, 4320 4321 .@"comptime" => { 4322 astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 4323 error.OutOfMemory => return error.OutOfMemory, 4324 error.AnalysisFail => {}, 4325 }; 4326 continue; 4327 }, 4328 .@"usingnamespace" => { 4329 astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 4330 error.OutOfMemory => return error.OutOfMemory, 4331 error.AnalysisFail => {}, 4332 }; 4333 continue; 4334 }, 4335 .test_decl => { 4336 astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 4337 error.OutOfMemory => return error.OutOfMemory, 4338 error.AnalysisFail => {}, 4339 }; 4340 continue; 4341 }, 4342 else => unreachable, 4343 }; 4344 if (field_index % 32 == 0 and field_index != 0) { 4345 try bit_bag.append(gpa, cur_bit_bag); 4346 cur_bit_bag = 0; 4347 } 4348 assert(member.comptime_token == null); 4349 assert(member.ast.type_expr == 0); 4350 assert(member.ast.align_expr == 0); 4351 4352 const field_name = try astgen.identAsString(member.ast.name_token); 4353 fields_data.appendAssumeCapacity(field_name); 4354 4355 const have_value = member.ast.value_expr != 0; 4356 cur_bit_bag = (cur_bit_bag >> 1) | 4357 (@as(u32, @boolToInt(have_value)) << 31); 4358 4359 if (have_value) { 4360 if (arg_inst == .none) { 4361 return astgen.failNodeNotes( 4362 node, 4363 "explicitly valued enum missing integer tag type", 4364 .{}, 4365 &[_]u32{ 4366 try astgen.errNoteNode( 4367 member.ast.value_expr, 4368 "tag value specified here", 4369 .{}, 4370 ), 4371 }, 4372 ); 4373 } 4374 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .ty = arg_inst }, member.ast.value_expr); 4375 fields_data.appendAssumeCapacity(@enumToInt(tag_value_inst)); 4376 } 4377 4378 field_index += 1; 4379 } 4380 { 4381 const empty_slot_count = 32 - (field_index % 32); 4382 if (empty_slot_count < 32) { 4383 cur_bit_bag >>= @intCast(u5, empty_slot_count); 4384 } 4385 } 4386 { 4387 const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); 4388 if (empty_slot_count < WipDecls.fields_per_u32) { 4389 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); 4390 } 4391 } 4392 4393 const decl_inst = try gz.reserveInstructionIndex(); 4394 if (block_scope.instructions.items.len != 0) { 4395 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); 4396 } 4397 4398 try gz.setEnum(decl_inst, .{ 4399 .src_node = node, 4400 .nonexhaustive = nonexhaustive, 4401 .tag_type = arg_inst, 4402 .body_len = @intCast(u32, block_scope.instructions.items.len), 4403 .fields_len = @intCast(u32, field_index), 4404 .decls_len = @intCast(u32, wip_decls.decl_index), 4405 }); 4406 4407 try astgen.extra.ensureUnusedCapacity(gpa, bit_bag.items.len + 4408 1 + fields_data.items.len + 4409 block_scope.instructions.items.len + 4410 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + 4411 wip_decls.payload.items.len); 4412 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. 4413 if (wip_decls.decl_index != 0) { 4414 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); 4415 } 4416 astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); 4417 4418 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); 4419 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. 4420 astgen.extra.appendAssumeCapacity(cur_bit_bag); 4421 astgen.extra.appendSliceAssumeCapacity(fields_data.items); 4422 4423 return rvalue(gz, rl, indexToRef(decl_inst), node); 4424 }, 4425 .keyword_opaque => { 4426 assert(container_decl.ast.arg == 0); 4427 4428 var namespace: Scope.Namespace = .{ .parent = scope, .node = node }; 4429 defer namespace.decls.deinit(gpa); 4430 4431 try astgen.scanDecls(&namespace, container_decl.ast.members); 4432 4433 var wip_decls: WipDecls = .{}; 4434 defer wip_decls.deinit(gpa); 4435 4436 for (container_decl.ast.members) |member_node| { 4437 switch (node_tags[member_node]) { 4438 .container_field_init, .container_field_align, .container_field => {}, 4439 4440 .fn_decl => { 4441 const fn_proto = node_datas[member_node].lhs; 4442 const body = node_datas[member_node].rhs; 4443 switch (node_tags[fn_proto]) { 4444 .fn_proto_simple => { 4445 var params: [1]ast.Node.Index = undefined; 4446 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { 4447 error.OutOfMemory => return error.OutOfMemory, 4448 error.AnalysisFail => {}, 4449 }; 4450 continue; 4451 }, 4452 .fn_proto_multi => { 4453 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoMulti(fn_proto)) catch |err| switch (err) { 4454 error.OutOfMemory => return error.OutOfMemory, 4455 error.AnalysisFail => {}, 4456 }; 4457 continue; 4458 }, 4459 .fn_proto_one => { 4460 var params: [1]ast.Node.Index = undefined; 4461 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { 4462 error.OutOfMemory => return error.OutOfMemory, 4463 error.AnalysisFail => {}, 4464 }; 4465 continue; 4466 }, 4467 .fn_proto => { 4468 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProto(fn_proto)) catch |err| switch (err) { 4469 error.OutOfMemory => return error.OutOfMemory, 4470 error.AnalysisFail => {}, 4471 }; 4472 continue; 4473 }, 4474 else => unreachable, 4475 } 4476 }, 4477 .fn_proto_simple => { 4478 var params: [1]ast.Node.Index = undefined; 4479 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { 4480 error.OutOfMemory => return error.OutOfMemory, 4481 error.AnalysisFail => {}, 4482 }; 4483 continue; 4484 }, 4485 .fn_proto_multi => { 4486 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoMulti(member_node)) catch |err| switch (err) { 4487 error.OutOfMemory => return error.OutOfMemory, 4488 error.AnalysisFail => {}, 4489 }; 4490 continue; 4491 }, 4492 .fn_proto_one => { 4493 var params: [1]ast.Node.Index = undefined; 4494 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { 4495 error.OutOfMemory => return error.OutOfMemory, 4496 error.AnalysisFail => {}, 4497 }; 4498 continue; 4499 }, 4500 .fn_proto => { 4501 astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProto(member_node)) catch |err| switch (err) { 4502 error.OutOfMemory => return error.OutOfMemory, 4503 error.AnalysisFail => {}, 4504 }; 4505 continue; 4506 }, 4507 4508 .global_var_decl => { 4509 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.globalVarDecl(member_node)) catch |err| switch (err) { 4510 error.OutOfMemory => return error.OutOfMemory, 4511 error.AnalysisFail => {}, 4512 }; 4513 continue; 4514 }, 4515 .local_var_decl => { 4516 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.localVarDecl(member_node)) catch |err| switch (err) { 4517 error.OutOfMemory => return error.OutOfMemory, 4518 error.AnalysisFail => {}, 4519 }; 4520 continue; 4521 }, 4522 .simple_var_decl => { 4523 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.simpleVarDecl(member_node)) catch |err| switch (err) { 4524 error.OutOfMemory => return error.OutOfMemory, 4525 error.AnalysisFail => {}, 4526 }; 4527 continue; 4528 }, 4529 .aligned_var_decl => { 4530 astgen.globalVarDecl(gz, &namespace.base, &wip_decls, member_node, tree.alignedVarDecl(member_node)) catch |err| switch (err) { 4531 error.OutOfMemory => return error.OutOfMemory, 4532 error.AnalysisFail => {}, 4533 }; 4534 continue; 4535 }, 4536 4537 .@"comptime" => { 4538 astgen.comptimeDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 4539 error.OutOfMemory => return error.OutOfMemory, 4540 error.AnalysisFail => {}, 4541 }; 4542 continue; 4543 }, 4544 .@"usingnamespace" => { 4545 astgen.usingnamespaceDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 4546 error.OutOfMemory => return error.OutOfMemory, 4547 error.AnalysisFail => {}, 4548 }; 4549 continue; 4550 }, 4551 .test_decl => { 4552 astgen.testDecl(gz, &namespace.base, &wip_decls, member_node) catch |err| switch (err) { 4553 error.OutOfMemory => return error.OutOfMemory, 4554 error.AnalysisFail => {}, 4555 }; 4556 continue; 4557 }, 4558 else => unreachable, 4559 } 4560 } 4561 { 4562 const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); 4563 if (empty_slot_count < WipDecls.fields_per_u32) { 4564 wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); 4565 } 4566 } 4567 const tag: Zir.Inst.Tag = switch (gz.anon_name_strategy) { 4568 .parent => .opaque_decl, 4569 .anon => .opaque_decl_anon, 4570 .func => .opaque_decl_func, 4571 }; 4572 const decl_inst = try gz.addBlock(tag, node); 4573 try gz.instructions.append(gpa, decl_inst); 4574 4575 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len + 4576 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + 4577 wip_decls.payload.items.len); 4578 const zir_datas = astgen.instructions.items(.data); 4579 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{ 4580 .decls_len = @intCast(u32, wip_decls.decl_index), 4581 }); 4582 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. 4583 if (wip_decls.decl_index != 0) { 4584 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); 4585 } 4586 astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); 4587 4588 return rvalue(gz, rl, indexToRef(decl_inst), node); 4589 }, 4590 else => unreachable, 4591 } 4592 } 4593 4594 fn errorSetDecl(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 4595 const astgen = gz.astgen; 4596 const gpa = astgen.gpa; 4597 const tree = astgen.tree; 4598 const main_tokens = tree.nodes.items(.main_token); 4599 const token_tags = tree.tokens.items(.tag); 4600 4601 var field_names: std.ArrayListUnmanaged(u32) = .{}; 4602 defer field_names.deinit(gpa); 4603 4604 { 4605 const error_token = main_tokens[node]; 4606 var tok_i = error_token + 2; 4607 var field_i: usize = 0; 4608 while (true) : (tok_i += 1) { 4609 switch (token_tags[tok_i]) { 4610 .doc_comment, .comma => {}, 4611 .identifier => { 4612 const str_index = try astgen.identAsString(tok_i); 4613 try field_names.append(gpa, str_index); 4614 field_i += 1; 4615 }, 4616 .r_brace => break, 4617 else => unreachable, 4618 } 4619 } 4620 } 4621 4622 const result = try gz.addPlNode(.error_set_decl, node, Zir.Inst.ErrorSetDecl{ 4623 .fields_len = @intCast(u32, field_names.items.len), 4624 }); 4625 try astgen.extra.appendSlice(gpa, field_names.items); 4626 return rvalue(gz, rl, result, node); 4627 } 4628 4629 fn tryExpr( 4630 parent_gz: *GenZir, 4631 scope: *Scope, 4632 rl: ResultLoc, 4633 node: ast.Node.Index, 4634 operand_node: ast.Node.Index, 4635 ) InnerError!Zir.Inst.Ref { 4636 const astgen = parent_gz.astgen; 4637 4638 const fn_block = astgen.fn_block orelse { 4639 return astgen.failNode(node, "'try' outside function scope", .{}); 4640 }; 4641 4642 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{}); 4643 4644 var block_scope = parent_gz.makeSubBlock(scope); 4645 block_scope.setBreakResultLoc(rl); 4646 defer block_scope.instructions.deinit(astgen.gpa); 4647 4648 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { 4649 .ref => .ref, 4650 else => .none, 4651 }; 4652 const err_ops = switch (rl) { 4653 // zig fmt: off 4654 .ref => [3]Zir.Inst.Tag{ .is_non_err_ptr, .err_union_code_ptr, .err_union_payload_unsafe_ptr }, 4655 else => [3]Zir.Inst.Tag{ .is_non_err, .err_union_code, .err_union_payload_unsafe }, 4656 // zig fmt: on 4657 }; 4658 // This could be a pointer or value depending on the `operand_rl` parameter. 4659 // We cannot use `block_scope.break_result_loc` because that has the bare 4660 // type, whereas this expression has the optional type. Later we make 4661 // up for this fact by calling rvalue on the else branch. 4662 const operand = try expr(&block_scope, &block_scope.base, operand_rl, operand_node); 4663 const cond = try block_scope.addUnNode(err_ops[0], operand, node); 4664 const condbr = try block_scope.addCondBr(.condbr, node); 4665 4666 const block = try parent_gz.addBlock(.block, node); 4667 try parent_gz.instructions.append(astgen.gpa, block); 4668 try block_scope.setBlockBody(block); 4669 4670 var then_scope = parent_gz.makeSubBlock(scope); 4671 defer then_scope.instructions.deinit(astgen.gpa); 4672 4673 block_scope.break_count += 1; 4674 // This could be a pointer or value depending on `err_ops[2]`. 4675 const unwrapped_payload = try then_scope.addUnNode(err_ops[2], operand, node); 4676 const then_result = switch (rl) { 4677 .ref => unwrapped_payload, 4678 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node), 4679 }; 4680 4681 var else_scope = parent_gz.makeSubBlock(scope); 4682 defer else_scope.instructions.deinit(astgen.gpa); 4683 4684 const err_code = try else_scope.addUnNode(err_ops[1], operand, node); 4685 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); 4686 const else_result = try else_scope.addUnNode(.ret_node, err_code, node); 4687 4688 return finishThenElseBlock( 4689 parent_gz, 4690 rl, 4691 node, 4692 &block_scope, 4693 &then_scope, 4694 &else_scope, 4695 condbr, 4696 cond, 4697 then_result, 4698 else_result, 4699 block, 4700 block, 4701 .@"break", 4702 ); 4703 } 4704 4705 fn orelseCatchExpr( 4706 parent_gz: *GenZir, 4707 scope: *Scope, 4708 rl: ResultLoc, 4709 node: ast.Node.Index, 4710 lhs: ast.Node.Index, 4711 cond_op: Zir.Inst.Tag, 4712 unwrap_op: Zir.Inst.Tag, 4713 unwrap_code_op: Zir.Inst.Tag, 4714 rhs: ast.Node.Index, 4715 payload_token: ?ast.TokenIndex, 4716 ) InnerError!Zir.Inst.Ref { 4717 const astgen = parent_gz.astgen; 4718 const tree = astgen.tree; 4719 4720 var block_scope = parent_gz.makeSubBlock(scope); 4721 block_scope.setBreakResultLoc(rl); 4722 defer block_scope.instructions.deinit(astgen.gpa); 4723 4724 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { 4725 .ref => .ref, 4726 else => .none, 4727 }; 4728 block_scope.break_count += 1; 4729 // This could be a pointer or value depending on the `operand_rl` parameter. 4730 // We cannot use `block_scope.break_result_loc` because that has the bare 4731 // type, whereas this expression has the optional type. Later we make 4732 // up for this fact by calling rvalue on the else branch. 4733 const operand = try expr(&block_scope, &block_scope.base, operand_rl, lhs); 4734 const cond = try block_scope.addUnNode(cond_op, operand, node); 4735 const condbr = try block_scope.addCondBr(.condbr, node); 4736 4737 const block = try parent_gz.addBlock(.block, node); 4738 try parent_gz.instructions.append(astgen.gpa, block); 4739 try block_scope.setBlockBody(block); 4740 4741 var then_scope = parent_gz.makeSubBlock(scope); 4742 defer then_scope.instructions.deinit(astgen.gpa); 4743 4744 // This could be a pointer or value depending on `unwrap_op`. 4745 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); 4746 const then_result = switch (rl) { 4747 .ref => unwrapped_payload, 4748 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node), 4749 }; 4750 4751 var else_scope = parent_gz.makeSubBlock(scope); 4752 defer else_scope.instructions.deinit(astgen.gpa); 4753 4754 var err_val_scope: Scope.LocalVal = undefined; 4755 const else_sub_scope = blk: { 4756 const payload = payload_token orelse break :blk &else_scope.base; 4757 if (mem.eql(u8, tree.tokenSlice(payload), "_")) { 4758 return astgen.failTok(payload, "discard of error capture; omit it instead", .{}); 4759 } 4760 const err_name = try astgen.identAsString(payload); 4761 err_val_scope = .{ 4762 .parent = &else_scope.base, 4763 .gen_zir = &else_scope, 4764 .name = err_name, 4765 .inst = try else_scope.addUnNode(unwrap_code_op, operand, node), 4766 .token_src = payload, 4767 .id_cat = .@"capture", 4768 }; 4769 break :blk &err_val_scope.base; 4770 }; 4771 4772 block_scope.break_count += 1; 4773 const else_result = try expr(&else_scope, else_sub_scope, block_scope.break_result_loc, rhs); 4774 try checkUsed(parent_gz, &else_scope.base, else_sub_scope); 4775 4776 // We hold off on the break instructions as well as copying the then/else 4777 // instructions into place until we know whether to keep store_to_block_ptr 4778 // instructions or not. 4779 4780 return finishThenElseBlock( 4781 parent_gz, 4782 rl, 4783 node, 4784 &block_scope, 4785 &then_scope, 4786 &else_scope, 4787 condbr, 4788 cond, 4789 then_result, 4790 else_result, 4791 block, 4792 block, 4793 .@"break", 4794 ); 4795 } 4796 4797 fn finishThenElseBlock( 4798 parent_gz: *GenZir, 4799 rl: ResultLoc, 4800 node: ast.Node.Index, 4801 block_scope: *GenZir, 4802 then_scope: *GenZir, 4803 else_scope: *GenZir, 4804 condbr: Zir.Inst.Index, 4805 cond: Zir.Inst.Ref, 4806 then_result: Zir.Inst.Ref, 4807 else_result: Zir.Inst.Ref, 4808 main_block: Zir.Inst.Index, 4809 then_break_block: Zir.Inst.Index, 4810 break_tag: Zir.Inst.Tag, 4811 ) InnerError!Zir.Inst.Ref { 4812 // We now have enough information to decide whether the result instruction should 4813 // be communicated via result location pointer or break instructions. 4814 const strat = rl.strategy(block_scope); 4815 switch (strat.tag) { 4816 .break_void => { 4817 if (!then_scope.endsWithNoReturn()) { 4818 _ = try then_scope.addBreak(break_tag, then_break_block, .void_value); 4819 } 4820 if (!else_scope.endsWithNoReturn()) { 4821 _ = try else_scope.addBreak(break_tag, main_block, .void_value); 4822 } 4823 assert(!strat.elide_store_to_block_ptr_instructions); 4824 try setCondBrPayload(condbr, cond, then_scope, else_scope); 4825 return indexToRef(main_block); 4826 }, 4827 .break_operand => { 4828 if (!then_scope.endsWithNoReturn()) { 4829 _ = try then_scope.addBreak(break_tag, then_break_block, then_result); 4830 } 4831 if (else_result != .none) { 4832 if (!else_scope.endsWithNoReturn()) { 4833 _ = try else_scope.addBreak(break_tag, main_block, else_result); 4834 } 4835 } else { 4836 _ = try else_scope.addBreak(break_tag, main_block, .void_value); 4837 } 4838 if (strat.elide_store_to_block_ptr_instructions) { 4839 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope, block_scope.rl_ptr); 4840 } else { 4841 try setCondBrPayload(condbr, cond, then_scope, else_scope); 4842 } 4843 const block_ref = indexToRef(main_block); 4844 switch (rl) { 4845 .ref => return block_ref, 4846 else => return rvalue(parent_gz, rl, block_ref, node), 4847 } 4848 }, 4849 } 4850 } 4851 4852 /// Return whether the identifier names of two tokens are equal. Resolves @"" 4853 /// tokens without allocating. 4854 /// OK in theory it could do it without allocating. This implementation 4855 /// allocates when the @"" form is used. 4856 fn tokenIdentEql(astgen: *AstGen, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { 4857 const ident_name_1 = try astgen.identifierTokenString(token1); 4858 const ident_name_2 = try astgen.identifierTokenString(token2); 4859 return mem.eql(u8, ident_name_1, ident_name_2); 4860 } 4861 4862 fn fieldAccess( 4863 gz: *GenZir, 4864 scope: *Scope, 4865 rl: ResultLoc, 4866 node: ast.Node.Index, 4867 ) InnerError!Zir.Inst.Ref { 4868 const astgen = gz.astgen; 4869 const tree = astgen.tree; 4870 const main_tokens = tree.nodes.items(.main_token); 4871 const node_datas = tree.nodes.items(.data); 4872 4873 const object_node = node_datas[node].lhs; 4874 const dot_token = main_tokens[node]; 4875 const field_ident = dot_token + 1; 4876 const str_index = try astgen.identAsString(field_ident); 4877 switch (rl) { 4878 .ref => return gz.addPlNode(.field_ptr, node, Zir.Inst.Field{ 4879 .lhs = try expr(gz, scope, .ref, object_node), 4880 .field_name_start = str_index, 4881 }), 4882 else => return rvalue(gz, rl, try gz.addPlNode(.field_val, node, Zir.Inst.Field{ 4883 .lhs = try expr(gz, scope, .none_or_ref, object_node), 4884 .field_name_start = str_index, 4885 }), node), 4886 } 4887 } 4888 4889 fn arrayAccess( 4890 gz: *GenZir, 4891 scope: *Scope, 4892 rl: ResultLoc, 4893 node: ast.Node.Index, 4894 ) InnerError!Zir.Inst.Ref { 4895 const astgen = gz.astgen; 4896 const tree = astgen.tree; 4897 const node_datas = tree.nodes.items(.data); 4898 switch (rl) { 4899 .ref => return gz.addBin( 4900 .elem_ptr, 4901 try expr(gz, scope, .ref, node_datas[node].lhs), 4902 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), 4903 ), 4904 else => return rvalue(gz, rl, try gz.addBin( 4905 .elem_val, 4906 try expr(gz, scope, .none_or_ref, node_datas[node].lhs), 4907 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), 4908 ), node), 4909 } 4910 } 4911 4912 fn simpleBinOp( 4913 gz: *GenZir, 4914 scope: *Scope, 4915 rl: ResultLoc, 4916 node: ast.Node.Index, 4917 op_inst_tag: Zir.Inst.Tag, 4918 ) InnerError!Zir.Inst.Ref { 4919 const astgen = gz.astgen; 4920 const tree = astgen.tree; 4921 const node_datas = tree.nodes.items(.data); 4922 4923 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{ 4924 .lhs = try expr(gz, scope, .none, node_datas[node].lhs), 4925 .rhs = try expr(gz, scope, .none, node_datas[node].rhs), 4926 }); 4927 return rvalue(gz, rl, result, node); 4928 } 4929 4930 fn simpleStrTok( 4931 gz: *GenZir, 4932 rl: ResultLoc, 4933 ident_token: ast.TokenIndex, 4934 node: ast.Node.Index, 4935 op_inst_tag: Zir.Inst.Tag, 4936 ) InnerError!Zir.Inst.Ref { 4937 const astgen = gz.astgen; 4938 const str_index = try astgen.identAsString(ident_token); 4939 const result = try gz.addStrTok(op_inst_tag, str_index, ident_token); 4940 return rvalue(gz, rl, result, node); 4941 } 4942 4943 fn boolBinOp( 4944 gz: *GenZir, 4945 scope: *Scope, 4946 rl: ResultLoc, 4947 node: ast.Node.Index, 4948 zir_tag: Zir.Inst.Tag, 4949 ) InnerError!Zir.Inst.Ref { 4950 const astgen = gz.astgen; 4951 const tree = astgen.tree; 4952 const node_datas = tree.nodes.items(.data); 4953 4954 const lhs = try expr(gz, scope, bool_rl, node_datas[node].lhs); 4955 const bool_br = try gz.addBoolBr(zir_tag, lhs); 4956 4957 var rhs_scope = gz.makeSubBlock(scope); 4958 defer rhs_scope.instructions.deinit(gz.astgen.gpa); 4959 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs); 4960 if (!gz.refIsNoReturn(rhs)) { 4961 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); 4962 } 4963 try rhs_scope.setBoolBrBody(bool_br); 4964 4965 const block_ref = indexToRef(bool_br); 4966 return rvalue(gz, rl, block_ref, node); 4967 } 4968 4969 fn ifExpr( 4970 parent_gz: *GenZir, 4971 scope: *Scope, 4972 rl: ResultLoc, 4973 node: ast.Node.Index, 4974 if_full: ast.full.If, 4975 ) InnerError!Zir.Inst.Ref { 4976 const astgen = parent_gz.astgen; 4977 const tree = astgen.tree; 4978 const token_tags = tree.tokens.items(.tag); 4979 4980 var block_scope = parent_gz.makeSubBlock(scope); 4981 block_scope.setBreakResultLoc(rl); 4982 defer block_scope.instructions.deinit(astgen.gpa); 4983 4984 const payload_is_ref = if (if_full.payload_token) |payload_token| 4985 token_tags[payload_token] == .asterisk 4986 else 4987 false; 4988 4989 const cond: struct { 4990 inst: Zir.Inst.Ref, 4991 bool_bit: Zir.Inst.Ref, 4992 } = c: { 4993 if (if_full.error_token) |_| { 4994 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 4995 const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); 4996 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 4997 break :c .{ 4998 .inst = err_union, 4999 .bool_bit = try block_scope.addUnNode(tag, err_union, node), 5000 }; 5001 } else if (if_full.payload_token) |_| { 5002 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5003 const optional = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); 5004 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 5005 break :c .{ 5006 .inst = optional, 5007 .bool_bit = try block_scope.addUnNode(tag, optional, node), 5008 }; 5009 } else { 5010 const cond = try expr(&block_scope, &block_scope.base, bool_rl, if_full.ast.cond_expr); 5011 break :c .{ 5012 .inst = cond, 5013 .bool_bit = cond, 5014 }; 5015 } 5016 }; 5017 5018 const condbr = try block_scope.addCondBr(.condbr, node); 5019 5020 const block = try parent_gz.addBlock(.block, node); 5021 try parent_gz.instructions.append(astgen.gpa, block); 5022 try block_scope.setBlockBody(block); 5023 5024 var then_scope = parent_gz.makeSubBlock(scope); 5025 defer then_scope.instructions.deinit(astgen.gpa); 5026 5027 var payload_val_scope: Scope.LocalVal = undefined; 5028 5029 const then_sub_scope = s: { 5030 if (if_full.error_token != null) { 5031 if (if_full.payload_token) |payload_token| { 5032 const tag: Zir.Inst.Tag = if (payload_is_ref) 5033 .err_union_payload_unsafe_ptr 5034 else 5035 .err_union_payload_unsafe; 5036 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5037 const token_name_index = payload_token + @boolToInt(payload_is_ref); 5038 const ident_name = try astgen.identAsString(token_name_index); 5039 const token_name_str = tree.tokenSlice(token_name_index); 5040 if (mem.eql(u8, "_", token_name_str)) 5041 break :s &then_scope.base; 5042 try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index, token_name_str); 5043 payload_val_scope = .{ 5044 .parent = &then_scope.base, 5045 .gen_zir = &then_scope, 5046 .name = ident_name, 5047 .inst = payload_inst, 5048 .token_src = payload_token, 5049 .id_cat = .@"capture", 5050 }; 5051 break :s &payload_val_scope.base; 5052 } else { 5053 break :s &then_scope.base; 5054 } 5055 } else if (if_full.payload_token) |payload_token| { 5056 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5057 const tag: Zir.Inst.Tag = if (payload_is_ref) 5058 .optional_payload_unsafe_ptr 5059 else 5060 .optional_payload_unsafe; 5061 const ident_bytes = tree.tokenSlice(ident_token); 5062 if (mem.eql(u8, "_", ident_bytes)) 5063 break :s &then_scope.base; 5064 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5065 const ident_name = try astgen.identAsString(ident_token); 5066 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes); 5067 payload_val_scope = .{ 5068 .parent = &then_scope.base, 5069 .gen_zir = &then_scope, 5070 .name = ident_name, 5071 .inst = payload_inst, 5072 .token_src = ident_token, 5073 .id_cat = .@"capture", 5074 }; 5075 break :s &payload_val_scope.base; 5076 } else { 5077 break :s &then_scope.base; 5078 } 5079 }; 5080 5081 block_scope.break_count += 1; 5082 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_loc, if_full.ast.then_expr); 5083 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5084 // We hold off on the break instructions as well as copying the then/else 5085 // instructions into place until we know whether to keep store_to_block_ptr 5086 // instructions or not. 5087 5088 var else_scope = parent_gz.makeSubBlock(scope); 5089 defer else_scope.instructions.deinit(astgen.gpa); 5090 5091 const else_node = if_full.ast.else_expr; 5092 const else_info: struct { 5093 src: ast.Node.Index, 5094 result: Zir.Inst.Ref, 5095 } = if (else_node != 0) blk: { 5096 block_scope.break_count += 1; 5097 const sub_scope = s: { 5098 if (if_full.error_token) |error_token| { 5099 const tag: Zir.Inst.Tag = if (payload_is_ref) 5100 .err_union_code_ptr 5101 else 5102 .err_union_code; 5103 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); 5104 const ident_name = try astgen.identAsString(error_token); 5105 const error_token_str = tree.tokenSlice(error_token); 5106 if (mem.eql(u8, "_", error_token_str)) 5107 break :s &else_scope.base; 5108 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, error_token_str); 5109 payload_val_scope = .{ 5110 .parent = &else_scope.base, 5111 .gen_zir = &else_scope, 5112 .name = ident_name, 5113 .inst = payload_inst, 5114 .token_src = error_token, 5115 .id_cat = .@"capture", 5116 }; 5117 break :s &payload_val_scope.base; 5118 } else { 5119 break :s &else_scope.base; 5120 } 5121 }; 5122 const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node); 5123 try checkUsed(parent_gz, &else_scope.base, sub_scope); 5124 break :blk .{ 5125 .src = else_node, 5126 .result = e, 5127 }; 5128 } else .{ 5129 .src = if_full.ast.then_expr, 5130 .result = .none, 5131 }; 5132 5133 return finishThenElseBlock( 5134 parent_gz, 5135 rl, 5136 node, 5137 &block_scope, 5138 &then_scope, 5139 &else_scope, 5140 condbr, 5141 cond.bool_bit, 5142 then_result, 5143 else_info.result, 5144 block, 5145 block, 5146 .@"break", 5147 ); 5148 } 5149 5150 fn setCondBrPayload( 5151 condbr: Zir.Inst.Index, 5152 cond: Zir.Inst.Ref, 5153 then_scope: *GenZir, 5154 else_scope: *GenZir, 5155 ) !void { 5156 const astgen = then_scope.astgen; 5157 5158 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len + 5159 then_scope.instructions.items.len + else_scope.instructions.items.len); 5160 5161 const zir_datas = astgen.instructions.items(.data); 5162 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5163 .condition = cond, 5164 .then_body_len = @intCast(u32, then_scope.instructions.items.len), 5165 .else_body_len = @intCast(u32, else_scope.instructions.items.len), 5166 }); 5167 astgen.extra.appendSliceAssumeCapacity(then_scope.instructions.items); 5168 astgen.extra.appendSliceAssumeCapacity(else_scope.instructions.items); 5169 } 5170 5171 fn setCondBrPayloadElideBlockStorePtr( 5172 condbr: Zir.Inst.Index, 5173 cond: Zir.Inst.Ref, 5174 then_scope: *GenZir, 5175 else_scope: *GenZir, 5176 block_ptr: Zir.Inst.Ref, 5177 ) !void { 5178 const astgen = then_scope.astgen; 5179 5180 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len + 5181 then_scope.instructions.items.len + else_scope.instructions.items.len); 5182 5183 const zir_tags = astgen.instructions.items(.tag); 5184 const zir_datas = astgen.instructions.items(.data); 5185 5186 const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ 5187 .condition = cond, 5188 .then_body_len = @intCast(u32, then_scope.instructions.items.len), 5189 .else_body_len = @intCast(u32, else_scope.instructions.items.len), 5190 }); 5191 zir_datas[condbr].pl_node.payload_index = condbr_pl; 5192 const then_body_len_index = condbr_pl + 1; 5193 const else_body_len_index = condbr_pl + 2; 5194 5195 for (then_scope.instructions.items) |src_inst| { 5196 if (zir_tags[src_inst] == .store_to_block_ptr) { 5197 if (zir_datas[src_inst].bin.lhs == block_ptr) { 5198 astgen.extra.items[then_body_len_index] -= 1; 5199 continue; 5200 } 5201 } 5202 astgen.extra.appendAssumeCapacity(src_inst); 5203 } 5204 for (else_scope.instructions.items) |src_inst| { 5205 if (zir_tags[src_inst] == .store_to_block_ptr) { 5206 if (zir_datas[src_inst].bin.lhs == block_ptr) { 5207 astgen.extra.items[else_body_len_index] -= 1; 5208 continue; 5209 } 5210 } 5211 astgen.extra.appendAssumeCapacity(src_inst); 5212 } 5213 } 5214 5215 fn whileExpr( 5216 parent_gz: *GenZir, 5217 scope: *Scope, 5218 rl: ResultLoc, 5219 node: ast.Node.Index, 5220 while_full: ast.full.While, 5221 ) InnerError!Zir.Inst.Ref { 5222 const astgen = parent_gz.astgen; 5223 const tree = astgen.tree; 5224 const token_tags = tree.tokens.items(.tag); 5225 5226 if (while_full.label_token) |label_token| { 5227 try astgen.checkLabelRedefinition(scope, label_token); 5228 } 5229 5230 const is_inline = parent_gz.force_comptime or while_full.inline_token != null; 5231 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 5232 const loop_block = try parent_gz.addBlock(loop_tag, node); 5233 try parent_gz.instructions.append(astgen.gpa, loop_block); 5234 5235 var loop_scope = parent_gz.makeSubBlock(scope); 5236 loop_scope.setBreakResultLoc(rl); 5237 defer loop_scope.instructions.deinit(astgen.gpa); 5238 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 5239 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); 5240 5241 var continue_scope = parent_gz.makeSubBlock(&loop_scope.base); 5242 defer continue_scope.instructions.deinit(astgen.gpa); 5243 5244 const payload_is_ref = if (while_full.payload_token) |payload_token| 5245 token_tags[payload_token] == .asterisk 5246 else 5247 false; 5248 5249 const cond: struct { 5250 inst: Zir.Inst.Ref, 5251 bool_bit: Zir.Inst.Ref, 5252 } = c: { 5253 if (while_full.error_token) |_| { 5254 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5255 const err_union = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); 5256 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; 5257 break :c .{ 5258 .inst = err_union, 5259 .bool_bit = try continue_scope.addUnNode(tag, err_union, node), 5260 }; 5261 } else if (while_full.payload_token) |_| { 5262 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5263 const optional = try expr(&continue_scope, &continue_scope.base, cond_rl, while_full.ast.cond_expr); 5264 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_null_ptr else .is_non_null; 5265 break :c .{ 5266 .inst = optional, 5267 .bool_bit = try continue_scope.addUnNode(tag, optional, node), 5268 }; 5269 } else { 5270 const cond = try expr(&continue_scope, &continue_scope.base, bool_rl, while_full.ast.cond_expr); 5271 break :c .{ 5272 .inst = cond, 5273 .bool_bit = cond, 5274 }; 5275 } 5276 }; 5277 5278 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 5279 const condbr = try continue_scope.addCondBr(condbr_tag, node); 5280 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 5281 const cond_block = try loop_scope.addBlock(block_tag, node); 5282 try loop_scope.instructions.append(astgen.gpa, cond_block); 5283 try continue_scope.setBlockBody(cond_block); 5284 5285 var then_scope = parent_gz.makeSubBlock(&continue_scope.base); 5286 defer then_scope.instructions.deinit(astgen.gpa); 5287 5288 var payload_val_scope: Scope.LocalVal = undefined; 5289 5290 const then_sub_scope = s: { 5291 if (while_full.error_token != null) { 5292 if (while_full.payload_token) |payload_token| { 5293 const tag: Zir.Inst.Tag = if (payload_is_ref) 5294 .err_union_payload_unsafe_ptr 5295 else 5296 .err_union_payload_unsafe; 5297 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5298 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5299 const ident_bytes = tree.tokenSlice(ident_token); 5300 if (mem.eql(u8, "_", ident_bytes)) 5301 break :s &then_scope.base; 5302 const payload_name_loc = payload_token + @boolToInt(payload_is_ref); 5303 const ident_name = try astgen.identAsString(payload_name_loc); 5304 try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc, ident_bytes); 5305 payload_val_scope = .{ 5306 .parent = &then_scope.base, 5307 .gen_zir = &then_scope, 5308 .name = ident_name, 5309 .inst = payload_inst, 5310 .token_src = payload_token, 5311 .id_cat = .@"capture", 5312 }; 5313 break :s &payload_val_scope.base; 5314 } else { 5315 break :s &then_scope.base; 5316 } 5317 } else if (while_full.payload_token) |payload_token| { 5318 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; 5319 const tag: Zir.Inst.Tag = if (payload_is_ref) 5320 .optional_payload_unsafe_ptr 5321 else 5322 .optional_payload_unsafe; 5323 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node); 5324 const ident_name = try astgen.identAsString(ident_token); 5325 const ident_bytes = tree.tokenSlice(ident_token); 5326 if (mem.eql(u8, "_", ident_bytes)) 5327 break :s &then_scope.base; 5328 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token, ident_bytes); 5329 payload_val_scope = .{ 5330 .parent = &then_scope.base, 5331 .gen_zir = &then_scope, 5332 .name = ident_name, 5333 .inst = payload_inst, 5334 .token_src = ident_token, 5335 .id_cat = .@"capture", 5336 }; 5337 break :s &payload_val_scope.base; 5338 } else { 5339 break :s &then_scope.base; 5340 } 5341 }; 5342 5343 // This code could be improved to avoid emitting the continue expr when there 5344 // are no jumps to it. This happens when the last statement of a while body is noreturn 5345 // and there are no `continue` statements. 5346 // Tracking issue: https://github.com/ziglang/zig/issues/9185 5347 if (while_full.ast.cont_expr != 0) { 5348 _ = try expr(&loop_scope, then_sub_scope, .{ .ty = .void_type }, while_full.ast.cont_expr); 5349 } 5350 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 5351 _ = try loop_scope.addNode(repeat_tag, node); 5352 5353 try loop_scope.setBlockBody(loop_block); 5354 loop_scope.break_block = loop_block; 5355 loop_scope.continue_block = cond_block; 5356 if (while_full.label_token) |label_token| { 5357 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 5358 .token = label_token, 5359 .block_inst = loop_block, 5360 }); 5361 } 5362 5363 loop_scope.break_count += 1; 5364 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); 5365 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5366 5367 var else_scope = parent_gz.makeSubBlock(&continue_scope.base); 5368 defer else_scope.instructions.deinit(astgen.gpa); 5369 5370 const else_node = while_full.ast.else_expr; 5371 const else_info: struct { 5372 src: ast.Node.Index, 5373 result: Zir.Inst.Ref, 5374 } = if (else_node != 0) blk: { 5375 loop_scope.break_count += 1; 5376 const sub_scope = s: { 5377 if (while_full.error_token) |error_token| { 5378 const tag: Zir.Inst.Tag = if (payload_is_ref) 5379 .err_union_code_ptr 5380 else 5381 .err_union_code; 5382 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node); 5383 const ident_name = try astgen.identAsString(error_token); 5384 const ident_bytes = tree.tokenSlice(error_token); 5385 if (mem.eql(u8, ident_bytes, "_")) 5386 break :s &else_scope.base; 5387 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token, ident_bytes); 5388 payload_val_scope = .{ 5389 .parent = &else_scope.base, 5390 .gen_zir = &else_scope, 5391 .name = ident_name, 5392 .inst = payload_inst, 5393 .token_src = error_token, 5394 .id_cat = .@"capture", 5395 }; 5396 break :s &payload_val_scope.base; 5397 } else { 5398 break :s &else_scope.base; 5399 } 5400 }; 5401 const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); 5402 try checkUsed(parent_gz, &else_scope.base, sub_scope); 5403 break :blk .{ 5404 .src = else_node, 5405 .result = e, 5406 }; 5407 } else .{ 5408 .src = while_full.ast.then_expr, 5409 .result = .none, 5410 }; 5411 5412 if (loop_scope.label) |some| { 5413 if (!some.used) { 5414 return astgen.failTok(some.token, "unused while loop label", .{}); 5415 } 5416 } 5417 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 5418 return finishThenElseBlock( 5419 parent_gz, 5420 rl, 5421 node, 5422 &loop_scope, 5423 &then_scope, 5424 &else_scope, 5425 condbr, 5426 cond.bool_bit, 5427 then_result, 5428 else_info.result, 5429 loop_block, 5430 cond_block, 5431 break_tag, 5432 ); 5433 } 5434 5435 fn forExpr( 5436 parent_gz: *GenZir, 5437 scope: *Scope, 5438 rl: ResultLoc, 5439 node: ast.Node.Index, 5440 for_full: ast.full.While, 5441 ) InnerError!Zir.Inst.Ref { 5442 const astgen = parent_gz.astgen; 5443 5444 if (for_full.label_token) |label_token| { 5445 try astgen.checkLabelRedefinition(scope, label_token); 5446 } 5447 5448 // Set up variables and constants. 5449 const is_inline = parent_gz.force_comptime or for_full.inline_token != null; 5450 const tree = astgen.tree; 5451 const token_tags = tree.tokens.items(.tag); 5452 5453 const payload_is_ref = if (for_full.payload_token) |payload_token| 5454 token_tags[payload_token] == .asterisk 5455 else 5456 false; 5457 5458 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; 5459 const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr); 5460 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); 5461 5462 const index_ptr = blk: { 5463 const index_ptr = try parent_gz.addUnNode(.alloc, .usize_type, node); 5464 // initialize to zero 5465 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize); 5466 break :blk index_ptr; 5467 }; 5468 5469 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop; 5470 const loop_block = try parent_gz.addBlock(loop_tag, node); 5471 try parent_gz.instructions.append(astgen.gpa, loop_block); 5472 5473 var loop_scope = parent_gz.makeSubBlock(scope); 5474 loop_scope.setBreakResultLoc(rl); 5475 defer loop_scope.instructions.deinit(astgen.gpa); 5476 defer loop_scope.labeled_breaks.deinit(astgen.gpa); 5477 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); 5478 5479 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); 5480 defer cond_scope.instructions.deinit(astgen.gpa); 5481 5482 // check condition i < array_expr.len 5483 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 5484 const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, Zir.Inst.Bin{ 5485 .lhs = index, 5486 .rhs = len, 5487 }); 5488 5489 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; 5490 const condbr = try cond_scope.addCondBr(condbr_tag, node); 5491 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block; 5492 const cond_block = try loop_scope.addBlock(block_tag, node); 5493 try loop_scope.instructions.append(astgen.gpa, cond_block); 5494 try cond_scope.setBlockBody(cond_block); 5495 5496 // Increment the index variable. 5497 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); 5498 const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ 5499 .lhs = index_2, 5500 .rhs = .one_usize, 5501 }); 5502 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one); 5503 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat; 5504 _ = try loop_scope.addNode(repeat_tag, node); 5505 5506 try loop_scope.setBlockBody(loop_block); 5507 loop_scope.break_block = loop_block; 5508 loop_scope.continue_block = cond_block; 5509 if (for_full.label_token) |label_token| { 5510 loop_scope.label = @as(?GenZir.Label, GenZir.Label{ 5511 .token = label_token, 5512 .block_inst = loop_block, 5513 }); 5514 } 5515 5516 var then_scope = parent_gz.makeSubBlock(&cond_scope.base); 5517 defer then_scope.instructions.deinit(astgen.gpa); 5518 5519 var payload_val_scope: Scope.LocalVal = undefined; 5520 var index_scope: Scope.LocalPtr = undefined; 5521 const then_sub_scope = blk: { 5522 const payload_token = for_full.payload_token.?; 5523 const ident = if (token_tags[payload_token] == .asterisk) 5524 payload_token + 1 5525 else 5526 payload_token; 5527 const is_ptr = ident != payload_token; 5528 const value_name = tree.tokenSlice(ident); 5529 var payload_sub_scope: *Scope = undefined; 5530 if (!mem.eql(u8, value_name, "_")) { 5531 const name_str_index = try astgen.identAsString(ident); 5532 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val; 5533 const payload_inst = try then_scope.addBin(tag, array_ptr, index); 5534 try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name); 5535 payload_val_scope = .{ 5536 .parent = &then_scope.base, 5537 .gen_zir = &then_scope, 5538 .name = name_str_index, 5539 .inst = payload_inst, 5540 .token_src = ident, 5541 .id_cat = .@"capture", 5542 }; 5543 payload_sub_scope = &payload_val_scope.base; 5544 } else if (is_ptr) { 5545 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 5546 } else { 5547 payload_sub_scope = &then_scope.base; 5548 } 5549 5550 const index_token = if (token_tags[ident + 1] == .comma) 5551 ident + 2 5552 else 5553 break :blk payload_sub_scope; 5554 const token_bytes = tree.tokenSlice(index_token); 5555 if (mem.eql(u8, token_bytes, "_")) { 5556 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{}); 5557 } 5558 const index_name = try astgen.identAsString(index_token); 5559 try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes); 5560 index_scope = .{ 5561 .parent = payload_sub_scope, 5562 .gen_zir = &then_scope, 5563 .name = index_name, 5564 .ptr = index_ptr, 5565 .token_src = index_token, 5566 .maybe_comptime = is_inline, 5567 .id_cat = .@"loop index capture", 5568 }; 5569 break :blk &index_scope.base; 5570 }; 5571 5572 loop_scope.break_count += 1; 5573 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); 5574 try checkUsed(parent_gz, &then_scope.base, then_sub_scope); 5575 5576 var else_scope = parent_gz.makeSubBlock(&cond_scope.base); 5577 defer else_scope.instructions.deinit(astgen.gpa); 5578 5579 const else_node = for_full.ast.else_expr; 5580 const else_info: struct { 5581 src: ast.Node.Index, 5582 result: Zir.Inst.Ref, 5583 } = if (else_node != 0) blk: { 5584 loop_scope.break_count += 1; 5585 const sub_scope = &else_scope.base; 5586 break :blk .{ 5587 .src = else_node, 5588 .result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node), 5589 }; 5590 } else .{ 5591 .src = for_full.ast.then_expr, 5592 .result = .none, 5593 }; 5594 5595 if (loop_scope.label) |some| { 5596 if (!some.used) { 5597 return astgen.failTok(some.token, "unused for loop label", .{}); 5598 } 5599 } 5600 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; 5601 return finishThenElseBlock( 5602 parent_gz, 5603 rl, 5604 node, 5605 &loop_scope, 5606 &then_scope, 5607 &else_scope, 5608 condbr, 5609 cond, 5610 then_result, 5611 else_info.result, 5612 loop_block, 5613 cond_block, 5614 break_tag, 5615 ); 5616 } 5617 5618 fn switchExpr( 5619 parent_gz: *GenZir, 5620 scope: *Scope, 5621 rl: ResultLoc, 5622 switch_node: ast.Node.Index, 5623 ) InnerError!Zir.Inst.Ref { 5624 const astgen = parent_gz.astgen; 5625 const gpa = astgen.gpa; 5626 const tree = astgen.tree; 5627 const node_datas = tree.nodes.items(.data); 5628 const node_tags = tree.nodes.items(.tag); 5629 const main_tokens = tree.nodes.items(.main_token); 5630 const token_tags = tree.tokens.items(.tag); 5631 const operand_node = node_datas[switch_node].lhs; 5632 const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); 5633 const case_nodes = tree.extra_data[extra.start..extra.end]; 5634 5635 // We perform two passes over the AST. This first pass is to collect information 5636 // for the following variables, make note of the special prong AST node index, 5637 // and bail out with a compile error if there are multiple special prongs present. 5638 var any_payload_is_ref = false; 5639 var scalar_cases_len: u32 = 0; 5640 var multi_cases_len: u32 = 0; 5641 var special_prong: Zir.SpecialProng = .none; 5642 var special_node: ast.Node.Index = 0; 5643 var else_src: ?ast.TokenIndex = null; 5644 var underscore_src: ?ast.TokenIndex = null; 5645 for (case_nodes) |case_node| { 5646 const case = switch (node_tags[case_node]) { 5647 .switch_case_one => tree.switchCaseOne(case_node), 5648 .switch_case => tree.switchCase(case_node), 5649 else => unreachable, 5650 }; 5651 if (case.payload_token) |payload_token| { 5652 if (token_tags[payload_token] == .asterisk) { 5653 any_payload_is_ref = true; 5654 } 5655 } 5656 // Check for else/`_` prong. 5657 if (case.ast.values.len == 0) { 5658 const case_src = case.ast.arrow_token - 1; 5659 if (else_src) |src| { 5660 return astgen.failTokNotes( 5661 case_src, 5662 "multiple else prongs in switch expression", 5663 .{}, 5664 &[_]u32{ 5665 try astgen.errNoteTok( 5666 src, 5667 "previous else prong here", 5668 .{}, 5669 ), 5670 }, 5671 ); 5672 } else if (underscore_src) |some_underscore| { 5673 return astgen.failNodeNotes( 5674 switch_node, 5675 "else and '_' prong in switch expression", 5676 .{}, 5677 &[_]u32{ 5678 try astgen.errNoteTok( 5679 case_src, 5680 "else prong here", 5681 .{}, 5682 ), 5683 try astgen.errNoteTok( 5684 some_underscore, 5685 "'_' prong here", 5686 .{}, 5687 ), 5688 }, 5689 ); 5690 } 5691 special_node = case_node; 5692 special_prong = .@"else"; 5693 else_src = case_src; 5694 continue; 5695 } else if (case.ast.values.len == 1 and 5696 node_tags[case.ast.values[0]] == .identifier and 5697 mem.eql(u8, tree.tokenSlice(main_tokens[case.ast.values[0]]), "_")) 5698 { 5699 const case_src = case.ast.arrow_token - 1; 5700 if (underscore_src) |src| { 5701 return astgen.failTokNotes( 5702 case_src, 5703 "multiple '_' prongs in switch expression", 5704 .{}, 5705 &[_]u32{ 5706 try astgen.errNoteTok( 5707 src, 5708 "previous '_' prong here", 5709 .{}, 5710 ), 5711 }, 5712 ); 5713 } else if (else_src) |some_else| { 5714 return astgen.failNodeNotes( 5715 switch_node, 5716 "else and '_' prong in switch expression", 5717 .{}, 5718 &[_]u32{ 5719 try astgen.errNoteTok( 5720 some_else, 5721 "else prong here", 5722 .{}, 5723 ), 5724 try astgen.errNoteTok( 5725 case_src, 5726 "'_' prong here", 5727 .{}, 5728 ), 5729 }, 5730 ); 5731 } 5732 special_node = case_node; 5733 special_prong = .under; 5734 underscore_src = case_src; 5735 continue; 5736 } 5737 5738 if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) { 5739 scalar_cases_len += 1; 5740 } else { 5741 multi_cases_len += 1; 5742 } 5743 } 5744 5745 const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; 5746 const operand = try expr(parent_gz, scope, operand_rl, operand_node); 5747 // We need the type of the operand to use as the result location for all the prong items. 5748 const typeof_tag: Zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof; 5749 const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); 5750 const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; 5751 5752 // Contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. 5753 // This is the header as well as the optional else prong body, as well as all the 5754 // scalar cases. 5755 // At the end we will memcpy this into place. 5756 var scalar_cases_payload = ArrayListUnmanaged(u32){}; 5757 defer scalar_cases_payload.deinit(gpa); 5758 // Same deal, but this is only the `extra` data for the multi cases. 5759 var multi_cases_payload = ArrayListUnmanaged(u32){}; 5760 defer multi_cases_payload.deinit(gpa); 5761 5762 var block_scope = parent_gz.makeSubBlock(scope); 5763 block_scope.setBreakResultLoc(rl); 5764 defer block_scope.instructions.deinit(gpa); 5765 5766 // This gets added to the parent block later, after the item expressions. 5767 const switch_block = try parent_gz.addBlock(undefined, switch_node); 5768 5769 // We re-use this same scope for all cases, including the special prong, if any. 5770 var case_scope = parent_gz.makeSubBlock(&block_scope.base); 5771 defer case_scope.instructions.deinit(gpa); 5772 5773 // Do the else/`_` first because it goes first in the payload. 5774 var capture_val_scope: Scope.LocalVal = undefined; 5775 if (special_node != 0) { 5776 const case = switch (node_tags[special_node]) { 5777 .switch_case_one => tree.switchCaseOne(special_node), 5778 .switch_case => tree.switchCase(special_node), 5779 else => unreachable, 5780 }; 5781 const sub_scope = blk: { 5782 const payload_token = case.payload_token orelse break :blk &case_scope.base; 5783 const ident = if (token_tags[payload_token] == .asterisk) 5784 payload_token + 1 5785 else 5786 payload_token; 5787 const is_ptr = ident != payload_token; 5788 if (mem.eql(u8, tree.tokenSlice(ident), "_")) { 5789 if (is_ptr) { 5790 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 5791 } 5792 break :blk &case_scope.base; 5793 } 5794 const capture_tag: Zir.Inst.Tag = if (is_ptr) 5795 .switch_capture_else_ref 5796 else 5797 .switch_capture_else; 5798 const capture = try case_scope.add(.{ 5799 .tag = capture_tag, 5800 .data = .{ .switch_capture = .{ 5801 .switch_inst = switch_block, 5802 .prong_index = undefined, 5803 } }, 5804 }); 5805 const capture_name = try astgen.identAsString(payload_token); 5806 capture_val_scope = .{ 5807 .parent = &case_scope.base, 5808 .gen_zir = &case_scope, 5809 .name = capture_name, 5810 .inst = capture, 5811 .token_src = payload_token, 5812 .id_cat = .@"capture", 5813 }; 5814 break :blk &capture_val_scope.base; 5815 }; 5816 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); 5817 try checkUsed(parent_gz, &case_scope.base, sub_scope); 5818 if (!parent_gz.refIsNoReturn(case_result)) { 5819 block_scope.break_count += 1; 5820 _ = try case_scope.addBreak(.@"break", switch_block, case_result); 5821 } 5822 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. 5823 try scalar_cases_payload.ensureUnusedCapacity(gpa, case_scope.instructions.items.len + 5824 3 + // operand, scalar_cases_len, else body len 5825 @boolToInt(multi_cases_len != 0)); 5826 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); 5827 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); 5828 if (multi_cases_len != 0) { 5829 scalar_cases_payload.appendAssumeCapacity(multi_cases_len); 5830 } 5831 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); 5832 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); 5833 } else { 5834 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. 5835 try scalar_cases_payload.ensureUnusedCapacity( 5836 gpa, 5837 @as(usize, 2) + // operand, scalar_cases_len 5838 @boolToInt(multi_cases_len != 0), 5839 ); 5840 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); 5841 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); 5842 if (multi_cases_len != 0) { 5843 scalar_cases_payload.appendAssumeCapacity(multi_cases_len); 5844 } 5845 } 5846 5847 // In this pass we generate all the item and prong expressions except the special case. 5848 var multi_case_index: u32 = 0; 5849 var scalar_case_index: u32 = 0; 5850 for (case_nodes) |case_node| { 5851 if (case_node == special_node) 5852 continue; 5853 const case = switch (node_tags[case_node]) { 5854 .switch_case_one => tree.switchCaseOne(case_node), 5855 .switch_case => tree.switchCase(case_node), 5856 else => unreachable, 5857 }; 5858 5859 // Reset the scope. 5860 case_scope.instructions.shrinkRetainingCapacity(0); 5861 5862 const is_multi_case = case.ast.values.len != 1 or 5863 node_tags[case.ast.values[0]] == .switch_range; 5864 5865 const sub_scope = blk: { 5866 const payload_token = case.payload_token orelse break :blk &case_scope.base; 5867 const ident = if (token_tags[payload_token] == .asterisk) 5868 payload_token + 1 5869 else 5870 payload_token; 5871 const is_ptr = ident != payload_token; 5872 if (mem.eql(u8, tree.tokenSlice(ident), "_")) { 5873 if (is_ptr) { 5874 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); 5875 } 5876 break :blk &case_scope.base; 5877 } 5878 const is_multi_case_bits: u2 = @boolToInt(is_multi_case); 5879 const is_ptr_bits: u2 = @boolToInt(is_ptr); 5880 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { 5881 0b00 => .switch_capture, 5882 0b01 => .switch_capture_ref, 5883 0b10 => .switch_capture_multi, 5884 0b11 => .switch_capture_multi_ref, 5885 }; 5886 const capture_index = if (is_multi_case) ci: { 5887 multi_case_index += 1; 5888 break :ci multi_case_index - 1; 5889 } else ci: { 5890 scalar_case_index += 1; 5891 break :ci scalar_case_index - 1; 5892 }; 5893 const capture = try case_scope.add(.{ 5894 .tag = capture_tag, 5895 .data = .{ .switch_capture = .{ 5896 .switch_inst = switch_block, 5897 .prong_index = capture_index, 5898 } }, 5899 }); 5900 const capture_name = try astgen.identAsString(ident); 5901 capture_val_scope = .{ 5902 .parent = &case_scope.base, 5903 .gen_zir = &case_scope, 5904 .name = capture_name, 5905 .inst = capture, 5906 .token_src = payload_token, 5907 .id_cat = .@"capture", 5908 }; 5909 break :blk &capture_val_scope.base; 5910 }; 5911 5912 if (is_multi_case) { 5913 // items_len, ranges_len, body_len 5914 const header_index = multi_cases_payload.items.len; 5915 try multi_cases_payload.resize(gpa, multi_cases_payload.items.len + 3); 5916 5917 // items 5918 var items_len: u32 = 0; 5919 for (case.ast.values) |item_node| { 5920 if (node_tags[item_node] == .switch_range) continue; 5921 items_len += 1; 5922 5923 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); 5924 try multi_cases_payload.append(gpa, @enumToInt(item_inst)); 5925 } 5926 5927 // ranges 5928 var ranges_len: u32 = 0; 5929 for (case.ast.values) |range| { 5930 if (node_tags[range] != .switch_range) continue; 5931 ranges_len += 1; 5932 5933 const first = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].lhs); 5934 const last = try comptimeExpr(parent_gz, scope, item_rl, node_datas[range].rhs); 5935 try multi_cases_payload.appendSlice(gpa, &[_]u32{ 5936 @enumToInt(first), @enumToInt(last), 5937 }); 5938 } 5939 5940 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); 5941 try checkUsed(parent_gz, &case_scope.base, sub_scope); 5942 if (!parent_gz.refIsNoReturn(case_result)) { 5943 block_scope.break_count += 1; 5944 _ = try case_scope.addBreak(.@"break", switch_block, case_result); 5945 } 5946 5947 multi_cases_payload.items[header_index + 0] = items_len; 5948 multi_cases_payload.items[header_index + 1] = ranges_len; 5949 multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len); 5950 try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items); 5951 } else { 5952 const item_node = case.ast.values[0]; 5953 const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); 5954 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); 5955 try checkUsed(parent_gz, &case_scope.base, sub_scope); 5956 if (!parent_gz.refIsNoReturn(case_result)) { 5957 block_scope.break_count += 1; 5958 _ = try case_scope.addBreak(.@"break", switch_block, case_result); 5959 } 5960 try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 + 5961 case_scope.instructions.items.len); 5962 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst)); 5963 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); 5964 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); 5965 } 5966 } 5967 // Now that the item expressions are generated we can add this. 5968 try parent_gz.instructions.append(gpa, switch_block); 5969 5970 const ref_bit: u4 = @boolToInt(any_payload_is_ref); 5971 const multi_bit: u4 = @boolToInt(multi_cases_len != 0); 5972 const special_prong_bits: u4 = @enumToInt(special_prong); 5973 comptime { 5974 assert(@enumToInt(Zir.SpecialProng.none) == 0b00); 5975 assert(@enumToInt(Zir.SpecialProng.@"else") == 0b01); 5976 assert(@enumToInt(Zir.SpecialProng.under) == 0b10); 5977 } 5978 const zir_tags = astgen.instructions.items(.tag); 5979 zir_tags[switch_block] = switch ((ref_bit << 3) | (special_prong_bits << 1) | multi_bit) { 5980 0b0_00_0 => .switch_block, 5981 0b0_00_1 => .switch_block_multi, 5982 0b0_01_0 => .switch_block_else, 5983 0b0_01_1 => .switch_block_else_multi, 5984 0b0_10_0 => .switch_block_under, 5985 0b0_10_1 => .switch_block_under_multi, 5986 0b1_00_0 => .switch_block_ref, 5987 0b1_00_1 => .switch_block_ref_multi, 5988 0b1_01_0 => .switch_block_ref_else, 5989 0b1_01_1 => .switch_block_ref_else_multi, 5990 0b1_10_0 => .switch_block_ref_under, 5991 0b1_10_1 => .switch_block_ref_under_multi, 5992 else => unreachable, 5993 }; 5994 const payload_index = astgen.extra.items.len; 5995 const zir_datas = astgen.instructions.items(.data); 5996 zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); 5997 try astgen.extra.ensureUnusedCapacity(gpa, scalar_cases_payload.items.len + 5998 multi_cases_payload.items.len); 5999 const strat = rl.strategy(&block_scope); 6000 switch (strat.tag) { 6001 .break_operand => { 6002 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus 6003 // `elide_store_to_block_ptr_instructions` will either be true, 6004 // or all prongs are noreturn. 6005 if (!strat.elide_store_to_block_ptr_instructions) { 6006 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); 6007 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); 6008 return indexToRef(switch_block); 6009 } 6010 6011 // There will necessarily be a store_to_block_ptr for 6012 // all prongs, except for prongs that ended with a noreturn instruction. 6013 // Elide all the `store_to_block_ptr` instructions. 6014 6015 // The break instructions need to have their operands coerced if the 6016 // switch's result location is a `ty`. In this case we overwrite the 6017 // `store_to_block_ptr` instruction with an `as` instruction and repurpose 6018 // it as the break operand. 6019 6020 var extra_index: usize = 0; 6021 extra_index += 2; 6022 extra_index += @boolToInt(multi_cases_len != 0); 6023 if (special_prong != .none) special_prong: { 6024 const body_len_index = extra_index; 6025 const body_len = scalar_cases_payload.items[extra_index]; 6026 extra_index += 1; 6027 if (body_len < 2) { 6028 extra_index += body_len; 6029 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); 6030 break :special_prong; 6031 } 6032 extra_index += body_len - 2; 6033 const store_inst = scalar_cases_payload.items[extra_index]; 6034 if (zir_tags[store_inst] != .store_to_block_ptr or 6035 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) 6036 { 6037 extra_index += 2; 6038 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); 6039 break :special_prong; 6040 } 6041 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); 6042 if (block_scope.rl_ty_inst != .none) { 6043 extra_index += 1; 6044 const break_inst = scalar_cases_payload.items[extra_index]; 6045 extra_index += 1; 6046 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); 6047 zir_tags[store_inst] = .as; 6048 zir_datas[store_inst].bin = .{ 6049 .lhs = block_scope.rl_ty_inst, 6050 .rhs = zir_datas[break_inst].@"break".operand, 6051 }; 6052 zir_datas[break_inst].@"break".operand = indexToRef(store_inst); 6053 } else { 6054 scalar_cases_payload.items[body_len_index] -= 1; 6055 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); 6056 extra_index += 1; 6057 astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); 6058 extra_index += 1; 6059 } 6060 } else { 6061 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); 6062 } 6063 var scalar_i: u32 = 0; 6064 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 6065 const start_index = extra_index; 6066 extra_index += 1; 6067 const body_len_index = extra_index; 6068 const body_len = scalar_cases_payload.items[extra_index]; 6069 extra_index += 1; 6070 if (body_len < 2) { 6071 extra_index += body_len; 6072 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); 6073 continue; 6074 } 6075 extra_index += body_len - 2; 6076 const store_inst = scalar_cases_payload.items[extra_index]; 6077 if (zir_tags[store_inst] != .store_to_block_ptr or 6078 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) 6079 { 6080 extra_index += 2; 6081 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); 6082 continue; 6083 } 6084 if (block_scope.rl_ty_inst != .none) { 6085 extra_index += 1; 6086 const break_inst = scalar_cases_payload.items[extra_index]; 6087 extra_index += 1; 6088 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); 6089 zir_tags[store_inst] = .as; 6090 zir_datas[store_inst].bin = .{ 6091 .lhs = block_scope.rl_ty_inst, 6092 .rhs = zir_datas[break_inst].@"break".operand, 6093 }; 6094 zir_datas[break_inst].@"break".operand = indexToRef(store_inst); 6095 } else { 6096 scalar_cases_payload.items[body_len_index] -= 1; 6097 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[start_index..extra_index]); 6098 extra_index += 1; 6099 astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); 6100 extra_index += 1; 6101 } 6102 } 6103 extra_index = 0; 6104 var multi_i: u32 = 0; 6105 while (multi_i < multi_cases_len) : (multi_i += 1) { 6106 const start_index = extra_index; 6107 const items_len = multi_cases_payload.items[extra_index]; 6108 extra_index += 1; 6109 const ranges_len = multi_cases_payload.items[extra_index]; 6110 extra_index += 1; 6111 const body_len_index = extra_index; 6112 const body_len = multi_cases_payload.items[extra_index]; 6113 extra_index += 1; 6114 extra_index += items_len; 6115 extra_index += 2 * ranges_len; 6116 if (body_len < 2) { 6117 extra_index += body_len; 6118 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); 6119 continue; 6120 } 6121 extra_index += body_len - 2; 6122 const store_inst = multi_cases_payload.items[extra_index]; 6123 if (zir_tags[store_inst] != .store_to_block_ptr or 6124 zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) 6125 { 6126 extra_index += 2; 6127 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); 6128 continue; 6129 } 6130 if (block_scope.rl_ty_inst != .none) { 6131 extra_index += 1; 6132 const break_inst = multi_cases_payload.items[extra_index]; 6133 extra_index += 1; 6134 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); 6135 zir_tags[store_inst] = .as; 6136 zir_datas[store_inst].bin = .{ 6137 .lhs = block_scope.rl_ty_inst, 6138 .rhs = zir_datas[break_inst].@"break".operand, 6139 }; 6140 zir_datas[break_inst].@"break".operand = indexToRef(store_inst); 6141 } else { 6142 assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); 6143 multi_cases_payload.items[body_len_index] -= 1; 6144 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items[start_index..extra_index]); 6145 extra_index += 1; 6146 astgen.extra.appendAssumeCapacity(multi_cases_payload.items[extra_index]); 6147 extra_index += 1; 6148 } 6149 } 6150 6151 const block_ref = indexToRef(switch_block); 6152 switch (rl) { 6153 .ref => return block_ref, 6154 else => return rvalue(parent_gz, rl, block_ref, switch_node), 6155 } 6156 }, 6157 .break_void => { 6158 assert(!strat.elide_store_to_block_ptr_instructions); 6159 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); 6160 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); 6161 // Modify all the terminating instruction tags to become `break` variants. 6162 var extra_index: usize = payload_index; 6163 extra_index += 2; 6164 extra_index += @boolToInt(multi_cases_len != 0); 6165 if (special_prong != .none) { 6166 const body_len = astgen.extra.items[extra_index]; 6167 extra_index += 1; 6168 const body = astgen.extra.items[extra_index..][0..body_len]; 6169 extra_index += body_len; 6170 const last = body[body.len - 1]; 6171 if (zir_tags[last] == .@"break" and 6172 zir_datas[last].@"break".block_inst == switch_block) 6173 { 6174 zir_datas[last].@"break".operand = .void_value; 6175 } 6176 } 6177 var scalar_i: u32 = 0; 6178 while (scalar_i < scalar_cases_len) : (scalar_i += 1) { 6179 extra_index += 1; 6180 const body_len = astgen.extra.items[extra_index]; 6181 extra_index += 1; 6182 const body = astgen.extra.items[extra_index..][0..body_len]; 6183 extra_index += body_len; 6184 const last = body[body.len - 1]; 6185 if (zir_tags[last] == .@"break" and 6186 zir_datas[last].@"break".block_inst == switch_block) 6187 { 6188 zir_datas[last].@"break".operand = .void_value; 6189 } 6190 } 6191 var multi_i: u32 = 0; 6192 while (multi_i < multi_cases_len) : (multi_i += 1) { 6193 const items_len = astgen.extra.items[extra_index]; 6194 extra_index += 1; 6195 const ranges_len = astgen.extra.items[extra_index]; 6196 extra_index += 1; 6197 const body_len = astgen.extra.items[extra_index]; 6198 extra_index += 1; 6199 extra_index += items_len; 6200 extra_index += 2 * ranges_len; 6201 const body = astgen.extra.items[extra_index..][0..body_len]; 6202 extra_index += body_len; 6203 const last = body[body.len - 1]; 6204 if (zir_tags[last] == .@"break" and 6205 zir_datas[last].@"break".block_inst == switch_block) 6206 { 6207 zir_datas[last].@"break".operand = .void_value; 6208 } 6209 } 6210 6211 return indexToRef(switch_block); 6212 }, 6213 } 6214 } 6215 6216 fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 6217 const astgen = gz.astgen; 6218 const tree = astgen.tree; 6219 const node_datas = tree.nodes.items(.data); 6220 const node_tags = tree.nodes.items(.tag); 6221 6222 if (astgen.fn_block == null) { 6223 return astgen.failNode(node, "'return' outside function scope", .{}); 6224 } 6225 6226 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{}); 6227 6228 const defer_outer = &astgen.fn_block.?.base; 6229 6230 const operand_node = node_datas[node].lhs; 6231 if (operand_node == 0) { 6232 // Returning a void value; skip error defers. 6233 try genDefers(gz, defer_outer, scope, .normal_only); 6234 _ = try gz.addUnNode(.ret_node, .void_value, node); 6235 return Zir.Inst.Ref.unreachable_value; 6236 } 6237 6238 if (node_tags[operand_node] == .error_value) { 6239 // Hot path for `return error.Foo`. This bypasses result location logic as well as logic 6240 // for detecting whether to add something to the function's inferred error set. 6241 const ident_token = node_datas[operand_node].rhs; 6242 const err_name_str_index = try astgen.identAsString(ident_token); 6243 const defer_counts = countDefers(astgen, defer_outer, scope); 6244 if (!defer_counts.need_err_code) { 6245 try genDefers(gz, defer_outer, scope, .both_sans_err); 6246 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token); 6247 return Zir.Inst.Ref.unreachable_value; 6248 } 6249 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token); 6250 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 6251 _ = try gz.addUnNode(.ret_node, err_code, node); 6252 return Zir.Inst.Ref.unreachable_value; 6253 } 6254 6255 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{ 6256 .ptr = try gz.addNodeExtended(.ret_ptr, node), 6257 } else .{ 6258 .ty = try gz.addNodeExtended(.ret_type, node), 6259 }; 6260 const operand = try expr(gz, scope, rl, operand_node); 6261 6262 switch (nodeMayEvalToError(tree, operand_node)) { 6263 .never => { 6264 // Returning a value that cannot be an error; skip error defers. 6265 try genDefers(gz, defer_outer, scope, .normal_only); 6266 _ = try gz.addUnNode(.ret_node, operand, node); 6267 return Zir.Inst.Ref.unreachable_value; 6268 }, 6269 .always => { 6270 // Value is always an error. Emit both error defers and regular defers. 6271 const err_code = try gz.addUnNode(.err_union_code, operand, node); 6272 try genDefers(gz, defer_outer, scope, .{ .both = err_code }); 6273 try gz.addRet(rl, operand, node); 6274 return Zir.Inst.Ref.unreachable_value; 6275 }, 6276 .maybe => { 6277 const defer_counts = countDefers(astgen, defer_outer, scope); 6278 if (!defer_counts.have_err) { 6279 // Only regular defers; no branch needed. 6280 try genDefers(gz, defer_outer, scope, .normal_only); 6281 try gz.addRet(rl, operand, node); 6282 return Zir.Inst.Ref.unreachable_value; 6283 } 6284 6285 // Emit conditional branch for generating errdefers. 6286 const is_non_err = try gz.addUnNode(.is_non_err, operand, node); 6287 const condbr = try gz.addCondBr(.condbr, node); 6288 6289 var then_scope = gz.makeSubBlock(scope); 6290 defer then_scope.instructions.deinit(astgen.gpa); 6291 6292 try genDefers(&then_scope, defer_outer, scope, .normal_only); 6293 try then_scope.addRet(rl, operand, node); 6294 6295 var else_scope = gz.makeSubBlock(scope); 6296 defer else_scope.instructions.deinit(astgen.gpa); 6297 6298 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{ 6299 .both = try else_scope.addUnNode(.err_union_code, operand, node), 6300 }; 6301 try genDefers(&else_scope, defer_outer, scope, which_ones); 6302 try else_scope.addRet(rl, operand, node); 6303 6304 try setCondBrPayload(condbr, is_non_err, &then_scope, &else_scope); 6305 6306 return Zir.Inst.Ref.unreachable_value; 6307 }, 6308 } 6309 } 6310 6311 fn identifier( 6312 gz: *GenZir, 6313 scope: *Scope, 6314 rl: ResultLoc, 6315 ident: ast.Node.Index, 6316 ) InnerError!Zir.Inst.Ref { 6317 const tracy = trace(@src()); 6318 defer tracy.end(); 6319 6320 const astgen = gz.astgen; 6321 const tree = astgen.tree; 6322 const main_tokens = tree.nodes.items(.main_token); 6323 6324 const ident_token = main_tokens[ident]; 6325 const ident_name_raw = tree.tokenSlice(ident_token); 6326 if (mem.eql(u8, ident_name_raw, "_")) { 6327 return astgen.failNode(ident, "'_' used as an identifier without @\"_\" syntax", .{}); 6328 } 6329 const ident_name = try astgen.identifierTokenString(ident_token); 6330 6331 if (ident_name_raw[0] != '@') { 6332 if (simple_types.get(ident_name)) |zir_const_ref| { 6333 return rvalue(gz, rl, zir_const_ref, ident); 6334 } 6335 6336 if (ident_name.len >= 2) integer: { 6337 const first_c = ident_name[0]; 6338 if (first_c == 'i' or first_c == 'u') { 6339 const signedness: std.builtin.Signedness = switch (first_c == 'i') { 6340 true => .signed, 6341 false => .unsigned, 6342 }; 6343 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { 6344 error.Overflow => return astgen.failNode( 6345 ident, 6346 "primitive integer type '{s}' exceeds maximum bit width of 65535", 6347 .{ident_name}, 6348 ), 6349 error.InvalidCharacter => break :integer, 6350 }; 6351 const result = try gz.add(.{ 6352 .tag = .int_type, 6353 .data = .{ .int_type = .{ 6354 .src_node = gz.nodeIndexToRelative(ident), 6355 .signedness = signedness, 6356 .bit_count = bit_count, 6357 } }, 6358 }); 6359 return rvalue(gz, rl, result, ident); 6360 } 6361 } 6362 } 6363 6364 // Local variables, including function parameters. 6365 const name_str_index = try astgen.identAsString(ident_token); 6366 var s = scope; 6367 var found_already: ?ast.Node.Index = null; // we have found a decl with the same name already 6368 var hit_namespace: ast.Node.Index = 0; 6369 while (true) switch (s.tag) { 6370 .local_val => { 6371 const local_val = s.cast(Scope.LocalVal).?; 6372 6373 if (local_val.name == name_str_index) { 6374 local_val.used = true; 6375 // Captures of non-locals need to be emitted as decl_val or decl_ref. 6376 // This *might* be capturable depending on if it is comptime known. 6377 if (hit_namespace == 0) { 6378 return rvalue(gz, rl, local_val.inst, ident); 6379 } 6380 } 6381 s = local_val.parent; 6382 }, 6383 .local_ptr => { 6384 const local_ptr = s.cast(Scope.LocalPtr).?; 6385 if (local_ptr.name == name_str_index) { 6386 local_ptr.used = true; 6387 if (hit_namespace != 0) { 6388 if (local_ptr.maybe_comptime) 6389 break 6390 else 6391 return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{ 6392 try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}), 6393 try astgen.errNoteNode(hit_namespace, "crosses namespace boundary here", .{}), 6394 }); 6395 } 6396 switch (rl) { 6397 .ref, .none_or_ref => return local_ptr.ptr, 6398 else => { 6399 const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident); 6400 return rvalue(gz, rl, loaded, ident); 6401 }, 6402 } 6403 } 6404 s = local_ptr.parent; 6405 }, 6406 .gen_zir => s = s.cast(GenZir).?.parent, 6407 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 6408 .namespace => { 6409 const ns = s.cast(Scope.Namespace).?; 6410 if (ns.decls.get(name_str_index)) |i| { 6411 if (found_already) |f| { 6412 return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{ 6413 try astgen.errNoteNode(f, "declared here", .{}), 6414 try astgen.errNoteNode(i, "also declared here", .{}), 6415 }); 6416 } 6417 // We found a match but must continue looking for ambiguous references to decls. 6418 found_already = i; 6419 } 6420 hit_namespace = ns.node; 6421 s = ns.parent; 6422 }, 6423 .top => break, 6424 }; 6425 6426 // Decl references happen by name rather than ZIR index so that when unrelated 6427 // decls are modified, ZIR code containing references to them can be unmodified. 6428 switch (rl) { 6429 .ref, .none_or_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), 6430 else => { 6431 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); 6432 return rvalue(gz, rl, result, ident); 6433 }, 6434 } 6435 } 6436 6437 fn stringLiteral( 6438 gz: *GenZir, 6439 rl: ResultLoc, 6440 node: ast.Node.Index, 6441 ) InnerError!Zir.Inst.Ref { 6442 const astgen = gz.astgen; 6443 const tree = astgen.tree; 6444 const main_tokens = tree.nodes.items(.main_token); 6445 const str_lit_token = main_tokens[node]; 6446 const str = try astgen.strLitAsString(str_lit_token); 6447 const result = try gz.add(.{ 6448 .tag = .str, 6449 .data = .{ .str = .{ 6450 .start = str.index, 6451 .len = str.len, 6452 } }, 6453 }); 6454 return rvalue(gz, rl, result, node); 6455 } 6456 6457 fn multilineStringLiteral( 6458 gz: *GenZir, 6459 rl: ResultLoc, 6460 node: ast.Node.Index, 6461 ) InnerError!Zir.Inst.Ref { 6462 const astgen = gz.astgen; 6463 const str = try astgen.strLitNodeAsString(node); 6464 const result = try gz.add(.{ 6465 .tag = .str, 6466 .data = .{ .str = .{ 6467 .start = str.index, 6468 .len = str.len, 6469 } }, 6470 }); 6471 return rvalue(gz, rl, result, node); 6472 } 6473 6474 fn charLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { 6475 const astgen = gz.astgen; 6476 const tree = astgen.tree; 6477 const main_tokens = tree.nodes.items(.main_token); 6478 const main_token = main_tokens[node]; 6479 const slice = tree.tokenSlice(main_token); 6480 6481 switch (std.zig.parseCharLiteral(slice)) { 6482 .success => |codepoint| { 6483 const result = try gz.addInt(codepoint); 6484 return rvalue(gz, rl, result, node); 6485 }, 6486 .invalid_escape_character => |bad_index| { 6487 return astgen.failOff( 6488 main_token, 6489 @intCast(u32, bad_index), 6490 "invalid escape character: '{c}'", 6491 .{slice[bad_index]}, 6492 ); 6493 }, 6494 .expected_hex_digit => |bad_index| { 6495 return astgen.failOff( 6496 main_token, 6497 @intCast(u32, bad_index), 6498 "expected hex digit, found '{c}'", 6499 .{slice[bad_index]}, 6500 ); 6501 }, 6502 .empty_unicode_escape_sequence => |bad_index| { 6503 return astgen.failOff( 6504 main_token, 6505 @intCast(u32, bad_index), 6506 "empty unicode escape sequence", 6507 .{}, 6508 ); 6509 }, 6510 .expected_hex_digit_or_rbrace => |bad_index| { 6511 return astgen.failOff( 6512 main_token, 6513 @intCast(u32, bad_index), 6514 "expected hex digit or '}}', found '{c}'", 6515 .{slice[bad_index]}, 6516 ); 6517 }, 6518 .unicode_escape_overflow => |bad_index| { 6519 return astgen.failOff( 6520 main_token, 6521 @intCast(u32, bad_index), 6522 "unicode escape too large to be a valid codepoint", 6523 .{}, 6524 ); 6525 }, 6526 .expected_lbrace => |bad_index| { 6527 return astgen.failOff( 6528 main_token, 6529 @intCast(u32, bad_index), 6530 "expected '{{', found '{c}", 6531 .{slice[bad_index]}, 6532 ); 6533 }, 6534 .expected_end => |bad_index| { 6535 return astgen.failOff( 6536 main_token, 6537 @intCast(u32, bad_index), 6538 "expected ending single quote ('), found '{c}", 6539 .{slice[bad_index]}, 6540 ); 6541 }, 6542 .invalid_character => |bad_index| { 6543 return astgen.failOff( 6544 main_token, 6545 @intCast(u32, bad_index), 6546 "invalid byte in character literal: '{c}'", 6547 .{slice[bad_index]}, 6548 ); 6549 }, 6550 } 6551 } 6552 6553 fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 6554 const astgen = gz.astgen; 6555 const tree = astgen.tree; 6556 const main_tokens = tree.nodes.items(.main_token); 6557 const int_token = main_tokens[node]; 6558 const prefixed_bytes = tree.tokenSlice(int_token); 6559 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| { 6560 const result: Zir.Inst.Ref = switch (small_int) { 6561 0 => .zero, 6562 1 => .one, 6563 else => try gz.addInt(small_int), 6564 }; 6565 return rvalue(gz, rl, result, node); 6566 } else |err| switch (err) { 6567 error.InvalidCharacter => unreachable, // Caught by the parser. 6568 error.Overflow => {}, 6569 } 6570 6571 var base: u8 = 10; 6572 var non_prefixed: []const u8 = prefixed_bytes; 6573 if (mem.startsWith(u8, prefixed_bytes, "0x")) { 6574 base = 16; 6575 non_prefixed = prefixed_bytes[2..]; 6576 } else if (mem.startsWith(u8, prefixed_bytes, "0o")) { 6577 base = 8; 6578 non_prefixed = prefixed_bytes[2..]; 6579 } else if (mem.startsWith(u8, prefixed_bytes, "0b")) { 6580 base = 2; 6581 non_prefixed = prefixed_bytes[2..]; 6582 } 6583 6584 const gpa = astgen.gpa; 6585 var big_int = try std.math.big.int.Managed.init(gpa); 6586 defer big_int.deinit(); 6587 big_int.setString(base, non_prefixed) catch |err| switch (err) { 6588 error.InvalidCharacter => unreachable, // caught by parser 6589 error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above 6590 error.OutOfMemory => return error.OutOfMemory, 6591 }; 6592 6593 const limbs = big_int.limbs[0..big_int.len()]; 6594 assert(big_int.isPositive()); 6595 const result = try gz.addIntBig(limbs); 6596 return rvalue(gz, rl, result, node); 6597 } 6598 6599 fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { 6600 const astgen = gz.astgen; 6601 const tree = astgen.tree; 6602 const main_tokens = tree.nodes.items(.main_token); 6603 6604 const main_token = main_tokens[node]; 6605 const bytes = tree.tokenSlice(main_token); 6606 const float_number: f128 = if (bytes.len > 2 and bytes[1] == 'x') hex: { 6607 assert(bytes[0] == '0'); // validated by tokenizer 6608 break :hex std.fmt.parseHexFloat(f128, bytes) catch |err| switch (err) { 6609 error.InvalidCharacter => unreachable, // validated by tokenizer 6610 error.Overflow => return astgen.failNode(node, "number literal cannot be represented in a 128-bit floating point", .{}), 6611 }; 6612 } else std.fmt.parseFloat(f128, bytes) catch |err| switch (err) { 6613 error.InvalidCharacter => unreachable, // validated by tokenizer 6614 }; 6615 // If the value fits into a f64 without losing any precision, store it that way. 6616 @setFloatMode(.Strict); 6617 const smaller_float = @floatCast(f64, float_number); 6618 const bigger_again: f128 = smaller_float; 6619 if (bigger_again == float_number) { 6620 const result = try gz.addFloat(smaller_float); 6621 return rvalue(gz, rl, result, node); 6622 } 6623 // We need to use 128 bits. Break the float into 4 u32 values so we can 6624 // put it into the `extra` array. 6625 const int_bits = @bitCast(u128, float_number); 6626 const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{ 6627 .piece0 = @truncate(u32, int_bits), 6628 .piece1 = @truncate(u32, int_bits >> 32), 6629 .piece2 = @truncate(u32, int_bits >> 64), 6630 .piece3 = @truncate(u32, int_bits >> 96), 6631 }); 6632 return rvalue(gz, rl, result, node); 6633 } 6634 6635 fn asmExpr( 6636 gz: *GenZir, 6637 scope: *Scope, 6638 rl: ResultLoc, 6639 node: ast.Node.Index, 6640 full: ast.full.Asm, 6641 ) InnerError!Zir.Inst.Ref { 6642 const astgen = gz.astgen; 6643 const tree = astgen.tree; 6644 const main_tokens = tree.nodes.items(.main_token); 6645 const node_datas = tree.nodes.items(.data); 6646 const node_tags = tree.nodes.items(.tag); 6647 const token_tags = tree.tokens.items(.tag); 6648 6649 const asm_source = switch (node_tags[full.ast.template]) { 6650 .string_literal => try astgen.strLitAsString(main_tokens[full.ast.template]), 6651 .multiline_string_literal => try astgen.strLitNodeAsString(full.ast.template), 6652 else => return astgen.failNode(full.ast.template, "assembly code must use string literal syntax", .{}), 6653 }; 6654 6655 // See https://github.com/ziglang/zig/issues/215 and related issues discussing 6656 // possible inline assembly improvements. Until then here is status quo AstGen 6657 // for assembly syntax. It's used by std lib crypto aesni.zig. 6658 const is_container_asm = astgen.fn_block == null; 6659 if (is_container_asm) { 6660 if (full.volatile_token) |t| 6661 return astgen.failTok(t, "volatile is meaningless on global assembly", .{}); 6662 if (full.outputs.len != 0 or full.inputs.len != 0 or full.first_clobber != null) 6663 return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{}); 6664 } else { 6665 if (full.outputs.len == 0 and full.volatile_token == null) { 6666 return astgen.failNode(node, "assembly expression with no output must be marked volatile", .{}); 6667 } 6668 } 6669 if (full.outputs.len > 32) { 6670 return astgen.failNode(full.outputs[32], "too many asm outputs", .{}); 6671 } 6672 var outputs_buffer: [32]Zir.Inst.Asm.Output = undefined; 6673 const outputs = outputs_buffer[0..full.outputs.len]; 6674 6675 var output_type_bits: u32 = 0; 6676 6677 for (full.outputs) |output_node, i| { 6678 const symbolic_name = main_tokens[output_node]; 6679 const name = try astgen.identAsString(symbolic_name); 6680 const constraint_token = symbolic_name + 2; 6681 const constraint = (try astgen.strLitAsString(constraint_token)).index; 6682 const has_arrow = token_tags[symbolic_name + 4] == .arrow; 6683 if (has_arrow) { 6684 output_type_bits |= @as(u32, 1) << @intCast(u5, i); 6685 const out_type_node = node_datas[output_node].lhs; 6686 const out_type_inst = try typeExpr(gz, scope, out_type_node); 6687 outputs[i] = .{ 6688 .name = name, 6689 .constraint = constraint, 6690 .operand = out_type_inst, 6691 }; 6692 } else { 6693 const ident_token = symbolic_name + 4; 6694 const str_index = try astgen.identAsString(ident_token); 6695 // TODO this needs extra code for local variables. Have a look at #215 and related 6696 // issues and decide how to handle outputs. Do we want this to be identifiers? 6697 // Or maybe we want to force this to be expressions with a pointer type. 6698 // Until that is figured out this is only hooked up for referencing Decls. 6699 // TODO we have put this as an identifier lookup just so that we don't get 6700 // unused vars for outputs. We need to check if this is correct in the future ^^ 6701 // so we just put in this simple lookup. This is a workaround. 6702 { 6703 var s = scope; 6704 while (true) switch (s.tag) { 6705 .local_val => { 6706 const local_val = s.cast(Scope.LocalVal).?; 6707 if (local_val.name == str_index) { 6708 local_val.used = true; 6709 break; 6710 } 6711 s = local_val.parent; 6712 }, 6713 .local_ptr => { 6714 const local_ptr = s.cast(Scope.LocalPtr).?; 6715 if (local_ptr.name == str_index) { 6716 local_ptr.used = true; 6717 break; 6718 } 6719 s = local_ptr.parent; 6720 }, 6721 .gen_zir => s = s.cast(GenZir).?.parent, 6722 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 6723 .namespace, .top => break, 6724 }; 6725 } 6726 const operand = try gz.addStrTok(.decl_ref, str_index, ident_token); 6727 outputs[i] = .{ 6728 .name = name, 6729 .constraint = constraint, 6730 .operand = operand, 6731 }; 6732 } 6733 } 6734 6735 if (full.inputs.len > 32) { 6736 return astgen.failNode(full.inputs[32], "too many asm inputs", .{}); 6737 } 6738 var inputs_buffer: [32]Zir.Inst.Asm.Input = undefined; 6739 const inputs = inputs_buffer[0..full.inputs.len]; 6740 6741 for (full.inputs) |input_node, i| { 6742 const symbolic_name = main_tokens[input_node]; 6743 const name = try astgen.identAsString(symbolic_name); 6744 const constraint_token = symbolic_name + 2; 6745 const constraint = (try astgen.strLitAsString(constraint_token)).index; 6746 const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs); 6747 inputs[i] = .{ 6748 .name = name, 6749 .constraint = constraint, 6750 .operand = operand, 6751 }; 6752 } 6753 6754 var clobbers_buffer: [32]u32 = undefined; 6755 var clobber_i: usize = 0; 6756 if (full.first_clobber) |first_clobber| clobbers: { 6757 // asm ("foo" ::: "a", "b") 6758 // asm ("foo" ::: "a", "b",) 6759 var tok_i = first_clobber; 6760 while (true) : (tok_i += 1) { 6761 if (clobber_i >= clobbers_buffer.len) { 6762 return astgen.failTok(tok_i, "too many asm clobbers", .{}); 6763 } 6764 clobbers_buffer[clobber_i] = (try astgen.strLitAsString(tok_i)).index; 6765 clobber_i += 1; 6766 tok_i += 1; 6767 switch (token_tags[tok_i]) { 6768 .r_paren => break :clobbers, 6769 .comma => { 6770 if (token_tags[tok_i + 1] == .r_paren) { 6771 break :clobbers; 6772 } else { 6773 continue; 6774 } 6775 }, 6776 else => unreachable, 6777 } 6778 } 6779 } 6780 6781 const result = try gz.addAsm(.{ 6782 .node = node, 6783 .asm_source = asm_source.index, 6784 .is_volatile = full.volatile_token != null, 6785 .output_type_bits = output_type_bits, 6786 .outputs = outputs, 6787 .inputs = inputs, 6788 .clobbers = clobbers_buffer[0..clobber_i], 6789 }); 6790 return rvalue(gz, rl, result, node); 6791 } 6792 6793 fn as( 6794 gz: *GenZir, 6795 scope: *Scope, 6796 rl: ResultLoc, 6797 node: ast.Node.Index, 6798 lhs: ast.Node.Index, 6799 rhs: ast.Node.Index, 6800 ) InnerError!Zir.Inst.Ref { 6801 const dest_type = try typeExpr(gz, scope, lhs); 6802 switch (rl) { 6803 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => { 6804 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); 6805 return rvalue(gz, rl, result, node); 6806 }, 6807 .ptr, .inferred_ptr => |result_ptr| { 6808 return asRlPtr(gz, scope, rl, node, result_ptr, rhs, dest_type); 6809 }, 6810 .block_ptr => |block_scope| { 6811 return asRlPtr(gz, scope, rl, node, block_scope.rl_ptr, rhs, dest_type); 6812 }, 6813 } 6814 } 6815 6816 fn unionInit( 6817 gz: *GenZir, 6818 scope: *Scope, 6819 rl: ResultLoc, 6820 node: ast.Node.Index, 6821 params: []const ast.Node.Index, 6822 ) InnerError!Zir.Inst.Ref { 6823 const union_type = try typeExpr(gz, scope, params[0]); 6824 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 6825 switch (rl) { 6826 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => { 6827 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ 6828 .container_type = union_type, 6829 .field_name = field_name, 6830 }); 6831 const result = try expr(gz, scope, .{ .ty = union_type }, params[2]); 6832 return rvalue(gz, rl, result, node); 6833 }, 6834 .ptr => |result_ptr| { 6835 return unionInitRlPtr(gz, scope, node, result_ptr, params[2], union_type, field_name); 6836 }, 6837 .block_ptr => |block_scope| { 6838 return unionInitRlPtr(gz, scope, node, block_scope.rl_ptr, params[2], union_type, field_name); 6839 }, 6840 } 6841 } 6842 6843 fn unionInitRlPtr( 6844 parent_gz: *GenZir, 6845 scope: *Scope, 6846 node: ast.Node.Index, 6847 result_ptr: Zir.Inst.Ref, 6848 expr_node: ast.Node.Index, 6849 union_type: Zir.Inst.Ref, 6850 field_name: Zir.Inst.Ref, 6851 ) InnerError!Zir.Inst.Ref { 6852 const union_init_ptr = try parent_gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{ 6853 .result_ptr = result_ptr, 6854 .union_type = union_type, 6855 .field_name = field_name, 6856 }); 6857 // TODO check if we need to do the elision like below in asRlPtr 6858 return expr(parent_gz, scope, .{ .ptr = union_init_ptr }, expr_node); 6859 } 6860 6861 fn asRlPtr( 6862 parent_gz: *GenZir, 6863 scope: *Scope, 6864 rl: ResultLoc, 6865 src_node: ast.Node.Index, 6866 result_ptr: Zir.Inst.Ref, 6867 operand_node: ast.Node.Index, 6868 dest_type: Zir.Inst.Ref, 6869 ) InnerError!Zir.Inst.Ref { 6870 // Detect whether this expr() call goes into rvalue() to store the result into the 6871 // result location. If it does, elide the coerce_result_ptr instruction 6872 // as well as the store instruction, instead passing the result as an rvalue. 6873 const astgen = parent_gz.astgen; 6874 6875 var as_scope = parent_gz.makeSubBlock(scope); 6876 defer as_scope.instructions.deinit(astgen.gpa); 6877 6878 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr); 6879 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node); 6880 const parent_zir = &parent_gz.instructions; 6881 if (as_scope.rvalue_rl_count == 1) { 6882 // Busted! This expression didn't actually need a pointer. 6883 const zir_tags = astgen.instructions.items(.tag); 6884 const zir_datas = astgen.instructions.items(.data); 6885 try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len); 6886 for (as_scope.instructions.items) |src_inst| { 6887 if (indexToRef(src_inst) == as_scope.rl_ptr) continue; 6888 if (zir_tags[src_inst] == .store_to_block_ptr) { 6889 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; 6890 } 6891 parent_zir.appendAssumeCapacity(src_inst); 6892 } 6893 const casted_result = try parent_gz.addBin(.as, dest_type, result); 6894 return rvalue(parent_gz, rl, casted_result, operand_node); 6895 } else { 6896 try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items); 6897 return result; 6898 } 6899 } 6900 6901 fn bitCast( 6902 gz: *GenZir, 6903 scope: *Scope, 6904 rl: ResultLoc, 6905 node: ast.Node.Index, 6906 lhs: ast.Node.Index, 6907 rhs: ast.Node.Index, 6908 ) InnerError!Zir.Inst.Ref { 6909 const astgen = gz.astgen; 6910 const dest_type = try typeExpr(gz, scope, lhs); 6911 switch (rl) { 6912 .none, .none_or_ref, .discard, .ty, .coerced_ty => { 6913 const operand = try expr(gz, scope, .none, rhs); 6914 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{ 6915 .lhs = dest_type, 6916 .rhs = operand, 6917 }); 6918 return rvalue(gz, rl, result, node); 6919 }, 6920 .ref => { 6921 return astgen.failNode(node, "cannot take address of `@bitCast` result", .{}); 6922 }, 6923 .ptr, .inferred_ptr => |result_ptr| { 6924 return bitCastRlPtr(gz, scope, node, dest_type, result_ptr, rhs); 6925 }, 6926 .block_ptr => |block| { 6927 return bitCastRlPtr(gz, scope, node, dest_type, block.rl_ptr, rhs); 6928 }, 6929 } 6930 } 6931 6932 fn bitCastRlPtr( 6933 gz: *GenZir, 6934 scope: *Scope, 6935 node: ast.Node.Index, 6936 dest_type: Zir.Inst.Ref, 6937 result_ptr: Zir.Inst.Ref, 6938 rhs: ast.Node.Index, 6939 ) InnerError!Zir.Inst.Ref { 6940 const casted_result_ptr = try gz.addPlNode(.bitcast_result_ptr, node, Zir.Inst.Bin{ 6941 .lhs = dest_type, 6942 .rhs = result_ptr, 6943 }); 6944 return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs); 6945 } 6946 6947 fn typeOf( 6948 gz: *GenZir, 6949 scope: *Scope, 6950 rl: ResultLoc, 6951 node: ast.Node.Index, 6952 params: []const ast.Node.Index, 6953 ) InnerError!Zir.Inst.Ref { 6954 if (params.len < 1) { 6955 return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{}); 6956 } 6957 if (params.len == 1) { 6958 const expr_result = try reachableExpr(gz, scope, .none, params[0], node); 6959 const result = try gz.addUnNode(.typeof, expr_result, node); 6960 return rvalue(gz, rl, result, node); 6961 } 6962 const arena = gz.astgen.arena; 6963 var items = try arena.alloc(Zir.Inst.Ref, params.len); 6964 for (params) |param, param_i| { 6965 items[param_i] = try reachableExpr(gz, scope, .none, param, node); 6966 } 6967 6968 const result = try gz.addExtendedMultiOp(.typeof_peer, node, items); 6969 return rvalue(gz, rl, result, node); 6970 } 6971 6972 fn builtinCall( 6973 gz: *GenZir, 6974 scope: *Scope, 6975 rl: ResultLoc, 6976 node: ast.Node.Index, 6977 params: []const ast.Node.Index, 6978 ) InnerError!Zir.Inst.Ref { 6979 const astgen = gz.astgen; 6980 const tree = astgen.tree; 6981 const main_tokens = tree.nodes.items(.main_token); 6982 6983 const builtin_token = main_tokens[node]; 6984 const builtin_name = tree.tokenSlice(builtin_token); 6985 6986 // We handle the different builtins manually because they have different semantics depending 6987 // on the function. For example, `@as` and others participate in result location semantics, 6988 // and `@cImport` creates a special scope that collects a .c source code text buffer. 6989 // Also, some builtins have a variable number of parameters. 6990 6991 const info = BuiltinFn.list.get(builtin_name) orelse { 6992 return astgen.failNode(node, "invalid builtin function: '{s}'", .{ 6993 builtin_name, 6994 }); 6995 }; 6996 if (info.param_count) |expected| { 6997 if (expected != params.len) { 6998 const s = if (expected == 1) "" else "s"; 6999 return astgen.failNode(node, "expected {d} argument{s}, found {d}", .{ 7000 expected, s, params.len, 7001 }); 7002 } 7003 } 7004 7005 // zig fmt: off 7006 switch (info.tag) { 7007 .import => { 7008 const node_tags = tree.nodes.items(.tag); 7009 const operand_node = params[0]; 7010 7011 if (node_tags[operand_node] != .string_literal) { 7012 // Spec reference: https://github.com/ziglang/zig/issues/2206 7013 return astgen.failNode(operand_node, "@import operand must be a string literal", .{}); 7014 } 7015 const str_lit_token = main_tokens[operand_node]; 7016 const str = try astgen.strLitAsString(str_lit_token); 7017 const result = try gz.addStrTok(.import, str.index, str_lit_token); 7018 const gop = try astgen.imports.getOrPut(astgen.gpa, str.index); 7019 if (!gop.found_existing) { 7020 gop.value_ptr.* = str_lit_token; 7021 } 7022 return rvalue(gz, rl, result, node); 7023 }, 7024 .compile_log => { 7025 const arg_refs = try astgen.gpa.alloc(Zir.Inst.Ref, params.len); 7026 defer astgen.gpa.free(arg_refs); 7027 7028 for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param); 7029 7030 const result = try gz.addExtendedMultiOp(.compile_log, node, arg_refs); 7031 return rvalue(gz, rl, result, node); 7032 }, 7033 .field => { 7034 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 7035 if (rl == .ref) { 7036 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ 7037 .lhs = try expr(gz, scope, .ref, params[0]), 7038 .field_name = field_name, 7039 }); 7040 } 7041 const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ 7042 .lhs = try expr(gz, scope, .none, params[0]), 7043 .field_name = field_name, 7044 }); 7045 return rvalue(gz, rl, result, node); 7046 }, 7047 .as => return as( gz, scope, rl, node, params[0], params[1]), 7048 .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]), 7049 .TypeOf => return typeOf( gz, scope, rl, node, params), 7050 .union_init => return unionInit(gz, scope, rl, node, params), 7051 .c_import => return cImport( gz, scope, rl, node, params[0]), 7052 7053 .@"export" => { 7054 const node_tags = tree.nodes.items(.tag); 7055 const node_datas = tree.nodes.items(.data); 7056 // This function causes a Decl to be exported. The first parameter is not an expression, 7057 // but an identifier of the Decl to be exported. 7058 var namespace: Zir.Inst.Ref = .none; 7059 var decl_name: u32 = 0; 7060 switch (node_tags[params[0]]) { 7061 .identifier => { 7062 const ident_token = main_tokens[params[0]]; 7063 decl_name = try astgen.identAsString(ident_token); 7064 { 7065 var s = scope; 7066 while (true) switch (s.tag) { 7067 .local_val => { 7068 const local_val = s.cast(Scope.LocalVal).?; 7069 if (local_val.name == decl_name) { 7070 local_val.used = true; 7071 break; 7072 } 7073 s = local_val.parent; 7074 }, 7075 .local_ptr => { 7076 const local_ptr = s.cast(Scope.LocalPtr).?; 7077 if (local_ptr.name == decl_name) { 7078 if (!local_ptr.maybe_comptime) 7079 return astgen.failNode(params[0], "unable to export runtime-known value", .{}); 7080 local_ptr.used = true; 7081 break; 7082 } 7083 s = local_ptr.parent; 7084 }, 7085 .gen_zir => s = s.cast(GenZir).?.parent, 7086 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 7087 .namespace, .top => break, 7088 }; 7089 } 7090 }, 7091 .field_access => { 7092 const namespace_node = node_datas[params[0]].lhs; 7093 namespace = try typeExpr(gz, scope, namespace_node); 7094 const dot_token = main_tokens[params[0]]; 7095 const field_ident = dot_token + 1; 7096 decl_name = try astgen.identAsString(field_ident); 7097 }, 7098 else => return astgen.failNode( 7099 params[0], "symbol to export must identify a declaration", .{}, 7100 ), 7101 } 7102 const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]); 7103 _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ 7104 .namespace = namespace, 7105 .decl_name = decl_name, 7106 .options = options, 7107 }); 7108 return rvalue(gz, rl, .void_value, node); 7109 }, 7110 .@"extern" => { 7111 const type_inst = try typeExpr(gz, scope, params[0]); 7112 const options = try comptimeExpr(gz, scope, .{ .ty = .extern_options_type }, params[1]); 7113 const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{ 7114 .node = gz.nodeIndexToRelative(node), 7115 .lhs = type_inst, 7116 .rhs = options, 7117 }); 7118 return rvalue(gz, rl, result, node); 7119 }, 7120 7121 .breakpoint => return simpleNoOpVoid(gz, rl, node, .breakpoint), 7122 .fence => return simpleNoOpVoid(gz, rl, node, .fence), 7123 7124 .This => return rvalue(gz, rl, try gz.addNodeExtended(.this, node), node), 7125 .return_address => return rvalue(gz, rl, try gz.addNodeExtended(.ret_addr, node), node), 7126 .src => return rvalue(gz, rl, try gz.addNodeExtended(.builtin_src, node), node), 7127 .error_return_trace => return rvalue(gz, rl, try gz.addNodeExtended(.error_return_trace, node), node), 7128 .frame => return rvalue(gz, rl, try gz.addNodeExtended(.frame, node), node), 7129 .frame_address => return rvalue(gz, rl, try gz.addNodeExtended(.frame_address, node), node), 7130 7131 .type_info => return simpleUnOpType(gz, scope, rl, node, params[0], .type_info), 7132 .size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .size_of), 7133 .bit_size_of => return simpleUnOpType(gz, scope, rl, node, params[0], .bit_size_of), 7134 .align_of => return simpleUnOpType(gz, scope, rl, node, params[0], .align_of), 7135 7136 .ptr_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ptr_to_int), 7137 .error_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .error_to_int), 7138 .int_to_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u16_type }, params[0], .int_to_error), 7139 .compile_error => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .compile_error), 7140 .set_eval_branch_quota => return simpleUnOp(gz, scope, rl, node, .{ .ty = .u32_type }, params[0], .set_eval_branch_quota), 7141 .enum_to_int => return simpleUnOp(gz, scope, rl, node, .none, params[0], .enum_to_int), 7142 .bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int), 7143 .embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file), 7144 .error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name), 7145 .panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic), 7146 .set_align_stack => return simpleUnOp(gz, scope, rl, node, align_rl, params[0], .set_align_stack), 7147 .set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold), 7148 .set_float_mode => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .float_mode_type }, params[0], .set_float_mode), 7149 .set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety), 7150 .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt), 7151 .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin), 7152 .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos), 7153 .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp), 7154 .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2), 7155 .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log), 7156 .log2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log2), 7157 .log10 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log10), 7158 .fabs => return simpleUnOp(gz, scope, rl, node, .none, params[0], .fabs), 7159 .floor => return simpleUnOp(gz, scope, rl, node, .none, params[0], .floor), 7160 .ceil => return simpleUnOp(gz, scope, rl, node, .none, params[0], .ceil), 7161 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc), 7162 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round), 7163 .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name), 7164 .Type => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .type_info_type }, params[0], .reify), 7165 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name), 7166 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type), 7167 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size), 7168 7169 .float_to_int => return typeCast(gz, scope, rl, node, params[0], params[1], .float_to_int), 7170 .int_to_float => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_float), 7171 .int_to_ptr => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_ptr), 7172 .int_to_enum => return typeCast(gz, scope, rl, node, params[0], params[1], .int_to_enum), 7173 .float_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .float_cast), 7174 .int_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .int_cast), 7175 .err_set_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .err_set_cast), 7176 .ptr_cast => return typeCast(gz, scope, rl, node, params[0], params[1], .ptr_cast), 7177 .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate), 7178 .align_cast => { 7179 const dest_align = try comptimeExpr(gz, scope, align_rl, params[0]); 7180 const rhs = try expr(gz, scope, .none, params[1]); 7181 const result = try gz.addPlNode(.align_cast, node, Zir.Inst.Bin{ 7182 .lhs = dest_align, 7183 .rhs = rhs, 7184 }); 7185 return rvalue(gz, rl, result, node); 7186 }, 7187 7188 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl), 7189 .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field), 7190 7191 .clz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz), 7192 .ctz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz), 7193 .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count), 7194 .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap), 7195 .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse), 7196 7197 .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact), 7198 .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor), 7199 .div_trunc => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_trunc), 7200 .mod => return divBuiltin(gz, scope, rl, node, params[0], params[1], .mod), 7201 .rem => return divBuiltin(gz, scope, rl, node, params[0], params[1], .rem), 7202 7203 .shl_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shl_exact), 7204 .shr_exact => return shiftOp(gz, scope, rl, node, params[0], params[1], .shr_exact), 7205 7206 .bit_offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .bit_offset_of), 7207 .offset_of => return offsetOf(gz, scope, rl, node, params[0], params[1], .offset_of), 7208 7209 .c_undef => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_undef), 7210 .c_include => return simpleCBuiltin(gz, scope, rl, node, params[0], .c_include), 7211 7212 .cmpxchg_strong => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_strong), 7213 .cmpxchg_weak => return cmpxchg(gz, scope, rl, node, params, .cmpxchg_weak), 7214 7215 .wasm_memory_size => { 7216 const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); 7217 const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ 7218 .node = gz.nodeIndexToRelative(node), 7219 .operand = operand, 7220 }); 7221 return rvalue(gz, rl, result, node); 7222 }, 7223 .wasm_memory_grow => { 7224 const index_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); 7225 const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]); 7226 const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ 7227 .node = gz.nodeIndexToRelative(node), 7228 .lhs = index_arg, 7229 .rhs = delta_arg, 7230 }); 7231 return rvalue(gz, rl, result, node); 7232 }, 7233 .c_define => { 7234 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]); 7235 const value = try comptimeExpr(gz, scope, .none, params[1]); 7236 const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ 7237 .node = gz.nodeIndexToRelative(node), 7238 .lhs = name, 7239 .rhs = value, 7240 }); 7241 return rvalue(gz, rl, result, node); 7242 }, 7243 7244 .splat => { 7245 const len = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); 7246 const scalar = try expr(gz, scope, .none, params[1]); 7247 const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{ 7248 .lhs = len, 7249 .rhs = scalar, 7250 }); 7251 return rvalue(gz, rl, result, node); 7252 }, 7253 .reduce => { 7254 const op = try expr(gz, scope, .{ .ty = .reduce_op_type }, params[0]); 7255 const scalar = try expr(gz, scope, .none, params[1]); 7256 const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{ 7257 .lhs = op, 7258 .rhs = scalar, 7259 }); 7260 return rvalue(gz, rl, result, node); 7261 }, 7262 7263 .maximum => { 7264 const a = try expr(gz, scope, .none, params[0]); 7265 const b = try expr(gz, scope, .none, params[1]); 7266 const result = try gz.addPlNode(.maximum, node, Zir.Inst.Bin{ 7267 .lhs = a, 7268 .rhs = b, 7269 }); 7270 return rvalue(gz, rl, result, node); 7271 }, 7272 .minimum => { 7273 const a = try expr(gz, scope, .none, params[0]); 7274 const b = try expr(gz, scope, .none, params[1]); 7275 const result = try gz.addPlNode(.minimum, node, Zir.Inst.Bin{ 7276 .lhs = a, 7277 .rhs = b, 7278 }); 7279 return rvalue(gz, rl, result, node); 7280 }, 7281 7282 .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow), 7283 .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow), 7284 .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow), 7285 .shl_with_overflow => { 7286 const int_type = try typeExpr(gz, scope, params[0]); 7287 const log2_int_type = try gz.addUnNode(.log2_int_type, int_type, params[0]); 7288 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7289 .ptr_type_simple = .{ 7290 .is_allowzero = false, 7291 .is_mutable = true, 7292 .is_volatile = false, 7293 .size = .One, 7294 .elem_type = int_type, 7295 }, 7296 } }); 7297 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); 7298 const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, params[2]); 7299 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); 7300 const result = try gz.addExtendedPayload(.shl_with_overflow, Zir.Inst.OverflowArithmetic{ 7301 .node = gz.nodeIndexToRelative(node), 7302 .lhs = lhs, 7303 .rhs = rhs, 7304 .ptr = ptr, 7305 }); 7306 return rvalue(gz, rl, result, node); 7307 }, 7308 7309 .atomic_load => { 7310 const int_type = try typeExpr(gz, scope, params[0]); 7311 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7312 .ptr_type_simple = .{ 7313 .is_allowzero = false, 7314 .is_mutable = false, 7315 .is_volatile = false, 7316 .size = .One, 7317 .elem_type = int_type, 7318 }, 7319 } }); 7320 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); 7321 const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[2]); 7322 const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.Bin{ 7323 .lhs = ptr, 7324 .rhs = ordering, 7325 }); 7326 return rvalue(gz, rl, result, node); 7327 }, 7328 .atomic_rmw => { 7329 const int_type = try typeExpr(gz, scope, params[0]); 7330 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7331 .ptr_type_simple = .{ 7332 .is_allowzero = false, 7333 .is_mutable = true, 7334 .is_volatile = false, 7335 .size = .One, 7336 .elem_type = int_type, 7337 }, 7338 } }); 7339 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); 7340 const operation = try expr(gz, scope, .{ .ty = .atomic_rmw_op_type }, params[2]); 7341 const operand = try expr(gz, scope, .{ .ty = int_type }, params[3]); 7342 const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]); 7343 const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{ 7344 .ptr = ptr, 7345 .operation = operation, 7346 .operand = operand, 7347 .ordering = ordering, 7348 }); 7349 return rvalue(gz, rl, result, node); 7350 }, 7351 .atomic_store => { 7352 const int_type = try typeExpr(gz, scope, params[0]); 7353 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7354 .ptr_type_simple = .{ 7355 .is_allowzero = false, 7356 .is_mutable = true, 7357 .is_volatile = false, 7358 .size = .One, 7359 .elem_type = int_type, 7360 }, 7361 } }); 7362 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]); 7363 const operand = try expr(gz, scope, .{ .ty = int_type }, params[2]); 7364 const ordering = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[3]); 7365 const result = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{ 7366 .ptr = ptr, 7367 .operand = operand, 7368 .ordering = ordering, 7369 }); 7370 return rvalue(gz, rl, result, node); 7371 }, 7372 .mul_add => { 7373 const float_type = try typeExpr(gz, scope, params[0]); 7374 const mulend1 = try expr(gz, scope, .{ .ty = float_type }, params[1]); 7375 const mulend2 = try expr(gz, scope, .{ .ty = float_type }, params[2]); 7376 const addend = try expr(gz, scope, .{ .ty = float_type }, params[3]); 7377 const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{ 7378 .mulend1 = mulend1, 7379 .mulend2 = mulend2, 7380 .addend = addend, 7381 }); 7382 return rvalue(gz, rl, result, node); 7383 }, 7384 .call => { 7385 const options = try comptimeExpr(gz, scope, .{ .ty = .call_options_type }, params[0]); 7386 const callee = try expr(gz, scope, .none, params[1]); 7387 const args = try expr(gz, scope, .none, params[2]); 7388 const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ 7389 .options = options, 7390 .callee = callee, 7391 .args = args, 7392 }); 7393 return rvalue(gz, rl, result, node); 7394 }, 7395 .field_parent_ptr => { 7396 const parent_type = try typeExpr(gz, scope, params[0]); 7397 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); 7398 const field_ptr_type = try gz.addBin(.field_ptr_type, parent_type, field_name); 7399 const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ 7400 .parent_type = parent_type, 7401 .field_name = field_name, 7402 .field_ptr = try expr(gz, scope, .{ .ty = field_ptr_type }, params[2]), 7403 }); 7404 return rvalue(gz, rl, result, node); 7405 }, 7406 .memcpy => { 7407 const result = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{ 7408 .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]), 7409 .source = try expr(gz, scope, .{ .ty = .manyptr_const_u8_type }, params[1]), 7410 .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]), 7411 }); 7412 return rvalue(gz, rl, result, node); 7413 }, 7414 .memset => { 7415 const result = try gz.addPlNode(.memset, node, Zir.Inst.Memset{ 7416 .dest = try expr(gz, scope, .{ .ty = .manyptr_u8_type }, params[0]), 7417 .byte = try expr(gz, scope, .{ .ty = .u8_type }, params[1]), 7418 .byte_count = try expr(gz, scope, .{ .ty = .usize_type }, params[2]), 7419 }); 7420 return rvalue(gz, rl, result, node); 7421 }, 7422 .shuffle => { 7423 const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{ 7424 .elem_type = try typeExpr(gz, scope, params[0]), 7425 .a = try expr(gz, scope, .none, params[1]), 7426 .b = try expr(gz, scope, .none, params[2]), 7427 .mask = try comptimeExpr(gz, scope, .none, params[3]), 7428 }); 7429 return rvalue(gz, rl, result, node); 7430 }, 7431 .select => { 7432 const result = try gz.addPlNode(.select, node, Zir.Inst.Select{ 7433 .elem_type = try typeExpr(gz, scope, params[0]), 7434 .pred = try expr(gz, scope, .none, params[1]), 7435 .a = try expr(gz, scope, .none, params[2]), 7436 .b = try expr(gz, scope, .none, params[3]), 7437 }); 7438 return rvalue(gz, rl, result, node); 7439 }, 7440 .async_call => { 7441 const result = try gz.addPlNode(.builtin_async_call, node, Zir.Inst.AsyncCall{ 7442 .frame_buffer = try expr(gz, scope, .none, params[0]), 7443 .result_ptr = try expr(gz, scope, .none, params[1]), 7444 .fn_ptr = try expr(gz, scope, .none, params[2]), 7445 .args = try expr(gz, scope, .none, params[3]), 7446 }); 7447 return rvalue(gz, rl, result, node); 7448 }, 7449 .Vector => { 7450 const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{ 7451 .lhs = try comptimeExpr(gz, scope, .{.ty = .u32_type}, params[0]), 7452 .rhs = try typeExpr(gz, scope, params[1]), 7453 }); 7454 return rvalue(gz, rl, result, node); 7455 }, 7456 7457 } 7458 // zig fmt: on 7459 } 7460 7461 fn simpleNoOpVoid( 7462 gz: *GenZir, 7463 rl: ResultLoc, 7464 node: ast.Node.Index, 7465 tag: Zir.Inst.Tag, 7466 ) InnerError!Zir.Inst.Ref { 7467 _ = try gz.addNode(tag, node); 7468 return rvalue(gz, rl, .void_value, node); 7469 } 7470 7471 fn hasDeclOrField( 7472 gz: *GenZir, 7473 scope: *Scope, 7474 rl: ResultLoc, 7475 node: ast.Node.Index, 7476 lhs_node: ast.Node.Index, 7477 rhs_node: ast.Node.Index, 7478 tag: Zir.Inst.Tag, 7479 ) InnerError!Zir.Inst.Ref { 7480 const container_type = try typeExpr(gz, scope, lhs_node); 7481 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); 7482 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7483 .lhs = container_type, 7484 .rhs = name, 7485 }); 7486 return rvalue(gz, rl, result, node); 7487 } 7488 7489 fn typeCast( 7490 gz: *GenZir, 7491 scope: *Scope, 7492 rl: ResultLoc, 7493 node: ast.Node.Index, 7494 lhs_node: ast.Node.Index, 7495 rhs_node: ast.Node.Index, 7496 tag: Zir.Inst.Tag, 7497 ) InnerError!Zir.Inst.Ref { 7498 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7499 .lhs = try typeExpr(gz, scope, lhs_node), 7500 .rhs = try expr(gz, scope, .none, rhs_node), 7501 }); 7502 return rvalue(gz, rl, result, node); 7503 } 7504 7505 fn simpleUnOpType( 7506 gz: *GenZir, 7507 scope: *Scope, 7508 rl: ResultLoc, 7509 node: ast.Node.Index, 7510 operand_node: ast.Node.Index, 7511 tag: Zir.Inst.Tag, 7512 ) InnerError!Zir.Inst.Ref { 7513 const operand = try typeExpr(gz, scope, operand_node); 7514 const result = try gz.addUnNode(tag, operand, node); 7515 return rvalue(gz, rl, result, node); 7516 } 7517 7518 fn simpleUnOp( 7519 gz: *GenZir, 7520 scope: *Scope, 7521 rl: ResultLoc, 7522 node: ast.Node.Index, 7523 operand_rl: ResultLoc, 7524 operand_node: ast.Node.Index, 7525 tag: Zir.Inst.Tag, 7526 ) InnerError!Zir.Inst.Ref { 7527 const operand = try expr(gz, scope, operand_rl, operand_node); 7528 const result = try gz.addUnNode(tag, operand, node); 7529 return rvalue(gz, rl, result, node); 7530 } 7531 7532 fn cmpxchg( 7533 gz: *GenZir, 7534 scope: *Scope, 7535 rl: ResultLoc, 7536 node: ast.Node.Index, 7537 params: []const ast.Node.Index, 7538 tag: Zir.Inst.Tag, 7539 ) InnerError!Zir.Inst.Ref { 7540 const int_type = try typeExpr(gz, scope, params[0]); 7541 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7542 .ptr_type_simple = .{ 7543 .is_allowzero = false, 7544 .is_mutable = true, 7545 .is_volatile = false, 7546 .size = .One, 7547 .elem_type = int_type, 7548 }, 7549 } }); 7550 const result = try gz.addPlNode(tag, node, Zir.Inst.Cmpxchg{ 7551 // zig fmt: off 7552 .ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[1]), 7553 .expected_value = try expr(gz, scope, .{ .ty = int_type }, params[2]), 7554 .new_value = try expr(gz, scope, .{ .ty = int_type }, params[3]), 7555 .success_order = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[4]), 7556 .fail_order = try expr(gz, scope, .{ .ty = .atomic_ordering_type }, params[5]), 7557 // zig fmt: on 7558 }); 7559 return rvalue(gz, rl, result, node); 7560 } 7561 7562 fn bitBuiltin( 7563 gz: *GenZir, 7564 scope: *Scope, 7565 rl: ResultLoc, 7566 node: ast.Node.Index, 7567 int_type_node: ast.Node.Index, 7568 operand_node: ast.Node.Index, 7569 tag: Zir.Inst.Tag, 7570 ) InnerError!Zir.Inst.Ref { 7571 const int_type = try typeExpr(gz, scope, int_type_node); 7572 const operand = try expr(gz, scope, .{ .ty = int_type }, operand_node); 7573 const result = try gz.addUnNode(tag, operand, node); 7574 return rvalue(gz, rl, result, node); 7575 } 7576 7577 fn divBuiltin( 7578 gz: *GenZir, 7579 scope: *Scope, 7580 rl: ResultLoc, 7581 node: ast.Node.Index, 7582 lhs_node: ast.Node.Index, 7583 rhs_node: ast.Node.Index, 7584 tag: Zir.Inst.Tag, 7585 ) InnerError!Zir.Inst.Ref { 7586 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7587 .lhs = try expr(gz, scope, .none, lhs_node), 7588 .rhs = try expr(gz, scope, .none, rhs_node), 7589 }); 7590 return rvalue(gz, rl, result, node); 7591 } 7592 7593 fn simpleCBuiltin( 7594 gz: *GenZir, 7595 scope: *Scope, 7596 rl: ResultLoc, 7597 node: ast.Node.Index, 7598 operand_node: ast.Node.Index, 7599 tag: Zir.Inst.Extended, 7600 ) InnerError!Zir.Inst.Ref { 7601 const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); 7602 _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ 7603 .node = gz.nodeIndexToRelative(node), 7604 .operand = operand, 7605 }); 7606 return rvalue(gz, rl, .void_value, node); 7607 } 7608 7609 fn offsetOf( 7610 gz: *GenZir, 7611 scope: *Scope, 7612 rl: ResultLoc, 7613 node: ast.Node.Index, 7614 lhs_node: ast.Node.Index, 7615 rhs_node: ast.Node.Index, 7616 tag: Zir.Inst.Tag, 7617 ) InnerError!Zir.Inst.Ref { 7618 const type_inst = try typeExpr(gz, scope, lhs_node); 7619 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, rhs_node); 7620 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7621 .lhs = type_inst, 7622 .rhs = field_name, 7623 }); 7624 return rvalue(gz, rl, result, node); 7625 } 7626 7627 fn shiftOp( 7628 gz: *GenZir, 7629 scope: *Scope, 7630 rl: ResultLoc, 7631 node: ast.Node.Index, 7632 lhs_node: ast.Node.Index, 7633 rhs_node: ast.Node.Index, 7634 tag: Zir.Inst.Tag, 7635 ) InnerError!Zir.Inst.Ref { 7636 const lhs = try expr(gz, scope, .none, lhs_node); 7637 const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node); 7638 const rhs = try expr(gz, scope, .{ .ty = log2_int_type }, rhs_node); 7639 const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ 7640 .lhs = lhs, 7641 .rhs = rhs, 7642 }); 7643 return rvalue(gz, rl, result, node); 7644 } 7645 7646 fn cImport( 7647 gz: *GenZir, 7648 scope: *Scope, 7649 rl: ResultLoc, 7650 node: ast.Node.Index, 7651 body_node: ast.Node.Index, 7652 ) InnerError!Zir.Inst.Ref { 7653 const astgen = gz.astgen; 7654 const gpa = astgen.gpa; 7655 7656 var block_scope = gz.makeSubBlock(scope); 7657 block_scope.force_comptime = true; 7658 defer block_scope.instructions.deinit(gpa); 7659 7660 const block_inst = try gz.addBlock(.c_import, node); 7661 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node); 7662 if (!gz.refIsNoReturn(block_result)) { 7663 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value); 7664 } 7665 try block_scope.setBlockBody(block_inst); 7666 try gz.instructions.append(gpa, block_inst); 7667 7668 return rvalue(gz, rl, .void_value, node); 7669 } 7670 7671 fn overflowArithmetic( 7672 gz: *GenZir, 7673 scope: *Scope, 7674 rl: ResultLoc, 7675 node: ast.Node.Index, 7676 params: []const ast.Node.Index, 7677 tag: Zir.Inst.Extended, 7678 ) InnerError!Zir.Inst.Ref { 7679 const int_type = try typeExpr(gz, scope, params[0]); 7680 const ptr_type = try gz.add(.{ .tag = .ptr_type_simple, .data = .{ 7681 .ptr_type_simple = .{ 7682 .is_allowzero = false, 7683 .is_mutable = true, 7684 .is_volatile = false, 7685 .size = .One, 7686 .elem_type = int_type, 7687 }, 7688 } }); 7689 const lhs = try expr(gz, scope, .{ .ty = int_type }, params[1]); 7690 const rhs = try expr(gz, scope, .{ .ty = int_type }, params[2]); 7691 const ptr = try expr(gz, scope, .{ .ty = ptr_type }, params[3]); 7692 const result = try gz.addExtendedPayload(tag, Zir.Inst.OverflowArithmetic{ 7693 .node = gz.nodeIndexToRelative(node), 7694 .lhs = lhs, 7695 .rhs = rhs, 7696 .ptr = ptr, 7697 }); 7698 return rvalue(gz, rl, result, node); 7699 } 7700 7701 fn callExpr( 7702 gz: *GenZir, 7703 scope: *Scope, 7704 rl: ResultLoc, 7705 node: ast.Node.Index, 7706 call: ast.full.Call, 7707 ) InnerError!Zir.Inst.Ref { 7708 const astgen = gz.astgen; 7709 const lhs = try expr(gz, scope, .none, call.ast.fn_expr); 7710 7711 const args = try astgen.gpa.alloc(Zir.Inst.Ref, call.ast.params.len); 7712 defer astgen.gpa.free(args); 7713 7714 for (call.ast.params) |param_node, i| { 7715 const param_type = try gz.add(.{ 7716 .tag = .param_type, 7717 .data = .{ .param_type = .{ 7718 .callee = lhs, 7719 .param_index = @intCast(u32, i), 7720 } }, 7721 }); 7722 args[i] = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node); 7723 } 7724 7725 const modifier: std.builtin.CallOptions.Modifier = blk: { 7726 if (gz.force_comptime) { 7727 break :blk .compile_time; 7728 } 7729 if (call.async_token != null) { 7730 break :blk .async_kw; 7731 } 7732 if (gz.nosuspend_node != 0) { 7733 break :blk .no_async; 7734 } 7735 break :blk .auto; 7736 }; 7737 const result: Zir.Inst.Ref = res: { 7738 const tag: Zir.Inst.Tag = switch (modifier) { 7739 .auto => .call, 7740 .async_kw => .call_async, 7741 .never_tail => unreachable, 7742 .never_inline => unreachable, 7743 .no_async => .call_nosuspend, 7744 .always_tail => unreachable, 7745 .always_inline => unreachable, 7746 .compile_time => .call_compile_time, 7747 }; 7748 break :res try gz.addCall(tag, lhs, args, node); 7749 }; 7750 return rvalue(gz, rl, result, node); // TODO function call with result location 7751 } 7752 7753 pub const simple_types = std.ComptimeStringMap(Zir.Inst.Ref, .{ 7754 .{ "anyerror", .anyerror_type }, 7755 .{ "anyframe", .anyframe_type }, 7756 .{ "bool", .bool_type }, 7757 .{ "c_int", .c_int_type }, 7758 .{ "c_long", .c_long_type }, 7759 .{ "c_longdouble", .c_longdouble_type }, 7760 .{ "c_longlong", .c_longlong_type }, 7761 .{ "c_short", .c_short_type }, 7762 .{ "c_uint", .c_uint_type }, 7763 .{ "c_ulong", .c_ulong_type }, 7764 .{ "c_ulonglong", .c_ulonglong_type }, 7765 .{ "c_ushort", .c_ushort_type }, 7766 .{ "c_void", .c_void_type }, 7767 .{ "comptime_float", .comptime_float_type }, 7768 .{ "comptime_int", .comptime_int_type }, 7769 .{ "f128", .f128_type }, 7770 .{ "f16", .f16_type }, 7771 .{ "f32", .f32_type }, 7772 .{ "f64", .f64_type }, 7773 .{ "false", .bool_false }, 7774 .{ "i16", .i16_type }, 7775 .{ "i32", .i32_type }, 7776 .{ "i64", .i64_type }, 7777 .{ "i128", .i128_type }, 7778 .{ "i8", .i8_type }, 7779 .{ "isize", .isize_type }, 7780 .{ "noreturn", .noreturn_type }, 7781 .{ "null", .null_value }, 7782 .{ "true", .bool_true }, 7783 .{ "type", .type_type }, 7784 .{ "u16", .u16_type }, 7785 .{ "u32", .u32_type }, 7786 .{ "u64", .u64_type }, 7787 .{ "u128", .u128_type }, 7788 .{ "u1", .u1_type }, 7789 .{ "u8", .u8_type }, 7790 .{ "undefined", .undef }, 7791 .{ "usize", .usize_type }, 7792 .{ "void", .void_type }, 7793 }); 7794 7795 fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) bool { 7796 const node_tags = tree.nodes.items(.tag); 7797 const node_datas = tree.nodes.items(.data); 7798 const main_tokens = tree.nodes.items(.main_token); 7799 const token_tags = tree.tokens.items(.tag); 7800 7801 var node = start_node; 7802 while (true) { 7803 switch (node_tags[node]) { 7804 .root, 7805 .@"usingnamespace", 7806 .test_decl, 7807 .switch_case, 7808 .switch_case_one, 7809 .container_field_init, 7810 .container_field_align, 7811 .container_field, 7812 .asm_output, 7813 .asm_input, 7814 => unreachable, 7815 7816 .@"return", 7817 .@"break", 7818 .@"continue", 7819 .bit_not, 7820 .bool_not, 7821 .global_var_decl, 7822 .local_var_decl, 7823 .simple_var_decl, 7824 .aligned_var_decl, 7825 .@"defer", 7826 .@"errdefer", 7827 .address_of, 7828 .optional_type, 7829 .negation, 7830 .negation_wrap, 7831 .@"resume", 7832 .array_type, 7833 .array_type_sentinel, 7834 .ptr_type_aligned, 7835 .ptr_type_sentinel, 7836 .ptr_type, 7837 .ptr_type_bit_range, 7838 .@"suspend", 7839 .@"anytype", 7840 .fn_proto_simple, 7841 .fn_proto_multi, 7842 .fn_proto_one, 7843 .fn_proto, 7844 .fn_decl, 7845 .anyframe_type, 7846 .anyframe_literal, 7847 .integer_literal, 7848 .float_literal, 7849 .enum_literal, 7850 .string_literal, 7851 .multiline_string_literal, 7852 .char_literal, 7853 .unreachable_literal, 7854 .identifier, 7855 .error_set_decl, 7856 .container_decl, 7857 .container_decl_trailing, 7858 .container_decl_two, 7859 .container_decl_two_trailing, 7860 .container_decl_arg, 7861 .container_decl_arg_trailing, 7862 .tagged_union, 7863 .tagged_union_trailing, 7864 .tagged_union_two, 7865 .tagged_union_two_trailing, 7866 .tagged_union_enum_tag, 7867 .tagged_union_enum_tag_trailing, 7868 .@"asm", 7869 .asm_simple, 7870 .add, 7871 .add_wrap, 7872 .array_cat, 7873 .array_mult, 7874 .assign, 7875 .assign_bit_and, 7876 .assign_bit_or, 7877 .assign_bit_shift_left, 7878 .assign_bit_shift_right, 7879 .assign_bit_xor, 7880 .assign_div, 7881 .assign_sub, 7882 .assign_sub_wrap, 7883 .assign_mod, 7884 .assign_add, 7885 .assign_add_wrap, 7886 .assign_mul, 7887 .assign_mul_wrap, 7888 .bang_equal, 7889 .bit_and, 7890 .bit_or, 7891 .bit_shift_left, 7892 .bit_shift_right, 7893 .bit_xor, 7894 .bool_and, 7895 .bool_or, 7896 .div, 7897 .equal_equal, 7898 .error_union, 7899 .greater_or_equal, 7900 .greater_than, 7901 .less_or_equal, 7902 .less_than, 7903 .merge_error_sets, 7904 .mod, 7905 .mul, 7906 .mul_wrap, 7907 .switch_range, 7908 .field_access, 7909 .sub, 7910 .sub_wrap, 7911 .slice, 7912 .slice_open, 7913 .slice_sentinel, 7914 .deref, 7915 .array_access, 7916 .error_value, 7917 .while_simple, // This variant cannot have an else expression. 7918 .while_cont, // This variant cannot have an else expression. 7919 .for_simple, // This variant cannot have an else expression. 7920 .if_simple, // This variant cannot have an else expression. 7921 => return false, 7922 7923 // Forward the question to the LHS sub-expression. 7924 .grouped_expression, 7925 .@"try", 7926 .@"await", 7927 .@"comptime", 7928 .@"nosuspend", 7929 .unwrap_optional, 7930 => node = node_datas[node].lhs, 7931 7932 // Forward the question to the RHS sub-expression. 7933 .@"catch", 7934 .@"orelse", 7935 => node = node_datas[node].rhs, 7936 7937 // True because these are exactly the expressions we need memory locations for. 7938 .array_init_one, 7939 .array_init_one_comma, 7940 .array_init_dot_two, 7941 .array_init_dot_two_comma, 7942 .array_init_dot, 7943 .array_init_dot_comma, 7944 .array_init, 7945 .array_init_comma, 7946 .struct_init_one, 7947 .struct_init_one_comma, 7948 .struct_init_dot_two, 7949 .struct_init_dot_two_comma, 7950 .struct_init_dot, 7951 .struct_init_dot_comma, 7952 .struct_init, 7953 .struct_init_comma, 7954 => return true, 7955 7956 // True because depending on comptime conditions, sub-expressions 7957 // may be the kind that need memory locations. 7958 .@"while", // This variant always has an else expression. 7959 .@"if", // This variant always has an else expression. 7960 .@"for", // This variant always has an else expression. 7961 .@"switch", 7962 .switch_comma, 7963 .call_one, 7964 .call_one_comma, 7965 .async_call_one, 7966 .async_call_one_comma, 7967 .call, 7968 .call_comma, 7969 .async_call, 7970 .async_call_comma, 7971 => return true, 7972 7973 .block_two, 7974 .block_two_semicolon, 7975 .block, 7976 .block_semicolon, 7977 => { 7978 const lbrace = main_tokens[node]; 7979 if (token_tags[lbrace - 1] == .colon) { 7980 // Labeled blocks may need a memory location to forward 7981 // to their break statements. 7982 return true; 7983 } else { 7984 return false; 7985 } 7986 }, 7987 7988 .builtin_call, 7989 .builtin_call_comma, 7990 .builtin_call_two, 7991 .builtin_call_two_comma, 7992 => { 7993 const builtin_token = main_tokens[node]; 7994 const builtin_name = tree.tokenSlice(builtin_token); 7995 // If the builtin is an invalid name, we don't cause an error here; instead 7996 // let it pass, and the error will be "invalid builtin function" later. 7997 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false; 7998 return builtin_info.needs_mem_loc; 7999 }, 8000 } 8001 } 8002 } 8003 8004 fn nodeMayEvalToError(tree: *const ast.Tree, start_node: ast.Node.Index) enum { never, always, maybe } { 8005 const node_tags = tree.nodes.items(.tag); 8006 const node_datas = tree.nodes.items(.data); 8007 const main_tokens = tree.nodes.items(.main_token); 8008 const token_tags = tree.tokens.items(.tag); 8009 8010 var node = start_node; 8011 while (true) { 8012 switch (node_tags[node]) { 8013 .root, 8014 .@"usingnamespace", 8015 .test_decl, 8016 .switch_case, 8017 .switch_case_one, 8018 .container_field_init, 8019 .container_field_align, 8020 .container_field, 8021 .asm_output, 8022 .asm_input, 8023 => unreachable, 8024 8025 .error_value => return .always, 8026 8027 .@"asm", 8028 .asm_simple, 8029 .identifier, 8030 .field_access, 8031 .deref, 8032 .array_access, 8033 .while_simple, 8034 .while_cont, 8035 .for_simple, 8036 .if_simple, 8037 .@"while", 8038 .@"if", 8039 .@"for", 8040 .@"switch", 8041 .switch_comma, 8042 .call_one, 8043 .call_one_comma, 8044 .async_call_one, 8045 .async_call_one_comma, 8046 .call, 8047 .call_comma, 8048 .async_call, 8049 .async_call_comma, 8050 => return .maybe, 8051 8052 .@"return", 8053 .@"break", 8054 .@"continue", 8055 .bit_not, 8056 .bool_not, 8057 .global_var_decl, 8058 .local_var_decl, 8059 .simple_var_decl, 8060 .aligned_var_decl, 8061 .@"defer", 8062 .@"errdefer", 8063 .address_of, 8064 .optional_type, 8065 .negation, 8066 .negation_wrap, 8067 .@"resume", 8068 .array_type, 8069 .array_type_sentinel, 8070 .ptr_type_aligned, 8071 .ptr_type_sentinel, 8072 .ptr_type, 8073 .ptr_type_bit_range, 8074 .@"suspend", 8075 .@"anytype", 8076 .fn_proto_simple, 8077 .fn_proto_multi, 8078 .fn_proto_one, 8079 .fn_proto, 8080 .fn_decl, 8081 .anyframe_type, 8082 .anyframe_literal, 8083 .integer_literal, 8084 .float_literal, 8085 .enum_literal, 8086 .string_literal, 8087 .multiline_string_literal, 8088 .char_literal, 8089 .unreachable_literal, 8090 .error_set_decl, 8091 .container_decl, 8092 .container_decl_trailing, 8093 .container_decl_two, 8094 .container_decl_two_trailing, 8095 .container_decl_arg, 8096 .container_decl_arg_trailing, 8097 .tagged_union, 8098 .tagged_union_trailing, 8099 .tagged_union_two, 8100 .tagged_union_two_trailing, 8101 .tagged_union_enum_tag, 8102 .tagged_union_enum_tag_trailing, 8103 .add, 8104 .add_wrap, 8105 .array_cat, 8106 .array_mult, 8107 .assign, 8108 .assign_bit_and, 8109 .assign_bit_or, 8110 .assign_bit_shift_left, 8111 .assign_bit_shift_right, 8112 .assign_bit_xor, 8113 .assign_div, 8114 .assign_sub, 8115 .assign_sub_wrap, 8116 .assign_mod, 8117 .assign_add, 8118 .assign_add_wrap, 8119 .assign_mul, 8120 .assign_mul_wrap, 8121 .bang_equal, 8122 .bit_and, 8123 .bit_or, 8124 .bit_shift_left, 8125 .bit_shift_right, 8126 .bit_xor, 8127 .bool_and, 8128 .bool_or, 8129 .div, 8130 .equal_equal, 8131 .error_union, 8132 .greater_or_equal, 8133 .greater_than, 8134 .less_or_equal, 8135 .less_than, 8136 .merge_error_sets, 8137 .mod, 8138 .mul, 8139 .mul_wrap, 8140 .switch_range, 8141 .sub, 8142 .sub_wrap, 8143 .slice, 8144 .slice_open, 8145 .slice_sentinel, 8146 .array_init_one, 8147 .array_init_one_comma, 8148 .array_init_dot_two, 8149 .array_init_dot_two_comma, 8150 .array_init_dot, 8151 .array_init_dot_comma, 8152 .array_init, 8153 .array_init_comma, 8154 .struct_init_one, 8155 .struct_init_one_comma, 8156 .struct_init_dot_two, 8157 .struct_init_dot_two_comma, 8158 .struct_init_dot, 8159 .struct_init_dot_comma, 8160 .struct_init, 8161 .struct_init_comma, 8162 => return .never, 8163 8164 // Forward the question to the LHS sub-expression. 8165 .grouped_expression, 8166 .@"try", 8167 .@"await", 8168 .@"comptime", 8169 .@"nosuspend", 8170 .unwrap_optional, 8171 => node = node_datas[node].lhs, 8172 8173 // Forward the question to the RHS sub-expression. 8174 .@"catch", 8175 .@"orelse", 8176 => node = node_datas[node].rhs, 8177 8178 .block_two, 8179 .block_two_semicolon, 8180 .block, 8181 .block_semicolon, 8182 => { 8183 const lbrace = main_tokens[node]; 8184 if (token_tags[lbrace - 1] == .colon) { 8185 // Labeled blocks may need a memory location to forward 8186 // to their break statements. 8187 return .maybe; 8188 } else { 8189 return .never; 8190 } 8191 }, 8192 8193 .builtin_call, 8194 .builtin_call_comma, 8195 .builtin_call_two, 8196 .builtin_call_two_comma, 8197 => { 8198 const builtin_token = main_tokens[node]; 8199 const builtin_name = tree.tokenSlice(builtin_token); 8200 // If the builtin is an invalid name, we don't cause an error here; instead 8201 // let it pass, and the error will be "invalid builtin function" later. 8202 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe; 8203 if (builtin_info.tag == .err_set_cast) { 8204 return .always; 8205 } else { 8206 return .never; 8207 } 8208 }, 8209 } 8210 } 8211 } 8212 8213 fn nodeImpliesRuntimeBits(tree: *const ast.Tree, start_node: ast.Node.Index) bool { 8214 const node_tags = tree.nodes.items(.tag); 8215 const node_datas = tree.nodes.items(.data); 8216 8217 var node = start_node; 8218 while (true) { 8219 switch (node_tags[node]) { 8220 .root, 8221 .@"usingnamespace", 8222 .test_decl, 8223 .switch_case, 8224 .switch_case_one, 8225 .container_field_init, 8226 .container_field_align, 8227 .container_field, 8228 .asm_output, 8229 .asm_input, 8230 .global_var_decl, 8231 .local_var_decl, 8232 .simple_var_decl, 8233 .aligned_var_decl, 8234 => unreachable, 8235 8236 .@"return", 8237 .@"break", 8238 .@"continue", 8239 .bit_not, 8240 .bool_not, 8241 .@"defer", 8242 .@"errdefer", 8243 .address_of, 8244 .negation, 8245 .negation_wrap, 8246 .@"resume", 8247 .array_type, 8248 .@"suspend", 8249 .@"anytype", 8250 .fn_decl, 8251 .anyframe_literal, 8252 .integer_literal, 8253 .float_literal, 8254 .enum_literal, 8255 .string_literal, 8256 .multiline_string_literal, 8257 .char_literal, 8258 .unreachable_literal, 8259 .identifier, 8260 .error_set_decl, 8261 .container_decl, 8262 .container_decl_trailing, 8263 .container_decl_two, 8264 .container_decl_two_trailing, 8265 .container_decl_arg, 8266 .container_decl_arg_trailing, 8267 .tagged_union, 8268 .tagged_union_trailing, 8269 .tagged_union_two, 8270 .tagged_union_two_trailing, 8271 .tagged_union_enum_tag, 8272 .tagged_union_enum_tag_trailing, 8273 .@"asm", 8274 .asm_simple, 8275 .add, 8276 .add_wrap, 8277 .array_cat, 8278 .array_mult, 8279 .assign, 8280 .assign_bit_and, 8281 .assign_bit_or, 8282 .assign_bit_shift_left, 8283 .assign_bit_shift_right, 8284 .assign_bit_xor, 8285 .assign_div, 8286 .assign_sub, 8287 .assign_sub_wrap, 8288 .assign_mod, 8289 .assign_add, 8290 .assign_add_wrap, 8291 .assign_mul, 8292 .assign_mul_wrap, 8293 .bang_equal, 8294 .bit_and, 8295 .bit_or, 8296 .bit_shift_left, 8297 .bit_shift_right, 8298 .bit_xor, 8299 .bool_and, 8300 .bool_or, 8301 .div, 8302 .equal_equal, 8303 .error_union, 8304 .greater_or_equal, 8305 .greater_than, 8306 .less_or_equal, 8307 .less_than, 8308 .merge_error_sets, 8309 .mod, 8310 .mul, 8311 .mul_wrap, 8312 .switch_range, 8313 .field_access, 8314 .sub, 8315 .sub_wrap, 8316 .slice, 8317 .slice_open, 8318 .slice_sentinel, 8319 .deref, 8320 .array_access, 8321 .error_value, 8322 .while_simple, 8323 .while_cont, 8324 .for_simple, 8325 .if_simple, 8326 .@"catch", 8327 .@"orelse", 8328 .array_init_one, 8329 .array_init_one_comma, 8330 .array_init_dot_two, 8331 .array_init_dot_two_comma, 8332 .array_init_dot, 8333 .array_init_dot_comma, 8334 .array_init, 8335 .array_init_comma, 8336 .struct_init_one, 8337 .struct_init_one_comma, 8338 .struct_init_dot_two, 8339 .struct_init_dot_two_comma, 8340 .struct_init_dot, 8341 .struct_init_dot_comma, 8342 .struct_init, 8343 .struct_init_comma, 8344 .@"while", 8345 .@"if", 8346 .@"for", 8347 .@"switch", 8348 .switch_comma, 8349 .call_one, 8350 .call_one_comma, 8351 .async_call_one, 8352 .async_call_one_comma, 8353 .call, 8354 .call_comma, 8355 .async_call, 8356 .async_call_comma, 8357 .block_two, 8358 .block_two_semicolon, 8359 .block, 8360 .block_semicolon, 8361 .builtin_call, 8362 .builtin_call_comma, 8363 .builtin_call_two, 8364 .builtin_call_two_comma, 8365 => return false, 8366 8367 // Forward the question to the LHS sub-expression. 8368 .grouped_expression, 8369 .@"try", 8370 .@"await", 8371 .@"comptime", 8372 .@"nosuspend", 8373 .unwrap_optional, 8374 => node = node_datas[node].lhs, 8375 8376 .fn_proto_simple, 8377 .fn_proto_multi, 8378 .fn_proto_one, 8379 .fn_proto, 8380 .ptr_type_aligned, 8381 .ptr_type_sentinel, 8382 .ptr_type, 8383 .ptr_type_bit_range, 8384 .optional_type, 8385 .anyframe_type, 8386 .array_type_sentinel, 8387 => return true, 8388 } 8389 } 8390 } 8391 8392 /// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of 8393 /// result locations must call this function on their result. 8394 /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. 8395 /// If the `ResultLoc` is `ty`, it will coerce the result to the type. 8396 fn rvalue( 8397 gz: *GenZir, 8398 rl: ResultLoc, 8399 result: Zir.Inst.Ref, 8400 src_node: ast.Node.Index, 8401 ) InnerError!Zir.Inst.Ref { 8402 switch (rl) { 8403 .none, .none_or_ref, .coerced_ty => return result, 8404 .discard => { 8405 // Emit a compile error for discarding error values. 8406 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); 8407 return result; 8408 }, 8409 .ref => { 8410 // We need a pointer but we have a value. 8411 const tree = gz.astgen.tree; 8412 const src_token = tree.firstToken(src_node); 8413 return gz.addUnTok(.ref, result, src_token); 8414 }, 8415 .ty => |ty_inst| { 8416 // Quickly eliminate some common, unnecessary type coercion. 8417 const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32; 8418 const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32; 8419 const as_bool = @as(u64, @enumToInt(Zir.Inst.Ref.bool_type)) << 32; 8420 const as_usize = @as(u64, @enumToInt(Zir.Inst.Ref.usize_type)) << 32; 8421 const as_void = @as(u64, @enumToInt(Zir.Inst.Ref.void_type)) << 32; 8422 switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) { 8423 as_ty | @enumToInt(Zir.Inst.Ref.u1_type), 8424 as_ty | @enumToInt(Zir.Inst.Ref.u8_type), 8425 as_ty | @enumToInt(Zir.Inst.Ref.i8_type), 8426 as_ty | @enumToInt(Zir.Inst.Ref.u16_type), 8427 as_ty | @enumToInt(Zir.Inst.Ref.i16_type), 8428 as_ty | @enumToInt(Zir.Inst.Ref.u32_type), 8429 as_ty | @enumToInt(Zir.Inst.Ref.i32_type), 8430 as_ty | @enumToInt(Zir.Inst.Ref.u64_type), 8431 as_ty | @enumToInt(Zir.Inst.Ref.i64_type), 8432 as_ty | @enumToInt(Zir.Inst.Ref.usize_type), 8433 as_ty | @enumToInt(Zir.Inst.Ref.isize_type), 8434 as_ty | @enumToInt(Zir.Inst.Ref.c_short_type), 8435 as_ty | @enumToInt(Zir.Inst.Ref.c_ushort_type), 8436 as_ty | @enumToInt(Zir.Inst.Ref.c_int_type), 8437 as_ty | @enumToInt(Zir.Inst.Ref.c_uint_type), 8438 as_ty | @enumToInt(Zir.Inst.Ref.c_long_type), 8439 as_ty | @enumToInt(Zir.Inst.Ref.c_ulong_type), 8440 as_ty | @enumToInt(Zir.Inst.Ref.c_longlong_type), 8441 as_ty | @enumToInt(Zir.Inst.Ref.c_ulonglong_type), 8442 as_ty | @enumToInt(Zir.Inst.Ref.c_longdouble_type), 8443 as_ty | @enumToInt(Zir.Inst.Ref.f16_type), 8444 as_ty | @enumToInt(Zir.Inst.Ref.f32_type), 8445 as_ty | @enumToInt(Zir.Inst.Ref.f64_type), 8446 as_ty | @enumToInt(Zir.Inst.Ref.f128_type), 8447 as_ty | @enumToInt(Zir.Inst.Ref.c_void_type), 8448 as_ty | @enumToInt(Zir.Inst.Ref.bool_type), 8449 as_ty | @enumToInt(Zir.Inst.Ref.void_type), 8450 as_ty | @enumToInt(Zir.Inst.Ref.type_type), 8451 as_ty | @enumToInt(Zir.Inst.Ref.anyerror_type), 8452 as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), 8453 as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), 8454 as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), 8455 as_ty | @enumToInt(Zir.Inst.Ref.null_type), 8456 as_ty | @enumToInt(Zir.Inst.Ref.undefined_type), 8457 as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type), 8458 as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type), 8459 as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type), 8460 as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type), 8461 as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), 8462 as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type), 8463 as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type), 8464 as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), 8465 as_comptime_int | @enumToInt(Zir.Inst.Ref.one), 8466 as_bool | @enumToInt(Zir.Inst.Ref.bool_true), 8467 as_bool | @enumToInt(Zir.Inst.Ref.bool_false), 8468 as_usize | @enumToInt(Zir.Inst.Ref.zero_usize), 8469 as_usize | @enumToInt(Zir.Inst.Ref.one_usize), 8470 as_void | @enumToInt(Zir.Inst.Ref.void_value), 8471 => return result, // type of result is already correct 8472 8473 // Need an explicit type coercion instruction. 8474 else => return gz.addPlNode(.as_node, src_node, Zir.Inst.As{ 8475 .dest_type = ty_inst, 8476 .operand = result, 8477 }), 8478 } 8479 }, 8480 .ptr => |ptr_inst| { 8481 _ = try gz.addPlNode(.store_node, src_node, Zir.Inst.Bin{ 8482 .lhs = ptr_inst, 8483 .rhs = result, 8484 }); 8485 return result; 8486 }, 8487 .inferred_ptr => |alloc| { 8488 _ = try gz.addBin(.store_to_inferred_ptr, alloc, result); 8489 return result; 8490 }, 8491 .block_ptr => |block_scope| { 8492 block_scope.rvalue_rl_count += 1; 8493 _ = try gz.addBin(.store_to_block_ptr, block_scope.rl_ptr, result); 8494 return result; 8495 }, 8496 } 8497 } 8498 8499 /// Given an identifier token, obtain the string for it. 8500 /// If the token uses @"" syntax, parses as a string, reports errors if applicable, 8501 /// and allocates the result within `astgen.arena`. 8502 /// Otherwise, returns a reference to the source code bytes directly. 8503 /// See also `appendIdentStr` and `parseStrLit`. 8504 fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]const u8 { 8505 const tree = astgen.tree; 8506 const token_tags = tree.tokens.items(.tag); 8507 assert(token_tags[token] == .identifier); 8508 const ident_name = tree.tokenSlice(token); 8509 if (!mem.startsWith(u8, ident_name, "@")) { 8510 return ident_name; 8511 } 8512 var buf: ArrayListUnmanaged(u8) = .{}; 8513 defer buf.deinit(astgen.gpa); 8514 try astgen.parseStrLit(token, &buf, ident_name, 1); 8515 const duped = try astgen.arena.dupe(u8, buf.items); 8516 return duped; 8517 } 8518 8519 /// Given an identifier token, obtain the string for it (possibly parsing as a string 8520 /// literal if it is @"" syntax), and append the string to `buf`. 8521 /// See also `identifierTokenString` and `parseStrLit`. 8522 fn appendIdentStr( 8523 astgen: *AstGen, 8524 token: ast.TokenIndex, 8525 buf: *ArrayListUnmanaged(u8), 8526 ) InnerError!void { 8527 const tree = astgen.tree; 8528 const token_tags = tree.tokens.items(.tag); 8529 assert(token_tags[token] == .identifier); 8530 const ident_name = tree.tokenSlice(token); 8531 if (!mem.startsWith(u8, ident_name, "@")) { 8532 return buf.appendSlice(astgen.gpa, ident_name); 8533 } else { 8534 return astgen.parseStrLit(token, buf, ident_name, 1); 8535 } 8536 } 8537 8538 /// Appends the result to `buf`. 8539 fn parseStrLit( 8540 astgen: *AstGen, 8541 token: ast.TokenIndex, 8542 buf: *ArrayListUnmanaged(u8), 8543 bytes: []const u8, 8544 offset: u32, 8545 ) InnerError!void { 8546 const raw_string = bytes[offset..]; 8547 var buf_managed = buf.toManaged(astgen.gpa); 8548 const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string); 8549 buf.* = buf_managed.toUnmanaged(); 8550 switch (try result) { 8551 .success => return, 8552 .invalid_character => |bad_index| { 8553 return astgen.failOff( 8554 token, 8555 offset + @intCast(u32, bad_index), 8556 "invalid string literal character: '{c}'", 8557 .{raw_string[bad_index]}, 8558 ); 8559 }, 8560 .expected_hex_digits => |bad_index| { 8561 return astgen.failOff( 8562 token, 8563 offset + @intCast(u32, bad_index), 8564 "expected hex digits after '\\x'", 8565 .{}, 8566 ); 8567 }, 8568 .invalid_hex_escape => |bad_index| { 8569 return astgen.failOff( 8570 token, 8571 offset + @intCast(u32, bad_index), 8572 "invalid hex digit: '{c}'", 8573 .{raw_string[bad_index]}, 8574 ); 8575 }, 8576 .invalid_unicode_escape => |bad_index| { 8577 return astgen.failOff( 8578 token, 8579 offset + @intCast(u32, bad_index), 8580 "invalid unicode digit: '{c}'", 8581 .{raw_string[bad_index]}, 8582 ); 8583 }, 8584 .missing_matching_rbrace => |bad_index| { 8585 return astgen.failOff( 8586 token, 8587 offset + @intCast(u32, bad_index), 8588 "missing matching '}}' character", 8589 .{}, 8590 ); 8591 }, 8592 .expected_unicode_digits => |bad_index| { 8593 return astgen.failOff( 8594 token, 8595 offset + @intCast(u32, bad_index), 8596 "expected unicode digits after '\\u'", 8597 .{}, 8598 ); 8599 }, 8600 } 8601 } 8602 8603 fn failNode( 8604 astgen: *AstGen, 8605 node: ast.Node.Index, 8606 comptime format: []const u8, 8607 args: anytype, 8608 ) InnerError { 8609 return astgen.failNodeNotes(node, format, args, &[0]u32{}); 8610 } 8611 8612 fn failNodeNotes( 8613 astgen: *AstGen, 8614 node: ast.Node.Index, 8615 comptime format: []const u8, 8616 args: anytype, 8617 notes: []const u32, 8618 ) InnerError { 8619 @setCold(true); 8620 const string_bytes = &astgen.string_bytes; 8621 const msg = @intCast(u32, string_bytes.items.len); 8622 { 8623 var managed = string_bytes.toManaged(astgen.gpa); 8624 defer string_bytes.* = managed.toUnmanaged(); 8625 try managed.writer().print(format ++ "\x00", args); 8626 } 8627 const notes_index: u32 = if (notes.len != 0) blk: { 8628 const notes_start = astgen.extra.items.len; 8629 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 8630 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 8631 astgen.extra.appendSliceAssumeCapacity(notes); 8632 break :blk @intCast(u32, notes_start); 8633 } else 0; 8634 try astgen.compile_errors.append(astgen.gpa, .{ 8635 .msg = msg, 8636 .node = node, 8637 .token = 0, 8638 .byte_offset = 0, 8639 .notes = notes_index, 8640 }); 8641 return error.AnalysisFail; 8642 } 8643 8644 fn failTok( 8645 astgen: *AstGen, 8646 token: ast.TokenIndex, 8647 comptime format: []const u8, 8648 args: anytype, 8649 ) InnerError { 8650 return astgen.failTokNotes(token, format, args, &[0]u32{}); 8651 } 8652 8653 fn failTokNotes( 8654 astgen: *AstGen, 8655 token: ast.TokenIndex, 8656 comptime format: []const u8, 8657 args: anytype, 8658 notes: []const u32, 8659 ) InnerError { 8660 @setCold(true); 8661 const string_bytes = &astgen.string_bytes; 8662 const msg = @intCast(u32, string_bytes.items.len); 8663 { 8664 var managed = string_bytes.toManaged(astgen.gpa); 8665 defer string_bytes.* = managed.toUnmanaged(); 8666 try managed.writer().print(format ++ "\x00", args); 8667 } 8668 const notes_index: u32 = if (notes.len != 0) blk: { 8669 const notes_start = astgen.extra.items.len; 8670 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); 8671 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); 8672 astgen.extra.appendSliceAssumeCapacity(notes); 8673 break :blk @intCast(u32, notes_start); 8674 } else 0; 8675 try astgen.compile_errors.append(astgen.gpa, .{ 8676 .msg = msg, 8677 .node = 0, 8678 .token = token, 8679 .byte_offset = 0, 8680 .notes = notes_index, 8681 }); 8682 return error.AnalysisFail; 8683 } 8684 8685 /// Same as `fail`, except given an absolute byte offset. 8686 fn failOff( 8687 astgen: *AstGen, 8688 token: ast.TokenIndex, 8689 byte_offset: u32, 8690 comptime format: []const u8, 8691 args: anytype, 8692 ) InnerError { 8693 @setCold(true); 8694 const string_bytes = &astgen.string_bytes; 8695 const msg = @intCast(u32, string_bytes.items.len); 8696 { 8697 var managed = string_bytes.toManaged(astgen.gpa); 8698 defer string_bytes.* = managed.toUnmanaged(); 8699 try managed.writer().print(format ++ "\x00", args); 8700 } 8701 try astgen.compile_errors.append(astgen.gpa, .{ 8702 .msg = msg, 8703 .node = 0, 8704 .token = token, 8705 .byte_offset = byte_offset, 8706 .notes = 0, 8707 }); 8708 return error.AnalysisFail; 8709 } 8710 8711 fn errNoteTok( 8712 astgen: *AstGen, 8713 token: ast.TokenIndex, 8714 comptime format: []const u8, 8715 args: anytype, 8716 ) Allocator.Error!u32 { 8717 @setCold(true); 8718 const string_bytes = &astgen.string_bytes; 8719 const msg = @intCast(u32, string_bytes.items.len); 8720 { 8721 var managed = string_bytes.toManaged(astgen.gpa); 8722 defer string_bytes.* = managed.toUnmanaged(); 8723 try managed.writer().print(format ++ "\x00", args); 8724 } 8725 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 8726 .msg = msg, 8727 .node = 0, 8728 .token = token, 8729 .byte_offset = 0, 8730 .notes = 0, 8731 }); 8732 } 8733 8734 fn errNoteNode( 8735 astgen: *AstGen, 8736 node: ast.Node.Index, 8737 comptime format: []const u8, 8738 args: anytype, 8739 ) Allocator.Error!u32 { 8740 @setCold(true); 8741 const string_bytes = &astgen.string_bytes; 8742 const msg = @intCast(u32, string_bytes.items.len); 8743 { 8744 var managed = string_bytes.toManaged(astgen.gpa); 8745 defer string_bytes.* = managed.toUnmanaged(); 8746 try managed.writer().print(format ++ "\x00", args); 8747 } 8748 return astgen.addExtra(Zir.Inst.CompileErrors.Item{ 8749 .msg = msg, 8750 .node = node, 8751 .token = 0, 8752 .byte_offset = 0, 8753 .notes = 0, 8754 }); 8755 } 8756 8757 fn identAsString(astgen: *AstGen, ident_token: ast.TokenIndex) !u32 { 8758 const gpa = astgen.gpa; 8759 const string_bytes = &astgen.string_bytes; 8760 const str_index = @intCast(u32, string_bytes.items.len); 8761 try astgen.appendIdentStr(ident_token, string_bytes); 8762 const key = string_bytes.items[str_index..]; 8763 const gop = try astgen.string_table.getOrPut(gpa, key); 8764 if (gop.found_existing) { 8765 string_bytes.shrinkRetainingCapacity(str_index); 8766 return gop.value_ptr.*; 8767 } else { 8768 // We have to dupe the key into the arena, otherwise the memory 8769 // becomes invalidated when string_bytes gets data appended. 8770 // TODO https://github.com/ziglang/zig/issues/8528 8771 gop.key_ptr.* = try astgen.arena.dupe(u8, key); 8772 gop.value_ptr.* = str_index; 8773 try string_bytes.append(gpa, 0); 8774 return str_index; 8775 } 8776 } 8777 8778 const IndexSlice = struct { index: u32, len: u32 }; 8779 8780 fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice { 8781 const gpa = astgen.gpa; 8782 const string_bytes = &astgen.string_bytes; 8783 const str_index = @intCast(u32, string_bytes.items.len); 8784 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 8785 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 8786 const key = string_bytes.items[str_index..]; 8787 const gop = try astgen.string_table.getOrPut(gpa, key); 8788 if (gop.found_existing) { 8789 string_bytes.shrinkRetainingCapacity(str_index); 8790 return IndexSlice{ 8791 .index = gop.value_ptr.*, 8792 .len = @intCast(u32, key.len), 8793 }; 8794 } else { 8795 // We have to dupe the key into the arena, otherwise the memory 8796 // becomes invalidated when string_bytes gets data appended. 8797 // TODO https://github.com/ziglang/zig/issues/8528 8798 gop.key_ptr.* = try astgen.arena.dupe(u8, key); 8799 gop.value_ptr.* = str_index; 8800 // Still need a null byte because we are using the same table 8801 // to lookup null terminated strings, so if we get a match, it has to 8802 // be null terminated for that to work. 8803 try string_bytes.append(gpa, 0); 8804 return IndexSlice{ 8805 .index = str_index, 8806 .len = @intCast(u32, key.len), 8807 }; 8808 } 8809 } 8810 8811 fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice { 8812 const tree = astgen.tree; 8813 const node_datas = tree.nodes.items(.data); 8814 8815 const start = node_datas[node].lhs; 8816 const end = node_datas[node].rhs; 8817 8818 const gpa = astgen.gpa; 8819 const string_bytes = &astgen.string_bytes; 8820 const str_index = string_bytes.items.len; 8821 8822 // First line: do not append a newline. 8823 var tok_i = start; 8824 { 8825 const slice = tree.tokenSlice(tok_i); 8826 const line_bytes = slice[2 .. slice.len - 1]; 8827 try string_bytes.appendSlice(gpa, line_bytes); 8828 tok_i += 1; 8829 } 8830 // Following lines: each line prepends a newline. 8831 while (tok_i <= end) : (tok_i += 1) { 8832 const slice = tree.tokenSlice(tok_i); 8833 const line_bytes = slice[2 .. slice.len - 1]; 8834 try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1); 8835 string_bytes.appendAssumeCapacity('\n'); 8836 string_bytes.appendSliceAssumeCapacity(line_bytes); 8837 } 8838 const len = string_bytes.items.len - str_index; 8839 try string_bytes.append(gpa, 0); 8840 return IndexSlice{ 8841 .index = @intCast(u32, str_index), 8842 .len = @intCast(u32, len), 8843 }; 8844 } 8845 8846 fn testNameString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !u32 { 8847 const gpa = astgen.gpa; 8848 const string_bytes = &astgen.string_bytes; 8849 const str_index = @intCast(u32, string_bytes.items.len); 8850 const token_bytes = astgen.tree.tokenSlice(str_lit_token); 8851 try string_bytes.append(gpa, 0); // Indicates this is a test. 8852 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0); 8853 try string_bytes.append(gpa, 0); 8854 return str_index; 8855 } 8856 8857 const Scope = struct { 8858 tag: Tag, 8859 8860 fn cast(base: *Scope, comptime T: type) ?*T { 8861 if (T == Defer) { 8862 switch (base.tag) { 8863 .defer_normal, .defer_error => return @fieldParentPtr(T, "base", base), 8864 else => return null, 8865 } 8866 } 8867 if (base.tag != T.base_tag) 8868 return null; 8869 8870 return @fieldParentPtr(T, "base", base); 8871 } 8872 8873 const Tag = enum { 8874 gen_zir, 8875 local_val, 8876 local_ptr, 8877 defer_normal, 8878 defer_error, 8879 namespace, 8880 top, 8881 }; 8882 8883 /// The category of identifier. These tag names are user-visible in compile errors. 8884 const IdCat = enum { 8885 @"function parameter", 8886 @"local constant", 8887 @"local variable", 8888 @"loop index capture", 8889 @"capture", 8890 }; 8891 8892 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer. 8893 /// This structure lives as long as the AST generation of the Block 8894 /// node that contains the variable. 8895 const LocalVal = struct { 8896 const base_tag: Tag = .local_val; 8897 base: Scope = Scope{ .tag = base_tag }, 8898 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. 8899 parent: *Scope, 8900 gen_zir: *GenZir, 8901 inst: Zir.Inst.Ref, 8902 /// Source location of the corresponding variable declaration. 8903 token_src: ast.TokenIndex, 8904 /// String table index. 8905 name: u32, 8906 id_cat: IdCat, 8907 /// Track whether the name has been referenced. 8908 used: bool = false, 8909 }; 8910 8911 /// This could be a `const` or `var` local. It has a pointer instead of a value. 8912 /// This structure lives as long as the AST generation of the Block 8913 /// node that contains the variable. 8914 const LocalPtr = struct { 8915 const base_tag: Tag = .local_ptr; 8916 base: Scope = Scope{ .tag = base_tag }, 8917 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. 8918 parent: *Scope, 8919 gen_zir: *GenZir, 8920 ptr: Zir.Inst.Ref, 8921 /// Source location of the corresponding variable declaration. 8922 token_src: ast.TokenIndex, 8923 /// String table index. 8924 name: u32, 8925 id_cat: IdCat, 8926 /// true means we find out during Sema whether the value is comptime. 8927 /// false means it is already known at AstGen the value is runtime-known. 8928 maybe_comptime: bool, 8929 /// Track whether the name has been referenced. 8930 used: bool = false, 8931 }; 8932 8933 const Defer = struct { 8934 base: Scope, 8935 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. 8936 parent: *Scope, 8937 defer_node: ast.Node.Index, 8938 }; 8939 8940 /// Represents a global scope that has any number of declarations in it. 8941 /// Each declaration has this as the parent scope. 8942 const Namespace = struct { 8943 const base_tag: Tag = .namespace; 8944 base: Scope = Scope{ .tag = base_tag }, 8945 8946 parent: *Scope, 8947 /// Maps string table index to the source location of declaration, 8948 /// for the purposes of reporting name shadowing compile errors. 8949 decls: std.AutoHashMapUnmanaged(u32, ast.Node.Index) = .{}, 8950 node: ast.Node.Index, 8951 }; 8952 8953 const Top = struct { 8954 const base_tag: Scope.Tag = .top; 8955 base: Scope = Scope{ .tag = base_tag }, 8956 }; 8957 }; 8958 8959 /// This is a temporary structure; references to it are valid only 8960 /// while constructing a `Zir`. 8961 const GenZir = struct { 8962 const base_tag: Scope.Tag = .gen_zir; 8963 base: Scope = Scope{ .tag = base_tag }, 8964 force_comptime: bool, 8965 in_defer: bool, 8966 /// How decls created in this scope should be named. 8967 anon_name_strategy: Zir.Inst.NameStrategy = .anon, 8968 /// The containing decl AST node. 8969 decl_node_index: ast.Node.Index, 8970 /// The containing decl line index, absolute. 8971 decl_line: u32, 8972 parent: *Scope, 8973 /// All `GenZir` scopes for the same ZIR share this. 8974 astgen: *AstGen, 8975 /// Keeps track of the list of instructions in this scope only. Indexes 8976 /// to instructions in `astgen`. 8977 instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{}, 8978 label: ?Label = null, 8979 break_block: Zir.Inst.Index = 0, 8980 continue_block: Zir.Inst.Index = 0, 8981 /// Only valid when setBreakResultLoc is called. 8982 break_result_loc: AstGen.ResultLoc = undefined, 8983 /// When a block has a pointer result location, here it is. 8984 rl_ptr: Zir.Inst.Ref = .none, 8985 /// When a block has a type result location, here it is. 8986 rl_ty_inst: Zir.Inst.Ref = .none, 8987 /// Keeps track of how many branches of a block did not actually 8988 /// consume the result location. astgen uses this to figure out 8989 /// whether to rely on break instructions or writing to the result 8990 /// pointer for the result instruction. 8991 rvalue_rl_count: usize = 0, 8992 /// Keeps track of how many break instructions there are. When astgen is finished 8993 /// with a block, it can check this against rvalue_rl_count to find out whether 8994 /// the break instructions should be downgraded to break_void. 8995 break_count: usize = 0, 8996 /// Tracks `break :foo bar` instructions so they can possibly be elided later if 8997 /// the labeled block ends up not needing a result location pointer. 8998 labeled_breaks: ArrayListUnmanaged(Zir.Inst.Index) = .{}, 8999 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions 9000 /// so they can possibly be elided later if the labeled block ends up not needing 9001 /// a result location pointer. 9002 labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{}, 9003 9004 suspend_node: ast.Node.Index = 0, 9005 nosuspend_node: ast.Node.Index = 0, 9006 9007 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { 9008 return .{ 9009 .force_comptime = gz.force_comptime, 9010 .in_defer = gz.in_defer, 9011 .decl_node_index = gz.decl_node_index, 9012 .decl_line = gz.decl_line, 9013 .parent = scope, 9014 .astgen = gz.astgen, 9015 .suspend_node = gz.suspend_node, 9016 .nosuspend_node = gz.nosuspend_node, 9017 }; 9018 } 9019 9020 const Label = struct { 9021 token: ast.TokenIndex, 9022 block_inst: Zir.Inst.Index, 9023 used: bool = false, 9024 }; 9025 9026 fn endsWithNoReturn(gz: GenZir) bool { 9027 const tags = gz.astgen.instructions.items(.tag); 9028 if (gz.instructions.items.len == 0) return false; 9029 const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; 9030 return tags[last_inst].isNoReturn(); 9031 } 9032 9033 /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`. 9034 fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { 9035 if (inst_ref == .unreachable_value) return true; 9036 if (refToIndex(inst_ref)) |inst_index| { 9037 return gz.astgen.instructions.items(.tag)[inst_index].isNoReturn(); 9038 } 9039 return false; 9040 } 9041 9042 fn calcLine(gz: GenZir, node: ast.Node.Index) u32 { 9043 const astgen = gz.astgen; 9044 const tree = astgen.tree; 9045 const source = tree.source; 9046 const token_starts = tree.tokens.items(.start); 9047 const node_start = token_starts[tree.firstToken(node)]; 9048 9049 astgen.advanceSourceCursor(source, node_start); 9050 9051 return @intCast(u32, gz.decl_line + astgen.source_line); 9052 } 9053 9054 fn tokSrcLoc(gz: GenZir, token_index: ast.TokenIndex) LazySrcLoc { 9055 return .{ .token_offset = token_index - gz.srcToken() }; 9056 } 9057 9058 fn nodeSrcLoc(gz: GenZir, node_index: ast.Node.Index) LazySrcLoc { 9059 return .{ .node_offset = gz.nodeIndexToRelative(node_index) }; 9060 } 9061 9062 fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 { 9063 return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); 9064 } 9065 9066 fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 { 9067 return token - gz.srcToken(); 9068 } 9069 9070 fn srcToken(gz: GenZir) ast.TokenIndex { 9071 return gz.astgen.tree.firstToken(gz.decl_node_index); 9072 } 9073 9074 fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { 9075 // Depending on whether the result location is a pointer or value, different 9076 // ZIR needs to be generated. In the former case we rely on storing to the 9077 // pointer to communicate the result, and use breakvoid; in the latter case 9078 // the block break instructions will have the result values. 9079 // One more complication: when the result location is a pointer, we detect 9080 // the scenario where the result location is not consumed. In this case 9081 // we emit ZIR for the block break instructions to have the result values, 9082 // and then rvalue() on that to pass the value to the result location. 9083 switch (parent_rl) { 9084 .ty, .coerced_ty => |ty_inst| { 9085 gz.rl_ty_inst = ty_inst; 9086 gz.break_result_loc = parent_rl; 9087 }, 9088 .none_or_ref => { 9089 gz.break_result_loc = .ref; 9090 }, 9091 .discard, .none, .ptr, .ref => { 9092 gz.break_result_loc = parent_rl; 9093 }, 9094 9095 .inferred_ptr => |ptr| { 9096 gz.rl_ptr = ptr; 9097 gz.break_result_loc = .{ .block_ptr = gz }; 9098 }, 9099 9100 .block_ptr => |parent_block_scope| { 9101 gz.rl_ty_inst = parent_block_scope.rl_ty_inst; 9102 gz.rl_ptr = parent_block_scope.rl_ptr; 9103 gz.break_result_loc = .{ .block_ptr = gz }; 9104 }, 9105 } 9106 } 9107 9108 fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void { 9109 const gpa = gz.astgen.gpa; 9110 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + 9111 gz.instructions.items.len); 9112 const zir_datas = gz.astgen.instructions.items(.data); 9113 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity( 9114 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, 9115 ); 9116 gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); 9117 } 9118 9119 fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void { 9120 const gpa = gz.astgen.gpa; 9121 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + 9122 gz.instructions.items.len); 9123 const zir_datas = gz.astgen.instructions.items(.data); 9124 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity( 9125 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, 9126 ); 9127 gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items); 9128 } 9129 9130 /// Same as `setBlockBody` except we don't copy instructions which are 9131 /// `store_to_block_ptr` instructions with lhs set to .none. 9132 fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void { 9133 const gpa = gz.astgen.gpa; 9134 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + 9135 gz.instructions.items.len); 9136 const zir_datas = gz.astgen.instructions.items(.data); 9137 const zir_tags = gz.astgen.instructions.items(.tag); 9138 const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{ 9139 .body_len = @intCast(u32, gz.instructions.items.len), 9140 }); 9141 zir_datas[inst].pl_node.payload_index = block_pl_index; 9142 for (gz.instructions.items) |sub_inst| { 9143 if (zir_tags[sub_inst] == .store_to_block_ptr and 9144 zir_datas[sub_inst].bin.lhs == .none) 9145 { 9146 // Decrement `body_len`. 9147 gz.astgen.extra.items[block_pl_index] -= 1; 9148 continue; 9149 } 9150 gz.astgen.extra.appendAssumeCapacity(sub_inst); 9151 } 9152 } 9153 9154 fn addFunc(gz: *GenZir, args: struct { 9155 src_node: ast.Node.Index, 9156 body: []const Zir.Inst.Index, 9157 param_block: Zir.Inst.Index, 9158 ret_ty: []const Zir.Inst.Index, 9159 ret_br: Zir.Inst.Index, 9160 cc: Zir.Inst.Ref, 9161 align_inst: Zir.Inst.Ref, 9162 lib_name: u32, 9163 is_var_args: bool, 9164 is_inferred_error: bool, 9165 is_test: bool, 9166 is_extern: bool, 9167 }) !Zir.Inst.Ref { 9168 assert(args.src_node != 0); 9169 const astgen = gz.astgen; 9170 const gpa = astgen.gpa; 9171 9172 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9173 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 9174 9175 var src_locs_buffer: [3]u32 = undefined; 9176 var src_locs: []u32 = src_locs_buffer[0..0]; 9177 if (args.body.len != 0) { 9178 const tree = astgen.tree; 9179 const node_tags = tree.nodes.items(.tag); 9180 const node_datas = tree.nodes.items(.data); 9181 const token_starts = tree.tokens.items(.start); 9182 const fn_decl = args.src_node; 9183 assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); 9184 const block = node_datas[fn_decl].rhs; 9185 const lbrace_start = token_starts[tree.firstToken(block)]; 9186 const rbrace_start = token_starts[tree.lastToken(block)]; 9187 9188 astgen.advanceSourceCursor(tree.source, lbrace_start); 9189 const lbrace_line = @intCast(u32, astgen.source_line); 9190 const lbrace_column = @intCast(u32, astgen.source_column); 9191 9192 astgen.advanceSourceCursor(tree.source, rbrace_start); 9193 const rbrace_line = @intCast(u32, astgen.source_line); 9194 const rbrace_column = @intCast(u32, astgen.source_column); 9195 9196 const columns = lbrace_column | (rbrace_column << 16); 9197 src_locs_buffer[0] = lbrace_line; 9198 src_locs_buffer[1] = rbrace_line; 9199 src_locs_buffer[2] = columns; 9200 src_locs = &src_locs_buffer; 9201 } 9202 9203 if (args.cc != .none or args.lib_name != 0 or 9204 args.is_var_args or args.is_test or args.align_inst != .none or 9205 args.is_extern) 9206 { 9207 try astgen.extra.ensureUnusedCapacity( 9208 gpa, 9209 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len + 9210 args.ret_ty.len + args.body.len + src_locs.len + 9211 @boolToInt(args.lib_name != 0) + 9212 @boolToInt(args.align_inst != .none) + 9213 @boolToInt(args.cc != .none), 9214 ); 9215 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ 9216 .src_node = gz.nodeIndexToRelative(args.src_node), 9217 .param_block = args.param_block, 9218 .ret_body_len = @intCast(u32, args.ret_ty.len), 9219 .body_len = @intCast(u32, args.body.len), 9220 }); 9221 if (args.lib_name != 0) { 9222 astgen.extra.appendAssumeCapacity(args.lib_name); 9223 } 9224 if (args.cc != .none) { 9225 astgen.extra.appendAssumeCapacity(@enumToInt(args.cc)); 9226 } 9227 if (args.align_inst != .none) { 9228 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 9229 } 9230 astgen.extra.appendSliceAssumeCapacity(args.ret_ty); 9231 astgen.extra.appendSliceAssumeCapacity(args.body); 9232 astgen.extra.appendSliceAssumeCapacity(src_locs); 9233 9234 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 9235 if (args.ret_br != 0) { 9236 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index; 9237 } 9238 astgen.instructions.appendAssumeCapacity(.{ 9239 .tag = .extended, 9240 .data = .{ .extended = .{ 9241 .opcode = .func, 9242 .small = @bitCast(u16, Zir.Inst.ExtendedFunc.Small{ 9243 .is_var_args = args.is_var_args, 9244 .is_inferred_error = args.is_inferred_error, 9245 .has_lib_name = args.lib_name != 0, 9246 .has_cc = args.cc != .none, 9247 .has_align = args.align_inst != .none, 9248 .is_test = args.is_test, 9249 .is_extern = args.is_extern, 9250 }), 9251 .operand = payload_index, 9252 } }, 9253 }); 9254 gz.instructions.appendAssumeCapacity(new_index); 9255 return indexToRef(new_index); 9256 } else { 9257 try astgen.extra.ensureUnusedCapacity( 9258 gpa, 9259 @typeInfo(Zir.Inst.Func).Struct.fields.len + 9260 args.ret_ty.len + args.body.len + src_locs.len, 9261 ); 9262 9263 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{ 9264 .param_block = args.param_block, 9265 .ret_body_len = @intCast(u32, args.ret_ty.len), 9266 .body_len = @intCast(u32, args.body.len), 9267 }); 9268 astgen.extra.appendSliceAssumeCapacity(args.ret_ty); 9269 astgen.extra.appendSliceAssumeCapacity(args.body); 9270 astgen.extra.appendSliceAssumeCapacity(src_locs); 9271 9272 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; 9273 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 9274 if (args.ret_br != 0) { 9275 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index; 9276 } 9277 astgen.instructions.appendAssumeCapacity(.{ 9278 .tag = tag, 9279 .data = .{ .pl_node = .{ 9280 .src_node = gz.nodeIndexToRelative(args.src_node), 9281 .payload_index = payload_index, 9282 } }, 9283 }); 9284 gz.instructions.appendAssumeCapacity(new_index); 9285 return indexToRef(new_index); 9286 } 9287 } 9288 9289 fn addVar(gz: *GenZir, args: struct { 9290 align_inst: Zir.Inst.Ref, 9291 lib_name: u32, 9292 var_type: Zir.Inst.Ref, 9293 init: Zir.Inst.Ref, 9294 is_extern: bool, 9295 is_threadlocal: bool, 9296 }) !Zir.Inst.Ref { 9297 const astgen = gz.astgen; 9298 const gpa = astgen.gpa; 9299 9300 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9301 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 9302 9303 try astgen.extra.ensureUnusedCapacity( 9304 gpa, 9305 @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + 9306 @boolToInt(args.lib_name != 0) + 9307 @boolToInt(args.align_inst != .none) + 9308 @boolToInt(args.init != .none), 9309 ); 9310 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ 9311 .var_type = args.var_type, 9312 }); 9313 if (args.lib_name != 0) { 9314 astgen.extra.appendAssumeCapacity(args.lib_name); 9315 } 9316 if (args.align_inst != .none) { 9317 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 9318 } 9319 if (args.init != .none) { 9320 astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); 9321 } 9322 9323 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 9324 astgen.instructions.appendAssumeCapacity(.{ 9325 .tag = .extended, 9326 .data = .{ .extended = .{ 9327 .opcode = .variable, 9328 .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ 9329 .has_lib_name = args.lib_name != 0, 9330 .has_align = args.align_inst != .none, 9331 .has_init = args.init != .none, 9332 .is_extern = args.is_extern, 9333 .is_threadlocal = args.is_threadlocal, 9334 }), 9335 .operand = payload_index, 9336 } }, 9337 }); 9338 gz.instructions.appendAssumeCapacity(new_index); 9339 return indexToRef(new_index); 9340 } 9341 9342 fn addCall( 9343 gz: *GenZir, 9344 tag: Zir.Inst.Tag, 9345 callee: Zir.Inst.Ref, 9346 args: []const Zir.Inst.Ref, 9347 /// Absolute node index. This function does the conversion to offset from Decl. 9348 src_node: ast.Node.Index, 9349 ) !Zir.Inst.Ref { 9350 assert(callee != .none); 9351 assert(src_node != 0); 9352 const gpa = gz.astgen.gpa; 9353 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9354 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 9355 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Call).Struct.fields.len + 9356 args.len); 9357 9358 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{ 9359 .callee = callee, 9360 .args_len = @intCast(u32, args.len), 9361 }); 9362 gz.astgen.appendRefsAssumeCapacity(args); 9363 9364 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9365 gz.astgen.instructions.appendAssumeCapacity(.{ 9366 .tag = tag, 9367 .data = .{ .pl_node = .{ 9368 .src_node = gz.nodeIndexToRelative(src_node), 9369 .payload_index = payload_index, 9370 } }, 9371 }); 9372 gz.instructions.appendAssumeCapacity(new_index); 9373 return indexToRef(new_index); 9374 } 9375 9376 /// Note that this returns a `Zir.Inst.Index` not a ref. 9377 /// Leaves the `payload_index` field undefined. 9378 fn addBoolBr( 9379 gz: *GenZir, 9380 tag: Zir.Inst.Tag, 9381 lhs: Zir.Inst.Ref, 9382 ) !Zir.Inst.Index { 9383 assert(lhs != .none); 9384 const gpa = gz.astgen.gpa; 9385 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9386 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 9387 9388 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9389 gz.astgen.instructions.appendAssumeCapacity(.{ 9390 .tag = tag, 9391 .data = .{ .bool_br = .{ 9392 .lhs = lhs, 9393 .payload_index = undefined, 9394 } }, 9395 }); 9396 gz.instructions.appendAssumeCapacity(new_index); 9397 return new_index; 9398 } 9399 9400 fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { 9401 return gz.add(.{ 9402 .tag = .int, 9403 .data = .{ .int = integer }, 9404 }); 9405 } 9406 9407 fn addIntBig(gz: *GenZir, limbs: []const std.math.big.Limb) !Zir.Inst.Ref { 9408 const astgen = gz.astgen; 9409 const gpa = astgen.gpa; 9410 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9411 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 9412 try astgen.string_bytes.ensureUnusedCapacity(gpa, @sizeOf(std.math.big.Limb) * limbs.len); 9413 9414 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 9415 astgen.instructions.appendAssumeCapacity(.{ 9416 .tag = .int_big, 9417 .data = .{ .str = .{ 9418 .start = @intCast(u32, astgen.string_bytes.items.len), 9419 .len = @intCast(u32, limbs.len), 9420 } }, 9421 }); 9422 gz.instructions.appendAssumeCapacity(new_index); 9423 astgen.string_bytes.appendSliceAssumeCapacity(mem.sliceAsBytes(limbs)); 9424 return indexToRef(new_index); 9425 } 9426 9427 fn addFloat(gz: *GenZir, number: f64) !Zir.Inst.Ref { 9428 return gz.add(.{ 9429 .tag = .float, 9430 .data = .{ .float = number }, 9431 }); 9432 } 9433 9434 fn addUnNode( 9435 gz: *GenZir, 9436 tag: Zir.Inst.Tag, 9437 operand: Zir.Inst.Ref, 9438 /// Absolute node index. This function does the conversion to offset from Decl. 9439 src_node: ast.Node.Index, 9440 ) !Zir.Inst.Ref { 9441 assert(operand != .none); 9442 return gz.add(.{ 9443 .tag = tag, 9444 .data = .{ .un_node = .{ 9445 .operand = operand, 9446 .src_node = gz.nodeIndexToRelative(src_node), 9447 } }, 9448 }); 9449 } 9450 9451 fn addPlNode( 9452 gz: *GenZir, 9453 tag: Zir.Inst.Tag, 9454 /// Absolute node index. This function does the conversion to offset from Decl. 9455 src_node: ast.Node.Index, 9456 extra: anytype, 9457 ) !Zir.Inst.Ref { 9458 const gpa = gz.astgen.gpa; 9459 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9460 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 9461 9462 const payload_index = try gz.astgen.addExtra(extra); 9463 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9464 gz.astgen.instructions.appendAssumeCapacity(.{ 9465 .tag = tag, 9466 .data = .{ .pl_node = .{ 9467 .src_node = gz.nodeIndexToRelative(src_node), 9468 .payload_index = payload_index, 9469 } }, 9470 }); 9471 gz.instructions.appendAssumeCapacity(new_index); 9472 return indexToRef(new_index); 9473 } 9474 9475 fn addParam( 9476 gz: *GenZir, 9477 tag: Zir.Inst.Tag, 9478 /// Absolute token index. This function does the conversion to Decl offset. 9479 abs_tok_index: ast.TokenIndex, 9480 name: u32, 9481 body: []const u32, 9482 ) !Zir.Inst.Index { 9483 const gpa = gz.astgen.gpa; 9484 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9485 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 9486 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len + 9487 body.len); 9488 9489 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{ 9490 .name = name, 9491 .body_len = @intCast(u32, body.len), 9492 }); 9493 gz.astgen.extra.appendSliceAssumeCapacity(body); 9494 9495 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9496 gz.astgen.instructions.appendAssumeCapacity(.{ 9497 .tag = tag, 9498 .data = .{ .pl_tok = .{ 9499 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 9500 .payload_index = payload_index, 9501 } }, 9502 }); 9503 gz.instructions.appendAssumeCapacity(new_index); 9504 return new_index; 9505 } 9506 9507 fn addExtendedPayload( 9508 gz: *GenZir, 9509 opcode: Zir.Inst.Extended, 9510 extra: anytype, 9511 ) !Zir.Inst.Ref { 9512 const gpa = gz.astgen.gpa; 9513 9514 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9515 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 9516 9517 const payload_index = try gz.astgen.addExtra(extra); 9518 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9519 gz.astgen.instructions.appendAssumeCapacity(.{ 9520 .tag = .extended, 9521 .data = .{ .extended = .{ 9522 .opcode = opcode, 9523 .small = undefined, 9524 .operand = payload_index, 9525 } }, 9526 }); 9527 gz.instructions.appendAssumeCapacity(new_index); 9528 return indexToRef(new_index); 9529 } 9530 9531 fn addExtendedMultiOp( 9532 gz: *GenZir, 9533 opcode: Zir.Inst.Extended, 9534 node: ast.Node.Index, 9535 operands: []const Zir.Inst.Ref, 9536 ) !Zir.Inst.Ref { 9537 const astgen = gz.astgen; 9538 const gpa = astgen.gpa; 9539 9540 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9541 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 9542 try astgen.extra.ensureUnusedCapacity( 9543 gpa, 9544 @typeInfo(Zir.Inst.NodeMultiOp).Struct.fields.len + operands.len, 9545 ); 9546 9547 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.NodeMultiOp{ 9548 .src_node = gz.nodeIndexToRelative(node), 9549 }); 9550 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 9551 astgen.instructions.appendAssumeCapacity(.{ 9552 .tag = .extended, 9553 .data = .{ .extended = .{ 9554 .opcode = opcode, 9555 .small = @intCast(u16, operands.len), 9556 .operand = payload_index, 9557 } }, 9558 }); 9559 gz.instructions.appendAssumeCapacity(new_index); 9560 astgen.appendRefsAssumeCapacity(operands); 9561 return indexToRef(new_index); 9562 } 9563 9564 fn addArrayTypeSentinel( 9565 gz: *GenZir, 9566 len: Zir.Inst.Ref, 9567 sentinel: Zir.Inst.Ref, 9568 elem_type: Zir.Inst.Ref, 9569 ) !Zir.Inst.Ref { 9570 const gpa = gz.astgen.gpa; 9571 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9572 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 9573 9574 const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{ 9575 .sentinel = sentinel, 9576 .elem_type = elem_type, 9577 }); 9578 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9579 gz.astgen.instructions.appendAssumeCapacity(.{ 9580 .tag = .array_type_sentinel, 9581 .data = .{ .array_type_sentinel = .{ 9582 .len = len, 9583 .payload_index = payload_index, 9584 } }, 9585 }); 9586 gz.instructions.appendAssumeCapacity(new_index); 9587 return indexToRef(new_index); 9588 } 9589 9590 fn addUnTok( 9591 gz: *GenZir, 9592 tag: Zir.Inst.Tag, 9593 operand: Zir.Inst.Ref, 9594 /// Absolute token index. This function does the conversion to Decl offset. 9595 abs_tok_index: ast.TokenIndex, 9596 ) !Zir.Inst.Ref { 9597 assert(operand != .none); 9598 return gz.add(.{ 9599 .tag = tag, 9600 .data = .{ .un_tok = .{ 9601 .operand = operand, 9602 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 9603 } }, 9604 }); 9605 } 9606 9607 fn addStrTok( 9608 gz: *GenZir, 9609 tag: Zir.Inst.Tag, 9610 str_index: u32, 9611 /// Absolute token index. This function does the conversion to Decl offset. 9612 abs_tok_index: ast.TokenIndex, 9613 ) !Zir.Inst.Ref { 9614 return gz.add(.{ 9615 .tag = tag, 9616 .data = .{ .str_tok = .{ 9617 .start = str_index, 9618 .src_tok = gz.tokenIndexToRelative(abs_tok_index), 9619 } }, 9620 }); 9621 } 9622 9623 fn addBreak( 9624 gz: *GenZir, 9625 tag: Zir.Inst.Tag, 9626 break_block: Zir.Inst.Index, 9627 operand: Zir.Inst.Ref, 9628 ) !Zir.Inst.Index { 9629 return gz.addAsIndex(.{ 9630 .tag = tag, 9631 .data = .{ .@"break" = .{ 9632 .block_inst = break_block, 9633 .operand = operand, 9634 } }, 9635 }); 9636 } 9637 9638 fn addBin( 9639 gz: *GenZir, 9640 tag: Zir.Inst.Tag, 9641 lhs: Zir.Inst.Ref, 9642 rhs: Zir.Inst.Ref, 9643 ) !Zir.Inst.Ref { 9644 assert(lhs != .none); 9645 assert(rhs != .none); 9646 return gz.add(.{ 9647 .tag = tag, 9648 .data = .{ .bin = .{ 9649 .lhs = lhs, 9650 .rhs = rhs, 9651 } }, 9652 }); 9653 } 9654 9655 fn addDecl( 9656 gz: *GenZir, 9657 tag: Zir.Inst.Tag, 9658 decl_index: u32, 9659 src_node: ast.Node.Index, 9660 ) !Zir.Inst.Ref { 9661 return gz.add(.{ 9662 .tag = tag, 9663 .data = .{ .pl_node = .{ 9664 .src_node = gz.nodeIndexToRelative(src_node), 9665 .payload_index = decl_index, 9666 } }, 9667 }); 9668 } 9669 9670 fn addNode( 9671 gz: *GenZir, 9672 tag: Zir.Inst.Tag, 9673 /// Absolute node index. This function does the conversion to offset from Decl. 9674 src_node: ast.Node.Index, 9675 ) !Zir.Inst.Ref { 9676 return gz.add(.{ 9677 .tag = tag, 9678 .data = .{ .node = gz.nodeIndexToRelative(src_node) }, 9679 }); 9680 } 9681 9682 fn addNodeExtended( 9683 gz: *GenZir, 9684 opcode: Zir.Inst.Extended, 9685 /// Absolute node index. This function does the conversion to offset from Decl. 9686 src_node: ast.Node.Index, 9687 ) !Zir.Inst.Ref { 9688 return gz.add(.{ 9689 .tag = .extended, 9690 .data = .{ .extended = .{ 9691 .opcode = opcode, 9692 .small = undefined, 9693 .operand = @bitCast(u32, gz.nodeIndexToRelative(src_node)), 9694 } }, 9695 }); 9696 } 9697 9698 fn addAllocExtended( 9699 gz: *GenZir, 9700 args: struct { 9701 /// Absolute node index. This function does the conversion to offset from Decl. 9702 node: ast.Node.Index, 9703 type_inst: Zir.Inst.Ref, 9704 align_inst: Zir.Inst.Ref, 9705 is_const: bool, 9706 is_comptime: bool, 9707 }, 9708 ) !Zir.Inst.Ref { 9709 const astgen = gz.astgen; 9710 const gpa = astgen.gpa; 9711 9712 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9713 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 9714 try astgen.extra.ensureUnusedCapacity( 9715 gpa, 9716 @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len + 9717 @as(usize, @boolToInt(args.type_inst != .none)) + 9718 @as(usize, @boolToInt(args.align_inst != .none)), 9719 ); 9720 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.AllocExtended{ 9721 .src_node = gz.nodeIndexToRelative(args.node), 9722 }); 9723 if (args.type_inst != .none) { 9724 astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst)); 9725 } 9726 if (args.align_inst != .none) { 9727 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); 9728 } 9729 9730 const has_type: u4 = @boolToInt(args.type_inst != .none); 9731 const has_align: u4 = @boolToInt(args.align_inst != .none); 9732 const is_const: u4 = @boolToInt(args.is_const); 9733 const is_comptime: u4 = @boolToInt(args.is_comptime); 9734 const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3); 9735 9736 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 9737 astgen.instructions.appendAssumeCapacity(.{ 9738 .tag = .extended, 9739 .data = .{ .extended = .{ 9740 .opcode = .alloc, 9741 .small = small, 9742 .operand = payload_index, 9743 } }, 9744 }); 9745 gz.instructions.appendAssumeCapacity(new_index); 9746 return indexToRef(new_index); 9747 } 9748 9749 fn addAsm( 9750 gz: *GenZir, 9751 args: struct { 9752 /// Absolute node index. This function does the conversion to offset from Decl. 9753 node: ast.Node.Index, 9754 asm_source: u32, 9755 output_type_bits: u32, 9756 is_volatile: bool, 9757 outputs: []const Zir.Inst.Asm.Output, 9758 inputs: []const Zir.Inst.Asm.Input, 9759 clobbers: []const u32, 9760 }, 9761 ) !Zir.Inst.Ref { 9762 const astgen = gz.astgen; 9763 const gpa = astgen.gpa; 9764 9765 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9766 try astgen.instructions.ensureUnusedCapacity(gpa, 1); 9767 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Asm).Struct.fields.len + 9768 args.outputs.len * @typeInfo(Zir.Inst.Asm.Output).Struct.fields.len + 9769 args.inputs.len * @typeInfo(Zir.Inst.Asm.Input).Struct.fields.len + 9770 args.clobbers.len); 9771 9772 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Asm{ 9773 .src_node = gz.nodeIndexToRelative(args.node), 9774 .asm_source = args.asm_source, 9775 .output_type_bits = args.output_type_bits, 9776 }); 9777 for (args.outputs) |output| { 9778 _ = gz.astgen.addExtraAssumeCapacity(output); 9779 } 9780 for (args.inputs) |input| { 9781 _ = gz.astgen.addExtraAssumeCapacity(input); 9782 } 9783 gz.astgen.extra.appendSliceAssumeCapacity(args.clobbers); 9784 9785 // * 0b00000000_000XXXXX - `outputs_len`. 9786 // * 0b000000XX_XXX00000 - `inputs_len`. 9787 // * 0b0XXXXX00_00000000 - `clobbers_len`. 9788 // * 0bX0000000_00000000 - is volatile 9789 const small: u16 = @intCast(u16, args.outputs.len) | 9790 @intCast(u16, args.inputs.len << 5) | 9791 @intCast(u16, args.clobbers.len << 10) | 9792 (@as(u16, @boolToInt(args.is_volatile)) << 15); 9793 9794 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); 9795 astgen.instructions.appendAssumeCapacity(.{ 9796 .tag = .extended, 9797 .data = .{ .extended = .{ 9798 .opcode = .@"asm", 9799 .small = small, 9800 .operand = payload_index, 9801 } }, 9802 }); 9803 gz.instructions.appendAssumeCapacity(new_index); 9804 return indexToRef(new_index); 9805 } 9806 9807 /// Note that this returns a `Zir.Inst.Index` not a ref. 9808 /// Does *not* append the block instruction to the scope. 9809 /// Leaves the `payload_index` field undefined. 9810 fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { 9811 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9812 const gpa = gz.astgen.gpa; 9813 try gz.astgen.instructions.append(gpa, .{ 9814 .tag = tag, 9815 .data = .{ .pl_node = .{ 9816 .src_node = gz.nodeIndexToRelative(node), 9817 .payload_index = undefined, 9818 } }, 9819 }); 9820 return new_index; 9821 } 9822 9823 /// Note that this returns a `Zir.Inst.Index` not a ref. 9824 /// Leaves the `payload_index` field undefined. 9825 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { 9826 const gpa = gz.astgen.gpa; 9827 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9828 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9829 try gz.astgen.instructions.append(gpa, .{ 9830 .tag = tag, 9831 .data = .{ .pl_node = .{ 9832 .src_node = gz.nodeIndexToRelative(node), 9833 .payload_index = undefined, 9834 } }, 9835 }); 9836 gz.instructions.appendAssumeCapacity(new_index); 9837 return new_index; 9838 } 9839 9840 fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 9841 src_node: ast.Node.Index, 9842 body_len: u32, 9843 fields_len: u32, 9844 decls_len: u32, 9845 layout: std.builtin.TypeInfo.ContainerLayout, 9846 known_has_bits: bool, 9847 }) !void { 9848 const astgen = gz.astgen; 9849 const gpa = astgen.gpa; 9850 9851 try astgen.extra.ensureUnusedCapacity(gpa, 4); 9852 const payload_index = @intCast(u32, astgen.extra.items.len); 9853 9854 if (args.src_node != 0) { 9855 const node_offset = gz.nodeIndexToRelative(args.src_node); 9856 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 9857 } 9858 if (args.body_len != 0) { 9859 astgen.extra.appendAssumeCapacity(args.body_len); 9860 } 9861 if (args.fields_len != 0) { 9862 astgen.extra.appendAssumeCapacity(args.fields_len); 9863 } 9864 if (args.decls_len != 0) { 9865 astgen.extra.appendAssumeCapacity(args.decls_len); 9866 } 9867 astgen.instructions.set(inst, .{ 9868 .tag = .extended, 9869 .data = .{ .extended = .{ 9870 .opcode = .struct_decl, 9871 .small = @bitCast(u16, Zir.Inst.StructDecl.Small{ 9872 .has_src_node = args.src_node != 0, 9873 .has_body_len = args.body_len != 0, 9874 .has_fields_len = args.fields_len != 0, 9875 .has_decls_len = args.decls_len != 0, 9876 .known_has_bits = args.known_has_bits, 9877 .name_strategy = gz.anon_name_strategy, 9878 .layout = args.layout, 9879 }), 9880 .operand = payload_index, 9881 } }, 9882 }); 9883 } 9884 9885 fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 9886 src_node: ast.Node.Index, 9887 tag_type: Zir.Inst.Ref, 9888 body_len: u32, 9889 fields_len: u32, 9890 decls_len: u32, 9891 layout: std.builtin.TypeInfo.ContainerLayout, 9892 auto_enum_tag: bool, 9893 }) !void { 9894 const astgen = gz.astgen; 9895 const gpa = astgen.gpa; 9896 9897 try astgen.extra.ensureUnusedCapacity(gpa, 5); 9898 const payload_index = @intCast(u32, astgen.extra.items.len); 9899 9900 if (args.src_node != 0) { 9901 const node_offset = gz.nodeIndexToRelative(args.src_node); 9902 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 9903 } 9904 if (args.tag_type != .none) { 9905 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 9906 } 9907 if (args.body_len != 0) { 9908 astgen.extra.appendAssumeCapacity(args.body_len); 9909 } 9910 if (args.fields_len != 0) { 9911 astgen.extra.appendAssumeCapacity(args.fields_len); 9912 } 9913 if (args.decls_len != 0) { 9914 astgen.extra.appendAssumeCapacity(args.decls_len); 9915 } 9916 astgen.instructions.set(inst, .{ 9917 .tag = .extended, 9918 .data = .{ .extended = .{ 9919 .opcode = .union_decl, 9920 .small = @bitCast(u16, Zir.Inst.UnionDecl.Small{ 9921 .has_src_node = args.src_node != 0, 9922 .has_tag_type = args.tag_type != .none, 9923 .has_body_len = args.body_len != 0, 9924 .has_fields_len = args.fields_len != 0, 9925 .has_decls_len = args.decls_len != 0, 9926 .name_strategy = gz.anon_name_strategy, 9927 .layout = args.layout, 9928 .auto_enum_tag = args.auto_enum_tag, 9929 }), 9930 .operand = payload_index, 9931 } }, 9932 }); 9933 } 9934 9935 fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { 9936 src_node: ast.Node.Index, 9937 tag_type: Zir.Inst.Ref, 9938 body_len: u32, 9939 fields_len: u32, 9940 decls_len: u32, 9941 nonexhaustive: bool, 9942 }) !void { 9943 const astgen = gz.astgen; 9944 const gpa = astgen.gpa; 9945 9946 try astgen.extra.ensureUnusedCapacity(gpa, 5); 9947 const payload_index = @intCast(u32, astgen.extra.items.len); 9948 9949 if (args.src_node != 0) { 9950 const node_offset = gz.nodeIndexToRelative(args.src_node); 9951 astgen.extra.appendAssumeCapacity(@bitCast(u32, node_offset)); 9952 } 9953 if (args.tag_type != .none) { 9954 astgen.extra.appendAssumeCapacity(@enumToInt(args.tag_type)); 9955 } 9956 if (args.body_len != 0) { 9957 astgen.extra.appendAssumeCapacity(args.body_len); 9958 } 9959 if (args.fields_len != 0) { 9960 astgen.extra.appendAssumeCapacity(args.fields_len); 9961 } 9962 if (args.decls_len != 0) { 9963 astgen.extra.appendAssumeCapacity(args.decls_len); 9964 } 9965 astgen.instructions.set(inst, .{ 9966 .tag = .extended, 9967 .data = .{ .extended = .{ 9968 .opcode = .enum_decl, 9969 .small = @bitCast(u16, Zir.Inst.EnumDecl.Small{ 9970 .has_src_node = args.src_node != 0, 9971 .has_tag_type = args.tag_type != .none, 9972 .has_body_len = args.body_len != 0, 9973 .has_fields_len = args.fields_len != 0, 9974 .has_decls_len = args.decls_len != 0, 9975 .name_strategy = gz.anon_name_strategy, 9976 .nonexhaustive = args.nonexhaustive, 9977 }), 9978 .operand = payload_index, 9979 } }, 9980 }); 9981 } 9982 9983 fn add(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Ref { 9984 return indexToRef(try gz.addAsIndex(inst)); 9985 } 9986 9987 fn addAsIndex(gz: *GenZir, inst: Zir.Inst) !Zir.Inst.Index { 9988 const gpa = gz.astgen.gpa; 9989 try gz.instructions.ensureUnusedCapacity(gpa, 1); 9990 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 9991 9992 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 9993 gz.astgen.instructions.appendAssumeCapacity(inst); 9994 gz.instructions.appendAssumeCapacity(new_index); 9995 return new_index; 9996 } 9997 9998 fn reserveInstructionIndex(gz: *GenZir) !Zir.Inst.Index { 9999 const gpa = gz.astgen.gpa; 10000 try gz.instructions.ensureUnusedCapacity(gpa, 1); 10001 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); 10002 10003 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); 10004 gz.astgen.instructions.len += 1; 10005 gz.instructions.appendAssumeCapacity(new_index); 10006 return new_index; 10007 } 10008 10009 fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: ast.Node.Index) !void { 10010 switch (rl) { 10011 .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node), 10012 .ty => _ = try gz.addUnNode(.ret_node, operand, node), 10013 else => unreachable, 10014 } 10015 } 10016 }; 10017 10018 /// This can only be for short-lived references; the memory becomes invalidated 10019 /// when another string is added. 10020 fn nullTerminatedString(astgen: AstGen, index: usize) [*:0]const u8 { 10021 return @ptrCast([*:0]const u8, astgen.string_bytes.items.ptr) + index; 10022 } 10023 10024 fn isPrimitive(name: []const u8) bool { 10025 if (simple_types.get(name) != null) return true; 10026 if (name.len < 2) return false; 10027 const first_c = name[0]; 10028 if (first_c != 'i' and first_c != 'u') return false; 10029 if (std.fmt.parseInt(u16, name[1..], 10)) |_| { 10030 return true; 10031 } else |err| switch (err) { 10032 error.Overflow => return true, 10033 error.InvalidCharacter => return false, 10034 } 10035 } 10036 10037 /// Local variables shadowing detection, including function parameters and primitives. 10038 fn detectLocalShadowing( 10039 astgen: *AstGen, 10040 scope: *Scope, 10041 ident_name: u32, 10042 name_token: ast.TokenIndex, 10043 token_bytes: []const u8, 10044 ) !void { 10045 const gpa = astgen.gpa; 10046 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 10047 return astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 10048 token_bytes, 10049 }, &[_]u32{ 10050 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 10051 token_bytes, 10052 }), 10053 }); 10054 } 10055 10056 var s = scope; 10057 while (true) switch (s.tag) { 10058 .local_val => { 10059 const local_val = s.cast(Scope.LocalVal).?; 10060 if (local_val.name == ident_name) { 10061 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 10062 const name = try gpa.dupe(u8, name_slice); 10063 defer gpa.free(name); 10064 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 10065 @tagName(local_val.id_cat), name, 10066 }, &[_]u32{ 10067 try astgen.errNoteTok( 10068 local_val.token_src, 10069 "previous declaration here", 10070 .{}, 10071 ), 10072 }); 10073 } 10074 s = local_val.parent; 10075 }, 10076 .local_ptr => { 10077 const local_ptr = s.cast(Scope.LocalPtr).?; 10078 if (local_ptr.name == ident_name) { 10079 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 10080 const name = try gpa.dupe(u8, name_slice); 10081 defer gpa.free(name); 10082 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{ 10083 @tagName(local_ptr.id_cat), name, 10084 }, &[_]u32{ 10085 try astgen.errNoteTok( 10086 local_ptr.token_src, 10087 "previous declaration here", 10088 .{}, 10089 ), 10090 }); 10091 } 10092 s = local_ptr.parent; 10093 }, 10094 .namespace => { 10095 const ns = s.cast(Scope.Namespace).?; 10096 const decl_node = ns.decls.get(ident_name) orelse { 10097 s = ns.parent; 10098 continue; 10099 }; 10100 const name_slice = mem.span(astgen.nullTerminatedString(ident_name)); 10101 const name = try gpa.dupe(u8, name_slice); 10102 defer gpa.free(name); 10103 return astgen.failTokNotes(name_token, "local shadows declaration of '{s}'", .{ 10104 name, 10105 }, &[_]u32{ 10106 try astgen.errNoteNode(decl_node, "declared here", .{}), 10107 }); 10108 }, 10109 .gen_zir => s = s.cast(GenZir).?.parent, 10110 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, 10111 .top => break, 10112 }; 10113 } 10114 10115 fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void { 10116 var i = astgen.source_offset; 10117 var line = astgen.source_line; 10118 var column = astgen.source_column; 10119 while (i < end) : (i += 1) { 10120 if (source[i] == '\n') { 10121 line += 1; 10122 column = 0; 10123 } else { 10124 column += 1; 10125 } 10126 } 10127 astgen.source_offset = i; 10128 astgen.source_line = line; 10129 astgen.source_column = column; 10130 } 10131 10132 const ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len; 10133 10134 fn indexToRef(inst: Zir.Inst.Index) Zir.Inst.Ref { 10135 return @intToEnum(Zir.Inst.Ref, ref_start_index + inst); 10136 } 10137 10138 fn refToIndex(inst: Zir.Inst.Ref) ?Zir.Inst.Index { 10139 const ref_int = @enumToInt(inst); 10140 if (ref_int >= ref_start_index) { 10141 return ref_int - ref_start_index; 10142 } else { 10143 return null; 10144 } 10145 } 10146 10147 fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const ast.Node.Index) !void { 10148 const gpa = astgen.gpa; 10149 const tree = astgen.tree; 10150 const node_tags = tree.nodes.items(.tag); 10151 const main_tokens = tree.nodes.items(.main_token); 10152 for (members) |member_node| { 10153 const name_token = switch (node_tags[member_node]) { 10154 .fn_decl, 10155 .fn_proto_simple, 10156 .fn_proto_multi, 10157 .fn_proto_one, 10158 .fn_proto, 10159 .global_var_decl, 10160 .local_var_decl, 10161 .simple_var_decl, 10162 .aligned_var_decl, 10163 => main_tokens[member_node] + 1, 10164 10165 else => continue, 10166 }; 10167 10168 const token_bytes = astgen.tree.tokenSlice(name_token); 10169 if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { 10170 switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ 10171 token_bytes, 10172 }, &[_]u32{ 10173 try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ 10174 token_bytes, 10175 }), 10176 })) { 10177 error.AnalysisFail => continue, 10178 error.OutOfMemory => return error.OutOfMemory, 10179 } 10180 } 10181 10182 const name_str_index = try astgen.identAsString(name_token); 10183 const gop = try namespace.decls.getOrPut(gpa, name_str_index); 10184 if (gop.found_existing) { 10185 const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index))); 10186 defer gpa.free(name); 10187 switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{ 10188 name, 10189 }, &[_]u32{ 10190 try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}), 10191 })) { 10192 error.AnalysisFail => continue, 10193 error.OutOfMemory => return error.OutOfMemory, 10194 } 10195 } 10196 gop.value_ptr.* = member_node; 10197 } 10198 }