| ... | @@ -75,8 +75,6 @@ failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{}, | ... | @@ -75,8 +75,6 @@ failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{}, |
| 75 | /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. | 75 | /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. |
| 76 | failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, | 76 | failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, |
| 77 | | 77 | |
| 78 | next_anon_name_index: usize = 0, | | |
| 79 | | | |
| 80 | /// Candidates for deletion. After a semantic analysis update completes, this list | 78 | /// Candidates for deletion. After a semantic analysis update completes, this list |
| 81 | /// contains Decls that need to be deleted if they end up having no references to them. | 79 | /// contains Decls that need to be deleted if they end up having no references to them. |
| 82 | deletion_set: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, | 80 | deletion_set: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, |
| ... | @@ -912,9 +910,22 @@ pub const Scope = struct { | ... | @@ -912,9 +910,22 @@ pub const Scope = struct { |
| 912 | _ = ns.decls.orderedRemove(mem.spanZ(child.name)); | 910 | _ = ns.decls.orderedRemove(mem.spanZ(child.name)); |
| 913 | } | 911 | } |
| 914 | | 912 | |
| 915 | pub fn renderFullyQualifiedName(ns: Namespace, name: []const u8, writer: anytype) !void { | 913 | // This renders e.g. "std.fs.Dir.OpenOptions" |
| 916 | // TODO this should render e.g. "std.fs.Dir.OpenOptions" | 914 | pub fn renderFullyQualifiedName( |
| 917 | return writer.writeAll(name); | 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 | } |
| 918 | } | 929 | } |
| 919 | | 930 | |
| 920 | pub fn getDecl(ns: Namespace) *Decl { | 931 | pub fn getDecl(ns: Namespace) *Decl { |
| ... | @@ -1054,16 +1065,21 @@ pub const Scope = struct { | ... | @@ -1054,16 +1065,21 @@ pub const Scope = struct { |
| 1054 | gpa.destroy(file); | 1065 | gpa.destroy(file); |
| 1055 | } | 1066 | } |
| 1056 | | 1067 | |
| 1057 | pub fn fullyQualifiedNameZ(file: File, gpa: *Allocator) ![:0]u8 { | 1068 | pub fn renderFullyQualifiedName(file: File, writer: anytype) !void { |
| 1058 | // Convert all the slashes into dots and truncate the extension. | 1069 | // Convert all the slashes into dots and truncate the extension. |
| 1059 | const ext = std.fs.path.extension(file.sub_file_path); | 1070 | const ext = std.fs.path.extension(file.sub_file_path); |
| 1060 | const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len]; | 1071 | const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len]; |
| 1061 | const duped = try gpa.dupeZ(u8, noext); | 1072 | for (noext) |byte| switch (byte) { |
| 1062 | for (duped) |*byte| switch (byte.*) { | 1073 | '/', '\\' => try writer.writeByte('.'), |
| 1063 | '/', '\\' => byte.* = '.', | 1074 | else => try writer.writeByte(byte), |
| 1064 | else => continue, | | |
| 1065 | }; | 1075 | }; |
| 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); |
| 1067 | } | 1083 | } |
| 1068 | | 1084 | |
| 1069 | pub fn dumpSrc(file: *File, src: LazySrcLoc) void { | 1085 | pub fn dumpSrc(file: *File, src: LazySrcLoc) void { |
| ... | @@ -3723,17 +3739,34 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b | ... | @@ -3723,17 +3739,34 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b |
| 3723 | } | 3739 | } |
| 3724 | | 3740 | |
| 3725 | pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { | 3741 | pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { |
| 3726 | const name_index = mod.getNextAnonNameIndex(); | | |
| 3727 | const scope_decl = scope.ownerDecl().?; | 3742 | const scope_decl = scope.ownerDecl().?; |
| 3728 | const namespace = scope_decl.namespace; | 3743 | const namespace = scope_decl.namespace; |
| 3729 | try namespace.decls.ensureCapacity(mod.gpa, namespace.decls.count() + 1); | 3744 | try namespace.decls.ensureUnusedCapacity(mod.gpa, 1); |
| 3730 | const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index }); | 3745 | |
| 3731 | errdefer mod.gpa.free(name); | 3746 | // Find a unique name for the anon decl. |
| 3732 | const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node); | 3747 | var name_buf = std.ArrayList(u8).init(mod.gpa); |
| 3733 | namespace.decls.putAssumeCapacityNoClobber(name, new_decl); | 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) |
| 3734 | | 3768 | |
| 3735 | new_decl.src_line = scope_decl.src_line; | 3769 | new_decl.src_line = scope_decl.src_line; |
| 3736 | new_decl.name = name; | | |
| 3737 | new_decl.ty = typed_value.ty; | 3770 | new_decl.ty = typed_value.ty; |
| 3738 | new_decl.val = typed_value.val; | 3771 | new_decl.val = typed_value.val; |
| 3739 | new_decl.has_tv = true; | 3772 | new_decl.has_tv = true; |
| ... | @@ -3751,10 +3784,6 @@ pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) | ... | @@ -3751,10 +3784,6 @@ pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) |
| 3751 | return new_decl; | 3784 | return new_decl; |
| 3752 | } | 3785 | } |
| 3753 | | 3786 | |
| 3754 | fn getNextAnonNameIndex(mod: *Module) usize { | | |
| 3755 | return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic); | | |
| 3756 | } | | |
| 3757 | | | |
| 3758 | /// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces | 3787 | /// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces |
| 3759 | /// in scope and check each one for the identifier. | 3788 | /// in scope and check each one for the identifier. |
| 3760 | /// TODO emit a compile error if more than one decl would be matched. | 3789 | /// TODO emit a compile error if more than one decl would be matched. |