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(...@@ -1420,6 +1420,7 @@ fn varDecl(
1420 return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});1420 return mod.failNode(scope, var_decl.ast.align_node, "TODO implement alignment on locals", .{});
1421 }1421 }
1422 const astgen = gz.astgen;1422 const astgen = gz.astgen;
1423 const gpa = mod.gpa;
1423 const tree = gz.tree();1424 const tree = gz.tree();
1424 const token_tags = tree.tokens.items(.tag);1425 const token_tags = tree.tokens.items(.tag);
14251426
...@@ -1438,7 +1439,7 @@ fn varDecl(...@@ -1438,7 +1439,7 @@ fn varDecl(
1438 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{1439 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{
1439 ident_name,1440 ident_name,
1440 });1441 });
1441 errdefer msg.destroy(mod.gpa);1442 errdefer msg.destroy(gpa);
1442 try mod.errNote(scope, local_val.src, msg, "previous definition is here", .{});1443 try mod.errNote(scope, local_val.src, msg, "previous definition is here", .{});
1443 break :msg msg;1444 break :msg msg;
1444 };1445 };
...@@ -1453,7 +1454,7 @@ fn varDecl(...@@ -1453,7 +1454,7 @@ fn varDecl(
1453 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{1454 const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{
1454 ident_name,1455 ident_name,
1455 });1456 });
1456 errdefer msg.destroy(mod.gpa);1457 errdefer msg.destroy(gpa);
1457 try mod.errNote(scope, local_ptr.src, msg, "previous definition is here", .{});1458 try mod.errNote(scope, local_ptr.src, msg, "previous definition is here", .{});
1458 break :msg msg;1459 break :msg msg;
1459 };1460 };
...@@ -1467,9 +1468,19 @@ fn varDecl(...@@ -1467,9 +1468,19 @@ fn varDecl(
1467 }1468 }
14681469
1469 // Namespace vars shadowing detection1470 // Namespace vars shadowing detection
1470 if (mod.lookupDeclName(scope, ident_name)) |_| {1471 if (mod.lookupIdentifier(scope, ident_name)) |decl| {
1471 // TODO add note for other definition1472 const msg = msg: {
1472 return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name});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);
1473 }1484 }
1474 if (var_decl.ast.init_node == 0) {1485 if (var_decl.ast.init_node == 0) {
1475 return mod.fail(scope, name_src, "variables must be initialized", .{});1486 return mod.fail(scope, name_src, "variables must be initialized", .{});
...@@ -1503,7 +1514,7 @@ fn varDecl(...@@ -1503,7 +1514,7 @@ fn varDecl(
1503 .force_comptime = gz.force_comptime,1514 .force_comptime = gz.force_comptime,
1504 .astgen = astgen,1515 .astgen = astgen,
1505 };1516 };
1506 defer init_scope.instructions.deinit(mod.gpa);1517 defer init_scope.instructions.deinit(gpa);
15071518
1508 var resolve_inferred_alloc: zir.Inst.Ref = .none;1519 var resolve_inferred_alloc: zir.Inst.Ref = .none;
1509 var opt_type_inst: zir.Inst.Ref = .none;1520 var opt_type_inst: zir.Inst.Ref = .none;
...@@ -1529,7 +1540,7 @@ fn varDecl(...@@ -1529,7 +1540,7 @@ fn varDecl(
1529 // Move the init_scope instructions into the parent scope, eliding1540 // Move the init_scope instructions into the parent scope, eliding
1530 // the alloc instruction and the store_to_block_ptr instruction.1541 // the alloc instruction and the store_to_block_ptr instruction.
1531 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;1542 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);
1533 for (init_scope.instructions.items) |src_inst| {1544 for (init_scope.instructions.items) |src_inst| {
1534 if (astgen.indexToRef(src_inst) == init_scope.rl_ptr) continue;1545 if (astgen.indexToRef(src_inst) == init_scope.rl_ptr) continue;
1535 if (zir_tags[src_inst] == .store_to_block_ptr) {1546 if (zir_tags[src_inst] == .store_to_block_ptr) {
...@@ -1554,7 +1565,7 @@ fn varDecl(...@@ -1554,7 +1565,7 @@ fn varDecl(
1554 // Move the init_scope instructions into the parent scope, swapping1565 // Move the init_scope instructions into the parent scope, swapping
1555 // store_to_block_ptr for store_to_inferred_ptr.1566 // store_to_block_ptr for store_to_inferred_ptr.
1556 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;1567 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);
1558 for (init_scope.instructions.items) |src_inst| {1569 for (init_scope.instructions.items) |src_inst| {
1559 if (zir_tags[src_inst] == .store_to_block_ptr) {1570 if (zir_tags[src_inst] == .store_to_block_ptr) {
1560 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {1571 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...@@ -1798,6 +1809,91 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.I
1798 return rvalue(gz, scope, rl, result, node);1809 return rvalue(gz, scope, rl, result, node);
1799}1810}
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
1801fn containerDecl(1897fn containerDecl(
1802 gz: *GenZir,1898 gz: *GenZir,
1803 scope: *Scope,1899 scope: *Scope,
...@@ -1827,76 +1923,10 @@ fn containerDecl(...@@ -1827,76 +1923,10 @@ fn containerDecl(
1827 .keyword_extern => zir.Inst.Tag.struct_decl_extern,1923 .keyword_extern => zir.Inst.Tag.struct_decl_extern,
1828 else => unreachable,1924 else => unreachable,
1829 } else zir.Inst.Tag.struct_decl;1925 } 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
1837 assert(arg_inst == .none);1927 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);1929 const result = try structDeclInner(gz, scope, node, container_decl, tag);
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);
1900 return rvalue(gz, scope, rl, result, node);1930 return rvalue(gz, scope, rl, result, node);
1901 },1931 },
1902 .keyword_union => {1932 .keyword_union => {
...@@ -2930,7 +2960,7 @@ pub const SwitchProngSrc = union(enum) {...@@ -2930,7 +2960,7 @@ pub const SwitchProngSrc = union(enum) {
2930 ) LazySrcLoc {2960 ) LazySrcLoc {
2931 @setCold(true);2961 @setCold(true);
2932 const switch_node = decl.relativeToNodeIndex(switch_node_offset);2962 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();
2934 const main_tokens = tree.nodes.items(.main_token);2964 const main_tokens = tree.nodes.items(.main_token);
2935 const node_datas = tree.nodes.items(.data);2965 const node_datas = tree.nodes.items(.data);
2936 const node_tags = tree.nodes.items(.tag);2966 const node_tags = tree.nodes.items(.tag);
...@@ -3692,7 +3722,7 @@ fn identifier(...@@ -3692,7 +3722,7 @@ fn identifier(
3692 };3722 };
3693 }3723 }
36943724
3695 const decl = mod.lookupDeclName(scope, ident_name) orelse {3725 const decl = mod.lookupIdentifier(scope, ident_name) orelse {
3696 // TODO insert a "dependency on the non-existence of a decl" here to make this3726 // TODO insert a "dependency on the non-existence of a decl" here to make this
3697 // compile error go away when the decl is introduced. This data should be in a global3727 // compile error go away when the decl is introduced. This data should be in a global
3698 // sparse map since it is only relevant when a compile error occurs.3728 // 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 {...@@ -385,7 +385,7 @@ pub const AllErrors = struct {
385 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);385 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
386 for (notes) |*note, i| {386 for (notes) |*note, i| {
387 const module_note = module_err_msg.notes[i];387 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);
389 const byte_offset = try module_note.src_loc.byteOffset();389 const byte_offset = try module_note.src_loc.byteOffset();
390 const loc = std.zig.findLineColumn(source, byte_offset);390 const loc = std.zig.findLineColumn(source, byte_offset);
391 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;391 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
...@@ -400,7 +400,7 @@ pub const AllErrors = struct {...@@ -400,7 +400,7 @@ pub const AllErrors = struct {
400 },400 },
401 };401 };
402 }402 }
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);
404 const byte_offset = try module_err_msg.src_loc.byteOffset();404 const byte_offset = try module_err_msg.src_loc.byteOffset();
405 const loc = std.zig.findLineColumn(source, byte_offset);405 const loc = std.zig.findLineColumn(source, byte_offset);
406 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;406 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 {...@@ -1049,37 +1049,18 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1049 // However we currently do not have serialization of such metadata, so for now1049 // However we currently do not have serialization of such metadata, so for now
1050 // we set up an empty Module that does the entire compilation fresh.1050 // 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
1071 const module = try arena.create(Module);1052 const module = try arena.create(Module);
1072 errdefer module.deinit();1053 errdefer module.deinit();
1073 module.* = .{1054 module.* = .{
1074 .gpa = gpa,1055 .gpa = gpa,
1075 .comp = comp,1056 .comp = comp,
1076 .root_pkg = root_pkg,1057 .root_pkg = root_pkg,
1077 .root_scope = root_scope,
1078 .zig_cache_artifact_directory = zig_cache_artifact_directory,1058 .zig_cache_artifact_directory = zig_cache_artifact_directory,
1079 .emit_h = options.emit_h,1059 .emit_h = options.emit_h,
1080 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1),1060 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1),
1081 };1061 };
1082 module.error_name_list.appendAssumeCapacity("(no error)");1062 module.error_name_list.appendAssumeCapacity("(no error)");
1063
1083 break :blk module;1064 break :blk module;
1084 } else blk: {1065 } else blk: {
1085 if (options.emit_h != null) return error.NoZigModuleForCHeader;1066 if (options.emit_h != null) return error.NoZigModuleForCHeader;
...@@ -1485,31 +1466,50 @@ pub fn update(self: *Compilation) !void {...@@ -1485,31 +1466,50 @@ pub fn update(self: *Compilation) !void {
1485 module.compile_log_text.shrinkAndFree(module.gpa, 0);1466 module.compile_log_text.shrinkAndFree(module.gpa, 0);
1486 module.generation += 1;1467 module.generation += 1;
14871468
1488 // TODO Detect which source files changed.1469 // 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
1504 for (module.import_table.items()) |entry| {1470 for (module.import_table.items()) |entry| {
1505 module.unloadFile(entry.value);1471 const file = entry.value;
1506 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {1472 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
1507 error.AnalysisFail => {1473 defer f.close();
1508 assert(self.totalErrorCount() != 0);1474
1509 },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,
1510 else => |e| return e,1507 else => |e| return e,
1511 };1508 };
1512 }1509 }
1510
1511 // Simulate `_ = @import("std");` which in turn imports start.zig.
1512 _ = try module.importFile(module.root_pkg, "std");
1513 }1513 }
1514 }1514 }
15151515
...@@ -1551,7 +1551,9 @@ pub fn update(self: *Compilation) !void {...@@ -1551,7 +1551,9 @@ pub fn update(self: *Compilation) !void {
1551 // to report error messages. Otherwise we unload all source files to save memory.1551 // to report error messages. Otherwise we unload all source files to save memory.
1552 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {1552 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
1553 if (self.bin_file.options.module) |module| {1553 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 }
1555 }1557 }
1556 }1558 }
1557}1559}
...@@ -1580,13 +1582,13 @@ pub fn totalErrorCount(self: *Compilation) usize {...@@ -1580,13 +1582,13 @@ pub fn totalErrorCount(self: *Compilation) usize {
1580 // the previous parse success, including compile errors, but we cannot1582 // the previous parse success, including compile errors, but we cannot
1581 // emit them until the file succeeds parsing.1583 // emit them until the file succeeds parsing.
1582 for (module.failed_decls.items()) |entry| {1584 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) {
1584 continue;1586 continue;
1585 }1587 }
1586 total += 1;1588 total += 1;
1587 }1589 }
1588 for (module.emit_h_failed_decls.items()) |entry| {1590 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) {
1590 continue;1592 continue;
1591 }1593 }
1592 total += 1;1594 total += 1;
...@@ -1641,7 +1643,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1641,7 +1643,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1641 try AllErrors.add(module, &arena, &errors, entry.value.*);1643 try AllErrors.add(module, &arena, &errors, entry.value.*);
1642 }1644 }
1643 for (module.failed_decls.items()) |entry| {1645 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) {
1645 // Skip errors for Decls within files that had a parse failure.1647 // Skip errors for Decls within files that had a parse failure.
1646 // We'll try again once parsing succeeds.1648 // We'll try again once parsing succeeds.
1647 continue;1649 continue;
...@@ -1649,7 +1651,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1649,7 +1651,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1649 try AllErrors.add(module, &arena, &errors, entry.value.*);1651 try AllErrors.add(module, &arena, &errors, entry.value.*);
1650 }1652 }
1651 for (module.emit_h_failed_decls.items()) |entry| {1653 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) {
1653 // Skip errors for Decls within files that had a parse failure.1655 // Skip errors for Decls within files that had a parse failure.
1654 // We'll try again once parsing succeeds.1656 // We'll try again once parsing succeeds.
1655 continue;1657 continue;
src/Module.zig+409-269
...@@ -26,6 +26,7 @@ const trace = @import("tracy.zig").trace;...@@ -26,6 +26,7 @@ const trace = @import("tracy.zig").trace;
26const AstGen = @import("AstGen.zig");26const AstGen = @import("AstGen.zig");
27const Sema = @import("Sema.zig");27const Sema = @import("Sema.zig");
28const target_util = @import("target.zig");28const target_util = @import("target.zig");
29const Cache = @import("Cache.zig");
2930
30/// General-purpose allocator. Used for both temporary and long-term storage.31/// General-purpose allocator. Used for both temporary and long-term storage.
31gpa: *Allocator,32gpa: *Allocator,
...@@ -35,8 +36,6 @@ comp: *Compilation,...@@ -35,8 +36,6 @@ comp: *Compilation,
35zig_cache_artifact_directory: Compilation.Directory,36zig_cache_artifact_directory: Compilation.Directory,
36/// Pointer to externally managed resource. `null` if there is no zig file being compiled.37/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
37root_pkg: *Package,38root_pkg: *Package,
38/// Module owns this resource.
39root_scope: *Scope.File,
40/// It's rare for a decl to be exported, so we save memory by having a sparse map of39/// It's rare for a decl to be exported, so we save memory by having a sparse map of
41/// Decl pointers to details about them being exported.40/// Decl pointers to details about them being exported.
42/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.41/// 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) = .{},...@@ -52,6 +51,12 @@ symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{},
52export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},51export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
53/// Maps fully qualified namespaced names to the Decl struct for them.52/// Maps fully qualified namespaced names to the Decl struct for them.
54decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false) = .{},53decl_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
55/// We optimize memory usage for a compilation with no compile errors by storing the60/// We optimize memory usage for a compilation with no compile errors by storing the
56/// error messages and mapping outside of `Decl`.61/// error messages and mapping outside of `Decl`.
57/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.62/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
...@@ -85,9 +90,6 @@ global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{},...@@ -85,9 +90,6 @@ global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{},
85/// Corresponds with `global_error_set`.90/// Corresponds with `global_error_set`.
86error_name_list: ArrayListUnmanaged([]const u8) = .{},91error_name_list: ArrayListUnmanaged([]const u8) = .{},
8792
88/// Keys are fully qualified paths
89import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
90
91/// Incrementing integer used to compare against the corresponding Decl93/// Incrementing integer used to compare against the corresponding Decl
92/// field to determine whether a Decl's status applies to an ongoing update, or a94/// field to determine whether a Decl's status applies to an ongoing update, or a
93/// previous analysis.95/// previous analysis.
...@@ -147,15 +149,16 @@ pub const Decl = struct {...@@ -147,15 +149,16 @@ pub const Decl = struct {
147 /// This is necessary for mapping them to an address in the output file.149 /// This is necessary for mapping them to an address in the output file.
148 /// Memory owned by this decl, using Module's allocator.150 /// Memory owned by this decl, using Module's allocator.
149 name: [*:0]const u8,151 name: [*:0]const u8,
150 /// The direct parent container of the Decl.152 /// The direct parent namespace of the Decl.
151 /// Reference to externally owned memory.153 /// 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
154 /// An integer that can be checked against the corresponding incrementing157 /// An integer that can be checked against the corresponding incrementing
155 /// generation field of Module. This is used to determine whether `complete` status158 /// generation field of Module. This is used to determine whether `complete` status
156 /// represents pre- or post- re-analysis.159 /// represents pre- or post- re-analysis.
157 generation: u32,160 generation: u32,
158 /// The AST Node index or ZIR Inst index that contains this declaration.161 /// The AST node index of this declaration.
159 /// Must be recomputed when the corresponding source file is modified.162 /// Must be recomputed when the corresponding source file is modified.
160 src_node: ast.Node.Index,163 src_node: ast.Node.Index,
161164
...@@ -273,22 +276,22 @@ pub const Decl = struct {...@@ -273,22 +276,22 @@ pub const Decl = struct {
273 }276 }
274277
275 pub fn srcToken(decl: Decl) u32 {278 pub fn srcToken(decl: Decl) u32 {
276 const tree = &decl.container.file_scope.tree;279 const tree = &decl.namespace.file_scope.tree;
277 return tree.firstToken(decl.src_node);280 return tree.firstToken(decl.src_node);
278 }281 }
279282
280 pub fn srcByteOffset(decl: Decl) u32 {283 pub fn srcByteOffset(decl: Decl) u32 {
281 const tree = &decl.container.file_scope.tree;284 const tree = &decl.namespace.file_scope.tree;
282 return tree.tokens.items(.start)[decl.srcToken()];285 return tree.tokens.items(.start)[decl.srcToken()];
283 }286 }
284287
285 pub fn fullyQualifiedNameHash(decl: Decl) Scope.NameHash {288 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));
287 }290 }
288291
289 pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void {292 pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void {
290 const unqualified_name = mem.spanZ(decl.name);293 const unqualified_name = mem.spanZ(decl.name);
291 return decl.container.renderFullyQualifiedName(unqualified_name, writer);294 return decl.namespace.renderFullyQualifiedName(unqualified_name, writer);
292 }295 }
293296
294 pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 {297 pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 {
...@@ -330,7 +333,7 @@ pub const Decl = struct {...@@ -330,7 +333,7 @@ pub const Decl = struct {
330 }333 }
331334
332 pub fn getFileScope(decl: Decl) *Scope.File {335 pub fn getFileScope(decl: Decl) *Scope.File {
333 return decl.container.file_scope;336 return decl.namespace.file_scope;
334 }337 }
335338
336 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {339 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {
...@@ -377,7 +380,7 @@ pub const Struct = struct {...@@ -377,7 +380,7 @@ pub const Struct = struct {
377 /// Set of field names in declaration order.380 /// Set of field names in declaration order.
378 fields: std.StringArrayHashMapUnmanaged(Field),381 fields: std.StringArrayHashMapUnmanaged(Field),
379 /// Represents the declarations inside this struct.382 /// Represents the declarations inside this struct.
380 container: Scope.Container,383 namespace: Scope.Namespace,
381384
382 /// Offset from `owner_decl`, points to the struct AST node.385 /// Offset from `owner_decl`, points to the struct AST node.
383 node_offset: i32,386 node_offset: i32,
...@@ -434,7 +437,7 @@ pub const EnumFull = struct {...@@ -434,7 +437,7 @@ pub const EnumFull = struct {
434 /// If this hash map is empty, it means the enum tags are auto-numbered.437 /// If this hash map is empty, it means the enum tags are auto-numbered.
435 values: ValueMap,438 values: ValueMap,
436 /// Represents the declarations inside this struct.439 /// Represents the declarations inside this struct.
437 container: Scope.Container,440 namespace: Scope.Namespace,
438 /// Offset from `owner_decl`, points to the enum decl AST node.441 /// Offset from `owner_decl`, points to the enum decl AST node.
439 node_offset: i32,442 node_offset: i32,
440443
...@@ -521,7 +524,7 @@ pub const Scope = struct {...@@ -521,7 +524,7 @@ pub const Scope = struct {
521 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.arena,524 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.arena,
522 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.arena,525 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.arena,
523 .file => unreachable,526 .file => unreachable,
524 .container => unreachable,527 .namespace => unreachable,
525 .decl_ref => unreachable,528 .decl_ref => unreachable,
526 }529 }
527 }530 }
...@@ -533,7 +536,7 @@ pub const Scope = struct {...@@ -533,7 +536,7 @@ pub const Scope = struct {
533 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,536 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
534 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,537 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
535 .file => null,538 .file => null,
536 .container => null,539 .namespace => null,
537 .decl_ref => scope.cast(DeclRef).?.decl,540 .decl_ref => scope.cast(DeclRef).?.decl,
538 };541 };
539 }542 }
...@@ -545,36 +548,21 @@ pub const Scope = struct {...@@ -545,36 +548,21 @@ pub const Scope = struct {
545 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,548 .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl,
546 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,549 .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl,
547 .file => null,550 .file => null,
548 .container => null,551 .namespace => null,
549 .decl_ref => scope.cast(DeclRef).?.decl,552 .decl_ref => scope.cast(DeclRef).?.decl,
550 };553 };
551 }554 }
552555
553 /// Asserts the scope has a parent which is a Container and returns it.556 /// Asserts the scope has a parent which is a Namespace and returns it.
554 pub fn namespace(scope: *Scope) *Container {557 pub fn namespace(scope: *Scope) *Namespace {
555 switch (scope.tag) {558 switch (scope.tag) {
556 .block => return scope.cast(Block).?.sema.owner_decl.container,559 .block => return scope.cast(Block).?.sema.owner_decl.namespace,
557 .gen_zir => return scope.cast(GenZir).?.astgen.decl.container,560 .gen_zir => return scope.cast(GenZir).?.astgen.decl.namespace,
558 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.container,561 .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace,
559 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.container,562 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace,
560 .file => return &scope.cast(File).?.root_container,563 .file => return scope.cast(File).?.namespace,
561 .container => return scope.cast(Container).?,564 .namespace => return scope.cast(Namespace).?,
562 .decl_ref => return scope.cast(DeclRef).?.decl.container,565 .decl_ref => return scope.cast(DeclRef).?.decl.namespace,
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,
578 }566 }
579 }567 }
580568
...@@ -582,12 +570,12 @@ pub const Scope = struct {...@@ -582,12 +570,12 @@ pub const Scope = struct {
582 pub fn tree(scope: *Scope) *const ast.Tree {570 pub fn tree(scope: *Scope) *const ast.Tree {
583 switch (scope.tag) {571 switch (scope.tag) {
584 .file => return &scope.cast(File).?.tree,572 .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,
586 .gen_zir => return scope.cast(GenZir).?.tree(),574 .gen_zir => return scope.cast(GenZir).?.tree(),
587 .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.container.file_scope.tree,575 .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace.file_scope.tree,
588 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.container.file_scope.tree,576 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace.file_scope.tree,
589 .container => return &scope.cast(Container).?.file_scope.tree,577 .namespace => return &scope.cast(Namespace).?.file_scope.tree,
590 .decl_ref => return &scope.cast(DeclRef).?.decl.container.file_scope.tree,578 .decl_ref => return &scope.cast(DeclRef).?.decl.namespace.file_scope.tree,
591 }579 }
592 }580 }
593581
...@@ -599,16 +587,16 @@ pub const Scope = struct {...@@ -599,16 +587,16 @@ pub const Scope = struct {
599 .local_val => return scope.cast(LocalVal).?.gen_zir,587 .local_val => return scope.cast(LocalVal).?.gen_zir,
600 .local_ptr => return scope.cast(LocalPtr).?.gen_zir,588 .local_ptr => return scope.cast(LocalPtr).?.gen_zir,
601 .file => unreachable,589 .file => unreachable,
602 .container => unreachable,590 .namespace => unreachable,
603 .decl_ref => unreachable,591 .decl_ref => unreachable,
604 };592 };
605 }593 }
606594
607 /// Asserts the scope has a parent which is a Container or File and595 /// Asserts the scope has a parent which is a Namespace or File and
608 /// returns the sub_file_path field.596 /// returns the sub_file_path field.
609 pub fn subFilePath(base: *Scope) []const u8 {597 pub fn subFilePath(base: *Scope) []const u8 {
610 switch (base.tag) {598 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,
612 .file => return @fieldParentPtr(File, "base", base).sub_file_path,600 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
613 .block => unreachable,601 .block => unreachable,
614 .gen_zir => unreachable,602 .gen_zir => unreachable,
...@@ -618,30 +606,18 @@ pub const Scope = struct {...@@ -618,30 +606,18 @@ pub const Scope = struct {
618 }606 }
619 }607 }
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
633 /// When called from inside a Block Scope, chases the src_decl, not the owner_decl.609 /// When called from inside a Block Scope, chases the src_decl, not the owner_decl.
634 pub fn getFileScope(base: *Scope) *Scope.File {610 pub fn getFileScope(base: *Scope) *Scope.File {
635 var cur = base;611 var cur = base;
636 while (true) {612 while (true) {
637 cur = switch (cur.tag) {613 cur = switch (cur.tag) {
638 .container => return @fieldParentPtr(Container, "base", cur).file_scope,614 .namespace => return @fieldParentPtr(Namespace, "base", cur).file_scope,
639 .file => return @fieldParentPtr(File, "base", cur),615 .file => return @fieldParentPtr(File, "base", cur),
640 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,616 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
641 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,617 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
642 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,618 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
643 .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope,619 .block => return @fieldParentPtr(Block, "base", cur).src_decl.namespace.file_scope,
644 .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.container.file_scope,620 .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.namespace.file_scope,
645 };621 };
646 }622 }
647 }623 }
...@@ -657,8 +633,8 @@ pub const Scope = struct {...@@ -657,8 +633,8 @@ pub const Scope = struct {
657 pub const Tag = enum {633 pub const Tag = enum {
658 /// .zig source code.634 /// .zig source code.
659 file,635 file,
660 /// struct, enum or union, every .file contains one of these.636 /// Namespace owned by structs, enums, unions, and opaques for decls.
661 container,637 namespace,
662 block,638 block,
663 gen_zir,639 gen_zir,
664 local_val,640 local_val,
...@@ -669,37 +645,44 @@ pub const Scope = struct {...@@ -669,37 +645,44 @@ pub const Scope = struct {
669 decl_ref,645 decl_ref,
670 };646 };
671647
672 pub const Container = struct {648 /// The container that structs, enums, unions, and opaques have.
673 pub const base_tag: Tag = .container;649 pub const Namespace = struct {
650 pub const base_tag: Tag = .namespace;
674 base: Scope = Scope{ .tag = base_tag },651 base: Scope = Scope{ .tag = base_tag },
675652
653 parent: ?*Namespace,
676 file_scope: *Scope.File,654 file_scope: *Scope.File,
677 parent_name_hash: NameHash,655 parent_name_hash: NameHash,
678656 /// Will be a struct, enum, union, or opaque.
679 /// Direct children of the file.
680 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
681 ty: Type,657 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 {662 pub fn deinit(ns: *Namespace, gpa: *Allocator) void {
684 cont.decls.deinit(gpa);663 ns.decls.deinit(gpa);
685 // TODO either Container of File should have an arena for sub_file_path and ty664 ns.* = undefined;
686 gpa.destroy(cont.ty.castTag(.empty_struct).?);
687 gpa.free(cont.file_scope.sub_file_path);
688 cont.* = undefined;
689 }665 }
690666
691 pub fn removeDecl(cont: *Container, child: *Decl) void {667 pub fn removeDecl(ns: *Namespace, child: *Decl) void {
692 _ = cont.decls.swapRemove(child);668 _ = ns.decls.swapRemove(child);
693 }669 }
694670
695 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {671 /// Must generate unique bytes with no collisions with other decls.
696 return std.zig.hashName(cont.parent_name_hash, ".", name);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);
697 }676 }
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 {
700 // TODO this should render e.g. "std.fs.Dir.OpenOptions"679 // TODO this should render e.g. "std.fs.Dir.OpenOptions"
701 return writer.writeAll(name);680 return writer.writeAll(name);
702 }681 }
682
683 pub fn getDecl(ns: Namespace) *Decl {
684 return ns.ty.getOwnerDecl();
685 }
703 };686 };
704687
705 pub const File = struct {688 pub const File = struct {
...@@ -711,46 +694,54 @@ pub const Scope = struct {...@@ -711,46 +694,54 @@ pub const Scope = struct {
711 unloaded_parse_failure,694 unloaded_parse_failure,
712 loaded_success,695 loaded_success,
713 },696 },
714697 source_loaded: bool,
715 /// Relative to the owning package's root_src_dir.698 /// 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.
717 sub_file_path: []const u8,700 sub_file_path: []const u8,
718 source: union(enum) {701 /// Whether this is populated depends on `source_loaded`.
719 unloaded: void,702 source: [:0]const u8,
720 bytes: [:0]const u8,703 /// Whether this is populated depends on `status`.
721 },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,
722 /// Whether this is populated or not depends on `status`.711 /// Whether this is populated or not depends on `status`.
723 tree: ast.Tree,712 tree: ast.Tree,
724 /// Package that this file is a part of, managed externally.713 /// Package that this file is a part of, managed externally.
725 pkg: *Package,714 pkg: *Package,
726715 /// The namespace of the struct that represents this file.
727 root_container: Container,716 namespace: *Namespace,
728717
729 pub fn unload(file: *File, gpa: *Allocator) void {718 pub fn unload(file: *File, gpa: *Allocator) void {
730 switch (file.status) {719 file.unloadTree(gpa);
731 .unloaded_parse_failure,720 file.unloadSource(gpa);
732 .never_loaded,721 }
733 .unloaded_success,
734 => {
735 file.status = .unloaded_success;
736 },
737722
738 .loaded_success => {723 pub fn unloadTree(file: *File, gpa: *Allocator) void {
739 file.tree.deinit(gpa);724 if (file.status == .loaded_success) {
740 file.status = .unloaded_success;725 file.tree.deinit(gpa);
741 },
742 }726 }
743 switch (file.source) {727 file.status = .unloaded_success;
744 .bytes => |bytes| {728 }
745 gpa.free(bytes);729
746 file.source = .{ .unloaded = {} };730 pub fn unloadSource(file: *File, gpa: *Allocator) void {
747 },731 if (file.source_loaded) {
748 .unloaded => {},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;
749 }741 }
750 }742 }
751743
752 pub fn deinit(file: *File, gpa: *Allocator) void {744 pub fn deinit(file: *File, gpa: *Allocator) void {
753 file.root_container.deinit(gpa);
754 file.unload(gpa);745 file.unload(gpa);
755 file.* = undefined;746 file.* = undefined;
756 }747 }
...@@ -765,22 +756,44 @@ pub const Scope = struct {...@@ -765,22 +756,44 @@ pub const Scope = struct {
765 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });756 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
766 }757 }
767758
768 pub fn getSource(file: *File, module: *Module) ![:0]const u8 {759 pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {
769 switch (file.source) {760 if (file.source_loaded) return file.source;
770 .unloaded => {761
771 const source = try file.pkg.root_src_directory.handle.readFileAllocOptions(762 // Keep track of inode, file size, mtime, hash so we can detect which files
772 module.gpa,763 // have been modified when an incremental update is requested.
773 file.sub_file_path,764 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
774 std.math.maxInt(u32),765 defer f.close();
775 null,766
776 1,767 const stat = try f.stat();
777 0,768
778 );769 try file.finishGettingSource(gpa, f, stat);
779 file.source = .{ .bytes = source };770 assert(file.source_loaded);
780 return source;771 return file.source;
781 },772 }
782 .bytes => |bytes| return bytes,773
783 }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;
784 }797 }
785 };798 };
786799
...@@ -859,7 +872,7 @@ pub const Scope = struct {...@@ -859,7 +872,7 @@ pub const Scope = struct {
859 }872 }
860873
861 pub fn getFileScope(block: *Block) *Scope.File {874 pub fn getFileScope(block: *Block) *Scope.File {
862 return block.src_decl.container.file_scope;875 return block.src_decl.namespace.file_scope;
863 }876 }
864877
865 pub fn addNoOp(878 pub fn addNoOp(
...@@ -1110,7 +1123,7 @@ pub const Scope = struct {...@@ -1110,7 +1123,7 @@ pub const Scope = struct {
1110 }1123 }
11111124
1112 pub fn tree(gz: *const GenZir) *const ast.Tree {1125 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;
1114 }1127 }
11151128
1116 pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {1129 pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void {
...@@ -1678,7 +1691,7 @@ pub const SrcLoc = struct {...@@ -1678,7 +1691,7 @@ pub const SrcLoc = struct {
1678 .node_offset_switch_range,1691 .node_offset_switch_range,
1679 .node_offset_fn_type_cc,1692 .node_offset_fn_type_cc,
1680 .node_offset_fn_type_ret_ty,1693 .node_offset_fn_type_ret_ty,
1681 => src_loc.container.decl.container.file_scope,1694 => src_loc.container.decl.namespace.file_scope,
1682 };1695 };
1683 }1696 }
16841697
...@@ -1706,14 +1719,14 @@ pub const SrcLoc = struct {...@@ -1706,14 +1719,14 @@ pub const SrcLoc = struct {
1706 .token_offset => |tok_off| {1719 .token_offset => |tok_off| {
1707 const decl = src_loc.container.decl;1720 const decl = src_loc.container.decl;
1708 const tok_index = decl.srcToken() + tok_off;1721 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();
1710 const token_starts = tree.tokens.items(.start);1723 const token_starts = tree.tokens.items(.start);
1711 return token_starts[tok_index];1724 return token_starts[tok_index];
1712 },1725 },
1713 .node_offset, .node_offset_bin_op => |node_off| {1726 .node_offset, .node_offset_bin_op => |node_off| {
1714 const decl = src_loc.container.decl;1727 const decl = src_loc.container.decl;
1715 const node = decl.relativeToNodeIndex(node_off);1728 const node = decl.relativeToNodeIndex(node_off);
1716 const tree = decl.container.file_scope.base.tree();1729 const tree = decl.namespace.file_scope.base.tree();
1717 const main_tokens = tree.nodes.items(.main_token);1730 const main_tokens = tree.nodes.items(.main_token);
1718 const tok_index = main_tokens[node];1731 const tok_index = main_tokens[node];
1719 const token_starts = tree.tokens.items(.start);1732 const token_starts = tree.tokens.items(.start);
...@@ -1722,7 +1735,7 @@ pub const SrcLoc = struct {...@@ -1722,7 +1735,7 @@ pub const SrcLoc = struct {
1722 .node_offset_back2tok => |node_off| {1735 .node_offset_back2tok => |node_off| {
1723 const decl = src_loc.container.decl;1736 const decl = src_loc.container.decl;
1724 const node = decl.relativeToNodeIndex(node_off);1737 const node = decl.relativeToNodeIndex(node_off);
1725 const tree = decl.container.file_scope.base.tree();1738 const tree = decl.namespace.file_scope.base.tree();
1726 const tok_index = tree.firstToken(node) - 2;1739 const tok_index = tree.firstToken(node) - 2;
1727 const token_starts = tree.tokens.items(.start);1740 const token_starts = tree.tokens.items(.start);
1728 return token_starts[tok_index];1741 return token_starts[tok_index];
...@@ -1730,7 +1743,7 @@ pub const SrcLoc = struct {...@@ -1730,7 +1743,7 @@ pub const SrcLoc = struct {
1730 .node_offset_var_decl_ty => |node_off| {1743 .node_offset_var_decl_ty => |node_off| {
1731 const decl = src_loc.container.decl;1744 const decl = src_loc.container.decl;
1732 const node = decl.relativeToNodeIndex(node_off);1745 const node = decl.relativeToNodeIndex(node_off);
1733 const tree = decl.container.file_scope.base.tree();1746 const tree = decl.namespace.file_scope.base.tree();
1734 const node_tags = tree.nodes.items(.tag);1747 const node_tags = tree.nodes.items(.tag);
1735 const full = switch (node_tags[node]) {1748 const full = switch (node_tags[node]) {
1736 .global_var_decl => tree.globalVarDecl(node),1749 .global_var_decl => tree.globalVarDecl(node),
...@@ -1750,7 +1763,7 @@ pub const SrcLoc = struct {...@@ -1750,7 +1763,7 @@ pub const SrcLoc = struct {
1750 },1763 },
1751 .node_offset_builtin_call_arg0 => |node_off| {1764 .node_offset_builtin_call_arg0 => |node_off| {
1752 const decl = src_loc.container.decl;1765 const decl = src_loc.container.decl;
1753 const tree = decl.container.file_scope.base.tree();1766 const tree = decl.namespace.file_scope.base.tree();
1754 const node_datas = tree.nodes.items(.data);1767 const node_datas = tree.nodes.items(.data);
1755 const node_tags = tree.nodes.items(.tag);1768 const node_tags = tree.nodes.items(.tag);
1756 const node = decl.relativeToNodeIndex(node_off);1769 const node = decl.relativeToNodeIndex(node_off);
...@@ -1766,7 +1779,7 @@ pub const SrcLoc = struct {...@@ -1766,7 +1779,7 @@ pub const SrcLoc = struct {
1766 },1779 },
1767 .node_offset_builtin_call_arg1 => |node_off| {1780 .node_offset_builtin_call_arg1 => |node_off| {
1768 const decl = src_loc.container.decl;1781 const decl = src_loc.container.decl;
1769 const tree = decl.container.file_scope.base.tree();1782 const tree = decl.namespace.file_scope.base.tree();
1770 const node_datas = tree.nodes.items(.data);1783 const node_datas = tree.nodes.items(.data);
1771 const node_tags = tree.nodes.items(.tag);1784 const node_tags = tree.nodes.items(.tag);
1772 const node = decl.relativeToNodeIndex(node_off);1785 const node = decl.relativeToNodeIndex(node_off);
...@@ -1782,7 +1795,7 @@ pub const SrcLoc = struct {...@@ -1782,7 +1795,7 @@ pub const SrcLoc = struct {
1782 },1795 },
1783 .node_offset_array_access_index => |node_off| {1796 .node_offset_array_access_index => |node_off| {
1784 const decl = src_loc.container.decl;1797 const decl = src_loc.container.decl;
1785 const tree = decl.container.file_scope.base.tree();1798 const tree = decl.namespace.file_scope.base.tree();
1786 const node_datas = tree.nodes.items(.data);1799 const node_datas = tree.nodes.items(.data);
1787 const node_tags = tree.nodes.items(.tag);1800 const node_tags = tree.nodes.items(.tag);
1788 const node = decl.relativeToNodeIndex(node_off);1801 const node = decl.relativeToNodeIndex(node_off);
...@@ -1793,7 +1806,7 @@ pub const SrcLoc = struct {...@@ -1793,7 +1806,7 @@ pub const SrcLoc = struct {
1793 },1806 },
1794 .node_offset_slice_sentinel => |node_off| {1807 .node_offset_slice_sentinel => |node_off| {
1795 const decl = src_loc.container.decl;1808 const decl = src_loc.container.decl;
1796 const tree = decl.container.file_scope.base.tree();1809 const tree = decl.namespace.file_scope.base.tree();
1797 const node_datas = tree.nodes.items(.data);1810 const node_datas = tree.nodes.items(.data);
1798 const node_tags = tree.nodes.items(.tag);1811 const node_tags = tree.nodes.items(.tag);
1799 const node = decl.relativeToNodeIndex(node_off);1812 const node = decl.relativeToNodeIndex(node_off);
...@@ -1810,7 +1823,7 @@ pub const SrcLoc = struct {...@@ -1810,7 +1823,7 @@ pub const SrcLoc = struct {
1810 },1823 },
1811 .node_offset_call_func => |node_off| {1824 .node_offset_call_func => |node_off| {
1812 const decl = src_loc.container.decl;1825 const decl = src_loc.container.decl;
1813 const tree = decl.container.file_scope.base.tree();1826 const tree = decl.namespace.file_scope.base.tree();
1814 const node_datas = tree.nodes.items(.data);1827 const node_datas = tree.nodes.items(.data);
1815 const node_tags = tree.nodes.items(.tag);1828 const node_tags = tree.nodes.items(.tag);
1816 const node = decl.relativeToNodeIndex(node_off);1829 const node = decl.relativeToNodeIndex(node_off);
...@@ -1837,7 +1850,7 @@ pub const SrcLoc = struct {...@@ -1837,7 +1850,7 @@ pub const SrcLoc = struct {
1837 },1850 },
1838 .node_offset_field_name => |node_off| {1851 .node_offset_field_name => |node_off| {
1839 const decl = src_loc.container.decl;1852 const decl = src_loc.container.decl;
1840 const tree = decl.container.file_scope.base.tree();1853 const tree = decl.namespace.file_scope.base.tree();
1841 const node_datas = tree.nodes.items(.data);1854 const node_datas = tree.nodes.items(.data);
1842 const node_tags = tree.nodes.items(.tag);1855 const node_tags = tree.nodes.items(.tag);
1843 const node = decl.relativeToNodeIndex(node_off);1856 const node = decl.relativeToNodeIndex(node_off);
...@@ -1850,7 +1863,7 @@ pub const SrcLoc = struct {...@@ -1850,7 +1863,7 @@ pub const SrcLoc = struct {
1850 },1863 },
1851 .node_offset_deref_ptr => |node_off| {1864 .node_offset_deref_ptr => |node_off| {
1852 const decl = src_loc.container.decl;1865 const decl = src_loc.container.decl;
1853 const tree = decl.container.file_scope.base.tree();1866 const tree = decl.namespace.file_scope.base.tree();
1854 const node_datas = tree.nodes.items(.data);1867 const node_datas = tree.nodes.items(.data);
1855 const node_tags = tree.nodes.items(.tag);1868 const node_tags = tree.nodes.items(.tag);
1856 const node = decl.relativeToNodeIndex(node_off);1869 const node = decl.relativeToNodeIndex(node_off);
...@@ -1860,7 +1873,7 @@ pub const SrcLoc = struct {...@@ -1860,7 +1873,7 @@ pub const SrcLoc = struct {
1860 },1873 },
1861 .node_offset_asm_source => |node_off| {1874 .node_offset_asm_source => |node_off| {
1862 const decl = src_loc.container.decl;1875 const decl = src_loc.container.decl;
1863 const tree = decl.container.file_scope.base.tree();1876 const tree = decl.namespace.file_scope.base.tree();
1864 const node_datas = tree.nodes.items(.data);1877 const node_datas = tree.nodes.items(.data);
1865 const node_tags = tree.nodes.items(.tag);1878 const node_tags = tree.nodes.items(.tag);
1866 const node = decl.relativeToNodeIndex(node_off);1879 const node = decl.relativeToNodeIndex(node_off);
...@@ -1876,7 +1889,7 @@ pub const SrcLoc = struct {...@@ -1876,7 +1889,7 @@ pub const SrcLoc = struct {
1876 },1889 },
1877 .node_offset_asm_ret_ty => |node_off| {1890 .node_offset_asm_ret_ty => |node_off| {
1878 const decl = src_loc.container.decl;1891 const decl = src_loc.container.decl;
1879 const tree = decl.container.file_scope.base.tree();1892 const tree = decl.namespace.file_scope.base.tree();
1880 const node_datas = tree.nodes.items(.data);1893 const node_datas = tree.nodes.items(.data);
1881 const node_tags = tree.nodes.items(.tag);1894 const node_tags = tree.nodes.items(.tag);
1882 const node = decl.relativeToNodeIndex(node_off);1895 const node = decl.relativeToNodeIndex(node_off);
...@@ -1894,7 +1907,7 @@ pub const SrcLoc = struct {...@@ -1894,7 +1907,7 @@ pub const SrcLoc = struct {
1894 .node_offset_for_cond, .node_offset_if_cond => |node_off| {1907 .node_offset_for_cond, .node_offset_if_cond => |node_off| {
1895 const decl = src_loc.container.decl;1908 const decl = src_loc.container.decl;
1896 const node = decl.relativeToNodeIndex(node_off);1909 const node = decl.relativeToNodeIndex(node_off);
1897 const tree = decl.container.file_scope.base.tree();1910 const tree = decl.namespace.file_scope.base.tree();
1898 const node_tags = tree.nodes.items(.tag);1911 const node_tags = tree.nodes.items(.tag);
1899 const src_node = switch (node_tags[node]) {1912 const src_node = switch (node_tags[node]) {
1900 .if_simple => tree.ifSimple(node).ast.cond_expr,1913 .if_simple => tree.ifSimple(node).ast.cond_expr,
...@@ -1914,7 +1927,7 @@ pub const SrcLoc = struct {...@@ -1914,7 +1927,7 @@ pub const SrcLoc = struct {
1914 .node_offset_bin_lhs => |node_off| {1927 .node_offset_bin_lhs => |node_off| {
1915 const decl = src_loc.container.decl;1928 const decl = src_loc.container.decl;
1916 const node = decl.relativeToNodeIndex(node_off);1929 const node = decl.relativeToNodeIndex(node_off);
1917 const tree = decl.container.file_scope.base.tree();1930 const tree = decl.namespace.file_scope.base.tree();
1918 const node_datas = tree.nodes.items(.data);1931 const node_datas = tree.nodes.items(.data);
1919 const src_node = node_datas[node].lhs;1932 const src_node = node_datas[node].lhs;
1920 const main_tokens = tree.nodes.items(.main_token);1933 const main_tokens = tree.nodes.items(.main_token);
...@@ -1925,7 +1938,7 @@ pub const SrcLoc = struct {...@@ -1925,7 +1938,7 @@ pub const SrcLoc = struct {
1925 .node_offset_bin_rhs => |node_off| {1938 .node_offset_bin_rhs => |node_off| {
1926 const decl = src_loc.container.decl;1939 const decl = src_loc.container.decl;
1927 const node = decl.relativeToNodeIndex(node_off);1940 const node = decl.relativeToNodeIndex(node_off);
1928 const tree = decl.container.file_scope.base.tree();1941 const tree = decl.namespace.file_scope.base.tree();
1929 const node_datas = tree.nodes.items(.data);1942 const node_datas = tree.nodes.items(.data);
1930 const src_node = node_datas[node].rhs;1943 const src_node = node_datas[node].rhs;
1931 const main_tokens = tree.nodes.items(.main_token);1944 const main_tokens = tree.nodes.items(.main_token);
...@@ -1937,7 +1950,7 @@ pub const SrcLoc = struct {...@@ -1937,7 +1950,7 @@ pub const SrcLoc = struct {
1937 .node_offset_switch_operand => |node_off| {1950 .node_offset_switch_operand => |node_off| {
1938 const decl = src_loc.container.decl;1951 const decl = src_loc.container.decl;
1939 const node = decl.relativeToNodeIndex(node_off);1952 const node = decl.relativeToNodeIndex(node_off);
1940 const tree = decl.container.file_scope.base.tree();1953 const tree = decl.namespace.file_scope.base.tree();
1941 const node_datas = tree.nodes.items(.data);1954 const node_datas = tree.nodes.items(.data);
1942 const src_node = node_datas[node].lhs;1955 const src_node = node_datas[node].lhs;
1943 const main_tokens = tree.nodes.items(.main_token);1956 const main_tokens = tree.nodes.items(.main_token);
...@@ -1949,7 +1962,7 @@ pub const SrcLoc = struct {...@@ -1949,7 +1962,7 @@ pub const SrcLoc = struct {
1949 .node_offset_switch_special_prong => |node_off| {1962 .node_offset_switch_special_prong => |node_off| {
1950 const decl = src_loc.container.decl;1963 const decl = src_loc.container.decl;
1951 const switch_node = decl.relativeToNodeIndex(node_off);1964 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();
1953 const node_datas = tree.nodes.items(.data);1966 const node_datas = tree.nodes.items(.data);
1954 const node_tags = tree.nodes.items(.tag);1967 const node_tags = tree.nodes.items(.tag);
1955 const main_tokens = tree.nodes.items(.main_token);1968 const main_tokens = tree.nodes.items(.main_token);
...@@ -1976,7 +1989,7 @@ pub const SrcLoc = struct {...@@ -1976,7 +1989,7 @@ pub const SrcLoc = struct {
1976 .node_offset_switch_range => |node_off| {1989 .node_offset_switch_range => |node_off| {
1977 const decl = src_loc.container.decl;1990 const decl = src_loc.container.decl;
1978 const switch_node = decl.relativeToNodeIndex(node_off);1991 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();
1980 const node_datas = tree.nodes.items(.data);1993 const node_datas = tree.nodes.items(.data);
1981 const node_tags = tree.nodes.items(.tag);1994 const node_tags = tree.nodes.items(.tag);
1982 const main_tokens = tree.nodes.items(.main_token);1995 const main_tokens = tree.nodes.items(.main_token);
...@@ -2006,7 +2019,7 @@ pub const SrcLoc = struct {...@@ -2006,7 +2019,7 @@ pub const SrcLoc = struct {
20062019
2007 .node_offset_fn_type_cc => |node_off| {2020 .node_offset_fn_type_cc => |node_off| {
2008 const decl = src_loc.container.decl;2021 const decl = src_loc.container.decl;
2009 const tree = decl.container.file_scope.base.tree();2022 const tree = decl.namespace.file_scope.base.tree();
2010 const node_datas = tree.nodes.items(.data);2023 const node_datas = tree.nodes.items(.data);
2011 const node_tags = tree.nodes.items(.tag);2024 const node_tags = tree.nodes.items(.tag);
2012 const node = decl.relativeToNodeIndex(node_off);2025 const node = decl.relativeToNodeIndex(node_off);
...@@ -2026,7 +2039,7 @@ pub const SrcLoc = struct {...@@ -2026,7 +2039,7 @@ pub const SrcLoc = struct {
20262039
2027 .node_offset_fn_type_ret_ty => |node_off| {2040 .node_offset_fn_type_ret_ty => |node_off| {
2028 const decl = src_loc.container.decl;2041 const decl = src_loc.container.decl;
2029 const tree = decl.container.file_scope.base.tree();2042 const tree = decl.namespace.file_scope.base.tree();
2030 const node_datas = tree.nodes.items(.data);2043 const node_datas = tree.nodes.items(.data);
2031 const node_tags = tree.nodes.items(.tag);2044 const node_tags = tree.nodes.items(.tag);
2032 const node = decl.relativeToNodeIndex(node_off);2045 const node = decl.relativeToNodeIndex(node_off);
...@@ -2351,7 +2364,6 @@ pub fn deinit(mod: *Module) void {...@@ -2351,7 +2364,6 @@ pub fn deinit(mod: *Module) void {
2351 mod.export_owners.deinit(gpa);2364 mod.export_owners.deinit(gpa);
23522365
2353 mod.symbol_exports.deinit(gpa);2366 mod.symbol_exports.deinit(gpa);
2354 mod.root_scope.destroy(gpa);
23552367
2356 var it = mod.global_error_set.iterator();2368 var it = mod.global_error_set.iterator();
2357 while (it.next()) |entry| {2369 while (it.next()) |entry| {
...@@ -2362,6 +2374,7 @@ pub fn deinit(mod: *Module) void {...@@ -2362,6 +2374,7 @@ pub fn deinit(mod: *Module) void {
2362 mod.error_name_list.deinit(gpa);2374 mod.error_name_list.deinit(gpa);
23632375
2364 for (mod.import_table.items()) |entry| {2376 for (mod.import_table.items()) |entry| {
2377 gpa.free(entry.key);
2365 entry.value.destroy(gpa);2378 entry.value.destroy(gpa);
2366 }2379 }
2367 mod.import_table.deinit(gpa);2380 mod.import_table.deinit(gpa);
...@@ -2465,7 +2478,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2465,7 +2478,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
2465 const tracy = trace(@src());2478 const tracy = trace(@src());
2466 defer tracy.end();2479 defer tracy.end();
24672480
2468 const tree = try mod.getAstTree(decl.container.file_scope);2481 const tree = try mod.getAstTree(decl.namespace.file_scope);
2469 const node_tags = tree.nodes.items(.tag);2482 const node_tags = tree.nodes.items(.tag);
2470 const node_datas = tree.nodes.items(.data);2483 const node_datas = tree.nodes.items(.data);
2471 const decl_node = decl.src_node;2484 const decl_node = decl.src_node;
...@@ -2516,7 +2529,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2516,7 +2529,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
25162529
2517 var gen_scope: Scope.GenZir = .{2530 var gen_scope: Scope.GenZir = .{
2518 .force_comptime = true,2531 .force_comptime = true,
2519 .parent = &decl.container.base,2532 .parent = &decl.namespace.base,
2520 .astgen = &astgen,2533 .astgen = &astgen,
2521 };2534 };
2522 defer gen_scope.instructions.deinit(mod.gpa);2535 defer gen_scope.instructions.deinit(mod.gpa);
...@@ -2590,7 +2603,7 @@ fn astgenAndSemaFn(...@@ -2590,7 +2603,7 @@ fn astgenAndSemaFn(
25902603
2591 var fn_type_scope: Scope.GenZir = .{2604 var fn_type_scope: Scope.GenZir = .{
2592 .force_comptime = true,2605 .force_comptime = true,
2593 .parent = &decl.container.base,2606 .parent = &decl.namespace.base,
2594 .astgen = &fn_type_astgen,2607 .astgen = &fn_type_astgen,
2595 };2608 };
2596 defer fn_type_scope.instructions.deinit(mod.gpa);2609 defer fn_type_scope.instructions.deinit(mod.gpa);
...@@ -2829,7 +2842,7 @@ fn astgenAndSemaFn(...@@ -2829,7 +2842,7 @@ fn astgenAndSemaFn(
28292842
2830 var gen_scope: Scope.GenZir = .{2843 var gen_scope: Scope.GenZir = .{
2831 .force_comptime = false,2844 .force_comptime = false,
2832 .parent = &decl.container.base,2845 .parent = &decl.namespace.base,
2833 .astgen = &astgen,2846 .astgen = &astgen,
2834 };2847 };
2835 defer gen_scope.instructions.deinit(mod.gpa);2848 defer gen_scope.instructions.deinit(mod.gpa);
...@@ -3035,7 +3048,7 @@ fn astgenAndSemaVarDecl(...@@ -3035,7 +3048,7 @@ fn astgenAndSemaVarDecl(
30353048
3036 var gen_scope: Scope.GenZir = .{3049 var gen_scope: Scope.GenZir = .{
3037 .force_comptime = true,3050 .force_comptime = true,
3038 .parent = &decl.container.base,3051 .parent = &decl.namespace.base,
3039 .astgen = &astgen,3052 .astgen = &astgen,
3040 };3053 };
3041 defer gen_scope.instructions.deinit(mod.gpa);3054 defer gen_scope.instructions.deinit(mod.gpa);
...@@ -3104,7 +3117,7 @@ fn astgenAndSemaVarDecl(...@@ -3104,7 +3117,7 @@ fn astgenAndSemaVarDecl(
31043117
3105 var type_scope: Scope.GenZir = .{3118 var type_scope: Scope.GenZir = .{
3106 .force_comptime = true,3119 .force_comptime = true,
3107 .parent = &decl.container.base,3120 .parent = &decl.namespace.base,
3108 .astgen = &astgen,3121 .astgen = &astgen,
3109 };3122 };
3110 defer type_scope.instructions.deinit(mod.gpa);3123 defer type_scope.instructions.deinit(mod.gpa);
...@@ -3220,46 +3233,48 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3...@@ -3220,46 +3233,48 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3
3220 return @intCast(u32, gop.index);3233 return @intCast(u32, gop.index);
3221}3234}
32223235
3223pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {3236pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree {
3224 const tracy = trace(@src());3237 const tracy = trace(@src());
3225 defer tracy.end();3238 defer tracy.end();
32263239
3227 switch (root_scope.status) {3240 switch (file.status) {
3228 .never_loaded, .unloaded_success => {3241 .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
3233 var keep_tree = false;3248 var keep_tree = false;
3234 root_scope.tree = try std.zig.parse(mod.gpa, source);3249 file.tree = try std.zig.parse(gpa, source);
3235 defer if (!keep_tree) root_scope.tree.deinit(mod.gpa);3250 defer if (!keep_tree) file.tree.deinit(gpa);
32363251
3237 const tree = &root_scope.tree;3252 const tree = &file.tree;
32383253
3239 if (tree.errors.len != 0) {3254 if (tree.errors.len != 0) {
3240 const parse_err = tree.errors[0];3255 const parse_err = tree.errors[0];
32413256
3242 var msg = std.ArrayList(u8).init(mod.gpa);3257 var msg = std.ArrayList(u8).init(gpa);
3243 defer msg.deinit();3258 defer msg.deinit();
32443259
3245 const token_starts = tree.tokens.items(.start);3260 const token_starts = tree.tokens.items(.start);
32463261
3247 try tree.renderError(parse_err, msg.writer());3262 try tree.renderError(parse_err, msg.writer());
3248 const err_msg = try mod.gpa.create(ErrorMsg);3263 const err_msg = try gpa.create(ErrorMsg);
3249 err_msg.* = .{3264 err_msg.* = .{
3250 .src_loc = .{3265 .src_loc = .{
3251 .container = .{ .file_scope = root_scope },3266 .container = .{ .file_scope = file },
3252 .lazy = .{ .byte_abs = token_starts[parse_err.token] },3267 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
3253 },3268 },
3254 .msg = msg.toOwnedSlice(),3269 .msg = msg.toOwnedSlice(),
3255 };3270 };
32563271
3257 mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg);3272 mod.failed_files.putAssumeCapacityNoClobber(file, err_msg);
3258 root_scope.status = .unloaded_parse_failure;3273 file.status = .unloaded_parse_failure;
3259 return error.AnalysisFail;3274 return error.AnalysisFail;
3260 }3275 }
32613276
3262 root_scope.status = .loaded_success;3277 file.status = .loaded_success;
3263 keep_tree = true;3278 keep_tree = true;
32643279
3265 return tree;3280 return tree;
...@@ -3267,30 +3282,186 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {...@@ -3267,30 +3282,186 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
32673282
3268 .unloaded_parse_failure => return error.AnalysisFail,3283 .unloaded_parse_failure => return error.AnalysisFail,
32693284
3270 .loaded_success => return &root_scope.tree,3285 .loaded_success => return &file.tree,
3271 }3286 }
3272}3287}
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 {
3275 const tracy = trace(@src());3446 const tracy = trace(@src());
3276 defer tracy.end();3447 defer tracy.end();
32773448
3278 // We may be analyzing it for the first time, or this may be3449 // We may be analyzing it for the first time, or this may be
3279 // an incremental update. This code handles both cases.3450 // 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);
3281 const node_tags = tree.nodes.items(.tag);3452 const node_tags = tree.nodes.items(.tag);
3282 const node_datas = tree.nodes.items(.data);3453 const node_datas = tree.nodes.items(.data);
3283 const decls = tree.rootDecls();3454 const decls = tree.rootDecls();
32843455
3285 try mod.comp.work_queue.ensureUnusedCapacity(decls.len);3456 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 that3459 // Keep track of the decls that we expect to see in this namespace so that
3289 // we know which ones have been deleted.3460 // we know which ones have been deleted.
3290 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);3461 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);
3291 defer deleted_decls.deinit();3462 defer deleted_decls.deinit();
3292 try deleted_decls.ensureCapacity(container_scope.decls.items().len);3463 try deleted_decls.ensureCapacity(namespace.decls.items().len);
3293 for (container_scope.decls.items()) |entry| {3464 for (namespace.decls.items()) |entry| {
3294 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});3465 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
3295 }3466 }
32963467
...@@ -3310,7 +3481,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3310,7 +3481,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3310 .fn_proto_simple => {3481 .fn_proto_simple => {
3311 var params: [1]ast.Node.Index = undefined;3482 var params: [1]ast.Node.Index = undefined;
3312 try mod.semaContainerFn(3483 try mod.semaContainerFn(
3313 container_scope,3484 namespace,
3314 &deleted_decls,3485 &deleted_decls,
3315 &outdated_decls,3486 &outdated_decls,
3316 decl_node,3487 decl_node,
...@@ -3320,7 +3491,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3320,7 +3491,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3320 );3491 );
3321 },3492 },
3322 .fn_proto_multi => try mod.semaContainerFn(3493 .fn_proto_multi => try mod.semaContainerFn(
3323 container_scope,3494 namespace,
3324 &deleted_decls,3495 &deleted_decls,
3325 &outdated_decls,3496 &outdated_decls,
3326 decl_node,3497 decl_node,
...@@ -3331,7 +3502,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3331,7 +3502,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3331 .fn_proto_one => {3502 .fn_proto_one => {
3332 var params: [1]ast.Node.Index = undefined;3503 var params: [1]ast.Node.Index = undefined;
3333 try mod.semaContainerFn(3504 try mod.semaContainerFn(
3334 container_scope,3505 namespace,
3335 &deleted_decls,3506 &deleted_decls,
3336 &outdated_decls,3507 &outdated_decls,
3337 decl_node,3508 decl_node,
...@@ -3341,7 +3512,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3341,7 +3512,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3341 );3512 );
3342 },3513 },
3343 .fn_proto => try mod.semaContainerFn(3514 .fn_proto => try mod.semaContainerFn(
3344 container_scope,3515 namespace,
3345 &deleted_decls,3516 &deleted_decls,
3346 &outdated_decls,3517 &outdated_decls,
3347 decl_node,3518 decl_node,
...@@ -3355,7 +3526,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3355,7 +3526,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3355 .fn_proto_simple => {3526 .fn_proto_simple => {
3356 var params: [1]ast.Node.Index = undefined;3527 var params: [1]ast.Node.Index = undefined;
3357 try mod.semaContainerFn(3528 try mod.semaContainerFn(
3358 container_scope,3529 namespace,
3359 &deleted_decls,3530 &deleted_decls,
3360 &outdated_decls,3531 &outdated_decls,
3361 decl_node,3532 decl_node,
...@@ -3365,7 +3536,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3365,7 +3536,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3365 );3536 );
3366 },3537 },
3367 .fn_proto_multi => try mod.semaContainerFn(3538 .fn_proto_multi => try mod.semaContainerFn(
3368 container_scope,3539 namespace,
3369 &deleted_decls,3540 &deleted_decls,
3370 &outdated_decls,3541 &outdated_decls,
3371 decl_node,3542 decl_node,
...@@ -3376,7 +3547,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3376,7 +3547,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3376 .fn_proto_one => {3547 .fn_proto_one => {
3377 var params: [1]ast.Node.Index = undefined;3548 var params: [1]ast.Node.Index = undefined;
3378 try mod.semaContainerFn(3549 try mod.semaContainerFn(
3379 container_scope,3550 namespace,
3380 &deleted_decls,3551 &deleted_decls,
3381 &outdated_decls,3552 &outdated_decls,
3382 decl_node,3553 decl_node,
...@@ -3386,7 +3557,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3386,7 +3557,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3386 );3557 );
3387 },3558 },
3388 .fn_proto => try mod.semaContainerFn(3559 .fn_proto => try mod.semaContainerFn(
3389 container_scope,3560 namespace,
3390 &deleted_decls,3561 &deleted_decls,
3391 &outdated_decls,3562 &outdated_decls,
3392 decl_node,3563 decl_node,
...@@ -3396,7 +3567,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3396,7 +3567,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3396 ),3567 ),
33973568
3398 .global_var_decl => try mod.semaContainerVar(3569 .global_var_decl => try mod.semaContainerVar(
3399 container_scope,3570 namespace,
3400 &deleted_decls,3571 &deleted_decls,
3401 &outdated_decls,3572 &outdated_decls,
3402 decl_node,3573 decl_node,
...@@ -3404,7 +3575,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3404,7 +3575,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3404 tree.globalVarDecl(decl_node),3575 tree.globalVarDecl(decl_node),
3405 ),3576 ),
3406 .local_var_decl => try mod.semaContainerVar(3577 .local_var_decl => try mod.semaContainerVar(
3407 container_scope,3578 namespace,
3408 &deleted_decls,3579 &deleted_decls,
3409 &outdated_decls,3580 &outdated_decls,
3410 decl_node,3581 decl_node,
...@@ -3412,7 +3583,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3412,7 +3583,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3412 tree.localVarDecl(decl_node),3583 tree.localVarDecl(decl_node),
3413 ),3584 ),
3414 .simple_var_decl => try mod.semaContainerVar(3585 .simple_var_decl => try mod.semaContainerVar(
3415 container_scope,3586 namespace,
3416 &deleted_decls,3587 &deleted_decls,
3417 &outdated_decls,3588 &outdated_decls,
3418 decl_node,3589 decl_node,
...@@ -3420,7 +3591,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3420,7 +3591,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3420 tree.simpleVarDecl(decl_node),3591 tree.simpleVarDecl(decl_node),
3421 ),3592 ),
3422 .aligned_var_decl => try mod.semaContainerVar(3593 .aligned_var_decl => try mod.semaContainerVar(
3423 container_scope,3594 namespace,
3424 &deleted_decls,3595 &deleted_decls,
3425 &outdated_decls,3596 &outdated_decls,
3426 decl_node,3597 decl_node,
...@@ -3433,11 +3604,11 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3433,11 +3604,11 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3433 const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index});3604 const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index});
3434 defer mod.gpa.free(name);3605 defer mod.gpa.free(name);
34353606
3436 const name_hash = container_scope.fullyQualifiedNameHash(name);3607 const name_hash = namespace.fullyQualifiedNameHash(name);
3437 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));3608 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);3610 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
3440 container_scope.decls.putAssumeCapacity(new_decl, {});3611 namespace.decls.putAssumeCapacity(new_decl, {});
3441 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });3612 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
3442 },3613 },
34433614
...@@ -3483,7 +3654,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3483,7 +3654,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34833654
3484fn semaContainerFn(3655fn semaContainerFn(
3485 mod: *Module,3656 mod: *Module,
3486 container_scope: *Scope.Container,3657 namespace: *Scope.Namespace,
3487 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3658 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3488 outdated_decls: *std.AutoArrayHashMap(*Decl, void),3659 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3489 decl_node: ast.Node.Index,3660 decl_node: ast.Node.Index,
...@@ -3500,25 +3671,25 @@ fn semaContainerFn(...@@ -3500,25 +3671,25 @@ fn semaContainerFn(
3500 @panic("TODO missing function name");3671 @panic("TODO missing function name");
3501 };3672 };
3502 const name = tree.tokenSlice(name_token); // TODO use identifierTokenString3673 const name = tree.tokenSlice(name_token); // TODO use identifierTokenString
3503 const name_hash = container_scope.fullyQualifiedNameHash(name);3674 const name_hash = namespace.fullyQualifiedNameHash(name);
3504 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));3675 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
3505 if (mod.decl_table.get(name_hash)) |decl| {3676 if (mod.decl_table.get(name_hash)) |decl| {
3506 // Update the AST Node index of the decl, even if its contents are unchanged, it may3677 // Update the AST node of the decl; even if its contents are unchanged, it may
3507 // have been re-ordered.3678 // have been re-ordered.
3508 const prev_src_node = decl.src_node;3679 const prev_src_node = decl.src_node;
3509 decl.src_node = decl_node;3680 decl.src_node = decl_node;
3510 if (deleted_decls.swapRemove(decl) == null) {3681 if (deleted_decls.swapRemove(decl) == null) {
3511 decl.analysis = .sema_failure;3682 decl.analysis = .sema_failure;
3512 const msg = try ErrorMsg.create(mod.gpa, .{3683 const msg = try ErrorMsg.create(mod.gpa, .{
3513 .container = .{ .file_scope = container_scope.file_scope },3684 .container = .{ .file_scope = namespace.file_scope },
3514 .lazy = .{ .token_abs = name_token },3685 .lazy = .{ .token_abs = name_token },
3515 }, "redefinition of '{s}'", .{decl.name});3686 }, "redeclaration of '{s}'", .{decl.name});
3516 errdefer msg.destroy(mod.gpa);3687 errdefer msg.destroy(mod.gpa);
3517 const other_src_loc: SrcLoc = .{3688 const other_src_loc: SrcLoc = .{
3518 .container = .{ .file_scope = decl.container.file_scope },3689 .container = .{ .file_scope = decl.namespace.file_scope },
3519 .lazy = .{ .node_abs = prev_src_node },3690 .lazy = .{ .node_abs = prev_src_node },
3520 };3691 };
3521 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});3692 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
3522 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);3693 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
3523 } else {3694 } else {
3524 if (!srcHashEql(decl.contents_hash, contents_hash)) {3695 if (!srcHashEql(decl.contents_hash, contents_hash)) {
...@@ -3542,8 +3713,8 @@ fn semaContainerFn(...@@ -3542,8 +3713,8 @@ fn semaContainerFn(
3542 }3713 }
3543 }3714 }
3544 } else {3715 } else {
3545 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);3716 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
3546 container_scope.decls.putAssumeCapacity(new_decl, {});3717 namespace.decls.putAssumeCapacity(new_decl, {});
3547 if (fn_proto.extern_export_token) |maybe_export_token| {3718 if (fn_proto.extern_export_token) |maybe_export_token| {
3548 const token_tags = tree.tokens.items(.tag);3719 const token_tags = tree.tokens.items(.tag);
3549 if (token_tags[maybe_export_token] == .keyword_export) {3720 if (token_tags[maybe_export_token] == .keyword_export) {
...@@ -3556,7 +3727,7 @@ fn semaContainerFn(...@@ -3556,7 +3727,7 @@ fn semaContainerFn(
35563727
3557fn semaContainerVar(3728fn semaContainerVar(
3558 mod: *Module,3729 mod: *Module,
3559 container_scope: *Scope.Container,3730 namespace: *Scope.Namespace,
3560 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3731 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3561 outdated_decls: *std.AutoArrayHashMap(*Decl, void),3732 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3562 decl_node: ast.Node.Index,3733 decl_node: ast.Node.Index,
...@@ -3568,7 +3739,7 @@ fn semaContainerVar(...@@ -3568,7 +3739,7 @@ fn semaContainerVar(
35683739
3569 const name_token = var_decl.ast.mut_token + 1;3740 const name_token = var_decl.ast.mut_token + 1;
3570 const name = tree.tokenSlice(name_token); // TODO identifierTokenString3741 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
3571 const name_hash = container_scope.fullyQualifiedNameHash(name);3742 const name_hash = namespace.fullyQualifiedNameHash(name);
3572 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));3743 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
3573 if (mod.decl_table.get(name_hash)) |decl| {3744 if (mod.decl_table.get(name_hash)) |decl| {
3574 // Update the AST Node index of the decl, even if its contents are unchanged, it may3745 // Update the AST Node index of the decl, even if its contents are unchanged, it may
...@@ -3578,23 +3749,23 @@ fn semaContainerVar(...@@ -3578,23 +3749,23 @@ fn semaContainerVar(
3578 if (deleted_decls.swapRemove(decl) == null) {3749 if (deleted_decls.swapRemove(decl) == null) {
3579 decl.analysis = .sema_failure;3750 decl.analysis = .sema_failure;
3580 const msg = try ErrorMsg.create(mod.gpa, .{3751 const msg = try ErrorMsg.create(mod.gpa, .{
3581 .container = .{ .file_scope = container_scope.file_scope },3752 .container = .{ .file_scope = namespace.file_scope },
3582 .lazy = .{ .token_abs = name_token },3753 .lazy = .{ .token_abs = name_token },
3583 }, "redefinition of '{s}'", .{decl.name});3754 }, "redeclaration of '{s}'", .{decl.name});
3584 errdefer msg.destroy(mod.gpa);3755 errdefer msg.destroy(mod.gpa);
3585 const other_src_loc: SrcLoc = .{3756 const other_src_loc: SrcLoc = .{
3586 .container = .{ .file_scope = decl.container.file_scope },3757 .container = .{ .file_scope = decl.namespace.file_scope },
3587 .lazy = .{ .node_abs = prev_src_node },3758 .lazy = .{ .node_abs = prev_src_node },
3588 };3759 };
3589 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});3760 try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{});
3590 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);3761 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
3591 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {3762 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
3592 try outdated_decls.put(decl, {});3763 try outdated_decls.put(decl, {});
3593 decl.contents_hash = contents_hash;3764 decl.contents_hash = contents_hash;
3594 }3765 }
3595 } else {3766 } else {
3596 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);3767 const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
3597 container_scope.decls.putAssumeCapacity(new_decl, {});3768 namespace.decls.putAssumeCapacity(new_decl, {});
3598 if (var_decl.extern_export_token) |maybe_export_token| {3769 if (var_decl.extern_export_token) |maybe_export_token| {
3599 const token_tags = tree.tokens.items(.tag);3770 const token_tags = tree.tokens.items(.tag);
3600 if (token_tags[maybe_export_token] == .keyword_export) {3771 if (token_tags[maybe_export_token] == .keyword_export) {
...@@ -3624,7 +3795,7 @@ pub fn deleteDecl(...@@ -3624,7 +3795,7 @@ pub fn deleteDecl(
36243795
3625 // Remove from the namespace it resides in. In the case of an anonymous Decl it will3796 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
3626 // not be present in the set, and this does nothing.3797 // not be present in the set, and this does nothing.
3627 decl.container.removeDecl(decl);3798 decl.namespace.removeDecl(decl);
36283799
3629 const name_hash = decl.fullyQualifiedNameHash();3800 const name_hash = decl.fullyQualifiedNameHash();
3630 mod.decl_table.removeAssertDiscard(name_hash);3801 mod.decl_table.removeAssertDiscard(name_hash);
...@@ -3786,7 +3957,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {...@@ -3786,7 +3957,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
37863957
3787fn allocateNewDecl(3958fn allocateNewDecl(
3788 mod: *Module,3959 mod: *Module,
3789 scope: *Scope,3960 namespace: *Scope.Namespace,
3790 src_node: ast.Node.Index,3961 src_node: ast.Node.Index,
3791 contents_hash: std.zig.SrcHash,3962 contents_hash: std.zig.SrcHash,
3792) !*Decl {3963) !*Decl {
...@@ -3802,7 +3973,7 @@ fn allocateNewDecl(...@@ -3802,7 +3973,7 @@ fn allocateNewDecl(
38023973
3803 new_decl.* = .{3974 new_decl.* = .{
3804 .name = "",3975 .name = "",
3805 .container = scope.namespace(),3976 .namespace = namespace,
3806 .src_node = src_node,3977 .src_node = src_node,
3807 .typed_value = .{ .never_succeeded = {} },3978 .typed_value = .{ .never_succeeded = {} },
3808 .analysis = .unreferenced,3979 .analysis = .unreferenced,
...@@ -3832,14 +4003,14 @@ fn allocateNewDecl(...@@ -3832,14 +4003,14 @@ fn allocateNewDecl(
38324003
3833fn createNewDecl(4004fn createNewDecl(
3834 mod: *Module,4005 mod: *Module,
3835 scope: *Scope,4006 namespace: *Scope.Namespace,
3836 decl_name: []const u8,4007 decl_name: []const u8,
3837 src_node: ast.Node.Index,4008 src_node: ast.Node.Index,
3838 name_hash: Scope.NameHash,4009 name_hash: Scope.NameHash,
3839 contents_hash: std.zig.SrcHash,4010 contents_hash: std.zig.SrcHash,
3840) !*Decl {4011) !*Decl {
3841 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);4012 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);
3843 errdefer mod.gpa.destroy(new_decl);4014 errdefer mod.gpa.destroy(new_decl);
3844 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);4015 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
3845 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);4016 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
...@@ -3930,7 +4101,7 @@ pub fn analyzeExport(...@@ -3930,7 +4101,7 @@ pub fn analyzeExport(
3930 );4101 );
3931 errdefer msg.destroy(mod.gpa);4102 errdefer msg.destroy(mod.gpa);
3932 try mod.errNote(4103 try mod.errNote(
3933 &other_export.owner_decl.container.base,4104 &other_export.owner_decl.namespace.base,
3934 other_export.src,4105 other_export.src,
3935 msg,4106 msg,
3936 "other symbol here",4107 "other symbol here",
...@@ -4050,9 +4221,10 @@ pub fn createAnonymousDecl(...@@ -4050,9 +4221,10 @@ pub fn createAnonymousDecl(
4050 const scope_decl = scope.ownerDecl().?;4221 const scope_decl = scope.ownerDecl().?;
4051 const name = try std.fmt.allocPrint(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });4222 const name = try std.fmt.allocPrint(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
4052 defer mod.gpa.free(name);4223 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);
4054 const src_hash: std.zig.SrcHash = undefined;4226 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);
4056 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);4228 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
40574229
4058 decl_arena_state.* = decl_arena.state;4230 decl_arena_state.* = decl_arena.state;
...@@ -4076,55 +4248,30 @@ pub fn createAnonymousDecl(...@@ -4076,55 +4248,30 @@ pub fn createAnonymousDecl(
4076 return new_decl;4248 return new_decl;
4077}4249}
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
4122fn getNextAnonNameIndex(mod: *Module) usize {4251fn getNextAnonNameIndex(mod: *Module) usize {
4123 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);4252 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);
4124}4253}
41254254
4126pub fn lookupDeclName(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {4255/// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces
4127 const namespace = scope.namespace();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 {
4128 const name_hash = namespace.fullyQualifiedNameHash(ident_name);4275 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
4129 return mod.decl_table.get(name_hash);4276 return mod.decl_table.get(name_hash);
4130}4277}
...@@ -4271,7 +4418,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In...@@ -4271,7 +4418,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In
4271 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);4418 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg);
4272 },4419 },
4273 .file => unreachable,4420 .file => unreachable,
4274 .container => unreachable,4421 .namespace => unreachable,
4275 .decl_ref => {4422 .decl_ref => {
4276 const decl_ref = scope.cast(Scope.DeclRef).?;4423 const decl_ref = scope.cast(Scope.DeclRef).?;
4277 decl_ref.decl.analysis = .sema_failure;4424 decl_ref.decl.analysis = .sema_failure;
...@@ -4683,10 +4830,3 @@ pub fn parseStrLit(...@@ -4683,10 +4830,3 @@ pub fn parseStrLit(
4683 },4830 },
4684 }4831 }
4685}4832}
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(...@@ -609,10 +609,11 @@ fn zirStructDecl(
609 .owner_decl = sema.owner_decl,609 .owner_decl = sema.owner_decl,
610 .fields = fields_map,610 .fields = fields_map,
611 .node_offset = inst_data.src_node,611 .node_offset = inst_data.src_node,
612 .container = .{612 .namespace = .{
613 .parent = sema.owner_decl.namespace,
614 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
613 .ty = struct_ty,615 .ty = struct_ty,
614 .file_scope = block.getFileScope(),616 .file_scope = block.getFileScope(),
615 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
616 },617 },
617 };618 };
618 return sema.analyzeDeclVal(block, src, new_decl);619 return sema.analyzeDeclVal(block, src, new_decl);
...@@ -3640,42 +3641,43 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError...@@ -3640,42 +3641,43 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
3640 const mod = sema.mod;3641 const mod = sema.mod;
3641 const arena = sema.arena;3642 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(
3644 &block.base,3645 &block.base,
3645 lhs_src,3646 lhs_src,
3646 "expected struct, enum, union, or opaque, found '{}'",3647 "expected struct, enum, union, or opaque, found '{}'",
3647 .{container_type},3648 .{container_type},
3648 );3649 );
3649 if (mod.lookupDeclName(&container_scope.base, decl_name)) |decl| {3650 if (mod.lookupInNamespace(namespace, decl_name)) |decl| {
3650 // TODO if !decl.is_pub and inDifferentFiles() return false3651 if (decl.is_pub or decl.namespace.file_scope == block.base.namespace().file_scope) {
3651 return mod.constBool(arena, src, true);3652 return mod.constBool(arena, src, true);
3652 } else {3653 }
3653 return mod.constBool(arena, src, false);
3654 }3654 }
3655 return mod.constBool(arena, src, false);
3655}3656}
36563657
3657fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {3658fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
3658 const tracy = trace(@src());3659 const tracy = trace(@src());
3659 defer tracy.end();3660 defer tracy.end();
36603661
3662 const mod = sema.mod;
3661 const inst_data = sema.code.instructions.items(.data)[inst].un_node;3663 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
3662 const src = inst_data.src();3664 const src = inst_data.src();
3663 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };3665 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
3664 const operand = try sema.resolveConstString(block, operand_src, inst_data.operand);3666 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) {
3667 error.ImportOutsidePkgPath => {3669 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});
3669 },3671 },
3670 error.FileNotFound => {3672 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});
3672 },3674 },
3673 else => {3675 else => {
3674 // TODO: make sure this gets retried and not cached3676 // 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) });
3676 },3678 },
3677 };3679 };
3678 return sema.mod.constType(sema.arena, src, file_scope.root_container.ty);3680 return mod.constType(sema.arena, src, file.namespace.ty);
3679}3681}
36803682
3681fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {3683fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
...@@ -4707,21 +4709,9 @@ fn namedFieldPtr(...@@ -4707,21 +4709,9 @@ fn namedFieldPtr(
4707 });4709 });
4708 },4710 },
4709 .Struct, .Opaque, .Union => {4711 .Struct, .Opaque, .Union => {
4710 if (child_type.getContainerScope()) |container_scope| {4712 if (child_type.getNamespace()) |namespace| {
4711 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {4713 if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {
4712 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))4714 return inst;
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 );
4725 }4715 }
4726 }4716 }
4727 // TODO add note: declared here4717 // TODO add note: declared here
...@@ -4736,11 +4726,9 @@ fn namedFieldPtr(...@@ -4736,11 +4726,9 @@ fn namedFieldPtr(
4736 });4726 });
4737 },4727 },
4738 .Enum => {4728 .Enum => {
4739 if (child_type.getContainerScope()) |container_scope| {4729 if (child_type.getNamespace()) |namespace| {
4740 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {4730 if (try sema.analyzeNamespaceLookup(block, src, namespace, field_name)) |inst| {
4741 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))4731 return inst;
4742 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
4743 return sema.analyzeDeclRef(block, src, decl);
4744 }4732 }
4745 }4733 }
4746 const field_index = child_type.enumFieldIndex(field_name) orelse {4734 const field_index = child_type.enumFieldIndex(field_name) orelse {
...@@ -4778,6 +4766,32 @@ fn namedFieldPtr(...@@ -4778,6 +4766,32 @@ fn namedFieldPtr(
4778 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});4766 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
4779}4767}
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
4781fn analyzeStructFieldPtr(4795fn analyzeStructFieldPtr(
4782 sema: *Sema,4796 sema: *Sema,
4783 block: *Scope.Block,4797 block: *Scope.Block,
...@@ -5326,65 +5340,6 @@ fn analyzeSlice(...@@ -5326,65 +5340,6 @@ fn analyzeSlice(
5326 return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{});5340 return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{});
5327}5341}
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
5388/// Asserts that lhs and rhs types are both numeric.5343/// Asserts that lhs and rhs types are both numeric.
5389fn cmpNumeric(5344fn cmpNumeric(
5390 sema: *Sema,5345 sema: *Sema,
src/codegen.zig+2-2
...@@ -411,8 +411,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -411,8 +411,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
411 try branch_stack.append(.{});411 try branch_stack.append(.{});
412412
413 const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: {413 const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: {
414 const container_scope = module_fn.owner_decl.container;414 const namespace = module_fn.owner_decl.namespace;
415 const tree = container_scope.file_scope.tree;415 const tree = namespace.file_scope.tree;
416 const node_tags = tree.nodes.items(.tag);416 const node_tags = tree.nodes.items(.tag);
417 const node_datas = tree.nodes.items(.data);417 const node_datas = tree.nodes.items(.data);
418 const token_starts = tree.tokens.items(.start);418 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 {...@@ -2223,7 +2223,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2223 try dbg_line_buffer.ensureCapacity(26);2223 try dbg_line_buffer.ensureCapacity(26);
22242224
2225 const line_off: u28 = blk: {2225 const line_off: u28 = blk: {
2226 const tree = decl.container.file_scope.tree;2226 const tree = decl.namespace.file_scope.tree;
2227 const node_tags = tree.nodes.items(.tag);2227 const node_tags = tree.nodes.items(.tag);
2228 const node_datas = tree.nodes.items(.data);2228 const node_datas = tree.nodes.items(.data);
2229 const token_starts = tree.tokens.items(.start);2229 const token_starts = tree.tokens.items(.start);
...@@ -2749,7 +2749,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec...@@ -2749,7 +2749,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
27492749
2750 if (self.llvm_object) |_| return;2750 if (self.llvm_object) |_| return;
27512751
2752 const tree = decl.container.file_scope.tree;2752 const tree = decl.namespace.file_scope.tree;
2753 const node_tags = tree.nodes.items(.tag);2753 const node_tags = tree.nodes.items(.tag);
2754 const node_datas = tree.nodes.items(.data);2754 const node_datas = tree.nodes.items(.data);
2755 const token_starts = tree.tokens.items(.start);2755 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...@@ -904,7 +904,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
904 const tracy = trace(@src());904 const tracy = trace(@src());
905 defer tracy.end();905 defer tracy.end();
906906
907 const tree = decl.container.file_scope.tree;907 const tree = decl.namespace.file_scope.tree;
908 const node_tags = tree.nodes.items(.tag);908 const node_tags = tree.nodes.items(.tag);
909 const node_datas = tree.nodes.items(.data);909 const node_datas = tree.nodes.items(.data);
910 const token_starts = tree.tokens.items(.start);910 const token_starts = tree.tokens.items(.start);
...@@ -953,7 +953,7 @@ pub fn initDeclDebugBuffers(...@@ -953,7 +953,7 @@ pub fn initDeclDebugBuffers(
953 try dbg_line_buffer.ensureCapacity(26);953 try dbg_line_buffer.ensureCapacity(26);
954954
955 const line_off: u28 = blk: {955 const line_off: u28 = blk: {
956 const tree = decl.container.file_scope.tree;956 const tree = decl.namespace.file_scope.tree;
957 const node_tags = tree.nodes.items(.tag);957 const node_tags = tree.nodes.items(.tag);
958 const node_datas = tree.nodes.items(.data);958 const node_datas = tree.nodes.items(.data);
959 const token_starts = tree.tokens.items(.start);959 const token_starts = tree.tokens.items(.start);
src/type.zig+29-6
...@@ -2052,11 +2052,11 @@ pub const Type = extern union {...@@ -2052,11 +2052,11 @@ pub const Type = extern union {
2052 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);2052 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
2053 }2053 }
20542054
2055 /// Returns null if the type has no container.2055 /// Returns null if the type has no namespace.
2056 pub fn getContainerScope(self: Type) ?*Module.Scope.Container {2056 pub fn getNamespace(self: Type) ?*Module.Scope.Namespace {
2057 return switch (self.tag()) {2057 return switch (self.tag()) {
2058 .@"struct" => &self.castTag(.@"struct").?.data.container,2058 .@"struct" => &self.castTag(.@"struct").?.data.namespace,
2059 .enum_full => &self.castTag(.enum_full).?.data.container,2059 .enum_full => &self.castTag(.enum_full).?.data.namespace,
2060 .empty_struct => self.castTag(.empty_struct).?.data,2060 .empty_struct => self.castTag(.empty_struct).?.data,
2061 .@"opaque" => &self.castTag(.@"opaque").?.data,2061 .@"opaque" => &self.castTag(.@"opaque").?.data,
20622062
...@@ -2226,6 +2226,29 @@ pub const Type = extern union {...@@ -2226,6 +2226,29 @@ pub const Type = extern union {
2226 }2226 }
2227 }2227 }
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
2229 /// Asserts the type is an enum.2252 /// Asserts the type is an enum.
2230 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {2253 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
2231 const S = struct {2254 const S = struct {
...@@ -2564,12 +2587,12 @@ pub const Type = extern union {...@@ -2564,12 +2587,12 @@ pub const Type = extern union {
2564 /// Most commonly used for files.2587 /// Most commonly used for files.
2565 pub const ContainerScope = struct {2588 pub const ContainerScope = struct {
2566 base: Payload,2589 base: Payload,
2567 data: *Module.Scope.Container,2590 data: *Module.Scope.Namespace,
2568 };2591 };
25692592
2570 pub const Opaque = struct {2593 pub const Opaque = struct {
2571 base: Payload = .{ .tag = .@"opaque" },2594 base: Payload = .{ .tag = .@"opaque" },
2572 data: Module.Scope.Container,2595 data: Module.Scope.Namespace,
2573 };2596 };
25742597
2575 pub const Struct = struct {2598 pub const Struct = struct {
test/stage2/test.zig+13-9
...@@ -1048,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1048,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {
1048 "Hello, World!\n",1048 "Hello, World!\n",
1049 );1049 );
1050 try case.files.append(.{1050 try case.files.append(.{
1051 .src =1051 .src =
1052 \\pub fn print() void {1052 \\pub fn print() void {
1053 \\ asm volatile ("syscall"1053 \\ asm volatile ("syscall"
1054 \\ :1054 \\ :
...@@ -1082,10 +1082,14 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1082,10 +1082,14 @@ pub fn addCases(ctx: *TestContext) !void {
1082 \\ unreachable;1082 \\ unreachable;
1083 \\}1083 \\}
1084 ,1084 ,
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 },
1086 );1089 );
1087 try case.files.append(.{1090 try case.files.append(.{
1088 .src =1091 .src =
1092 \\// dummy comment to make print be on line 2
1089 \\fn print() void {1093 \\fn print() void {
1090 \\ asm volatile ("syscall"1094 \\ asm volatile ("syscall"
1091 \\ :1095 \\ :
...@@ -1102,22 +1106,22 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1102,22 +1106,22 @@ pub fn addCases(ctx: *TestContext) !void {
1102 });1106 });
1103 }1107 }
11041108
1105 ctx.compileError("function redefinition", linux_x64,1109 ctx.compileError("function redeclaration", linux_x64,
1106 \\// dummy comment1110 \\// dummy comment
1107 \\fn entry() void {}1111 \\fn entry() void {}
1108 \\fn entry() void {}1112 \\fn entry() void {}
1109 , &[_][]const u8{1113 , &[_][]const u8{
1110 ":3:4: error: redefinition of 'entry'",1114 ":3:4: error: redeclaration of 'entry'",
1111 ":2:1: note: previous definition here",1115 ":2:1: note: previously declared here",
1112 });1116 });
11131117
1114 ctx.compileError("global variable redefinition", linux_x64,1118 ctx.compileError("global variable redeclaration", linux_x64,
1115 \\// dummy comment1119 \\// dummy comment
1116 \\var foo = false;1120 \\var foo = false;
1117 \\var foo = true;1121 \\var foo = true;
1118 , &[_][]const u8{1122 , &[_][]const u8{
1119 ":3:5: error: redefinition of 'foo'",1123 ":3:5: error: redeclaration of 'foo'",
1120 ":2:1: note: previous definition here",1124 ":2:1: note: previously declared here",
1121 });1125 });
11221126
1123 ctx.compileError("compileError", linux_x64,1127 ctx.compileError("compileError", linux_x64,