authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-09 23:17:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 19:06:39-07:00
logf458192e56b13500ff6eb7c3e94dcf48240f4170
treee30f463ea61cb93511487f73983ac4ec26e3d9d8
parentccdf55310bee2dcf86b718d26a56933dc1a03443

stage2: entry point via std lib and proper updated file detection

Instead of Module setting up the root_scope with the root source file, instead, Module relies on the package table graph being set up properly, and inside `update()`, it does the equivalent of `_ = @import("std");`. This, in term, imports start.zig, which has the logic to call main (or not). `Module` no longer has `root_scope` - the root source file is no longer special, it's just in the package table mapped to "root". I also went ahead and implemented proper detection of updated files. mtime, inode, size, and source hash are kept in `Scope.File`. During an update, iterate over `import_table` and stat each file to find out which ones are updated. The source hash is redundant with the source hash used by the struct decl that corresponds to the file, so it should be removed in a future commit before merging the branch. * AstGen: add "previously declared here" notes for variables shadowing decls. * Parse imports as structs. Module now calls `AstGen.structDeclInner`, which is called by `AstGen.containerDecl`. - `importFile` is a bit kludgy with how it handles the top level Decl that kinda gets merged into the struct decl at the end of the function. Be on the look out for bugs related to that as well as possibly cleaner ways to implement this. * Module: factor out lookupDeclName into lookupIdentifier and lookupNa * Rename `Scope.Container` to `Scope.Namespace`. * Delete some dead code. This branch won't work until `usingnamespace` is implemented because it relies on `@import("builtin").OutputMode` and `OutputMode` comes from a `usingnamespace`.

10 files changed, 757 insertions(+), 507 deletions(-)

