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