diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-04-16 19:45:58 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-16 19:45:58 -0700 |
| commit | e13fc6b119c5593b4fccd5ae064c6b251bbe50e7 (patch) | |
| tree | f54c3357f9c9b3ca0e34635dab09f4000bbf2c5b /src | |
| parent | 415ef1be510e912ddbd3b73a4d20aac3fda27a0e (diff) | |
| download | zig-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.zig | 6 | ||||
| -rw-r--r-- | src/Module.zig | 99 | ||||
| -rw-r--r-- | src/Sema.zig | 2 |
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}); }, |