BRANCH_TODO created+96
......@@ -0,0 +1,96 @@
1 * get rid of failed_root_src_file
2
3
4 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
5 pkg.namespace_hash
6 else
7 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
8
9 file_scope.* = .{
10 .root_container = .{
11 .parent = null,
12 .file_scope = file_scope,
13 .decls = .{},
14 .ty = struct_ty,
15 .parent_name_hash = container_name_hash,
16 },
17 };
18 mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
19 error.AnalysisFail => {
20 assert(mod.comp.totalErrorCount() != 0);
21 },
22 else => |e| return e,
23 };
24 return file_scope;
25
26
27
28 // Until then we simulate a full cache miss. Source files could have been loaded
29 // for any reason; to force a refresh we unload now.
30 module.unloadFile(module.root_scope);
31 module.failed_root_src_file = null;
32 module.analyzeNamespace(&module.root_scope.root_container) catch |err| switch (err) {
33 error.AnalysisFail => {
34 assert(self.totalErrorCount() != 0);
35 },
36 error.OutOfMemory => return error.OutOfMemory,
37 else => |e| {
38 module.failed_root_src_file = e;
39 },
40 };
41
42 // TODO only analyze imports if they are still referenced
43 for (module.import_table.items()) |entry| {
44 module.unloadFile(entry.value);
45 module.analyzeNamespace(&entry.value.root_container) catch |err| switch (err) {
46 error.AnalysisFail => {
47 assert(self.totalErrorCount() != 0);
48 },
49 else => |e| return e,
50 };
51 }
52
53
54pub fn createContainerDecl(
55 mod: *Module,
56 scope: *Scope,
57 base_token: std.zig.ast.TokenIndex,
58 decl_arena: *std.heap.ArenaAllocator,
59 typed_value: TypedValue,
60) !*Decl {
61 const scope_decl = scope.ownerDecl().?;
62 const name = try mod.getAnonTypeName(scope, base_token);
63 defer mod.gpa.free(name);
64 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
65 const src_hash: std.zig.SrcHash = undefined;
66 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
67 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
68
69 decl_arena_state.* = decl_arena.state;
70 new_decl.typed_value = .{
71 .most_recent = .{
72 .typed_value = typed_value,
73 .arena = decl_arena_state,
74 },
75 };
76 new_decl.analysis = .complete;
77 new_decl.generation = mod.generation;
78
79 return new_decl;
80}
81
82fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
83 // TODO add namespaces, generic function signatrues
84 const tree = scope.tree();
85 const token_tags = tree.tokens.items(.tag);
86 const base_name = switch (token_tags[base_token]) {
87 .keyword_struct => "struct",
88 .keyword_enum => "enum",
89 .keyword_union => "union",
90 .keyword_opaque => "opaque",
91 else => unreachable,
92 };
93 const loc = tree.tokenLocation(0, base_token);
94 return std.fmt.allocPrint(mod.gpa, "{s}:{d}:{d}", .{ base_name, loc.line, loc.column });
95}
96
src/AstGen.zig+107-77
......@@ -1420,6 +1420,7 @@ fn varDecl(
14201420 return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});
14211421 }
14221422 const astgen = gz.astgen;
1423 const gpa = mod.gpa;
14231424 const tree = gz.tree();
14241425 const token_tags = tree.tokens.items(.tag);
14251426
......@@ -1438,7 +1439,7 @@ fn varDecl(
14381439 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{
14391440 ident_name,
14401441 });
1441 errdefer msg.destroy(mod.gpa);
1442 errdefer msg.destroy(gpa);
14421443 try mod.errNote(scope, local_val.src, msg, "previous definition is here", .{});
14431444 break :msg msg;
14441445 };
......@@ -1453,7 +1454,7 @@ fn varDecl(
14531454 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{
14541455 ident_name,
14551456 });
1456 errdefer msg.destroy(mod.gpa);
1457 errdefer msg.destroy(gpa);
14571458 try mod.errNote(scope, local_ptr.src, msg, "previous definition is here", .{});
14581459 break :msg msg;
14591460 };
......@@ -1467,9 +1468,19 @@ fn varDecl(
14671468 }
14681469
14691470 // Namespace vars shadowing detection
1470 if (mod.lookupDeclName(scope, ident_name)) |_| {
1471 // TODO add note for other definition
1472 return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name});
1471 if (mod.lookupIdentifier(scope, ident_name)) |decl| {
1472 const msg = msg: {
1473 const msg = try mod.errMsg(
1474 scope,
1475 name_src,
1476 "redeclaration of '{s}'",
1477 .{ident_name},
1478 );
1479 errdefer msg.destroy(gpa);
1480 try mod.errNoteNonLazy(decl.srcLoc(), msg, "previously declared here", .{});
1481 break :msg msg;
1482 };
1483 return mod.failWithOwnedErrorMsg(scope, msg);
14731484 }
14741485 if (var_decl.ast.init_node == 0) {
14751486 return mod.fail(scope, name_src, "variables must be initialized", .{});
......@@ -1503,7 +1514,7 @@ fn varDecl(
15031514 .force_comptime = gz.force_comptime,
15041515 .astgen = astgen,
15051516 };
1506 defer init_scope.instructions.deinit(mod.gpa);
1517 defer init_scope.instructions.deinit(gpa);
15071518
15081519 var resolve_inferred_alloc: zir.Inst.Ref = .none;
15091520 var opt_type_inst: zir.Inst.Ref = .none;
......@@ -1529,7 +1540,7 @@ fn varDecl(
15291540 // Move the init_scope instructions into the parent scope, eliding
15301541 // the alloc instruction and the store_to_block_ptr instruction.
15311542 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;
1532 try parent_zir.ensureCapacity(mod.gpa, expected_len);
1543 try parent_zir.ensureCapacity(gpa, expected_len);
15331544 for (init_scope.instructions.items) |src_inst| {
15341545 if (astgen.indexToRef(src_inst) == init_scope.rl_ptr) continue;
15351546 if (zir_tags[src_inst] == .store_to_block_ptr) {
......@@ -1554,7 +1565,7 @@ fn varDecl(
15541565 // Move the init_scope instructions into the parent scope, swapping
15551566 // store_to_block_ptr for store_to_inferred_ptr.
15561567 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;
1557 try parent_zir.ensureCapacity(mod.gpa, expected_len);
1568 try parent_zir.ensureCapacity(gpa, expected_len);
15581569 for (init_scope.instructions.items) |src_inst| {
15591570 if (zir_tags[src_inst] == .store_to_block_ptr) {
15601571 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {
......@@ -1798,6 +1809,91 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.I
17981809 return rvalue(gz, scope, rl, result, node);
17991810}
18001811
1812pub fn structDeclInner(
1813 gz: *GenZir,
1814 scope: *Scope,
1815 node: ast.Node.Index,
1816 container_decl: ast.full.ContainerDecl,
1817 tag: zir.Inst.Tag,
1818) InnerError!zir.Inst.Ref {
1819 if (container_decl.ast.members.len == 0) {
1820 return gz.addPlNode(tag, node, zir.Inst.StructDecl{ .fields_len = 0 });
1821 }
1822
1823 const astgen = gz.astgen;
1824 const mod = astgen.mod;
1825 const gpa = mod.gpa;
1826 const tree = gz.tree();
1827 const node_tags = tree.nodes.items(.tag);
1828
1829 var fields_data = ArrayListUnmanaged(u32){};
1830 defer fields_data.deinit(gpa);
1831
1832 // field_name and field_type are both mandatory
1833 try fields_data.ensureCapacity(gpa, container_decl.ast.members.len * 2);
1834
1835 // We only need this if there are greater than 16 fields.
1836 var bit_bag = ArrayListUnmanaged(u32){};
1837 defer bit_bag.deinit(gpa);
1838
1839 var cur_bit_bag: u32 = 0;
1840 var field_index: usize = 0;
1841 for (container_decl.ast.members) |member_node| {
1842 const member = switch (node_tags[member_node]) {
1843 .container_field_init => tree.containerFieldInit(member_node),
1844 .container_field_align => tree.containerFieldAlign(member_node),
1845 .container_field => tree.containerField(member_node),
1846 else => continue,
1847 };
1848 if (field_index % 16 == 0 and field_index != 0) {
1849 try bit_bag.append(gpa, cur_bit_bag);
1850 cur_bit_bag = 0;
1851 }
1852 if (member.comptime_token) |comptime_token| {
1853 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
1854 }
1855 try fields_data.ensureCapacity(gpa, fields_data.items.len + 4);
1856
1857 const field_name = try gz.identAsString(member.ast.name_token);
1858 fields_data.appendAssumeCapacity(field_name);
1859
1860 const field_type = try typeExpr(gz, scope, member.ast.type_expr);
1861 fields_data.appendAssumeCapacity(@enumToInt(field_type));
1862
1863 const have_align = member.ast.align_expr != 0;
1864 const have_value = member.ast.value_expr != 0;
1865 cur_bit_bag = (cur_bit_bag >> 2) |
1866 (@as(u32, @boolToInt(have_align)) << 30) |
1867 (@as(u32, @boolToInt(have_value)) << 31);
1868
1869 if (have_align) {
1870 const align_inst = try comptimeExpr(gz, scope, .{ .ty = .u32_type }, member.ast.align_expr);
1871 fields_data.appendAssumeCapacity(@enumToInt(align_inst));
1872 }
1873 if (have_value) {
1874 const default_inst = try comptimeExpr(gz, scope, .{ .ty = field_type }, member.ast.value_expr);
1875 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
1876 }
1877
1878 field_index += 1;
1879 }
1880 if (field_index == 0) {
1881 return gz.addPlNode(tag, node, zir.Inst.StructDecl{ .fields_len = 0 });
1882 }
1883 const empty_slot_count = 16 - (field_index % 16);
1884 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
1885
1886 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
1887 .fields_len = @intCast(u32, container_decl.ast.members.len),
1888 });
1889 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
1890 bit_bag.items.len + 1 + fields_data.items.len);
1891 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
1892 astgen.extra.appendAssumeCapacity(cur_bit_bag);
1893 astgen.extra.appendSliceAssumeCapacity(fields_data.items);
1894 return result;
1895}
1896
18011897fn containerDecl(
18021898 gz: *GenZir,
18031899 scope: *Scope,
......@@ -1827,76 +1923,10 @@ fn containerDecl(
18271923 .keyword_extern => zir.Inst.Tag.struct_decl_extern,
18281924 else => unreachable,
18291925 } else zir.Inst.Tag.struct_decl;
1830 if (container_decl.ast.members.len == 0) {
1831 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
1832 .fields_len = 0,
1833 });
1834 return rvalue(gz, scope, rl, result, node);
1835 }
18361926
18371927 assert(arg_inst == .none);
1838 var fields_data = ArrayListUnmanaged(u32){};
1839 defer fields_data.deinit(gpa);
1840
1841 // field_name and field_type are both mandatory
1842 try fields_data.ensureCapacity(gpa, container_decl.ast.members.len * 2);
1843
1844 // We only need this if there are greater than 16 fields.
1845 var bit_bag = ArrayListUnmanaged(u32){};
1846 defer bit_bag.deinit(gpa);
1847
1848 var cur_bit_bag: u32 = 0;
1849 var field_index: usize = 0;
1850 for (container_decl.ast.members) |member_node| {
1851 const member = switch (node_tags[member_node]) {
1852 .container_field_init => tree.containerFieldInit(member_node),
1853 .container_field_align => tree.containerFieldAlign(member_node),
1854 .container_field => tree.containerField(member_node),
1855 else => continue,
1856 };
1857 if (field_index % 16 == 0 and field_index != 0) {
1858 try bit_bag.append(gpa, cur_bit_bag);
1859 cur_bit_bag = 0;
1860 }
1861 if (member.comptime_token) |comptime_token| {
1862 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
1863 }
1864 try fields_data.ensureCapacity(gpa, fields_data.items.len + 4);
1865
1866 const field_name = try gz.identAsString(member.ast.name_token);
1867 fields_data.appendAssumeCapacity(field_name);
18681928
1869 const field_type = try typeExpr(gz, scope, member.ast.type_expr);
1870 fields_data.appendAssumeCapacity(@enumToInt(field_type));
1871
1872 const have_align = member.ast.align_expr != 0;
1873 const have_value = member.ast.value_expr != 0;
1874 cur_bit_bag = (cur_bit_bag >> 2) |
1875 (@as(u32, @boolToInt(have_align)) << 30) |
1876 (@as(u32, @boolToInt(have_value)) << 31);
1877
1878 if (have_align) {
1879 const align_inst = try comptimeExpr(gz, scope, .{ .ty = .u32_type }, member.ast.align_expr);
1880 fields_data.appendAssumeCapacity(@enumToInt(align_inst));
1881 }
1882 if (have_value) {
1883 const default_inst = try comptimeExpr(gz, scope, .{ .ty = field_type }, member.ast.value_expr);
1884 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
1885 }
1886
1887 field_index += 1;
1888 }
1889 const empty_slot_count = 16 - (field_index % 16);
1890 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
1891
1892 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
1893 .fields_len = @intCast(u32, container_decl.ast.members.len),
1894 });
1895 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
1896 bit_bag.items.len + 1 + fields_data.items.len);
1897 astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
1898 astgen.extra.appendAssumeCapacity(cur_bit_bag);
1899 astgen.extra.appendSliceAssumeCapacity(fields_data.items);
1929 const result = try structDeclInner(gz, scope, node, container_decl, tag);
19001930 return rvalue(gz, scope, rl, result, node);
19011931 },
19021932 .keyword_union => {
......@@ -2930,7 +2960,7 @@ pub const SwitchProngSrc = union(enum) {
29302960 ) LazySrcLoc {
29312961 @setCold(true);
29322962 const switch_node = decl.relativeToNodeIndex(switch_node_offset);
2933 const tree = decl.container.file_scope.base.tree();
2963 const tree = decl.namespace.file_scope.base.tree();
29342964 const main_tokens = tree.nodes.items(.main_token);
29352965 const node_datas = tree.nodes.items(.data);
29362966 const node_tags = tree.nodes.items(.tag);
......@@ -3692,7 +3722,7 @@ fn identifier(
36923722 };
36933723 }
36943724
3695 const decl = mod.lookupDeclName(scope, ident_name) orelse {
3725 const decl = mod.lookupIdentifier(scope, ident_name) orelse {
36963726 // TODO insert a "dependency on the non-existence of a decl" here to make this
36973727 // compile error go away when the decl is introduced. This data should be in a global
36983728 // sparse map since it is only relevant when a compile error occurs.
src/Compilation.zig+50-48
......@@ -385,7 +385,7 @@ pub const AllErrors = struct {
385385 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
386386 for (notes) |*note, i| {
387387 const module_note = module_err_msg.notes[i];
388 const source = try module_note.src_loc.fileScope().getSource(module);
388 const source = try module_note.src_loc.fileScope().getSource(module.gpa);
389389 const byte_offset = try module_note.src_loc.byteOffset();
390390 const loc = std.zig.findLineColumn(source, byte_offset);
391391 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
......@@ -400,7 +400,7 @@ pub const AllErrors = struct {
400400 },
401401 };
402402 }
403 const source = try module_err_msg.src_loc.fileScope().getSource(module);
403 const source = try module_err_msg.src_loc.fileScope().getSource(module.gpa);
404404 const byte_offset = try module_err_msg.src_loc.byteOffset();
405405 const loc = std.zig.findLineColumn(source, byte_offset);
406406 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;
......@@ -1049,37 +1049,18 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
10491049 // However we currently do not have serialization of such metadata, so for now
10501050 // we set up an empty Module that does the entire compilation fresh.
10511051
1052 const root_scope = try gpa.create(Module.Scope.File);
1053 errdefer gpa.destroy(root_scope);
1054
1055 const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container);
1056 root_scope.* = .{
1057 // TODO this is duped so it can be freed in Container.deinit
1058 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
1059 .source = .{ .unloaded = {} },
1060 .tree = undefined,
1061 .status = .never_loaded,
1062 .pkg = root_pkg,
1063 .root_container = .{
1064 .file_scope = root_scope,
1065 .decls = .{},
1066 .ty = struct_ty,
1067 .parent_name_hash = root_pkg.namespace_hash,
1068 },
1069 };
1070
10711052 const module = try arena.create(Module);
10721053 errdefer module.deinit();
10731054 module.* = .{
10741055 .gpa = gpa,
10751056 .comp = comp,
10761057 .root_pkg = root_pkg,
1077 .root_scope = root_scope,
10781058 .zig_cache_artifact_directory = zig_cache_artifact_directory,
10791059 .emit_h = options.emit_h,
10801060 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1),
10811061 };
10821062 module.error_name_list.appendAssumeCapacity("(no error)");
1063
10831064 break :blk module;
10841065 } else blk: {
10851066 if (options.emit_h != null) return error.NoZigModuleForCHeader;
......@@ -1485,31 +1466,50 @@ pub fn update(self: *Compilation) !void {
14851466 module.compile_log_text.shrinkAndFree(module.gpa, 0);
14861467 module.generation += 1;
14871468
1488 // TODO Detect which source files changed.
1489 // Until then we simulate a full cache miss. Source files could have been loaded
1490 // for any reason; to force a refresh we unload now.
1491 module.unloadFile(module.root_scope);
1492 module.failed_root_src_file = null;
1493 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
1494 error.AnalysisFail => {
1495 assert(self.totalErrorCount() != 0);
1496 },
1497 error.OutOfMemory => return error.OutOfMemory,
1498 else => |e| {
1499 module.failed_root_src_file = e;
1500 },
1501 };
1502
1503 // TODO only analyze imports if they are still referenced
1469 // Detect which source files changed.
15041470 for (module.import_table.items()) |entry| {
1505 module.unloadFile(entry.value);
1506 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
1507 error.AnalysisFail => {
1508 assert(self.totalErrorCount() != 0);
1509 },
1471 const file = entry.value;
1472 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
1473 defer f.close();
1474
1475 // TODO handle error here by populating a retryable compile error
1476 const stat = try f.stat();
1477 const unchanged_metadata =
1478 stat.size == file.stat_size and
1479 stat.mtime == file.stat_mtime and
1480 stat.inode == file.stat_inode;
1481
1482 if (unchanged_metadata) {
1483 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
1484 continue;
1485 }
1486
1487 const prev_hash = file.source_hash;
1488 file.unloadSource(module.gpa);
1489 // TODO handle error here by populating a retryable compile error
1490 try file.finishGettingSource(module.gpa, f, stat);
1491 assert(file.source_loaded);
1492 if (mem.eql(u8, &prev_hash, &file.source_hash)) {
1493 file.updateTreeToNewSource();
1494 log.debug("unmodified source hash of file: {s}", .{file.sub_file_path});
1495 continue;
1496 }
1497
1498 log.debug("source contents changed: {s}", .{file.sub_file_path});
1499 if (file.status == .unloaded_parse_failure) {
1500 module.failed_files.swapRemove(file).?.value.destroy(module.gpa);
1501 }
1502 file.unloadTree(module.gpa);
1503
1504 module.analyzeFile(file) catch |err| switch (err) {
1505 error.OutOfMemory => return error.OutOfMemory,
1506 error.AnalysisFail => continue,
15101507 else => |e| return e,
15111508 };
15121509 }
1510
1511 // Simulate `_ = @import("std");` which in turn imports start.zig.
1512 _ = try module.importFile(module.root_pkg, "std");
15131513 }
15141514 }
15151515
......@@ -1551,7 +1551,9 @@ pub fn update(self: *Compilation) !void {
15511551 // to report error messages. Otherwise we unload all source files to save memory.
15521552 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
15531553 if (self.bin_file.options.module) |module| {
1554 module.root_scope.unload(self.gpa);
1554 for (module.import_table.items()) |entry| {
1555 entry.value.unload(self.gpa);
1556 }
15551557 }
15561558 }
15571559}
......@@ -1580,13 +1582,13 @@ pub fn totalErrorCount(self: *Compilation) usize {
15801582 // the previous parse success, including compile errors, but we cannot
15811583 // emit them until the file succeeds parsing.
15821584 for (module.failed_decls.items()) |entry| {
1583 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1585 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
15841586 continue;
15851587 }
15861588 total += 1;
15871589 }
15881590 for (module.emit_h_failed_decls.items()) |entry| {
1589 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1591 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
15901592 continue;
15911593 }
15921594 total += 1;
......@@ -1641,7 +1643,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
16411643 try AllErrors.add(module, &arena, &errors, entry.value.*);
16421644 }
16431645 for (module.failed_decls.items()) |entry| {
1644 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1646 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
16451647 // Skip errors for Decls within files that had a parse failure.
16461648 // We'll try again once parsing succeeds.
16471649 continue;
......@@ -1649,7 +1651,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
16491651 try AllErrors.add(module, &arena, &errors, entry.value.*);
16501652 }
16511653 for (module.emit_h_failed_decls.items()) |entry| {
1652 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1654 if (entry.key.namespace.file_scope.status == .unloaded_parse_failure) {
16531655 // Skip errors for Decls within files that had a parse failure.
16541656 // We'll try again once parsing succeeds.
16551657 continue;
src/Module.zig+409-269
......@@ -26,6 +26,7 @@ const trace = @import("tracy.zig").trace;
2626const AstGen = @import("AstGen.zig");
2727const Sema = @import("Sema.zig");
2828const target_util = @import("target.zig");
29const Cache = @import("Cache.zig");
2930
3031/// General-purpose allocator. Used for both temporary and long-term storage.
3132gpa: *Allocator,
......@@ -35,8 +36,6 @@ comp: *Compilation,
3536zig_cache_artifact_directory: Compilation.Directory,
3637/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
3738root_pkg: *Package,
38/// Module owns this resource.
39root_scope: *Scope.File,
4039/// It's rare for a decl to be exported, so we save memory by having a sparse map of
4140/// Decl pointers to details about them being exported.
4241/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
......@@ -52,6 +51,12 @@ symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{},
5251export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
5352/// Maps fully qualified namespaced names to the Decl struct for them.
5453decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false) = .{},
54/// The set of all the files in the Module. We keep track of this in order to iterate
55/// over it and check which source files have been modified on the file system when
56/// an update is requested, as well as to cache `@import` results.
57/// Keys are fully resolved file paths. This table owns the keys and values.
58import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
59
5560/// We optimize memory usage for a compilation with no compile errors by storing the
5661/// error messages and mapping outside of `Decl`.
5762/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
......@@ -85,9 +90,6 @@ global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{},
8590/// Corresponds with `global_error_set`.
8691error_name_list: ArrayListUnmanaged([]const u8) = .{},
8792
88/// Keys are fully qualified paths
89import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
90
9193/// Incrementing integer used to compare against the corresponding Decl
9294/// field to determine whether a Decl's status applies to an ongoing update, or a
9395/// previous analysis.
......@@ -147,15 +149,16 @@ pub const Decl = struct {
147149 /// This is necessary for mapping them to an address in the output file.
148150 /// Memory owned by this decl, using Module's allocator.
149151 name: [*:0]const u8,
150 /// The direct parent container of the Decl.
152 /// The direct parent namespace of the Decl.
151153 /// Reference to externally owned memory.
152 container: *Scope.Container,
154 /// This is `null` for the Decl that represents a `File`.
155 namespace: *Scope.Namespace,
153156
154157 /// An integer that can be checked against the corresponding incrementing
155158 /// generation field of Module. This is used to determine whether `complete` status
156159 /// represents pre- or post- re-analysis.
157160 generation: u32,
158 /// The AST Node index or ZIR Inst index that contains this declaration.
161 /// The AST node index of this declaration.
159162 /// Must be recomputed when the corresponding source file is modified.
160163 src_node: ast.Node.Index,
161164
......@@ -273,22 +276,22 @@ pub const Decl = struct {
273276 }
274277
275278 pub fn srcToken(decl: Decl) u32 {
276 const tree = &decl.container.file_scope.tree;
279 const tree = &decl.namespace.file_scope.tree;
277280 return tree.firstToken(decl.src_node);
278281 }
279282
280283 pub fn srcByteOffset(decl: Decl) u32 {
281 const tree = &decl.container.file_scope.tree;
284 const tree = &decl.namespace.file_scope.tree;
282285 return tree.tokens.items(.start)[decl.srcToken()];
283286 }
284287
285288 pub fn fullyQualifiedNameHash(decl: Decl) Scope.NameHash {
286 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
289 return decl.namespace.fullyQualifiedNameHash(mem.spanZ(decl.name));
287290 }
288291
289292 pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void {
290293 const unqualified_name = mem.spanZ(decl.name);
291 return decl.container.renderFullyQualifiedName(unqualified_name, writer);
294 return decl.namespace.renderFullyQualifiedName(unqualified_name, writer);
292295 }
293296
294297 pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 {
......@@ -330,7 +333,7 @@ pub const Decl = struct {
330333 }
331334
332335 pub fn getFileScope(decl: Decl) *Scope.File {
333 return decl.container.file_scope;
336 return decl.namespace.file_scope;
334337 }
335338
336339 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {
......@@ -377,7 +380,7 @@ pub const Struct = struct {
377380 /// Set of field names in declaration order.
378381 fields: std.StringArrayHashMapUnmanaged(Field),
379382 /// Represents the declarations inside this struct.
380 container: Scope.Container,
383 namespace: Scope.Namespace,
381384
382385 /// Offset from `owner_decl`, points to the struct AST node.
383386 node_offset: i32,
......@@ -434,7 +437,7 @@ pub const EnumFull = struct {
434437 /// If this hash map is empty, it means the enum tags are auto-numbered.
435438 values: ValueMap,
436439 /// Represents the declarations inside this struct.
437 container: Scope.Container,
440 namespace: Scope.Namespace,
438441 /// Offset from `owner_decl`, points to the enum decl AST node.
439442 node_offset: i32,
440443
......@@ -521,7 +524,7 @@ pub const Scope = struct {
521524 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.arena,
522525 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.arena,
523526 .file => unreachable,
524 .container => unreachable,
527 .namespace => unreachable,
525528 .decl_ref => unreachable,
526529 }
527530 }
......@@ -533,7 +536,7 @@ pub const Scope = struct {
533536 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
534537 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
535538 .file => null,
536 .container => null,
539 .namespace => null,
537540 .decl_ref => scope.cast(DeclRef).?.decl,
538541 };
539542 }
......@@ -545,36 +548,21 @@ pub const Scope = struct {
545548 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
546549 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
547550 .file => null,
548 .container => null,
551 .namespace => null,
549552 .decl_ref => scope.cast(DeclRef).?.decl,
550553 };
551554 }
552555
553 /// Asserts the scope has a parent which is a Container and returns it.
554 pub fn namespace(scope: *Scope) *Container {
556 /// Asserts the scope has a parent which is a Namespace and returns it.
557 pub fn namespace(scope: *Scope) *Namespace {
555558 switch (scope.tag) {
556 .block => return scope.cast(Block).?.sema.owner_decl.container,
557 .gen_zir => return scope.cast(GenZir).?.astgen.decl.container,
558 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.container,
559 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.container,
560 .file => return &scope.cast(File).?.root_container,
561 .container => return scope.cast(Container).?,
562 .decl_ref => return scope.cast(DeclRef).?.decl.container,
563 }
564 }
565
566 /// Must generate unique bytes with no collisions with other decls.
567 /// The point of hashing here is only to limit the number of bytes of
568 /// the unique identifier to a fixed size (16 bytes).
569 pub fn fullyQualifiedNameHash(scope: *Scope, name: []const u8) NameHash {
570 switch (scope.tag) {
571 .block => unreachable,
572 .gen_zir => unreachable,
573 .local_val => unreachable,
574 .local_ptr => unreachable,
575 .file => unreachable,
576 .container => return scope.cast(Container).?.fullyQualifiedNameHash(name),
577 .decl_ref => unreachable,
559 .block => return scope.cast(Block).?.sema.owner_decl.namespace,
560 .gen_zir => return scope.cast(GenZir).?.astgen.decl.namespace,
561 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace,
562 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace,
563 .file => return scope.cast(File).?.namespace,
564 .namespace => return scope.cast(Namespace).?,
565 .decl_ref => return scope.cast(DeclRef).?.decl.namespace,
578566 }
579567 }
580568
......@@ -582,12 +570,12 @@ pub const Scope = struct {
582570 pub fn tree(scope: *Scope) *const ast.Tree {
583571 switch (scope.tag) {
584572 .file => return &scope.cast(File).?.tree,
585 .block => return &scope.cast(Block).?.src_decl.container.file_scope.tree,
573 .block => return &scope.cast(Block).?.src_decl.namespace.file_scope.tree,
586574 .gen_zir => return scope.cast(GenZir).?.tree(),
587 .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.container.file_scope.tree,
588 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.container.file_scope.tree,
589 .container => return &scope.cast(Container).?.file_scope.tree,
590 .decl_ref => return &scope.cast(DeclRef).?.decl.container.file_scope.tree,
575 .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace.file_scope.tree,
576 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace.file_scope.tree,
577 .namespace => return &scope.cast(Namespace).?.file_scope.tree,
578 .decl_ref => return &scope.cast(DeclRef).?.decl.namespace.file_scope.tree,
591579 }
592580 }
593581
......@@ -599,16 +587,16 @@ pub const Scope = struct {
599587 .local_val => return scope.cast(LocalVal).?.gen_zir,
600588 .local_ptr => return scope.cast(LocalPtr).?.gen_zir,
601589 .file => unreachable,
602 .container => unreachable,
590 .namespace => unreachable,
603591 .decl_ref => unreachable,
604592 };
605593 }
606594
607 /// Asserts the scope has a parent which is a Container or File and
595 /// Asserts the scope has a parent which is a Namespace or File and
608596 /// returns the sub_file_path field.
609597 pub fn subFilePath(base: *Scope) []const u8 {
610598 switch (base.tag) {
611 .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,
599 .namespace => return @fieldParentPtr(Namespace, "base", base).file_scope.sub_file_path,
612600 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
613601 .block => unreachable,
614602 .gen_zir => unreachable,
......@@ -618,30 +606,18 @@ pub const Scope = struct {
618606 }
619607 }
620608
621 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
622 switch (base.tag) {
623 .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),
624 .file => return @fieldParentPtr(File, "base", base).getSource(module),
625 .gen_zir => unreachable,
626 .local_val => unreachable,
627 .local_ptr => unreachable,
628 .block => unreachable,
629 .decl_ref => unreachable,
630 }
631 }
632
633609 /// When called from inside a Block Scope, chases the src_decl, not the owner_decl.
634610 pub fn getFileScope(base: *Scope) *Scope.File {
635611 var cur = base;
636612 while (true) {
637613 cur = switch (cur.tag) {
638 .container => return @fieldParentPtr(Container, "base", cur).file_scope,
614 .namespace => return @fieldParentPtr(Namespace, "base", cur).file_scope,
639615 .file => return @fieldParentPtr(File, "base", cur),
640616 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
641617 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
642618 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
643 .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope,
644 .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.container.file_scope,
619 .block => return @fieldParentPtr(Block, "base", cur).src_decl.namespace.file_scope,
620 .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.namespace.file_scope,
645621 };
646622 }
647623 }
......@@ -657,8 +633,8 @@ pub const Scope = struct {
657633 pub const Tag = enum {
658634 /// .zig source code.
659635 file,
660 /// struct, enum or union, every .file contains one of these.
661 container,
636 /// Namespace owned by structs, enums, unions, and opaques for decls.
637 namespace,
662638 block,
663639 gen_zir,
664640 local_val,
......@@ -669,37 +645,44 @@ pub const Scope = struct {
669645 decl_ref,
670646 };
671647
672 pub const Container = struct {
673 pub const base_tag: Tag = .container;
648 /// The container that structs, enums, unions, and opaques have.
649 pub const Namespace = struct {
650 pub const base_tag: Tag = .namespace;
674651 base: Scope = Scope{ .tag = base_tag },
675652
653 parent: ?*Namespace,
676654 file_scope: *Scope.File,
677655 parent_name_hash: NameHash,
678
679 /// Direct children of the file.
680 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
656 /// Will be a struct, enum, union, or opaque.
681657 ty: Type,
658 /// Direct children of the namespace. Used during an update to detect
659 /// which decls have been added/removed from source.
660 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
682661
683 pub fn deinit(cont: *Container, gpa: *Allocator) void {
684 cont.decls.deinit(gpa);
685 // TODO either Container of File should have an arena for sub_file_path and ty
686 gpa.destroy(cont.ty.castTag(.empty_struct).?);
687 gpa.free(cont.file_scope.sub_file_path);
688 cont.* = undefined;
662 pub fn deinit(ns: *Namespace, gpa: *Allocator) void {
663 ns.decls.deinit(gpa);
664 ns.* = undefined;
689665 }
690666
691 pub fn removeDecl(cont: *Container, child: *Decl) void {
692 _ = cont.decls.swapRemove(child);
667 pub fn removeDecl(ns: *Namespace, child: *Decl) void {
668 _ = ns.decls.swapRemove(child);
693669 }
694670
695 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
696 return std.zig.hashName(cont.parent_name_hash, ".", name);
671 /// Must generate unique bytes with no collisions with other decls.
672 /// The point of hashing here is only to limit the number of bytes of
673 /// the unique identifier to a fixed size (16 bytes).
674 pub fn fullyQualifiedNameHash(ns: Namespace, name: []const u8) NameHash {
675 return std.zig.hashName(ns.parent_name_hash, ".", name);
697676 }
698677
699 pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {
678 pub fn renderFullyQualifiedName(ns: Namespace, name: []const u8, writer: anytype) !void {
700679 // TODO this should render e.g. "std.fs.Dir.OpenOptions"
701680 return writer.writeAll(name);
702681 }
682
683 pub fn getDecl(ns: Namespace) *Decl {
684 return ns.ty.getOwnerDecl();
685 }
703686 };
704687
705688 pub const File = struct {
......@@ -711,46 +694,54 @@ pub const Scope = struct {
711694 unloaded_parse_failure,
712695 loaded_success,
713696 },
714
697 source_loaded: bool,
715698 /// Relative to the owning package's root_src_dir.
716 /// Reference to external memory, not owned by File.
699 /// Memory is stored in gpa, owned by File.
717700 sub_file_path: []const u8,
718 source: union(enum) {
719 unloaded: void,
720 bytes: [:0]const u8,
721 },
701 /// Whether this is populated depends on `source_loaded`.
702 source: [:0]const u8,
703 /// Whether this is populated depends on `status`.
704 stat_size: u64,
705 /// Whether this is populated depends on `status`.
706 stat_inode: std.fs.File.INode,
707 /// Whether this is populated depends on `status`.
708 stat_mtime: i128,
709 /// Whether this is populated depends on `status`.
710 source_hash: Cache.BinDigest,
722711 /// Whether this is populated or not depends on `status`.
723712 tree: ast.Tree,
724713 /// Package that this file is a part of, managed externally.
725714 pkg: *Package,
726
727 root_container: Container,
715 /// The namespace of the struct that represents this file.
716 namespace: *Namespace,
728717
729718 pub fn unload(file: *File, gpa: *Allocator) void {
730 switch (file.status) {
731 .unloaded_parse_failure,
732 .never_loaded,
733 .unloaded_success,
734 => {
735 file.status = .unloaded_success;
736 },
719 file.unloadTree(gpa);
720 file.unloadSource(gpa);
721 }
737722
738 .loaded_success => {
739 file.tree.deinit(gpa);
740 file.status = .unloaded_success;
741 },
723 pub fn unloadTree(file: *File, gpa: *Allocator) void {
724 if (file.status == .loaded_success) {
725 file.tree.deinit(gpa);
742726 }
743 switch (file.source) {
744 .bytes => |bytes| {
745 gpa.free(bytes);
746 file.source = .{ .unloaded = {} };
747 },
748 .unloaded => {},
727 file.status = .unloaded_success;
728 }
729
730 pub fn unloadSource(file: *File, gpa: *Allocator) void {
731 if (file.source_loaded) {
732 file.source_loaded = false;
733 gpa.free(file.source);
734 }
735 }
736
737 pub fn updateTreeToNewSource(file: *File) void {
738 assert(file.source_loaded);
739 if (file.status == .loaded_success) {
740 file.tree.source = file.source;
749741 }
750742 }
751743
752744 pub fn deinit(file: *File, gpa: *Allocator) void {
753 file.root_container.deinit(gpa);
754745 file.unload(gpa);
755746 file.* = undefined;
756747 }
......@@ -765,22 +756,44 @@ pub const Scope = struct {
765756 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
766757 }
767758
768 pub fn getSource(file: *File, module: *Module) ![:0]const u8 {
769 switch (file.source) {
770 .unloaded => {
771 const source = try file.pkg.root_src_directory.handle.readFileAllocOptions(
772 module.gpa,
773 file.sub_file_path,
774 std.math.maxInt(u32),
775 null,
776 1,
777 0,
778 );
779 file.source = .{ .bytes = source };
780 return source;
781 },
782 .bytes => |bytes| return bytes,
783 }
759 pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {
760 if (file.source_loaded) return file.source;
761
762 // Keep track of inode, file size, mtime, hash so we can detect which files
763 // have been modified when an incremental update is requested.
764 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
765 defer f.close();
766
767 const stat = try f.stat();
768
769 try file.finishGettingSource(gpa, f, stat);
770 assert(file.source_loaded);
771 return file.source;
772 }
773
774 pub fn finishGettingSource(
775 file: *File,
776 gpa: *Allocator,
777 f: std.fs.File,
778 stat: std.fs.File.Stat,
779 ) !void {
780 if (stat.size > std.math.maxInt(u32))
781 return error.FileTooBig;
782
783 const source = try gpa.allocSentinel(u8, stat.size, 0);
784 const amt = try f.readAll(source);
785 if (amt != stat.size)
786 return error.UnexpectedEndOfFile;
787
788 var hasher = Cache.hasher_init;
789 hasher.update(source);
790 hasher.final(&file.source_hash);
791
792 file.stat_size = stat.size;
793 file.stat_inode = stat.inode;
794 file.stat_mtime = stat.mtime;
795 file.source = source;
796 file.source_loaded = true;
784797 }
785798 };
786799
......@@ -859,7 +872,7 @@ pub const Scope = struct {
859872 }
860873
861874 pub fn getFileScope(block: *Block) *Scope.File {
862 return block.src_decl.container.file_scope;
875 return block.src_decl.namespace.file_scope;
863876 }
864877
865878 pub fn addNoOp(
......@@ -1110,7 +1123,7 @@ pub const Scope = struct {
11101123 }
11111124
11121125 pub fn tree(gz: *const GenZir) *const ast.Tree {
1113 return &gz.astgen.decl.container.file_scope.tree;
1126 return &gz.astgen.decl.namespace.file_scope.tree;
11141127 }
11151128
11161129 pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
......@@ -1678,7 +1691,7 @@ pub const SrcLoc = struct {
16781691 .node_offset_switch_range,
16791692 .node_offset_fn_type_cc,
16801693 .node_offset_fn_type_ret_ty,
1681 => src_loc.container.decl.container.file_scope,
1694 => src_loc.container.decl.namespace.file_scope,
16821695 };
16831696 }
16841697
......@@ -1706,14 +1719,14 @@ pub const SrcLoc = struct {
17061719 .token_offset => |tok_off| {
17071720 const decl = src_loc.container.decl;
17081721 const tok_index = decl.srcToken() + tok_off;
1709 const tree = decl.container.file_scope.base.tree();
1722 const tree = decl.namespace.file_scope.base.tree();
17101723 const token_starts = tree.tokens.items(.start);
17111724 return token_starts[tok_index];
17121725 },
17131726 .node_offset, .node_offset_bin_op => |node_off| {
17141727 const decl = src_loc.container.decl;
17151728 const node = decl.relativeToNodeIndex(node_off);
1716 const tree = decl.container.file_scope.base.tree();
1729 const tree = decl.namespace.file_scope.base.tree();
17171730 const main_tokens = tree.nodes.items(.main_token);
17181731 const tok_index = main_tokens[node];
17191732 const token_starts = tree.tokens.items(.start);
......@@ -1722,7 +1735,7 @@ pub const SrcLoc = struct {
17221735 .node_offset_back2tok => |node_off| {
17231736 const decl = src_loc.container.decl;
17241737 const node = decl.relativeToNodeIndex(node_off);
1725 const tree = decl.container.file_scope.base.tree();
1738 const tree = decl.namespace.file_scope.base.tree();
17261739 const tok_index = tree.firstToken(node) - 2;
17271740 const token_starts = tree.tokens.items(.start);
17281741 return token_starts[tok_index];
......@@ -1730,7 +1743,7 @@ pub const SrcLoc = struct {
17301743 .node_offset_var_decl_ty => |node_off| {
17311744 const decl = src_loc.container.decl;
17321745 const node = decl.relativeToNodeIndex(node_off);
1733 const tree = decl.container.file_scope.base.tree();
1746 const tree = decl.namespace.file_scope.base.tree();
17341747 const node_tags = tree.nodes.items(.tag);
17351748 const full = switch (node_tags[node]) {
17361749 .global_var_decl => tree.globalVarDecl(node),
......@@ -1750,7 +1763,7 @@ pub const SrcLoc = struct {
17501763 },
17511764 .node_offset_builtin_call_arg0 => |node_off| {
17521765 const decl = src_loc.container.decl;
1753 const tree = decl.container.file_scope.base.tree();
1766 const tree = decl.namespace.file_scope.base.tree();
17541767 const node_datas = tree.nodes.items(.data);
17551768 const node_tags = tree.nodes.items(.tag);
17561769 const node = decl.relativeToNodeIndex(node_off);
......@@ -1766,7 +1779,7 @@ pub const SrcLoc = struct {
17661779 },
17671780 .node_offset_builtin_call_arg1 => |node_off| {
17681781 const decl = src_loc.container.decl;
1769 const tree = decl.container.file_scope.base.tree();
1782 const tree = decl.namespace.file_scope.base.tree();
17701783 const node_datas = tree.nodes.items(.data);
17711784 const node_tags = tree.nodes.items(.tag);
17721785 const node = decl.relativeToNodeIndex(node_off);
......@@ -1782,7 +1795,7 @@ pub const SrcLoc = struct {
17821795 },
17831796 .node_offset_array_access_index => |node_off| {
17841797 const decl = src_loc.container.decl;
1785 const tree = decl.container.file_scope.base.tree();
1798 const tree = decl.namespace.file_scope.base.tree();
17861799 const node_datas = tree.nodes.items(.data);
17871800 const node_tags = tree.nodes.items(.tag);
17881801 const node = decl.relativeToNodeIndex(node_off);
......@@ -1793,7 +1806,7 @@ pub const SrcLoc = struct {
17931806 },
17941807 .node_offset_slice_sentinel => |node_off| {
17951808 const decl = src_loc.container.decl;
1796 const tree = decl.container.file_scope.base.tree();
1809 const tree = decl.namespace.file_scope.base.tree();
17971810 const node_datas = tree.nodes.items(.data);
17981811 const node_tags = tree.nodes.items(.tag);
17991812 const node = decl.relativeToNodeIndex(node_off);
......@@ -1810,7 +1823,7 @@ pub const SrcLoc = struct {
18101823 },
18111824 .node_offset_call_func => |node_off| {
18121825 const decl = src_loc.container.decl;
1813 const tree = decl.container.file_scope.base.tree();
1826 const tree = decl.namespace.file_scope.base.tree();
18141827 const node_datas = tree.nodes.items(.data);
18151828 const node_tags = tree.nodes.items(.tag);
18161829 const node = decl.relativeToNodeIndex(node_off);
......@@ -1837,7 +1850,7 @@ pub const SrcLoc = struct {
18371850 },
18381851 .node_offset_field_name => |node_off| {
18391852 const decl = src_loc.container.decl;
1840 const tree = decl.container.file_scope.base.tree();
1853 const tree = decl.namespace.file_scope.base.tree();
18411854 const node_datas = tree.nodes.items(.data);
18421855 const node_tags = tree.nodes.items(.tag);
18431856 const node = decl.relativeToNodeIndex(node_off);
......@@ -1850,7 +1863,7 @@ pub const SrcLoc = struct {
18501863 },
18511864 .node_offset_deref_ptr => |node_off| {
18521865 const decl = src_loc.container.decl;
1853 const tree = decl.container.file_scope.base.tree();
1866 const tree = decl.namespace.file_scope.base.tree();
18541867 const node_datas = tree.nodes.items(.data);
18551868 const node_tags = tree.nodes.items(.tag);
18561869 const node = decl.relativeToNodeIndex(node_off);
......@@ -1860,7 +1873,7 @@ pub const SrcLoc = struct {
18601873 },
18611874 .node_offset_asm_source => |node_off| {
18621875 const decl = src_loc.container.decl;
1863 const tree = decl.container.file_scope.base.tree();
1876 const tree = decl.namespace.file_scope.base.tree();
18641877 const node_datas = tree.nodes.items(.data);
18651878 const node_tags = tree.nodes.items(.tag);
18661879 const node = decl.relativeToNodeIndex(node_off);
......@@ -1876,7 +1889,7 @@ pub const SrcLoc = struct {
18761889 },
18771890 .node_offset_asm_ret_ty => |node_off| {
18781891 const decl = src_loc.container.decl;
1879 const tree = decl.container.file_scope.base.tree();
1892 const tree = decl.namespace.file_scope.base.tree();
18801893 const node_datas = tree.nodes.items(.data);
18811894 const node_tags = tree.nodes.items(.tag);
18821895 const node = decl.relativeToNodeIndex(node_off);
......@@ -1894,7 +1907,7 @@ pub const SrcLoc = struct {
18941907 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
18951908 const decl = src_loc.container.decl;
18961909 const node = decl.relativeToNodeIndex(node_off);
1897 const tree = decl.container.file_scope.base.tree();
1910 const tree = decl.namespace.file_scope.base.tree();
18981911 const node_tags = tree.nodes.items(.tag);
18991912 const src_node = switch (node_tags[node]) {
19001913 .if_simple => tree.ifSimple(node).ast.cond_expr,
......@@ -1914,7 +1927,7 @@ pub const SrcLoc = struct {
19141927 .node_offset_bin_lhs => |node_off| {
19151928 const decl = src_loc.container.decl;
19161929 const node = decl.relativeToNodeIndex(node_off);
1917 const tree = decl.container.file_scope.base.tree();
1930 const tree = decl.namespace.file_scope.base.tree();
19181931 const node_datas = tree.nodes.items(.data);
19191932 const src_node = node_datas[node].lhs;
19201933 const main_tokens = tree.nodes.items(.main_token);
......@@ -1925,7 +1938,7 @@ pub const SrcLoc = struct {
19251938 .node_offset_bin_rhs => |node_off| {
19261939 const decl = src_loc.container.decl;
19271940 const node = decl.relativeToNodeIndex(node_off);
1928 const tree = decl.container.file_scope.base.tree();
1941 const tree = decl.namespace.file_scope.base.tree();
19291942 const node_datas = tree.nodes.items(.data);
19301943 const src_node = node_datas[node].rhs;
19311944 const main_tokens = tree.nodes.items(.main_token);
......@@ -1937,7 +1950,7 @@ pub const SrcLoc = struct {
19371950 .node_offset_switch_operand => |node_off| {
19381951 const decl = src_loc.container.decl;
19391952 const node = decl.relativeToNodeIndex(node_off);
1940 const tree = decl.container.file_scope.base.tree();
1953 const tree = decl.namespace.file_scope.base.tree();
19411954 const node_datas = tree.nodes.items(.data);
19421955 const src_node = node_datas[node].lhs;
19431956 const main_tokens = tree.nodes.items(.main_token);
......@@ -1949,7 +1962,7 @@ pub const SrcLoc = struct {
19491962 .node_offset_switch_special_prong => |node_off| {
19501963 const decl = src_loc.container.decl;
19511964 const switch_node = decl.relativeToNodeIndex(node_off);
1952 const tree = decl.container.file_scope.base.tree();
1965 const tree = decl.namespace.file_scope.base.tree();
19531966 const node_datas = tree.nodes.items(.data);
19541967 const node_tags = tree.nodes.items(.tag);
19551968 const main_tokens = tree.nodes.items(.main_token);
......@@ -1976,7 +1989,7 @@ pub const SrcLoc = struct {
19761989 .node_offset_switch_range => |node_off| {
19771990 const decl = src_loc.container.decl;
19781991 const switch_node = decl.relativeToNodeIndex(node_off);
1979 const tree = decl.container.file_scope.base.tree();
1992 const tree = decl.namespace.file_scope.base.tree();
19801993 const node_datas = tree.nodes.items(.data);
19811994 const node_tags = tree.nodes.items(.tag);
19821995 const main_tokens = tree.nodes.items(.main_token);
......@@ -2006,7 +2019,7 @@ pub const SrcLoc = struct {
20062019
20072020 .node_offset_fn_type_cc => |node_off| {
20082021 const decl = src_loc.container.decl;
2009 const tree = decl.container.file_scope.base.tree();
2022 const tree = decl.namespace.file_scope.base.tree();
20102023 const node_datas = tree.nodes.items(.data);
20112024 const node_tags = tree.nodes.items(.tag);
20122025 const node = decl.relativeToNodeIndex(node_off);
......@@ -2026,7 +2039,7 @@ pub const SrcLoc = struct {
20262039
20272040 .node_offset_fn_type_ret_ty => |node_off| {
20282041 const decl = src_loc.container.decl;
2029 const tree = decl.container.file_scope.base.tree();
2042 const tree = decl.namespace.file_scope.base.tree();
20302043 const node_datas = tree.nodes.items(.data);
20312044 const node_tags = tree.nodes.items(.tag);
20322045 const node = decl.relativeToNodeIndex(node_off);
......@@ -2351,7 +2364,6 @@ pub fn deinit(mod: *Module) void {
23512364 mod.export_owners.deinit(gpa);
23522365
23532366 mod.symbol_exports.deinit(gpa);
2354 mod.root_scope.destroy(gpa);
23552367
23562368 var it = mod.global_error_set.iterator();
23572369 while (it.next()) |entry| {
......@@ -2362,6 +2374,7 @@ pub fn deinit(mod: *Module) void {
23622374 mod.error_name_list.deinit(gpa);
23632375
23642376 for (mod.import_table.items()) |entry| {
2377 gpa.free(entry.key);
23652378 entry.value.destroy(gpa);
23662379 }
23672380 mod.import_table.deinit(gpa);
......@@ -2465,7 +2478,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
24652478 const tracy = trace(@src());
24662479 defer tracy.end();
24672480
2468 const tree = try mod.getAstTree(decl.container.file_scope);
2481 const tree = try mod.getAstTree(decl.namespace.file_scope);
24692482 const node_tags = tree.nodes.items(.tag);
24702483 const node_datas = tree.nodes.items(.data);
24712484 const decl_node = decl.src_node;
......@@ -2516,7 +2529,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
25162529
25172530 var gen_scope: Scope.GenZir = .{
25182531 .force_comptime = true,
2519 .parent = &decl.container.base,
2532 .parent = &decl.namespace.base,
25202533 .astgen = &astgen,
25212534 };
25222535 defer gen_scope.instructions.deinit(mod.gpa);
......@@ -2590,7 +2603,7 @@ fn astgenAndSemaFn(
25902603
25912604 var fn_type_scope: Scope.GenZir = .{
25922605 .force_comptime = true,
2593 .parent = &decl.container.base,
2606 .parent = &decl.namespace.base,
25942607 .astgen = &fn_type_astgen,
25952608 };
25962609 defer fn_type_scope.instructions.deinit(mod.gpa);
......@@ -2829,7 +2842,7 @@ fn astgenAndSemaFn(
28292842
28302843 var gen_scope: Scope.GenZir = .{
28312844 .force_comptime = false,
2832 .parent = &decl.container.base,
2845 .parent = &decl.namespace.base,
28332846 .astgen = &astgen,
28342847 };
28352848 defer gen_scope.instructions.deinit(mod.gpa);
......@@ -3035,7 +3048,7 @@ fn astgenAndSemaVarDecl(
30353048
30363049 var gen_scope: Scope.GenZir = .{
30373050 .force_comptime = true,
3038 .parent = &decl.container.base,
3051 .parent = &decl.namespace.base,
30393052 .astgen = &astgen,
30403053 };
30413054 defer gen_scope.instructions.deinit(mod.gpa);
......@@ -3104,7 +3117,7 @@ fn astgenAndSemaVarDecl(
31043117
31053118 var type_scope: Scope.GenZir = .{
31063119 .force_comptime = true,
3107 .parent = &decl.container.base,
3120 .parent = &decl.namespace.base,
31083121 .astgen = &astgen,
31093122 };
31103123 defer type_scope.instructions.deinit(mod.gpa);
......@@ -3220,46 +3233,48 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3
32203233 return @intCast(u32, gop.index);
32213234}
32223235
3223pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
3236pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree {
32243237 const tracy = trace(@src());
32253238 defer tracy.end();
32263239
3227 switch (root_scope.status) {
3240 switch (file.status) {
32283241 .never_loaded, .unloaded_success => {
3229 try mod.failed_files.ensureCapacity(mod.gpa, mod.failed_files.items().len + 1);
3242 const gpa = mod.gpa;
3243
3244 try mod.failed_files.ensureCapacity(gpa, mod.failed_files.items().len + 1);
32303245
3231 const source = try root_scope.getSource(mod);
3246 const source = try file.getSource(gpa);
32323247
32333248 var keep_tree = false;
3234 root_scope.tree = try std.zig.parse(mod.gpa, source);
3235 defer if (!keep_tree) root_scope.tree.deinit(mod.gpa);
3249 file.tree = try std.zig.parse(gpa, source);
3250 defer if (!keep_tree) file.tree.deinit(gpa);
32363251
3237 const tree = &root_scope.tree;
3252 const tree = &file.tree;
32383253
32393254 if (tree.errors.len != 0) {
32403255 const parse_err = tree.errors[0];
32413256
3242 var msg = std.ArrayList(u8).init(mod.gpa);
3257 var msg = std.ArrayList(u8).init(gpa);
32433258 defer msg.deinit();
32443259
32453260 const token_starts = tree.tokens.items(.start);
32463261
32473262 try tree.renderError(parse_err, msg.writer());
3248 const err_msg = try mod.gpa.create(ErrorMsg);
3263 const err_msg = try gpa.create(ErrorMsg);
32493264 err_msg.* = .{
32503265 .src_loc = .{
3251 .container = .{ .file_scope = root_scope },
3266 .container = .{ .file_scope = file },
32523267 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
32533268 },
32543269 .msg = msg.toOwnedSlice(),
32553270 };
32563271
3257 mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg);
3258 root_scope.status = .unloaded_parse_failure;
3272 mod.failed_files.putAssumeCapacityNoClobber(file, err_msg);
3273 file.status = .unloaded_parse_failure;
32593274 return error.AnalysisFail;
32603275 }
32613276
3262 root_scope.status = .loaded_success;
3277 file.status = .loaded_success;
32633278 keep_tree = true;
32643279
32653280 return tree;
......@@ -3267,30 +3282,186 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
32673282
32683283 .unloaded_parse_failure => return error.AnalysisFail,
32693284
3270 .loaded_success => return &root_scope.tree,
3285 .loaded_success => return &file.tree,
32713286 }
32723287}
32733288
3274pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3289pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*Scope.File {
3290 const gpa = mod.gpa;
3291
3292 const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
3293 const found_pkg = cur_pkg.table.get(import_string);
3294
3295 const resolved_path = if (found_pkg) |pkg|
3296 try std.fs.path.resolve(gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path })
3297 else
3298 try std.fs.path.resolve(gpa, &[_][]const u8{ cur_pkg_dir_path, import_string });
3299 var keep_resolved_path = false;
3300 defer if (!keep_resolved_path) gpa.free(resolved_path);
3301
3302 const gop = try mod.import_table.getOrPut(gpa, resolved_path);
3303 if (gop.found_existing) return gop.entry.value;
3304
3305 if (found_pkg == null) {
3306 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
3307 defer gpa.free(resolved_root_path);
3308
3309 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
3310 return error.ImportOutsidePkgPath;
3311 }
3312 }
3313
3314 const new_file = try gpa.create(Scope.File);
3315 gop.entry.value = new_file;
3316 new_file.* = .{
3317 .sub_file_path = resolved_path,
3318 .source = undefined,
3319 .source_hash = undefined,
3320 .source_loaded = false,
3321 .stat_size = undefined,
3322 .stat_inode = undefined,
3323 .stat_mtime = undefined,
3324 .tree = undefined,
3325 .status = .never_loaded,
3326 .pkg = found_pkg orelse cur_pkg,
3327 .namespace = undefined,
3328 };
3329 keep_resolved_path = true;
3330
3331 const tree = try mod.getAstTree(new_file);
3332
3333 const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg|
3334 pkg.namespace_hash
3335 else
3336 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
3337
3338 // We need a Decl to pass to AstGen and collect dependencies. But ultimately we
3339 // want to pass them on to the Decl for the struct that represents the file.
3340 var tmp_namespace: Scope.Namespace = .{
3341 .parent = null,
3342 .file_scope = new_file,
3343 .parent_name_hash = parent_name_hash,
3344 .ty = Type.initTag(.type),
3345 };
3346 const top_decl = try mod.createNewDecl(
3347 &tmp_namespace,
3348 resolved_path,
3349 0,
3350 parent_name_hash,
3351 new_file.source_hash,
3352 );
3353 defer {
3354 mod.decl_table.removeAssertDiscard(parent_name_hash);
3355 top_decl.destroy(mod);
3356 }
3357
3358 var gen_scope_arena = std.heap.ArenaAllocator.init(gpa);
3359 defer gen_scope_arena.deinit();
3360
3361 var astgen = try AstGen.init(mod, top_decl, &gen_scope_arena.allocator);
3362 defer astgen.deinit();
3363
3364 var gen_scope: Scope.GenZir = .{
3365 .force_comptime = true,
3366 .parent = &new_file.base,
3367 .astgen = &astgen,
3368 };
3369 defer gen_scope.instructions.deinit(gpa);
3370
3371 const container_decl: ast.full.ContainerDecl = .{
3372 .layout_token = null,
3373 .ast = .{
3374 .main_token = undefined,
3375 .enum_token = null,
3376 .members = tree.rootDecls(),
3377 .arg = 0,
3378 },
3379 };
3380
3381 const struct_decl_ref = try AstGen.structDeclInner(
3382 &gen_scope,
3383 &gen_scope.base,
3384 0,
3385 container_decl,
3386 .struct_decl,
3387 );
3388 _ = try gen_scope.addBreak(.break_inline, 0, struct_decl_ref);
3389
3390 var code = try gen_scope.finish();
3391 defer code.deinit(gpa);
3392 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
3393 code.dump(gpa, "import", &gen_scope.base, 0) catch {};
3394 }
3395
3396 var sema: Sema = .{
3397 .mod = mod,
3398 .gpa = gpa,
3399 .arena = &gen_scope_arena.allocator,
3400 .code = code,
3401 .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len),
3402 .owner_decl = top_decl,
3403 .func = null,
3404 .owner_func = null,
3405 .param_inst_list = &.{},
3406 };
3407 var block_scope: Scope.Block = .{
3408 .parent = null,
3409 .sema = &sema,
3410 .src_decl = top_decl,
3411 .instructions = .{},
3412 .inlining = null,
3413 .is_comptime = true,
3414 };
3415 defer block_scope.instructions.deinit(gpa);
3416
3417 const init_inst_zir_ref = try sema.rootAsRef(&block_scope);
3418 const analyzed_struct_inst = try sema.resolveInst(init_inst_zir_ref);
3419 assert(analyzed_struct_inst.ty.zigTypeTag() == .Type);
3420 const val = analyzed_struct_inst.value().?;
3421 const struct_ty = try val.toType(&gen_scope_arena.allocator);
3422 const struct_decl = struct_ty.getOwnerDecl();
3423
3424 new_file.namespace = struct_ty.getNamespace().?;
3425 new_file.namespace.parent = null;
3426 new_file.namespace.parent_name_hash = tmp_namespace.parent_name_hash;
3427
3428 // Transfer the dependencies to `owner_decl`.
3429 assert(top_decl.dependants.count() == 0);
3430 for (top_decl.dependencies.items()) |entry| {
3431 const dep = entry.key;
3432 dep.removeDependant(top_decl);
3433 if (dep == struct_decl) continue;
3434 _ = try mod.declareDeclDependency(struct_decl, dep);
3435 }
3436
3437 try mod.analyzeFile(new_file);
3438 return new_file;
3439}
3440
3441pub fn analyzeFile(mod: *Module, file: *Scope.File) !void {
3442 return mod.analyzeNamespace(file.namespace);
3443}
3444
3445pub fn analyzeNamespace(mod: *Module, namespace: *Scope.Namespace) !void {
32753446 const tracy = trace(@src());
32763447 defer tracy.end();
32773448
32783449 // We may be analyzing it for the first time, or this may be
32793450 // an incremental update. This code handles both cases.
3280 const tree = try mod.getAstTree(container_scope.file_scope);
3451 const tree = try mod.getAstTree(namespace.file_scope);
32813452 const node_tags = tree.nodes.items(.tag);
32823453 const node_datas = tree.nodes.items(.data);
32833454 const decls = tree.rootDecls();
32843455
32853456 try mod.comp.work_queue.ensureUnusedCapacity(decls.len);
3286 try container_scope.decls.ensureCapacity(mod.gpa, decls.len);
3457 try namespace.decls.ensureCapacity(mod.gpa, decls.len);
32873458
3288 // Keep track of the decls that we expect to see in this file so that
3459 // Keep track of the decls that we expect to see in this namespace so that
32893460 // we know which ones have been deleted.
32903461 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);
32913462 defer deleted_decls.deinit();
3292 try deleted_decls.ensureCapacity(container_scope.decls.items().len);
3293 for (container_scope.decls.items()) |entry| {
3463 try deleted_decls.ensureCapacity(namespace.decls.items().len);
3464 for (namespace.decls.items()) |entry| {
32943465 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
32953466 }
32963467
......@@ -3310,7 +3481,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33103481 .fn_proto_simple => {
33113482 var params: [1]ast.Node.Index = undefined;
33123483 try mod.semaContainerFn(
3313 container_scope,
3484 namespace,
33143485 &deleted_decls,
33153486 &outdated_decls,
33163487 decl_node,
......@@ -3320,7 +3491,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33203491 );
33213492 },
33223493 .fn_proto_multi => try mod.semaContainerFn(
3323 container_scope,
3494 namespace,
33243495 &deleted_decls,
33253496 &outdated_decls,
33263497 decl_node,
......@@ -3331,7 +3502,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33313502 .fn_proto_one => {
33323503 var params: [1]ast.Node.Index = undefined;
33333504 try mod.semaContainerFn(
3334 container_scope,
3505 namespace,
33353506 &deleted_decls,
33363507 &outdated_decls,
33373508 decl_node,
......@@ -3341,7 +3512,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33413512 );
33423513 },
33433514 .fn_proto => try mod.semaContainerFn(
3344 container_scope,
3515 namespace,
33453516 &deleted_decls,
33463517 &outdated_decls,
33473518 decl_node,
......@@ -3355,7 +3526,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33553526 .fn_proto_simple => {
33563527 var params: [1]ast.Node.Index = undefined;
33573528 try mod.semaContainerFn(
3358 container_scope,
3529 namespace,
33593530 &deleted_decls,
33603531 &outdated_decls,
33613532 decl_node,
......@@ -3365,7 +3536,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33653536 );
33663537 },
33673538 .fn_proto_multi => try mod.semaContainerFn(
3368 container_scope,
3539 namespace,
33693540 &deleted_decls,
33703541 &outdated_decls,
33713542 decl_node,
......@@ -3376,7 +3547,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33763547 .fn_proto_one => {
33773548 var params: [1]ast.Node.Index = undefined;
33783549 try mod.semaContainerFn(
3379 container_scope,
3550 namespace,
33803551 &deleted_decls,
33813552 &outdated_decls,
33823553 decl_node,
......@@ -3386,7 +3557,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33863557 );
33873558 },
33883559 .fn_proto => try mod.semaContainerFn(
3389 container_scope,
3560 namespace,
33903561 &deleted_decls,
33913562 &outdated_decls,
33923563 decl_node,
......@@ -3396,7 +3567,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33963567 ),
33973568
33983569 .global_var_decl => try mod.semaContainerVar(
3399 container_scope,
3570 namespace,
34003571 &deleted_decls,
34013572 &outdated_decls,
34023573 decl_node,
......@@ -3404,7 +3575,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34043575 tree.globalVarDecl(decl_node),
34053576 ),
34063577 .local_var_decl => try mod.semaContainerVar(
3407 container_scope,
3578 namespace,
34083579 &deleted_decls,
34093580 &outdated_decls,
34103581 decl_node,
......@@ -3412,7 +3583,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34123583 tree.localVarDecl(decl_node),
34133584 ),
34143585 .simple_var_decl => try mod.semaContainerVar(
3415 container_scope,
3586 namespace,
34163587 &deleted_decls,
34173588 &outdated_decls,
34183589 decl_node,
......@@ -3420,7 +3591,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34203591 tree.simpleVarDecl(decl_node),
34213592 ),
34223593 .aligned_var_decl => try mod.semaContainerVar(
3423 container_scope,
3594 namespace,
34243595 &deleted_decls,
34253596 &outdated_decls,
34263597 decl_node,
......@@ -3433,11 +3604,11 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34333604 const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index});
34343605 defer mod.gpa.free(name);
34353606
3436 const name_hash = container_scope.fullyQualifiedNameHash(name);
3607 const name_hash = namespace.fullyQualifiedNameHash(name);
34373608 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
34383609
3439 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
3440 container_scope.decls.putAssumeCapacity(new_decl, {});
3610 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
3611 namespace.decls.putAssumeCapacity(new_decl, {});
34413612 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
34423613 },
34433614
......@@ -3483,7 +3654,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34833654
34843655fn semaContainerFn(
34853656 mod: *Module,
3486 container_scope: *Scope.Container,
3657 namespace: *Scope.Namespace,
34873658 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
34883659 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
34893660 decl_node: ast.Node.Index,
......@@ -3500,25 +3671,25 @@ fn semaContainerFn(
35003671 @panic("TODO missing function name");
35013672 };
35023673 const name = tree.tokenSlice(name_token); // TODO use identifierTokenString
3503 const name_hash = container_scope.fullyQualifiedNameHash(name);
3674 const name_hash = namespace.fullyQualifiedNameHash(name);
35043675 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
35053676 if (mod.decl_table.get(name_hash)) |decl| {
3506 // Update the AST Node index of the decl, even if its contents are unchanged, it may
3677 // Update the AST node of the decl; even if its contents are unchanged, it may
35073678 // have been re-ordered.
35083679 const prev_src_node = decl.src_node;
35093680 decl.src_node = decl_node;
35103681 if (deleted_decls.swapRemove(decl) == null) {
35113682 decl.analysis = .sema_failure;
35123683 const msg = try ErrorMsg.create(mod.gpa, .{
3513 .container = .{ .file_scope = container_scope.file_scope },
3684 .container = .{ .file_scope = namespace.file_scope },
35143685 .lazy = .{ .token_abs = name_token },
3515 }, "redefinition of '{s}'", .{decl.name});
3686 }, "redeclaration of '{s}'", .{decl.name});
35163687 errdefer msg.destroy(mod.gpa);
35173688 const other_src_loc: SrcLoc = .{
3518 .container = .{ .file_scope = decl.container.file_scope },
3689 .container = .{ .file_scope = decl.namespace.file_scope },
35193690 .lazy = .{ .node_abs = prev_src_node },
35203691 };
3521 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});
3692 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
35223693 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
35233694 } else {
35243695 if (!srcHashEql(decl.contents_hash, contents_hash)) {
......@@ -3542,8 +3713,8 @@ fn semaContainerFn(
35423713 }
35433714 }
35443715 } else {
3545 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
3546 container_scope.decls.putAssumeCapacity(new_decl, {});
3716 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
3717 namespace.decls.putAssumeCapacity(new_decl, {});
35473718 if (fn_proto.extern_export_token) |maybe_export_token| {
35483719 const token_tags = tree.tokens.items(.tag);
35493720 if (token_tags[maybe_export_token] == .keyword_export) {
......@@ -3556,7 +3727,7 @@ fn semaContainerFn(
35563727
35573728fn semaContainerVar(
35583729 mod: *Module,
3559 container_scope: *Scope.Container,
3730 namespace: *Scope.Namespace,
35603731 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
35613732 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
35623733 decl_node: ast.Node.Index,
......@@ -3568,7 +3739,7 @@ fn semaContainerVar(
35683739
35693740 const name_token = var_decl.ast.mut_token + 1;
35703741 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
3571 const name_hash = container_scope.fullyQualifiedNameHash(name);
3742 const name_hash = namespace.fullyQualifiedNameHash(name);
35723743 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
35733744 if (mod.decl_table.get(name_hash)) |decl| {
35743745 // Update the AST Node index of the decl, even if its contents are unchanged, it may
......@@ -3578,23 +3749,23 @@ fn semaContainerVar(
35783749 if (deleted_decls.swapRemove(decl) == null) {
35793750 decl.analysis = .sema_failure;
35803751 const msg = try ErrorMsg.create(mod.gpa, .{
3581 .container = .{ .file_scope = container_scope.file_scope },
3752 .container = .{ .file_scope = namespace.file_scope },
35823753 .lazy = .{ .token_abs = name_token },
3583 }, "redefinition of '{s}'", .{decl.name});
3754 }, "redeclaration of '{s}'", .{decl.name});
35843755 errdefer msg.destroy(mod.gpa);
35853756 const other_src_loc: SrcLoc = .{
3586 .container = .{ .file_scope = decl.container.file_scope },
3757 .container = .{ .file_scope = decl.namespace.file_scope },
35873758 .lazy = .{ .node_abs = prev_src_node },
35883759 };
3589 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});
3760 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
35903761 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
35913762 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
35923763 try outdated_decls.put(decl, {});
35933764 decl.contents_hash = contents_hash;
35943765 }
35953766 } else {
3596 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
3597 container_scope.decls.putAssumeCapacity(new_decl, {});
3767 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
3768 namespace.decls.putAssumeCapacity(new_decl, {});
35983769 if (var_decl.extern_export_token) |maybe_export_token| {
35993770 const token_tags = tree.tokens.items(.tag);
36003771 if (token_tags[maybe_export_token] == .keyword_export) {
......@@ -3624,7 +3795,7 @@ pub fn deleteDecl(
36243795
36253796 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
36263797 // not be present in the set, and this does nothing.
3627 decl.container.removeDecl(decl);
3798 decl.namespace.removeDecl(decl);
36283799
36293800 const name_hash = decl.fullyQualifiedNameHash();
36303801 mod.decl_table.removeAssertDiscard(name_hash);
......@@ -3786,7 +3957,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
37863957
37873958fn allocateNewDecl(
37883959 mod: *Module,
3789 scope: *Scope,
3960 namespace: *Scope.Namespace,
37903961 src_node: ast.Node.Index,
37913962 contents_hash: std.zig.SrcHash,
37923963) !*Decl {
......@@ -3802,7 +3973,7 @@ fn allocateNewDecl(
38023973
38033974 new_decl.* = .{
38043975 .name = "",
3805 .container = scope.namespace(),
3976 .namespace = namespace,
38063977 .src_node = src_node,
38073978 .typed_value = .{ .never_succeeded = {} },
38083979 .analysis = .unreferenced,
......@@ -3832,14 +4003,14 @@ fn allocateNewDecl(
38324003
38334004fn createNewDecl(
38344005 mod: *Module,
3835 scope: *Scope,
4006 namespace: *Scope.Namespace,
38364007 decl_name: []const u8,
38374008 src_node: ast.Node.Index,
38384009 name_hash: Scope.NameHash,
38394010 contents_hash: std.zig.SrcHash,
38404011) !*Decl {
38414012 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);
3842 const new_decl = try mod.allocateNewDecl(scope, src_node, contents_hash);
4013 const new_decl = try mod.allocateNewDecl(namespace, src_node, contents_hash);
38434014 errdefer mod.gpa.destroy(new_decl);
38444015 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
38454016 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
......@@ -3930,7 +4101,7 @@ pub fn analyzeExport(
39304101 );
39314102 errdefer msg.destroy(mod.gpa);
39324103 try mod.errNote(
3933 &other_export.owner_decl.container.base,
4104 &other_export.owner_decl.namespace.base,
39344105 other_export.src,
39354106 msg,
39364107 "other symbol here",
......@@ -4050,9 +4221,10 @@ pub fn createAnonymousDecl(
40504221 const scope_decl = scope.ownerDecl().?;
40514222 const name = try std.fmt.allocPrint(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
40524223 defer mod.gpa.free(name);
4053 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
4224 const namespace = scope_decl.namespace;
4225 const name_hash = namespace.fullyQualifiedNameHash(name);
40544226 const src_hash: std.zig.SrcHash = undefined;
4055 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
4227 const new_decl = try mod.createNewDecl(namespace, name, scope_decl.src_node, name_hash, src_hash);
40564228 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
40574229
40584230 decl_arena_state.* = decl_arena.state;
......@@ -4076,55 +4248,30 @@ pub fn createAnonymousDecl(
40764248 return new_decl;
40774249}
40784250
4079pub fn createContainerDecl(
4080 mod: *Module,
4081 scope: *Scope,
4082 base_token: std.zig.ast.TokenIndex,
4083 decl_arena: *std.heap.ArenaAllocator,
4084 typed_value: TypedValue,
4085) !*Decl {
4086 const scope_decl = scope.ownerDecl().?;
4087 const name = try mod.getAnonTypeName(scope, base_token);
4088 defer mod.gpa.free(name);
4089 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
4090 const src_hash: std.zig.SrcHash = undefined;
4091 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
4092 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
4093
4094 decl_arena_state.* = decl_arena.state;
4095 new_decl.typed_value = .{
4096 .most_recent = .{
4097 .typed_value = typed_value,
4098 .arena = decl_arena_state,
4099 },
4100 };
4101 new_decl.analysis = .complete;
4102 new_decl.generation = mod.generation;
4103
4104 return new_decl;
4105}
4106
4107fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
4108 // TODO add namespaces, generic function signatrues
4109 const tree = scope.tree();
4110 const token_tags = tree.tokens.items(.tag);
4111 const base_name = switch (token_tags[base_token]) {
4112 .keyword_struct => "struct",
4113 .keyword_enum => "enum",
4114 .keyword_union => "union",
4115 .keyword_opaque => "opaque",
4116 else => unreachable,
4117 };
4118 const loc = tree.tokenLocation(0, base_token);
4119 return std.fmt.allocPrint(mod.gpa, "{s}:{d}:{d}", .{ base_name, loc.line, loc.column });
4120}
4121
41224251fn getNextAnonNameIndex(mod: *Module) usize {
41234252 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);
41244253}
41254254
4126pub fn lookupDeclName(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
4127 const namespace = scope.namespace();
4255/// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces
4256/// in scope and check each one for the identifier.
4257pub fn lookupIdentifier(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
4258 var namespace = scope.namespace();
4259 while (true) {
4260 if (mod.lookupInNamespace(namespace, ident_name)) |decl| {
4261 return decl;
4262 }
4263 namespace = namespace.parent orelse break;
4264 }
4265 return null;
4266}
4267
4268/// This looks up a member of a specific namespace. It is affected by `usingnamespace` but
4269/// only for ones in the specified namespace.
4270pub fn lookupInNamespace(
4271 mod: *Module,
4272 namespace: *Scope.Namespace,
4273 ident_name: []const u8,
4274) ?*Decl {
41284275 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
41294276 return mod.decl_table.get(name_hash);
41304277}
......@@ -4271,7 +4418,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In
42714418 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
42724419 },
42734420 .file => unreachable,
4274 .container => unreachable,
4421 .namespace => unreachable,
42754422 .decl_ref => {
42764423 const decl_ref = scope.cast(Scope.DeclRef).?;
42774424 decl_ref.decl.analysis = .sema_failure;
......@@ -4683,10 +4830,3 @@ pub fn parseStrLit(
46834830 },
46844831 }
46854832}
4686
4687pub fn unloadFile(mod: *Module, file_scope: *Scope.File) void {
4688 if (file_scope.status == .unloaded_parse_failure) {
4689 mod.failed_files.swapRemove(file_scope).?.value.destroy(mod.gpa);
4690 }
4691 file_scope.unload(mod.gpa);
4692}
src/Sema.zig+47-92
......@@ -609,10 +609,11 @@ fn zirStructDecl(
609609 .owner_decl = sema.owner_decl,
610610 .fields = fields_map,
611611 .node_offset = inst_data.src_node,
612 .container = .{
612 .namespace = .{
613 .parent = sema.owner_decl.namespace,
614 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
613615 .ty = struct_ty,
614616 .file_scope = block.getFileScope(),
615 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
616617 },
617618 };
618619 return sema.analyzeDeclVal(block, src, new_decl);
......@@ -3640,42 +3641,43 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
36403641 const mod = sema.mod;
36413642 const arena = sema.arena;
36423643
3643 const container_scope = container_type.getContainerScope() orelse return mod.fail(
3644 const namespace = container_type.getNamespace() orelse return mod.fail(
36443645 &block.base,
36453646 lhs_src,
36463647 "expected struct, enum, union, or opaque, found '{}'",
36473648 .{container_type},
36483649 );
3649 if (mod.lookupDeclName(&container_scope.base, decl_name)) |decl| {
3650 // TODO if !decl.is_pub and inDifferentFiles() return false
3651 return mod.constBool(arena, src, true);
3652 } else {
3653 return mod.constBool(arena, src, false);
3650 if (mod.lookupInNamespace(namespace, decl_name)) |decl| {
3651 if (decl.is_pub or decl.namespace.file_scope == block.base.namespace().file_scope) {
3652 return mod.constBool(arena, src, true);
3653 }
36543654 }
3655 return mod.constBool(arena, src, false);
36553656}
36563657
36573658fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
36583659 const tracy = trace(@src());
36593660 defer tracy.end();
36603661
3662 const mod = sema.mod;
36613663 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
36623664 const src = inst_data.src();
36633665 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
36643666 const operand = try sema.resolveConstString(block, operand_src, inst_data.operand);
36653667
3666 const file_scope = sema.analyzeImport(block, src, operand) catch |err| switch (err) {
3668 const file = mod.importFile(block.getFileScope().pkg, operand) catch |err| switch (err) {
36673669 error.ImportOutsidePkgPath => {
3668 return sema.mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
3670 return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
36693671 },
36703672 error.FileNotFound => {
3671 return sema.mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
3673 return mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
36723674 },
36733675 else => {
36743676 // TODO: make sure this gets retried and not cached
3675 return sema.mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
3677 return mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
36763678 },
36773679 };
3678 return sema.mod.constType(sema.arena, src, file_scope.root_container.ty);
3680 return mod.constType(sema.arena, src, file.namespace.ty);
36793681}
36803682
36813683fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
......@@ -4707,21 +4709,9 @@ fn namedFieldPtr(
47074709 });
47084710 },
47094711 .Struct, .Opaque, .Union => {
4710 if (child_type.getContainerScope()) |container_scope| {
4711 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4712 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))
4713 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
4714 return sema.analyzeDeclRef(block, src, decl);
4715 }
4716
4717 // TODO this will give false positives for structs inside the root file
4718 if (container_scope.file_scope == mod.root_scope) {
4719 return mod.fail(
4720 &block.base,
4721 src,
4722 "root source file has no member named '{s}'",
4723 .{field_name},
4724 );
4712 if (child_type.getNamespace()) |namespace| {
4713 if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {
4714 return inst;
47254715 }
47264716 }
47274717 // TODO add note: declared here
......@@ -4736,11 +4726,9 @@ fn namedFieldPtr(
47364726 });
47374727 },
47384728 .Enum => {
4739 if (child_type.getContainerScope()) |container_scope| {
4740 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4741 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))
4742 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
4743 return sema.analyzeDeclRef(block, src, decl);
4729 if (child_type.getNamespace()) |namespace| {
4730 if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {
4731 return inst;
47444732 }
47454733 }
47464734 const field_index = child_type.enumFieldIndex(field_name) orelse {
......@@ -4778,6 +4766,32 @@ fn namedFieldPtr(
47784766 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
47794767}
47804768
4769fn analyzeNamespaceLookup(
4770 sema: *Sema,
4771 block: *Scope.Block,
4772 src: LazySrcLoc,
4773 namespace: *Scope.Namespace,
4774 decl_name: []const u8,
4775) InnerError!?*Inst {
4776 const mod = sema.mod;
4777 const gpa = sema.gpa;
4778 if (mod.lookupInNamespace(namespace, decl_name)) |decl| {
4779 if (!decl.is_pub and decl.namespace.file_scope != block.getFileScope()) {
4780 const msg = msg: {
4781 const msg = try mod.errMsg(&block.base, src, "'{s}' is not marked 'pub'", .{
4782 decl_name,
4783 });
4784 errdefer msg.destroy(gpa);
4785 try mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{});
4786 break :msg msg;
4787 };
4788 return mod.failWithOwnedErrorMsg(&block.base, msg);
4789 }
4790 return try sema.analyzeDeclRef(block, src, decl);
4791 }
4792 return null;
4793}
4794
47814795fn analyzeStructFieldPtr(
47824796 sema: *Sema,
47834797 block: *Scope.Block,
......@@ -5326,65 +5340,6 @@ fn analyzeSlice(
53265340 return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{});
53275341}
53285342
5329fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_string: []const u8) !*Scope.File {
5330 const cur_pkg = block.getFileScope().pkg;
5331 const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
5332 const found_pkg = cur_pkg.table.get(target_string);
5333
5334 const resolved_path = if (found_pkg) |pkg|
5335 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path })
5336 else
5337 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
5338 errdefer sema.gpa.free(resolved_path);
5339
5340 if (sema.mod.import_table.get(resolved_path)) |cached_import| {
5341 sema.gpa.free(resolved_path);
5342 return cached_import;
5343 }
5344
5345 if (found_pkg == null) {
5346 const resolved_root_path = try std.fs.path.resolve(sema.gpa, &[_][]const u8{cur_pkg_dir_path});
5347 defer sema.gpa.free(resolved_root_path);
5348
5349 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
5350 return error.ImportOutsidePkgPath;
5351 }
5352 }
5353
5354 // TODO Scope.Container arena for ty and sub_file_path
5355 const file_scope = try sema.gpa.create(Scope.File);
5356 errdefer sema.gpa.destroy(file_scope);
5357 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);
5358 errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?);
5359
5360 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
5361 pkg.namespace_hash
5362 else
5363 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
5364
5365 file_scope.* = .{
5366 .sub_file_path = resolved_path,
5367 .source = .{ .unloaded = {} },
5368 .tree = undefined,
5369 .status = .never_loaded,
5370 .pkg = found_pkg orelse cur_pkg,
5371 .root_container = .{
5372 .file_scope = file_scope,
5373 .decls = .{},
5374 .ty = struct_ty,
5375 .parent_name_hash = container_name_hash,
5376 },
5377 };
5378 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
5379 error.AnalysisFail => {
5380 assert(sema.mod.comp.totalErrorCount() != 0);
5381 },
5382 else => |e| return e,
5383 };
5384 try sema.mod.import_table.put(sema.gpa, file_scope.sub_file_path, file_scope);
5385 return file_scope;
5386}
5387
53885343/// Asserts that lhs and rhs types are both numeric.
53895344fn cmpNumeric(
53905345 sema: *Sema,
src/codegen.zig+2-2
......@@ -411,8 +411,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
411411 try branch_stack.append(.{});
412412
413413 const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: {
414 const container_scope = module_fn.owner_decl.container;
415 const tree = container_scope.file_scope.tree;
414 const namespace = module_fn.owner_decl.namespace;
415 const tree = namespace.file_scope.tree;
416416 const node_tags = tree.nodes.items(.tag);
417417 const node_datas = tree.nodes.items(.data);
418418 const token_starts = tree.tokens.items(.start);
src/link/Elf.zig+2-2
......@@ -2223,7 +2223,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
22232223 try dbg_line_buffer.ensureCapacity(26);
22242224
22252225 const line_off: u28 = blk: {
2226 const tree = decl.container.file_scope.tree;
2226 const tree = decl.namespace.file_scope.tree;
22272227 const node_tags = tree.nodes.items(.tag);
22282228 const node_datas = tree.nodes.items(.data);
22292229 const token_starts = tree.tokens.items(.start);
......@@ -2749,7 +2749,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
27492749
27502750 if (self.llvm_object) |_| return;
27512751
2752 const tree = decl.container.file_scope.tree;
2752 const tree = decl.namespace.file_scope.tree;
27532753 const node_tags = tree.nodes.items(.tag);
27542754 const node_datas = tree.nodes.items(.data);
27552755 const token_starts = tree.tokens.items(.start);
src/link/MachO/DebugSymbols.zig+2-2
......@@ -904,7 +904,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
904904 const tracy = trace(@src());
905905 defer tracy.end();
906906
907 const tree = decl.container.file_scope.tree;
907 const tree = decl.namespace.file_scope.tree;
908908 const node_tags = tree.nodes.items(.tag);
909909 const node_datas = tree.nodes.items(.data);
910910 const token_starts = tree.tokens.items(.start);
......@@ -953,7 +953,7 @@ pub fn initDeclDebugBuffers(
953953 try dbg_line_buffer.ensureCapacity(26);
954954
955955 const line_off: u28 = blk: {
956 const tree = decl.container.file_scope.tree;
956 const tree = decl.namespace.file_scope.tree;
957957 const node_tags = tree.nodes.items(.tag);
958958 const node_datas = tree.nodes.items(.data);
959959 const token_starts = tree.tokens.items(.start);
src/type.zig+29-6
......@@ -2052,11 +2052,11 @@ pub const Type = extern union {
20522052 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
20532053 }
20542054
2055 /// Returns null if the type has no container.
2056 pub fn getContainerScope(self: Type) ?*Module.Scope.Container {
2055 /// Returns null if the type has no namespace.
2056 pub fn getNamespace(self: Type) ?*Module.Scope.Namespace {
20572057 return switch (self.tag()) {
2058 .@"struct" => &self.castTag(.@"struct").?.data.container,
2059 .enum_full => &self.castTag(.enum_full).?.data.container,
2058 .@"struct" => &self.castTag(.@"struct").?.data.namespace,
2059 .enum_full => &self.castTag(.enum_full).?.data.namespace,
20602060 .empty_struct => self.castTag(.empty_struct).?.data,
20612061 .@"opaque" => &self.castTag(.@"opaque").?.data,
20622062
......@@ -2226,6 +2226,29 @@ pub const Type = extern union {
22262226 }
22272227 }
22282228
2229 pub fn getOwnerDecl(ty: Type) *Module.Decl {
2230 switch (ty.tag()) {
2231 .enum_full, .enum_nonexhaustive => {
2232 const enum_full = ty.cast(Payload.EnumFull).?.data;
2233 return enum_full.owner_decl;
2234 },
2235 .enum_simple => {
2236 const enum_simple = ty.castTag(.enum_simple).?.data;
2237 return enum_simple.owner_decl;
2238 },
2239 .@"struct" => {
2240 const struct_obj = ty.castTag(.@"struct").?.data;
2241 return struct_obj.owner_decl;
2242 },
2243 .error_set => {
2244 const error_set = ty.castTag(.error_set).?.data;
2245 return error_set.owner_decl;
2246 },
2247 .@"opaque" => @panic("TODO"),
2248 else => unreachable,
2249 }
2250 }
2251
22292252 /// Asserts the type is an enum.
22302253 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
22312254 const S = struct {
......@@ -2564,12 +2587,12 @@ pub const Type = extern union {
25642587 /// Most commonly used for files.
25652588 pub const ContainerScope = struct {
25662589 base: Payload,
2567 data: *Module.Scope.Container,
2590 data: *Module.Scope.Namespace,
25682591 };
25692592
25702593 pub const Opaque = struct {
25712594 base: Payload = .{ .tag = .@"opaque" },
2572 data: Module.Scope.Container,
2595 data: Module.Scope.Namespace,
25732596 };
25742597
25752598 pub const Struct = struct {
test/stage2/test.zig+13-9
......@@ -1048,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {
10481048 "Hello, World!\n",
10491049 );
10501050 try case.files.append(.{
1051 .src =
1051 .src =
10521052 \\pub fn print() void {
10531053 \\ asm volatile ("syscall"
10541054 \\ :
......@@ -1082,10 +1082,14 @@ pub fn addCases(ctx: *TestContext) !void {
10821082 \\ unreachable;
10831083 \\}
10841084 ,
1085 &.{":2:25: error: 'print' is private"},
1085 &.{
1086 ":2:25: error: 'print' is not marked 'pub'",
1087 "print.zig:2:1: note: declared here",
1088 },
10861089 );
10871090 try case.files.append(.{
1088 .src =
1091 .src =
1092 \\// dummy comment to make print be on line 2
10891093 \\fn print() void {
10901094 \\ asm volatile ("syscall"
10911095 \\ :
......@@ -1102,22 +1106,22 @@ pub fn addCases(ctx: *TestContext) !void {
11021106 });
11031107 }
11041108
1105 ctx.compileError("function redefinition", linux_x64,
1109 ctx.compileError("function redeclaration", linux_x64,
11061110 \\// dummy comment
11071111 \\fn entry() void {}
11081112 \\fn entry() void {}
11091113 , &[_][]const u8{
1110 ":3:4: error: redefinition of 'entry'",
1111 ":2:1: note: previous definition here",
1114 ":3:4: error: redeclaration of 'entry'",
1115 ":2:1: note: previously declared here",
11121116 });
11131117
1114 ctx.compileError("global variable redefinition", linux_x64,
1118 ctx.compileError("global variable redeclaration", linux_x64,
11151119 \\// dummy comment
11161120 \\var foo = false;
11171121 \\var foo = true;
11181122 , &[_][]const u8{
1119 ":3:5: error: redefinition of 'foo'",
1120 ":2:1: note: previous definition here",
1123 ":3:5: error: redeclaration of 'foo'",
1124 ":2:1: note: previously declared here",
11211125 });
11221126
11231127 ctx.compileError("compileError", linux_x64,