authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-08 10:38:54+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-14 07:40:05+00:00
log48af67c15230f81ff70d6f27364452116b5bdf30
tree5f223d17e383078fb217afb99765e7be7527c6b4
parent00969062a9d5e8229737f0ec38a8af91822caf31
signaturelock-open Commit is signed but in an unrecognized format.

Zcu: rename implicitly-named decls to avoid overriding by explicit decls


2 files changed, 62 insertions(+), 17 deletions(-)

src/Module.zig+54-17
......@@ -4083,6 +4083,9 @@ pub fn scanNamespace(
40834083 const gpa = zcu.gpa;
40844084 const namespace = zcu.namespacePtr(namespace_index);
40854085
4086 var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
4087 defer seen_decls.deinit(gpa);
4088
40864089 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
40874090 try namespace.decls.ensureTotalCapacity(gpa, decls.len);
40884091
......@@ -4090,19 +4093,44 @@ pub fn scanNamespace(
40904093 .zcu = zcu,
40914094 .namespace_index = namespace_index,
40924095 .parent_decl = parent_decl,
4096 .seen_decls = &seen_decls,
4097 .pass = .named,
40934098 };
40944099 for (decls) |decl_inst| {
40954100 try scanDecl(&scan_decl_iter, decl_inst);
40964101 }
4102 scan_decl_iter.pass = .unnamed;
4103 for (decls) |decl_inst| {
4104 try scanDecl(&scan_decl_iter, decl_inst);
4105 }
40974106}
40984107
40994108const ScanDeclIter = struct {
41004109 zcu: *Zcu,
41014110 namespace_index: Namespace.Index,
41024111 parent_decl: *Decl,
4112 seen_decls: *std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
4113 /// Decl scanning is run in two passes, so that we can detect when a generated
4114 /// name would clash with an explicit name and use a different one.
4115 pass: enum { named, unnamed },
41034116 usingnamespace_index: usize = 0,
41044117 comptime_index: usize = 0,
41054118 unnamed_test_index: usize = 0,
4119
4120 fn avoidNameConflict(iter: *ScanDeclIter, comptime fmt: []const u8, args: anytype) !InternPool.NullTerminatedString {
4121 const zcu = iter.zcu;
4122 const gpa = zcu.gpa;
4123 const ip = &zcu.intern_pool;
4124 var name = try ip.getOrPutStringFmt(gpa, fmt, args);
4125 var gop = try iter.seen_decls.getOrPut(gpa, name);
4126 var next_suffix: u32 = 0;
4127 while (gop.found_existing) {
4128 name = try ip.getOrPutStringFmt(gpa, fmt ++ "_{d}", args ++ .{next_suffix});
4129 gop = try iter.seen_decls.getOrPut(gpa, name);
4130 next_suffix += 1;
4131 }
4132 return name;
4133 }
41064134};
41074135
41084136fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
......@@ -4126,54 +4154,63 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
41264154 // Every Decl needs a name.
41274155 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
41284156 .@"comptime" => info: {
4157 if (iter.pass != .unnamed) return;
41294158 const i = iter.comptime_index;
41304159 iter.comptime_index += 1;
4131 // TODO: avoid collisions with named decls with this name
41324160 break :info .{
4133 try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),
4161 try iter.avoidNameConflict("comptime_{d}", .{i}),
41344162 .@"comptime",
41354163 false,
41364164 };
41374165 },
41384166 .@"usingnamespace" => info: {
4167 if (iter.pass != .unnamed) return;
41394168 const i = iter.usingnamespace_index;
41404169 iter.usingnamespace_index += 1;
4141 // TODO: avoid collisions with named decls with this name
41424170 break :info .{
4143 try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),
4171 try iter.avoidNameConflict("usingnamespace_{d}", .{i}),
41444172 .@"usingnamespace",
41454173 false,
41464174 };
41474175 },
41484176 .unnamed_test => info: {
4177 if (iter.pass != .unnamed) return;
41494178 const i = iter.unnamed_test_index;
41504179 iter.unnamed_test_index += 1;
4151 // TODO: avoid collisions with named decls with this name
41524180 break :info .{
4153 try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),
4181 try iter.avoidNameConflict("test_{d}", .{i}),
41544182 .@"test",
41554183 false,
41564184 };
41574185 },
41584186 .decltest => info: {
4187 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
4188 if (iter.pass != .unnamed) return;
41594189 assert(declaration.flags.has_doc_comment);
41604190 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
4161 // TODO: avoid collisions with named decls with this name
41624191 break :info .{
4163 try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),
4192 try iter.avoidNameConflict("decltest.{s}", .{name}),
41644193 .@"test",
41654194 true,
41664195 };
41674196 },
4168 _ => if (declaration.name.isNamedTest(zir)) .{
4169 // TODO: avoid collisions with named decls with this name
4170 try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4171 .@"test",
4172 true,
4173 } else .{
4174 try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),
4175 .named,
4176 false,
4197 _ => if (declaration.name.isNamedTest(zir)) info: {
4198 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
4199 if (iter.pass != .unnamed) return;
4200 break :info .{
4201 try iter.avoidNameConflict("test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4202 .@"test",
4203 true,
4204 };
4205 } else info: {
4206 if (iter.pass != .named) return;
4207 const name = try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?));
4208 try iter.seen_decls.putNoClobber(gpa, name, {});
4209 break :info .{
4210 name,
4211 .named,
4212 false,
4213 };
41774214 },
41784215 };
41794216
test/cases/compile_errors/comptime_decl_name_conflict_resolved.zig created+8
......@@ -0,0 +1,8 @@
1comptime {
2 @compileError("should be reached");
3}
4const comptime_0 = {};
5
6// error
7//
8// :2:5: error: should be reached