| ... | @@ -272,7 +272,7 @@ analysis_roots_len: usize = 0, | ... | @@ -272,7 +272,7 @@ analysis_roots_len: usize = 0, |
| 272 | /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and | 272 | /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and |
| 273 | /// reset to `null` when any semantic analysis occurs (since this invalidates the data). | 273 | /// reset to `null` when any semantic analysis occurs (since this invalidates the data). |
| 274 | /// Allocated into `gpa`. | 274 | /// Allocated into `gpa`. |
| 275 | resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null, | 275 | resolved_references: ?std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null, |
| 276 | | 276 | |
| 277 | /// If `true`, then semantic analysis must not occur on this update due to AstGen errors. | 277 | /// If `true`, then semantic analysis must not occur on this update due to AstGen errors. |
| 278 | /// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped. | 278 | /// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped. |
| ... | @@ -3985,45 +3985,42 @@ pub const ResolvedReference = struct { | ... | @@ -3985,45 +3985,42 @@ pub const ResolvedReference = struct { |
| 3985 | /// If an `AnalUnit` is not in the returned map, it is unreferenced. | 3985 | /// If an `AnalUnit` is not in the returned map, it is unreferenced. |
| 3986 | /// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller. | 3986 | /// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller. |
| 3987 | /// This hashmap is cached, so repeated calls to this function are cheap. | 3987 | /// This hashmap is cached, so repeated calls to this function are cheap. |
| 3988 | pub fn resolveReferences(zcu: *Zcu) !*const std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) { | 3988 | pub fn resolveReferences(zcu: *Zcu) !*const std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) { |
| 3989 | if (zcu.resolved_references == null) { | 3989 | if (zcu.resolved_references == null) { |
| 3990 | zcu.resolved_references = try zcu.resolveReferencesInner(); | 3990 | zcu.resolved_references = try zcu.resolveReferencesInner(); |
| 3991 | } | 3991 | } |
| 3992 | return &zcu.resolved_references.?; | 3992 | return &zcu.resolved_references.?; |
| 3993 | } | 3993 | } |
| 3994 | fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) { | 3994 | fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) { |
| 3995 | const gpa = zcu.gpa; | 3995 | const gpa = zcu.gpa; |
| 3996 | const comp = zcu.comp; | 3996 | const comp = zcu.comp; |
| 3997 | const ip = &zcu.intern_pool; | 3997 | const ip = &zcu.intern_pool; |
| 3998 | | 3998 | |
| 3999 | var result: std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = .empty; | 3999 | var units: std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) = .empty; |
| 4000 | errdefer result.deinit(gpa); | 4000 | var types: std.AutoArrayHashMapUnmanaged(InternPool.Index, ?ResolvedReference) = .empty; |
| 4001 | | | |
| 4002 | var checked_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty; | | |
| 4003 | var type_queue: std.AutoArrayHashMapUnmanaged(InternPool.Index, ?ResolvedReference) = .empty; | | |
| 4004 | var unit_queue: std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) = .empty; | | |
| 4005 | defer { | 4001 | defer { |
| 4006 | checked_types.deinit(gpa); | 4002 | units.deinit(gpa); |
| 4007 | type_queue.deinit(gpa); | 4003 | types.deinit(gpa); |
| 4008 | unit_queue.deinit(gpa); | | |
| 4009 | } | 4004 | } |
| 4010 | | 4005 | |
| 4011 | // This is not a sufficient size, but a lower bound. | 4006 | // This is not a sufficient size, but an approximate lower bound. |
| 4012 | try result.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); | 4007 | try units.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); |
| 4013 | | 4008 | |
| 4014 | try type_queue.ensureTotalCapacity(gpa, zcu.analysis_roots_len); | 4009 | try types.ensureTotalCapacity(gpa, zcu.analysis_roots_len); |
| 4015 | for (zcu.analysisRoots()) |mod| { | 4010 | for (zcu.analysisRoots()) |mod| { |
| 4016 | const file = zcu.module_roots.get(mod).?.unwrap() orelse continue; | 4011 | const file = zcu.module_roots.get(mod).?.unwrap() orelse continue; |
| 4017 | const root_ty = zcu.fileRootType(file); | 4012 | const root_ty = zcu.fileRootType(file); |
| 4018 | if (root_ty == .none) continue; | 4013 | if (root_ty == .none) continue; |
| 4019 | type_queue.putAssumeCapacityNoClobber(root_ty, null); | 4014 | types.putAssumeCapacityNoClobber(root_ty, null); |
| 4020 | } | 4015 | } |
| 4021 | | 4016 | |
| | 4017 | var unit_idx: usize = 0; |
| | 4018 | var type_idx: usize = 0; |
| 4022 | while (true) { | 4019 | while (true) { |
| 4023 | if (type_queue.pop()) |kv| { | 4020 | if (type_idx < types.count()) { |
| 4024 | const ty = kv.key; | 4021 | const ty = types.keys()[type_idx]; |
| 4025 | const referencer = kv.value; | 4022 | const referencer = types.values()[type_idx]; |
| 4026 | try checked_types.putNoClobber(gpa, ty, {}); | 4023 | type_idx += 1; |
| 4027 | | 4024 | |
| 4028 | log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); | 4025 | log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); |
| 4029 | | 4026 | |
| ... | @@ -4037,8 +4034,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4037,8 +4034,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4037 | if (has_resolution) { | 4034 | if (has_resolution) { |
| 4038 | // this should only be referenced by the type | 4035 | // this should only be referenced by the type |
| 4039 | const unit: AnalUnit = .wrap(.{ .type = ty }); | 4036 | const unit: AnalUnit = .wrap(.{ .type = ty }); |
| 4040 | assert(!result.contains(unit)); | 4037 | try units.putNoClobber(gpa, unit, referencer); |
| 4041 | try unit_queue.putNoClobber(gpa, unit, referencer); | | |
| 4042 | } | 4038 | } |
| 4043 | | 4039 | |
| 4044 | // If this is a union with a generated tag, its tag type is automatically referenced. | 4040 | // If this is a union with a generated tag, its tag type is automatically referenced. |
| ... | @@ -4047,9 +4043,8 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4047,9 +4043,8 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4047 | const tag_ty = union_obj.enum_tag_ty; | 4043 | const tag_ty = union_obj.enum_tag_ty; |
| 4048 | if (tag_ty != .none) { | 4044 | if (tag_ty != .none) { |
| 4049 | if (ip.indexToKey(tag_ty).enum_type == .generated_tag) { | 4045 | if (ip.indexToKey(tag_ty).enum_type == .generated_tag) { |
| 4050 | if (!checked_types.contains(tag_ty)) { | 4046 | const gop = try types.getOrPut(gpa, tag_ty); |
| 4051 | try type_queue.put(gpa, tag_ty, referencer); | 4047 | if (!gop.found_existing) gop.value_ptr.* = referencer; |
| 4052 | } | | |
| 4053 | } | 4048 | } |
| 4054 | } | 4049 | } |
| 4055 | } | 4050 | } |
| ... | @@ -4060,12 +4055,13 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4060,12 +4055,13 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4060 | for (zcu.namespacePtr(ns).comptime_decls.items) |cu| { | 4055 | for (zcu.namespacePtr(ns).comptime_decls.items) |cu| { |
| 4061 | // `comptime` decls are always analyzed. | 4056 | // `comptime` decls are always analyzed. |
| 4062 | const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); | 4057 | const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); |
| 4063 | if (!result.contains(unit)) { | 4058 | const gop = try units.getOrPut(gpa, unit); |
| | 4059 | if (!gop.found_existing) { |
| 4064 | log.debug("type '{f}': ref comptime %{}", .{ | 4060 | log.debug("type '{f}': ref comptime %{}", .{ |
| 4065 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), | 4061 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 4066 | @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue), | 4062 | @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue), |
| 4067 | }); | 4063 | }); |
| 4068 | try unit_queue.put(gpa, unit, referencer); | 4064 | gop.value_ptr.* = referencer; |
| 4069 | } | 4065 | } |
| 4070 | } | 4066 | } |
| 4071 | for (zcu.namespacePtr(ns).test_decls.items) |nav_id| { | 4067 | for (zcu.namespacePtr(ns).test_decls.items) |nav_id| { |
| ... | @@ -4092,14 +4088,20 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4092,14 +4088,20 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4092 | }, | 4088 | }, |
| 4093 | }; | 4089 | }; |
| 4094 | if (want_analysis) { | 4090 | if (want_analysis) { |
| 4095 | log.debug("type '{f}': ref test %{}", .{ | 4091 | { |
| 4096 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), | 4092 | const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id })); |
| 4097 | @intFromEnum(inst_info.inst), | 4093 | if (!gop.found_existing) { |
| 4098 | }); | 4094 | log.debug("type '{f}': ref test %{}", .{ |
| 4099 | try unit_queue.put(gpa, .wrap(.{ .nav_val = nav_id }), referencer); | 4095 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| | 4096 | @intFromEnum(inst_info.inst), |
| | 4097 | }); |
| | 4098 | gop.value_ptr.* = referencer; |
| | 4099 | } |
| | 4100 | } |
| 4100 | // Non-fatal AstGen errors could mean this test decl failed | 4101 | // Non-fatal AstGen errors could mean this test decl failed |
| 4101 | if (nav.status == .fully_resolved) { | 4102 | if (nav.status == .fully_resolved) { |
| 4102 | try unit_queue.put(gpa, .wrap(.{ .func = nav.status.fully_resolved.val }), referencer); | 4103 | const gop = try units.getOrPut(gpa, .wrap(.{ .func = nav.status.fully_resolved.val })); |
| | 4104 | if (!gop.found_existing) gop.value_ptr.* = referencer; |
| 4103 | } | 4105 | } |
| 4104 | } | 4106 | } |
| 4105 | } | 4107 | } |
| ... | @@ -4110,12 +4112,13 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4110,12 +4112,13 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4110 | const decl = file.zir.?.getDeclaration(inst_info.inst); | 4112 | const decl = file.zir.?.getDeclaration(inst_info.inst); |
| 4111 | if (decl.linkage == .@"export") { | 4113 | if (decl.linkage == .@"export") { |
| 4112 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); | 4114 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); |
| 4113 | if (!result.contains(unit)) { | 4115 | const gop = try units.getOrPut(gpa, unit); |
| | 4116 | if (!gop.found_existing) { |
| 4114 | log.debug("type '{f}': ref named %{}", .{ | 4117 | log.debug("type '{f}': ref named %{}", .{ |
| 4115 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), | 4118 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 4116 | @intFromEnum(inst_info.inst), | 4119 | @intFromEnum(inst_info.inst), |
| 4117 | }); | 4120 | }); |
| 4118 | try unit_queue.put(gpa, unit, referencer); | 4121 | gop.value_ptr.* = referencer; |
| 4119 | } | 4122 | } |
| 4120 | } | 4123 | } |
| 4121 | } | 4124 | } |
| ... | @@ -4126,20 +4129,21 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4126,20 +4129,21 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4126 | const decl = file.zir.?.getDeclaration(inst_info.inst); | 4129 | const decl = file.zir.?.getDeclaration(inst_info.inst); |
| 4127 | if (decl.linkage == .@"export") { | 4130 | if (decl.linkage == .@"export") { |
| 4128 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); | 4131 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); |
| 4129 | if (!result.contains(unit)) { | 4132 | const gop = try units.getOrPut(gpa, unit); |
| | 4133 | if (!gop.found_existing) { |
| 4130 | log.debug("type '{f}': ref named %{}", .{ | 4134 | log.debug("type '{f}': ref named %{}", .{ |
| 4131 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), | 4135 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 4132 | @intFromEnum(inst_info.inst), | 4136 | @intFromEnum(inst_info.inst), |
| 4133 | }); | 4137 | }); |
| 4134 | try unit_queue.put(gpa, unit, referencer); | 4138 | gop.value_ptr.* = referencer; |
| 4135 | } | 4139 | } |
| 4136 | } | 4140 | } |
| 4137 | } | 4141 | } |
| 4138 | continue; | 4142 | continue; |
| 4139 | } | 4143 | } |
| 4140 | if (unit_queue.pop()) |kv| { | 4144 | if (unit_idx < units.count()) { |
| 4141 | const unit = kv.key; | 4145 | const unit = units.keys()[unit_idx]; |
| 4142 | try result.putNoClobber(gpa, unit, kv.value); | 4146 | unit_idx += 1; |
| 4143 | | 4147 | |
| 4144 | // `nav_val` and `nav_ty` reference each other *implicitly* to save memory. | 4148 | // `nav_val` and `nav_ty` reference each other *implicitly* to save memory. |
| 4145 | queue_paired: { | 4149 | queue_paired: { |
| ... | @@ -4148,8 +4152,9 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4148,8 +4152,9 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4148 | .nav_ty => |n| .{ .nav_val = n }, | 4152 | .nav_ty => |n| .{ .nav_val = n }, |
| 4149 | .@"comptime", .type, .func, .memoized_state => break :queue_paired, | 4153 | .@"comptime", .type, .func, .memoized_state => break :queue_paired, |
| 4150 | }); | 4154 | }); |
| 4151 | if (result.contains(other)) break :queue_paired; | 4155 | const gop = try units.getOrPut(gpa, other); |
| 4152 | try unit_queue.put(gpa, other, kv.value); // same reference location | 4156 | if (gop.found_existing) break :queue_paired; |
| | 4157 | gop.value_ptr.* = units.values()[unit_idx]; // same reference location |
| 4153 | } | 4158 | } |
| 4154 | | 4159 | |
| 4155 | log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)}); | 4160 | log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)}); |
| ... | @@ -4159,16 +4164,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4159,16 +4164,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4159 | var ref_idx = first_ref_idx; | 4164 | var ref_idx = first_ref_idx; |
| 4160 | while (ref_idx != std.math.maxInt(u32)) { | 4165 | while (ref_idx != std.math.maxInt(u32)) { |
| 4161 | const ref = zcu.all_references.items[ref_idx]; | 4166 | const ref = zcu.all_references.items[ref_idx]; |
| 4162 | if (!result.contains(ref.referenced)) { | 4167 | const gop = try units.getOrPut(gpa, ref.referenced); |
| | 4168 | if (!gop.found_existing) { |
| 4163 | log.debug("unit '{f}': ref unit '{f}'", .{ | 4169 | log.debug("unit '{f}': ref unit '{f}'", .{ |
| 4164 | zcu.fmtAnalUnit(unit), | 4170 | zcu.fmtAnalUnit(unit), |
| 4165 | zcu.fmtAnalUnit(ref.referenced), | 4171 | zcu.fmtAnalUnit(ref.referenced), |
| 4166 | }); | 4172 | }); |
| 4167 | try unit_queue.put(gpa, ref.referenced, .{ | 4173 | gop.value_ptr.* = .{ |
| 4168 | .referencer = unit, | 4174 | .referencer = unit, |
| 4169 | .src = ref.src, | 4175 | .src = ref.src, |
| 4170 | .inline_frame = ref.inline_frame, | 4176 | .inline_frame = ref.inline_frame, |
| 4171 | }); | 4177 | }; |
| 4172 | } | 4178 | } |
| 4173 | ref_idx = ref.next; | 4179 | ref_idx = ref.next; |
| 4174 | } | 4180 | } |
| ... | @@ -4178,16 +4184,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4178,16 +4184,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4178 | var ref_idx = first_ref_idx; | 4184 | var ref_idx = first_ref_idx; |
| 4179 | while (ref_idx != std.math.maxInt(u32)) { | 4185 | while (ref_idx != std.math.maxInt(u32)) { |
| 4180 | const ref = zcu.all_type_references.items[ref_idx]; | 4186 | const ref = zcu.all_type_references.items[ref_idx]; |
| 4181 | if (!checked_types.contains(ref.referenced)) { | 4187 | const gop = try types.getOrPut(gpa, ref.referenced); |
| | 4188 | if (!gop.found_existing) { |
| 4182 | log.debug("unit '{f}': ref type '{f}'", .{ | 4189 | log.debug("unit '{f}': ref type '{f}'", .{ |
| 4183 | zcu.fmtAnalUnit(unit), | 4190 | zcu.fmtAnalUnit(unit), |
| 4184 | Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip), | 4191 | Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip), |
| 4185 | }); | 4192 | }); |
| 4186 | try type_queue.put(gpa, ref.referenced, .{ | 4193 | gop.value_ptr.* = .{ |
| 4187 | .referencer = unit, | 4194 | .referencer = unit, |
| 4188 | .src = ref.src, | 4195 | .src = ref.src, |
| 4189 | .inline_frame = .none, | 4196 | .inline_frame = .none, |
| 4190 | }); | 4197 | }; |
| 4191 | } | 4198 | } |
| 4192 | ref_idx = ref.next; | 4199 | ref_idx = ref.next; |
| 4193 | } | 4200 | } |
| ... | @@ -4197,7 +4204,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv | ... | @@ -4197,7 +4204,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 4197 | break; | 4204 | break; |
| 4198 | } | 4205 | } |
| 4199 | | 4206 | |
| 4200 | return result; | 4207 | return units.move(); |
| 4201 | } | 4208 | } |
| 4202 | | 4209 | |
| 4203 | pub fn analysisRoots(zcu: *Zcu) []*Package.Module { | 4210 | pub fn analysisRoots(zcu: *Zcu) []*Package.Module { |