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(...@@ -4083,6 +4083,9 @@ pub fn scanNamespace(
4083 const gpa = zcu.gpa;4083 const gpa = zcu.gpa;
4084 const namespace = zcu.namespacePtr(namespace_index);4084 const namespace = zcu.namespacePtr(namespace_index);
40854085
4086 var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
4087 defer seen_decls.deinit(gpa);
4088
4086 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);4089 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
4087 try namespace.decls.ensureTotalCapacity(gpa, decls.len);4090 try namespace.decls.ensureTotalCapacity(gpa, decls.len);
40884091
...@@ -4090,19 +4093,44 @@ pub fn scanNamespace(...@@ -4090,19 +4093,44 @@ pub fn scanNamespace(
4090 .zcu = zcu,4093 .zcu = zcu,
4091 .namespace_index = namespace_index,4094 .namespace_index = namespace_index,
4092 .parent_decl = parent_decl,4095 .parent_decl = parent_decl,
4096 .seen_decls = &seen_decls,
4097 .pass = .named,
4093 };4098 };
4094 for (decls) |decl_inst| {4099 for (decls) |decl_inst| {
4095 try scanDecl(&scan_decl_iter, decl_inst);4100 try scanDecl(&scan_decl_iter, decl_inst);
4096 }4101 }
4102 scan_decl_iter.pass = .unnamed;
4103 for (decls) |decl_inst| {
4104 try scanDecl(&scan_decl_iter, decl_inst);
4105 }
4097}4106}
40984107
4099const ScanDeclIter = struct {4108const ScanDeclIter = struct {
4100 zcu: *Zcu,4109 zcu: *Zcu,
4101 namespace_index: Namespace.Index,4110 namespace_index: Namespace.Index,
4102 parent_decl: *Decl,4111 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 },
4103 usingnamespace_index: usize = 0,4116 usingnamespace_index: usize = 0,
4104 comptime_index: usize = 0,4117 comptime_index: usize = 0,
4105 unnamed_test_index: usize = 0,4118 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 }
4106};4134};
41074135
4108fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {4136fn 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...@@ -4126,54 +4154,63 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
4126 // Every Decl needs a name.4154 // Every Decl needs a name.
4127 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {4155 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
4128 .@"comptime" => info: {4156 .@"comptime" => info: {
4157 if (iter.pass != .unnamed) return;
4129 const i = iter.comptime_index;4158 const i = iter.comptime_index;
4130 iter.comptime_index += 1;4159 iter.comptime_index += 1;
4131 // TODO: avoid collisions with named decls with this name
4132 break :info .{4160 break :info .{
4133 try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),4161 try iter.avoidNameConflict("comptime_{d}", .{i}),
4134 .@"comptime",4162 .@"comptime",
4135 false,4163 false,
4136 };4164 };
4137 },4165 },
4138 .@"usingnamespace" => info: {4166 .@"usingnamespace" => info: {
4167 if (iter.pass != .unnamed) return;
4139 const i = iter.usingnamespace_index;4168 const i = iter.usingnamespace_index;
4140 iter.usingnamespace_index += 1;4169 iter.usingnamespace_index += 1;
4141 // TODO: avoid collisions with named decls with this name
4142 break :info .{4170 break :info .{
4143 try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),4171 try iter.avoidNameConflict("usingnamespace_{d}", .{i}),
4144 .@"usingnamespace",4172 .@"usingnamespace",
4145 false,4173 false,
4146 };4174 };
4147 },4175 },
4148 .unnamed_test => info: {4176 .unnamed_test => info: {
4177 if (iter.pass != .unnamed) return;
4149 const i = iter.unnamed_test_index;4178 const i = iter.unnamed_test_index;
4150 iter.unnamed_test_index += 1;4179 iter.unnamed_test_index += 1;
4151 // TODO: avoid collisions with named decls with this name
4152 break :info .{4180 break :info .{
4153 try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),4181 try iter.avoidNameConflict("test_{d}", .{i}),
4154 .@"test",4182 .@"test",
4155 false,4183 false,
4156 };4184 };
4157 },4185 },
4158 .decltest => info: {4186 .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;
4159 assert(declaration.flags.has_doc_comment);4189 assert(declaration.flags.has_doc_comment);
4160 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));4190 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
4161 // TODO: avoid collisions with named decls with this name
4162 break :info .{4191 break :info .{
4163 try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),4192 try iter.avoidNameConflict("decltest.{s}", .{name}),
4164 .@"test",4193 .@"test",
4165 true,4194 true,
4166 };4195 };
4167 },4196 },
4168 _ => if (declaration.name.isNamedTest(zir)) .{4197 _ => if (declaration.name.isNamedTest(zir)) info: {
4169 // TODO: avoid collisions with named decls with this name4198 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
4170 try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),4199 if (iter.pass != .unnamed) return;
4171 .@"test",4200 break :info .{
4172 true,4201 try iter.avoidNameConflict("test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4173 } else .{4202 .@"test",
4174 try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),4203 true,
4175 .named,4204 };
4176 false,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 };
4177 },4214 },
4178 };4215 };
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