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