authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-16 19:45:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-16 19:45:58-07:00
loge13fc6b119c5593b4fccd5ae064c6b251bbe50e7
treef54c3357f9c9b3ca0e34635dab09f4000bbf2c5b
parent415ef1be510e912ddbd3b73a4d20aac3fda27a0e

stage2: make `@import` relative to the current file

previously, it was incorrectly relative to the package directory

3 files changed, 86 insertions(+), 21 deletions(-)

src/Compilation.zig+4-2
......@@ -1535,7 +1535,8 @@ pub fn update(self: *Compilation) !void {
15351535
15361536 // Make sure std.zig is inside the import_table. We unconditionally need
15371537 // it for start.zig.
1538 _ = try module.importFile(module.root_pkg, "std");
1538 const std_pkg = module.root_pkg.table.get("std").?;
1539 _ = try module.importPkg(module.root_pkg, std_pkg);
15391540
15401541 // Put a work item in for every known source file to detect if
15411542 // it changed, and, if so, re-compute ZIR and then queue the job
......@@ -2118,6 +2119,7 @@ fn workerAstGenFile(
21182119 // there is a missing `failed_files` error message.
21192120 error.OutOfMemory => {},
21202121 };
2122 return;
21212123 },
21222124 };
21232125
......@@ -2136,7 +2138,7 @@ fn workerAstGenFile(
21362138 const lock = comp.mutex.acquire();
21372139 defer lock.release();
21382140
2139 break :blk mod.importFile(file.pkg, import_path) catch continue;
2141 break :blk mod.importFile(file, import_path) catch continue;
21402142 };
21412143 if (import_result.is_new) {
21422144 wg.start();
src/Module.zig+81-18
......@@ -739,6 +739,7 @@ pub const Scope = struct {
739739 }
740740
741741 pub fn deinit(file: *File, gpa: *Allocator) void {
742 gpa.free(file.sub_file_path);
742743 file.unload(gpa);
743744 file.* = undefined;
744745 }
......@@ -746,6 +747,11 @@ pub const Scope = struct {
746747 pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {
747748 if (file.source_loaded) return file.source;
748749
750 const root_dir_path = file.pkg.root_src_directory.path orelse ".";
751 log.debug("File.getSource, not cached. pkgdir={s} sub_file_path={s}", .{
752 root_dir_path, file.sub_file_path,
753 });
754
749755 // Keep track of inode, file size, mtime, hash so we can detect which files
750756 // have been modified when an incremental update is requested.
751757 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
......@@ -2633,20 +2639,70 @@ pub const ImportFileResult = struct {
26332639 is_new: bool,
26342640};
26352641
2642pub fn importPkg(mod: *Module, cur_pkg: *Package, pkg: *Package) !ImportFileResult {
2643 const gpa = mod.gpa;
2644
2645 // The resolved path is used as the key in the import table, to detect if
2646 // an import refers to the same as another, despite different relative paths
2647 // or differently mapped package names.
2648 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
2649 pkg.root_src_directory.path orelse ".", pkg.root_src_path,
2650 });
2651 var keep_resolved_path = false;
2652 defer if (!keep_resolved_path) gpa.free(resolved_path);
2653
2654 const gop = try mod.import_table.getOrPut(gpa, resolved_path);
2655 if (gop.found_existing) return ImportFileResult{
2656 .file = gop.entry.value,
2657 .is_new = false,
2658 };
2659 keep_resolved_path = true; // It's now owned by import_table.
2660
2661 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
2662 errdefer gpa.free(sub_file_path);
2663
2664 const new_file = try gpa.create(Scope.File);
2665 errdefer gpa.destroy(new_file);
2666
2667 gop.entry.value = new_file;
2668 new_file.* = .{
2669 .sub_file_path = sub_file_path,
2670 .source = undefined,
2671 .source_loaded = false,
2672 .tree_loaded = false,
2673 .zir_loaded = false,
2674 .stat_size = undefined,
2675 .stat_inode = undefined,
2676 .stat_mtime = undefined,
2677 .tree = undefined,
2678 .zir = undefined,
2679 .status = .never_loaded,
2680 .pkg = pkg,
2681 .namespace = undefined,
2682 };
2683 return ImportFileResult{
2684 .file = new_file,
2685 .is_new = true,
2686 };
2687}
2688
26362689pub fn importFile(
26372690 mod: *Module,
2638 cur_pkg: *Package,
2691 cur_file: *Scope.File,
26392692 import_string: []const u8,
26402693) !ImportFileResult {
2694 if (cur_file.pkg.table.get(import_string)) |pkg| {
2695 return mod.importPkg(cur_file.pkg, pkg);
2696 }
26412697 const gpa = mod.gpa;
26422698
2643 const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
2644 const found_pkg = cur_pkg.table.get(import_string);
2645
2646 const resolved_path = if (found_pkg) |pkg|
2647 try std.fs.path.resolve(gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path })
2648 else
2649 try std.fs.path.resolve(gpa, &[_][]const u8{ cur_pkg_dir_path, import_string });
2699 // The resolved path is used as the key in the import table, to detect if
2700 // an import refers to the same as another, despite different relative paths
2701 // or differently mapped package names.
2702 const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
2703 const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
2704 cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string,
2705 });
26502706 var keep_resolved_path = false;
26512707 defer if (!keep_resolved_path) gpa.free(resolved_path);
26522708
......@@ -2655,20 +2711,28 @@ pub fn importFile(
26552711 .file = gop.entry.value,
26562712 .is_new = false,
26572713 };
2714 keep_resolved_path = true; // It's now owned by import_table.
26582715
2659 if (found_pkg == null) {
2660 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
2661 defer gpa.free(resolved_root_path);
2716 const new_file = try gpa.create(Scope.File);
2717 errdefer gpa.destroy(new_file);
26622718
2663 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
2664 return error.ImportOutsidePkgPath;
2665 }
2719 const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
2720 defer gpa.free(resolved_root_path);
2721
2722 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
2723 return error.ImportOutsidePkgPath;
26662724 }
2725 // +1 for the directory separator here.
2726 const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]);
2727 errdefer gpa.free(sub_file_path);
2728
2729 log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{
2730 resolved_root_path, resolved_path, sub_file_path, import_string,
2731 });
26672732
2668 const new_file = try gpa.create(Scope.File);
26692733 gop.entry.value = new_file;
26702734 new_file.* = .{
2671 .sub_file_path = resolved_path,
2735 .sub_file_path = sub_file_path,
26722736 .source = undefined,
26732737 .source_loaded = false,
26742738 .tree_loaded = false,
......@@ -2679,10 +2743,9 @@ pub fn importFile(
26792743 .tree = undefined,
26802744 .zir = undefined,
26812745 .status = .never_loaded,
2682 .pkg = found_pkg orelse cur_pkg,
2746 .pkg = cur_file.pkg,
26832747 .namespace = undefined,
26842748 };
2685 keep_resolved_path = true;
26862749 return ImportFileResult{
26872750 .file = new_file,
26882751 .is_new = true,
src/Sema.zig+1-1
......@@ -3904,7 +3904,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
39043904 const src = inst_data.src();
39053905 const operand = inst_data.get(sema.code);
39063906
3907 const result = mod.importFile(block.getFileScope().pkg, operand) catch |err| switch (err) {
3907 const result = mod.importFile(block.getFileScope(), operand) catch |err| switch (err) {
39083908 error.ImportOutsidePkgPath => {
39093909 return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
39103910 },