Commit 6d71d79dc2

mlugg <mlugg@mlugg.co.uk>
2023-01-22 17:12:40
Package: store package name directly
By @Vexu's suggestion, since fetching the name from the parent package is error-prone and complex, and optimising Package for size isn't really a priority.
1 parent c0284e2
src/Compilation.zig
@@ -1610,6 +1610,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
 
             const builtin_pkg = try Package.createWithDir(
                 gpa,
+                "builtin",
                 zig_cache_artifact_directory,
                 null,
                 "builtin.zig",
@@ -1618,6 +1619,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
 
             const std_pkg = try Package.createWithDir(
                 gpa,
+                "std",
                 options.zig_lib_directory,
                 "std",
                 "std.zig",
@@ -1625,11 +1627,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
             errdefer std_pkg.destroy(gpa);
 
             const root_pkg = if (options.is_test) root_pkg: {
+                // TODO: we currently have two packages named 'root' here, which is weird. This
+                // should be changed as part of the resolution of #12201
                 const test_pkg = if (options.test_runner_path) |test_runner|
-                    try Package.create(gpa, null, test_runner)
+                    try Package.create(gpa, "root", null, test_runner)
                 else
                     try Package.createWithDir(
                         gpa,
+                        "root",
                         options.zig_lib_directory,
                         null,
                         "test_runner.zig",
@@ -1640,9 +1645,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
             } else main_pkg;
             errdefer if (options.is_test) root_pkg.destroy(gpa);
 
-            try main_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);
-            try main_pkg.add(gpa, "root", root_pkg);
-            try main_pkg.addAndAdopt(gpa, "std", std_pkg);
+            try main_pkg.addAndAdopt(gpa, builtin_pkg);
+            try main_pkg.add(gpa, root_pkg);
+            try main_pkg.addAndAdopt(gpa, std_pkg);
 
             const main_pkg_is_std = m: {
                 const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
@@ -5320,6 +5325,7 @@ fn buildOutputFromZig(
     var main_pkg: Package = .{
         .root_src_directory = comp.zig_lib_directory,
         .root_src_path = src_basename,
+        .name = "root",
     };
     defer main_pkg.deinitTable(comp.gpa);
     const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
src/main.zig
@@ -857,6 +857,7 @@ fn buildOutputType(
     var pkg_tree_root: Package = .{
         .root_src_directory = .{ .path = null, .handle = fs.cwd() },
         .root_src_path = &[0]u8{},
+        .name = &[0]u8{},
     };
     defer freePkgTree(gpa, &pkg_tree_root, false);
     var cur_pkg: *Package = &pkg_tree_root;
@@ -947,6 +948,7 @@ fn buildOutputType(
 
                         const new_cur_pkg = Package.create(
                             gpa,
+                            pkg_name,
                             fs.path.dirname(pkg_path),
                             fs.path.basename(pkg_path),
                         ) catch |err| {
@@ -958,7 +960,7 @@ fn buildOutputType(
                         } else if (cur_pkg.table.get(pkg_name)) |prev| {
                             fatal("unable to add package '{s}' -> '{s}': already exists as '{s}", .{ pkg_name, pkg_path, prev.root_src_path });
                         }
-                        try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg);
+                        try cur_pkg.addAndAdopt(gpa, new_cur_pkg);
                         cur_pkg = new_cur_pkg;
                     } else if (mem.eql(u8, arg, "--pkg-end")) {
                         cur_pkg = cur_pkg.parent orelse
@@ -2841,14 +2843,14 @@ fn buildOutputType(
         if (main_pkg_path) |unresolved_main_pkg_path| {
             const p = try introspect.resolvePath(arena, unresolved_main_pkg_path);
             if (p.len == 0) {
-                break :blk try Package.create(gpa, null, src_path);
+                break :blk try Package.create(gpa, "root", null, src_path);
             } else {
                 const rel_src_path = try fs.path.relative(arena, p, src_path);
-                break :blk try Package.create(gpa, p, rel_src_path);
+                break :blk try Package.create(gpa, "root", p, rel_src_path);
             }
         } else {
             const root_src_dir_path = fs.path.dirname(src_path);
-            break :blk Package.create(gpa, root_src_dir_path, fs.path.basename(src_path)) catch |err| {
+            break :blk Package.create(gpa, "root", root_src_dir_path, fs.path.basename(src_path)) catch |err| {
                 if (root_src_dir_path) |p| {
                     fatal("unable to open '{s}': {s}", .{ p, @errorName(err) });
                 } else {
@@ -4093,6 +4095,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
         var main_pkg: Package = .{
             .root_src_directory = zig_lib_directory,
             .root_src_path = "build_runner.zig",
+            .name = "root",
         };
 
         if (!build_options.omit_pkg_fetching_code) {
@@ -4133,20 +4136,22 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
 
             const deps_pkg = try Package.createFilePkg(
                 gpa,
+                "@dependencies",
                 local_cache_directory,
                 "dependencies.zig",
                 dependencies_source.items,
             );
 
             mem.swap(Package.Table, &main_pkg.table, &deps_pkg.table);
-            try main_pkg.addAndAdopt(gpa, "@dependencies", deps_pkg);
+            try main_pkg.addAndAdopt(gpa, deps_pkg);
         }
 
         var build_pkg: Package = .{
             .root_src_directory = build_directory,
             .root_src_path = build_zig_basename,
+            .name = "@build",
         };
-        try main_pkg.addAndAdopt(gpa, "@build", &build_pkg);
+        try main_pkg.addAndAdopt(gpa, &build_pkg);
 
         const comp = Compilation.create(gpa, .{
             .zig_lib_directory = zig_lib_directory,
@@ -4381,7 +4386,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
                 .root_decl = .none,
             };
 
-            file.pkg = try Package.create(gpa, null, file.sub_file_path);
+            file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);
             defer file.pkg.destroy(gpa);
 
             file.zir = try AstGen.generate(gpa, file.tree);
@@ -4591,7 +4596,7 @@ fn fmtPathFile(
             .root_decl = .none,
         };
 
-        file.pkg = try Package.create(fmt.gpa, null, file.sub_file_path);
+        file.pkg = try Package.create(fmt.gpa, "root", null, file.sub_file_path);
         defer file.pkg.destroy(fmt.gpa);
 
         if (stat.size > max_src_size)
@@ -5303,7 +5308,7 @@ pub fn cmdAstCheck(
         file.stat.size = source.len;
     }
 
-    file.pkg = try Package.create(gpa, null, file.sub_file_path);
+    file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);
     defer file.pkg.destroy(gpa);
 
     file.tree = try std.zig.parse(gpa, file.source);
@@ -5422,7 +5427,7 @@ pub fn cmdChangelist(
         .root_decl = .none,
     };
 
-    file.pkg = try Package.create(gpa, null, file.sub_file_path);
+    file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);
     defer file.pkg.destroy(gpa);
 
     const source = try arena.allocSentinel(u8, @intCast(usize, stat.size), 0);
src/Module.zig
@@ -3220,16 +3220,11 @@ pub fn deinit(mod: *Module) void {
     // The callsite of `Compilation.create` owns the `main_pkg`, however
     // Module owns the builtin and std packages that it adds.
     if (mod.main_pkg.table.fetchRemove("builtin")) |kv| {
-        gpa.free(kv.key);
         kv.value.destroy(gpa);
     }
     if (mod.main_pkg.table.fetchRemove("std")) |kv| {
-        gpa.free(kv.key);
         kv.value.destroy(gpa);
     }
-    if (mod.main_pkg.table.fetchRemove("root")) |kv| {
-        gpa.free(kv.key);
-    }
     if (mod.root_pkg != mod.main_pkg) {
         mod.root_pkg.destroy(gpa);
     }
src/Package.zig
@@ -24,10 +24,13 @@ table: Table = .{},
 parent: ?*Package = null,
 /// Whether to free `root_src_directory` on `destroy`.
 root_src_directory_owned: bool = false,
+/// This information can be recovered from 'table', but it's more convenient to store on the package.
+name: []const u8,
 
 /// Allocate a Package. No references to the slices passed are kept.
 pub fn create(
     gpa: Allocator,
+    name: []const u8,
     /// Null indicates the current working directory
     root_src_dir_path: ?[]const u8,
     /// Relative to root_src_dir_path
@@ -42,6 +45,9 @@ pub fn create(
     const owned_src_path = try gpa.dupe(u8, root_src_path);
     errdefer gpa.free(owned_src_path);
 
+    const owned_name = try gpa.dupe(u8, name);
+    errdefer gpa.free(owned_name);
+
     ptr.* = .{
         .root_src_directory = .{
             .path = owned_dir_path,
@@ -49,6 +55,7 @@ pub fn create(
         },
         .root_src_path = owned_src_path,
         .root_src_directory_owned = true,
+        .name = owned_name,
     };
 
     return ptr;
@@ -56,6 +63,7 @@ pub fn create(
 
 pub fn createWithDir(
     gpa: Allocator,
+    name: []const u8,
     directory: Compilation.Directory,
     /// Relative to `directory`. If null, means `directory` is the root src dir
     /// and is owned externally.
@@ -69,6 +77,9 @@ pub fn createWithDir(
     const owned_src_path = try gpa.dupe(u8, root_src_path);
     errdefer gpa.free(owned_src_path);
 
+    const owned_name = try gpa.dupe(u8, name);
+    errdefer gpa.free(owned_name);
+
     if (root_src_dir_path) |p| {
         const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});
         errdefer gpa.free(owned_dir_path);
@@ -80,12 +91,14 @@ pub fn createWithDir(
             },
             .root_src_directory_owned = true,
             .root_src_path = owned_src_path,
+            .name = owned_name,
         };
     } else {
         ptr.* = .{
             .root_src_directory = directory,
             .root_src_directory_owned = false,
             .root_src_path = owned_src_path,
+            .name = owned_name,
         };
     }
     return ptr;
@@ -95,6 +108,7 @@ pub fn createWithDir(
 /// inside its table; the caller is responsible for calling destroy() on them.
 pub fn destroy(pkg: *Package, gpa: Allocator) void {
     gpa.free(pkg.root_src_path);
+    gpa.free(pkg.name);
 
     if (pkg.root_src_directory_owned) {
         // 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 {
 
 /// Only frees memory associated with the table.
 pub fn deinitTable(pkg: *Package, gpa: Allocator) void {
-    var it = pkg.table.keyIterator();
-    while (it.next()) |key| {
-        gpa.free(key.*);
-    }
-
     pkg.table.deinit(gpa);
 }
 
-pub fn add(pkg: *Package, gpa: Allocator, name: []const u8, package: *Package) !void {
+pub fn add(pkg: *Package, gpa: Allocator, package: *Package) !void {
     try pkg.table.ensureUnusedCapacity(gpa, 1);
-    const name_dupe = try gpa.dupe(u8, name);
-    pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
+    pkg.table.putAssumeCapacityNoClobber(package.name, package);
 }
 
-pub fn addAndAdopt(parent: *Package, gpa: Allocator, name: []const u8, child: *Package) !void {
+pub fn addAndAdopt(parent: *Package, gpa: Allocator, child: *Package) !void {
     assert(child.parent == null); // make up your mind, who is the parent??
     child.parent = parent;
-    return parent.add(gpa, name, child);
+    return parent.add(gpa, child);
 }
 
 pub const build_zig_basename = "build.zig";
@@ -237,7 +245,7 @@ pub fn fetchAndAddDependencies(
             sub_prefix,
         );
 
-        try addAndAdopt(pkg, gpa, fqn, sub_pkg);
+        try addAndAdopt(pkg, gpa, sub_pkg);
 
         try dependencies_source.writer().print("    pub const {s} = @import(\"{}\");\n", .{
             std.zig.fmtId(fqn), std.zig.fmtEscapes(fqn),
@@ -249,6 +257,7 @@ pub fn fetchAndAddDependencies(
 
 pub fn createFilePkg(
     gpa: Allocator,
+    name: []const u8,
     cache_directory: Compilation.Directory,
     basename: []const u8,
     contents: []const u8,
@@ -269,7 +278,7 @@ pub fn createFilePkg(
     const o_dir_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;
     try renameTmpIntoCache(cache_directory.handle, tmp_dir_sub_path, o_dir_sub_path);
 
-    return createWithDir(gpa, cache_directory, o_dir_sub_path, basename);
+    return createWithDir(gpa, name, cache_directory, o_dir_sub_path, basename);
 }
 
 fn fetchAndUnpack(
@@ -312,6 +321,9 @@ fn fetchAndUnpack(
         const owned_src_path = try gpa.dupe(u8, build_zig_basename);
         errdefer gpa.free(owned_src_path);
 
+        const owned_name = try gpa.dupe(u8, fqn);
+        errdefer gpa.free(owned_name);
+
         const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});
         errdefer gpa.free(build_root);
 
@@ -326,6 +338,7 @@ fn fetchAndUnpack(
             },
             .root_src_directory_owned = true,
             .root_src_path = owned_src_path,
+            .name = owned_name,
         };
 
         return ptr;
@@ -414,7 +427,7 @@ fn fetchAndUnpack(
         std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),
     });
 
-    return createWithDir(gpa, global_cache_directory, pkg_dir_sub_path, build_zig_basename);
+    return createWithDir(gpa, fqn, global_cache_directory, pkg_dir_sub_path, build_zig_basename);
 }
 
 fn reportError(
src/Sema.zig
@@ -5211,6 +5211,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
     }
     const c_import_pkg = Package.create(
         sema.gpa,
+        "c_import", // TODO: should we make this unique?
         null,
         c_import_res.out_zig_path,
     ) catch |err| switch (err) {
@@ -11663,20 +11664,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
         },
         error.PackageNotFound => {
             const cur_pkg = block.getFileScope().pkg;
-            const parent = if (cur_pkg == sema.mod.main_pkg or cur_pkg == sema.mod.root_pkg)
-                "root"
-            else if (cur_pkg.parent) |parent| blk: {
-                var it = parent.table.iterator();
-                while (it.next()) |pkg| {
-                    if (pkg.value_ptr.* == cur_pkg) {
-                        break :blk pkg.key_ptr.*;
-                    }
-                }
-                unreachable;
-            } else {
-                return sema.fail(block, operand_src, "no package named '{s}' available", .{operand});
-            };
-            return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, parent });
+            return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, cur_pkg.name });
         },
         else => {
             // TODO: these errors are file system errors; make sure an update() will
src/test.zig
@@ -1497,6 +1497,7 @@ pub const TestContext = struct {
         var main_pkg: Package = .{
             .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
             .root_src_path = tmp_src_path,
+            .name = "root",
         };
         defer main_pkg.table.deinit(allocator);