authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-08 14:34:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-08 14:34:30-07:00
log5cd9afc6b6cf33f650e5afc6b726b91dfb97e697
treef5942db64513b2cd4715b27c049efb1ae990af43
parentaa0352fad6d8230ab2d8d71c024429faa54144d2

stage2: fully qualified names and better anonymous names

* no more global atomic variable for anonymous decl indexes. Instead the Namespace decl table is used to figure out anonymous decl names. - This prepares for better multi-threaded semantic analysis in the future, with no contention on this global atomic integer. * implement fully qualified names for namespaces.

1 files changed, 51 insertions(+), 22 deletions(-)

src/Module.zig+51-22
......@@ -75,8 +75,6 @@ failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{},
7575/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
7676failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
7777
78next_anon_name_index: usize = 0,
79
8078/// Candidates for deletion. After a semantic analysis update completes, this list
8179/// contains Decls that need to be deleted if they end up having no references to them.
8280deletion_set: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
......@@ -912,9 +910,22 @@ pub const Scope = struct {
912910 _ = ns.decls.orderedRemove(mem.spanZ(child.name));
913911 }
914912
915 pub fn renderFullyQualifiedName(ns: Namespace, name: []const u8, writer: anytype) !void {
916 // TODO this should render e.g. "std.fs.Dir.OpenOptions"
917 return writer.writeAll(name);
913 // This renders e.g. "std.fs.Dir.OpenOptions"
914 pub fn renderFullyQualifiedName(
915 ns: Namespace,
916 name: []const u8,
917 writer: anytype,
918 ) @TypeOf(writer).Error!void {
919 if (ns.parent) |parent| {
920 const decl = ns.getDecl();
921 try parent.renderFullyQualifiedName(mem.spanZ(decl.name), writer);
922 } else {
923 try ns.file_scope.renderFullyQualifiedName(writer);
924 }
925 if (name.len != 0) {
926 try writer.writeAll(".");
927 try writer.writeAll(name);
928 }
918929 }
919930
920931 pub fn getDecl(ns: Namespace) *Decl {
......@@ -1054,16 +1065,21 @@ pub const Scope = struct {
10541065 gpa.destroy(file);
10551066 }
10561067
1057 pub fn fullyQualifiedNameZ(file: File, gpa: *Allocator) ![:0]u8 {
1068 pub fn renderFullyQualifiedName(file: File, writer: anytype) !void {
10581069 // Convert all the slashes into dots and truncate the extension.
10591070 const ext = std.fs.path.extension(file.sub_file_path);
10601071 const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len];
1061 const duped = try gpa.dupeZ(u8, noext);
1062 for (duped) |*byte| switch (byte.*) {
1063 '/', '\\' => byte.* = '.',
1064 else => continue,
1072 for (noext) |byte| switch (byte) {
1073 '/', '\\' => try writer.writeByte('.'),
1074 else => try writer.writeByte(byte),
10651075 };
1066 return duped;
1076 }
1077
1078 pub fn fullyQualifiedNameZ(file: File, gpa: *Allocator) ![:0]u8 {
1079 var buf = std.ArrayList(u8).init(gpa);
1080 defer buf.deinit();
1081 try file.renderFullyQualifiedName(buf.writer());
1082 return buf.toOwnedSliceSentinel(0);
10671083 }
10681084
10691085 pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
......@@ -3723,17 +3739,34 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b
37233739}
37243740
37253741pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl {
3726 const name_index = mod.getNextAnonNameIndex();
37273742 const scope_decl = scope.ownerDecl().?;
37283743 const namespace = scope_decl.namespace;
3729 try namespace.decls.ensureCapacity(mod.gpa, namespace.decls.count() + 1);
3730 const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
3731 errdefer mod.gpa.free(name);
3732 const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node);
3733 namespace.decls.putAssumeCapacityNoClobber(name, new_decl);
3744 try namespace.decls.ensureUnusedCapacity(mod.gpa, 1);
3745
3746 // Find a unique name for the anon decl.
3747 var name_buf = std.ArrayList(u8).init(mod.gpa);
3748 defer name_buf.deinit();
3749
3750 try name_buf.appendSlice(mem.spanZ(scope_decl.name));
3751 var name_index: usize = namespace.decls.count();
3752
3753 const new_decl = while (true) {
3754 const gop = namespace.decls.getOrPutAssumeCapacity(name_buf.items);
3755 if (!gop.found_existing) {
3756 const name = try name_buf.toOwnedSliceSentinel(0);
3757 const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node);
3758 new_decl.name = name;
3759 gop.entry.key = name;
3760 gop.entry.value = new_decl;
3761 break gop.entry.value;
3762 }
3763
3764 name_buf.clearRetainingCapacity();
3765 try name_buf.writer().print("{s}__anon_{d}", .{ scope_decl.name, name_index });
3766 name_index += 1;
3767 } else unreachable; // TODO should not need else unreachable on while(true)
37343768
37353769 new_decl.src_line = scope_decl.src_line;
3736 new_decl.name = name;
37373770 new_decl.ty = typed_value.ty;
37383771 new_decl.val = typed_value.val;
37393772 new_decl.has_tv = true;
......@@ -3751,10 +3784,6 @@ pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue)
37513784 return new_decl;
37523785}
37533786
3754fn getNextAnonNameIndex(mod: *Module) usize {
3755 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);
3756}
3757
37583787/// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces
37593788/// in scope and check each one for the identifier.
37603789/// TODO emit a compile error if more than one decl would be matched.