authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-23 14:25:42+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-23 14:25:42+02:00
log220020599cc11764eb9ed32025dd506f2affedda
tree4467fe3ff1f919eec89bafac7435fe58cf9a876a
parentd395127552ab6f04b7b044b2a309e0d1e8977775
parent5f9186d0ce78ce1eb7db9634849b38d2e90d071e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13670 from mlugg/fix/astgen-ambiguous-package

AstGen: detect and error on files included in multiple packages

6 files changed, 172 insertions(+), 56 deletions(-)

src/Compilation.zig+71-14
...@@ -639,14 +639,6 @@ pub const AllErrors = struct {...@@ -639,14 +639,6 @@ pub const AllErrors = struct {
639 note_i += 1;639 note_i += 1;
640 }640 }
641 }641 }
642 if (module_err_msg.src_loc.lazy == .entire_file) {
643 try errors.append(.{
644 .plain = .{
645 .msg = try allocator.dupe(u8, module_err_msg.msg),
646 },
647 });
648 return;
649 }
650642
651 const reference_trace = try allocator.alloc(Message, module_err_msg.reference_trace.len);643 const reference_trace = try allocator.alloc(Message, module_err_msg.reference_trace.len);
652 for (reference_trace) |*reference, i| {644 for (reference_trace) |*reference, i| {
...@@ -683,7 +675,7 @@ pub const AllErrors = struct {...@@ -683,7 +675,7 @@ pub const AllErrors = struct {
683 .column = @intCast(u32, err_loc.column),675 .column = @intCast(u32, err_loc.column),
684 .notes = notes_buf[0..note_i],676 .notes = notes_buf[0..note_i],
685 .reference_trace = reference_trace,677 .reference_trace = reference_trace,
686 .source_line = try allocator.dupe(u8, err_loc.source_line),678 .source_line = if (module_err_msg.src_loc.lazy == .entire_file) null else try allocator.dupe(u8, err_loc.source_line),
687 },679 },
688 });680 });
689 }681 }
...@@ -1610,6 +1602,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1610,6 +1602,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16101602
1611 const builtin_pkg = try Package.createWithDir(1603 const builtin_pkg = try Package.createWithDir(
1612 gpa,1604 gpa,
1605 "builtin",
1613 zig_cache_artifact_directory,1606 zig_cache_artifact_directory,
1614 null,1607 null,
1615 "builtin.zig",1608 "builtin.zig",
...@@ -1618,6 +1611,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1618,6 +1611,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16181611
1619 const std_pkg = try Package.createWithDir(1612 const std_pkg = try Package.createWithDir(
1620 gpa,1613 gpa,
1614 "std",
1621 options.zig_lib_directory,1615 options.zig_lib_directory,
1622 "std",1616 "std",
1623 "std.zig",1617 "std.zig",
...@@ -1625,11 +1619,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1625,11 +1619,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1625 errdefer std_pkg.destroy(gpa);1619 errdefer std_pkg.destroy(gpa);
16261620
1627 const root_pkg = if (options.is_test) root_pkg: {1621 const root_pkg = if (options.is_test) root_pkg: {
1622 // TODO: we currently have two packages named 'root' here, which is weird. This
1623 // should be changed as part of the resolution of #12201
1628 const test_pkg = if (options.test_runner_path) |test_runner|1624 const test_pkg = if (options.test_runner_path) |test_runner|
1629 try Package.create(gpa, null, test_runner)1625 try Package.create(gpa, "root", null, test_runner)
1630 else1626 else
1631 try Package.createWithDir(1627 try Package.createWithDir(
1632 gpa,1628 gpa,
1629 "root",
1633 options.zig_lib_directory,1630 options.zig_lib_directory,
1634 null,1631 null,
1635 "test_runner.zig",1632 "test_runner.zig",
...@@ -1640,9 +1637,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1640,9 +1637,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1640 } else main_pkg;1637 } else main_pkg;
1641 errdefer if (options.is_test) root_pkg.destroy(gpa);1638 errdefer if (options.is_test) root_pkg.destroy(gpa);
16421639
1643 try main_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);1640 try main_pkg.addAndAdopt(gpa, builtin_pkg);
1644 try main_pkg.add(gpa, "root", root_pkg);1641 try main_pkg.add(gpa, root_pkg);
1645 try main_pkg.addAndAdopt(gpa, "std", std_pkg);1642 try main_pkg.addAndAdopt(gpa, std_pkg);
16461643
1647 const main_pkg_is_std = m: {1644 const main_pkg_is_std = m: {
1648 const std_path = try std.fs.path.resolve(arena, &[_][]const u8{1645 const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
...@@ -3075,6 +3072,57 @@ pub fn performAllTheWork(...@@ -3075,6 +3072,57 @@ pub fn performAllTheWork(
3075 }3072 }
3076 }3073 }
30773074
3075 if (comp.bin_file.options.module) |mod| {
3076 for (mod.import_table.values()) |file| {
3077 if (!file.multi_pkg) continue;
3078 const err = err_blk: {
3079 const notes = try mod.gpa.alloc(Module.ErrorMsg, file.references.items.len);
3080 errdefer mod.gpa.free(notes);
3081
3082 for (notes) |*note, i| {
3083 errdefer for (notes[0..i]) |*n| n.deinit(mod.gpa);
3084 note.* = switch (file.references.items[i]) {
3085 .import => |loc| try Module.ErrorMsg.init(
3086 mod.gpa,
3087 loc,
3088 "imported from package {s}",
3089 .{loc.file_scope.pkg.name},
3090 ),
3091 .root => |pkg| try Module.ErrorMsg.init(
3092 mod.gpa,
3093 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
3094 "root of package {s}",
3095 .{pkg.name},
3096 ),
3097 };
3098 }
3099 errdefer for (notes) |*n| n.deinit(mod.gpa);
3100
3101 const err = try Module.ErrorMsg.create(
3102 mod.gpa,
3103 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
3104 "file exists in multiple packages",
3105 .{},
3106 );
3107 err.notes = notes;
3108 break :err_blk err;
3109 };
3110 errdefer err.destroy(mod.gpa);
3111 try mod.failed_files.putNoClobber(mod.gpa, file, err);
3112 }
3113
3114 // Now that we've reported the errors, we need to deal with
3115 // dependencies. Any file referenced by a multi_pkg file should also be
3116 // marked multi_pkg and have its status set to astgen_failure, as it's
3117 // ambiguous which package they should be analyzed as a part of. We need
3118 // to add this flag after reporting the errors however, as otherwise
3119 // we'd get an error for every single downstream file, which wouldn't be
3120 // very useful.
3121 for (mod.import_table.values()) |file| {
3122 if (file.multi_pkg) file.recursiveMarkMultiPkg(mod);
3123 }
3124 }
3125
3078 {3126 {
3079 const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls");3127 const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls");
3080 defer outdated_and_deleted_decls_frame.end();3128 defer outdated_and_deleted_decls_frame.end();
...@@ -3499,7 +3547,15 @@ fn workerAstGenFile(...@@ -3499,7 +3547,15 @@ fn workerAstGenFile(
3499 comp.mutex.lock();3547 comp.mutex.lock();
3500 defer comp.mutex.unlock();3548 defer comp.mutex.unlock();
35013549
3502 break :blk mod.importFile(file, import_path) catch continue;3550 const res = mod.importFile(file, import_path) catch continue;
3551 if (!res.is_pkg) {
3552 res.file.addReference(mod.*, .{ .import = .{
3553 .file_scope = file,
3554 .parent_decl_node = 0,
3555 .lazy = .{ .token_abs = item.data.token },
3556 } }) catch continue;
3557 }
3558 break :blk res;
3503 };3559 };
3504 if (import_result.is_new) {3560 if (import_result.is_new) {
3505 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{3561 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
...@@ -5327,6 +5383,7 @@ fn buildOutputFromZig(...@@ -5327,6 +5383,7 @@ fn buildOutputFromZig(
5327 var main_pkg: Package = .{5383 var main_pkg: Package = .{
5328 .root_src_directory = comp.zig_lib_directory,5384 .root_src_directory = comp.zig_lib_directory,
5329 .root_src_path = src_basename,5385 .root_src_path = src_basename,
5386 .name = "root",
5330 };5387 };
5331 defer main_pkg.deinitTable(comp.gpa);5388 defer main_pkg.deinitTable(comp.gpa);
5332 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];5389 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
src/Module.zig+57-5
...@@ -1943,6 +1943,10 @@ pub const File = struct {...@@ -1943,6 +1943,10 @@ pub const File = struct {
1943 zir: Zir,1943 zir: Zir,
1944 /// Package that this file is a part of, managed externally.1944 /// Package that this file is a part of, managed externally.
1945 pkg: *Package,1945 pkg: *Package,
1946 /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
1947 multi_pkg: bool = false,
1948 /// List of references to this file, used for multi-package errors.
1949 references: std.ArrayListUnmanaged(Reference) = .{},
19461950
1947 /// Used by change detection algorithm, after astgen, contains the1951 /// Used by change detection algorithm, after astgen, contains the
1948 /// set of decls that existed in the previous ZIR but not in the new one.1952 /// set of decls that existed in the previous ZIR but not in the new one.
...@@ -1958,6 +1962,14 @@ pub const File = struct {...@@ -1958,6 +1962,14 @@ pub const File = struct {
1958 /// successful, this field is unloaded.1962 /// successful, this field is unloaded.
1959 prev_zir: ?*Zir = null,1963 prev_zir: ?*Zir = null,
19601964
1965 /// A single reference to a file.
1966 const Reference = union(enum) {
1967 /// The file is imported directly (i.e. not as a package) with @import.
1968 import: SrcLoc,
1969 /// The file is the root of a package.
1970 root: *Package,
1971 };
1972
1961 pub fn unload(file: *File, gpa: Allocator) void {1973 pub fn unload(file: *File, gpa: Allocator) void {
1962 file.unloadTree(gpa);1974 file.unloadTree(gpa);
1963 file.unloadSource(gpa);1975 file.unloadSource(gpa);
...@@ -1990,6 +2002,7 @@ pub const File = struct {...@@ -1990,6 +2002,7 @@ pub const File = struct {
1990 log.debug("deinit File {s}", .{file.sub_file_path});2002 log.debug("deinit File {s}", .{file.sub_file_path});
1991 file.deleted_decls.deinit(gpa);2003 file.deleted_decls.deinit(gpa);
1992 file.outdated_decls.deinit(gpa);2004 file.outdated_decls.deinit(gpa);
2005 file.references.deinit(gpa);
1993 if (file.root_decl.unwrap()) |root_decl| {2006 if (file.root_decl.unwrap()) |root_decl| {
1994 mod.destroyDecl(root_decl);2007 mod.destroyDecl(root_decl);
1995 }2008 }
...@@ -2110,6 +2123,44 @@ pub const File = struct {...@@ -2110,6 +2123,44 @@ pub const File = struct {
2110 else => true,2123 else => true,
2111 };2124 };
2112 }2125 }
2126
2127 /// Add a reference to this file during AstGen.
2128 pub fn addReference(file: *File, mod: Module, ref: Reference) !void {
2129 try file.references.append(mod.gpa, ref);
2130
2131 const pkg = switch (ref) {
2132 .import => |loc| loc.file_scope.pkg,
2133 .root => |pkg| pkg,
2134 };
2135 if (pkg != file.pkg) file.multi_pkg = true;
2136 }
2137
2138 /// Mark this file and every file referenced by it as multi_pkg and report an
2139 /// astgen_failure error for them. AstGen must have completed in its entirety.
2140 pub fn recursiveMarkMultiPkg(file: *File, mod: *Module) void {
2141 file.multi_pkg = true;
2142 file.status = .astgen_failure;
2143
2144 std.debug.assert(file.zir_loaded);
2145 const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)];
2146 if (imports_index == 0) return;
2147 const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);
2148
2149 var import_i: u32 = 0;
2150 var extra_index = extra.end;
2151 while (import_i < extra.data.imports_len) : (import_i += 1) {
2152 const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index);
2153 extra_index = item.end;
2154
2155 const import_path = file.zir.nullTerminatedString(item.data.name);
2156 if (mem.eql(u8, import_path, "builtin")) continue;
2157
2158 const res = mod.importFile(file, import_path) catch continue;
2159 if (!res.is_pkg and !res.file.multi_pkg) {
2160 res.file.recursiveMarkMultiPkg(mod);
2161 }
2162 }
2163 }
2113};2164};
21142165
2115/// Represents the contents of a file loaded with `@embedFile`.2166/// Represents the contents of a file loaded with `@embedFile`.
...@@ -3220,16 +3271,11 @@ pub fn deinit(mod: *Module) void {...@@ -3220,16 +3271,11 @@ pub fn deinit(mod: *Module) void {
3220 // The callsite of `Compilation.create` owns the `main_pkg`, however3271 // The callsite of `Compilation.create` owns the `main_pkg`, however
3221 // Module owns the builtin and std packages that it adds.3272 // Module owns the builtin and std packages that it adds.
3222 if (mod.main_pkg.table.fetchRemove("builtin")) |kv| {3273 if (mod.main_pkg.table.fetchRemove("builtin")) |kv| {
3223 gpa.free(kv.key);
3224 kv.value.destroy(gpa);3274 kv.value.destroy(gpa);
3225 }3275 }
3226 if (mod.main_pkg.table.fetchRemove("std")) |kv| {3276 if (mod.main_pkg.table.fetchRemove("std")) |kv| {
3227 gpa.free(kv.key);
3228 kv.value.destroy(gpa);3277 kv.value.destroy(gpa);
3229 }3278 }
3230 if (mod.main_pkg.table.fetchRemove("root")) |kv| {
3231 gpa.free(kv.key);
3232 }
3233 if (mod.root_pkg != mod.main_pkg) {3279 if (mod.root_pkg != mod.main_pkg) {
3234 mod.root_pkg.destroy(gpa);3280 mod.root_pkg.destroy(gpa);
3235 }3281 }
...@@ -4695,6 +4741,7 @@ pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_...@@ -4695,6 +4741,7 @@ pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_
4695pub const ImportFileResult = struct {4741pub const ImportFileResult = struct {
4696 file: *File,4742 file: *File,
4697 is_new: bool,4743 is_new: bool,
4744 is_pkg: bool,
4698};4745};
46994746
4700pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {4747pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
...@@ -4714,6 +4761,7 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {...@@ -4714,6 +4761,7 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
4714 if (gop.found_existing) return ImportFileResult{4761 if (gop.found_existing) return ImportFileResult{
4715 .file = gop.value_ptr.*,4762 .file = gop.value_ptr.*,
4716 .is_new = false,4763 .is_new = false,
4764 .is_pkg = true,
4717 };4765 };
47184766
4719 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);4767 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
...@@ -4737,9 +4785,11 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {...@@ -4737,9 +4785,11 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
4737 .pkg = pkg,4785 .pkg = pkg,
4738 .root_decl = .none,4786 .root_decl = .none,
4739 };4787 };
4788 try new_file.addReference(mod.*, .{ .root = pkg });
4740 return ImportFileResult{4789 return ImportFileResult{
4741 .file = new_file,4790 .file = new_file,
4742 .is_new = true,4791 .is_new = true,
4792 .is_pkg = true,
4743 };4793 };
4744}4794}
47454795
...@@ -4780,6 +4830,7 @@ pub fn importFile(...@@ -4780,6 +4830,7 @@ pub fn importFile(
4780 if (gop.found_existing) return ImportFileResult{4830 if (gop.found_existing) return ImportFileResult{
4781 .file = gop.value_ptr.*,4831 .file = gop.value_ptr.*,
4782 .is_new = false,4832 .is_new = false,
4833 .is_pkg = false,
4783 };4834 };
47844835
4785 const new_file = try gpa.create(File);4836 const new_file = try gpa.create(File);
...@@ -4825,6 +4876,7 @@ pub fn importFile(...@@ -4825,6 +4876,7 @@ pub fn importFile(
4825 return ImportFileResult{4876 return ImportFileResult{
4826 .file = new_file,4877 .file = new_file,
4827 .is_new = true,4878 .is_new = true,
4879 .is_pkg = false,
4828 };4880 };
4829}4881}
48304882
src/Package.zig+26-13
...@@ -24,10 +24,13 @@ table: Table = .{},...@@ -24,10 +24,13 @@ table: Table = .{},
24parent: ?*Package = null,24parent: ?*Package = null,
25/// Whether to free `root_src_directory` on `destroy`.25/// Whether to free `root_src_directory` on `destroy`.
26root_src_directory_owned: bool = false,26root_src_directory_owned: bool = false,
27/// This information can be recovered from 'table', but it's more convenient to store on the package.
28name: []const u8,
2729
28/// Allocate a Package. No references to the slices passed are kept.30/// Allocate a Package. No references to the slices passed are kept.
29pub fn create(31pub fn create(
30 gpa: Allocator,32 gpa: Allocator,
33 name: []const u8,
31 /// Null indicates the current working directory34 /// Null indicates the current working directory
32 root_src_dir_path: ?[]const u8,35 root_src_dir_path: ?[]const u8,
33 /// Relative to root_src_dir_path36 /// Relative to root_src_dir_path
...@@ -42,6 +45,9 @@ pub fn create(...@@ -42,6 +45,9 @@ pub fn create(
42 const owned_src_path = try gpa.dupe(u8, root_src_path);45 const owned_src_path = try gpa.dupe(u8, root_src_path);
43 errdefer gpa.free(owned_src_path);46 errdefer gpa.free(owned_src_path);
4447
48 const owned_name = try gpa.dupe(u8, name);
49 errdefer gpa.free(owned_name);
50
45 ptr.* = .{51 ptr.* = .{
46 .root_src_directory = .{52 .root_src_directory = .{
47 .path = owned_dir_path,53 .path = owned_dir_path,
...@@ -49,6 +55,7 @@ pub fn create(...@@ -49,6 +55,7 @@ pub fn create(
49 },55 },
50 .root_src_path = owned_src_path,56 .root_src_path = owned_src_path,
51 .root_src_directory_owned = true,57 .root_src_directory_owned = true,
58 .name = owned_name,
52 };59 };
5360
54 return ptr;61 return ptr;
...@@ -56,6 +63,7 @@ pub fn create(...@@ -56,6 +63,7 @@ pub fn create(
5663
57pub fn createWithDir(64pub fn createWithDir(
58 gpa: Allocator,65 gpa: Allocator,
66 name: []const u8,
59 directory: Compilation.Directory,67 directory: Compilation.Directory,
60 /// Relative to `directory`. If null, means `directory` is the root src dir68 /// Relative to `directory`. If null, means `directory` is the root src dir
61 /// and is owned externally.69 /// and is owned externally.
...@@ -69,6 +77,9 @@ pub fn createWithDir(...@@ -69,6 +77,9 @@ pub fn createWithDir(
69 const owned_src_path = try gpa.dupe(u8, root_src_path);77 const owned_src_path = try gpa.dupe(u8, root_src_path);
70 errdefer gpa.free(owned_src_path);78 errdefer gpa.free(owned_src_path);
7179
80 const owned_name = try gpa.dupe(u8, name);
81 errdefer gpa.free(owned_name);
82
72 if (root_src_dir_path) |p| {83 if (root_src_dir_path) |p| {
73 const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});84 const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});
74 errdefer gpa.free(owned_dir_path);85 errdefer gpa.free(owned_dir_path);
...@@ -80,12 +91,14 @@ pub fn createWithDir(...@@ -80,12 +91,14 @@ pub fn createWithDir(
80 },91 },
81 .root_src_directory_owned = true,92 .root_src_directory_owned = true,
82 .root_src_path = owned_src_path,93 .root_src_path = owned_src_path,
94 .name = owned_name,
83 };95 };
84 } else {96 } else {
85 ptr.* = .{97 ptr.* = .{
86 .root_src_directory = directory,98 .root_src_directory = directory,
87 .root_src_directory_owned = false,99 .root_src_directory_owned = false,
88 .root_src_path = owned_src_path,100 .root_src_path = owned_src_path,
101 .name = owned_name,
89 };102 };
90 }103 }
91 return ptr;104 return ptr;
...@@ -95,6 +108,7 @@ pub fn createWithDir(...@@ -95,6 +108,7 @@ pub fn createWithDir(
95/// inside its table; the caller is responsible for calling destroy() on them.108/// inside its table; the caller is responsible for calling destroy() on them.
96pub fn destroy(pkg: *Package, gpa: Allocator) void {109pub fn destroy(pkg: *Package, gpa: Allocator) void {
97 gpa.free(pkg.root_src_path);110 gpa.free(pkg.root_src_path);
111 gpa.free(pkg.name);
98112
99 if (pkg.root_src_directory_owned) {113 if (pkg.root_src_directory_owned) {
100 // If root_src_directory.path is null then the handle is the cwd()114 // If root_src_directory.path is null then the handle is the cwd()
...@@ -111,24 +125,18 @@ pub fn destroy(pkg: *Package, gpa: Allocator) void {...@@ -111,24 +125,18 @@ pub fn destroy(pkg: *Package, gpa: Allocator) void {
111125
112/// Only frees memory associated with the table.126/// Only frees memory associated with the table.
113pub fn deinitTable(pkg: *Package, gpa: Allocator) void {127pub fn deinitTable(pkg: *Package, gpa: Allocator) void {
114 var it = pkg.table.keyIterator();
115 while (it.next()) |key| {
116 gpa.free(key.*);
117 }
118
119 pkg.table.deinit(gpa);128 pkg.table.deinit(gpa);
120}129}
121130
122pub fn add(pkg: *Package, gpa: Allocator, name: []const u8, package: *Package) !void {131pub fn add(pkg: *Package, gpa: Allocator, package: *Package) !void {
123 try pkg.table.ensureUnusedCapacity(gpa, 1);132 try pkg.table.ensureUnusedCapacity(gpa, 1);
124 const name_dupe = try gpa.dupe(u8, name);133 pkg.table.putAssumeCapacityNoClobber(package.name, package);
125 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
126}134}
127135
128pub fn addAndAdopt(parent: *Package, gpa: Allocator, name: []const u8, child: *Package) !void {136pub fn addAndAdopt(parent: *Package, gpa: Allocator, child: *Package) !void {
129 assert(child.parent == null); // make up your mind, who is the parent??137 assert(child.parent == null); // make up your mind, who is the parent??
130 child.parent = parent;138 child.parent = parent;
131 return parent.add(gpa, name, child);139 return parent.add(gpa, child);
132}140}
133141
134pub const build_zig_basename = "build.zig";142pub const build_zig_basename = "build.zig";
...@@ -237,7 +245,7 @@ pub fn fetchAndAddDependencies(...@@ -237,7 +245,7 @@ pub fn fetchAndAddDependencies(
237 sub_prefix,245 sub_prefix,
238 );246 );
239247
240 try addAndAdopt(pkg, gpa, fqn, sub_pkg);248 try addAndAdopt(pkg, gpa, sub_pkg);
241249
242 try dependencies_source.writer().print(" pub const {s} = @import(\"{}\");\n", .{250 try dependencies_source.writer().print(" pub const {s} = @import(\"{}\");\n", .{
243 std.zig.fmtId(fqn), std.zig.fmtEscapes(fqn),251 std.zig.fmtId(fqn), std.zig.fmtEscapes(fqn),
...@@ -249,6 +257,7 @@ pub fn fetchAndAddDependencies(...@@ -249,6 +257,7 @@ pub fn fetchAndAddDependencies(
249257
250pub fn createFilePkg(258pub fn createFilePkg(
251 gpa: Allocator,259 gpa: Allocator,
260 name: []const u8,
252 cache_directory: Compilation.Directory,261 cache_directory: Compilation.Directory,
253 basename: []const u8,262 basename: []const u8,
254 contents: []const u8,263 contents: []const u8,
...@@ -269,7 +278,7 @@ pub fn createFilePkg(...@@ -269,7 +278,7 @@ pub fn createFilePkg(
269 const o_dir_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;278 const o_dir_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;
270 try renameTmpIntoCache(cache_directory.handle, tmp_dir_sub_path, o_dir_sub_path);279 try renameTmpIntoCache(cache_directory.handle, tmp_dir_sub_path, o_dir_sub_path);
271280
272 return createWithDir(gpa, cache_directory, o_dir_sub_path, basename);281 return createWithDir(gpa, name, cache_directory, o_dir_sub_path, basename);
273}282}
274283
275fn fetchAndUnpack(284fn fetchAndUnpack(
...@@ -312,6 +321,9 @@ fn fetchAndUnpack(...@@ -312,6 +321,9 @@ fn fetchAndUnpack(
312 const owned_src_path = try gpa.dupe(u8, build_zig_basename);321 const owned_src_path = try gpa.dupe(u8, build_zig_basename);
313 errdefer gpa.free(owned_src_path);322 errdefer gpa.free(owned_src_path);
314323
324 const owned_name = try gpa.dupe(u8, fqn);
325 errdefer gpa.free(owned_name);
326
315 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});327 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});
316 errdefer gpa.free(build_root);328 errdefer gpa.free(build_root);
317329
...@@ -326,6 +338,7 @@ fn fetchAndUnpack(...@@ -326,6 +338,7 @@ fn fetchAndUnpack(
326 },338 },
327 .root_src_directory_owned = true,339 .root_src_directory_owned = true,
328 .root_src_path = owned_src_path,340 .root_src_path = owned_src_path,
341 .name = owned_name,
329 };342 };
330343
331 return ptr;344 return ptr;
...@@ -414,7 +427,7 @@ fn fetchAndUnpack(...@@ -414,7 +427,7 @@ fn fetchAndUnpack(
414 std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),427 std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),
415 });428 });
416429
417 return createWithDir(gpa, global_cache_directory, pkg_dir_sub_path, build_zig_basename);430 return createWithDir(gpa, fqn, global_cache_directory, pkg_dir_sub_path, build_zig_basename);
418}431}
419432
420fn reportError(433fn reportError(
src/Sema.zig+2-14
...@@ -5211,6 +5211,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5211,6 +5211,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5211 }5211 }
5212 const c_import_pkg = Package.create(5212 const c_import_pkg = Package.create(
5213 sema.gpa,5213 sema.gpa,
5214 "c_import", // TODO: should we make this unique?
5214 null,5215 null,
5215 c_import_res.out_zig_path,5216 c_import_res.out_zig_path,
5216 ) catch |err| switch (err) {5217 ) catch |err| switch (err) {
...@@ -11663,20 +11664,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -11663,20 +11664,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
11663 },11664 },
11664 error.PackageNotFound => {11665 error.PackageNotFound => {
11665 const cur_pkg = block.getFileScope().pkg;11666 const cur_pkg = block.getFileScope().pkg;
11666 const parent = if (cur_pkg == sema.mod.main_pkg or cur_pkg == sema.mod.root_pkg)11667 return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, cur_pkg.name });
11667 "root"
11668 else if (cur_pkg.parent) |parent| blk: {
11669 var it = parent.table.iterator();
11670 while (it.next()) |pkg| {
11671 if (pkg.value_ptr.* == cur_pkg) {
11672 break :blk pkg.key_ptr.*;
11673 }
11674 }
11675 unreachable;
11676 } else {
11677 return sema.fail(block, operand_src, "no package named '{s}' available", .{operand});
11678 };
11679 return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, parent });
11680 },11668 },
11681 else => {11669 else => {
11682 // TODO: these errors are file system errors; make sure an update() will11670 // TODO: these errors are file system errors; make sure an update() will
src/main.zig+15-10
...@@ -857,6 +857,7 @@ fn buildOutputType(...@@ -857,6 +857,7 @@ fn buildOutputType(
857 var pkg_tree_root: Package = .{857 var pkg_tree_root: Package = .{
858 .root_src_directory = .{ .path = null, .handle = fs.cwd() },858 .root_src_directory = .{ .path = null, .handle = fs.cwd() },
859 .root_src_path = &[0]u8{},859 .root_src_path = &[0]u8{},
860 .name = &[0]u8{},
860 };861 };
861 defer freePkgTree(gpa, &pkg_tree_root, false);862 defer freePkgTree(gpa, &pkg_tree_root, false);
862 var cur_pkg: *Package = &pkg_tree_root;863 var cur_pkg: *Package = &pkg_tree_root;
...@@ -947,6 +948,7 @@ fn buildOutputType(...@@ -947,6 +948,7 @@ fn buildOutputType(
947948
948 const new_cur_pkg = Package.create(949 const new_cur_pkg = Package.create(
949 gpa,950 gpa,
951 pkg_name,
950 fs.path.dirname(pkg_path),952 fs.path.dirname(pkg_path),
951 fs.path.basename(pkg_path),953 fs.path.basename(pkg_path),
952 ) catch |err| {954 ) catch |err| {
...@@ -958,7 +960,7 @@ fn buildOutputType(...@@ -958,7 +960,7 @@ fn buildOutputType(
958 } else if (cur_pkg.table.get(pkg_name)) |prev| {960 } else if (cur_pkg.table.get(pkg_name)) |prev| {
959 fatal("unable to add package '{s}' -> '{s}': already exists as '{s}", .{ pkg_name, pkg_path, prev.root_src_path });961 fatal("unable to add package '{s}' -> '{s}': already exists as '{s}", .{ pkg_name, pkg_path, prev.root_src_path });
960 }962 }
961 try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg);963 try cur_pkg.addAndAdopt(gpa, new_cur_pkg);
962 cur_pkg = new_cur_pkg;964 cur_pkg = new_cur_pkg;
963 } else if (mem.eql(u8, arg, "--pkg-end")) {965 } else if (mem.eql(u8, arg, "--pkg-end")) {
964 cur_pkg = cur_pkg.parent orelse966 cur_pkg = cur_pkg.parent orelse
...@@ -2841,14 +2843,14 @@ fn buildOutputType(...@@ -2841,14 +2843,14 @@ fn buildOutputType(
2841 if (main_pkg_path) |unresolved_main_pkg_path| {2843 if (main_pkg_path) |unresolved_main_pkg_path| {
2842 const p = try introspect.resolvePath(arena, unresolved_main_pkg_path);2844 const p = try introspect.resolvePath(arena, unresolved_main_pkg_path);
2843 if (p.len == 0) {2845 if (p.len == 0) {
2844 break :blk try Package.create(gpa, null, src_path);2846 break :blk try Package.create(gpa, "root", null, src_path);
2845 } else {2847 } else {
2846 const rel_src_path = try fs.path.relative(arena, p, src_path);2848 const rel_src_path = try fs.path.relative(arena, p, src_path);
2847 break :blk try Package.create(gpa, p, rel_src_path);2849 break :blk try Package.create(gpa, "root", p, rel_src_path);
2848 }2850 }
2849 } else {2851 } else {
2850 const root_src_dir_path = fs.path.dirname(src_path);2852 const root_src_dir_path = fs.path.dirname(src_path);
2851 break :blk Package.create(gpa, root_src_dir_path, fs.path.basename(src_path)) catch |err| {2853 break :blk Package.create(gpa, "root", root_src_dir_path, fs.path.basename(src_path)) catch |err| {
2852 if (root_src_dir_path) |p| {2854 if (root_src_dir_path) |p| {
2853 fatal("unable to open '{s}': {s}", .{ p, @errorName(err) });2855 fatal("unable to open '{s}': {s}", .{ p, @errorName(err) });
2854 } else {2856 } else {
...@@ -4093,6 +4095,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4093,6 +4095,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4093 var main_pkg: Package = .{4095 var main_pkg: Package = .{
4094 .root_src_directory = zig_lib_directory,4096 .root_src_directory = zig_lib_directory,
4095 .root_src_path = "build_runner.zig",4097 .root_src_path = "build_runner.zig",
4098 .name = "root",
4096 };4099 };
40974100
4098 if (!build_options.omit_pkg_fetching_code) {4101 if (!build_options.omit_pkg_fetching_code) {
...@@ -4133,20 +4136,22 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4133,20 +4136,22 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
41334136
4134 const deps_pkg = try Package.createFilePkg(4137 const deps_pkg = try Package.createFilePkg(
4135 gpa,4138 gpa,
4139 "@dependencies",
4136 local_cache_directory,4140 local_cache_directory,
4137 "dependencies.zig",4141 "dependencies.zig",
4138 dependencies_source.items,4142 dependencies_source.items,
4139 );4143 );
41404144
4141 mem.swap(Package.Table, &main_pkg.table, &deps_pkg.table);4145 mem.swap(Package.Table, &main_pkg.table, &deps_pkg.table);
4142 try main_pkg.addAndAdopt(gpa, "@dependencies", deps_pkg);4146 try main_pkg.addAndAdopt(gpa, deps_pkg);
4143 }4147 }
41444148
4145 var build_pkg: Package = .{4149 var build_pkg: Package = .{
4146 .root_src_directory = build_directory,4150 .root_src_directory = build_directory,
4147 .root_src_path = build_zig_basename,4151 .root_src_path = build_zig_basename,
4152 .name = "@build",
4148 };4153 };
4149 try main_pkg.addAndAdopt(gpa, "@build", &build_pkg);4154 try main_pkg.addAndAdopt(gpa, &build_pkg);
41504155
4151 const comp = Compilation.create(gpa, .{4156 const comp = Compilation.create(gpa, .{
4152 .zig_lib_directory = zig_lib_directory,4157 .zig_lib_directory = zig_lib_directory,
...@@ -4381,7 +4386,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -4381,7 +4386,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
4381 .root_decl = .none,4386 .root_decl = .none,
4382 };4387 };
43834388
4384 file.pkg = try Package.create(gpa, null, file.sub_file_path);4389 file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);
4385 defer file.pkg.destroy(gpa);4390 defer file.pkg.destroy(gpa);
43864391
4387 file.zir = try AstGen.generate(gpa, file.tree);4392 file.zir = try AstGen.generate(gpa, file.tree);
...@@ -4592,7 +4597,7 @@ fn fmtPathFile(...@@ -4592,7 +4597,7 @@ fn fmtPathFile(
4592 .root_decl = .none,4597 .root_decl = .none,
4593 };4598 };
45944599
4595 file.pkg = try Package.create(fmt.gpa, null, file.sub_file_path);4600 file.pkg = try Package.create(fmt.gpa, "root", null, file.sub_file_path);
4596 defer file.pkg.destroy(fmt.gpa);4601 defer file.pkg.destroy(fmt.gpa);
45974602
4598 if (stat.size > max_src_size)4603 if (stat.size > max_src_size)
...@@ -5304,7 +5309,7 @@ pub fn cmdAstCheck(...@@ -5304,7 +5309,7 @@ pub fn cmdAstCheck(
5304 file.stat.size = source.len;5309 file.stat.size = source.len;
5305 }5310 }
53065311
5307 file.pkg = try Package.create(gpa, null, file.sub_file_path);5312 file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);
5308 defer file.pkg.destroy(gpa);5313 defer file.pkg.destroy(gpa);
53095314
5310 file.tree = try std.zig.parse(gpa, file.source);5315 file.tree = try std.zig.parse(gpa, file.source);
...@@ -5423,7 +5428,7 @@ pub fn cmdChangelist(...@@ -5423,7 +5428,7 @@ pub fn cmdChangelist(
5423 .root_decl = .none,5428 .root_decl = .none,
5424 };5429 };
54255430
5426 file.pkg = try Package.create(gpa, null, file.sub_file_path);5431 file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);
5427 defer file.pkg.destroy(gpa);5432 defer file.pkg.destroy(gpa);
54285433
5429 const source = try arena.allocSentinel(u8, @intCast(usize, stat.size), 0);5434 const source = try arena.allocSentinel(u8, @intCast(usize, stat.size), 0);
src/test.zig+1
...@@ -1497,6 +1497,7 @@ pub const TestContext = struct {...@@ -1497,6 +1497,7 @@ pub const TestContext = struct {
1497 var main_pkg: Package = .{1497 var main_pkg: Package = .{
1498 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },1498 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
1499 .root_src_path = tmp_src_path,1499 .root_src_path = tmp_src_path,
1500 .name = "root",
1500 };1501 };
1501 defer main_pkg.table.deinit(allocator);1502 defer main_pkg.table.deinit(allocator);
15021503