authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-16 14:44:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-16 14:48:10-07:00
log01b4bf34ea4f37d8b778bb2413ac1fc445f8bead
tree6075a5f6e35448ab1899b34a559d5c1ce9e27bd2
parentcf57e8223f06f6b305e7274445cf935b1ed312d2

stage2: AstGen improvements

* AstGen: represent compile errors in ZIR rather than returning `error.AnalysisFail`. * ZIR: remove decl_ref and decl_val instructions. These are replaced by `decl_ref_named` and `decl_val_named`, respectively, which will probably get renamed in the future to the instructions that were just deleted. * AstGen: implement `@This()`, `@fence()`, `@returnAddress()`, and `@src()`. * AstGen: struct_decl improved to support fields_len=0 but have decls. * AstGen: fix missing null bytes after compile error messages. * SrcLoc: no longer depend on `Decl`. Instead have an explicit field `parent_decl_node` which is an absolute AST Node index. * Module: `failed_files` table can have null value, in which case the key, which is a `*Scope.File`, will have ZIR errors in it. * ZIR: implement text rendering of struct decls. * CLI: introduce debug_usage and `zig astgen` command which is enabled when the compiler is built in debug mode.

7 files changed, 457 insertions(+), 263 deletions(-)

BRANCH_TODO+11
...@@ -1,3 +1,14 @@...@@ -1,3 +1,14 @@
1 * AstGen decls into blocks so we can evaluate them independently
2 * look for cached zir code
3 * save zir code to cache
4 * store list of imported strings
5 * use list of imported strings to queue up more astgen tasks
6 * keep track of file dependencies/dependants
7 * unload files from memory when a dependency is dropped
8 * implement zir error notes
9
10 * implement the new AstGen compile errors
11
1 * get rid of failed_root_src_file12 * get rid of failed_root_src_file
2 * get rid of Scope.DeclRef13 * get rid of Scope.DeclRef
3 * handle decl collision with usingnamespace14 * handle decl collision with usingnamespace
src/AstGen.zig+36-24
...@@ -96,14 +96,18 @@ pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir {...@@ -96,14 +96,18 @@ pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir {
96 .arg = 0,96 .arg = 0,
97 },97 },
98 };98 };
99 const struct_decl_ref = try AstGen.structDeclInner(99 if (AstGen.structDeclInner(
100 &gen_scope,100 &gen_scope,
101 &gen_scope.base,101 &gen_scope.base,
102 0,102 0,
103 container_decl,103 container_decl,
104 .struct_decl,104 .struct_decl,
105 );105 )) |struct_decl_ref| {
106 astgen.extra.items[0] = @enumToInt(struct_decl_ref);106 astgen.extra.items[0] = @enumToInt(struct_decl_ref);
107 } else |err| switch (err) {
108 error.OutOfMemory => return error.OutOfMemory,
109 error.AnalysisFail => {}, // Handled via compile_errors below.
110 }
107111
108 if (astgen.compile_errors.items.len == 0) {112 if (astgen.compile_errors.items.len == 0) {
109 astgen.extra.items[1] = 0;113 astgen.extra.items[1] = 0;
...@@ -1272,8 +1276,6 @@ fn blockExprStmts(...@@ -1272,8 +1276,6 @@ fn blockExprStmts(
1272 .cmp_gt,1276 .cmp_gt,
1273 .cmp_neq,1277 .cmp_neq,
1274 .coerce_result_ptr,1278 .coerce_result_ptr,
1275 .decl_ref,
1276 .decl_val,
1277 .decl_ref_named,1279 .decl_ref_named,
1278 .decl_val_named,1280 .decl_val_named,
1279 .load,1281 .load,
...@@ -1381,6 +1383,10 @@ fn blockExprStmts(...@@ -1381,6 +1383,10 @@ fn blockExprStmts(
1381 .type_info,1383 .type_info,
1382 .size_of,1384 .size_of,
1383 .bit_size_of,1385 .bit_size_of,
1386 .this,
1387 .fence,
1388 .ret_addr,
1389 .builtin_src,
1384 => break :b false,1390 => break :b false,
13851391
1386 // ZIR instructions that are always either `noreturn` or `void`.1392 // ZIR instructions that are always either `noreturn` or `void`.
...@@ -2385,13 +2391,16 @@ fn structDeclInner(...@@ -2385,13 +2391,16 @@ fn structDeclInner(
23852391
2386 const decl_inst = try gz.addBlock(tag, node);2392 const decl_inst = try gz.addBlock(tag, node);
2387 try gz.instructions.append(gpa, decl_inst);2393 try gz.instructions.append(gpa, decl_inst);
2388 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);2394 if (field_index != 0) {
2395 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
2396 }
23892397
2390 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +2398 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
2391 @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +2399 @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
2392 bit_bag.items.len + 1 + fields_data.items.len +2400 bit_bag.items.len + @boolToInt(field_index != 0) + fields_data.items.len +
2393 block_scope.instructions.items.len +2401 block_scope.instructions.items.len +
2394 wip_decls.bit_bag.items.len + 1 + wip_decls.name_and_value.items.len);2402 wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
2403 wip_decls.name_and_value.items.len);
2395 const zir_datas = astgen.instructions.items(.data);2404 const zir_datas = astgen.instructions.items(.data);
2396 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{2405 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
2397 .body_len = @intCast(u32, block_scope.instructions.items.len),2406 .body_len = @intCast(u32, block_scope.instructions.items.len),
...@@ -2401,11 +2410,15 @@ fn structDeclInner(...@@ -2401,11 +2410,15 @@ fn structDeclInner(
2401 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);2410 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
24022411
2403 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.2412 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
2404 astgen.extra.appendAssumeCapacity(cur_bit_bag);2413 if (field_index != 0) {
2414 astgen.extra.appendAssumeCapacity(cur_bit_bag);
2415 }
2405 astgen.extra.appendSliceAssumeCapacity(fields_data.items);2416 astgen.extra.appendSliceAssumeCapacity(fields_data.items);
24062417
2407 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.2418 astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
2408 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);2419 if (wip_decls.decl_index != 0) {
2420 astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
2421 }
2409 astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items);2422 astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items);
24102423
2411 return gz.indexToRef(decl_inst);2424 return gz.indexToRef(decl_inst);
...@@ -4750,6 +4763,11 @@ fn builtinCall(...@@ -4750,6 +4763,11 @@ fn builtinCall(
4750 return rvalue(gz, scope, rl, result, node);4763 return rvalue(gz, scope, rl, result, node);
4751 },4764 },
47524765
4766 .This => return rvalue(gz, scope, rl, try gz.addNode(.this, node), node),
4767 .fence => return rvalue(gz, scope, rl, try gz.addNode(.fence, node), node),
4768 .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node),
4769 .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node),
4770
4753 .add_with_overflow,4771 .add_with_overflow,
4754 .align_cast,4772 .align_cast,
4755 .align_of,4773 .align_of,
...@@ -4778,7 +4796,6 @@ fn builtinCall(...@@ -4778,7 +4796,6 @@ fn builtinCall(
4778 .error_name,4796 .error_name,
4779 .error_return_trace,4797 .error_return_trace,
4780 .err_set_cast,4798 .err_set_cast,
4781 .fence,
4782 .field_parent_ptr,4799 .field_parent_ptr,
4783 .float_to_int,4800 .float_to_int,
4784 .has_field,4801 .has_field,
...@@ -4794,7 +4811,6 @@ fn builtinCall(...@@ -4794,7 +4811,6 @@ fn builtinCall(
4794 .pop_count,4811 .pop_count,
4795 .ptr_cast,4812 .ptr_cast,
4796 .rem,4813 .rem,
4797 .return_address,
4798 .set_align_stack,4814 .set_align_stack,
4799 .set_cold,4815 .set_cold,
4800 .set_float_mode,4816 .set_float_mode,
...@@ -4805,7 +4821,6 @@ fn builtinCall(...@@ -4805,7 +4821,6 @@ fn builtinCall(
4805 .shuffle,4821 .shuffle,
4806 .splat,4822 .splat,
4807 .reduce,4823 .reduce,
4808 .src,
4809 .sqrt,4824 .sqrt,
4810 .sin,4825 .sin,
4811 .cos,4826 .cos,
...@@ -4821,21 +4836,18 @@ fn builtinCall(...@@ -4821,21 +4836,18 @@ fn builtinCall(
4821 .round,4836 .round,
4822 .sub_with_overflow,4837 .sub_with_overflow,
4823 .tag_name,4838 .tag_name,
4824 .This,
4825 .truncate,4839 .truncate,
4826 .Type,4840 .Type,
4827 .type_name,4841 .type_name,
4828 .union_init,4842 .union_init,
4829 => return astgen.failNode(node, "TODO: implement builtin function {s}", .{
4830 builtin_name,
4831 }),
4832
4833 .async_call,4843 .async_call,
4834 .frame,4844 .frame,
4835 .Frame,4845 .Frame,
4836 .frame_address,4846 .frame_address,
4837 .frame_size,4847 .frame_size,
4838 => return astgen.failNode(node, "async and related features are not yet supported", .{}),4848 => return astgen.failNode(node, "TODO: implement builtin function {s}", .{
4849 builtin_name,
4850 }),
4839 }4851 }
4840}4852}
48414853
...@@ -5376,7 +5388,7 @@ pub fn failNodeNotes(...@@ -5376,7 +5388,7 @@ pub fn failNodeNotes(
5376 {5388 {
5377 var managed = string_bytes.toManaged(astgen.gpa);5389 var managed = string_bytes.toManaged(astgen.gpa);
5378 defer string_bytes.* = managed.toUnmanaged();5390 defer string_bytes.* = managed.toUnmanaged();
5379 try managed.writer().print(format, args);5391 try managed.writer().print(format ++ "\x00", args);
5380 }5392 }
5381 const notes_index: u32 = if (notes.len != 0) blk: {5393 const notes_index: u32 = if (notes.len != 0) blk: {
5382 const notes_start = astgen.extra.items.len;5394 const notes_start = astgen.extra.items.len;
...@@ -5417,7 +5429,7 @@ pub fn failTokNotes(...@@ -5417,7 +5429,7 @@ pub fn failTokNotes(
5417 {5429 {
5418 var managed = string_bytes.toManaged(astgen.gpa);5430 var managed = string_bytes.toManaged(astgen.gpa);
5419 defer string_bytes.* = managed.toUnmanaged();5431 defer string_bytes.* = managed.toUnmanaged();
5420 try managed.writer().print(format, args);5432 try managed.writer().print(format ++ "\x00", args);
5421 }5433 }
5422 const notes_index: u32 = if (notes.len != 0) blk: {5434 const notes_index: u32 = if (notes.len != 0) blk: {
5423 const notes_start = astgen.extra.items.len;5435 const notes_start = astgen.extra.items.len;
...@@ -5451,7 +5463,7 @@ pub fn failOff(...@@ -5451,7 +5463,7 @@ pub fn failOff(
5451 {5463 {
5452 var managed = string_bytes.toManaged(astgen.gpa);5464 var managed = string_bytes.toManaged(astgen.gpa);
5453 defer string_bytes.* = managed.toUnmanaged();5465 defer string_bytes.* = managed.toUnmanaged();
5454 try managed.writer().print(format, args);5466 try managed.writer().print(format ++ "\x00", args);
5455 }5467 }
5456 try astgen.compile_errors.append(astgen.gpa, .{5468 try astgen.compile_errors.append(astgen.gpa, .{
5457 .msg = msg,5469 .msg = msg,
...@@ -5475,7 +5487,7 @@ pub fn errNoteTok(...@@ -5475,7 +5487,7 @@ pub fn errNoteTok(
5475 {5487 {
5476 var managed = string_bytes.toManaged(astgen.gpa);5488 var managed = string_bytes.toManaged(astgen.gpa);
5477 defer string_bytes.* = managed.toUnmanaged();5489 defer string_bytes.* = managed.toUnmanaged();
5478 try managed.writer().print(format, args);5490 try managed.writer().print(format ++ "\x00", args);
5479 }5491 }
5480 return astgen.addExtra(Zir.Inst.CompileErrors.Item{5492 return astgen.addExtra(Zir.Inst.CompileErrors.Item{
5481 .msg = msg,5493 .msg = msg,
...@@ -5498,7 +5510,7 @@ pub fn errNoteNode(...@@ -5498,7 +5510,7 @@ pub fn errNoteNode(
5498 {5510 {
5499 var managed = string_bytes.toManaged(astgen.gpa);5511 var managed = string_bytes.toManaged(astgen.gpa);
5500 defer string_bytes.* = managed.toUnmanaged();5512 defer string_bytes.* = managed.toUnmanaged();
5501 try managed.writer().print(format, args);5513 try managed.writer().print(format ++ "\x00", args);
5502 }5514 }
5503 return astgen.addExtra(Zir.Inst.CompileErrors.Item{5515 return astgen.addExtra(Zir.Inst.CompileErrors.Item{
5504 .msg = msg,5516 .msg = msg,
src/Compilation.zig+63-6
...@@ -391,10 +391,10 @@ pub const AllErrors = struct {...@@ -391,10 +391,10 @@ pub const AllErrors = struct {
391 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);391 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
392 for (notes) |*note, i| {392 for (notes) |*note, i| {
393 const module_note = module_err_msg.notes[i];393 const module_note = module_err_msg.notes[i];
394 const source = try module_note.src_loc.fileScope().getSource(module.gpa);394 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
395 const byte_offset = try module_note.src_loc.byteOffset();395 const byte_offset = try module_note.src_loc.byteOffset();
396 const loc = std.zig.findLineColumn(source, byte_offset);396 const loc = std.zig.findLineColumn(source, byte_offset);
397 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;397 const sub_file_path = module_note.src_loc.file_scope.sub_file_path;
398 note.* = .{398 note.* = .{
399 .src = .{399 .src = .{
400 .src_path = try arena.allocator.dupe(u8, sub_file_path),400 .src_path = try arena.allocator.dupe(u8, sub_file_path),
...@@ -406,10 +406,10 @@ pub const AllErrors = struct {...@@ -406,10 +406,10 @@ pub const AllErrors = struct {
406 },406 },
407 };407 };
408 }408 }
409 const source = try module_err_msg.src_loc.fileScope().getSource(module.gpa);409 const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
410 const byte_offset = try module_err_msg.src_loc.byteOffset();410 const byte_offset = try module_err_msg.src_loc.byteOffset();
411 const loc = std.zig.findLineColumn(source, byte_offset);411 const loc = std.zig.findLineColumn(source, byte_offset);
412 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;412 const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;
413 try errors.append(.{413 try errors.append(.{
414 .src = .{414 .src = .{
415 .src_path = try arena.allocator.dupe(u8, sub_file_path),415 .src_path = try arena.allocator.dupe(u8, sub_file_path),
...@@ -423,6 +423,56 @@ pub const AllErrors = struct {...@@ -423,6 +423,56 @@ pub const AllErrors = struct {
423 });423 });
424 }424 }
425425
426 pub fn addZir(
427 arena: *Allocator,
428 errors: *std.ArrayList(Message),
429 file: *Module.Scope.File,
430 source: []const u8,
431 ) !void {
432 assert(file.zir_loaded);
433 assert(file.tree_loaded);
434 const Zir = @import("Zir.zig");
435 const payload_index = file.zir.extra[Zir.compile_error_extra_index];
436 assert(payload_index != 0);
437
438 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
439 const items_len = header.data.items_len;
440 var extra_index = header.end;
441 var item_i: usize = 0;
442 while (item_i < items_len) : (item_i += 1) {
443 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
444 extra_index = item.end;
445
446 if (item.data.notes != 0) {
447 @panic("TODO implement AllErrors for Zir notes");
448 }
449
450 const msg = file.zir.nullTerminatedString(item.data.msg);
451 const byte_offset = blk: {
452 const token_starts = file.tree.tokens.items(.start);
453 if (item.data.node != 0) {
454 const main_tokens = file.tree.nodes.items(.main_token);
455 const main_token = main_tokens[item.data.node];
456 break :blk token_starts[main_token];
457 }
458 break :blk token_starts[item.data.token] + item.data.byte_offset;
459 };
460 const loc = std.zig.findLineColumn(source, byte_offset);
461
462 try errors.append(.{
463 .src = .{
464 .src_path = try arena.dupe(u8, file.sub_file_path),
465 .msg = try arena.dupe(u8, msg),
466 .byte_offset = byte_offset,
467 .line = @intCast(u32, loc.line),
468 .column = @intCast(u32, loc.column),
469 .notes = &.{}, // TODO
470 .source_line = try arena.dupe(u8, loc.source_line),
471 },
472 });
473 }
474 }
475
426 fn addPlain(476 fn addPlain(
427 arena: *std.heap.ArenaAllocator,477 arena: *std.heap.ArenaAllocator,
428 errors: *std.ArrayList(Message),478 errors: *std.ArrayList(Message),
...@@ -1624,7 +1674,13 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1624,7 +1674,13 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1624 }1674 }
1625 if (self.bin_file.options.module) |module| {1675 if (self.bin_file.options.module) |module| {
1626 for (module.failed_files.items()) |entry| {1676 for (module.failed_files.items()) |entry| {
1627 try AllErrors.add(module, &arena, &errors, entry.value.*);1677 if (entry.value) |msg| {
1678 try AllErrors.add(module, &arena, &errors, msg.*);
1679 } else {
1680 // Must be ZIR errors.
1681 const source = try entry.key.getSource(module.gpa);
1682 try AllErrors.addZir(&arena.allocator, &errors, entry.key, source);
1683 }
1628 }1684 }
1629 for (module.failed_decls.items()) |entry| {1685 for (module.failed_decls.items()) |entry| {
1630 if (entry.key.namespace.file_scope.status == .parse_failure) {1686 if (entry.key.namespace.file_scope.status == .parse_failure) {
...@@ -2276,7 +2332,8 @@ fn reportRetryableAstGenError(...@@ -2276,7 +2332,8 @@ fn reportRetryableAstGenError(
2276 file.status = .retryable_failure;2332 file.status = .retryable_failure;
22772333
2278 const err_msg = try Module.ErrorMsg.create(gpa, .{2334 const err_msg = try Module.ErrorMsg.create(gpa, .{
2279 .container = .{ .file_scope = file },2335 .file_scope = file,
2336 .parent_decl_node = 0,
2280 .lazy = .entire_file,2337 .lazy = .entire_file,
2281 }, "unable to load {s}: {s}", .{2338 }, "unable to load {s}: {s}", .{
2282 file.sub_file_path, @errorName(err),2339 file.sub_file_path, @errorName(err),
src/Module.zig+91-129
...@@ -70,7 +70,7 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},...@@ -70,7 +70,7 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
70compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},70compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},
71/// Using a map here for consistency with the other fields here.71/// Using a map here for consistency with the other fields here.
72/// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator.72/// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator.
73failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{},73failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{},
74/// Using a map here for consistency with the other fields here.74/// Using a map here for consistency with the other fields here.
75/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.75/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
76failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},76failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
...@@ -267,9 +267,10 @@ pub const Decl = struct {...@@ -267,9 +267,10 @@ pub const Decl = struct {
267 return .{ .node_offset = decl.nodeIndexToRelative(node_index) };267 return .{ .node_offset = decl.nodeIndexToRelative(node_index) };
268 }268 }
269269
270 pub fn srcLoc(decl: *Decl) SrcLoc {270 pub fn srcLoc(decl: Decl) SrcLoc {
271 return .{271 return .{
272 .container = .{ .decl = decl },272 .file_scope = decl.getFileScope(),
273 .parent_decl_node = decl.src_node,
273 .lazy = .{ .node_offset = 0 },274 .lazy = .{ .node_offset = 0 },
274 };275 };
275 }276 }
...@@ -367,7 +368,8 @@ pub const ErrorSet = struct {...@@ -367,7 +368,8 @@ pub const ErrorSet = struct {
367368
368 pub fn srcLoc(self: ErrorSet) SrcLoc {369 pub fn srcLoc(self: ErrorSet) SrcLoc {
369 return .{370 return .{
370 .container = .{ .decl = self.owner_decl },371 .file_scope = self.owner_decl.getFileScope(),
372 .parent_decl_node = self.owner_decl.src_node,
371 .lazy = .{ .node_offset = self.node_offset },373 .lazy = .{ .node_offset = self.node_offset },
372 };374 };
373 }375 }
...@@ -397,7 +399,8 @@ pub const Struct = struct {...@@ -397,7 +399,8 @@ pub const Struct = struct {
397399
398 pub fn srcLoc(s: Struct) SrcLoc {400 pub fn srcLoc(s: Struct) SrcLoc {
399 return .{401 return .{
400 .container = .{ .decl = s.owner_decl },402 .file_scope = s.owner_decl.getFileScope(),
403 .parent_decl_node = s.owner_decl.src_node,
401 .lazy = .{ .node_offset = s.node_offset },404 .lazy = .{ .node_offset = s.node_offset },
402 };405 };
403 }406 }
...@@ -416,7 +419,8 @@ pub const EnumSimple = struct {...@@ -416,7 +419,8 @@ pub const EnumSimple = struct {
416419
417 pub fn srcLoc(self: EnumSimple) SrcLoc {420 pub fn srcLoc(self: EnumSimple) SrcLoc {
418 return .{421 return .{
419 .container = .{ .decl = self.owner_decl },422 .file_scope = self.owner_decl.getFileScope(),
423 .parent_decl_node = self.owner_decl.src_node,
420 .lazy = .{ .node_offset = self.node_offset },424 .lazy = .{ .node_offset = self.node_offset },
421 };425 };
422 }426 }
...@@ -444,7 +448,8 @@ pub const EnumFull = struct {...@@ -444,7 +448,8 @@ pub const EnumFull = struct {
444448
445 pub fn srcLoc(self: EnumFull) SrcLoc {449 pub fn srcLoc(self: EnumFull) SrcLoc {
446 return .{450 return .{
447 .container = .{ .decl = self.owner_decl },451 .file_scope = self.owner_decl.getFileScope(),
452 .parent_decl_node = self.owner_decl.src_node,
448 .lazy = .{ .node_offset = self.node_offset },453 .lazy = .{ .node_offset = self.node_offset },
449 };454 };
450 }455 }
...@@ -1710,51 +1715,19 @@ pub const ErrorMsg = struct {...@@ -1710,51 +1715,19 @@ pub const ErrorMsg = struct {
17101715
1711/// Canonical reference to a position within a source file.1716/// Canonical reference to a position within a source file.
1712pub const SrcLoc = struct {1717pub const SrcLoc = struct {
1713 /// The active field is determined by tag of `lazy`.1718 file_scope: *Scope.File,
1714 container: union {1719 /// Might be 0 depending on tag of `lazy`.
1715 /// The containing `Decl` according to the source code.1720 parent_decl_node: ast.Node.Index,
1716 decl: *Decl,1721 /// Relative to `parent_decl_node`.
1717 file_scope: *Scope.File,
1718 },
1719 /// Relative to `decl`.
1720 lazy: LazySrcLoc,1722 lazy: LazySrcLoc,
17211723
1722 pub fn fileScope(src_loc: SrcLoc) *Scope.File {1724 pub fn declSrcToken(src_loc: SrcLoc) ast.TokenIndex {
1723 return switch (src_loc.lazy) {1725 const tree = src_loc.file_scope.tree;
1724 .unneeded => unreachable,1726 return tree.firstToken(src_loc.parent_decl_node);
17251727 }
1726 .byte_abs,
1727 .token_abs,
1728 .node_abs,
1729 .entire_file,
1730 => src_loc.container.file_scope,
17311728
1732 .byte_offset,1729 pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) ast.TokenIndex {
1733 .token_offset,1730 return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node));
1734 .node_offset,
1735 .node_offset_back2tok,
1736 .node_offset_var_decl_ty,
1737 .node_offset_for_cond,
1738 .node_offset_builtin_call_arg0,
1739 .node_offset_builtin_call_arg1,
1740 .node_offset_array_access_index,
1741 .node_offset_slice_sentinel,
1742 .node_offset_call_func,
1743 .node_offset_field_name,
1744 .node_offset_deref_ptr,
1745 .node_offset_asm_source,
1746 .node_offset_asm_ret_ty,
1747 .node_offset_if_cond,
1748 .node_offset_bin_op,
1749 .node_offset_bin_lhs,
1750 .node_offset_bin_rhs,
1751 .node_offset_switch_operand,
1752 .node_offset_switch_special_prong,
1753 .node_offset_switch_range,
1754 .node_offset_fn_type_cc,
1755 .node_offset_fn_type_ret_ty,
1756 => src_loc.container.decl.namespace.file_scope,
1757 };
1758 }1731 }
17591732
1760 pub fn byteOffset(src_loc: SrcLoc) !u32 {1733 pub fn byteOffset(src_loc: SrcLoc) !u32 {
...@@ -1765,48 +1738,45 @@ pub const SrcLoc = struct {...@@ -1765,48 +1738,45 @@ pub const SrcLoc = struct {
1765 .byte_abs => |byte_index| return byte_index,1738 .byte_abs => |byte_index| return byte_index,
17661739
1767 .token_abs => |tok_index| {1740 .token_abs => |tok_index| {
1768 const tree = src_loc.container.file_scope.tree;1741 const tree = src_loc.file_scope.tree;
1769 const token_starts = tree.tokens.items(.start);1742 const token_starts = tree.tokens.items(.start);
1770 return token_starts[tok_index];1743 return token_starts[tok_index];
1771 },1744 },
1772 .node_abs => |node| {1745 .node_abs => |node| {
1773 const tree = src_loc.container.file_scope.tree;1746 const tree = src_loc.file_scope.tree;
1774 const token_starts = tree.tokens.items(.start);1747 const token_starts = tree.tokens.items(.start);
1775 const tok_index = tree.firstToken(node);1748 const tok_index = tree.firstToken(node);
1776 return token_starts[tok_index];1749 return token_starts[tok_index];
1777 },1750 },
1778 .byte_offset => |byte_off| {1751 .byte_offset => |byte_off| {
1779 const decl = src_loc.container.decl;1752 const tree = src_loc.file_scope.tree;
1780 return decl.srcByteOffset() + byte_off;1753 const token_starts = tree.tokens.items(.start);
1754 return token_starts[src_loc.declSrcToken()] + byte_off;
1781 },1755 },
1782 .token_offset => |tok_off| {1756 .token_offset => |tok_off| {
1783 const decl = src_loc.container.decl;1757 const tok_index = src_loc.declSrcToken() + tok_off;
1784 const tok_index = decl.srcToken() + tok_off;1758 const tree = src_loc.file_scope.tree;
1785 const tree = decl.namespace.file_scope.tree;
1786 const token_starts = tree.tokens.items(.start);1759 const token_starts = tree.tokens.items(.start);
1787 return token_starts[tok_index];1760 return token_starts[tok_index];
1788 },1761 },
1789 .node_offset, .node_offset_bin_op => |node_off| {1762 .node_offset, .node_offset_bin_op => |node_off| {
1790 const decl = src_loc.container.decl;1763 const node = src_loc.declRelativeToNodeIndex(node_off);
1791 const node = decl.relativeToNodeIndex(node_off);1764 const tree = src_loc.file_scope.tree;
1792 const tree = decl.namespace.file_scope.tree;
1793 const main_tokens = tree.nodes.items(.main_token);1765 const main_tokens = tree.nodes.items(.main_token);
1794 const tok_index = main_tokens[node];1766 const tok_index = main_tokens[node];
1795 const token_starts = tree.tokens.items(.start);1767 const token_starts = tree.tokens.items(.start);
1796 return token_starts[tok_index];1768 return token_starts[tok_index];
1797 },1769 },
1798 .node_offset_back2tok => |node_off| {1770 .node_offset_back2tok => |node_off| {
1799 const decl = src_loc.container.decl;1771 const node = src_loc.declRelativeToNodeIndex(node_off);
1800 const node = decl.relativeToNodeIndex(node_off);1772 const tree = src_loc.file_scope.tree;
1801 const tree = decl.namespace.file_scope.tree;
1802 const tok_index = tree.firstToken(node) - 2;1773 const tok_index = tree.firstToken(node) - 2;
1803 const token_starts = tree.tokens.items(.start);1774 const token_starts = tree.tokens.items(.start);
1804 return token_starts[tok_index];1775 return token_starts[tok_index];
1805 },1776 },
1806 .node_offset_var_decl_ty => |node_off| {1777 .node_offset_var_decl_ty => |node_off| {
1807 const decl = src_loc.container.decl;1778 const node = src_loc.declRelativeToNodeIndex(node_off);
1808 const node = decl.relativeToNodeIndex(node_off);1779 const tree = src_loc.file_scope.tree;
1809 const tree = decl.namespace.file_scope.tree;
1810 const node_tags = tree.nodes.items(.tag);1780 const node_tags = tree.nodes.items(.tag);
1811 const full = switch (node_tags[node]) {1781 const full = switch (node_tags[node]) {
1812 .global_var_decl => tree.globalVarDecl(node),1782 .global_var_decl => tree.globalVarDecl(node),
...@@ -1825,11 +1795,10 @@ pub const SrcLoc = struct {...@@ -1825,11 +1795,10 @@ pub const SrcLoc = struct {
1825 return token_starts[tok_index];1795 return token_starts[tok_index];
1826 },1796 },
1827 .node_offset_builtin_call_arg0 => |node_off| {1797 .node_offset_builtin_call_arg0 => |node_off| {
1828 const decl = src_loc.container.decl;1798 const tree = src_loc.file_scope.tree;
1829 const tree = decl.namespace.file_scope.tree;
1830 const node_datas = tree.nodes.items(.data);1799 const node_datas = tree.nodes.items(.data);
1831 const node_tags = tree.nodes.items(.tag);1800 const node_tags = tree.nodes.items(.tag);
1832 const node = decl.relativeToNodeIndex(node_off);1801 const node = src_loc.declRelativeToNodeIndex(node_off);
1833 const param = switch (node_tags[node]) {1802 const param = switch (node_tags[node]) {
1834 .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs,1803 .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs,
1835 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs],1804 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs],
...@@ -1841,11 +1810,10 @@ pub const SrcLoc = struct {...@@ -1841,11 +1810,10 @@ pub const SrcLoc = struct {
1841 return token_starts[tok_index];1810 return token_starts[tok_index];
1842 },1811 },
1843 .node_offset_builtin_call_arg1 => |node_off| {1812 .node_offset_builtin_call_arg1 => |node_off| {
1844 const decl = src_loc.container.decl;1813 const tree = src_loc.file_scope.tree;
1845 const tree = decl.namespace.file_scope.tree;
1846 const node_datas = tree.nodes.items(.data);1814 const node_datas = tree.nodes.items(.data);
1847 const node_tags = tree.nodes.items(.tag);1815 const node_tags = tree.nodes.items(.tag);
1848 const node = decl.relativeToNodeIndex(node_off);1816 const node = src_loc.declRelativeToNodeIndex(node_off);
1849 const param = switch (node_tags[node]) {1817 const param = switch (node_tags[node]) {
1850 .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs,1818 .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs,
1851 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1],1819 .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1],
...@@ -1857,22 +1825,20 @@ pub const SrcLoc = struct {...@@ -1857,22 +1825,20 @@ pub const SrcLoc = struct {
1857 return token_starts[tok_index];1825 return token_starts[tok_index];
1858 },1826 },
1859 .node_offset_array_access_index => |node_off| {1827 .node_offset_array_access_index => |node_off| {
1860 const decl = src_loc.container.decl;1828 const tree = src_loc.file_scope.tree;
1861 const tree = decl.namespace.file_scope.tree;
1862 const node_datas = tree.nodes.items(.data);1829 const node_datas = tree.nodes.items(.data);
1863 const node_tags = tree.nodes.items(.tag);1830 const node_tags = tree.nodes.items(.tag);
1864 const node = decl.relativeToNodeIndex(node_off);1831 const node = src_loc.declRelativeToNodeIndex(node_off);
1865 const main_tokens = tree.nodes.items(.main_token);1832 const main_tokens = tree.nodes.items(.main_token);
1866 const tok_index = main_tokens[node_datas[node].rhs];1833 const tok_index = main_tokens[node_datas[node].rhs];
1867 const token_starts = tree.tokens.items(.start);1834 const token_starts = tree.tokens.items(.start);
1868 return token_starts[tok_index];1835 return token_starts[tok_index];
1869 },1836 },
1870 .node_offset_slice_sentinel => |node_off| {1837 .node_offset_slice_sentinel => |node_off| {
1871 const decl = src_loc.container.decl;1838 const tree = src_loc.file_scope.tree;
1872 const tree = decl.namespace.file_scope.tree;
1873 const node_datas = tree.nodes.items(.data);1839 const node_datas = tree.nodes.items(.data);
1874 const node_tags = tree.nodes.items(.tag);1840 const node_tags = tree.nodes.items(.tag);
1875 const node = decl.relativeToNodeIndex(node_off);1841 const node = src_loc.declRelativeToNodeIndex(node_off);
1876 const full = switch (node_tags[node]) {1842 const full = switch (node_tags[node]) {
1877 .slice_open => tree.sliceOpen(node),1843 .slice_open => tree.sliceOpen(node),
1878 .slice => tree.slice(node),1844 .slice => tree.slice(node),
...@@ -1885,11 +1851,10 @@ pub const SrcLoc = struct {...@@ -1885,11 +1851,10 @@ pub const SrcLoc = struct {
1885 return token_starts[tok_index];1851 return token_starts[tok_index];
1886 },1852 },
1887 .node_offset_call_func => |node_off| {1853 .node_offset_call_func => |node_off| {
1888 const decl = src_loc.container.decl;1854 const tree = src_loc.file_scope.tree;
1889 const tree = decl.namespace.file_scope.tree;
1890 const node_datas = tree.nodes.items(.data);1855 const node_datas = tree.nodes.items(.data);
1891 const node_tags = tree.nodes.items(.tag);1856 const node_tags = tree.nodes.items(.tag);
1892 const node = decl.relativeToNodeIndex(node_off);1857 const node = src_loc.declRelativeToNodeIndex(node_off);
1893 var params: [1]ast.Node.Index = undefined;1858 var params: [1]ast.Node.Index = undefined;
1894 const full = switch (node_tags[node]) {1859 const full = switch (node_tags[node]) {
1895 .call_one,1860 .call_one,
...@@ -1912,11 +1877,10 @@ pub const SrcLoc = struct {...@@ -1912,11 +1877,10 @@ pub const SrcLoc = struct {
1912 return token_starts[tok_index];1877 return token_starts[tok_index];
1913 },1878 },
1914 .node_offset_field_name => |node_off| {1879 .node_offset_field_name => |node_off| {
1915 const decl = src_loc.container.decl;1880 const tree = src_loc.file_scope.tree;
1916 const tree = decl.namespace.file_scope.tree;
1917 const node_datas = tree.nodes.items(.data);1881 const node_datas = tree.nodes.items(.data);
1918 const node_tags = tree.nodes.items(.tag);1882 const node_tags = tree.nodes.items(.tag);
1919 const node = decl.relativeToNodeIndex(node_off);1883 const node = src_loc.declRelativeToNodeIndex(node_off);
1920 const tok_index = switch (node_tags[node]) {1884 const tok_index = switch (node_tags[node]) {
1921 .field_access => node_datas[node].rhs,1885 .field_access => node_datas[node].rhs,
1922 else => tree.firstToken(node) - 2,1886 else => tree.firstToken(node) - 2,
...@@ -1925,21 +1889,19 @@ pub const SrcLoc = struct {...@@ -1925,21 +1889,19 @@ pub const SrcLoc = struct {
1925 return token_starts[tok_index];1889 return token_starts[tok_index];
1926 },1890 },
1927 .node_offset_deref_ptr => |node_off| {1891 .node_offset_deref_ptr => |node_off| {
1928 const decl = src_loc.container.decl;1892 const tree = src_loc.file_scope.tree;
1929 const tree = decl.namespace.file_scope.tree;
1930 const node_datas = tree.nodes.items(.data);1893 const node_datas = tree.nodes.items(.data);
1931 const node_tags = tree.nodes.items(.tag);1894 const node_tags = tree.nodes.items(.tag);
1932 const node = decl.relativeToNodeIndex(node_off);1895 const node = src_loc.declRelativeToNodeIndex(node_off);
1933 const tok_index = node_datas[node].lhs;1896 const tok_index = node_datas[node].lhs;
1934 const token_starts = tree.tokens.items(.start);1897 const token_starts = tree.tokens.items(.start);
1935 return token_starts[tok_index];1898 return token_starts[tok_index];
1936 },1899 },
1937 .node_offset_asm_source => |node_off| {1900 .node_offset_asm_source => |node_off| {
1938 const decl = src_loc.container.decl;1901 const tree = src_loc.file_scope.tree;
1939 const tree = decl.namespace.file_scope.tree;
1940 const node_datas = tree.nodes.items(.data);1902 const node_datas = tree.nodes.items(.data);
1941 const node_tags = tree.nodes.items(.tag);1903 const node_tags = tree.nodes.items(.tag);
1942 const node = decl.relativeToNodeIndex(node_off);1904 const node = src_loc.declRelativeToNodeIndex(node_off);
1943 const full = switch (node_tags[node]) {1905 const full = switch (node_tags[node]) {
1944 .asm_simple => tree.asmSimple(node),1906 .asm_simple => tree.asmSimple(node),
1945 .@"asm" => tree.asmFull(node),1907 .@"asm" => tree.asmFull(node),
...@@ -1951,11 +1913,10 @@ pub const SrcLoc = struct {...@@ -1951,11 +1913,10 @@ pub const SrcLoc = struct {
1951 return token_starts[tok_index];1913 return token_starts[tok_index];
1952 },1914 },
1953 .node_offset_asm_ret_ty => |node_off| {1915 .node_offset_asm_ret_ty => |node_off| {
1954 const decl = src_loc.container.decl;1916 const tree = src_loc.file_scope.tree;
1955 const tree = decl.namespace.file_scope.tree;
1956 const node_datas = tree.nodes.items(.data);1917 const node_datas = tree.nodes.items(.data);
1957 const node_tags = tree.nodes.items(.tag);1918 const node_tags = tree.nodes.items(.tag);
1958 const node = decl.relativeToNodeIndex(node_off);1919 const node = src_loc.declRelativeToNodeIndex(node_off);
1959 const full = switch (node_tags[node]) {1920 const full = switch (node_tags[node]) {
1960 .asm_simple => tree.asmSimple(node),1921 .asm_simple => tree.asmSimple(node),
1961 .@"asm" => tree.asmFull(node),1922 .@"asm" => tree.asmFull(node),
...@@ -1968,9 +1929,8 @@ pub const SrcLoc = struct {...@@ -1968,9 +1929,8 @@ pub const SrcLoc = struct {
1968 },1929 },
19691930
1970 .node_offset_for_cond, .node_offset_if_cond => |node_off| {1931 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
1971 const decl = src_loc.container.decl;1932 const node = src_loc.declRelativeToNodeIndex(node_off);
1972 const node = decl.relativeToNodeIndex(node_off);1933 const tree = src_loc.file_scope.tree;
1973 const tree = decl.namespace.file_scope.tree;
1974 const node_tags = tree.nodes.items(.tag);1934 const node_tags = tree.nodes.items(.tag);
1975 const src_node = switch (node_tags[node]) {1935 const src_node = switch (node_tags[node]) {
1976 .if_simple => tree.ifSimple(node).ast.cond_expr,1936 .if_simple => tree.ifSimple(node).ast.cond_expr,
...@@ -1988,9 +1948,8 @@ pub const SrcLoc = struct {...@@ -1988,9 +1948,8 @@ pub const SrcLoc = struct {
1988 return token_starts[tok_index];1948 return token_starts[tok_index];
1989 },1949 },
1990 .node_offset_bin_lhs => |node_off| {1950 .node_offset_bin_lhs => |node_off| {
1991 const decl = src_loc.container.decl;1951 const node = src_loc.declRelativeToNodeIndex(node_off);
1992 const node = decl.relativeToNodeIndex(node_off);1952 const tree = src_loc.file_scope.tree;
1993 const tree = decl.namespace.file_scope.tree;
1994 const node_datas = tree.nodes.items(.data);1953 const node_datas = tree.nodes.items(.data);
1995 const src_node = node_datas[node].lhs;1954 const src_node = node_datas[node].lhs;
1996 const main_tokens = tree.nodes.items(.main_token);1955 const main_tokens = tree.nodes.items(.main_token);
...@@ -1999,9 +1958,8 @@ pub const SrcLoc = struct {...@@ -1999,9 +1958,8 @@ pub const SrcLoc = struct {
1999 return token_starts[tok_index];1958 return token_starts[tok_index];
2000 },1959 },
2001 .node_offset_bin_rhs => |node_off| {1960 .node_offset_bin_rhs => |node_off| {
2002 const decl = src_loc.container.decl;1961 const node = src_loc.declRelativeToNodeIndex(node_off);
2003 const node = decl.relativeToNodeIndex(node_off);1962 const tree = src_loc.file_scope.tree;
2004 const tree = decl.namespace.file_scope.tree;
2005 const node_datas = tree.nodes.items(.data);1963 const node_datas = tree.nodes.items(.data);
2006 const src_node = node_datas[node].rhs;1964 const src_node = node_datas[node].rhs;
2007 const main_tokens = tree.nodes.items(.main_token);1965 const main_tokens = tree.nodes.items(.main_token);
...@@ -2011,9 +1969,8 @@ pub const SrcLoc = struct {...@@ -2011,9 +1969,8 @@ pub const SrcLoc = struct {
2011 },1969 },
20121970
2013 .node_offset_switch_operand => |node_off| {1971 .node_offset_switch_operand => |node_off| {
2014 const decl = src_loc.container.decl;1972 const node = src_loc.declRelativeToNodeIndex(node_off);
2015 const node = decl.relativeToNodeIndex(node_off);1973 const tree = src_loc.file_scope.tree;
2016 const tree = decl.namespace.file_scope.tree;
2017 const node_datas = tree.nodes.items(.data);1974 const node_datas = tree.nodes.items(.data);
2018 const src_node = node_datas[node].lhs;1975 const src_node = node_datas[node].lhs;
2019 const main_tokens = tree.nodes.items(.main_token);1976 const main_tokens = tree.nodes.items(.main_token);
...@@ -2023,9 +1980,8 @@ pub const SrcLoc = struct {...@@ -2023,9 +1980,8 @@ pub const SrcLoc = struct {
2023 },1980 },
20241981
2025 .node_offset_switch_special_prong => |node_off| {1982 .node_offset_switch_special_prong => |node_off| {
2026 const decl = src_loc.container.decl;1983 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
2027 const switch_node = decl.relativeToNodeIndex(node_off);1984 const tree = src_loc.file_scope.tree;
2028 const tree = decl.namespace.file_scope.tree;
2029 const node_datas = tree.nodes.items(.data);1985 const node_datas = tree.nodes.items(.data);
2030 const node_tags = tree.nodes.items(.tag);1986 const node_tags = tree.nodes.items(.tag);
2031 const main_tokens = tree.nodes.items(.main_token);1987 const main_tokens = tree.nodes.items(.main_token);
...@@ -2050,9 +2006,8 @@ pub const SrcLoc = struct {...@@ -2050,9 +2006,8 @@ pub const SrcLoc = struct {
2050 },2006 },
20512007
2052 .node_offset_switch_range => |node_off| {2008 .node_offset_switch_range => |node_off| {
2053 const decl = src_loc.container.decl;2009 const switch_node = src_loc.declRelativeToNodeIndex(node_off);
2054 const switch_node = decl.relativeToNodeIndex(node_off);2010 const tree = src_loc.file_scope.tree;
2055 const tree = decl.namespace.file_scope.tree;
2056 const node_datas = tree.nodes.items(.data);2011 const node_datas = tree.nodes.items(.data);
2057 const node_tags = tree.nodes.items(.tag);2012 const node_tags = tree.nodes.items(.tag);
2058 const main_tokens = tree.nodes.items(.main_token);2013 const main_tokens = tree.nodes.items(.main_token);
...@@ -2081,11 +2036,10 @@ pub const SrcLoc = struct {...@@ -2081,11 +2036,10 @@ pub const SrcLoc = struct {
2081 },2036 },
20822037
2083 .node_offset_fn_type_cc => |node_off| {2038 .node_offset_fn_type_cc => |node_off| {
2084 const decl = src_loc.container.decl;2039 const tree = src_loc.file_scope.tree;
2085 const tree = decl.namespace.file_scope.tree;
2086 const node_datas = tree.nodes.items(.data);2040 const node_datas = tree.nodes.items(.data);
2087 const node_tags = tree.nodes.items(.tag);2041 const node_tags = tree.nodes.items(.tag);
2088 const node = decl.relativeToNodeIndex(node_off);2042 const node = src_loc.declRelativeToNodeIndex(node_off);
2089 var params: [1]ast.Node.Index = undefined;2043 var params: [1]ast.Node.Index = undefined;
2090 const full = switch (node_tags[node]) {2044 const full = switch (node_tags[node]) {
2091 .fn_proto_simple => tree.fnProtoSimple(&params, node),2045 .fn_proto_simple => tree.fnProtoSimple(&params, node),
...@@ -2101,11 +2055,10 @@ pub const SrcLoc = struct {...@@ -2101,11 +2055,10 @@ pub const SrcLoc = struct {
2101 },2055 },
21022056
2103 .node_offset_fn_type_ret_ty => |node_off| {2057 .node_offset_fn_type_ret_ty => |node_off| {
2104 const decl = src_loc.container.decl;2058 const tree = src_loc.file_scope.tree;
2105 const tree = decl.namespace.file_scope.tree;
2106 const node_datas = tree.nodes.items(.data);2059 const node_datas = tree.nodes.items(.data);
2107 const node_tags = tree.nodes.items(.tag);2060 const node_tags = tree.nodes.items(.tag);
2108 const node = decl.relativeToNodeIndex(node_off);2061 const node = src_loc.declRelativeToNodeIndex(node_off);
2109 var params: [1]ast.Node.Index = undefined;2062 var params: [1]ast.Node.Index = undefined;
2110 const full = switch (node_tags[node]) {2063 const full = switch (node_tags[node]) {
2111 .fn_proto_simple => tree.fnProtoSimple(&params, node),2064 .fn_proto_simple => tree.fnProtoSimple(&params, node),
...@@ -2288,7 +2241,8 @@ pub const LazySrcLoc = union(enum) {...@@ -2288,7 +2241,8 @@ pub const LazySrcLoc = union(enum) {
2288 .token_abs,2241 .token_abs,
2289 .node_abs,2242 .node_abs,
2290 => .{2243 => .{
2291 .container = .{ .file_scope = scope.getFileScope() },2244 .file_scope = scope.getFileScope(),
2245 .parent_decl_node = 0,
2292 .lazy = lazy,2246 .lazy = lazy,
2293 },2247 },
22942248
...@@ -2317,7 +2271,8 @@ pub const LazySrcLoc = union(enum) {...@@ -2317,7 +2271,8 @@ pub const LazySrcLoc = union(enum) {
2317 .node_offset_fn_type_cc,2271 .node_offset_fn_type_cc,
2318 .node_offset_fn_type_ret_ty,2272 .node_offset_fn_type_ret_ty,
2319 => .{2273 => .{
2320 .container = .{ .decl = scope.srcDecl().? },2274 .file_scope = scope.getFileScope(),
2275 .parent_decl_node = scope.srcDecl().?.src_node,
2321 .lazy = lazy,2276 .lazy = lazy,
2322 },2277 },
2323 };2278 };
...@@ -2332,7 +2287,8 @@ pub const LazySrcLoc = union(enum) {...@@ -2332,7 +2287,8 @@ pub const LazySrcLoc = union(enum) {
2332 .token_abs,2287 .token_abs,
2333 .node_abs,2288 .node_abs,
2334 => .{2289 => .{
2335 .container = .{ .file_scope = decl.getFileScope() },2290 .file_scope = decl.getFileScope(),
2291 .parent_decl_node = 0,
2336 .lazy = lazy,2292 .lazy = lazy,
2337 },2293 },
23382294
...@@ -2361,7 +2317,8 @@ pub const LazySrcLoc = union(enum) {...@@ -2361,7 +2317,8 @@ pub const LazySrcLoc = union(enum) {
2361 .node_offset_fn_type_cc,2317 .node_offset_fn_type_cc,
2362 .node_offset_fn_type_ret_ty,2318 .node_offset_fn_type_ret_ty,
2363 => .{2319 => .{
2364 .container = .{ .decl = decl },2320 .file_scope = decl.getFileScope(),
2321 .parent_decl_node = decl.src_node,
2365 .lazy = lazy,2322 .lazy = lazy,
2366 },2323 },
2367 };2324 };
...@@ -2409,7 +2366,7 @@ pub fn deinit(mod: *Module) void {...@@ -2409,7 +2366,7 @@ pub fn deinit(mod: *Module) void {
2409 mod.emit_h_failed_decls.deinit(gpa);2366 mod.emit_h_failed_decls.deinit(gpa);
24102367
2411 for (mod.failed_files.items()) |entry| {2368 for (mod.failed_files.items()) |entry| {
2412 entry.value.destroy(gpa);2369 if (entry.value) |msg| msg.destroy(gpa);
2413 }2370 }
2414 mod.failed_files.deinit(gpa);2371 mod.failed_files.deinit(gpa);
24152372
...@@ -2495,7 +2452,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2495,7 +2452,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2495 const lock = comp.mutex.acquire();2452 const lock = comp.mutex.acquire();
2496 defer lock.release();2453 defer lock.release();
2497 if (mod.failed_files.swapRemove(file)) |entry| {2454 if (mod.failed_files.swapRemove(file)) |entry| {
2498 entry.value.destroy(gpa); // Delete previous error message.2455 if (entry.value) |msg| msg.destroy(gpa); // Delete previous error message.
2499 }2456 }
2500 },2457 },
2501 }2458 }
...@@ -2531,7 +2488,8 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2531,7 +2488,8 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2531 const err_msg = try gpa.create(ErrorMsg);2488 const err_msg = try gpa.create(ErrorMsg);
2532 err_msg.* = .{2489 err_msg.* = .{
2533 .src_loc = .{2490 .src_loc = .{
2534 .container = .{ .file_scope = file },2491 .file_scope = file,
2492 .parent_decl_node = 0,
2535 .lazy = .{ .byte_abs = token_starts[parse_err.token] },2493 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
2536 },2494 },
2537 .msg = msg.toOwnedSlice(),2495 .msg = msg.toOwnedSlice(),
...@@ -2550,11 +2508,11 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2550,11 +2508,11 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2550 file.zir = try AstGen.generate(gpa, file);2508 file.zir = try AstGen.generate(gpa, file);
2551 file.zir_loaded = true;2509 file.zir_loaded = true;
25522510
2553 if (file.zir.extra[1] != 0) {2511 if (file.zir.hasCompileErrors()) {
2554 {2512 {
2555 const lock = comp.mutex.acquire();2513 const lock = comp.mutex.acquire();
2556 defer lock.release();2514 defer lock.release();
2557 try mod.failed_files.putNoClobber(gpa, file, undefined);2515 try mod.failed_files.putNoClobber(gpa, file, null);
2558 }2516 }
2559 file.status = .astgen_failure;2517 file.status = .astgen_failure;
2560 return error.AnalysisFail;2518 return error.AnalysisFail;
...@@ -2972,12 +2930,14 @@ fn semaContainerFn(...@@ -2972,12 +2930,14 @@ fn semaContainerFn(
2972 if (deleted_decls.swapRemove(decl) == null) {2930 if (deleted_decls.swapRemove(decl) == null) {
2973 decl.analysis = .sema_failure;2931 decl.analysis = .sema_failure;
2974 const msg = try ErrorMsg.create(mod.gpa, .{2932 const msg = try ErrorMsg.create(mod.gpa, .{
2975 .container = .{ .file_scope = namespace.file_scope },2933 .file_scope = namespace.file_scope,
2934 .parent_decl_node = 0,
2976 .lazy = .{ .token_abs = name_token },2935 .lazy = .{ .token_abs = name_token },
2977 }, "redeclaration of '{s}'", .{decl.name});2936 }, "redeclaration of '{s}'", .{decl.name});
2978 errdefer msg.destroy(mod.gpa);2937 errdefer msg.destroy(mod.gpa);
2979 const other_src_loc: SrcLoc = .{2938 const other_src_loc: SrcLoc = .{
2980 .container = .{ .file_scope = decl.namespace.file_scope },2939 .file_scope = namespace.file_scope,
2940 .parent_decl_node = 0,
2981 .lazy = .{ .node_abs = prev_src_node },2941 .lazy = .{ .node_abs = prev_src_node },
2982 };2942 };
2983 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});2943 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
...@@ -3040,12 +3000,14 @@ fn semaContainerVar(...@@ -3040,12 +3000,14 @@ fn semaContainerVar(
3040 if (deleted_decls.swapRemove(decl) == null) {3000 if (deleted_decls.swapRemove(decl) == null) {
3041 decl.analysis = .sema_failure;3001 decl.analysis = .sema_failure;
3042 const msg = try ErrorMsg.create(mod.gpa, .{3002 const msg = try ErrorMsg.create(mod.gpa, .{
3043 .container = .{ .file_scope = namespace.file_scope },3003 .file_scope = namespace.file_scope,
3004 .parent_decl_node = 0,
3044 .lazy = .{ .token_abs = name_token },3005 .lazy = .{ .token_abs = name_token },
3045 }, "redeclaration of '{s}'", .{decl.name});3006 }, "redeclaration of '{s}'", .{decl.name});
3046 errdefer msg.destroy(mod.gpa);3007 errdefer msg.destroy(mod.gpa);
3047 const other_src_loc: SrcLoc = .{3008 const other_src_loc: SrcLoc = .{
3048 .container = .{ .file_scope = decl.namespace.file_scope },3009 .file_scope = decl.namespace.file_scope,
3010 .parent_decl_node = 0,
3049 .lazy = .{ .node_abs = prev_src_node },3011 .lazy = .{ .node_abs = prev_src_node },
3050 };3012 };
3051 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});3013 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
src/Sema.zig+25-16
...@@ -170,9 +170,7 @@ pub fn analyzeBody(...@@ -170,9 +170,7 @@ pub fn analyzeBody(
170 .cmp_lte => try sema.zirCmp(block, inst, .lte),170 .cmp_lte => try sema.zirCmp(block, inst, .lte),
171 .cmp_neq => try sema.zirCmp(block, inst, .neq),171 .cmp_neq => try sema.zirCmp(block, inst, .neq),
172 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),172 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
173 .decl_ref => try sema.zirDeclRef(block, inst),
174 .decl_ref_named => try sema.zirDeclRefNamed(block, inst),173 .decl_ref_named => try sema.zirDeclRefNamed(block, inst),
175 .decl_val => try sema.zirDeclVal(block, inst),
176 .decl_val_named => try sema.zirDeclValNamed(block, inst),174 .decl_val_named => try sema.zirDeclValNamed(block, inst),
177 .load => try sema.zirLoad(block, inst),175 .load => try sema.zirLoad(block, inst),
178 .div => try sema.zirArithmetic(block, inst),176 .div => try sema.zirArithmetic(block, inst),
...@@ -266,6 +264,10 @@ pub fn analyzeBody(...@@ -266,6 +264,10 @@ pub fn analyzeBody(
266 .type_info => try sema.zirTypeInfo(block, inst),264 .type_info => try sema.zirTypeInfo(block, inst),
267 .size_of => try sema.zirSizeOf(block, inst),265 .size_of => try sema.zirSizeOf(block, inst),
268 .bit_size_of => try sema.zirBitSizeOf(block, inst),266 .bit_size_of => try sema.zirBitSizeOf(block, inst),
267 .this => try sema.zirThis(block, inst),
268 .fence => try sema.zirFence(block, inst),
269 .ret_addr => try sema.zirRetAddr(block, inst),
270 .builtin_src => try sema.zirBuiltinSrc(block, inst),
269 .typeof => try sema.zirTypeof(block, inst),271 .typeof => try sema.zirTypeof(block, inst),
270 .typeof_elem => try sema.zirTypeofElem(block, inst),272 .typeof_elem => try sema.zirTypeofElem(block, inst),
271 .typeof_peer => try sema.zirTypeofPeer(block, inst),273 .typeof_peer => try sema.zirTypeofPeer(block, inst),
...@@ -1656,20 +1658,6 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE...@@ -1656,20 +1658,6 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
1656 _ = try block.addDbgStmt(src, abs_byte_off);1658 _ = try block.addDbgStmt(src, abs_byte_off);
1657}1659}
16581660
1659fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1660 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1661 const src = inst_data.src();
1662 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
1663 return sema.analyzeDeclRef(block, src, decl);
1664}
1665
1666fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1667 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1668 const src = inst_data.src();
1669 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
1670 return sema.analyzeDeclVal(block, src, decl);
1671}
1672
1673fn zirDeclRefNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {1661fn zirDeclRefNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1674 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;1662 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
1675 const src = inst_data.src();1663 const src = inst_data.src();
...@@ -4373,6 +4361,27 @@ fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr...@@ -4373,6 +4361,27 @@ fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr
4373 return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size);4361 return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size);
4374}4362}
43754363
4364fn zirThis(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4365 const src_node = sema.code.instructions.items(.data)[inst].node;
4366 const src: LazySrcLoc = .{ .node_offset = src_node };
4367 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{});
4368}
4369fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4370 const src_node = sema.code.instructions.items(.data)[inst].node;
4371 const src: LazySrcLoc = .{ .node_offset = src_node };
4372 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{});
4373}
4374fn zirRetAddr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4375 const src_node = sema.code.instructions.items(.data)[inst].node;
4376 const src: LazySrcLoc = .{ .node_offset = src_node };
4377 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirRetAddr", .{});
4378}
4379fn zirBuiltinSrc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4380 const src_node = sema.code.instructions.items(.data)[inst].node;
4381 const src: LazySrcLoc = .{ .node_offset = src_node };
4382 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirBuiltinSrc", .{});
4383}
4384
4376fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {4385fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4377 const inst_data = sema.code.instructions.items(.data)[inst].un_node;4386 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4378 const src = inst_data.src();4387 const src = inst_data.src();
src/Zir.zig+138-82
...@@ -42,6 +42,9 @@ string_bytes: []u8,...@@ -42,6 +42,9 @@ string_bytes: []u8,
42/// payload at this index.42/// payload at this index.
43extra: []u32,43extra: []u32,
4444
45pub const main_struct_extra_index = 0;
46pub const compile_error_extra_index = 1;
47
45/// Returns the requested data, as well as the new index which is at the start of the48/// Returns the requested data, as well as the new index which is at the start of the
46/// trailers for the object.49/// trailers for the object.
47pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } {50pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } {
...@@ -76,6 +79,10 @@ pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref {...@@ -76,6 +79,10 @@ pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref {
76 return @bitCast([]Inst.Ref, raw_slice);79 return @bitCast([]Inst.Ref, raw_slice);
77}80}
7881
82pub fn hasCompileErrors(code: Zir) bool {
83 return code.extra[compile_error_extra_index] != 0;
84}
85
79pub fn deinit(code: *Zir, gpa: *Allocator) void {86pub fn deinit(code: *Zir, gpa: *Allocator) void {
80 code.instructions.deinit(gpa);87 code.instructions.deinit(gpa);
81 gpa.free(code.string_bytes);88 gpa.free(code.string_bytes);
...@@ -83,13 +90,11 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void {...@@ -83,13 +90,11 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void {
83 code.* = undefined;90 code.* = undefined;
84}91}
8592
86/// For debugging purposes, like dumpFn but for unanalyzed zir blocks93/// Write human-readable, debug formatted ZIR code to a file.
87pub fn dump(94pub fn renderAsTextToFile(
88 code: Zir,
89 gpa: *Allocator,95 gpa: *Allocator,
90 kind: []const u8,96 scope_file: *Module.Scope.File,
91 scope: *Module.Scope,97 fs_file: std.fs.File,
92 param_count: usize,
93) !void {98) !void {
94 var arena = std.heap.ArenaAllocator.init(gpa);99 var arena = std.heap.ArenaAllocator.init(gpa);
95 defer arena.deinit();100 defer arena.deinit();
...@@ -97,17 +102,17 @@ pub fn dump(...@@ -97,17 +102,17 @@ pub fn dump(
97 var writer: Writer = .{102 var writer: Writer = .{
98 .gpa = gpa,103 .gpa = gpa,
99 .arena = &arena.allocator,104 .arena = &arena.allocator,
100 .scope = scope,105 .file = scope_file,
101 .code = code,106 .code = scope_file.zir,
102 .indent = 0,107 .indent = 0,
103 .param_count = param_count,108 .parent_decl_node = 0,
109 .param_count = 0,
104 };110 };
105111
106 const decl_name = scope.srcDecl().?.name;112 const main_struct_inst = scope_file.zir.extra[0] - @intCast(u32, Inst.Ref.typed_value_map.len);
107 const stderr = std.io.getStdErr().writer();113 try fs_file.writer().print("%{d} ", .{main_struct_inst});
108 try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name });114 try writer.writeInstToStream(fs_file.writer(), main_struct_inst);
109 try writer.writeInstToStream(stderr, 0);115 try fs_file.writeAll("\n");
110 try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name });
111}116}
112117
113/// These are untyped instructions generated from an Abstract Syntax Tree.118/// These are untyped instructions generated from an Abstract Syntax Tree.
...@@ -291,12 +296,6 @@ pub const Inst = struct {...@@ -291,12 +296,6 @@ pub const Inst = struct {
291 /// Declares the beginning of a statement. Used for debug info.296 /// Declares the beginning of a statement. Used for debug info.
292 /// Uses the `node` union field.297 /// Uses the `node` union field.
293 dbg_stmt_node,298 dbg_stmt_node,
294 /// Represents a pointer to a global decl.
295 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
296 decl_ref,
297 /// Equivalent to a decl_ref followed by load.
298 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
299 decl_val,
300 /// Same as `decl_ref` except instead of indexing into decls, uses299 /// Same as `decl_ref` except instead of indexing into decls, uses
301 /// a name to identify the Decl. Uses the `str_tok` union field.300 /// a name to identify the Decl. Uses the `str_tok` union field.
302 decl_ref_named,301 decl_ref_named,
...@@ -705,6 +704,14 @@ pub const Inst = struct {...@@ -705,6 +704,14 @@ pub const Inst = struct {
705 size_of,704 size_of,
706 /// Implements the `@bitSizeOf` builtin. Uses `un_node`.705 /// Implements the `@bitSizeOf` builtin. Uses `un_node`.
707 bit_size_of,706 bit_size_of,
707 /// Implements the `@This` builtin. Uses `node`.
708 this,
709 /// Implements the `@fence` builtin. Uses `un_node`.
710 fence,
711 /// Implements the `@returnAddress` builtin. Uses `un_node`.
712 ret_addr,
713 /// Implements the `@src` builtin. Uses `un_node`.
714 builtin_src,
708715
709 /// Returns whether the instruction is one of the control flow "noreturn" types.716 /// Returns whether the instruction is one of the control flow "noreturn" types.
710 /// Function calls do not count.717 /// Function calls do not count.
...@@ -758,8 +765,6 @@ pub const Inst = struct {...@@ -758,8 +765,6 @@ pub const Inst = struct {
758 .enum_decl_nonexhaustive,765 .enum_decl_nonexhaustive,
759 .opaque_decl,766 .opaque_decl,
760 .dbg_stmt_node,767 .dbg_stmt_node,
761 .decl_ref,
762 .decl_val,
763 .decl_ref_named,768 .decl_ref_named,
764 .decl_val_named,769 .decl_val_named,
765 .load,770 .load,
...@@ -873,6 +878,10 @@ pub const Inst = struct {...@@ -873,6 +878,10 @@ pub const Inst = struct {
873 .type_info,878 .type_info,
874 .size_of,879 .size_of,
875 .bit_size_of,880 .bit_size_of,
881 .this,
882 .fence,
883 .ret_addr,
884 .builtin_src,
876 => false,885 => false,
877886
878 .@"break",887 .@"break",
...@@ -1647,11 +1656,16 @@ pub const SpecialProng = enum { none, @"else", under };...@@ -1647,11 +1656,16 @@ pub const SpecialProng = enum { none, @"else", under };
1647const Writer = struct {1656const Writer = struct {
1648 gpa: *Allocator,1657 gpa: *Allocator,
1649 arena: *Allocator,1658 arena: *Allocator,
1650 scope: *Module.Scope,1659 file: *Module.Scope.File,
1651 code: Zir,1660 code: Zir,
1652 indent: usize,1661 indent: u32,
1662 parent_decl_node: u32,
1653 param_count: usize,1663 param_count: usize,
16541664
1665 fn relativeToNodeIndex(self: *Writer, offset: i32) ast.Node.Index {
1666 return @bitCast(ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node));
1667 }
1668
1655 fn writeInstToStream(1669 fn writeInstToStream(
1656 self: *Writer,1670 self: *Writer,
1657 stream: anytype,1671 stream: anytype,
...@@ -1832,10 +1846,6 @@ const Writer = struct {...@@ -1832,10 +1846,6 @@ const Writer = struct {
1832 .typeof_peer,1846 .typeof_peer,
1833 => try self.writePlNodeMultiOp(stream, inst),1847 => try self.writePlNodeMultiOp(stream, inst),
18341848
1835 .decl_ref,
1836 .decl_val,
1837 => try self.writePlNodeDecl(stream, inst),
1838
1839 .field_ptr,1849 .field_ptr,
1840 .field_val,1850 .field_val,
1841 => try self.writePlNodeField(stream, inst),1851 => try self.writePlNodeField(stream, inst),
...@@ -1851,6 +1861,10 @@ const Writer = struct {...@@ -1851,6 +1861,10 @@ const Writer = struct {
1851 .repeat_inline,1861 .repeat_inline,
1852 .alloc_inferred,1862 .alloc_inferred,
1853 .alloc_inferred_mut,1863 .alloc_inferred_mut,
1864 .this,
1865 .fence,
1866 .ret_addr,
1867 .builtin_src,
1854 => try self.writeNode(stream, inst),1868 => try self.writeNode(stream, inst),
18551869
1856 .error_value,1870 .error_value,
...@@ -2067,68 +2081,114 @@ const Writer = struct {...@@ -2067,68 +2081,114 @@ const Writer = struct {
2067 const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index);2081 const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index);
2068 const body = self.code.extra[extra.end..][0..extra.data.body_len];2082 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2069 const fields_len = extra.data.fields_len;2083 const fields_len = extra.data.fields_len;
2084 const decls_len = extra.data.decls_len;
2085
2086 const prev_parent_decl_node = self.parent_decl_node;
2087 self.parent_decl_node = self.relativeToNodeIndex(inst_data.src_node);
2088
2089 var extra_index: usize = undefined;
20702090
2071 if (fields_len == 0) {2091 if (fields_len == 0) {
2072 assert(body.len == 0);2092 assert(body.len == 0);
2073 try stream.writeAll("{}, {}) ");2093 try stream.writeAll("{}, {}, {");
2074 try self.writeSrc(stream, inst_data.src());2094 extra_index = extra.end;
2075 return;2095 } else {
2076 }2096 try stream.writeAll("{\n");
2097 self.indent += 2;
2098 try self.writeBody(stream, body);
2099
2100 try stream.writeByteNTimes(' ', self.indent - 2);
2101 try stream.writeAll("}, {\n");
2102
2103 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
2104 const body_end = extra.end + body.len;
2105 extra_index = body_end + bit_bags_count;
2106 var bit_bag_index: usize = body_end;
2107 var cur_bit_bag: u32 = undefined;
2108 var field_i: u32 = 0;
2109 while (field_i < fields_len) : (field_i += 1) {
2110 if (field_i % 16 == 0) {
2111 cur_bit_bag = self.code.extra[bit_bag_index];
2112 bit_bag_index += 1;
2113 }
2114 const has_align = @truncate(u1, cur_bit_bag) != 0;
2115 cur_bit_bag >>= 1;
2116 const has_default = @truncate(u1, cur_bit_bag) != 0;
2117 cur_bit_bag >>= 1;
20772118
2078 try stream.writeAll("{\n");2119 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2079 self.indent += 2;2120 extra_index += 1;
2080 try self.writeBody(stream, body);2121 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2122 extra_index += 1;
20812123
2082 try stream.writeByteNTimes(' ', self.indent - 2);2124 try stream.writeByteNTimes(' ', self.indent);
2083 try stream.writeAll("}, {\n");2125 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
2126 try self.writeInstRef(stream, field_type);
20842127
2085 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;2128 if (has_align) {
2086 const body_end = extra.end + body.len;2129 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2087 var extra_index: usize = body_end + bit_bags_count;2130 extra_index += 1;
2088 var bit_bag_index: usize = body_end;2131
2132 try stream.writeAll(" align(");
2133 try self.writeInstRef(stream, align_ref);
2134 try stream.writeAll(")");
2135 }
2136 if (has_default) {
2137 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2138 extra_index += 1;
2139
2140 try stream.writeAll(" = ");
2141 try self.writeInstRef(stream, default_ref);
2142 }
2143 try stream.writeAll(",\n");
2144 }
2145
2146 self.indent -= 2;
2147 try stream.writeByteNTimes(' ', self.indent);
2148 try stream.writeAll("}, {");
2149 }
2150 if (decls_len == 0) {
2151 try stream.writeAll("}) ");
2152 } else {
2153 try stream.writeAll("\n");
2154 self.indent += 2;
2155 try self.writeDecls(stream, decls_len, extra_index);
2156 self.indent -= 2;
2157 try stream.writeByteNTimes(' ', self.indent);
2158 try stream.writeAll("}) ");
2159 }
2160 self.parent_decl_node = prev_parent_decl_node;
2161 try self.writeSrc(stream, inst_data.src());
2162 }
2163
2164 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !void {
2165 const bit_bags_count = std.math.divCeil(usize, decls_len, 16) catch unreachable;
2166 var extra_index = extra_start + bit_bags_count;
2167 var bit_bag_index: usize = extra_start;
2089 var cur_bit_bag: u32 = undefined;2168 var cur_bit_bag: u32 = undefined;
2090 var field_i: u32 = 0;2169 var decl_i: u32 = 0;
2091 while (field_i < fields_len) : (field_i += 1) {2170 while (decl_i < decls_len) : (decl_i += 1) {
2092 if (field_i % 16 == 0) {2171 if (decl_i % 16 == 0) {
2093 cur_bit_bag = self.code.extra[bit_bag_index];2172 cur_bit_bag = self.code.extra[bit_bag_index];
2094 bit_bag_index += 1;2173 bit_bag_index += 1;
2095 }2174 }
2096 const has_align = @truncate(u1, cur_bit_bag) != 0;2175 const is_pub = @truncate(u1, cur_bit_bag) != 0;
2097 cur_bit_bag >>= 1;2176 cur_bit_bag >>= 1;
2098 const has_default = @truncate(u1, cur_bit_bag) != 0;2177 const is_exported = @truncate(u1, cur_bit_bag) != 0;
2099 cur_bit_bag >>= 1;2178 cur_bit_bag >>= 1;
21002179
2101 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);2180 const decl_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2102 extra_index += 1;2181 extra_index += 1;
2103 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);2182 const decl_value = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2104 extra_index += 1;2183 extra_index += 1;
21052184
2185 const pub_str = if (is_pub) "pub " else "";
2186 const export_str = if (is_exported) "export " else "";
2106 try stream.writeByteNTimes(' ', self.indent);2187 try stream.writeByteNTimes(' ', self.indent);
2107 try stream.print("{}: ", .{std.zig.fmtId(field_name)});2188 try stream.print("{s}{s}{} = ", .{ pub_str, export_str, std.zig.fmtId(decl_name) });
2108 try self.writeInstRef(stream, field_type);2189 try self.writeInstRef(stream, decl_value);
21092190 try stream.writeAll("\n");
2110 if (has_align) {
2111 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2112 extra_index += 1;
2113
2114 try stream.writeAll(" align(");
2115 try self.writeInstRef(stream, align_ref);
2116 try stream.writeAll(")");
2117 }
2118 if (has_default) {
2119 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2120 extra_index += 1;
2121
2122 try stream.writeAll(" = ");
2123 try self.writeInstRef(stream, default_ref);
2124 }
2125 try stream.writeAll(",\n");
2126 }2191 }
2127
2128 self.indent -= 2;
2129 try stream.writeByteNTimes(' ', self.indent);
2130 try stream.writeAll("}) ");
2131 try self.writeSrc(stream, inst_data.src());
2132 }2192 }
21332193
2134 fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {2194 fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
...@@ -2374,14 +2434,6 @@ const Writer = struct {...@@ -2374,14 +2434,6 @@ const Writer = struct {
2374 try self.writeSrc(stream, inst_data.src());2434 try self.writeSrc(stream, inst_data.src());
2375 }2435 }
23762436
2377 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2378 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2379 const owner_decl = self.scope.ownerDecl().?;
2380 const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key;
2381 try stream.print("{s}) ", .{decl.name});
2382 try self.writeSrc(stream, inst_data.src());
2383 }
2384
2385 fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void {2437 fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2386 const inst_data = self.code.instructions.items(.data)[inst].pl_node;2438 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2387 const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data;2439 const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data;
...@@ -2593,8 +2645,12 @@ const Writer = struct {...@@ -2593,8 +2645,12 @@ const Writer = struct {
2593 }2645 }
25942646
2595 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {2647 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {
2596 const tree = self.scope.tree();2648 const tree = self.file.tree;
2597 const src_loc = src.toSrcLoc(self.scope);2649 const src_loc: Module.SrcLoc = .{
2650 .file_scope = self.file,
2651 .parent_decl_node = self.parent_decl_node,
2652 .lazy = src,
2653 };
2598 const abs_byte_off = try src_loc.byteOffset();2654 const abs_byte_off = try src_loc.byteOffset();
2599 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);2655 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
2600 try stream.print("{s}:{d}:{d}", .{2656 try stream.print("{s}:{d}:{d}", .{
src/main.zig+93-6
...@@ -25,7 +25,11 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn {...@@ -25,7 +25,11 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
25 process.exit(1);25 process.exit(1);
26}26}
2727
28pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB28/// There are many assumptions in the entire codebase that Zig source files can
29/// be byte-indexed with a u32 integer.
30pub const max_src_size = std.math.maxInt(u32);
31
32pub const debug_extensions_enabled = std.builtin.mode == .Debug;
2933
30pub const Color = enum {34pub const Color = enum {
31 auto,35 auto,
...@@ -33,7 +37,7 @@ pub const Color = enum {...@@ -33,7 +37,7 @@ pub const Color = enum {
33 on,37 on,
34};38};
3539
36const usage =40const normal_usage =
37 \\Usage: zig [command] [options]41 \\Usage: zig [command] [options]
38 \\42 \\
39 \\Commands:43 \\Commands:
...@@ -63,6 +67,16 @@ const usage =...@@ -63,6 +67,16 @@ const usage =
63 \\67 \\
64;68;
6569
70const debug_usage = normal_usage ++
71 \\
72 \\Debug Commands:
73 \\
74 \\ astgen Print ZIR code for a .zig source file
75 \\
76;
77
78const usage = if (debug_extensions_enabled) debug_usage else normal_usage;
79
66pub const log_level: std.log.Level = switch (std.builtin.mode) {80pub const log_level: std.log.Level = switch (std.builtin.mode) {
67 .Debug => .debug,81 .Debug => .debug,
68 .ReleaseSafe, .ReleaseFast => .info,82 .ReleaseSafe, .ReleaseFast => .info,
...@@ -206,13 +220,15 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -206,13 +220,15 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
206 const stdout = io.getStdOut().writer();220 const stdout = io.getStdOut().writer();
207 return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target);221 return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target);
208 } else if (mem.eql(u8, cmd, "version")) {222 } else if (mem.eql(u8, cmd, "version")) {
209 try std.io.getStdOut().writeAll(build_options.version ++ "\n");223 return std.io.getStdOut().writeAll(build_options.version ++ "\n");
210 } else if (mem.eql(u8, cmd, "env")) {224 } else if (mem.eql(u8, cmd, "env")) {
211 try @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());225 return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
212 } else if (mem.eql(u8, cmd, "zen")) {226 } else if (mem.eql(u8, cmd, "zen")) {
213 try io.getStdOut().writeAll(info_zen);227 return io.getStdOut().writeAll(info_zen);
214 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {228 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
215 try io.getStdOut().writeAll(usage);229 return io.getStdOut().writeAll(usage);
230 } else if (debug_extensions_enabled and mem.eql(u8, cmd, "astgen")) {
231 return cmdAstgen(gpa, arena, cmd_args);
216 } else {232 } else {
217 std.log.info("{s}", .{usage});233 std.log.info("{s}", .{usage});
218 fatal("unknown command: {s}", .{args[1]});234 fatal("unknown command: {s}", .{args[1]});
...@@ -3485,3 +3501,74 @@ pub fn cleanExit() void {...@@ -3485,3 +3501,74 @@ pub fn cleanExit() void {
3485 process.exit(0);3501 process.exit(0);
3486 }3502 }
3487}3503}
3504
3505/// This is only enabled for debug builds.
3506pub fn cmdAstgen(
3507 gpa: *Allocator,
3508 arena: *Allocator,
3509 args: []const []const u8,
3510) !void {
3511 const Module = @import("Module.zig");
3512 const AstGen = @import("AstGen.zig");
3513 const Zir = @import("Zir.zig");
3514
3515 const zig_source_file = args[0];
3516
3517 var f = try fs.cwd().openFile(zig_source_file, .{});
3518 defer f.close();
3519
3520 const stat = try f.stat();
3521
3522 if (stat.size > max_src_size)
3523 return error.FileTooBig;
3524
3525 var file: Module.Scope.File = .{
3526 .status = .never_loaded,
3527 .source_loaded = false,
3528 .tree_loaded = false,
3529 .zir_loaded = false,
3530 .sub_file_path = zig_source_file,
3531 .source = undefined,
3532 .stat_size = stat.size,
3533 .stat_inode = stat.inode,
3534 .stat_mtime = stat.mtime,
3535 .tree = undefined,
3536 .zir = undefined,
3537 .pkg = undefined,
3538 .namespace = undefined,
3539 };
3540
3541 const source = try arena.allocSentinel(u8, stat.size, 0);
3542 const amt = try f.readAll(source);
3543 if (amt != stat.size)
3544 return error.UnexpectedEndOfFile;
3545 file.source = source;
3546 file.source_loaded = true;
3547
3548 file.tree = try std.zig.parse(gpa, file.source);
3549 file.tree_loaded = true;
3550 defer file.tree.deinit(gpa);
3551
3552 for (file.tree.errors) |parse_error| {
3553 try printErrMsgToFile(gpa, parse_error, file.tree, zig_source_file, io.getStdErr(), .auto);
3554 }
3555 if (file.tree.errors.len != 0) {
3556 process.exit(1);
3557 }
3558
3559 file.zir = try AstGen.generate(gpa, &file);
3560 file.zir_loaded = true;
3561 defer file.zir.deinit(gpa);
3562
3563 if (file.zir.hasCompileErrors()) {
3564 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
3565 try Compilation.AllErrors.addZir(arena, &errors, &file, source);
3566 const ttyconf = std.debug.detectTTYConfig();
3567 for (errors.items) |full_err_msg| {
3568 full_err_msg.renderToStdErr(ttyconf);
3569 }
3570 process.exit(1);
3571 }
3572
3573 return Zir.renderAsTextToFile(gpa, &file, io.getStdOut());
3574}