diff --git a/src/InternPool.zig b/src/InternPool.zig index ce9622e54d57bc0703d9151a5bbd35e3ef57298c..230ef78d63dd4190c712a6b955b5ea594d89ddb6 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -546,6 +546,8 @@ pub const Nav = struct { analysis: ?struct { namespace: NamespaceIndex, zir_index: TrackedInst.Index, + /// Initially `false`. Set to `true` by `setWantNavAnalysis`. + wanted: bool, }, status: union(enum) { /// This `Nav` is pending semantic analysis. @@ -743,7 +745,7 @@ pub const Nav = struct { const Repr = struct { name: NullTerminatedString, fqn: NullTerminatedString, - // The following 1 fields are either both populated, or both `.none`. + // The following 2 fields are either both populated, or both `.none`. analysis_namespace: OptionalNamespaceIndex, analysis_zir_index: TrackedInst.Index.Optional, /// Populated only if `bits.status != .unresolved`. @@ -762,7 +764,7 @@ pub const Nav = struct { @"addrspace": std.builtin.AddressSpace, /// Populated only if `bits.status == .type_resolved`. is_threadlocal: bool, - _: u1 = 0, + want_analysis: bool, }; fn unpack(repr: Repr) Nav { @@ -772,6 +774,7 @@ pub const Nav = struct { .analysis = if (repr.analysis_namespace.unwrap()) |namespace| .{ .namespace = namespace, .zir_index = repr.analysis_zir_index.unwrap().?, + .wanted = repr.bits.want_analysis, } else a: { assert(repr.analysis_zir_index == .none); break :a null; @@ -824,6 +827,7 @@ pub const Nav = struct { .alignment = .none, .@"addrspace" = .generic, .is_threadlocal = false, + .want_analysis = if (nav.analysis) |a| a.wanted else false, }, .type_resolved => |r| .{ .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved, @@ -831,6 +835,7 @@ pub const Nav = struct { .alignment = r.alignment, .@"addrspace" = r.@"addrspace", .is_threadlocal = r.is_threadlocal, + .want_analysis = if (nav.analysis) |a| a.wanted else false, }, .fully_resolved => |r| .{ .status = .fully_resolved, @@ -838,6 +843,7 @@ pub const Nav = struct { .alignment = r.alignment, .@"addrspace" = r.@"addrspace", .is_threadlocal = false, + .want_analysis = if (nav.analysis) |a| a.wanted else false, }, }, }; @@ -2412,17 +2418,6 @@ pub const Key = union(enum) { @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); } - pub fn setAnalyzed(func: Func, ip: *InternPool, io: Io) void { - const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; - extra_mutex.lockUncancelable(io); - defer extra_mutex.unlock(io); - - const analysis_ptr = func.analysisPtr(ip); - var analysis = analysis_ptr.*; - analysis.is_analyzed = true; - @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); - } - /// Returns a pointer that becomes invalid after any additions to the `InternPool`. fn zirBodyInstPtr(func: Func, ip: *const InternPool) *TrackedInst.Index { const extra = ip.getLocalShared(func.tid).extra.acquire(); @@ -3314,6 +3309,25 @@ pub const LoadedStructType = struct { /// May be `undefined` if `layout != .@"packed"`. packed_backing_mode: BackingTypeMode, + /// Initially `false`, and set to `true` once any dependency on or reference to the struct's + /// layout is encountered, after which it is never reset to `false`, even across incremental + /// updates. + /// + /// This field is purely an optimization to avoid resolving the layout of types whose layouts + /// are never demanded. If this field is `true` but the layout is not actually needed, the + /// compiler frontend resolves this by traversing the reference graph at the end of each update + /// with `Zcu.resolveReferences` and hiding compile errors which arise from this analysis. + want_layout: bool, + /// Initially `false`, and set to `true` once any dependency on or reference to the struct's + /// default field values is encountered, after which it is never reset to `false`, even across + /// incremental updates. + /// + /// This field is purely an optimization to avoid resolving the layout of types whose layouts + /// are never demanded. If this field is `true` but the layout is not actually needed, the + /// compiler frontend resolves this by traversing the reference graph at the end of each update + /// with `Zcu.resolveReferences` and hiding compile errors which arise from this analysis. + want_defaults: bool, + // The remaining fields are only valid once the struct's layout is resolved. field_name_map: MapIndex, field_names: NullTerminatedString.Slice, @@ -3490,6 +3504,16 @@ pub const LoadedUnionType = struct { /// or populate `enum_tag_type`. reified_field_names: NullTerminatedString.Slice, + /// Initially `false`, and set to `true` once any dependency on or reference to the struct's + /// layout is encountered, after which it is never reset to `false`, even across incremental + /// updates. + /// + /// This field is purely an optimization to avoid resolving the layout of types whose layouts + /// are never demanded. If this field is `true` but the layout is not actually needed, the + /// compiler frontend resolves this by traversing the reference graph at the end of each update + /// with `Zcu.resolveReferences` and hiding compile errors which arise from this analysis. + want_layout: bool, + // The remaining fields are only valid once the union's layout is resolved. field_types: Index.Slice, field_aligns: Alignment.Slice, @@ -3532,6 +3556,16 @@ pub const LoadedEnumType = struct { int_tag_mode: BackingTypeMode, nonexhaustive: bool, + /// Initially `false`, and set to `true` once any dependency on or reference to the struct's + /// layout is encountered, after which it is never reset to `false`, even across incremental + /// updates. + /// + /// This field is purely an optimization to avoid resolving the layout of types whose layouts + /// are never demanded. If this field is `true` but the layout is not actually needed, the + /// compiler frontend resolves this by traversing the reference graph at the end of each update + /// with `Zcu.resolveReferences` and hiding compile errors which arise from this analysis. + want_layout: bool, + // The remaining fields are only valid once the enum's layout is resolved. int_tag_type: Index, field_name_map: MapIndex, @@ -3669,6 +3703,9 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { }, .packed_backing_mode = undefined, + .want_layout = extra.data.flags.want_layout, + .want_defaults = extra.data.flags.want_defaults, + .field_name_map = extra.data.field_name_map, .field_names = field_names, .field_types = field_types, @@ -3690,15 +3727,15 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { }; const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, item.data); var extra_index = extra.end; - const captures: CaptureValue.Slice = switch (extra.data.captures_len) { + const captures: CaptureValue.Slice = switch (extra.data.bits.captures_len) { .reified => captures: { extra_index += 2; // type_hash: PackedU64 break :captures .empty; }, - _ => .{ + _ => |n| .{ .tid = unwrapped_index.tid, .start = extra_index, - .len = @intFromEnum(extra.data.captures_len), + .len = @intFromEnum(n), }, }; extra_index += captures.len; @@ -3723,13 +3760,16 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { return .{ .zir_index = extra.data.zir_index, .captures = captures, - .is_reified = extra.data.captures_len == .reified, + .is_reified = extra.data.bits.captures_len == .reified, .name = extra.data.name, .name_nav = extra.data.name_nav, .namespace = extra.data.namespace, .layout = .@"packed", .packed_backing_mode = backing_mode, + .want_layout = extra.data.bits.want_layout, + .want_defaults = extra.data.bits.want_defaults, + .field_name_map = extra.data.field_name_map, .field_names = field_names, .field_types = field_types, @@ -3813,6 +3853,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { .packed_backing_mode = undefined, .packed_backing_int_type = undefined, .reified_field_names = reified_field_names, + .want_layout = extra.data.flags.want_layout, .field_types = field_types, .field_aligns = field_aligns, .has_no_possible_value = extra.data.flags.has_no_possible_value, @@ -3828,19 +3869,19 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { }; const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, item.data); var extra_index = extra.end; - const captures: CaptureValue.Slice = switch (extra.data.captures_len) { + const captures: CaptureValue.Slice = switch (extra.data.bits.captures_len) { .reified => captures: { extra_index += 2; // type_hash: PackedU64 break :captures .empty; }, - _ => .{ + _ => |n| .{ .tid = unwrapped_index.tid, .start = extra_index, - .len = @intFromEnum(extra.data.captures_len), + .len = @intFromEnum(n), }, }; extra_index += captures.len; - const reified_field_names: NullTerminatedString.Slice = if (extra.data.captures_len == .reified) .{ + const reified_field_names: NullTerminatedString.Slice = if (extra.data.bits.captures_len == .reified) .{ .tid = unwrapped_index.tid, .start = extra_index, .len = extra.data.fields_len, @@ -3855,7 +3896,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { return .{ .zir_index = extra.data.zir_index, .captures = captures, - .is_reified = extra.data.captures_len == .reified, + .is_reified = extra.data.bits.captures_len == .reified, .name = extra.data.name, .name_nav = extra.data.name_nav, .namespace = extra.data.namespace, @@ -3866,6 +3907,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { .packed_backing_mode = backing_mode, .packed_backing_int_type = extra.data.backing_int_type, .reified_field_names = reified_field_names, + .want_layout = extra.data.bits.want_layout, .field_types = field_types, .field_aligns = .empty, .has_no_possible_value = undefined, @@ -3891,7 +3933,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { }; const extra = extraDataTrail(extra_list, Tag.TypeEnum, item.data); var extra_index: u32 = @intCast(extra.end); - const zir_index: TrackedInst.Index.Optional, const captures: CaptureValue.Slice, const owner_union: Index = switch (extra.data.captures_len) { + const zir_index: TrackedInst.Index.Optional, const captures: CaptureValue.Slice, const owner_union: Index = switch (extra.data.bits.captures_len) { .reified => info: { const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]); extra_index += 1; @@ -3903,13 +3945,13 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { extra_index += 1; break :info .{ .none, .empty, owner_union }; }, - _ => info: { + _ => |n| info: { const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]); extra_index += 1; const captures: CaptureValue.Slice = .{ .tid = unwrapped_index.tid, .start = extra_index, - .len = @intFromEnum(extra.data.captures_len), + .len = @intFromEnum(n), }; extra_index += captures.len; break :info .{ zir_index.toOptional(), captures, .none }; @@ -3935,7 +3977,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { return .{ .zir_index = zir_index, .captures = captures, - .is_reified = extra.data.captures_len == .reified, + .is_reified = extra.data.bits.captures_len == .reified, .owner_union = owner_union, .name = extra.data.name, .name_nav = extra.data.name_nav, @@ -3943,6 +3985,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { .int_tag_type = extra.data.int_tag_type, .int_tag_mode = if (explicit_int_tag) .explicit else .auto, .nonexhaustive = nonexhaustive, + .want_layout = extra.data.bits.want_layout, .field_name_map = extra.data.field_name_map, .field_value_map = field_value_map, .field_names = field_names, @@ -5629,7 +5672,10 @@ pub const Tag = enum(u8) { /// Alignment of the whole struct. Always `.none` until layout resolved. alignment: Alignment, - _: u16 = 0, + want_layout: bool, + want_defaults: bool, + + _: u14 = 0, }; }; @@ -5641,10 +5687,7 @@ pub const Tag = enum(u8) { /// 4. field_default: Index // if item tag implies field defaults; for each `fields_len` pub const TypeStructPacked = struct { zir_index: TrackedInst.Index, - captures_len: enum(u32) { - reified = std.math.maxInt(u32), - _, - }, + bits: Bits, name: NullTerminatedString, name_nav: Nav.Index.Optional, @@ -5655,6 +5698,15 @@ pub const Tag = enum(u8) { fields_len: u32, field_name_map: MapIndex, + + const Bits = packed struct(u32) { + captures_len: enum(u30) { + reified = std.math.maxInt(u30), + _, + }, + want_layout: bool, + want_defaults: bool, + }; }; /// For declared unions, field names are intentionally omitted because they are available in @@ -5718,7 +5770,9 @@ pub const Tag = enum(u8) { /// Alignment of the whole union. Always `.none` until layout resolved. alignment: Alignment, - _: u15 = 0, + want_layout: bool, + + _: u14 = 0, }; }; @@ -5734,10 +5788,7 @@ pub const Tag = enum(u8) { /// 3. field_type: Index // for each `fields_len` pub const TypeUnionPacked = struct { zir_index: TrackedInst.Index, - captures_len: enum(u32) { - reified = std.math.maxInt(u32), - _, - }, + bits: Bits, name: NullTerminatedString, name_nav: Nav.Index.Optional, @@ -5753,6 +5804,14 @@ pub const Tag = enum(u8) { /// to store it directly. This is also necessary for `dumpStatsFallible` to /// work on unresolved types. fields_len: u32, + + const Bits = packed struct(u32) { + captures_len: enum(u31) { + reified = std.math.maxInt(u31), + _, + }, + want_layout: bool, + }; }; /// Trailing: @@ -5764,11 +5823,7 @@ pub const Tag = enum(u8) { /// 5. field_name: NullTerminatedString // for each `fields_len` /// 6. field_value: Index // if tag is not `.type_enum_auto`; for each `fields_len` pub const TypeEnum = struct { - captures_len: enum(u32) { - reified = std.math.maxInt(u32), - generated_union_tag = std.math.maxInt(u32) - 1, - _, - }, + bits: Bits, name: NullTerminatedString, name_nav: Nav.Index.Optional, @@ -5780,6 +5835,15 @@ pub const Tag = enum(u8) { fields_len: u32, field_name_map: MapIndex, + + const Bits = packed struct(u32) { + captures_len: enum(u31) { + reified = std.math.maxInt(u31), + generated_union_tag = std.math.maxInt(u31) - 1, + _, + }, + want_layout: bool, + }; }; /// Trailing: @@ -5812,7 +5876,7 @@ pub const BackingTypeMode = enum(u1) { /// equality or hashing, except for `inferred_error_set` which is considered /// to be part of the type of the function. pub const FuncAnalysis = packed struct(u32) { - is_analyzed: bool, + want_runtime_analysis: bool, branch_hint: std.builtin.BranchHint, is_noinline: bool, has_error_trace: bool, @@ -6597,17 +6661,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { => .{ .struct_type = ns: { const extra_list = unwrapped_index.getExtra(ip); const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data); - break :ns switch (extra.data.captures_len) { + break :ns switch (extra.data.bits.captures_len) { .reified => .{ .reified = .{ .zir_index = extra.data.zir_index, .type_hash = extraData(extra_list, PackedU64, extra.end).get(), } }, - _ => .{ .declared = .{ + _ => |len| .{ .declared = .{ .zir_index = extra.data.zir_index, .captures = .{ .owned = .{ .tid = unwrapped_index.tid, .start = extra.end, - .len = @intFromEnum(extra.data.captures_len), + .len = @intFromEnum(len), } }, } }, }; @@ -6637,17 +6701,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .type_union_packed_auto, .type_union_packed_explicit => .{ .union_type = ns: { const extra_list = unwrapped_index.getExtra(ip); const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data); - break :ns switch (extra.data.captures_len) { + break :ns switch (extra.data.bits.captures_len) { .reified => .{ .reified = .{ .zir_index = extra.data.zir_index, .type_hash = extraData(extra_list, PackedU64, extra.end).get(), } }, - _ => .{ .declared = .{ + _ => |len| .{ .declared = .{ .zir_index = extra.data.zir_index, .captures = .{ .owned = .{ .tid = unwrapped_index.tid, .start = extra.end, - .len = @intFromEnum(extra.data.captures_len), + .len = @intFromEnum(len), } }, } }, }; @@ -6655,7 +6719,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .type_enum_auto, .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: { const extra_list = unwrapped_index.getExtra(ip); const extra = extraDataTrail(extra_list, Tag.TypeEnum, data); - break :ns switch (extra.data.captures_len) { + break :ns switch (extra.data.bits.captures_len) { .reified => .{ .reified = .{ .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(), @@ -6663,12 +6727,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .generated_union_tag => .{ .generated_union_tag = owner_union: { break :owner_union @enumFromInt(extra_list.view().items(.@"0")[extra.end]); } }, - _ => .{ .declared = .{ + _ => |len| .{ .declared = .{ .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), .captures = .{ .owned = .{ .tid = unwrapped_index.tid, .start = extra.end + 1, - .len = @intFromEnum(extra.data.captures_len), + .len = @intFromEnum(len), } }, } }, }; @@ -8138,7 +8202,11 @@ pub fn getDeclaredStructType( const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ .zir_index = ini.zir_index, - .captures_len = @enumFromInt(ini.captures.len), + .bits = .{ + .captures_len = @enumFromInt(ini.captures.len), + .want_layout = false, + .want_defaults = false, + }, .name = undefined, // set by `finish` .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` @@ -8204,6 +8272,8 @@ pub fn getDeclaredStructType( .comptime_only = false, .has_runtime_bits = false, .alignment = .none, + .want_layout = false, + .want_defaults = false, }, }); if (ini.captures.len != 0) { @@ -8281,7 +8351,11 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ .zir_index = ini.zir_index, - .captures_len = .reified, + .bits = .{ + .captures_len = .reified, + .want_layout = false, + .want_defaults = false, + }, .name = undefined, // set by `finish` .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` @@ -8352,6 +8426,8 @@ pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Pe .comptime_only = false, .has_runtime_bits = false, .alignment = .none, + .want_layout = false, + .want_defaults = false, }, }); _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash @@ -8451,7 +8527,10 @@ pub fn getDeclaredUnionType( const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{ .zir_index = ini.zir_index, - .captures_len = @enumFromInt(ini.captures.len), + .bits = .{ + .captures_len = @enumFromInt(ini.captures.len), + .want_layout = false, + }, .name = undefined, // set by `finish` .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` @@ -8509,6 +8588,7 @@ pub fn getDeclaredUnionType( .comptime_only = false, .has_runtime_bits = false, .alignment = .none, + .want_layout = false, }, }); if (ini.captures.len > 0) { @@ -8572,7 +8652,10 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{ .zir_index = ini.zir_index, - .captures_len = .reified, + .bits = .{ + .captures_len = .reified, + .want_layout = false, + }, .name = undefined, // set by `finish` .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` @@ -8633,6 +8716,7 @@ pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.Per .comptime_only = false, .has_runtime_bits = false, .alignment = .none, + .want_layout = false, }, }); _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); @@ -8723,7 +8807,10 @@ pub fn getDeclaredEnumType( (if (have_values) ini.fields_len else 0)); // field_value const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{ - .captures_len = @enumFromInt(ini.captures.len), + .bits = .{ + .captures_len = @enumFromInt(ini.captures.len), + .want_layout = false, + }, .name = undefined, // set by `finish` .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` @@ -8795,7 +8882,10 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT (if (have_values) ini.fields_len else 0)); // field_value const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{ - .captures_len = .reified, + .bits = .{ + .captures_len = .reified, + .want_layout = false, + }, .name = undefined, // set by `finish` .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` @@ -8865,7 +8955,10 @@ pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu (if (have_values) ini.fields_len else 0)); // field_value const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{ - .captures_len = .generated_union_tag, + .bits = .{ + .captures_len = .generated_union_tag, + .want_layout = false, + }, .name = undefined, // set by `finish` .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` @@ -9249,7 +9342,7 @@ pub fn getFuncDecl( const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{ .analysis = .{ - .is_analyzed = false, + .want_runtime_analysis = false, .branch_hint = .none, .is_noinline = key.is_noinline, .has_error_trace = false, @@ -9359,7 +9452,7 @@ pub fn getFuncDeclIes( const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{ .analysis = .{ - .is_analyzed = false, + .want_runtime_analysis = false, .branch_hint = .none, .is_noinline = key.is_noinline, .has_error_trace = false, @@ -9557,7 +9650,7 @@ pub fn getFuncInstance( const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{ .analysis = .{ - .is_analyzed = false, + .want_runtime_analysis = false, .branch_hint = .none, .is_noinline = arg.is_noinline, .has_error_trace = false, @@ -9658,7 +9751,7 @@ fn getFuncInstanceIes( const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{ .analysis = .{ - .is_analyzed = false, + .want_runtime_analysis = false, .branch_hint = .none, .is_noinline = arg.is_noinline, .has_error_trace = false, @@ -9902,9 +9995,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { TrackedInst.Index, TrackedInst.Index.Optional, ComptimeAllocIndex, - @FieldType(Tag.TypeStructPacked, "captures_len"), - @FieldType(Tag.TypeUnionPacked, "captures_len"), - @FieldType(Tag.TypeEnum, "captures_len"), => @intFromEnum(@field(item, field.name)), u32, @@ -9916,6 +10006,9 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { Tag.TypePointer.PackedOffset, Tag.TypeUnion.Flags, Tag.TypeStruct.Flags, + Tag.TypeStructPacked.Bits, + Tag.TypeUnionPacked.Bits, + Tag.TypeEnum.Bits, => @bitCast(@field(item, field.name)), else => @compileError("bad field type: " ++ @typeName(field.type)), @@ -9967,9 +10060,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat TrackedInst.Index, TrackedInst.Index.Optional, ComptimeAllocIndex, - @FieldType(Tag.TypeStructPacked, "captures_len"), - @FieldType(Tag.TypeUnionPacked, "captures_len"), - @FieldType(Tag.TypeEnum, "captures_len"), => @enumFromInt(extra_item), u32, @@ -9981,6 +10071,9 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat Tag.TypeUnion.Flags, Tag.TypeStruct.Flags, FuncAnalysis, + Tag.TypeStructPacked.Bits, + Tag.TypeUnionPacked.Bits, + Tag.TypeEnum.Bits, => @bitCast(extra_item), else => @compileError("bad field type: " ++ @typeName(field.type)), @@ -10750,7 +10843,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo .type_struct_packed_auto, .type_struct_packed_explicit => b: { var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len; const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data); - switch (extra.data.captures_len) { + switch (extra.data.bits.captures_len) { .reified => n += 2, // type_hash: PackedU64 _ => |len| n += @intFromEnum(len), // capture: CaptureValue } @@ -10761,7 +10854,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo .type_struct_packed_auto_defaults, .type_struct_packed_explicit_defaults => b: { var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len; const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data); - switch (extra.data.captures_len) { + switch (extra.data.bits.captures_len) { .reified => n += 2, // type_hash: PackedU64 _ => |len| n += @intFromEnum(len), // capture: CaptureValue } @@ -10790,7 +10883,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo .type_union_packed_auto, .type_union_packed_explicit => b: { var n: usize = @typeInfo(Tag.TypeUnionPacked).@"struct".fields.len; const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data); - switch (extra.data.captures_len) { + switch (extra.data.bits.captures_len) { .reified => n += 2, // type_hash: PackedU64 _ => |len| n += @intFromEnum(len), // capture: CaptureValue } @@ -10800,7 +10893,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo .type_enum_auto => b: { var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len; const extra = extraData(extra_list, Tag.TypeEnum, data); - switch (extra.captures_len) { + switch (extra.bits.captures_len) { .generated_union_tag => n += 1, // owner_union: Index .reified => { n += 1; // zir_index: TrackedInst.Index, @@ -10817,7 +10910,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo .type_enum_explicit, .type_enum_nonexhaustive => b: { var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len; const extra = extraData(extra_list, Tag.TypeEnum, data); - switch (extra.captures_len) { + switch (extra.bits.captures_len) { .generated_union_tag => n += 1, // owner_union: Index .reified => { n += 1; // zir_index: TrackedInst.Index, @@ -11204,6 +11297,7 @@ pub fn createDeclNav( .analysis = .{ .namespace = namespace, .zir_index = zir_index, + .wanted = false, }, .status = .unresolved, })); @@ -12829,3 +12923,175 @@ pub fn resolveEnumLayout( extra_items[item.data + std.meta.fieldIndex(Tag.TypeEnum, "int_tag_type").?] = @intFromEnum(int_tag_type); } + +/// Sets the "want_layout" flag on the given struct, union, or enum type. Returns true if the flag +/// was *not* already set, meaning we have just discovered the first reference to this type's +/// layout. This flag is never reset to false, and exists purely as an optimization; for details, +/// see doc comments in `LoadedStructType`. +pub fn setWantTypeLayout(ip: *InternPool, io: Io, container_type: Index) bool { + const unwrapped_index = container_type.unwrap(ip); + + const local = ip.getLocal(unwrapped_index.tid); + local.mutate.extra.mutex.lockUncancelable(io); + defer local.mutate.extra.mutex.unlock(io); + + const extra_items = local.shared.extra.view().items(.@"0"); + const item = unwrapped_index.getItem(ip); + switch (item.tag) { + .type_struct_packed_auto, + .type_struct_packed_explicit, + .type_struct_packed_auto_defaults, + .type_struct_packed_explicit_defaults, + => { + const bits: *Tag.TypeStructPacked.Bits = @ptrCast(&extra_items[ + item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "bits").? + ]); + if (bits.want_layout) { + return false; + } else { + bits.want_layout = true; + return true; + } + }, + + .type_struct => { + const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[ + item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").? + ]); + if (flags.want_layout) { + return false; + } else { + flags.want_layout = true; + return true; + } + }, + + .type_union_packed_auto, + .type_union_packed_explicit, + => { + const bits: *Tag.TypeUnionPacked.Bits = @ptrCast(&extra_items[ + item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "bits").? + ]); + if (bits.want_layout) { + return false; + } else { + bits.want_layout = true; + return true; + } + }, + + .type_union => { + const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[ + item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").? + ]); + if (flags.want_layout) { + return false; + } else { + flags.want_layout = true; + return true; + } + }, + + .type_enum_auto, + .type_enum_explicit, + .type_enum_nonexhaustive, + => { + const bits: *Tag.TypeEnum.Bits = @ptrCast(&extra_items[ + item.data + std.meta.fieldIndex(Tag.TypeEnum, "bits").? + ]); + if (bits.want_layout) { + return false; + } else { + bits.want_layout = true; + return true; + } + }, + + else => unreachable, + } +} + +/// Like `setWantTypeLayout`, but for the default field values of a struct (so this sets the +/// `want_defaults` flag rather than the `want_layout` flag). +pub fn setWantStructDefaults(ip: *InternPool, io: Io, struct_type: Index) bool { + const unwrapped_index = struct_type.unwrap(ip); + + const local = ip.getLocal(unwrapped_index.tid); + local.mutate.extra.mutex.lockUncancelable(io); + defer local.mutate.extra.mutex.unlock(io); + + const extra_items = local.shared.extra.view().items(.@"0"); + const item = unwrapped_index.getItem(ip); + switch (item.tag) { + .type_struct_packed_auto, + .type_struct_packed_explicit, + .type_struct_packed_auto_defaults, + .type_struct_packed_explicit_defaults, + => { + const bits: *Tag.TypeStructPacked.Bits = @ptrCast(&extra_items[ + item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "bits").? + ]); + if (bits.want_defaults) { + return false; + } else { + bits.want_defaults = true; + return true; + } + }, + + .type_struct => { + const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[ + item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").? + ]); + if (flags.want_defaults) { + return false; + } else { + flags.want_defaults = true; + return true; + } + }, + + else => unreachable, + } +} + +/// Like `setWantTypeLayout`, but for runtime analysis of a function body, using the +/// `FuncAnalysis.want_runtime_analysis` flag. +pub fn setWantRuntimeFnAnalysis(ip: *InternPool, io: Io, func_index: Index) bool { + const unwrapped_index = func_index.unwrap(ip); + + const local = ip.getLocal(unwrapped_index.tid); + local.mutate.extra.mutex.lockUncancelable(io); + defer local.mutate.extra.mutex.unlock(io); + + const a = funcAnalysisPtr(ip, func_index); + if (a.want_runtime_analysis) { + return false; + } else { + a.want_runtime_analysis = true; + return true; + } +} + +/// Like `setWantTypeLayout`, but for runtime analysis of a `Nav`, using the `Nav.analysis.wanted` flag. +pub fn setWantNavAnalysis(ip: *InternPool, io: Io, nav_index: Nav.Index) bool { + const unwrapped = nav_index.unwrap(ip); + + const local = ip.getLocal(unwrapped.tid); + local.mutate.extra.mutex.lockUncancelable(io); + defer local.mutate.extra.mutex.unlock(io); + + const navs = local.shared.navs.view(); + + if (navs.items(.analysis_namespace)[unwrapped.index] == .none) { + return false; + } + + const bits = &navs.items(.bits)[unwrapped.index]; + if (bits.want_analysis) { + return false; + } else { + bits.want_analysis = true; + return true; + } +} diff --git a/src/Sema.zig b/src/Sema.zig index 2fffe8ae546af74951980c583506ba82647b0d60..a506a7e6bbc369bf6a9906d2cda4dd6b41450317 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3258,7 +3258,7 @@ fn zirAllocExtended( } else .none; if (small.has_type) { - try sema.ensureLayoutResolved(var_ty); + try sema.ensureLayoutResolved(var_ty, ty_src); if (block.isComptime() or small.is_comptime or var_ty.comptimeOnly(zcu)) { return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment); } @@ -3322,7 +3322,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); const var_src = block.nodeOffset(inst_data.src_node); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); - try sema.ensureLayoutResolved(var_ty); + try sema.ensureLayoutResolved(var_ty, ty_src); return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); } @@ -3743,7 +3743,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I const var_src = block.nodeOffset(inst_data.src_node); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); - try sema.ensureLayoutResolved(var_ty); + try sema.ensureLayoutResolved(var_ty, ty_src); if (block.isComptime() or var_ty.comptimeOnly(zcu)) { return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); } @@ -3775,7 +3775,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const var_src = block.nodeOffset(inst_data.src_node); const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); - try sema.ensureLayoutResolved(var_ty); + try sema.ensureLayoutResolved(var_ty, ty_src); if (block.isComptime()) { return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); } @@ -4132,8 +4132,9 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const ptr = sema.resolveInst(un_node.operand); - try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu)); - return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node)); + const src = block.nodeOffset(un_node.src_node); + try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu), src); + return sema.optEuBasePtrInit(block, ptr, src); } fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -4518,7 +4519,7 @@ fn validateStructInit( if (struct_ty.structFieldIsComptime(i, zcu)) continue; if (!struct_ty.isTuple(zcu)) { - try sema.ensureStructDefaultsResolved(struct_ty); + try sema.ensureStructDefaultsResolved(struct_ty, init_src); } const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse { @@ -4642,7 +4643,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr } const elem_ty = operand_ty.childType(zcu); - try sema.ensureLayoutResolved(elem_ty); + try sema.ensureLayoutResolved(elem_ty, src); if (try elem_ty.onePossibleValue(pt) != null) { // No need to validate the actual pointer value, we don't need it! @@ -7025,7 +7026,7 @@ fn analyzeCall( break :ret_ty full_ty; }; - try sema.ensureLayoutResolved(resolved_ret_ty); + try sema.ensureLayoutResolved(resolved_ret_ty, func_ret_ty_src); // If we've discovered after evaluating arguments that a generic function instantiation is // comptime-only, then we can mark the block as comptime *now*. @@ -7122,7 +7123,7 @@ fn analyzeCall( .generic_owner = func_val.?.toIntern(), .comptime_args = comptime_args, }); - try sema.ensureLayoutResolved(.fromInterned(ip.typeOf(func_instance))); + try sema.ensureLayoutResolved(.fromInterned(ip.typeOf(func_instance)), call_src); if (zcu.comp.debugIncremental()) { const nav = ip.indexToKey(func_instance).func.owner_nav; const gop = try zcu.incremental_debug_state.navs.getOrPut(gpa, nav); @@ -7196,7 +7197,7 @@ fn analyzeCall( return .unreachable_value; } - try sema.ensureLayoutResolved(sema.typeOf(maybe_opv)); + try sema.ensureLayoutResolved(sema.typeOf(maybe_opv), func_ret_ty_src); if (try sema.typeOf(maybe_opv).onePossibleValue(pt)) |opv| { return .fromValue(opv); } else { @@ -7270,7 +7271,7 @@ fn analyzeCall( // We're about to do an inline call; if the return type expression was generic, the return type // may not be resolved yet. It's correct to resolve it because the function is going to return a // value of this type. - try sema.ensureLayoutResolved(resolved_ret_ty); + try sema.ensureLayoutResolved(resolved_ret_ty, func_ret_ty_src); // For an inline call, we depend on the source code of the whole function definition. try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index }); @@ -7532,7 +7533,6 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil const zcu = pt.zcu; const bin = sema.code.instructions.items(.data)[@intFromEnum(inst)].bin; const maybe_wrapped_indexable_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, bin.lhs) orelse return .generic_poison_type; - try sema.ensureLayoutResolved(maybe_wrapped_indexable_ty); const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(zcu); assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) { @@ -8040,7 +8040,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError if (dest_ty.zigTypeTag(zcu) != .@"enum") { return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)}); } - try sema.ensureLayoutResolved(dest_ty); + try sema.ensureLayoutResolved(dest_ty, src); _ = try sema.checkIntType(block, operand_src, operand_ty); if (sema.resolveValue(operand)) |int_val| { @@ -8103,7 +8103,7 @@ fn zirOptionalPayloadPtr( const ptr_ty = sema.typeOf(optional_ptr); assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer); - try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu)); + try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src); return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); } @@ -8313,7 +8313,7 @@ fn zirErrUnionPayloadPtr( const ptr_ty = sema.typeOf(operand); assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer); - try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu)); + try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src); return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); } @@ -9022,6 +9022,7 @@ fn funcCommon( const io = comp.io; const ip = &zcu.intern_pool; + const src = block.nodeOffset(src_node_offset); const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset }); const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset }); @@ -9091,7 +9092,7 @@ fn funcCommon( .lbrace_column = @as(u16, @truncate(src_locs.columns)), .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), })); - try sema.ensureLayoutResolved(func_val.typeOf(zcu)); + try sema.ensureLayoutResolved(func_val.typeOf(zcu), src); return .fromValue(func_val); } @@ -9106,7 +9107,7 @@ fn funcCommon( }); if (has_body) { - try sema.ensureLayoutResolved(.fromInterned(func_ty)); + try sema.ensureLayoutResolved(.fromInterned(func_ty), src); return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{ .owner_nav = sema.owner.unwrap().nav_val, .ty = func_ty, @@ -9762,7 +9763,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.failWithOwnedErrorMsg(block, msg); } try sema.checkIndexable(block, src, indexable_ty); - try sema.ensureLayoutResolved(indexable_ty.childType(zcu)); + try sema.ensureLayoutResolved(indexable_ty.childType(zcu), src); return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false); } @@ -9983,7 +9984,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp err_union_ty.fmt(pt), }); } - try sema.ensureLayoutResolved(err_union_ty); + try sema.ensureLayoutResolved(err_union_ty, operand_src); const non_err_cond = if (non_err_case.operand_is_ref) try sema.analyzePtrIsNonErr(block, operand_src, eu_maybe_ptr) @@ -11287,7 +11288,7 @@ fn validateSwitchBlock( } break :operand_ty raw_operand_ty; }; - try sema.ensureLayoutResolved(operand_ty); + try sema.ensureLayoutResolved(operand_ty, operand_src); const item_ty: Type = item_ty: { switch (operand_ty.zigTypeTag(zcu)) { @@ -12870,7 +12871,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const name_src = block.builtinCallArgSrc(inst_data.src_node, 1); const ty = try sema.resolveType(block, ty_src, extra.lhs); const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name }); - try sema.ensureLayoutResolved(ty); + try sema.ensureLayoutResolved(ty, ty_src); const ip = &zcu.intern_pool; const has_field = hf: { @@ -15270,7 +15271,7 @@ fn analyzeArithmetic( else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"), }; - try sema.ensureLayoutResolved(lhs_ty.childType(zcu)); + try sema.ensureLayoutResolved(lhs_ty.childType(zcu), src); return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src); }, } @@ -15964,7 +15965,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .@"anyframe", => {}, } - try sema.ensureLayoutResolved(ty); + try sema.ensureLayoutResolved(ty, operand_src); return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu))); } @@ -16005,7 +16006,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A .@"anyframe", => {}, } - try sema.ensureLayoutResolved(operand_ty); + try sema.ensureLayoutResolved(operand_ty, operand_src); return .fromValue(try pt.intValue(.comptime_int, operand_ty.bitSize(zcu))); } @@ -16251,7 +16252,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const type_info_ty = try sema.getBuiltinType(src, .Type); const type_info_tag_ty = type_info_ty.unionTagType(zcu).?; - try sema.ensureLayoutResolved(ty); + try sema.ensureLayoutResolved(ty, src); if (ty.typeDeclInst(zcu)) |type_decl_inst| { try sema.declareDependency(.{ .namespace = type_decl_inst }); @@ -16412,7 +16413,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (info.flags.alignment.toByteUnits()) |b| break :bytes b; const elem_ty: Type = .fromInterned(info.child); // MLUGG TODO: this resolution is sus, but i doubt i'll solve it in this branch - try sema.ensureLayoutResolved(elem_ty); + try sema.ensureLayoutResolved(elem_ty, src); break :bytes elem_ty.abiAlignment(zcu).toByteUnits().?; }); @@ -16873,7 +16874,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .struct_type => ip.loadStructType(ty.toIntern()), else => unreachable, }; - try sema.ensureStructDefaultsResolved(ty); // can't do this sooner, since it's not allowed on tuples + try sema.ensureStructDefaultsResolved(ty, src); // can't do this sooner, since it's not allowed on tuples struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); for (struct_field_vals, 0..) |*field_val, field_index| { @@ -18294,7 +18295,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size, }); } - try sema.ensureLayoutResolved(elem_ty); + try sema.ensureLayoutResolved(elem_ty, elem_ty_src); const elem_bit_size = elem_ty.bitSize(zcu); if (elem_bit_size > host_size * 8 - bit_offset) { return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{ @@ -18363,7 +18364,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE const pt = sema.pt; const zcu = pt.zcu; - try sema.ensureLayoutResolved(obj_ty); + try sema.ensureLayoutResolved(obj_ty, ty_src); switch (obj_ty.zigTypeTag(zcu)) { .@"struct" => return sema.structInitEmpty(block, obj_ty, src, src), @@ -18428,7 +18429,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is }); } else ty_operand; - try sema.ensureLayoutResolved(init_ty); + try sema.ensureLayoutResolved(init_ty, src); const obj_ty = init_ty.optEuBaseType(zcu); @@ -18544,7 +18545,7 @@ fn zirStructInit( // The type wasn't actually known, so treat this as an anon struct init. return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref); }; - try sema.ensureLayoutResolved(result_ty); + try sema.ensureLayoutResolved(result_ty, src); const resolved_ty = result_ty.optEuBaseType(zcu); if (resolved_ty.zigTypeTag(zcu) == .@"struct") { @@ -18751,7 +18752,7 @@ fn finishStructInit( continue; } - try sema.ensureStructDefaultsResolved(struct_ty); + try sema.ensureStructDefaultsResolved(struct_ty, init_src); const field_default: InternPool.Index = d: { if (struct_type.field_defaults.len == 0) break :d .none; @@ -18979,17 +18980,11 @@ fn structInitAnon( }); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - try zcu.outdated.ensureUnusedCapacity(gpa, 1); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); - errdefer comptime unreachable; // because we don't remove the `outdated` entries - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; try sema.addTypeReferenceEntry(src, struct_ty); - try sema.ensureLayoutResolved(struct_ty); + try sema.ensureLayoutResolved(struct_ty, src); _ = opt_runtime_index orelse { const struct_val = try pt.aggregateValue(struct_ty, values); @@ -19308,7 +19303,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const field_src = block.builtinCallArgSrc(inst_data.src_node, 1); const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name }); - try sema.ensureLayoutResolved(aggregate_ty); + try sema.ensureLayoutResolved(aggregate_ty, ty_src); return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); } @@ -19328,7 +19323,7 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu); const zir_field_name = sema.code.nullTerminatedString(extra.name_start); const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls); - try sema.ensureLayoutResolved(aggregate_ty); + try sema.ensureLayoutResolved(aggregate_ty, ty_src); return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src); } @@ -19431,7 +19426,7 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (ty.isNoReturn(zcu)) { return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)}); } - try sema.ensureLayoutResolved(ty); + try sema.ensureLayoutResolved(ty, operand_src); return .fromValue(try pt.intValue(.comptime_int, ty.abiAlignment(zcu).toByteUnits().?)); } @@ -19912,7 +19907,7 @@ fn zirReifyFn( const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs }); const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty); - try sema.ensureLayoutResolved(ret_ty); + try sema.ensureLayoutResolved(ret_ty, ret_ty_src); const fn_attrs_uncoerced = sema.resolveInst(extra.fn_attrs); const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src); @@ -19937,7 +19932,7 @@ fn zirReifyFn( param_types_src, fn_attrs.@"callconv", ); - try sema.ensureLayoutResolved(param_ty); + try sema.ensureLayoutResolved(param_ty, param_types_src); if (param_ty.comptimeOnly(zcu)) { return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)}); } @@ -20253,14 +20248,6 @@ fn zirReifyStruct( }); try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); - - try zcu.outdated.ensureUnusedCapacity(gpa, 1); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); - errdefer comptime unreachable; // because we don't remove the `outdated` entries - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); return .fromIntern(wip.finish(ip, new_namespace_index)); }, @@ -20482,15 +20469,6 @@ fn zirReifyUnion( if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); - // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); - - try zcu.outdated.ensureUnusedCapacity(gpa, 1); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); - errdefer comptime unreachable; // because we don't remove the `outdated` entry - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); - return .fromIntern(wip.finish(ip, new_namespace_index)); }, } @@ -20643,15 +20621,6 @@ fn zirReifyEnum( try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); - - try zcu.outdated.ensureUnusedCapacity(gpa, 1); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); - errdefer comptime unreachable; // because we don't remove the `outdated` entry - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); - return .fromIntern(wip.finish(ip, new_namespace_index)); }, } @@ -20874,7 +20843,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const elem_ty = ptr_ty.nullablePtrElem(zcu); // We'll need to validate the pointer alignment. - try sema.ensureLayoutResolved(elem_ty); + try sema.ensureLayoutResolved(elem_ty, src); const ptr_align = ptr_ty.ptrAlignment(zcu); if (ptr_ty.isSlice(zcu)) { @@ -21217,8 +21186,8 @@ fn ptrCastFull( const src_info = operand_ty.ptrInfo(zcu); const dest_info = dest_ty.ptrInfo(zcu); - try sema.ensureLayoutResolved(.fromInterned(src_info.child)); - try sema.ensureLayoutResolved(.fromInterned(dest_info.child)); + try sema.ensureLayoutResolved(.fromInterned(src_info.child), operand_src); + try sema.ensureLayoutResolved(.fromInterned(dest_info.child), src); const DestSliceLen = union(enum) { undef, @@ -21989,7 +21958,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 const ty = try sema.resolveType(block, ty_src, extra.lhs); const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.rhs, .{ .simple = .field_name }); - try sema.ensureLayoutResolved(ty); + try sema.ensureLayoutResolved(ty, ty_src); const pt = sema.pt; const zcu = pt.zcu; @@ -23072,7 +23041,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true); const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order }); - try sema.ensureLayoutResolved(elem_ty); + try sema.ensureLayoutResolved(elem_ty, elem_ty_src); switch (order) { .release, .acq_rel => { @@ -23392,7 +23361,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)}); } const parent_ty: Type = .fromInterned(parent_ptr_info.child); - try sema.ensureLayoutResolved(parent_ty); + try sema.ensureLayoutResolved(parent_ty, inst_src); switch (parent_ty.zigTypeTag(zcu)) { .@"struct", .@"union" => {}, else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}), @@ -24002,8 +23971,8 @@ fn zirMemcpy( const dest_elem_ty = dest_ty.indexableElem(zcu); const src_elem_ty = src_ty.indexableElem(zcu); - try sema.ensureLayoutResolved(dest_elem_ty); - try sema.ensureLayoutResolved(src_elem_ty); + try sema.ensureLayoutResolved(dest_elem_ty, dest_src); + try sema.ensureLayoutResolved(src_elem_ty, src_src); const imc = try sema.coerceInMemoryAllowed( block, @@ -25518,7 +25487,7 @@ fn fieldPtrLoad( const zcu = pt.zcu; const object_ptr_ty = sema.typeOf(object_ptr); const pointee_ty = object_ptr_ty.childType(zcu); - try sema.ensureLayoutResolved(pointee_ty); // MLUGG TODO + try sema.ensureLayoutResolved(pointee_ty, src); // MLUGG TODO if (try pointee_ty.onePossibleValue(pt)) |opv| { const object: Air.Inst.Ref = .fromValue(opv); return fieldVal(sema, block, src, object, field_name, field_name_src); @@ -25654,7 +25623,7 @@ fn fieldVal( if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { return inst; } - try sema.ensureLayoutResolved(child_type); + try sema.ensureLayoutResolved(child_type, src); if (child_type.unionTagType(zcu)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| { const field_index: u32 = @intCast(field_index_usize); @@ -25667,7 +25636,7 @@ fn fieldVal( if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { return inst; } - try sema.ensureLayoutResolved(child_type); + try sema.ensureLayoutResolved(child_type, src); const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); const field_index: u32 = @intCast(field_index_usize); @@ -25693,7 +25662,7 @@ fn fieldVal( }, .@"struct" => if (is_pointer_to) { // Avoid loading the entire struct by fetching a pointer and loading that - try sema.ensureLayoutResolved(inner_ty); + try sema.ensureLayoutResolved(inner_ty, src); const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); return sema.analyzeLoad(block, src, field_ptr, object_src); } else { @@ -25701,7 +25670,7 @@ fn fieldVal( }, .@"union" => if (is_pointer_to) { // Avoid loading the entire union by fetching a pointer and loading that - try sema.ensureLayoutResolved(inner_ty); + try sema.ensureLayoutResolved(inner_ty, src); const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); return sema.analyzeLoad(block, src, field_ptr, object_src); } else { @@ -25884,7 +25853,7 @@ fn fieldPtr( if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { return inst; } - try sema.ensureLayoutResolved(child_type); + try sema.ensureLayoutResolved(child_type, src); if (child_type.unionTagType(zcu)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { const field_index_u32: u32 = @intCast(field_index); @@ -25898,7 +25867,7 @@ fn fieldPtr( if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { return inst; } - try sema.ensureLayoutResolved(child_type); + try sema.ensureLayoutResolved(child_type, src); const field_index = child_type.enumFieldIndex(field_name, zcu) orelse { return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); }; @@ -25920,7 +25889,7 @@ fn fieldPtr( try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) else object_ptr; - try sema.ensureLayoutResolved(inner_ty); + try sema.ensureLayoutResolved(inner_ty, src); const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); return field_ptr; @@ -25930,7 +25899,7 @@ fn fieldPtr( try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) else object_ptr; - try sema.ensureLayoutResolved(inner_ty); + try sema.ensureLayoutResolved(inner_ty, src); const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); return field_ptr; @@ -25974,7 +25943,7 @@ fn fieldCallBind( // Optionally dereference a second pointer to get the concrete type. const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one; const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty; - try sema.ensureLayoutResolved(concrete_ty); + try sema.ensureLayoutResolved(concrete_ty, src); const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; const object_ptr = if (is_double_ptr) try sema.analyzeLoad(block, src, raw_ptr, src) @@ -26661,7 +26630,7 @@ fn elemPtr( else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}), }; try sema.checkIndexable(block, src, indexable_ty); - try sema.ensureLayoutResolved(indexable_ty); + try sema.ensureLayoutResolved(indexable_ty, src); const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) { .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), @@ -26673,7 +26642,7 @@ fn elemPtr( }, else => { const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); - try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu)); + try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src); return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety); }, }; @@ -26769,7 +26738,7 @@ fn elemVal( switch (indexable_ty.zigTypeTag(zcu)) { .pointer => { const child_ty = indexable_ty.childType(zcu); - try sema.ensureLayoutResolved(child_ty); + try sema.ensureLayoutResolved(child_ty, src); switch (indexable_ty.ptrSize(zcu)) { .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), .many, .c => { @@ -27293,7 +27262,7 @@ fn coerceExtra( const target = zcu.getTarget(); inst_ty.assertHasLayout(zcu); - try sema.ensureLayoutResolved(dest_ty); + try sema.ensureLayoutResolved(dest_ty, inst_src); // If the types are the same, we can return the operand. if (dest_ty.eql(inst_ty, zcu)) @@ -28657,8 +28626,8 @@ fn coerceInMemoryAllowedFns( } }; } - try sema.ensureLayoutResolved(src_ty); - try sema.ensureLayoutResolved(dest_ty); + try sema.ensureLayoutResolved(src_ty, src_src); + try sema.ensureLayoutResolved(dest_ty, dest_src); const src_is_runtime = src_ty.fnHasRuntimeBits(zcu); const dest_is_runtime = dest_ty.fnHasRuntimeBits(zcu); if (src_is_runtime != dest_is_runtime) return .{ .fn_generic = !dest_is_runtime }; @@ -28712,7 +28681,7 @@ fn coerceInMemoryAllowedFns( const src_is_comptime = src_info.paramIsComptime(@intCast(param_i)); const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i)); if (src_is_comptime == dest_is_comptime) break :comptime_param; - try sema.ensureLayoutResolved(dest_param_ty); + try sema.ensureLayoutResolved(dest_param_ty, dest_src); if (!dest_is_mut and src_is_comptime and !dest_is_comptime and dest_param_ty.comptimeOnly(zcu)) { // A parameter which is marked `comptime` can drop that annotation if the type is comptime-only. // The function remains generic, and the parameter is going to be comptime-resolved either way, @@ -28940,11 +28909,11 @@ fn coerceInMemoryAllowedPtrs( dest_info.child != src_info.child) { const src_align = if (src_info.flags.alignment == .none) a: { - try sema.ensureLayoutResolved(src_child); + try sema.ensureLayoutResolved(src_child, src_src); break :a src_child.abiAlignment(zcu); } else src_info.flags.alignment; const dest_align = if (dest_info.flags.alignment == .none) a: { - try sema.ensureLayoutResolved(dest_child); + try sema.ensureLayoutResolved(dest_child, dest_src); break :a dest_child.abiAlignment(zcu); } else dest_info.flags.alignment; if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) { @@ -29294,7 +29263,7 @@ fn bitCast( const old_ty = sema.typeOf(inst); old_ty.assertHasLayout(zcu); - try sema.ensureLayoutResolved(dest_ty); + try sema.ensureLayoutResolved(dest_ty, inst_src); const dest_bits = dest_ty.bitSize(zcu); const old_bits = old_ty.bitSize(zcu); @@ -29908,7 +29877,7 @@ fn analyzeNavVal( return sema.analyzeLoad(block, src, ref, src); } -fn addReferenceEntry( +pub fn addReferenceEntry( sema: *Sema, opt_block: ?*Block, src: LazySrcLoc, @@ -30176,7 +30145,7 @@ fn analyzeLoad( return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}); } - try sema.ensureLayoutResolved(elem_ty); + try sema.ensureLayoutResolved(elem_ty, src); if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { @@ -30561,7 +30530,7 @@ fn analyzeSlice( else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}), } - try sema.ensureLayoutResolved(elem_ty); + try sema.ensureLayoutResolved(elem_ty, src); const ptr = if (slice_ty.isSlice(zcu)) try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) @@ -34024,7 +33993,7 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc, .type => if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .type) { return sema.fail(block, src, "{s}.{s} is not a type", .{ parent_name, name }); } else val: { - try sema.ensureLayoutResolved(uncoerced_val.toType()); + try sema.ensureLayoutResolved(uncoerced_val.toType(), src); break :val uncoerced_val; }, .func => val: { @@ -34271,20 +34240,9 @@ fn zirStructDecl( }); errdefer pt.destroyNamespace(new_namespace_index); try pt.scanNamespace(new_namespace_index, struct_decl.decls); - // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) }); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - try zcu.outdated.ensureUnusedCapacity(gpa, 2); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); - errdefer comptime unreachable; // because we don't remove the `outdated` entries - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {}); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; @@ -34364,17 +34322,8 @@ fn zirUnionDecl( try pt.scanNamespace(new_namespace_index, union_decl.decls); - // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); - if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - try zcu.outdated.ensureUnusedCapacity(gpa, 1); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); - errdefer comptime unreachable; // because we don't remove the `outdated` entry - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; @@ -34434,17 +34383,8 @@ fn zirEnumDecl( try pt.scanNamespace(new_namespace_index, enum_decl.decls); - // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); - if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - try zcu.outdated.ensureUnusedCapacity(gpa, 1); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); - errdefer comptime unreachable; // because we don't remove the `outdated` entry - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig index bb10a39729ad41d3e74af62428b671985c13a0cf..71256ae44ddc4e6283171172bfb0cdda3f8eb50e 100644 --- a/src/Sema/LowerZon.zig +++ b/src/Sema/LowerZon.zig @@ -300,7 +300,7 @@ fn checkTypeInner( } else { const gop = try visited.getOrPut(sema.arena, ty.toIntern()); if (gop.found_existing) return; - try sema.ensureLayoutResolved(ty); + try sema.ensureLayoutResolved(ty, self.import_loc); const struct_info = zcu.typeToStruct(ty).?; for (struct_info.field_types.get(ip)) |field_type| { try self.checkTypeInner(.fromInterned(field_type), null, visited); @@ -309,7 +309,7 @@ fn checkTypeInner( .@"union" => { const gop = try visited.getOrPut(sema.arena, ty.toIntern()); if (gop.found_existing) return; - try sema.ensureLayoutResolved(ty); + try sema.ensureLayoutResolved(ty, self.import_loc); const union_info = zcu.typeToUnion(ty).?; for (union_info.field_types.get(ip)) |field_type| { if (field_type != .void_type) { @@ -646,6 +646,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I const gpa = comp.gpa; const io = comp.io; const ip = &pt.zcu.intern_pool; + try self.sema.ensureLayoutResolved(res_ty, self.import_loc); switch (node.get(self.file.zoir.?)) { .enum_literal => |field_name| { const field_name_interned = try ip.getOrPutString( @@ -768,8 +769,8 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool const io = comp.io; const ip = &pt.zcu.intern_pool; - try self.sema.ensureLayoutResolved(res_ty); - try self.sema.ensureStructDefaultsResolved(res_ty); + try self.sema.ensureLayoutResolved(res_ty, self.import_loc); + try self.sema.ensureStructDefaultsResolved(res_ty, self.import_loc); const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?; const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) { @@ -919,7 +920,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. const gpa = comp.gpa; const io = comp.io; const ip = &pt.zcu.intern_pool; - try self.sema.ensureLayoutResolved(res_ty); + try self.sema.ensureLayoutResolved(res_ty, self.import_loc); const union_info = pt.zcu.typeToUnion(res_ty).?; const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type); diff --git a/src/Sema/bitcast.zig b/src/Sema/bitcast.zig index ee70bd1746466aaf57c8812083f37892e69dac59..b496db1ce0e167aad6cacf51568ecc9bb91cde97 100644 --- a/src/Sema/bitcast.zig +++ b/src/Sema/bitcast.zig @@ -80,7 +80,7 @@ fn bitCastInner( const val_ty = val.typeOf(zcu); val_ty.assertHasLayout(zcu); - try sema.ensureLayoutResolved(dest_ty); + dest_ty.assertHasLayout(zcu); assert(val_ty.hasWellDefinedLayout(zcu)); @@ -138,8 +138,8 @@ fn bitCastSpliceInner( const val_ty = val.typeOf(zcu); const splice_val_ty = splice_val.typeOf(zcu); - try sema.ensureLayoutResolved(val_ty); - try sema.ensureLayoutResolved(splice_val_ty); + val_ty.assertHasLayout(zcu); + splice_val_ty.assertHasLayout(zcu); const splice_bits = splice_val_ty.bitSize(zcu); diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig index f18cf9aaaeae1557d1a69799516d0f7687096dd0..970cf4f0116328dc6f84fe4c1e755eb71a4a915a 100644 --- a/src/Sema/type_resolution.zig +++ b/src/Sema/type_resolution.zig @@ -19,7 +19,7 @@ const arith = @import("arith.zig"); /// Adds incremental dependencies tracking any required type resolution. /// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific). /// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing -pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { +pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!void { const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -35,20 +35,21 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { .func_type => |func_type| { for (func_type.param_types.get(ip)) |param_ty| { - try ensureLayoutResolved(sema, .fromInterned(param_ty)); + try ensureLayoutResolved(sema, .fromInterned(param_ty), src); } - try ensureLayoutResolved(sema, .fromInterned(func_type.return_type)); + try ensureLayoutResolved(sema, .fromInterned(func_type.return_type), src); }, - .array_type => |arr| return ensureLayoutResolved(sema, .fromInterned(arr.child)), - .vector_type => |vec| return ensureLayoutResolved(sema, .fromInterned(vec.child)), - .opt_type => |child| return ensureLayoutResolved(sema, .fromInterned(child)), - .error_union_type => |eu| return ensureLayoutResolved(sema, .fromInterned(eu.payload_type)), + .array_type => |arr| return ensureLayoutResolved(sema, .fromInterned(arr.child), src), + .vector_type => |vec| return ensureLayoutResolved(sema, .fromInterned(vec.child), src), + .opt_type => |child| return ensureLayoutResolved(sema, .fromInterned(child), src), + .error_union_type => |eu| return ensureLayoutResolved(sema, .fromInterned(eu.payload_type), src), .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| { - try ensureLayoutResolved(sema, .fromInterned(field_ty)); + try ensureLayoutResolved(sema, .fromInterned(field_ty), src); }, .struct_type, .union_type, .enum_type => { try sema.declareDependency(.{ .type_layout = ty.toIntern() }); + try sema.addReferenceEntry(null, src, .wrap(.{ .type_layout = ty.toIntern() })); if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { // TODO: better error message return sema.failWithOwnedErrorMsg(null, try sema.errMsg( @@ -89,13 +90,14 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { /// /// It is not necessary to call this function to query the values of comptime fields: those values /// are available from type *layout* resolution, see `ensureLayoutResolved`. -pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type) SemaError!void { +pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!void { const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; assert(ip.indexToKey(ty.toIntern()) == .struct_type); try sema.declareDependency(.{ .struct_defaults = ty.toIntern() }); + try sema.addReferenceEntry(null, src, .wrap(.{ .struct_defaults = ty.toIntern() })); if (zcu.analysis_in_progress.contains(.wrap(.{ .struct_defaults = ty.toIntern() }))) { // TODO: better error message return sema.failWithOwnedErrorMsg(null, try sema.errMsg( @@ -120,7 +122,8 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { assert(sema.owner.unwrap().type_layout == struct_ty.toIntern()); const struct_obj = ip.loadStructType(struct_ty.toIntern()); - const zir_index = struct_obj.zir_index.resolve(ip).?; + assert(struct_obj.want_layout); + const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail; var block: Block = .{ .parent = null, @@ -219,7 +222,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { const field_ty: Type = .fromInterned(field_ty_ip); assert(!field_ty.isGenericPoison()); const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); - try sema.ensureLayoutResolved(field_ty); + try sema.ensureLayoutResolved(field_ty, field_ty_src); if (field_ty.zigTypeTag(zcu) == .@"opaque") { return sema.failWithOwnedErrorMsg(&block, msg: { @@ -368,7 +371,7 @@ fn resolvePackedStructLayout( const field_ty: Type = .fromInterned(field_ty_ip); assert(!field_ty.isGenericPoison()); const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); - try sema.ensureLayoutResolved(field_ty); + try sema.ensureLayoutResolved(field_ty, field_ty_src); if (field_ty.zigTypeTag(zcu) == .@"opaque") { return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)}); @@ -458,17 +461,20 @@ pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern()); - try sema.ensureLayoutResolved(struct_ty); + try sema.ensureLayoutResolved(struct_ty, struct_ty.srcLoc(zcu)); const struct_obj = ip.loadStructType(struct_ty.toIntern()); + assert(struct_obj.want_defaults); + + if (struct_obj.is_reified) { + // `Sema.zirReifyStruct` has already populated the default field values *and* (by loading + // the default values from pointers) validated their types, so we have nothing to do. We + // don't even need to mark any dependencies. + return; + } try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); - // This logic isn't used for reified structs, because the signature of `@Struct` requires that - // default values are populated and correctly typed from the moment the struct type is interned - // (because `Sema.zirReifyStruct` had to dereference the default value from a pointer). - assert(!struct_obj.is_reified); - if (struct_obj.field_defaults.len == 0) { // The struct has no default field values, so the slice has been omitted. return; @@ -509,7 +515,7 @@ fn resolveStructDefaultsInner( const ip = &zcu.intern_pool; // We'll need to map the struct decl instruction to provide result types - const zir_index = struct_obj.zir_index.resolve(ip).?; + const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail; try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); const field_types = struct_obj.field_types.get(ip); @@ -555,7 +561,8 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { assert(sema.owner.unwrap().type_layout == union_ty.toIntern()); const union_obj = ip.loadUnionType(union_ty.toIntern()); - const zir_index = union_obj.zir_index.resolve(ip).?; + assert(union_obj.want_layout); + const zir_index = union_obj.zir_index.resolve(ip) orelse return error.AnalysisFail; var block: Block = .{ .parent = null, @@ -627,16 +634,11 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { .generation = zcu.generation, }); if (comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - try zcu.outdated.ensureUnusedCapacity(gpa, 1); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); - errdefer comptime unreachable; // because we don't remove the `outdated` entry - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); break :tag_ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; - try sema.ensureLayoutResolved(enum_tag_ty); + try sema.ensureLayoutResolved(enum_tag_ty, block.src(.container_arg)); const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern()); if (union_obj.is_reified) { @@ -731,7 +733,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { const field_ty: Type = .fromInterned(field_ty_ip); assert(!field_ty.isGenericPoison()); const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); - try sema.ensureLayoutResolved(field_ty); + try sema.ensureLayoutResolved(field_ty, field_ty_src); if (field_ty.zigTypeTag(zcu) == .@"opaque") { return sema.failWithOwnedErrorMsg(&block, msg: { const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); @@ -889,7 +891,7 @@ fn resolvePackedUnionLayout( const field_ty: Type = .fromInterned(field_ty_ip); assert(!field_ty.isGenericPoison()); const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); - try sema.ensureLayoutResolved(field_ty); + try sema.ensureLayoutResolved(field_ty, field_ty_src); if (field_ty.zigTypeTag(zcu) == .@"opaque") { return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); @@ -995,6 +997,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { assert(sema.owner.unwrap().type_layout == enum_ty.toIntern()); const enum_obj = ip.loadEnumType(enum_ty.toIntern()); + assert(enum_obj.want_layout); const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: { if (enum_obj.owner_union == .none) break :un null; @@ -1002,6 +1005,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { }; const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index; + const zir_index = tracked_inst.resolve(ip) orelse return error.AnalysisFail; var block: Block = .{ .parent = null, @@ -1040,7 +1044,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { // Generated tag enums for declared unions do not yet have field names populated. It is // our job to populate them now. try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); - const zir_union = sema.code.getUnionDecl(union_obj.zir_index.resolve(ip).?); + const zir_union = sema.code.getUnionDecl(zir_index); for (zir_union.field_names) |zir_field_name| { const name_slice = sema.code.nullTerminatedString(zir_field_name); const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); @@ -1065,7 +1069,7 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { } else { // Declared enums do not yet have field names populated. It is our job to populate them now. try sema.declareDependency(.{ .src_hash = enum_obj.zir_index.unwrap().? }); - const zir_enum = sema.code.getEnumDecl(enum_obj.zir_index.unwrap().?.resolve(ip).?); + const zir_enum = sema.code.getEnumDecl(zir_index); for (zir_enum.field_names) |zir_field_name| { const name_slice = sema.code.nullTerminatedString(zir_field_name); const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); @@ -1087,7 +1091,6 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { // Reification has no equivalent of 'union(enum(T))'. break :ty null; } - const zir_index = union_obj.zir_index.resolve(ip).?; const zir_union = sema.code.getUnionDecl(zir_index); if (zir_union.kind != .tagged_enum_explicit) { break :ty null; // int tag type will be inferred @@ -1102,7 +1105,6 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index); break :ty try sema.analyzeAsType(&block, tag_type_src, .enum_int_tag_type, type_ref); } else ty: { - const zir_index = enum_obj.zir_index.unwrap().?.resolve(ip).?; const zir_enum = sema.code.getEnumDecl(zir_index); const tag_type_body = zir_enum.tag_type_body orelse { break :ty null; // int tag type will be inferred @@ -1147,8 +1149,6 @@ pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void { // There may be old field values in here from a previous update. field_value_map.get(ip).clearRetainingCapacity(); - const zir_index = tracked_inst.resolve(ip).?; - // Map the enum (or union) decl instruction to provide the tag type as the result type try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(int_tag_ty.toIntern())); diff --git a/src/Type.zig b/src/Type.zig index ca94c09bf04fc00503dc414541a0861194cf4256..5b5839cf6f40e5953e182162289aa2e7b05ba96d 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -3044,7 +3044,20 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| { assertHasLayout(.fromInterned(field_ty), zcu); }, - .struct_type, .union_type, .enum_type => { + .struct_type => { + assert(zcu.intern_pool.loadStructType(ty.toIntern()).want_layout); + const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); + assert(!zcu.outdated.contains(unit)); + assert(!zcu.potentially_outdated.contains(unit)); + }, + .union_type => { + assert(zcu.intern_pool.loadUnionType(ty.toIntern()).want_layout); + const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); + assert(!zcu.outdated.contains(unit)); + assert(!zcu.potentially_outdated.contains(unit)); + }, + .enum_type => { + assert(zcu.intern_pool.loadEnumType(ty.toIntern()).want_layout); const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); assert(!zcu.outdated.contains(unit)); assert(!zcu.potentially_outdated.contains(unit)); diff --git a/src/Value.zig b/src/Value.zig index de7aacd1e1f2c84737acb243aa1565ac5fc0a94b..d513e5d07d9d07311a7d15b106e57795b54e92be 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -2149,7 +2149,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh const base_ptr = Value.fromInterned(field.base); const base_ptr_ty = base_ptr.typeOf(zcu); const agg_ty = base_ptr_ty.childType(zcu); - if (resolve_types) try opt_sema.?.ensureLayoutResolved(agg_ty); + if (resolve_types) try opt_sema.?.ensureLayoutResolved(agg_ty, .unneeded); // MLUGG TODO: unneeded is a hack const field_ty: Type, const field_align: InternPool.Alignment = switch (agg_ty.zigTypeTag(zcu)) { .@"struct", .@"union" => .{ agg_ty.fieldType(@intCast(field.index), zcu), agg_ty.resolvedFieldAlignment(@intCast(field.index), pt.zcu) }, .pointer => switch (field.index) { diff --git a/src/Zcu.zig b/src/Zcu.zig index 3b17bc1c0981d1e19f57db43412f4b309484faf4..aedbf7043c32aa83d8e7988d8bd3bb2304476632 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -266,9 +266,6 @@ outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty, /// it as outdated. retryable_failures: std.ArrayList(AnalUnit) = .empty, -func_body_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty, -nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, - /// These are the modules which we initially queue for analysis in `Compilation.update`. /// `resolveReferences` will use these as the root of its reachability traversal. analysis_roots_buffer: [5]*Package.Module, @@ -2814,9 +2811,6 @@ pub fn deinit(zcu: *Zcu) void { zcu.outdated_ready.deinit(gpa); zcu.retryable_failures.deinit(gpa); - zcu.func_body_analysis_queued.deinit(gpa); - zcu.nav_val_analysis_queued.deinit(gpa); - zcu.test_functions.deinit(gpa); for (zcu.global_assembly.values()) |s| { @@ -3179,8 +3173,6 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni /// recursive analysis (all of its previously-marked dependencies are already up-to-date), because /// recursive analysis can cause over-analysis on incremental updates. pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { - if (!zcu.comp.config.incremental) return null; - if (zcu.outdated_ready.count() > 0) { const unit = zcu.outdated_ready.keys()[0]; log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)}); @@ -3458,47 +3450,35 @@ pub fn mapOldZirToNew( /// The caller is responsible for ensuring the function decl itself is already /// analyzed, and for ensuring it can exist at runtime (see /// `Type.fnHasRuntimeBitsSema`). This function does *not* guarantee that the body -/// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`. -pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !void { +/// will be analyzed when it returns: for that, see `PerThread.ensureFuncBodyUpToDate`. +pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func: InternPool.Index) !void { + const comp = zcu.comp; + const gpa = comp.gpa; + const io = comp.io; const ip = &zcu.intern_pool; - - const func = zcu.funcInfo(func_index); - - assert(func.ty == func.uncoerced_ty); // analyze the body of the original function, not a coerced one - - if (zcu.func_body_analysis_queued.contains(func_index)) return; - - if (func.analysisUnordered(ip).is_analyzed) { - if (!zcu.outdated.contains(.wrap(.{ .func = func_index })) and - !zcu.potentially_outdated.contains(.wrap(.{ .func = func_index }))) - { - // This function has been analyzed before and is definitely up-to-date. - return; - } + assert(func == ip.unwrapCoercedFunc(func)); // analyze the body of the original function, not a coerced one + if (ip.setWantRuntimeFnAnalysis(io, func)) { + // This is the first reference to this function, so we must ensure it will be analyzed. + const unit: AnalUnit = .wrap(.{ .func = func }); + try zcu.outdated.putNoClobber(gpa, unit, 0); + try zcu.outdated_ready.putNoClobber(gpa, unit, {}); } - - try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1); - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .func = func_index }) }); - zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {}); } -pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void { +pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav: InternPool.Nav.Index) !void { + const comp = zcu.comp; + const gpa = comp.gpa; + const io = comp.io; const ip = &zcu.intern_pool; - - if (zcu.nav_val_analysis_queued.contains(nav_id)) return; - - if (ip.getNav(nav_id).status == .fully_resolved) { - if (!zcu.outdated.contains(.wrap(.{ .nav_val = nav_id })) and - !zcu.potentially_outdated.contains(.wrap(.{ .nav_val = nav_id }))) - { - // This `Nav` has been analyzed before and is definitely up-to-date. - return; - } + if (ip.setWantNavAnalysis(io, nav)) { + // This is the first reference to this function, so we must ensure it will be analyzed. + try zcu.outdated.ensureUnusedCapacity(gpa, 2); + try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); + zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), 0); + zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), 0); + zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), {}); + zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), {}); } - - try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1); - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .nav_val = nav_id }) }); - zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {}); } pub const ImportResult = struct { @@ -4035,37 +4015,6 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); - // If this type undergoes type resolution, the corresponding `AnalUnit`s are automatically referenced. - const has_layout: bool, const has_inits: bool = switch (ip.indexToKey(ty)) { - .struct_type => .{ true, true }, - .union_type => .{ true, false }, - .enum_type => .{ false, true }, - .opaque_type => .{ false, false }, - else => unreachable, - }; - if (has_layout) { - // this should only be referenced by the type - const unit: AnalUnit = .wrap(.{ .type_layout = ty }); - try units.putNoClobber(gpa, unit, referencer); - } - if (has_inits) { - // this should only be referenced by the type - const unit: AnalUnit = .wrap(.{ .struct_defaults = ty }); - try units.putNoClobber(gpa, unit, referencer); - } - - // If this is a union with a generated tag, its tag type is automatically referenced. - // We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location. - implicit_tag: { - const loaded_union = zcu.typeToUnion(.fromInterned(ty)) orelse break :implicit_tag; - const tag_ty = loaded_union.enum_tag_type; - if (tag_ty == .none) break :implicit_tag; - if (ip.indexToKey(tag_ty).enum_type != .generated_union_tag) break :implicit_tag; - const gop = try types.getOrPut(gpa, tag_ty); - if (gop.found_existing) break :implicit_tag; - gop.value_ptr.* = referencer; - } - // Queue any decls within this type which would be automatically analyzed. // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`. const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?; diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index d937367c4ac871c61e7bd285e9ddf04f7df175c7..00c911caf4e67e3a7dcf5691ebe7cf45d53ff002 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -719,20 +719,9 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca }); errdefer pt.destroyNamespace(new_namespace_index); try pt.scanNamespace(new_namespace_index, struct_decl.decls); - // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); - try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .struct_defaults = wip.index }) }); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - try zcu.outdated.ensureUnusedCapacity(gpa, 2); - try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); - errdefer comptime unreachable; // because we don't remove the `outdated` entries - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); - zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), 0); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); - zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = wip.index }), {}); - const file_root_type: Type = .fromInterned(wip.finish(ip, new_namespace_index)); zcu.setFileRootType(file_index, file_root_type.toIntern()); @@ -1075,11 +1064,12 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void assert(!zcu.analysis_in_progress.contains(anal_unit)); const was_outdated = zcu.outdated.swapRemove(anal_unit) or - zcu.potentially_outdated.swapRemove(anal_unit); + zcu.potentially_outdated.swapRemove(anal_unit) or + zcu.intern_pool.setWantTypeLayout(zcu.comp.io, ty.toIntern()); if (was_outdated) { _ = zcu.outdated_ready.swapRemove(anal_unit); - // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`. + // `was_outdated` is true in the initial update, so this isn't a `dev.check`. if (dev.env.supports(.incremental)) { zcu.deleteUnitExports(anal_unit); zcu.deleteUnitReferences(anal_unit); @@ -1182,16 +1172,13 @@ pub fn ensureStructDefaultsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!v assert(!zcu.analysis_in_progress.contains(anal_unit)); - // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's - // the only indicator as to whether or not analysis is required; when a struct/enum is - // first created, it's marked as outdated. - const was_outdated = zcu.outdated.swapRemove(anal_unit) or - zcu.potentially_outdated.swapRemove(anal_unit); + zcu.potentially_outdated.swapRemove(anal_unit) or + zcu.intern_pool.setWantStructDefaults(zcu.comp.io, ty.toIntern()); if (was_outdated) { _ = zcu.outdated_ready.swapRemove(anal_unit); - // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`. + // `was_outdated` is true in the initial update, so this isn't a `dev.check`. if (dev.env.supports(.incremental)) { zcu.deleteUnitExports(anal_unit); zcu.deleteUnitReferences(anal_unit); @@ -1279,8 +1266,6 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu const gpa = zcu.gpa; const ip = &zcu.intern_pool; - _ = zcu.nav_val_analysis_queued.swapRemove(nav_id); - const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id }); const nav = ip.getNav(nav_id); @@ -1288,6 +1273,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu assert(!zcu.analysis_in_progress.contains(anal_unit)); + try zcu.ensureNavValAnalysisQueued(nav_id); + // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the // status is `.unresolved`, which indicates that the value is outdated because it has *never* // been analyzed so far. @@ -1317,10 +1304,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu } else { // We can trust the current information about this unit. if (prev_failed) return error.AnalysisFail; - switch (nav.status) { - .unresolved, .type_resolved => {}, - .fully_resolved => return, - } + assert(nav.status == .fully_resolved); + return; } if (zcu.comp.debugIncremental()) { @@ -1488,9 +1473,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr const maybe_ty: ?Type = if (zir_decl.type_body != null) ty: { // Since we have a type body, the type is resolved separately! - // Of course, we need to make sure we depend on it properly. - try sema.declareDependency(.{ .nav_ty = nav_id }); - try pt.ensureNavTypeUpToDate(nav_id); + try sema.ensureNavResolved(&block, init_src, nav_id, .type); break :ty .fromInterned(ip.getNav(nav_id).typeOf(ip)); } else null; @@ -1602,7 +1585,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type, // this resolves the type `type` (which needs no resolution), not the struct itself. - try sema.ensureLayoutResolved(nav_ty); + try sema.ensureLayoutResolved(nav_ty, init_src); const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) { .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen @@ -1692,6 +1675,8 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc assert(!zcu.analysis_in_progress.contains(anal_unit)); + try zcu.ensureNavValAnalysisQueued(nav_id); + const type_resolved_by_value: bool = from_val: { const analysis = nav.analysis orelse break :from_val false; const inst_resolved = analysis.zir_index.resolveFull(ip) orelse break :from_val false; @@ -1733,10 +1718,8 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc } else { // We can trust the current information about this unit. if (prev_failed) return error.AnalysisFail; - switch (nav.status) { - .unresolved => {}, - .type_resolved, .fully_resolved => return, - } + assert(nav.status != .unresolved); + return; } if (zcu.comp.debugIncremental()) { @@ -1869,7 +1852,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr break :ty .fromInterned(type_ref.toInterned().?); }; - try sema.ensureLayoutResolved(resolved_ty); + try sema.ensureLayoutResolved(resolved_ty, ty_src); // In the case where the type is specified, this function is also responsible for resolving // the pointer modifiers, i.e. alignment, linksection, addrspace. @@ -1929,8 +1912,6 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z const gpa = zcu.gpa; const ip = &zcu.intern_pool; - _ = zcu.func_body_analysis_queued.swapRemove(func_index); - const anal_unit: AnalUnit = .wrap(.{ .func = func_index }); log.debug("ensureFuncBodyUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); @@ -1942,7 +1923,8 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z assert(func.ty == func.uncoerced_ty); // analyze the body of the original function, not a coerced one const was_outdated = zcu.outdated.swapRemove(anal_unit) or - zcu.potentially_outdated.swapRemove(anal_unit); + zcu.potentially_outdated.swapRemove(anal_unit) or + ip.setWantRuntimeFnAnalysis(zcu.comp.io, func_index); const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit); @@ -1958,10 +1940,8 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); } else { // We can trust the current information about this function. - if (prev_failed) { - return error.AnalysisFail; - } - if (func.analysisUnordered(ip).is_analyzed) return; + if (prev_failed) return error.AnalysisFail; + return; } if (zcu.comp.debugIncremental()) { @@ -3026,7 +3006,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {}); defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); - func.setAnalyzed(ip, io); if (func.analysisUnordered(ip).inferred_error_set) { func.setResolvedErrorSet(ip, io, .none); } @@ -3144,7 +3123,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]); runtime_param_index += 1; - try sema.ensureLayoutResolved(param_ty); + try sema.ensureLayoutResolved(param_ty, inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) })); if (try param_ty.onePossibleValue(pt)) |opv| { gop.value_ptr.* = .fromValue(opv); continue; @@ -3161,7 +3140,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem }); } - try sema.ensureLayoutResolved(sema.fn_ret_ty); + try sema.ensureLayoutResolved(sema.fn_ret_ty, inner_block.src(.{ .node_offset_fn_type_ret_ty = .zero })); const last_arg_index = inner_block.instructions.items.len;