aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-16 19:45:58 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-16 19:45:58 -0700
commite13fc6b119c5593b4fccd5ae064c6b251bbe50e7 (patch)
treef54c3357f9c9b3ca0e34635dab09f4000bbf2c5b /src
parent415ef1be510e912ddbd3b73a4d20aac3fda27a0e (diff)
downloadzig-e13fc6b119c5593b4fccd5ae064c6b251bbe50e7.tar.gz
zig-e13fc6b119c5593b4fccd5ae064c6b251bbe50e7.zip
stage2: make `@import` relative to the current file
previously, it was incorrectly relative to the package directory
Diffstat (limited to 'src')
-rw-r--r--src/Compilation.zig6
-rw-r--r--src/Module.zig99
-rw-r--r--src/Sema.zig2
3 files changed, 86 insertions, 21 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 3f0937c957..7a496ccc45 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -1535,7 +1535,8 @@ pub fn update(self: *Compilation) !void {
// Make sure std.zig is inside the import_table. We unconditionally need
// it for start.zig.
- _ = try module.importFile(module.root_pkg, "std");
+ const std_pkg = module.root_pkg.table.get("std").?;
+ _ = try module.importPkg(module.root_pkg, std_pkg);
// Put a work item in for every known source file to detect if
// it changed, and, if so, re-compute ZIR and then queue the job
@@ -2118,6 +2119,7 @@ fn workerAstGenFile(
// there is a missing `failed_files` error message.
error.OutOfMemory => {},
};
+ return;
},
};
@@ -2136,7 +2138,7 @@ fn workerAstGenFile(
const lock = comp.mutex.acquire();
defer lock.release();
- break :blk mod.importFile(file.pkg, import_path) catch continue;
+ break :blk mod.importFile(file, import_path) catch continue;
};
if (import_result.is_new) {
wg.start();
diff --git a/src/Module.zig b/src/Module.zig
index 9ecd8bab51..7c18f8f65a 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -739,6 +739,7 @@ pub const Scope = struct {
}
pub fn deinit(file: *File, gpa: *Allocator) void {
+ gpa.free(file.sub_file_path);
file.unload(gpa);
file.* = undefined;
}
@@ -746,6 +747,11 @@ pub const Scope = struct {
pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 {
if (file.source_loaded) return file.source;
+ const root_dir_path = file.pkg.root_src_directory.path orelse ".";
+ log.debug("File.getSource, not cached. pkgdir={s} sub_file_path={s}", .{
+ root_dir_path, file.sub_file_path,
+ });
+
// Keep track of inode, file size, mtime, hash so we can detect which files
// have been modified when an incremental update is requested.
var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
@@ -2633,20 +2639,70 @@ pub const ImportFileResult = struct {
is_new: bool,
};
+pub fn importPkg(mod: *Module, cur_pkg: *Package, pkg: *Package) !ImportFileResult {
+ const gpa = mod.gpa;
+
+ // The resolved path is used as the key in the import table, to detect if
+ // an import refers to the same as another, despite different relative paths
+ // or differently mapped package names.
+ const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
+ pkg.root_src_directory.path orelse ".", pkg.root_src_path,
+ });
+ var keep_resolved_path = false;
+ defer if (!keep_resolved_path) gpa.free(resolved_path);
+
+ const gop = try mod.import_table.getOrPut(gpa, resolved_path);
+ if (gop.found_existing) return ImportFileResult{
+ .file = gop.entry.value,
+ .is_new = false,
+ };
+ keep_resolved_path = true; // It's now owned by import_table.
+
+ const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
+ errdefer gpa.free(sub_file_path);
+
+ const new_file = try gpa.create(Scope.File);
+ errdefer gpa.destroy(new_file);
+
+ gop.entry.value = new_file;
+ new_file.* = .{
+ .sub_file_path = sub_file_path,
+ .source = undefined,
+ .source_loaded = false,
+ .tree_loaded = false,
+ .zir_loaded = false,
+ .stat_size = undefined,
+ .stat_inode = undefined,
+ .stat_mtime = undefined,
+ .tree = undefined,
+ .zir = undefined,
+ .status = .never_loaded,
+ .pkg = pkg,
+ .namespace = undefined,
+ };
+ return ImportFileResult{
+ .file = new_file,
+ .is_new = true,
+ };
+}
+
pub fn importFile(
mod: *Module,
- cur_pkg: *Package,
+ cur_file: *Scope.File,
import_string: []const u8,
) !ImportFileResult {
+ if (cur_file.pkg.table.get(import_string)) |pkg| {
+ return mod.importPkg(cur_file.pkg, pkg);
+ }
const gpa = mod.gpa;
- const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
- const found_pkg = cur_pkg.table.get(import_string);
-
- const resolved_path = if (found_pkg) |pkg|
- try std.fs.path.resolve(gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path })
- else
- try std.fs.path.resolve(gpa, &[_][]const u8{ cur_pkg_dir_path, import_string });
+ // The resolved path is used as the key in the import table, to detect if
+ // an import refers to the same as another, despite different relative paths
+ // or differently mapped package names.
+ const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
+ const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
+ cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string,
+ });
var keep_resolved_path = false;
defer if (!keep_resolved_path) gpa.free(resolved_path);
@@ -2655,20 +2711,28 @@ pub fn importFile(
.file = gop.entry.value,
.is_new = false,
};
+ keep_resolved_path = true; // It's now owned by import_table.
- if (found_pkg == null) {
- const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
- defer gpa.free(resolved_root_path);
+ const new_file = try gpa.create(Scope.File);
+ errdefer gpa.destroy(new_file);
- if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
- return error.ImportOutsidePkgPath;
- }
+ const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
+ defer gpa.free(resolved_root_path);
+
+ if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
+ return error.ImportOutsidePkgPath;
}
+ // +1 for the directory separator here.
+ const sub_file_path = try gpa.dupe(u8, resolved_path[resolved_root_path.len + 1 ..]);
+ errdefer gpa.free(sub_file_path);
+
+ log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{
+ resolved_root_path, resolved_path, sub_file_path, import_string,
+ });
- const new_file = try gpa.create(Scope.File);
gop.entry.value = new_file;
new_file.* = .{
- .sub_file_path = resolved_path,
+ .sub_file_path = sub_file_path,
.source = undefined,
.source_loaded = false,
.tree_loaded = false,
@@ -2679,10 +2743,9 @@ pub fn importFile(
.tree = undefined,
.zir = undefined,
.status = .never_loaded,
- .pkg = found_pkg orelse cur_pkg,
+ .pkg = cur_file.pkg,
.namespace = undefined,
};
- keep_resolved_path = true;
return ImportFileResult{
.file = new_file,
.is_new = true,
diff --git a/src/Sema.zig b/src/Sema.zig
index 0d9a3edd55..f98882b0b0 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -3904,7 +3904,7 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
const src = inst_data.src();
const operand = inst_data.get(sema.code);
- const result = mod.importFile(block.getFileScope().pkg, operand) catch |err| switch (err) {
+ const result = mod.importFile(block.getFileScope(), operand) catch |err| switch (err) {
error.ImportOutsidePkgPath => {
return mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
},