aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2023-01-23 14:25:42 +0200
committerGitHub <noreply@github.com>2023-01-23 14:25:42 +0200
commit220020599cc11764eb9ed32025dd506f2affedda (patch)
tree4467fe3ff1f919eec89bafac7435fe58cf9a876a /src/Module.zig
parentd395127552ab6f04b7b044b2a309e0d1e8977775 (diff)
parent5f9186d0ce78ce1eb7db9634849b38d2e90d071e (diff)
downloadzig-220020599cc11764eb9ed32025dd506f2affedda.tar.gz
zig-220020599cc11764eb9ed32025dd506f2affedda.zip
Merge pull request #13670 from mlugg/fix/astgen-ambiguous-package
AstGen: detect and error on files included in multiple packages
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig62
1 files changed, 57 insertions, 5 deletions
diff --git a/src/Module.zig b/src/Module.zig
index f2f51907cb..b17c140231 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -1943,6 +1943,10 @@ pub const File = struct {
zir: Zir,
/// Package that this file is a part of, managed externally.
pkg: *Package,
+ /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
+ multi_pkg: bool = false,
+ /// List of references to this file, used for multi-package errors.
+ references: std.ArrayListUnmanaged(Reference) = .{},
/// Used by change detection algorithm, after astgen, contains the
/// set of decls that existed in the previous ZIR but not in the new one.
@@ -1958,6 +1962,14 @@ pub const File = struct {
/// successful, this field is unloaded.
prev_zir: ?*Zir = null,
+ /// A single reference to a file.
+ const Reference = union(enum) {
+ /// The file is imported directly (i.e. not as a package) with @import.
+ import: SrcLoc,
+ /// The file is the root of a package.
+ root: *Package,
+ };
+
pub fn unload(file: *File, gpa: Allocator) void {
file.unloadTree(gpa);
file.unloadSource(gpa);
@@ -1990,6 +2002,7 @@ pub const File = struct {
log.debug("deinit File {s}", .{file.sub_file_path});
file.deleted_decls.deinit(gpa);
file.outdated_decls.deinit(gpa);
+ file.references.deinit(gpa);
if (file.root_decl.unwrap()) |root_decl| {
mod.destroyDecl(root_decl);
}
@@ -2110,6 +2123,44 @@ pub const File = struct {
else => true,
};
}
+
+ /// Add a reference to this file during AstGen.
+ pub fn addReference(file: *File, mod: Module, ref: Reference) !void {
+ try file.references.append(mod.gpa, ref);
+
+ const pkg = switch (ref) {
+ .import => |loc| loc.file_scope.pkg,
+ .root => |pkg| pkg,
+ };
+ if (pkg != file.pkg) file.multi_pkg = true;
+ }
+
+ /// Mark this file and every file referenced by it as multi_pkg and report an
+ /// astgen_failure error for them. AstGen must have completed in its entirety.
+ pub fn recursiveMarkMultiPkg(file: *File, mod: *Module) void {
+ file.multi_pkg = true;
+ file.status = .astgen_failure;
+
+ std.debug.assert(file.zir_loaded);
+ const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)];
+ if (imports_index == 0) return;
+ const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);
+
+ var import_i: u32 = 0;
+ var extra_index = extra.end;
+ while (import_i < extra.data.imports_len) : (import_i += 1) {
+ const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index);
+ extra_index = item.end;
+
+ const import_path = file.zir.nullTerminatedString(item.data.name);
+ if (mem.eql(u8, import_path, "builtin")) continue;
+
+ const res = mod.importFile(file, import_path) catch continue;
+ if (!res.is_pkg and !res.file.multi_pkg) {
+ res.file.recursiveMarkMultiPkg(mod);
+ }
+ }
+ }
};
/// Represents the contents of a file loaded with `@embedFile`.
@@ -3220,16 +3271,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);
}
@@ -4695,6 +4741,7 @@ pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_
pub const ImportFileResult = struct {
file: *File,
is_new: bool,
+ is_pkg: bool,
};
pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
@@ -4714,6 +4761,7 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
if (gop.found_existing) return ImportFileResult{
.file = gop.value_ptr.*,
.is_new = false,
+ .is_pkg = true,
};
const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
@@ -4737,9 +4785,11 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
.pkg = pkg,
.root_decl = .none,
};
+ try new_file.addReference(mod.*, .{ .root = pkg });
return ImportFileResult{
.file = new_file,
.is_new = true,
+ .is_pkg = true,
};
}
@@ -4780,6 +4830,7 @@ pub fn importFile(
if (gop.found_existing) return ImportFileResult{
.file = gop.value_ptr.*,
.is_new = false,
+ .is_pkg = false,
};
const new_file = try gpa.create(File);
@@ -4825,6 +4876,7 @@ pub fn importFile(
return ImportFileResult{
.file = new_file,
.is_new = true,
+ .is_pkg = false,
};
}