| author | |
| committer | |
| log | 84c2ebd6c6b16752d8d030d5904d0a525283cbf5 |
| tree | 442234d4a737c6fbcf4f165ac18fa2a31cef9ac1 |
| parent | 65cbdefe4d923efd8fd2cfb555cc02a52c5635fc |
Another big commit, sorry! This commit makes all fixes necessary for
incremental updates of the compiler itself (specifically, adding a
breakpoint to `zirCompileLog`) to succeed, at least on the frontend.
The biggest change here is a reform to how types are handled. It works
like this:
* When a type is first created in `zirStructDecl` etc, its namespace is
scanned. If the type requires resolution, an `interned` dependency is
declared for the containing `AnalUnit`.
* `zirThis` also declared an `interned` dependency for its `AnalUnit` on
the namespace's owner type.
* If the type's namespace changes, the surrounding source declaration
changes hash, so `zirStructDecl` etc will be hit again. We check
whether the namespace has been scanned this generation, and re-scan it
if not.
* Namespace lookups also check whether the namespace in question
requires a re-scan based on the generation. This is because there's no
guarantee that the `zirStructDecl` is re-analyzed before the namespace
lookup is re-analyzed.
* If a type's structure (essentially its fields) change, then the type's
`Cau` is considered outdated. When the type is re-analyzed due to
being outdated, or the `zirStructDecl` is re-analyzed by being
transitively outdated, or a corresponding `zirThis` is re-analyzed by
being transitively outdated, the struct type is recreated at a new
`InternPool` index. The namespace's owner is updated (but not
re-scanned, since that is handled by the mechanisms above), and the
old type, while remaining a valid `Index`, is removed from the map
metadata so it will never be found by lookups. `zirStructDecl` and
`zirThis` store an `interned` dependency on the *new* type.5 files changed, 949 insertions(+), 333 deletions(-)
src/Compilation.zig+2| ... | @@ -3569,6 +3569,8 @@ pub fn performAllTheWork( | ... | @@ -3569,6 +3569,8 @@ pub fn performAllTheWork( |
| 3569 | mod.sema_prog_node = std.Progress.Node.none; | 3569 | mod.sema_prog_node = std.Progress.Node.none; |
| 3570 | mod.codegen_prog_node.end(); | 3570 | mod.codegen_prog_node.end(); |
| 3571 | mod.codegen_prog_node = std.Progress.Node.none; | 3571 | mod.codegen_prog_node = std.Progress.Node.none; |
| 3572 | |||
| 3573 | mod.generation += 1; | ||
| 3572 | }; | 3574 | }; |
| 3573 | try comp.performAllTheWorkInner(main_progress_node); | 3575 | try comp.performAllTheWorkInner(main_progress_node); |
| 3574 | if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error; | 3576 | if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error; |
src/InternPool.zig+88-25| ... | @@ -684,10 +684,6 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI | ... | @@ -684,10 +684,6 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI |
| 684 | .ip = ip, | 684 | .ip = ip, |
| 685 | .next_entry = .none, | 685 | .next_entry = .none, |
| 686 | }; | 686 | }; |
| 687 | if (ip.dep_entries.items[@intFromEnum(first_entry)].depender == .none) return .{ | ||
| 688 | .ip = ip, | ||
| 689 | .next_entry = .none, | ||
| 690 | }; | ||
| 691 | return .{ | 687 | return .{ |
| 692 | .ip = ip, | 688 | .ip = ip, |
| 693 | .next_entry = first_entry.toOptional(), | 689 | .next_entry = first_entry.toOptional(), |
| ... | @@ -724,7 +720,6 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend | ... | @@ -724,7 +720,6 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 724 | 720 | ||
| 725 | if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) { | 721 | if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) { |
| 726 | // Dummy entry, so we can reuse it rather than allocating a new one! | 722 | // Dummy entry, so we can reuse it rather than allocating a new one! |
| 727 | ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].next = .none; | ||
| 728 | break :new_index gop.value_ptr.*; | 723 | break :new_index gop.value_ptr.*; |
| 729 | } | 724 | } |
| 730 | 725 | ||
| ... | @@ -732,7 +727,12 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend | ... | @@ -732,7 +727,12 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 732 | const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: { | 727 | const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: { |
| 733 | break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] }; | 728 | break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] }; |
| 734 | } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() }; | 729 | } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() }; |
| 735 | ptr.next = if (gop.found_existing) gop.value_ptr.*.toOptional() else .none; | 730 | if (gop.found_existing) { |
| 731 | ptr.next = gop.value_ptr.*.toOptional(); | ||
| 732 | ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].prev = new_index.toOptional(); | ||
| 733 | } else { | ||
| 734 | ptr.next = .none; | ||
| 735 | } | ||
| 736 | gop.value_ptr.* = new_index; | 736 | gop.value_ptr.* = new_index; |
| 737 | break :new_index new_index; | 737 | break :new_index new_index; |
| 738 | }, | 738 | }, |
| ... | @@ -754,10 +754,9 @@ pub const NamespaceNameKey = struct { | ... | @@ -754,10 +754,9 @@ pub const NamespaceNameKey = struct { |
| 754 | }; | 754 | }; |
| 755 | 755 | ||
| 756 | pub const DepEntry = extern struct { | 756 | pub const DepEntry = extern struct { |
| 757 | /// If null, this is a dummy entry - all other fields are `undefined`. It is | 757 | /// If null, this is a dummy entry. `next_dependee` is undefined. This is the first |
| 758 | /// the first and only entry in one of `intern_pool.*_deps`, and does not | 758 | /// entry in one of `*_deps`, and does not appear in any list by `first_dependency`, |
| 759 | /// appear in any list by `first_dependency`, but is not in | 759 | /// but is not in `free_dep_entries` since `*_deps` stores a reference to it. |
| 760 | /// `free_dep_entries` since `*_deps` stores a reference to it. | ||
| 761 | depender: AnalUnit.Optional, | 760 | depender: AnalUnit.Optional, |
| 762 | /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee. | 761 | /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee. |
| 763 | /// Used to iterate all dependers for a given dependee during an update. | 762 | /// Used to iterate all dependers for a given dependee during an update. |
| ... | @@ -2689,7 +2688,12 @@ pub const Key = union(enum) { | ... | @@ -2689,7 +2688,12 @@ pub const Key = union(enum) { |
| 2689 | 2688 | ||
| 2690 | .variable => |a_info| { | 2689 | .variable => |a_info| { |
| 2691 | const b_info = b.variable; | 2690 | const b_info = b.variable; |
| 2692 | return a_info.owner_nav == b_info.owner_nav; | 2691 | return a_info.owner_nav == b_info.owner_nav and |
| 2692 | a_info.ty == b_info.ty and | ||
| 2693 | a_info.init == b_info.init and | ||
| 2694 | a_info.lib_name == b_info.lib_name and | ||
| 2695 | a_info.is_threadlocal == b_info.is_threadlocal and | ||
| 2696 | a_info.is_weak_linkage == b_info.is_weak_linkage; | ||
| 2693 | }, | 2697 | }, |
| 2694 | .@"extern" => |a_info| { | 2698 | .@"extern" => |a_info| { |
| 2695 | const b_info = b.@"extern"; | 2699 | const b_info = b.@"extern"; |
| ... | @@ -8016,6 +8020,10 @@ pub const UnionTypeInit = struct { | ... | @@ -8016,6 +8020,10 @@ pub const UnionTypeInit = struct { |
| 8016 | zir_index: TrackedInst.Index, | 8020 | zir_index: TrackedInst.Index, |
| 8017 | captures: []const CaptureValue, | 8021 | captures: []const CaptureValue, |
| 8018 | }, | 8022 | }, |
| 8023 | declared_owned_captures: struct { | ||
| 8024 | zir_index: TrackedInst.Index, | ||
| 8025 | captures: CaptureValue.Slice, | ||
| 8026 | }, | ||
| 8019 | reified: struct { | 8027 | reified: struct { |
| 8020 | zir_index: TrackedInst.Index, | 8028 | zir_index: TrackedInst.Index, |
| 8021 | type_hash: u64, | 8029 | type_hash: u64, |
| ... | @@ -8037,6 +8045,10 @@ pub fn getUnionType( | ... | @@ -8037,6 +8045,10 @@ pub fn getUnionType( |
| 8037 | .zir_index = d.zir_index, | 8045 | .zir_index = d.zir_index, |
| 8038 | .captures = .{ .external = d.captures }, | 8046 | .captures = .{ .external = d.captures }, |
| 8039 | } }, | 8047 | } }, |
| 8048 | .declared_owned_captures => |d| .{ .declared = .{ | ||
| 8049 | .zir_index = d.zir_index, | ||
| 8050 | .captures = .{ .owned = d.captures }, | ||
| 8051 | } }, | ||
| 8040 | .reified => |r| .{ .reified = .{ | 8052 | .reified => |r| .{ .reified = .{ |
| 8041 | .zir_index = r.zir_index, | 8053 | .zir_index = r.zir_index, |
| 8042 | .type_hash = r.type_hash, | 8054 | .type_hash = r.type_hash, |
| ... | @@ -8060,7 +8072,7 @@ pub fn getUnionType( | ... | @@ -8060,7 +8072,7 @@ pub fn getUnionType( |
| 8060 | // TODO: fmt bug | 8072 | // TODO: fmt bug |
| 8061 | // zig fmt: off | 8073 | // zig fmt: off |
| 8062 | switch (ini.key) { | 8074 | switch (ini.key) { |
| 8063 | .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | 8075 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, |
| 8064 | .reified => 2, // type_hash: PackedU64 | 8076 | .reified => 2, // type_hash: PackedU64 |
| 8065 | } + | 8077 | } + |
| 8066 | // zig fmt: on | 8078 | // zig fmt: on |
| ... | @@ -8069,7 +8081,10 @@ pub fn getUnionType( | ... | @@ -8069,7 +8081,10 @@ pub fn getUnionType( |
| 8069 | 8081 | ||
| 8070 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ | 8082 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ |
| 8071 | .flags = .{ | 8083 | .flags = .{ |
| 8072 | .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0, | 8084 | .any_captures = switch (ini.key) { |
| 8085 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | ||
| 8086 | .reified => false, | ||
| 8087 | }, | ||
| 8073 | .runtime_tag = ini.flags.runtime_tag, | 8088 | .runtime_tag = ini.flags.runtime_tag, |
| 8074 | .any_aligned_fields = ini.flags.any_aligned_fields, | 8089 | .any_aligned_fields = ini.flags.any_aligned_fields, |
| 8075 | .layout = ini.flags.layout, | 8090 | .layout = ini.flags.layout, |
| ... | @@ -8078,7 +8093,10 @@ pub fn getUnionType( | ... | @@ -8078,7 +8093,10 @@ pub fn getUnionType( |
| 8078 | .assumed_runtime_bits = ini.flags.assumed_runtime_bits, | 8093 | .assumed_runtime_bits = ini.flags.assumed_runtime_bits, |
| 8079 | .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned, | 8094 | .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned, |
| 8080 | .alignment = ini.flags.alignment, | 8095 | .alignment = ini.flags.alignment, |
| 8081 | .is_reified = ini.key == .reified, | 8096 | .is_reified = switch (ini.key) { |
| 8097 | .declared, .declared_owned_captures => false, | ||
| 8098 | .reified => true, | ||
| 8099 | }, | ||
| 8082 | }, | 8100 | }, |
| 8083 | .fields_len = ini.fields_len, | 8101 | .fields_len = ini.fields_len, |
| 8084 | .size = std.math.maxInt(u32), | 8102 | .size = std.math.maxInt(u32), |
| ... | @@ -8102,6 +8120,10 @@ pub fn getUnionType( | ... | @@ -8102,6 +8120,10 @@ pub fn getUnionType( |
| 8102 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | 8120 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 8103 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | 8121 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 8104 | }, | 8122 | }, |
| 8123 | .declared_owned_captures => |d| if (d.captures.len != 0) { | ||
| 8124 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | ||
| 8125 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | ||
| 8126 | }, | ||
| 8105 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | 8127 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), |
| 8106 | } | 8128 | } |
| 8107 | 8129 | ||
| ... | @@ -8199,6 +8221,10 @@ pub const StructTypeInit = struct { | ... | @@ -8199,6 +8221,10 @@ pub const StructTypeInit = struct { |
| 8199 | zir_index: TrackedInst.Index, | 8221 | zir_index: TrackedInst.Index, |
| 8200 | captures: []const CaptureValue, | 8222 | captures: []const CaptureValue, |
| 8201 | }, | 8223 | }, |
| 8224 | declared_owned_captures: struct { | ||
| 8225 | zir_index: TrackedInst.Index, | ||
| 8226 | captures: CaptureValue.Slice, | ||
| 8227 | }, | ||
| 8202 | reified: struct { | 8228 | reified: struct { |
| 8203 | zir_index: TrackedInst.Index, | 8229 | zir_index: TrackedInst.Index, |
| 8204 | type_hash: u64, | 8230 | type_hash: u64, |
| ... | @@ -8220,6 +8246,10 @@ pub fn getStructType( | ... | @@ -8220,6 +8246,10 @@ pub fn getStructType( |
| 8220 | .zir_index = d.zir_index, | 8246 | .zir_index = d.zir_index, |
| 8221 | .captures = .{ .external = d.captures }, | 8247 | .captures = .{ .external = d.captures }, |
| 8222 | } }, | 8248 | } }, |
| 8249 | .declared_owned_captures => |d| .{ .declared = .{ | ||
| 8250 | .zir_index = d.zir_index, | ||
| 8251 | .captures = .{ .owned = d.captures }, | ||
| 8252 | } }, | ||
| 8223 | .reified => |r| .{ .reified = .{ | 8253 | .reified => |r| .{ .reified = .{ |
| 8224 | .zir_index = r.zir_index, | 8254 | .zir_index = r.zir_index, |
| 8225 | .type_hash = r.type_hash, | 8255 | .type_hash = r.type_hash, |
| ... | @@ -8251,7 +8281,7 @@ pub fn getStructType( | ... | @@ -8251,7 +8281,7 @@ pub fn getStructType( |
| 8251 | // TODO: fmt bug | 8281 | // TODO: fmt bug |
| 8252 | // zig fmt: off | 8282 | // zig fmt: off |
| 8253 | switch (ini.key) { | 8283 | switch (ini.key) { |
| 8254 | .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | 8284 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, |
| 8255 | .reified => 2, // type_hash: PackedU64 | 8285 | .reified => 2, // type_hash: PackedU64 |
| 8256 | } + | 8286 | } + |
| 8257 | // zig fmt: on | 8287 | // zig fmt: on |
| ... | @@ -8267,10 +8297,16 @@ pub fn getStructType( | ... | @@ -8267,10 +8297,16 @@ pub fn getStructType( |
| 8267 | .backing_int_ty = .none, | 8297 | .backing_int_ty = .none, |
| 8268 | .names_map = names_map, | 8298 | .names_map = names_map, |
| 8269 | .flags = .{ | 8299 | .flags = .{ |
| 8270 | .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0, | 8300 | .any_captures = switch (ini.key) { |
| 8301 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | ||
| 8302 | .reified => false, | ||
| 8303 | }, | ||
| 8271 | .field_inits_wip = false, | 8304 | .field_inits_wip = false, |
| 8272 | .inits_resolved = ini.inits_resolved, | 8305 | .inits_resolved = ini.inits_resolved, |
| 8273 | .is_reified = ini.key == .reified, | 8306 | .is_reified = switch (ini.key) { |
| 8307 | .declared, .declared_owned_captures => false, | ||
| 8308 | .reified => true, | ||
| 8309 | }, | ||
| 8274 | }, | 8310 | }, |
| 8275 | }); | 8311 | }); |
| 8276 | try items.append(.{ | 8312 | try items.append(.{ |
| ... | @@ -8282,6 +8318,10 @@ pub fn getStructType( | ... | @@ -8282,6 +8318,10 @@ pub fn getStructType( |
| 8282 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | 8318 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 8283 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | 8319 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 8284 | }, | 8320 | }, |
| 8321 | .declared_owned_captures => |d| if (d.captures.len != 0) { | ||
| 8322 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | ||
| 8323 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | ||
| 8324 | }, | ||
| 8285 | .reified => |r| { | 8325 | .reified => |r| { |
| 8286 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); | 8326 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); |
| 8287 | }, | 8327 | }, |
| ... | @@ -8309,7 +8349,7 @@ pub fn getStructType( | ... | @@ -8309,7 +8349,7 @@ pub fn getStructType( |
| 8309 | // TODO: fmt bug | 8349 | // TODO: fmt bug |
| 8310 | // zig fmt: off | 8350 | // zig fmt: off |
| 8311 | switch (ini.key) { | 8351 | switch (ini.key) { |
| 8312 | .declared => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | 8352 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, |
| 8313 | .reified => 2, // type_hash: PackedU64 | 8353 | .reified => 2, // type_hash: PackedU64 |
| 8314 | } + | 8354 | } + |
| 8315 | // zig fmt: on | 8355 | // zig fmt: on |
| ... | @@ -8324,7 +8364,10 @@ pub fn getStructType( | ... | @@ -8324,7 +8364,10 @@ pub fn getStructType( |
| 8324 | .fields_len = ini.fields_len, | 8364 | .fields_len = ini.fields_len, |
| 8325 | .size = std.math.maxInt(u32), | 8365 | .size = std.math.maxInt(u32), |
| 8326 | .flags = .{ | 8366 | .flags = .{ |
| 8327 | .any_captures = ini.key == .declared and ini.key.declared.captures.len != 0, | 8367 | .any_captures = switch (ini.key) { |
| 8368 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | ||
| 8369 | .reified => false, | ||
| 8370 | }, | ||
| 8328 | .is_extern = is_extern, | 8371 | .is_extern = is_extern, |
| 8329 | .known_non_opv = ini.known_non_opv, | 8372 | .known_non_opv = ini.known_non_opv, |
| 8330 | .requires_comptime = ini.requires_comptime, | 8373 | .requires_comptime = ini.requires_comptime, |
| ... | @@ -8342,7 +8385,10 @@ pub fn getStructType( | ... | @@ -8342,7 +8385,10 @@ pub fn getStructType( |
| 8342 | .field_inits_wip = false, | 8385 | .field_inits_wip = false, |
| 8343 | .inits_resolved = ini.inits_resolved, | 8386 | .inits_resolved = ini.inits_resolved, |
| 8344 | .fully_resolved = false, | 8387 | .fully_resolved = false, |
| 8345 | .is_reified = ini.key == .reified, | 8388 | .is_reified = switch (ini.key) { |
| 8389 | .declared, .declared_owned_captures => false, | ||
| 8390 | .reified => true, | ||
| 8391 | }, | ||
| 8346 | }, | 8392 | }, |
| 8347 | }); | 8393 | }); |
| 8348 | try items.append(.{ | 8394 | try items.append(.{ |
| ... | @@ -8354,6 +8400,10 @@ pub fn getStructType( | ... | @@ -8354,6 +8400,10 @@ pub fn getStructType( |
| 8354 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | 8400 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 8355 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | 8401 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 8356 | }, | 8402 | }, |
| 8403 | .declared_owned_captures => |d| if (d.captures.len != 0) { | ||
| 8404 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | ||
| 8405 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | ||
| 8406 | }, | ||
| 8357 | .reified => |r| { | 8407 | .reified => |r| { |
| 8358 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); | 8408 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); |
| 8359 | }, | 8409 | }, |
| ... | @@ -9157,6 +9207,10 @@ pub const EnumTypeInit = struct { | ... | @@ -9157,6 +9207,10 @@ pub const EnumTypeInit = struct { |
| 9157 | zir_index: TrackedInst.Index, | 9207 | zir_index: TrackedInst.Index, |
| 9158 | captures: []const CaptureValue, | 9208 | captures: []const CaptureValue, |
| 9159 | }, | 9209 | }, |
| 9210 | declared_owned_captures: struct { | ||
| 9211 | zir_index: TrackedInst.Index, | ||
| 9212 | captures: CaptureValue.Slice, | ||
| 9213 | }, | ||
| 9160 | reified: struct { | 9214 | reified: struct { |
| 9161 | zir_index: TrackedInst.Index, | 9215 | zir_index: TrackedInst.Index, |
| 9162 | type_hash: u64, | 9216 | type_hash: u64, |
| ... | @@ -9261,6 +9315,10 @@ pub fn getEnumType( | ... | @@ -9261,6 +9315,10 @@ pub fn getEnumType( |
| 9261 | .zir_index = d.zir_index, | 9315 | .zir_index = d.zir_index, |
| 9262 | .captures = .{ .external = d.captures }, | 9316 | .captures = .{ .external = d.captures }, |
| 9263 | } }, | 9317 | } }, |
| 9318 | .declared_owned_captures => |d| .{ .declared = .{ | ||
| 9319 | .zir_index = d.zir_index, | ||
| 9320 | .captures = .{ .owned = d.captures }, | ||
| 9321 | } }, | ||
| 9264 | .reified => |r| .{ .reified = .{ | 9322 | .reified => |r| .{ .reified = .{ |
| 9265 | .zir_index = r.zir_index, | 9323 | .zir_index = r.zir_index, |
| 9266 | .type_hash = r.type_hash, | 9324 | .type_hash = r.type_hash, |
| ... | @@ -9288,7 +9346,7 @@ pub fn getEnumType( | ... | @@ -9288,7 +9346,7 @@ pub fn getEnumType( |
| 9288 | // TODO: fmt bug | 9346 | // TODO: fmt bug |
| 9289 | // zig fmt: off | 9347 | // zig fmt: off |
| 9290 | switch (ini.key) { | 9348 | switch (ini.key) { |
| 9291 | .declared => |d| d.captures.len, | 9349 | inline .declared, .declared_owned_captures => |d| d.captures.len, |
| 9292 | .reified => 2, // type_hash: PackedU64 | 9350 | .reified => 2, // type_hash: PackedU64 |
| 9293 | } + | 9351 | } + |
| 9294 | // zig fmt: on | 9352 | // zig fmt: on |
| ... | @@ -9298,7 +9356,7 @@ pub fn getEnumType( | ... | @@ -9298,7 +9356,7 @@ pub fn getEnumType( |
| 9298 | const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ | 9356 | const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ |
| 9299 | .name = undefined, // set by `prepare` | 9357 | .name = undefined, // set by `prepare` |
| 9300 | .captures_len = switch (ini.key) { | 9358 | .captures_len = switch (ini.key) { |
| 9301 | .declared => |d| @intCast(d.captures.len), | 9359 | inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), |
| 9302 | .reified => std.math.maxInt(u32), | 9360 | .reified => std.math.maxInt(u32), |
| 9303 | }, | 9361 | }, |
| 9304 | .namespace = undefined, // set by `prepare` | 9362 | .namespace = undefined, // set by `prepare` |
| ... | @@ -9317,6 +9375,7 @@ pub fn getEnumType( | ... | @@ -9317,6 +9375,7 @@ pub fn getEnumType( |
| 9317 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | 9375 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` |
| 9318 | switch (ini.key) { | 9376 | switch (ini.key) { |
| 9319 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | 9377 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9378 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), | ||
| 9320 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | 9379 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), |
| 9321 | } | 9380 | } |
| 9322 | const names_start = extra.mutate.len; | 9381 | const names_start = extra.mutate.len; |
| ... | @@ -9347,7 +9406,7 @@ pub fn getEnumType( | ... | @@ -9347,7 +9406,7 @@ pub fn getEnumType( |
| 9347 | // TODO: fmt bug | 9406 | // TODO: fmt bug |
| 9348 | // zig fmt: off | 9407 | // zig fmt: off |
| 9349 | switch (ini.key) { | 9408 | switch (ini.key) { |
| 9350 | .declared => |d| d.captures.len, | 9409 | inline .declared, .declared_owned_captures => |d| d.captures.len, |
| 9351 | .reified => 2, // type_hash: PackedU64 | 9410 | .reified => 2, // type_hash: PackedU64 |
| 9352 | } + | 9411 | } + |
| 9353 | // zig fmt: on | 9412 | // zig fmt: on |
| ... | @@ -9358,7 +9417,7 @@ pub fn getEnumType( | ... | @@ -9358,7 +9417,7 @@ pub fn getEnumType( |
| 9358 | const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{ | 9417 | const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{ |
| 9359 | .name = undefined, // set by `prepare` | 9418 | .name = undefined, // set by `prepare` |
| 9360 | .captures_len = switch (ini.key) { | 9419 | .captures_len = switch (ini.key) { |
| 9361 | .declared => |d| @intCast(d.captures.len), | 9420 | inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), |
| 9362 | .reified => std.math.maxInt(u32), | 9421 | .reified => std.math.maxInt(u32), |
| 9363 | }, | 9422 | }, |
| 9364 | .namespace = undefined, // set by `prepare` | 9423 | .namespace = undefined, // set by `prepare` |
| ... | @@ -9382,6 +9441,7 @@ pub fn getEnumType( | ... | @@ -9382,6 +9441,7 @@ pub fn getEnumType( |
| 9382 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | 9441 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` |
| 9383 | switch (ini.key) { | 9442 | switch (ini.key) { |
| 9384 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | 9443 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9444 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), | ||
| 9385 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | 9445 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), |
| 9386 | } | 9446 | } |
| 9387 | const names_start = extra.mutate.len; | 9447 | const names_start = extra.mutate.len; |
| ... | @@ -9445,10 +9505,12 @@ pub fn getGeneratedTagEnumType( | ... | @@ -9445,10 +9505,12 @@ pub fn getGeneratedTagEnumType( |
| 9445 | .tid = tid, | 9505 | .tid = tid, |
| 9446 | .index = items.mutate.len, | 9506 | .index = items.mutate.len, |
| 9447 | }, ip); | 9507 | }, ip); |
| 9508 | const parent_namespace = ip.namespacePtr(ini.parent_namespace); | ||
| 9448 | const namespace = try ip.createNamespace(gpa, tid, .{ | 9509 | const namespace = try ip.createNamespace(gpa, tid, .{ |
| 9449 | .parent = ini.parent_namespace.toOptional(), | 9510 | .parent = ini.parent_namespace.toOptional(), |
| 9450 | .owner_type = enum_index, | 9511 | .owner_type = enum_index, |
| 9451 | .file_scope = ip.namespacePtr(ini.parent_namespace).file_scope, | 9512 | .file_scope = parent_namespace.file_scope, |
| 9513 | .generation = parent_namespace.generation, | ||
| 9452 | }); | 9514 | }); |
| 9453 | errdefer ip.destroyNamespace(tid, namespace); | 9515 | errdefer ip.destroyNamespace(tid, namespace); |
| 9454 | 9516 | ||
| ... | @@ -11044,6 +11106,7 @@ pub fn destroyNamespace( | ... | @@ -11044,6 +11106,7 @@ pub fn destroyNamespace( |
| 11044 | .parent = undefined, | 11106 | .parent = undefined, |
| 11045 | .file_scope = undefined, | 11107 | .file_scope = undefined, |
| 11046 | .owner_type = undefined, | 11108 | .owner_type = undefined, |
| 11109 | .generation = undefined, | ||
| 11047 | }; | 11110 | }; |
| 11048 | @field(namespace, Local.namespace_next_free_field) = | 11111 | @field(namespace, Local.namespace_next_free_field) = |
| 11049 | @enumFromInt(local.mutate.namespaces.free_list); | 11112 | @enumFromInt(local.mutate.namespaces.free_list); |
src/Sema.zig+254-198| ... | @@ -2723,32 +2723,6 @@ fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) { | ... | @@ -2723,32 +2723,6 @@ fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) { |
| 2723 | return new; | 2723 | return new; |
| 2724 | } | 2724 | } |
| 2725 | 2725 | ||
| 2726 | /// Given a type just looked up in the `InternPool`, check whether it is | ||
| 2727 | /// considered outdated on this update. If so, returns `true`, and the | ||
| 2728 | /// caller must replace the outdated type with a fresh one. | ||
| 2729 | fn checkOutdatedType(sema: *Sema, ty: InternPool.Index) !bool { | ||
| 2730 | const pt = sema.pt; | ||
| 2731 | const zcu = pt.zcu; | ||
| 2732 | const ip = &zcu.intern_pool; | ||
| 2733 | |||
| 2734 | if (!zcu.comp.incremental) return false; | ||
| 2735 | |||
| 2736 | const cau_index = switch (ip.indexToKey(ty)) { | ||
| 2737 | .struct_type => ip.loadStructType(ty).cau.unwrap().?, | ||
| 2738 | .union_type => ip.loadUnionType(ty).cau, | ||
| 2739 | .enum_type => ip.loadEnumType(ty).cau.unwrap().?, | ||
| 2740 | else => unreachable, | ||
| 2741 | }; | ||
| 2742 | const cau_unit = AnalUnit.wrap(.{ .cau = cau_index }); | ||
| 2743 | const was_outdated = zcu.outdated.swapRemove(cau_unit) or | ||
| 2744 | zcu.potentially_outdated.swapRemove(cau_unit); | ||
| 2745 | if (!was_outdated) return false; | ||
| 2746 | _ = zcu.outdated_ready.swapRemove(cau_unit); | ||
| 2747 | zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, cau_unit); | ||
| 2748 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | ||
| 2749 | return true; | ||
| 2750 | } | ||
| 2751 | |||
| 2752 | fn zirStructDecl( | 2726 | fn zirStructDecl( |
| 2753 | sema: *Sema, | 2727 | sema: *Sema, |
| 2754 | block: *Block, | 2728 | block: *Block, |
| ... | @@ -2815,13 +2789,16 @@ fn zirStructDecl( | ... | @@ -2815,13 +2789,16 @@ fn zirStructDecl( |
| 2815 | } }, | 2789 | } }, |
| 2816 | }; | 2790 | }; |
| 2817 | const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) { | 2791 | const wip_ty = sema.wrapWipTy(switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) { |
| 2818 | .existing => |ty| wip: { | 2792 | .existing => |ty| { |
| 2819 | if (!try sema.checkOutdatedType(ty)) { | 2793 | const new_ty = try pt.ensureTypeUpToDate(ty, false); |
| 2820 | try sema.declareDependency(.{ .interned = ty }); | 2794 | |
| 2821 | try sema.addTypeReferenceEntry(src, ty); | 2795 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 2822 | return Air.internedToRef(ty); | 2796 | // up on e.g. changed comptime decls. |
| 2823 | } | 2797 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod)); |
| 2824 | break :wip (try ip.getStructType(gpa, pt.tid, struct_init, true)).wip; | 2798 | |
| 2799 | try sema.declareDependency(.{ .interned = new_ty }); | ||
| 2800 | try sema.addTypeReferenceEntry(src, new_ty); | ||
| 2801 | return Air.internedToRef(new_ty); | ||
| 2825 | }, | 2802 | }, |
| 2826 | .wip => |wip| wip, | 2803 | .wip => |wip| wip, |
| 2827 | }); | 2804 | }); |
| ... | @@ -2839,6 +2816,7 @@ fn zirStructDecl( | ... | @@ -2839,6 +2816,7 @@ fn zirStructDecl( |
| 2839 | .parent = block.namespace.toOptional(), | 2816 | .parent = block.namespace.toOptional(), |
| 2840 | .owner_type = wip_ty.index, | 2817 | .owner_type = wip_ty.index, |
| 2841 | .file_scope = block.getFileScopeIndex(mod), | 2818 | .file_scope = block.getFileScopeIndex(mod), |
| 2819 | .generation = mod.generation, | ||
| 2842 | }); | 2820 | }); |
| 2843 | errdefer pt.destroyNamespace(new_namespace_index); | 2821 | errdefer pt.destroyNamespace(new_namespace_index); |
| 2844 | 2822 | ||
| ... | @@ -2977,7 +2955,6 @@ fn zirEnumDecl( | ... | @@ -2977,7 +2955,6 @@ fn zirEnumDecl( |
| 2977 | 2955 | ||
| 2978 | const tracked_inst = try block.trackZir(inst); | 2956 | const tracked_inst = try block.trackZir(inst); |
| 2979 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; | 2957 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; |
| 2980 | const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } }; | ||
| 2981 | 2958 | ||
| 2982 | const tag_type_ref = if (small.has_tag_type) blk: { | 2959 | const tag_type_ref = if (small.has_tag_type) blk: { |
| 2983 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); | 2960 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); |
| ... | @@ -3041,13 +3018,16 @@ fn zirEnumDecl( | ... | @@ -3041,13 +3018,16 @@ fn zirEnumDecl( |
| 3041 | } }, | 3018 | } }, |
| 3042 | }; | 3019 | }; |
| 3043 | const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) { | 3020 | const wip_ty = sema.wrapWipTy(switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) { |
| 3044 | .existing => |ty| wip: { | 3021 | .existing => |ty| { |
| 3045 | if (!try sema.checkOutdatedType(ty)) { | 3022 | const new_ty = try pt.ensureTypeUpToDate(ty, false); |
| 3046 | try sema.declareDependency(.{ .interned = ty }); | 3023 | |
| 3047 | try sema.addTypeReferenceEntry(src, ty); | 3024 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 3048 | return Air.internedToRef(ty); | 3025 | // up on e.g. changed comptime decls. |
| 3049 | } | 3026 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod)); |
| 3050 | break :wip (try ip.getEnumType(gpa, pt.tid, enum_init, true)).wip; | 3027 | |
| 3028 | try sema.declareDependency(.{ .interned = new_ty }); | ||
| 3029 | try sema.addTypeReferenceEntry(src, new_ty); | ||
| 3030 | return Air.internedToRef(new_ty); | ||
| 3051 | }, | 3031 | }, |
| 3052 | .wip => |wip| wip, | 3032 | .wip => |wip| wip, |
| 3053 | }); | 3033 | }); |
| ... | @@ -3071,19 +3051,12 @@ fn zirEnumDecl( | ... | @@ -3071,19 +3051,12 @@ fn zirEnumDecl( |
| 3071 | .parent = block.namespace.toOptional(), | 3051 | .parent = block.namespace.toOptional(), |
| 3072 | .owner_type = wip_ty.index, | 3052 | .owner_type = wip_ty.index, |
| 3073 | .file_scope = block.getFileScopeIndex(mod), | 3053 | .file_scope = block.getFileScopeIndex(mod), |
| 3054 | .generation = mod.generation, | ||
| 3074 | }); | 3055 | }); |
| 3075 | errdefer if (!done) pt.destroyNamespace(new_namespace_index); | 3056 | errdefer if (!done) pt.destroyNamespace(new_namespace_index); |
| 3076 | 3057 | ||
| 3077 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 3058 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| 3078 | 3059 | ||
| 3079 | if (pt.zcu.comp.incremental) { | ||
| 3080 | try mod.intern_pool.addDependency( | ||
| 3081 | gpa, | ||
| 3082 | AnalUnit.wrap(.{ .cau = new_cau_index }), | ||
| 3083 | .{ .src_hash = try block.trackZir(inst) }, | ||
| 3084 | ); | ||
| 3085 | } | ||
| 3086 | |||
| 3087 | try pt.scanNamespace(new_namespace_index, decls); | 3060 | try pt.scanNamespace(new_namespace_index, decls); |
| 3088 | 3061 | ||
| 3089 | try sema.declareDependency(.{ .interned = wip_ty.index }); | 3062 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| ... | @@ -3094,144 +3067,22 @@ fn zirEnumDecl( | ... | @@ -3094,144 +3067,22 @@ fn zirEnumDecl( |
| 3094 | wip_ty.prepare(ip, new_cau_index, new_namespace_index); | 3067 | wip_ty.prepare(ip, new_cau_index, new_namespace_index); |
| 3095 | done = true; | 3068 | done = true; |
| 3096 | 3069 | ||
| 3097 | const int_tag_ty = ty: { | 3070 | try Sema.resolveDeclaredEnum( |
| 3098 | // We create a block for the field type instructions because they | 3071 | pt, |
| 3099 | // may need to reference Decls from inside the enum namespace. | 3072 | wip_ty, |
| 3100 | // Within the field type, default value, and alignment expressions, the owner should be the enum's `Cau`. | 3073 | inst, |
| 3101 | 3074 | tracked_inst, | |
| 3102 | const prev_owner = sema.owner; | 3075 | new_namespace_index, |
| 3103 | sema.owner = AnalUnit.wrap(.{ .cau = new_cau_index }); | 3076 | type_name, |
| 3104 | defer sema.owner = prev_owner; | 3077 | new_cau_index, |
| 3105 | 3078 | small, | |
| 3106 | const prev_func_index = sema.func_index; | 3079 | body, |
| 3107 | sema.func_index = .none; | 3080 | tag_type_ref, |
| 3108 | defer sema.func_index = prev_func_index; | 3081 | any_values, |
| 3109 | 3082 | fields_len, | |
| 3110 | var enum_block: Block = .{ | 3083 | sema.code, |
| 3111 | .parent = null, | 3084 | body_end, |
| 3112 | .sema = sema, | 3085 | ); |
| 3113 | .namespace = new_namespace_index, | ||
| 3114 | .instructions = .{}, | ||
| 3115 | .inlining = null, | ||
| 3116 | .is_comptime = true, | ||
| 3117 | .src_base_inst = tracked_inst, | ||
| 3118 | .type_name_ctx = type_name, | ||
| 3119 | }; | ||
| 3120 | defer enum_block.instructions.deinit(sema.gpa); | ||
| 3121 | |||
| 3122 | if (body.len != 0) { | ||
| 3123 | _ = try sema.analyzeInlineBody(&enum_block, body, inst); | ||
| 3124 | } | ||
| 3125 | |||
| 3126 | if (tag_type_ref != .none) { | ||
| 3127 | const ty = try sema.resolveType(&enum_block, tag_ty_src, tag_type_ref); | ||
| 3128 | if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) { | ||
| 3129 | return sema.fail(&enum_block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)}); | ||
| 3130 | } | ||
| 3131 | break :ty ty; | ||
| 3132 | } else if (fields_len == 0) { | ||
| 3133 | break :ty try pt.intType(.unsigned, 0); | ||
| 3134 | } else { | ||
| 3135 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 3136 | break :ty try pt.intType(.unsigned, bits); | ||
| 3137 | } | ||
| 3138 | }; | ||
| 3139 | |||
| 3140 | wip_ty.setTagTy(ip, int_tag_ty.toIntern()); | ||
| 3141 | |||
| 3142 | if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | ||
| 3143 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(pt)) { | ||
| 3144 | return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); | ||
| 3145 | } | ||
| 3146 | } | ||
| 3147 | |||
| 3148 | var bit_bag_index: usize = body_end; | ||
| 3149 | var cur_bit_bag: u32 = undefined; | ||
| 3150 | var field_i: u32 = 0; | ||
| 3151 | var last_tag_val: ?Value = null; | ||
| 3152 | while (field_i < fields_len) : (field_i += 1) { | ||
| 3153 | if (field_i % 32 == 0) { | ||
| 3154 | cur_bit_bag = sema.code.extra[bit_bag_index]; | ||
| 3155 | bit_bag_index += 1; | ||
| 3156 | } | ||
| 3157 | const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0; | ||
| 3158 | cur_bit_bag >>= 1; | ||
| 3159 | |||
| 3160 | const field_name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]); | ||
| 3161 | const field_name_zir = sema.code.nullTerminatedString(field_name_index); | ||
| 3162 | extra_index += 2; // field name, doc comment | ||
| 3163 | |||
| 3164 | const field_name = try mod.intern_pool.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls); | ||
| 3165 | |||
| 3166 | const value_src: LazySrcLoc = .{ | ||
| 3167 | .base_node_inst = tracked_inst, | ||
| 3168 | .offset = .{ .container_field_value = field_i }, | ||
| 3169 | }; | ||
| 3170 | |||
| 3171 | const tag_overflow = if (has_tag_value) overflow: { | ||
| 3172 | const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); | ||
| 3173 | extra_index += 1; | ||
| 3174 | const tag_inst = try sema.resolveInst(tag_val_ref); | ||
| 3175 | last_tag_val = try sema.resolveConstDefinedValue(block, .{ | ||
| 3176 | .base_node_inst = tracked_inst, | ||
| 3177 | .offset = .{ .container_field_name = field_i }, | ||
| 3178 | }, tag_inst, .{ | ||
| 3179 | .needed_comptime_reason = "enum tag value must be comptime-known", | ||
| 3180 | }); | ||
| 3181 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; | ||
| 3182 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 3183 | if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 3184 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 3185 | const other_field_src: LazySrcLoc = .{ | ||
| 3186 | .base_node_inst = tracked_inst, | ||
| 3187 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 3188 | }; | ||
| 3189 | const msg = msg: { | ||
| 3190 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); | ||
| 3191 | errdefer msg.destroy(gpa); | ||
| 3192 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 3193 | break :msg msg; | ||
| 3194 | }; | ||
| 3195 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 3196 | } | ||
| 3197 | break :overflow false; | ||
| 3198 | } else if (any_values) overflow: { | ||
| 3199 | var overflow: ?usize = null; | ||
| 3200 | last_tag_val = if (last_tag_val) |val| | ||
| 3201 | try sema.intAdd(val, try pt.intValue(int_tag_ty, 1), int_tag_ty, &overflow) | ||
| 3202 | else | ||
| 3203 | try pt.intValue(int_tag_ty, 0); | ||
| 3204 | if (overflow != null) break :overflow true; | ||
| 3205 | if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 3206 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 3207 | const other_field_src: LazySrcLoc = .{ | ||
| 3208 | .base_node_inst = tracked_inst, | ||
| 3209 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 3210 | }; | ||
| 3211 | const msg = msg: { | ||
| 3212 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); | ||
| 3213 | errdefer msg.destroy(gpa); | ||
| 3214 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 3215 | break :msg msg; | ||
| 3216 | }; | ||
| 3217 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 3218 | } | ||
| 3219 | break :overflow false; | ||
| 3220 | } else overflow: { | ||
| 3221 | assert(wip_ty.nextField(&mod.intern_pool, field_name, .none) == null); | ||
| 3222 | last_tag_val = try pt.intValue(Type.comptime_int, field_i); | ||
| 3223 | if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true; | ||
| 3224 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 3225 | break :overflow false; | ||
| 3226 | }; | ||
| 3227 | |||
| 3228 | if (tag_overflow) { | ||
| 3229 | const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{ | ||
| 3230 | last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt), | ||
| 3231 | }); | ||
| 3232 | return sema.failWithOwnedErrorMsg(block, msg); | ||
| 3233 | } | ||
| 3234 | } | ||
| 3235 | 3086 | ||
| 3236 | codegen_type: { | 3087 | codegen_type: { |
| 3237 | if (mod.comp.config.use_llvm) break :codegen_type; | 3088 | if (mod.comp.config.use_llvm) break :codegen_type; |
| ... | @@ -3311,13 +3162,16 @@ fn zirUnionDecl( | ... | @@ -3311,13 +3162,16 @@ fn zirUnionDecl( |
| 3311 | } }, | 3162 | } }, |
| 3312 | }; | 3163 | }; |
| 3313 | const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) { | 3164 | const wip_ty = sema.wrapWipTy(switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) { |
| 3314 | .existing => |ty| wip: { | 3165 | .existing => |ty| { |
| 3315 | if (!try sema.checkOutdatedType(ty)) { | 3166 | const new_ty = try pt.ensureTypeUpToDate(ty, false); |
| 3316 | try sema.declareDependency(.{ .interned = ty }); | 3167 | |
| 3317 | try sema.addTypeReferenceEntry(src, ty); | 3168 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 3318 | return Air.internedToRef(ty); | 3169 | // up on e.g. changed comptime decls. |
| 3319 | } | 3170 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(mod)); |
| 3320 | break :wip (try ip.getUnionType(gpa, pt.tid, union_init, true)).wip; | 3171 | |
| 3172 | try sema.declareDependency(.{ .interned = new_ty }); | ||
| 3173 | try sema.addTypeReferenceEntry(src, new_ty); | ||
| 3174 | return Air.internedToRef(new_ty); | ||
| 3321 | }, | 3175 | }, |
| 3322 | .wip => |wip| wip, | 3176 | .wip => |wip| wip, |
| 3323 | }); | 3177 | }); |
| ... | @@ -3335,6 +3189,7 @@ fn zirUnionDecl( | ... | @@ -3335,6 +3189,7 @@ fn zirUnionDecl( |
| 3335 | .parent = block.namespace.toOptional(), | 3189 | .parent = block.namespace.toOptional(), |
| 3336 | .owner_type = wip_ty.index, | 3190 | .owner_type = wip_ty.index, |
| 3337 | .file_scope = block.getFileScopeIndex(mod), | 3191 | .file_scope = block.getFileScopeIndex(mod), |
| 3192 | .generation = mod.generation, | ||
| 3338 | }); | 3193 | }); |
| 3339 | errdefer pt.destroyNamespace(new_namespace_index); | 3194 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3340 | 3195 | ||
| ... | @@ -3344,7 +3199,7 @@ fn zirUnionDecl( | ... | @@ -3344,7 +3199,7 @@ fn zirUnionDecl( |
| 3344 | try mod.intern_pool.addDependency( | 3199 | try mod.intern_pool.addDependency( |
| 3345 | gpa, | 3200 | gpa, |
| 3346 | AnalUnit.wrap(.{ .cau = new_cau_index }), | 3201 | AnalUnit.wrap(.{ .cau = new_cau_index }), |
| 3347 | .{ .src_hash = try block.trackZir(inst) }, | 3202 | .{ .src_hash = tracked_inst }, |
| 3348 | ); | 3203 | ); |
| 3349 | } | 3204 | } |
| 3350 | 3205 | ||
| ... | @@ -3406,8 +3261,12 @@ fn zirOpaqueDecl( | ... | @@ -3406,8 +3261,12 @@ fn zirOpaqueDecl( |
| 3406 | }; | 3261 | }; |
| 3407 | // No `wrapWipTy` needed as no std.builtin types are opaque. | 3262 | // No `wrapWipTy` needed as no std.builtin types are opaque. |
| 3408 | const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) { | 3263 | const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) { |
| 3409 | // No `checkOutdatedType` as opaque types are never outdated. | ||
| 3410 | .existing => |ty| { | 3264 | .existing => |ty| { |
| 3265 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | ||
| 3266 | // up on e.g. changed comptime decls. | ||
| 3267 | try pt.ensureNamespaceUpToDate(Type.fromInterned(ty).getNamespaceIndex(mod)); | ||
| 3268 | |||
| 3269 | try sema.declareDependency(.{ .interned = ty }); | ||
| 3411 | try sema.addTypeReferenceEntry(src, ty); | 3270 | try sema.addTypeReferenceEntry(src, ty); |
| 3412 | return Air.internedToRef(ty); | 3271 | return Air.internedToRef(ty); |
| 3413 | }, | 3272 | }, |
| ... | @@ -3427,6 +3286,7 @@ fn zirOpaqueDecl( | ... | @@ -3427,6 +3286,7 @@ fn zirOpaqueDecl( |
| 3427 | .parent = block.namespace.toOptional(), | 3286 | .parent = block.namespace.toOptional(), |
| 3428 | .owner_type = wip_ty.index, | 3287 | .owner_type = wip_ty.index, |
| 3429 | .file_scope = block.getFileScopeIndex(mod), | 3288 | .file_scope = block.getFileScopeIndex(mod), |
| 3289 | .generation = mod.generation, | ||
| 3430 | }); | 3290 | }); |
| 3431 | errdefer pt.destroyNamespace(new_namespace_index); | 3291 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3432 | 3292 | ||
| ... | @@ -6072,6 +5932,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -6072,6 +5932,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 6072 | // trigger re-analysis later. | 5932 | // trigger re-analysis later. |
| 6073 | try pt.ensureFileAnalyzed(result.file_index); | 5933 | try pt.ensureFileAnalyzed(result.file_index); |
| 6074 | const ty = zcu.fileRootType(result.file_index); | 5934 | const ty = zcu.fileRootType(result.file_index); |
| 5935 | try sema.declareDependency(.{ .interned = ty }); | ||
| 6075 | try sema.addTypeReferenceEntry(src, ty); | 5936 | try sema.addTypeReferenceEntry(src, ty); |
| 6076 | return Air.internedToRef(ty); | 5937 | return Air.internedToRef(ty); |
| 6077 | } | 5938 | } |
| ... | @@ -6821,6 +6682,8 @@ fn lookupInNamespace( | ... | @@ -6821,6 +6682,8 @@ fn lookupInNamespace( |
| 6821 | const zcu = pt.zcu; | 6682 | const zcu = pt.zcu; |
| 6822 | const ip = &zcu.intern_pool; | 6683 | const ip = &zcu.intern_pool; |
| 6823 | 6684 | ||
| 6685 | try pt.ensureNamespaceUpToDate(namespace_index); | ||
| 6686 | |||
| 6824 | const namespace = zcu.namespacePtr(namespace_index); | 6687 | const namespace = zcu.namespacePtr(namespace_index); |
| 6825 | 6688 | ||
| 6826 | const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu }; | 6689 | const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu }; |
| ... | @@ -14038,6 +13901,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -14038,6 +13901,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 14038 | // trigger re-analysis later. | 13901 | // trigger re-analysis later. |
| 14039 | try pt.ensureFileAnalyzed(result.file_index); | 13902 | try pt.ensureFileAnalyzed(result.file_index); |
| 14040 | const ty = zcu.fileRootType(result.file_index); | 13903 | const ty = zcu.fileRootType(result.file_index); |
| 13904 | try sema.declareDependency(.{ .interned = ty }); | ||
| 14041 | try sema.addTypeReferenceEntry(operand_src, ty); | 13905 | try sema.addTypeReferenceEntry(operand_src, ty); |
| 14042 | return Air.internedToRef(ty); | 13906 | return Air.internedToRef(ty); |
| 14043 | } | 13907 | } |
| ... | @@ -17703,7 +17567,13 @@ fn zirThis( | ... | @@ -17703,7 +17567,13 @@ fn zirThis( |
| 17703 | _ = extended; | 17567 | _ = extended; |
| 17704 | const pt = sema.pt; | 17568 | const pt = sema.pt; |
| 17705 | const namespace = pt.zcu.namespacePtr(block.namespace); | 17569 | const namespace = pt.zcu.namespacePtr(block.namespace); |
| 17706 | return Air.internedToRef(namespace.owner_type); | 17570 | const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type, false); |
| 17571 | switch (pt.zcu.intern_pool.indexToKey(new_ty)) { | ||
| 17572 | .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }), | ||
| 17573 | .opaque_type => {}, | ||
| 17574 | else => unreachable, | ||
| 17575 | } | ||
| 17576 | return Air.internedToRef(new_ty); | ||
| 17707 | } | 17577 | } |
| 17708 | 17578 | ||
| 17709 | fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 17579 | fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | @@ -19005,6 +18875,7 @@ fn typeInfoNamespaceDecls( | ... | @@ -19005,6 +18875,7 @@ fn typeInfoNamespaceDecls( |
| 19005 | const ip = &zcu.intern_pool; | 18875 | const ip = &zcu.intern_pool; |
| 19006 | 18876 | ||
| 19007 | const namespace_index = opt_namespace_index.unwrap() orelse return; | 18877 | const namespace_index = opt_namespace_index.unwrap() orelse return; |
| 18878 | try pt.ensureNamespaceUpToDate(namespace_index); | ||
| 19008 | const namespace = zcu.namespacePtr(namespace_index); | 18879 | const namespace = zcu.namespacePtr(namespace_index); |
| 19009 | 18880 | ||
| 19010 | const gop = try seen_namespaces.getOrPut(namespace); | 18881 | const gop = try seen_namespaces.getOrPut(namespace); |
| ... | @@ -21871,6 +21742,7 @@ fn zirReify( | ... | @@ -21871,6 +21742,7 @@ fn zirReify( |
| 21871 | .parent = block.namespace.toOptional(), | 21742 | .parent = block.namespace.toOptional(), |
| 21872 | .owner_type = wip_ty.index, | 21743 | .owner_type = wip_ty.index, |
| 21873 | .file_scope = block.getFileScopeIndex(mod), | 21744 | .file_scope = block.getFileScopeIndex(mod), |
| 21745 | .generation = mod.generation, | ||
| 21874 | }); | 21746 | }); |
| 21875 | 21747 | ||
| 21876 | try sema.addTypeReferenceEntry(src, wip_ty.index); | 21748 | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| ... | @@ -22080,6 +21952,7 @@ fn reifyEnum( | ... | @@ -22080,6 +21952,7 @@ fn reifyEnum( |
| 22080 | .parent = block.namespace.toOptional(), | 21952 | .parent = block.namespace.toOptional(), |
| 22081 | .owner_type = wip_ty.index, | 21953 | .owner_type = wip_ty.index, |
| 22082 | .file_scope = block.getFileScopeIndex(mod), | 21954 | .file_scope = block.getFileScopeIndex(mod), |
| 21955 | .generation = mod.generation, | ||
| 22083 | }); | 21956 | }); |
| 22084 | 21957 | ||
| 22085 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 21958 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| ... | @@ -22384,6 +22257,7 @@ fn reifyUnion( | ... | @@ -22384,6 +22257,7 @@ fn reifyUnion( |
| 22384 | .parent = block.namespace.toOptional(), | 22257 | .parent = block.namespace.toOptional(), |
| 22385 | .owner_type = wip_ty.index, | 22258 | .owner_type = wip_ty.index, |
| 22386 | .file_scope = block.getFileScopeIndex(mod), | 22259 | .file_scope = block.getFileScopeIndex(mod), |
| 22260 | .generation = mod.generation, | ||
| 22387 | }); | 22261 | }); |
| 22388 | 22262 | ||
| 22389 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 22263 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| ... | @@ -22667,6 +22541,7 @@ fn reifyStruct( | ... | @@ -22667,6 +22541,7 @@ fn reifyStruct( |
| 22667 | .parent = block.namespace.toOptional(), | 22541 | .parent = block.namespace.toOptional(), |
| 22668 | .owner_type = wip_ty.index, | 22542 | .owner_type = wip_ty.index, |
| 22669 | .file_scope = block.getFileScopeIndex(mod), | 22543 | .file_scope = block.getFileScopeIndex(mod), |
| 22544 | .generation = mod.generation, | ||
| 22670 | }); | 22545 | }); |
| 22671 | 22546 | ||
| 22672 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | 22547 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); |
| ... | @@ -35373,7 +35248,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { | ... | @@ -35373,7 +35248,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { |
| 35373 | if (struct_type.haveLayout(ip)) | 35248 | if (struct_type.haveLayout(ip)) |
| 35374 | return; | 35249 | return; |
| 35375 | 35250 | ||
| 35376 | try ty.resolveFields(pt); | 35251 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); |
| 35377 | 35252 | ||
| 35378 | if (struct_type.layout == .@"packed") { | 35253 | if (struct_type.layout == .@"packed") { |
| 35379 | semaBackingIntType(pt, struct_type) catch |err| switch (err) { | 35254 | semaBackingIntType(pt, struct_type) catch |err| switch (err) { |
| ... | @@ -38499,6 +38374,187 @@ fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index { | ... | @@ -38499,6 +38374,187 @@ fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index { |
| 38499 | return ip.getCau(cau).zir_index; | 38374 | return ip.getCau(cau).zir_index; |
| 38500 | } | 38375 | } |
| 38501 | 38376 | ||
| 38377 | /// Called as soon as a `declared` enum type is created. | ||
| 38378 | /// Resolves the tag type and field inits. | ||
| 38379 | /// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this. | ||
| 38380 | pub fn resolveDeclaredEnum( | ||
| 38381 | pt: Zcu.PerThread, | ||
| 38382 | wip_ty: InternPool.WipEnumType, | ||
| 38383 | inst: Zir.Inst.Index, | ||
| 38384 | tracked_inst: InternPool.TrackedInst.Index, | ||
| 38385 | namespace: InternPool.NamespaceIndex, | ||
| 38386 | type_name: InternPool.NullTerminatedString, | ||
| 38387 | enum_cau: InternPool.Cau.Index, | ||
| 38388 | small: Zir.Inst.EnumDecl.Small, | ||
| 38389 | body: []const Zir.Inst.Index, | ||
| 38390 | tag_type_ref: Zir.Inst.Ref, | ||
| 38391 | any_values: bool, | ||
| 38392 | fields_len: u32, | ||
| 38393 | zir: Zir, | ||
| 38394 | body_end: usize, | ||
| 38395 | ) Zcu.CompileError!void { | ||
| 38396 | const zcu = pt.zcu; | ||
| 38397 | const gpa = zcu.gpa; | ||
| 38398 | const ip = &zcu.intern_pool; | ||
| 38399 | |||
| 38400 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 38401 | |||
| 38402 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; | ||
| 38403 | const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } }; | ||
| 38404 | |||
| 38405 | const anal_unit = AnalUnit.wrap(.{ .cau = enum_cau }); | ||
| 38406 | |||
| 38407 | var arena = std.heap.ArenaAllocator.init(gpa); | ||
| 38408 | defer arena.deinit(); | ||
| 38409 | |||
| 38410 | var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa); | ||
| 38411 | defer comptime_err_ret_trace.deinit(); | ||
| 38412 | |||
| 38413 | var sema: Sema = .{ | ||
| 38414 | .pt = pt, | ||
| 38415 | .gpa = gpa, | ||
| 38416 | .arena = arena.allocator(), | ||
| 38417 | .code = zir, | ||
| 38418 | .owner = anal_unit, | ||
| 38419 | .func_index = .none, | ||
| 38420 | .func_is_naked = false, | ||
| 38421 | .fn_ret_ty = Type.void, | ||
| 38422 | .fn_ret_ty_ies = null, | ||
| 38423 | .comptime_err_ret_trace = &comptime_err_ret_trace, | ||
| 38424 | }; | ||
| 38425 | defer sema.deinit(); | ||
| 38426 | |||
| 38427 | try sema.declareDependency(.{ .src_hash = tracked_inst }); | ||
| 38428 | |||
| 38429 | var block: Block = .{ | ||
| 38430 | .parent = null, | ||
| 38431 | .sema = &sema, | ||
| 38432 | .namespace = namespace, | ||
| 38433 | .instructions = .{}, | ||
| 38434 | .inlining = null, | ||
| 38435 | .is_comptime = true, | ||
| 38436 | .src_base_inst = tracked_inst, | ||
| 38437 | .type_name_ctx = type_name, | ||
| 38438 | }; | ||
| 38439 | defer block.instructions.deinit(gpa); | ||
| 38440 | |||
| 38441 | const int_tag_ty = ty: { | ||
| 38442 | if (body.len != 0) { | ||
| 38443 | _ = try sema.analyzeInlineBody(&block, body, inst); | ||
| 38444 | } | ||
| 38445 | |||
| 38446 | if (tag_type_ref != .none) { | ||
| 38447 | const ty = try sema.resolveType(&block, tag_ty_src, tag_type_ref); | ||
| 38448 | if (ty.zigTypeTag(zcu) != .Int and ty.zigTypeTag(zcu) != .ComptimeInt) { | ||
| 38449 | return sema.fail(&block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)}); | ||
| 38450 | } | ||
| 38451 | break :ty ty; | ||
| 38452 | } else if (fields_len == 0) { | ||
| 38453 | break :ty try pt.intType(.unsigned, 0); | ||
| 38454 | } else { | ||
| 38455 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 38456 | break :ty try pt.intType(.unsigned, bits); | ||
| 38457 | } | ||
| 38458 | }; | ||
| 38459 | |||
| 38460 | wip_ty.setTagTy(ip, int_tag_ty.toIntern()); | ||
| 38461 | |||
| 38462 | if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | ||
| 38463 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(pt)) { | ||
| 38464 | return sema.fail(&block, src, "non-exhaustive enum specifies every value", .{}); | ||
| 38465 | } | ||
| 38466 | } | ||
| 38467 | |||
| 38468 | var extra_index = body_end + bit_bags_count; | ||
| 38469 | var bit_bag_index: usize = body_end; | ||
| 38470 | var cur_bit_bag: u32 = undefined; | ||
| 38471 | var last_tag_val: ?Value = null; | ||
| 38472 | for (0..fields_len) |field_i_usize| { | ||
| 38473 | const field_i: u32 = @intCast(field_i_usize); | ||
| 38474 | if (field_i % 32 == 0) { | ||
| 38475 | cur_bit_bag = zir.extra[bit_bag_index]; | ||
| 38476 | bit_bag_index += 1; | ||
| 38477 | } | ||
| 38478 | const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0; | ||
| 38479 | cur_bit_bag >>= 1; | ||
| 38480 | |||
| 38481 | const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]); | ||
| 38482 | const field_name_zir = zir.nullTerminatedString(field_name_index); | ||
| 38483 | extra_index += 2; // field name, doc comment | ||
| 38484 | |||
| 38485 | const field_name = try ip.getOrPutString(gpa, pt.tid, field_name_zir, .no_embedded_nulls); | ||
| 38486 | |||
| 38487 | const value_src: LazySrcLoc = .{ | ||
| 38488 | .base_node_inst = tracked_inst, | ||
| 38489 | .offset = .{ .container_field_value = field_i }, | ||
| 38490 | }; | ||
| 38491 | |||
| 38492 | const tag_overflow = if (has_tag_value) overflow: { | ||
| 38493 | const tag_val_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | ||
| 38494 | extra_index += 1; | ||
| 38495 | const tag_inst = try sema.resolveInst(tag_val_ref); | ||
| 38496 | last_tag_val = try sema.resolveConstDefinedValue(&block, .{ | ||
| 38497 | .base_node_inst = tracked_inst, | ||
| 38498 | .offset = .{ .container_field_name = field_i }, | ||
| 38499 | }, tag_inst, .{ | ||
| 38500 | .needed_comptime_reason = "enum tag value must be comptime-known", | ||
| 38501 | }); | ||
| 38502 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; | ||
| 38503 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 38504 | if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 38505 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 38506 | const other_field_src: LazySrcLoc = .{ | ||
| 38507 | .base_node_inst = tracked_inst, | ||
| 38508 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 38509 | }; | ||
| 38510 | const msg = msg: { | ||
| 38511 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)}); | ||
| 38512 | errdefer msg.destroy(gpa); | ||
| 38513 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 38514 | break :msg msg; | ||
| 38515 | }; | ||
| 38516 | return sema.failWithOwnedErrorMsg(&block, msg); | ||
| 38517 | } | ||
| 38518 | break :overflow false; | ||
| 38519 | } else if (any_values) overflow: { | ||
| 38520 | var overflow: ?usize = null; | ||
| 38521 | last_tag_val = if (last_tag_val) |val| | ||
| 38522 | try sema.intAdd(val, try pt.intValue(int_tag_ty, 1), int_tag_ty, &overflow) | ||
| 38523 | else | ||
| 38524 | try pt.intValue(int_tag_ty, 0); | ||
| 38525 | if (overflow != null) break :overflow true; | ||
| 38526 | if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| { | ||
| 38527 | assert(conflict.kind == .value); // AstGen validated names are unique | ||
| 38528 | const other_field_src: LazySrcLoc = .{ | ||
| 38529 | .base_node_inst = tracked_inst, | ||
| 38530 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | ||
| 38531 | }; | ||
| 38532 | const msg = msg: { | ||
| 38533 | const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)}); | ||
| 38534 | errdefer msg.destroy(gpa); | ||
| 38535 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | ||
| 38536 | break :msg msg; | ||
| 38537 | }; | ||
| 38538 | return sema.failWithOwnedErrorMsg(&block, msg); | ||
| 38539 | } | ||
| 38540 | break :overflow false; | ||
| 38541 | } else overflow: { | ||
| 38542 | assert(wip_ty.nextField(ip, field_name, .none) == null); | ||
| 38543 | last_tag_val = try pt.intValue(Type.comptime_int, field_i); | ||
| 38544 | if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true; | ||
| 38545 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | ||
| 38546 | break :overflow false; | ||
| 38547 | }; | ||
| 38548 | |||
| 38549 | if (tag_overflow) { | ||
| 38550 | const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{ | ||
| 38551 | last_tag_val.?.fmtValueSema(pt, &sema), int_tag_ty.fmt(pt), | ||
| 38552 | }); | ||
| 38553 | return sema.failWithOwnedErrorMsg(&block, msg); | ||
| 38554 | } | ||
| 38555 | } | ||
| 38556 | } | ||
| 38557 | |||
| 38502 | pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; | 38558 | pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; |
| 38503 | pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; | 38559 | pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; |
| 38504 | 38560 |
src/Zcu.zig+34-27| ... | @@ -215,6 +215,8 @@ panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId | ... | @@ -215,6 +215,8 @@ panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId |
| 215 | panic_func_index: InternPool.Index = .none, | 215 | panic_func_index: InternPool.Index = .none, |
| 216 | null_stack_trace: InternPool.Index = .none, | 216 | null_stack_trace: InternPool.Index = .none, |
| 217 | 217 | ||
| 218 | generation: u32 = 0, | ||
| 219 | |||
| 218 | pub const PerThread = @import("Zcu/PerThread.zig"); | 220 | pub const PerThread = @import("Zcu/PerThread.zig"); |
| 219 | 221 | ||
| 220 | pub const PanicId = enum { | 222 | pub const PanicId = enum { |
| ... | @@ -332,6 +334,7 @@ pub const TypeReference = struct { | ... | @@ -332,6 +334,7 @@ pub const TypeReference = struct { |
| 332 | pub const Namespace = struct { | 334 | pub const Namespace = struct { |
| 333 | parent: OptionalIndex, | 335 | parent: OptionalIndex, |
| 334 | file_scope: File.Index, | 336 | file_scope: File.Index, |
| 337 | generation: u32, | ||
| 335 | /// Will be a struct, enum, union, or opaque. | 338 | /// Will be a struct, enum, union, or opaque. |
| 336 | owner_type: InternPool.Index, | 339 | owner_type: InternPool.Index, |
| 337 | /// Members of the namespace which are marked `pub`. | 340 | /// Members of the namespace which are marked `pub`. |
| ... | @@ -2295,7 +2298,7 @@ pub fn markDependeeOutdated( | ... | @@ -2295,7 +2298,7 @@ pub fn markDependeeOutdated( |
| 2295 | marked_po: enum { not_marked_po, marked_po }, | 2298 | marked_po: enum { not_marked_po, marked_po }, |
| 2296 | dependee: InternPool.Dependee, | 2299 | dependee: InternPool.Dependee, |
| 2297 | ) !void { | 2300 | ) !void { |
| 2298 | log.debug("outdated dependee: {}", .{fmtDependee(dependee, zcu)}); | 2301 | log.debug("outdated dependee: {}", .{zcu.fmtDependee(dependee)}); |
| 2299 | var it = zcu.intern_pool.dependencyIterator(dependee); | 2302 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 2300 | while (it.next()) |depender| { | 2303 | while (it.next()) |depender| { |
| 2301 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { | 2304 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { |
| ... | @@ -2303,9 +2306,9 @@ pub fn markDependeeOutdated( | ... | @@ -2303,9 +2306,9 @@ pub fn markDependeeOutdated( |
| 2303 | .not_marked_po => {}, | 2306 | .not_marked_po => {}, |
| 2304 | .marked_po => { | 2307 | .marked_po => { |
| 2305 | po_dep_count.* -= 1; | 2308 | po_dep_count.* -= 1; |
| 2306 | log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), po_dep_count.* }); | 2309 | log.debug("outdated {} => already outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); |
| 2307 | if (po_dep_count.* == 0) { | 2310 | if (po_dep_count.* == 0) { |
| 2308 | log.debug("outdated ready: {}", .{fmtAnalUnit(depender, zcu)}); | 2311 | log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); |
| 2309 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); | 2312 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 2310 | } | 2313 | } |
| 2311 | }, | 2314 | }, |
| ... | @@ -2316,20 +2319,19 @@ pub fn markDependeeOutdated( | ... | @@ -2316,20 +2319,19 @@ pub fn markDependeeOutdated( |
| 2316 | const new_po_dep_count = switch (marked_po) { | 2319 | const new_po_dep_count = switch (marked_po) { |
| 2317 | .not_marked_po => if (opt_po_entry) |e| e.value else 0, | 2320 | .not_marked_po => if (opt_po_entry) |e| e.value else 0, |
| 2318 | .marked_po => if (opt_po_entry) |e| e.value - 1 else { | 2321 | .marked_po => if (opt_po_entry) |e| e.value - 1 else { |
| 2319 | // This dependency has been registered during in-progress analysis, but the unit is | 2322 | // This `AnalUnit` has already been re-analyzed this update, and registered a dependency |
| 2320 | // not in `potentially_outdated` because analysis is in-progress. Nothing to do. | 2323 | // on this thing, but already has sufficiently up-to-date information. Nothing to do. |
| 2321 | continue; | 2324 | continue; |
| 2322 | }, | 2325 | }, |
| 2323 | }; | 2326 | }; |
| 2324 | log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), new_po_dep_count }); | ||
| 2325 | try zcu.outdated.putNoClobber( | 2327 | try zcu.outdated.putNoClobber( |
| 2326 | zcu.gpa, | 2328 | zcu.gpa, |
| 2327 | depender, | 2329 | depender, |
| 2328 | new_po_dep_count, | 2330 | new_po_dep_count, |
| 2329 | ); | 2331 | ); |
| 2330 | log.debug("outdated: {}", .{fmtAnalUnit(depender, zcu)}); | 2332 | log.debug("outdated {} => new outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); |
| 2331 | if (new_po_dep_count == 0) { | 2333 | if (new_po_dep_count == 0) { |
| 2332 | log.debug("outdated ready: {}", .{fmtAnalUnit(depender, zcu)}); | 2334 | log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); |
| 2333 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); | 2335 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 2334 | } | 2336 | } |
| 2335 | // If this is a Decl and was not previously PO, we must recursively | 2337 | // If this is a Decl and was not previously PO, we must recursively |
| ... | @@ -2342,16 +2344,16 @@ pub fn markDependeeOutdated( | ... | @@ -2342,16 +2344,16 @@ pub fn markDependeeOutdated( |
| 2342 | } | 2344 | } |
| 2343 | 2345 | ||
| 2344 | pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { | 2346 | pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2345 | log.debug("up-to-date dependee: {}", .{fmtDependee(dependee, zcu)}); | 2347 | log.debug("up-to-date dependee: {}", .{zcu.fmtDependee(dependee)}); |
| 2346 | var it = zcu.intern_pool.dependencyIterator(dependee); | 2348 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 2347 | while (it.next()) |depender| { | 2349 | while (it.next()) |depender| { |
| 2348 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { | 2350 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { |
| 2349 | // This depender is already outdated, but it now has one | 2351 | // This depender is already outdated, but it now has one |
| 2350 | // less PO dependency! | 2352 | // less PO dependency! |
| 2351 | po_dep_count.* -= 1; | 2353 | po_dep_count.* -= 1; |
| 2352 | log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), po_dep_count.* }); | 2354 | log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); |
| 2353 | if (po_dep_count.* == 0) { | 2355 | if (po_dep_count.* == 0) { |
| 2354 | log.debug("outdated ready: {}", .{fmtAnalUnit(depender, zcu)}); | 2356 | log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)}); |
| 2355 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); | 2357 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 2356 | } | 2358 | } |
| 2357 | continue; | 2359 | continue; |
| ... | @@ -2365,11 +2367,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { | ... | @@ -2365,11 +2367,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2365 | }; | 2367 | }; |
| 2366 | if (ptr.* > 1) { | 2368 | if (ptr.* > 1) { |
| 2367 | ptr.* -= 1; | 2369 | ptr.* -= 1; |
| 2368 | log.debug("po dep count: {} = {}", .{ fmtAnalUnit(depender, zcu), ptr.* }); | 2370 | log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); |
| 2369 | continue; | 2371 | continue; |
| 2370 | } | 2372 | } |
| 2371 | 2373 | ||
| 2372 | log.debug("up-to-date (po deps = 0): {}", .{fmtAnalUnit(depender, zcu)}); | 2374 | log.debug("up-to-date {} => {} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); |
| 2373 | 2375 | ||
| 2374 | // This dependency is no longer PO, i.e. is known to be up-to-date. | 2376 | // This dependency is no longer PO, i.e. is known to be up-to-date. |
| 2375 | assert(zcu.potentially_outdated.swapRemove(depender)); | 2377 | assert(zcu.potentially_outdated.swapRemove(depender)); |
| ... | @@ -2398,7 +2400,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni | ... | @@ -2398,7 +2400,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 2398 | }, | 2400 | }, |
| 2399 | .func => |func_index| .{ .interned = func_index }, // IES | 2401 | .func => |func_index| .{ .interned = func_index }, // IES |
| 2400 | }; | 2402 | }; |
| 2401 | log.debug("marking dependee po: {}", .{fmtDependee(dependee, zcu)}); | 2403 | log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)}); |
| 2402 | var it = ip.dependencyIterator(dependee); | 2404 | var it = ip.dependencyIterator(dependee); |
| 2403 | while (it.next()) |po| { | 2405 | while (it.next()) |po| { |
| 2404 | if (zcu.outdated.getPtr(po)) |po_dep_count| { | 2406 | if (zcu.outdated.getPtr(po)) |po_dep_count| { |
| ... | @@ -2408,17 +2410,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni | ... | @@ -2408,17 +2410,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 2408 | _ = zcu.outdated_ready.swapRemove(po); | 2410 | _ = zcu.outdated_ready.swapRemove(po); |
| 2409 | } | 2411 | } |
| 2410 | po_dep_count.* += 1; | 2412 | po_dep_count.* += 1; |
| 2411 | log.debug("po dep count: {} = {}", .{ fmtAnalUnit(po, zcu), po_dep_count.* }); | 2413 | log.debug("po {} => {} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); |
| 2412 | continue; | 2414 | continue; |
| 2413 | } | 2415 | } |
| 2414 | if (zcu.potentially_outdated.getPtr(po)) |n| { | 2416 | if (zcu.potentially_outdated.getPtr(po)) |n| { |
| 2415 | // There is now one more PO dependency. | 2417 | // There is now one more PO dependency. |
| 2416 | n.* += 1; | 2418 | n.* += 1; |
| 2417 | log.debug("po dep count: {} = {}", .{ fmtAnalUnit(po, zcu), n.* }); | 2419 | log.debug("po {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); |
| 2418 | continue; | 2420 | continue; |
| 2419 | } | 2421 | } |
| 2420 | try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1); | 2422 | try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1); |
| 2421 | log.debug("po dep count: {} = {}", .{ fmtAnalUnit(po, zcu), 1 }); | 2423 | log.debug("po {} => {} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); |
| 2422 | // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. | 2424 | // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. |
| 2423 | try zcu.markTransitiveDependersPotentiallyOutdated(po); | 2425 | try zcu.markTransitiveDependersPotentiallyOutdated(po); |
| 2424 | } | 2426 | } |
| ... | @@ -2443,7 +2445,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { | ... | @@ -2443,7 +2445,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2443 | 2445 | ||
| 2444 | if (zcu.outdated_ready.count() > 0) { | 2446 | if (zcu.outdated_ready.count() > 0) { |
| 2445 | const unit = zcu.outdated_ready.keys()[0]; | 2447 | const unit = zcu.outdated_ready.keys()[0]; |
| 2446 | log.debug("findOutdatedToAnalyze: trivial {}", .{fmtAnalUnit(unit, zcu)}); | 2448 | log.debug("findOutdatedToAnalyze: trivial {}", .{zcu.fmtAnalUnit(unit)}); |
| 2447 | return unit; | 2449 | return unit; |
| 2448 | } | 2450 | } |
| 2449 | 2451 | ||
| ... | @@ -2498,10 +2500,15 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { | ... | @@ -2498,10 +2500,15 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2498 | const nav = zcu.funcInfo(func).owner_nav; | 2500 | const nav = zcu.funcInfo(func).owner_nav; |
| 2499 | std.io.getStdErr().writer().print("outdated: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {}; | 2501 | std.io.getStdErr().writer().print("outdated: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {}; |
| 2500 | } | 2502 | } |
| 2503 | for (zcu.potentially_outdated.keys(), zcu.potentially_outdated.values()) |o, opod| { | ||
| 2504 | const func = o.unwrap().func; | ||
| 2505 | const nav = zcu.funcInfo(func).owner_nav; | ||
| 2506 | std.io.getStdErr().writer().print("po: func {}, nav {}, name '{}', [p]o deps {}\n", .{ func, nav, ip.getNav(nav).fqn.fmt(ip), opod }) catch {}; | ||
| 2507 | } | ||
| 2501 | } | 2508 | } |
| 2502 | 2509 | ||
| 2503 | log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{ | 2510 | log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{ |
| 2504 | fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? }), zcu), | 2511 | zcu.fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? })), |
| 2505 | chosen_cau_dependers, | 2512 | chosen_cau_dependers, |
| 2506 | }); | 2513 | }); |
| 2507 | 2514 | ||
| ... | @@ -2744,7 +2751,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { | ... | @@ -2744,7 +2751,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 2744 | const gpa = zcu.gpa; | 2751 | const gpa = zcu.gpa; |
| 2745 | 2752 | ||
| 2746 | unit_refs: { | 2753 | unit_refs: { |
| 2747 | const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse return; | 2754 | const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs; |
| 2748 | var idx = kv.value; | 2755 | var idx = kv.value; |
| 2749 | 2756 | ||
| 2750 | while (idx != std.math.maxInt(u32)) { | 2757 | while (idx != std.math.maxInt(u32)) { |
| ... | @@ -2758,7 +2765,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { | ... | @@ -2758,7 +2765,7 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 2758 | } | 2765 | } |
| 2759 | 2766 | ||
| 2760 | type_refs: { | 2767 | type_refs: { |
| 2761 | const kv = zcu.type_reference_table.fetchSwapRemove(anal_unit) orelse return; | 2768 | const kv = zcu.type_reference_table.fetchSwapRemove(anal_unit) orelse break :type_refs; |
| 2762 | var idx = kv.value; | 2769 | var idx = kv.value; |
| 2763 | 2770 | ||
| 2764 | while (idx != std.math.maxInt(u32)) { | 2771 | while (idx != std.math.maxInt(u32)) { |
| ... | @@ -3280,7 +3287,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve | ... | @@ -3280,7 +3287,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve |
| 3280 | const unit = kv.key; | 3287 | const unit = kv.key; |
| 3281 | try result.putNoClobber(gpa, unit, kv.value); | 3288 | try result.putNoClobber(gpa, unit, kv.value); |
| 3282 | 3289 | ||
| 3283 | log.debug("handle unit '{}'", .{fmtAnalUnit(unit, zcu)}); | 3290 | log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)}); |
| 3284 | 3291 | ||
| 3285 | if (zcu.reference_table.get(unit)) |first_ref_idx| { | 3292 | if (zcu.reference_table.get(unit)) |first_ref_idx| { |
| 3286 | assert(first_ref_idx != std.math.maxInt(u32)); | 3293 | assert(first_ref_idx != std.math.maxInt(u32)); |
| ... | @@ -3289,8 +3296,8 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve | ... | @@ -3289,8 +3296,8 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve |
| 3289 | const ref = zcu.all_references.items[ref_idx]; | 3296 | const ref = zcu.all_references.items[ref_idx]; |
| 3290 | if (!result.contains(ref.referenced)) { | 3297 | if (!result.contains(ref.referenced)) { |
| 3291 | log.debug("unit '{}': ref unit '{}'", .{ | 3298 | log.debug("unit '{}': ref unit '{}'", .{ |
| 3292 | fmtAnalUnit(unit, zcu), | 3299 | zcu.fmtAnalUnit(unit), |
| 3293 | fmtAnalUnit(ref.referenced, zcu), | 3300 | zcu.fmtAnalUnit(ref.referenced), |
| 3294 | }); | 3301 | }); |
| 3295 | try unit_queue.put(gpa, ref.referenced, .{ | 3302 | try unit_queue.put(gpa, ref.referenced, .{ |
| 3296 | .referencer = unit, | 3303 | .referencer = unit, |
| ... | @@ -3307,7 +3314,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve | ... | @@ -3307,7 +3314,7 @@ pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolve |
| 3307 | const ref = zcu.all_type_references.items[ref_idx]; | 3314 | const ref = zcu.all_type_references.items[ref_idx]; |
| 3308 | if (!checked_types.contains(ref.referenced)) { | 3315 | if (!checked_types.contains(ref.referenced)) { |
| 3309 | log.debug("unit '{}': ref type '{}'", .{ | 3316 | log.debug("unit '{}': ref type '{}'", .{ |
| 3310 | fmtAnalUnit(unit, zcu), | 3317 | zcu.fmtAnalUnit(unit), |
| 3311 | Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip), | 3318 | Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip), |
| 3312 | }); | 3319 | }); |
| 3313 | try type_queue.put(gpa, ref.referenced, .{ | 3320 | try type_queue.put(gpa, ref.referenced, .{ |
| ... | @@ -3389,10 +3396,10 @@ pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File { | ... | @@ -3389,10 +3396,10 @@ pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File { |
| 3389 | return zcu.fileByIndex(file_index); | 3396 | return zcu.fileByIndex(file_index); |
| 3390 | } | 3397 | } |
| 3391 | 3398 | ||
| 3392 | fn fmtAnalUnit(unit: AnalUnit, zcu: *Zcu) std.fmt.Formatter(formatAnalUnit) { | 3399 | pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) { |
| 3393 | return .{ .data = .{ .unit = unit, .zcu = zcu } }; | 3400 | return .{ .data = .{ .unit = unit, .zcu = zcu } }; |
| 3394 | } | 3401 | } |
| 3395 | fn fmtDependee(d: InternPool.Dependee, zcu: *Zcu) std.fmt.Formatter(formatDependee) { | 3402 | pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Formatter(formatDependee) { |
| 3396 | return .{ .data = .{ .dependee = d, .zcu = zcu } }; | 3403 | return .{ .data = .{ .dependee = d, .zcu = zcu } }; |
| 3397 | } | 3404 | } |
| 3398 | 3405 |
src/Zcu/PerThread.zig+571-83| ... | @@ -485,10 +485,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { | ... | @@ -485,10 +485,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 485 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | 485 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 486 | const file_root_type = pt.zcu.fileRootType(file_index); | 486 | const file_root_type = pt.zcu.fileRootType(file_index); |
| 487 | if (file_root_type != .none) { | 487 | if (file_root_type != .none) { |
| 488 | // The namespace is already up-to-date thanks to the `updateFileNamespace` calls at the | 488 | _ = try pt.ensureTypeUpToDate(file_root_type, false); |
| 489 | // start of this update. We just have to check whether the type itself is okay! | ||
| 490 | const file_root_type_cau = pt.zcu.intern_pool.loadStructType(file_root_type).cau.unwrap().?; | ||
| 491 | return pt.ensureCauAnalyzed(file_root_type_cau); | ||
| 492 | } else { | 489 | } else { |
| 493 | return pt.semaFile(file_index); | 490 | return pt.semaFile(file_index); |
| 494 | } | 491 | } |
| ... | @@ -505,10 +502,10 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu | ... | @@ -505,10 +502,10 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 505 | const gpa = zcu.gpa; | 502 | const gpa = zcu.gpa; |
| 506 | const ip = &zcu.intern_pool; | 503 | const ip = &zcu.intern_pool; |
| 507 | 504 | ||
| 508 | const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index }); | 505 | const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); |
| 509 | const cau = ip.getCau(cau_index); | 506 | const cau = ip.getCau(cau_index); |
| 510 | 507 | ||
| 511 | //log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)}); | 508 | log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)}); |
| 512 | 509 | ||
| 513 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | 510 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 514 | 511 | ||
| ... | @@ -552,10 +549,12 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu | ... | @@ -552,10 +549,12 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 552 | // Since it does not, this must be a transitive failure. | 549 | // Since it does not, this must be a transitive failure. |
| 553 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); | 550 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); |
| 554 | } | 551 | } |
| 555 | // We treat errors as up-to-date, since those uses would just trigger a transitive error | 552 | // We treat errors as up-to-date, since those uses would just trigger a transitive error. |
| 553 | // The exception is types, since type declarations may require re-analysis if the type, e.g. its captures, changed. | ||
| 554 | const outdated = cau.owner.unwrap() == .type; | ||
| 556 | break :res .{ .{ | 555 | break :res .{ .{ |
| 557 | .invalidate_decl_val = false, | 556 | .invalidate_decl_val = outdated, |
| 558 | .invalidate_decl_ref = false, | 557 | .invalidate_decl_ref = outdated, |
| 559 | }, true }; | 558 | }, true }; |
| 560 | }, | 559 | }, |
| 561 | error.OutOfMemory => res: { | 560 | error.OutOfMemory => res: { |
| ... | @@ -610,7 +609,7 @@ fn ensureCauAnalyzedInner( | ... | @@ -610,7 +609,7 @@ fn ensureCauAnalyzedInner( |
| 610 | const ip = &zcu.intern_pool; | 609 | const ip = &zcu.intern_pool; |
| 611 | 610 | ||
| 612 | const cau = ip.getCau(cau_index); | 611 | const cau = ip.getCau(cau_index); |
| 613 | const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index }); | 612 | const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); |
| 614 | 613 | ||
| 615 | const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | 614 | const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 616 | 615 | ||
| ... | @@ -626,7 +625,6 @@ fn ensureCauAnalyzedInner( | ... | @@ -626,7 +625,6 @@ fn ensureCauAnalyzedInner( |
| 626 | // * so, it uses the same `struct` | 625 | // * so, it uses the same `struct` |
| 627 | // * but this doesn't stop it from updating the namespace! | 626 | // * but this doesn't stop it from updating the namespace! |
| 628 | // * we basically do `scanDecls`, updating the namespace as needed | 627 | // * we basically do `scanDecls`, updating the namespace as needed |
| 629 | // * TODO: optimize this to make sure we only do it once a generation i guess? | ||
| 630 | // * so everyone lived happily ever after | 628 | // * so everyone lived happily ever after |
| 631 | 629 | ||
| 632 | if (zcu.fileByIndex(inst_info.file).status != .success_zir) { | 630 | if (zcu.fileByIndex(inst_info.file).status != .success_zir) { |
| ... | @@ -646,17 +644,6 @@ fn ensureCauAnalyzedInner( | ... | @@ -646,17 +644,6 @@ fn ensureCauAnalyzedInner( |
| 646 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); | 644 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); |
| 647 | } | 645 | } |
| 648 | 646 | ||
| 649 | if (inst_info.inst == .main_struct_inst) { | ||
| 650 | // Note that this is definitely a *recreation* due to outdated, because | ||
| 651 | // this instruction indicates that `cau.owner` is a `type`, which only | ||
| 652 | // reaches here if `cau_outdated`. | ||
| 653 | try pt.recreateFileRoot(inst_info.file); | ||
| 654 | return .{ | ||
| 655 | .invalidate_decl_val = true, | ||
| 656 | .invalidate_decl_ref = true, | ||
| 657 | }; | ||
| 658 | } | ||
| 659 | |||
| 660 | const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) { | 647 | const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) { |
| 661 | .nav => |nav| ip.getNav(nav).fqn.toSlice(ip), | 648 | .nav => |nav| ip.getNav(nav).fqn.toSlice(ip), |
| 662 | .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), | 649 | .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), |
| ... | @@ -685,9 +672,9 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter | ... | @@ -685,9 +672,9 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 685 | 672 | ||
| 686 | const func = zcu.funcInfo(maybe_coerced_func_index); | 673 | const func = zcu.funcInfo(maybe_coerced_func_index); |
| 687 | 674 | ||
| 688 | //log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)}); | 675 | log.debug("ensureFuncBodyAnalyzed {d}", .{@intFromEnum(func_index)}); |
| 689 | 676 | ||
| 690 | const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index }); | 677 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); |
| 691 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or | 678 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 692 | zcu.potentially_outdated.swapRemove(anal_unit); | 679 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 693 | 680 | ||
| ... | @@ -742,7 +729,7 @@ fn ensureFuncBodyAnalyzedInner( | ... | @@ -742,7 +729,7 @@ fn ensureFuncBodyAnalyzedInner( |
| 742 | const ip = &zcu.intern_pool; | 729 | const ip = &zcu.intern_pool; |
| 743 | 730 | ||
| 744 | const func = zcu.funcInfo(func_index); | 731 | const func = zcu.funcInfo(func_index); |
| 745 | const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index }); | 732 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); |
| 746 | 733 | ||
| 747 | // Here's an interesting question: is this function actually valid? | 734 | // Here's an interesting question: is this function actually valid? |
| 748 | // Maybe the signature changed, so we'll end up creating a whole different `func` | 735 | // Maybe the signature changed, so we'll end up creating a whole different `func` |
| ... | @@ -766,7 +753,7 @@ fn ensureFuncBodyAnalyzedInner( | ... | @@ -766,7 +753,7 @@ fn ensureFuncBodyAnalyzedInner( |
| 766 | if (func_outdated) { | 753 | if (func_outdated) { |
| 767 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); // IES | 754 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); // IES |
| 768 | } | 755 | } |
| 769 | ip.removeDependenciesForDepender(gpa, InternPool.AnalUnit.wrap(.{ .func = func_index })); | 756 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index })); |
| 770 | ip.remove(pt.tid, func_index); | 757 | ip.remove(pt.tid, func_index); |
| 771 | @panic("TODO: remove orphaned function from binary"); | 758 | @panic("TODO: remove orphaned function from binary"); |
| 772 | } | 759 | } |
| ... | @@ -901,7 +888,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai | ... | @@ -901,7 +888,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai |
| 901 | "unable to codegen: {s}", | 888 | "unable to codegen: {s}", |
| 902 | .{@errorName(err)}, | 889 | .{@errorName(err)}, |
| 903 | )); | 890 | )); |
| 904 | try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .func = func_index })); | 891 | try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index })); |
| 905 | }, | 892 | }, |
| 906 | }; | 893 | }; |
| 907 | } else if (zcu.llvm_object) |llvm_object| { | 894 | } else if (zcu.llvm_object) |llvm_object| { |
| ... | @@ -982,7 +969,7 @@ fn createFileRootStruct( | ... | @@ -982,7 +969,7 @@ fn createFileRootStruct( |
| 982 | if (zcu.comp.incremental) { | 969 | if (zcu.comp.incremental) { |
| 983 | try ip.addDependency( | 970 | try ip.addDependency( |
| 984 | gpa, | 971 | gpa, |
| 985 | InternPool.AnalUnit.wrap(.{ .cau = new_cau_index }), | 972 | AnalUnit.wrap(.{ .cau = new_cau_index }), |
| 986 | .{ .src_hash = tracked_inst }, | 973 | .{ .src_hash = tracked_inst }, |
| 987 | ); | 974 | ); |
| 988 | } | 975 | } |
| ... | @@ -998,35 +985,6 @@ fn createFileRootStruct( | ... | @@ -998,35 +985,6 @@ fn createFileRootStruct( |
| 998 | return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); | 985 | return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); |
| 999 | } | 986 | } |
| 1000 | 987 | ||
| 1001 | /// Recreate the root type of a file after it becomes outdated. A new struct type | ||
| 1002 | /// is constructed at a new InternPool index, reusing the namespace for efficiency. | ||
| 1003 | fn recreateFileRoot(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | ||
| 1004 | const zcu = pt.zcu; | ||
| 1005 | const ip = &zcu.intern_pool; | ||
| 1006 | const file = zcu.fileByIndex(file_index); | ||
| 1007 | const file_root_type = zcu.fileRootType(file_index); | ||
| 1008 | const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu); | ||
| 1009 | |||
| 1010 | assert(file_root_type != .none); | ||
| 1011 | |||
| 1012 | log.debug("recreateFileRoot mod={s} sub_file_path={s}", .{ | ||
| 1013 | file.mod.fully_qualified_name, | ||
| 1014 | file.sub_file_path, | ||
| 1015 | }); | ||
| 1016 | |||
| 1017 | if (file.status != .success_zir) { | ||
| 1018 | return error.AnalysisFail; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | // Invalidate the existing type, reusing its namespace. | ||
| 1022 | const file_root_type_cau = ip.loadStructType(file_root_type).cau.unwrap().?; | ||
| 1023 | ip.removeDependenciesForDepender( | ||
| 1024 | zcu.gpa, | ||
| 1025 | InternPool.AnalUnit.wrap(.{ .cau = file_root_type_cau }), | ||
| 1026 | ); | ||
| 1027 | _ = try pt.createFileRootStruct(file_index, namespace_index, true); | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | /// Re-scan the namespace of a file's root struct type on an incremental update. | 988 | /// Re-scan the namespace of a file's root struct type on an incremental update. |
| 1031 | /// The file must have successfully populated ZIR. | 989 | /// The file must have successfully populated ZIR. |
| 1032 | /// If the file's root struct type is not populated (the file is unreferenced), nothing is done. | 990 | /// If the file's root struct type is not populated (the file is unreferenced), nothing is done. |
| ... | @@ -1060,6 +1018,7 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator. | ... | @@ -1060,6 +1018,7 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator. |
| 1060 | break :decls file.zir.bodySlice(extra_index, decls_len); | 1018 | break :decls file.zir.bodySlice(extra_index, decls_len); |
| 1061 | }; | 1019 | }; |
| 1062 | try pt.scanNamespace(namespace_index, decls); | 1020 | try pt.scanNamespace(namespace_index, decls); |
| 1021 | zcu.namespacePtr(namespace_index).generation = zcu.generation; | ||
| 1063 | } | 1022 | } |
| 1064 | 1023 | ||
| 1065 | fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | 1024 | fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| ... | @@ -1080,6 +1039,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | ... | @@ -1080,6 +1039,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 1080 | .parent = .none, | 1039 | .parent = .none, |
| 1081 | .owner_type = undefined, // set in `createFileRootStruct` | 1040 | .owner_type = undefined, // set in `createFileRootStruct` |
| 1082 | .file_scope = file_index, | 1041 | .file_scope = file_index, |
| 1042 | .generation = zcu.generation, | ||
| 1083 | }); | 1043 | }); |
| 1084 | const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false); | 1044 | const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false); |
| 1085 | errdefer zcu.intern_pool.remove(pt.tid, struct_ty); | 1045 | errdefer zcu.intern_pool.remove(pt.tid, struct_ty); |
| ... | @@ -1131,7 +1091,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { | ... | @@ -1131,7 +1091,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { |
| 1131 | const gpa = zcu.gpa; | 1091 | const gpa = zcu.gpa; |
| 1132 | const ip = &zcu.intern_pool; | 1092 | const ip = &zcu.intern_pool; |
| 1133 | 1093 | ||
| 1134 | const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index }); | 1094 | const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); |
| 1135 | 1095 | ||
| 1136 | const cau = ip.getCau(cau_index); | 1096 | const cau = ip.getCau(cau_index); |
| 1137 | const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | 1097 | const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| ... | @@ -1151,10 +1111,12 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { | ... | @@ -1151,10 +1111,12 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { |
| 1151 | // This declaration has no value so is definitely not a std.builtin type. | 1111 | // This declaration has no value so is definitely not a std.builtin type. |
| 1152 | break :ip_index .none; | 1112 | break :ip_index .none; |
| 1153 | }, | 1113 | }, |
| 1154 | .type => { | 1114 | .type => |ty| { |
| 1155 | // This is an incremental update, and this type is being re-analyzed because it is outdated. | 1115 | // This is an incremental update, and this type is being re-analyzed because it is outdated. |
| 1156 | // The type must be recreated at a new `InternPool.Index`. | 1116 | // Create a new type in its place, and mark the old one as outdated so that use sites will |
| 1157 | // Mark it outdated so that creation sites are re-analyzed. | 1117 | // be re-analyzed and discover an up-to-date type. |
| 1118 | const new_ty = try pt.ensureTypeUpToDate(ty, true); | ||
| 1119 | assert(new_ty != ty); | ||
| 1158 | return .{ | 1120 | return .{ |
| 1159 | .invalidate_decl_val = true, | 1121 | .invalidate_decl_val = true, |
| 1160 | .invalidate_decl_ref = true, | 1122 | .invalidate_decl_ref = true, |
| ... | @@ -2002,21 +1964,23 @@ const ScanDeclIter = struct { | ... | @@ -2002,21 +1964,23 @@ const ScanDeclIter = struct { |
| 2002 | 1964 | ||
| 2003 | try namespace.other_decls.append(gpa, cau); | 1965 | try namespace.other_decls.append(gpa, cau); |
| 2004 | 1966 | ||
| 2005 | // For a `comptime` declaration, whether to re-analyze is based solely on whether the | 1967 | if (existing_cau == null) { |
| 2006 | // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already. | 1968 | // For a `comptime` declaration, whether to analyze is based solely on whether the |
| 2007 | const unit = InternPool.AnalUnit.wrap(.{ .cau = cau }); | 1969 | // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already. |
| 2008 | if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| { | 1970 | const unit = AnalUnit.wrap(.{ .cau = cau }); |
| 2009 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | 1971 | if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| { |
| 2010 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | 1972 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); |
| 2011 | zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value); | 1973 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); |
| 2012 | if (kv.value == 0) { // no PO deps | 1974 | zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value); |
| 1975 | if (kv.value == 0) { // no PO deps | ||
| 1976 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); | ||
| 1977 | } | ||
| 1978 | } else if (!zcu.outdated.contains(unit)) { | ||
| 1979 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 1980 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 1981 | zcu.outdated.putAssumeCapacityNoClobber(unit, 0); | ||
| 2013 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); | 1982 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); |
| 2014 | } | 1983 | } |
| 2015 | } else if (!zcu.outdated.contains(unit)) { | ||
| 2016 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | ||
| 2017 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | ||
| 2018 | zcu.outdated.putAssumeCapacityNoClobber(unit, 0); | ||
| 2019 | zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {}); | ||
| 2020 | } | 1984 | } |
| 2021 | 1985 | ||
| 2022 | break :cau .{ cau, true }; | 1986 | break :cau .{ cau, true }; |
| ... | @@ -2027,9 +1991,6 @@ const ScanDeclIter = struct { | ... | @@ -2027,9 +1991,6 @@ const ScanDeclIter = struct { |
| 2027 | const cau, const nav = if (existing_cau) |cau_index| cau_nav: { | 1991 | const cau, const nav = if (existing_cau) |cau_index| cau_nav: { |
| 2028 | const nav_index = ip.getCau(cau_index).owner.unwrap().nav; | 1992 | const nav_index = ip.getCau(cau_index).owner.unwrap().nav; |
| 2029 | const nav = ip.getNav(nav_index); | 1993 | const nav = ip.getNav(nav_index); |
| 2030 | if (nav.name != name) { | ||
| 2031 | std.debug.panic("'{}' vs '{}'", .{ nav.name.fmt(ip), name.fmt(ip) }); | ||
| 2032 | } | ||
| 2033 | assert(nav.name == name); | 1994 | assert(nav.name == name); |
| 2034 | assert(nav.fqn == fqn); | 1995 | assert(nav.fqn == fqn); |
| 2035 | break :cau_nav .{ cau_index, nav_index }; | 1996 | break :cau_nav .{ cau_index, nav_index }; |
| ... | @@ -2078,7 +2039,7 @@ const ScanDeclIter = struct { | ... | @@ -2078,7 +2039,7 @@ const ScanDeclIter = struct { |
| 2078 | }, | 2039 | }, |
| 2079 | }; | 2040 | }; |
| 2080 | 2041 | ||
| 2081 | if (want_analysis or declaration.flags.is_export) { | 2042 | if (existing_cau == null and (want_analysis or declaration.flags.is_export)) { |
| 2082 | log.debug( | 2043 | log.debug( |
| 2083 | "scanDecl queue analyze_cau file='{s}' cau_index={d}", | 2044 | "scanDecl queue analyze_cau file='{s}' cau_index={d}", |
| 2084 | .{ namespace.fileScope(zcu).sub_file_path, cau }, | 2045 | .{ namespace.fileScope(zcu).sub_file_path, cau }, |
| ... | @@ -2098,7 +2059,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! | ... | @@ -2098,7 +2059,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2098 | const gpa = zcu.gpa; | 2059 | const gpa = zcu.gpa; |
| 2099 | const ip = &zcu.intern_pool; | 2060 | const ip = &zcu.intern_pool; |
| 2100 | 2061 | ||
| 2101 | const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index }); | 2062 | const anal_unit = AnalUnit.wrap(.{ .func = func_index }); |
| 2102 | const func = zcu.funcInfo(func_index); | 2063 | const func = zcu.funcInfo(func_index); |
| 2103 | const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail; | 2064 | const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail; |
| 2104 | const file = zcu.fileByIndex(inst_info.file); | 2065 | const file = zcu.fileByIndex(inst_info.file); |
| ... | @@ -2484,7 +2445,7 @@ fn processExportsInner( | ... | @@ -2484,7 +2445,7 @@ fn processExportsInner( |
| 2484 | const nav = ip.getNav(nav_index); | 2445 | const nav = ip.getNav(nav_index); |
| 2485 | if (zcu.failed_codegen.contains(nav_index)) break :failed true; | 2446 | if (zcu.failed_codegen.contains(nav_index)) break :failed true; |
| 2486 | if (nav.analysis_owner.unwrap()) |cau| { | 2447 | if (nav.analysis_owner.unwrap()) |cau| { |
| 2487 | const cau_unit = InternPool.AnalUnit.wrap(.{ .cau = cau }); | 2448 | const cau_unit = AnalUnit.wrap(.{ .cau = cau }); |
| 2488 | if (zcu.failed_analysis.contains(cau_unit)) break :failed true; | 2449 | if (zcu.failed_analysis.contains(cau_unit)) break :failed true; |
| 2489 | if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true; | 2450 | if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true; |
| 2490 | } | 2451 | } |
| ... | @@ -2494,7 +2455,7 @@ fn processExportsInner( | ... | @@ -2494,7 +2455,7 @@ fn processExportsInner( |
| 2494 | }; | 2455 | }; |
| 2495 | // If the value is a function, we also need to check if that function succeeded analysis. | 2456 | // If the value is a function, we also need to check if that function succeeded analysis. |
| 2496 | if (val.typeOf(zcu).zigTypeTag(zcu) == .Fn) { | 2457 | if (val.typeOf(zcu).zigTypeTag(zcu) == .Fn) { |
| 2497 | const func_unit = InternPool.AnalUnit.wrap(.{ .func = val.toIntern() }); | 2458 | const func_unit = AnalUnit.wrap(.{ .func = val.toIntern() }); |
| 2498 | if (zcu.failed_analysis.contains(func_unit)) break :failed true; | 2459 | if (zcu.failed_analysis.contains(func_unit)) break :failed true; |
| 2499 | if (zcu.transitive_failed_analysis.contains(func_unit)) break :failed true; | 2460 | if (zcu.transitive_failed_analysis.contains(func_unit)) break :failed true; |
| 2500 | } | 2461 | } |
| ... | @@ -2669,7 +2630,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void | ... | @@ -2669,7 +2630,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void |
| 2669 | .{@errorName(err)}, | 2630 | .{@errorName(err)}, |
| 2670 | )); | 2631 | )); |
| 2671 | if (nav.analysis_owner.unwrap()) |cau| { | 2632 | if (nav.analysis_owner.unwrap()) |cau| { |
| 2672 | try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalUnit.wrap(.{ .cau = cau })); | 2633 | try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .cau = cau })); |
| 2673 | } else { | 2634 | } else { |
| 2674 | // TODO: we don't have a way to indicate that this failure is retryable! | 2635 | // TODO: we don't have a way to indicate that this failure is retryable! |
| 2675 | // Since these are really rare, we could as a cop-out retry the whole build next update. | 2636 | // Since these are really rare, we could as a cop-out retry the whole build next update. |
| ... | @@ -2782,7 +2743,7 @@ pub fn reportRetryableFileError( | ... | @@ -2782,7 +2743,7 @@ pub fn reportRetryableFileError( |
| 2782 | gop.value_ptr.* = err_msg; | 2743 | gop.value_ptr.* = err_msg; |
| 2783 | } | 2744 | } |
| 2784 | 2745 | ||
| 2785 | /// Shortcut for calling `intern_pool.get`. | 2746 | ///Shortcut for calling `intern_pool.get`. |
| 2786 | pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index { | 2747 | pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index { |
| 2787 | return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key); | 2748 | return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key); |
| 2788 | } | 2749 | } |
| ... | @@ -3367,6 +3328,532 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo | ... | @@ -3367,6 +3328,532 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo |
| 3367 | return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(pt); | 3328 | return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(pt); |
| 3368 | } | 3329 | } |
| 3369 | 3330 | ||
| 3331 | /// Given a container type requiring resolution, ensures that it is up-to-date. | ||
| 3332 | /// If not, the type is recreated at a new `InternPool.Index`. | ||
| 3333 | /// The new index is returned. This is the same as the old index if the fields were up-to-date. | ||
| 3334 | /// If `already_updating` is set, assumes the type is already outdated and undergoing re-analysis rather than checking `zcu.outdated`. | ||
| 3335 | pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updating: bool) Zcu.SemaError!InternPool.Index { | ||
| 3336 | const zcu = pt.zcu; | ||
| 3337 | const ip = &zcu.intern_pool; | ||
| 3338 | switch (ip.indexToKey(ty)) { | ||
| 3339 | .struct_type => |key| { | ||
| 3340 | const struct_obj = ip.loadStructType(ty); | ||
| 3341 | const outdated = already_updating or o: { | ||
| 3342 | const anal_unit = AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? }); | ||
| 3343 | const o = zcu.outdated.swapRemove(anal_unit) or | ||
| 3344 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 3345 | if (o) { | ||
| 3346 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 3347 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | ||
| 3348 | } | ||
| 3349 | break :o o; | ||
| 3350 | }; | ||
| 3351 | if (!outdated) return ty; | ||
| 3352 | return pt.recreateStructType(ty, key, struct_obj); | ||
| 3353 | }, | ||
| 3354 | .union_type => |key| { | ||
| 3355 | const union_obj = ip.loadUnionType(ty); | ||
| 3356 | const outdated = already_updating or o: { | ||
| 3357 | const anal_unit = AnalUnit.wrap(.{ .cau = union_obj.cau }); | ||
| 3358 | const o = zcu.outdated.swapRemove(anal_unit) or | ||
| 3359 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 3360 | if (o) { | ||
| 3361 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 3362 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | ||
| 3363 | } | ||
| 3364 | break :o o; | ||
| 3365 | }; | ||
| 3366 | if (!outdated) return ty; | ||
| 3367 | return pt.recreateUnionType(ty, key, union_obj); | ||
| 3368 | }, | ||
| 3369 | .enum_type => |key| { | ||
| 3370 | const enum_obj = ip.loadEnumType(ty); | ||
| 3371 | const outdated = already_updating or o: { | ||
| 3372 | const anal_unit = AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? }); | ||
| 3373 | const o = zcu.outdated.swapRemove(anal_unit) or | ||
| 3374 | zcu.potentially_outdated.swapRemove(anal_unit); | ||
| 3375 | if (o) { | ||
| 3376 | _ = zcu.outdated_ready.swapRemove(anal_unit); | ||
| 3377 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | ||
| 3378 | } | ||
| 3379 | break :o o; | ||
| 3380 | }; | ||
| 3381 | if (!outdated) return ty; | ||
| 3382 | return pt.recreateEnumType(ty, key, enum_obj); | ||
| 3383 | }, | ||
| 3384 | .opaque_type => { | ||
| 3385 | assert(!already_updating); | ||
| 3386 | return ty; | ||
| 3387 | }, | ||
| 3388 | else => unreachable, | ||
| 3389 | } | ||
| 3390 | } | ||
| 3391 | |||
| 3392 | fn recreateStructType( | ||
| 3393 | pt: Zcu.PerThread, | ||
| 3394 | ty: InternPool.Index, | ||
| 3395 | full_key: InternPool.Key.NamespaceType, | ||
| 3396 | struct_obj: InternPool.LoadedStructType, | ||
| 3397 | ) Zcu.SemaError!InternPool.Index { | ||
| 3398 | const zcu = pt.zcu; | ||
| 3399 | const gpa = zcu.gpa; | ||
| 3400 | const ip = &zcu.intern_pool; | ||
| 3401 | |||
| 3402 | const key = switch (full_key) { | ||
| 3403 | .reified => unreachable, // never outdated | ||
| 3404 | .empty_struct => unreachable, // never outdated | ||
| 3405 | .generated_tag => unreachable, // not a struct | ||
| 3406 | .declared => |d| d, | ||
| 3407 | }; | ||
| 3408 | |||
| 3409 | if (@intFromEnum(ty) <= InternPool.static_len) { | ||
| 3410 | @panic("TODO: recreate resolved builtin type"); | ||
| 3411 | } | ||
| 3412 | |||
| 3413 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3414 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3415 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3416 | const zir = file.zir; | ||
| 3417 | |||
| 3418 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3419 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3420 | assert(extended.opcode == .struct_decl); | ||
| 3421 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | ||
| 3422 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); | ||
| 3423 | var extra_index = extra.end; | ||
| 3424 | |||
| 3425 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3426 | const captures_len = zir.extra[extra_index]; | ||
| 3427 | extra_index += 1; | ||
| 3428 | break :blk captures_len; | ||
| 3429 | } else 0; | ||
| 3430 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3431 | const fields_len = zir.extra[extra_index]; | ||
| 3432 | extra_index += 1; | ||
| 3433 | break :blk fields_len; | ||
| 3434 | } else 0; | ||
| 3435 | |||
| 3436 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; | ||
| 3437 | if (fields_len != struct_obj.field_types.len) return error.AnalysisFail; | ||
| 3438 | |||
| 3439 | // The old type will be unused, so drop its dependency information. | ||
| 3440 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = struct_obj.cau.unwrap().? })); | ||
| 3441 | |||
| 3442 | const namespace_index = struct_obj.namespace.unwrap().?; | ||
| 3443 | |||
| 3444 | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ | ||
| 3445 | .layout = small.layout, | ||
| 3446 | .fields_len = fields_len, | ||
| 3447 | .known_non_opv = small.known_non_opv, | ||
| 3448 | .requires_comptime = if (small.known_comptime_only) .yes else .unknown, | ||
| 3449 | .is_tuple = small.is_tuple, | ||
| 3450 | .any_comptime_fields = small.any_comptime_fields, | ||
| 3451 | .any_default_inits = small.any_default_inits, | ||
| 3452 | .inits_resolved = false, | ||
| 3453 | .any_aligned_fields = small.any_aligned_fields, | ||
| 3454 | .key = .{ .declared_owned_captures = .{ | ||
| 3455 | .zir_index = key.zir_index, | ||
| 3456 | .captures = key.captures.owned, | ||
| 3457 | } }, | ||
| 3458 | }, true)) { | ||
| 3459 | .wip => |wip| wip, | ||
| 3460 | .existing => unreachable, // we passed `replace_existing` | ||
| 3461 | }; | ||
| 3462 | errdefer wip_ty.cancel(ip, pt.tid); | ||
| 3463 | |||
| 3464 | wip_ty.setName(ip, struct_obj.name); | ||
| 3465 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | ||
| 3466 | try ip.addDependency( | ||
| 3467 | gpa, | ||
| 3468 | AnalUnit.wrap(.{ .cau = new_cau_index }), | ||
| 3469 | .{ .src_hash = key.zir_index }, | ||
| 3470 | ); | ||
| 3471 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | ||
| 3472 | // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive. | ||
| 3473 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | ||
| 3474 | |||
| 3475 | const new_ty = wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); | ||
| 3476 | if (inst_info.inst == .main_struct_inst) { | ||
| 3477 | // This is the root type of a file! Update the reference. | ||
| 3478 | zcu.setFileRootType(inst_info.file, new_ty); | ||
| 3479 | } | ||
| 3480 | return new_ty; | ||
| 3481 | } | ||
| 3482 | |||
| 3483 | fn recreateUnionType( | ||
| 3484 | pt: Zcu.PerThread, | ||
| 3485 | ty: InternPool.Index, | ||
| 3486 | full_key: InternPool.Key.NamespaceType, | ||
| 3487 | union_obj: InternPool.LoadedUnionType, | ||
| 3488 | ) Zcu.SemaError!InternPool.Index { | ||
| 3489 | const zcu = pt.zcu; | ||
| 3490 | const gpa = zcu.gpa; | ||
| 3491 | const ip = &zcu.intern_pool; | ||
| 3492 | |||
| 3493 | const key = switch (full_key) { | ||
| 3494 | .reified => unreachable, // never outdated | ||
| 3495 | .empty_struct => unreachable, // never outdated | ||
| 3496 | .generated_tag => unreachable, // not a union | ||
| 3497 | .declared => |d| d, | ||
| 3498 | }; | ||
| 3499 | |||
| 3500 | if (@intFromEnum(ty) <= InternPool.static_len) { | ||
| 3501 | @panic("TODO: recreate resolved builtin type"); | ||
| 3502 | } | ||
| 3503 | |||
| 3504 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3505 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3506 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3507 | const zir = file.zir; | ||
| 3508 | |||
| 3509 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3510 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3511 | assert(extended.opcode == .union_decl); | ||
| 3512 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | ||
| 3513 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | ||
| 3514 | var extra_index = extra.end; | ||
| 3515 | |||
| 3516 | extra_index += @intFromBool(small.has_tag_type); | ||
| 3517 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3518 | const captures_len = zir.extra[extra_index]; | ||
| 3519 | extra_index += 1; | ||
| 3520 | break :blk captures_len; | ||
| 3521 | } else 0; | ||
| 3522 | extra_index += @intFromBool(small.has_body_len); | ||
| 3523 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3524 | const fields_len = zir.extra[extra_index]; | ||
| 3525 | extra_index += 1; | ||
| 3526 | break :blk fields_len; | ||
| 3527 | } else 0; | ||
| 3528 | |||
| 3529 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; | ||
| 3530 | if (fields_len != union_obj.field_types.len) return error.AnalysisFail; | ||
| 3531 | |||
| 3532 | // The old type will be unused, so drop its dependency information. | ||
| 3533 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = union_obj.cau })); | ||
| 3534 | |||
| 3535 | const namespace_index = union_obj.namespace; | ||
| 3536 | |||
| 3537 | const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{ | ||
| 3538 | .flags = .{ | ||
| 3539 | .layout = small.layout, | ||
| 3540 | .status = .none, | ||
| 3541 | .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) | ||
| 3542 | .tagged | ||
| 3543 | else if (small.layout != .auto) | ||
| 3544 | .none | ||
| 3545 | else switch (true) { // TODO | ||
| 3546 | true => .safety, | ||
| 3547 | false => .none, | ||
| 3548 | }, | ||
| 3549 | .any_aligned_fields = small.any_aligned_fields, | ||
| 3550 | .requires_comptime = .unknown, | ||
| 3551 | .assumed_runtime_bits = false, | ||
| 3552 | .assumed_pointer_aligned = false, | ||
| 3553 | .alignment = .none, | ||
| 3554 | }, | ||
| 3555 | .fields_len = fields_len, | ||
| 3556 | .enum_tag_ty = .none, // set later | ||
| 3557 | .field_types = &.{}, // set later | ||
| 3558 | .field_aligns = &.{}, // set later | ||
| 3559 | .key = .{ .declared_owned_captures = .{ | ||
| 3560 | .zir_index = key.zir_index, | ||
| 3561 | .captures = key.captures.owned, | ||
| 3562 | } }, | ||
| 3563 | }, true)) { | ||
| 3564 | .wip => |wip| wip, | ||
| 3565 | .existing => unreachable, // we passed `replace_existing` | ||
| 3566 | }; | ||
| 3567 | errdefer wip_ty.cancel(ip, pt.tid); | ||
| 3568 | |||
| 3569 | wip_ty.setName(ip, union_obj.name); | ||
| 3570 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | ||
| 3571 | try ip.addDependency( | ||
| 3572 | gpa, | ||
| 3573 | AnalUnit.wrap(.{ .cau = new_cau_index }), | ||
| 3574 | .{ .src_hash = key.zir_index }, | ||
| 3575 | ); | ||
| 3576 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | ||
| 3577 | // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive. | ||
| 3578 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | ||
| 3579 | return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); | ||
| 3580 | } | ||
| 3581 | |||
| 3582 | fn recreateEnumType( | ||
| 3583 | pt: Zcu.PerThread, | ||
| 3584 | ty: InternPool.Index, | ||
| 3585 | full_key: InternPool.Key.NamespaceType, | ||
| 3586 | enum_obj: InternPool.LoadedEnumType, | ||
| 3587 | ) Zcu.SemaError!InternPool.Index { | ||
| 3588 | const zcu = pt.zcu; | ||
| 3589 | const gpa = zcu.gpa; | ||
| 3590 | const ip = &zcu.intern_pool; | ||
| 3591 | |||
| 3592 | const key = switch (full_key) { | ||
| 3593 | .reified => unreachable, // never outdated | ||
| 3594 | .empty_struct => unreachable, // never outdated | ||
| 3595 | .generated_tag => unreachable, // never outdated | ||
| 3596 | .declared => |d| d, | ||
| 3597 | }; | ||
| 3598 | |||
| 3599 | if (@intFromEnum(ty) <= InternPool.static_len) { | ||
| 3600 | @panic("TODO: recreate resolved builtin type"); | ||
| 3601 | } | ||
| 3602 | |||
| 3603 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3604 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3605 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3606 | const zir = file.zir; | ||
| 3607 | |||
| 3608 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3609 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3610 | assert(extended.opcode == .enum_decl); | ||
| 3611 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | ||
| 3612 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); | ||
| 3613 | var extra_index = extra.end; | ||
| 3614 | |||
| 3615 | const tag_type_ref = if (small.has_tag_type) blk: { | ||
| 3616 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | ||
| 3617 | extra_index += 1; | ||
| 3618 | break :blk tag_type_ref; | ||
| 3619 | } else .none; | ||
| 3620 | |||
| 3621 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3622 | const captures_len = zir.extra[extra_index]; | ||
| 3623 | extra_index += 1; | ||
| 3624 | break :blk captures_len; | ||
| 3625 | } else 0; | ||
| 3626 | |||
| 3627 | const body_len = if (small.has_body_len) blk: { | ||
| 3628 | const body_len = zir.extra[extra_index]; | ||
| 3629 | extra_index += 1; | ||
| 3630 | break :blk body_len; | ||
| 3631 | } else 0; | ||
| 3632 | |||
| 3633 | const fields_len = if (small.has_fields_len) blk: { | ||
| 3634 | const fields_len = zir.extra[extra_index]; | ||
| 3635 | extra_index += 1; | ||
| 3636 | break :blk fields_len; | ||
| 3637 | } else 0; | ||
| 3638 | |||
| 3639 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3640 | const decls_len = zir.extra[extra_index]; | ||
| 3641 | extra_index += 1; | ||
| 3642 | break :blk decls_len; | ||
| 3643 | } else 0; | ||
| 3644 | |||
| 3645 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; | ||
| 3646 | if (fields_len != enum_obj.names.len) return error.AnalysisFail; | ||
| 3647 | |||
| 3648 | extra_index += captures_len; | ||
| 3649 | extra_index += decls_len; | ||
| 3650 | |||
| 3651 | const body = zir.bodySlice(extra_index, body_len); | ||
| 3652 | extra_index += body.len; | ||
| 3653 | |||
| 3654 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | ||
| 3655 | const body_end = extra_index; | ||
| 3656 | extra_index += bit_bags_count; | ||
| 3657 | |||
| 3658 | const any_values = for (zir.extra[body_end..][0..bit_bags_count]) |bag| { | ||
| 3659 | if (bag != 0) break true; | ||
| 3660 | } else false; | ||
| 3661 | |||
| 3662 | // The old type will be unused, so drop its dependency information. | ||
| 3663 | ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? })); | ||
| 3664 | |||
| 3665 | const namespace_index = enum_obj.namespace; | ||
| 3666 | |||
| 3667 | const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{ | ||
| 3668 | .has_values = any_values, | ||
| 3669 | .tag_mode = if (small.nonexhaustive) | ||
| 3670 | .nonexhaustive | ||
| 3671 | else if (tag_type_ref == .none) | ||
| 3672 | .auto | ||
| 3673 | else | ||
| 3674 | .explicit, | ||
| 3675 | .fields_len = fields_len, | ||
| 3676 | .key = .{ .declared_owned_captures = .{ | ||
| 3677 | .zir_index = key.zir_index, | ||
| 3678 | .captures = key.captures.owned, | ||
| 3679 | } }, | ||
| 3680 | }, true)) { | ||
| 3681 | .wip => |wip| wip, | ||
| 3682 | .existing => unreachable, // we passed `replace_existing` | ||
| 3683 | }; | ||
| 3684 | var done = true; | ||
| 3685 | errdefer if (!done) wip_ty.cancel(ip, pt.tid); | ||
| 3686 | |||
| 3687 | wip_ty.setName(ip, enum_obj.name); | ||
| 3688 | |||
| 3689 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | ||
| 3690 | |||
| 3691 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | ||
| 3692 | // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive. | ||
| 3693 | |||
| 3694 | wip_ty.prepare(ip, new_cau_index, namespace_index); | ||
| 3695 | done = true; | ||
| 3696 | |||
| 3697 | Sema.resolveDeclaredEnum( | ||
| 3698 | pt, | ||
| 3699 | wip_ty, | ||
| 3700 | inst_info.inst, | ||
| 3701 | key.zir_index, | ||
| 3702 | namespace_index, | ||
| 3703 | enum_obj.name, | ||
| 3704 | new_cau_index, | ||
| 3705 | small, | ||
| 3706 | body, | ||
| 3707 | tag_type_ref, | ||
| 3708 | any_values, | ||
| 3709 | fields_len, | ||
| 3710 | zir, | ||
| 3711 | body_end, | ||
| 3712 | ) catch |err| switch (err) { | ||
| 3713 | error.GenericPoison => unreachable, | ||
| 3714 | error.ComptimeBreak => unreachable, | ||
| 3715 | error.ComptimeReturn => unreachable, | ||
| 3716 | error.AnalysisFail, error.OutOfMemory => |e| return e, | ||
| 3717 | }; | ||
| 3718 | |||
| 3719 | return wip_ty.index; | ||
| 3720 | } | ||
| 3721 | |||
| 3722 | /// Given a namespace, re-scan its declarations from the type definition if they have not | ||
| 3723 | /// yet been re-scanned on this update. | ||
| 3724 | /// If the type declaration instruction has been lost, returns `error.AnalysisFail`. | ||
| 3725 | /// This will effectively short-circuit the caller, which will be semantic analysis of a | ||
| 3726 | /// guaranteed-unreferenced `AnalUnit`, to trigger a transitive analysis error. | ||
| 3727 | pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace.Index) Zcu.SemaError!void { | ||
| 3728 | const zcu = pt.zcu; | ||
| 3729 | const ip = &zcu.intern_pool; | ||
| 3730 | const namespace = zcu.namespacePtr(namespace_index); | ||
| 3731 | |||
| 3732 | if (namespace.generation == zcu.generation) return; | ||
| 3733 | |||
| 3734 | const Container = enum { @"struct", @"union", @"enum", @"opaque" }; | ||
| 3735 | const container: Container, const full_key = switch (ip.indexToKey(namespace.owner_type)) { | ||
| 3736 | .struct_type => |k| .{ .@"struct", k }, | ||
| 3737 | .union_type => |k| .{ .@"union", k }, | ||
| 3738 | .enum_type => |k| .{ .@"enum", k }, | ||
| 3739 | .opaque_type => |k| .{ .@"opaque", k }, | ||
| 3740 | else => unreachable, // namespaces are owned by a container type | ||
| 3741 | }; | ||
| 3742 | |||
| 3743 | const key = switch (full_key) { | ||
| 3744 | .reified, .empty_struct, .generated_tag => { | ||
| 3745 | // Namespace always empty, so up-to-date. | ||
| 3746 | namespace.generation = zcu.generation; | ||
| 3747 | return; | ||
| 3748 | }, | ||
| 3749 | .declared => |d| d, | ||
| 3750 | }; | ||
| 3751 | |||
| 3752 | // Namespace outdated -- re-scan the type if necessary. | ||
| 3753 | |||
| 3754 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; | ||
| 3755 | const file = zcu.fileByIndex(inst_info.file); | ||
| 3756 | if (file.status != .success_zir) return error.AnalysisFail; | ||
| 3757 | const zir = file.zir; | ||
| 3758 | |||
| 3759 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | ||
| 3760 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | ||
| 3761 | |||
| 3762 | const decls = switch (container) { | ||
| 3763 | .@"struct" => decls: { | ||
| 3764 | assert(extended.opcode == .struct_decl); | ||
| 3765 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | ||
| 3766 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); | ||
| 3767 | var extra_index = extra.end; | ||
| 3768 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3769 | const captures_len = zir.extra[extra_index]; | ||
| 3770 | extra_index += 1; | ||
| 3771 | break :blk captures_len; | ||
| 3772 | } else 0; | ||
| 3773 | extra_index += @intFromBool(small.has_fields_len); | ||
| 3774 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3775 | const decls_len = zir.extra[extra_index]; | ||
| 3776 | extra_index += 1; | ||
| 3777 | break :blk decls_len; | ||
| 3778 | } else 0; | ||
| 3779 | extra_index += captures_len; | ||
| 3780 | if (small.has_backing_int) { | ||
| 3781 | const backing_int_body_len = zir.extra[extra_index]; | ||
| 3782 | extra_index += 1; // backing_int_body_len | ||
| 3783 | if (backing_int_body_len == 0) { | ||
| 3784 | extra_index += 1; // backing_int_ref | ||
| 3785 | } else { | ||
| 3786 | extra_index += backing_int_body_len; // backing_int_body_inst | ||
| 3787 | } | ||
| 3788 | } | ||
| 3789 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3790 | }, | ||
| 3791 | .@"union" => decls: { | ||
| 3792 | assert(extended.opcode == .union_decl); | ||
| 3793 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | ||
| 3794 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | ||
| 3795 | var extra_index = extra.end; | ||
| 3796 | extra_index += @intFromBool(small.has_tag_type); | ||
| 3797 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3798 | const captures_len = zir.extra[extra_index]; | ||
| 3799 | extra_index += 1; | ||
| 3800 | break :blk captures_len; | ||
| 3801 | } else 0; | ||
| 3802 | extra_index += @intFromBool(small.has_body_len); | ||
| 3803 | extra_index += @intFromBool(small.has_fields_len); | ||
| 3804 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3805 | const decls_len = zir.extra[extra_index]; | ||
| 3806 | extra_index += 1; | ||
| 3807 | break :blk decls_len; | ||
| 3808 | } else 0; | ||
| 3809 | extra_index += captures_len; | ||
| 3810 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3811 | }, | ||
| 3812 | .@"enum" => decls: { | ||
| 3813 | assert(extended.opcode == .enum_decl); | ||
| 3814 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | ||
| 3815 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); | ||
| 3816 | var extra_index = extra.end; | ||
| 3817 | extra_index += @intFromBool(small.has_tag_type); | ||
| 3818 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3819 | const captures_len = zir.extra[extra_index]; | ||
| 3820 | extra_index += 1; | ||
| 3821 | break :blk captures_len; | ||
| 3822 | } else 0; | ||
| 3823 | extra_index += @intFromBool(small.has_body_len); | ||
| 3824 | extra_index += @intFromBool(small.has_fields_len); | ||
| 3825 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3826 | const decls_len = zir.extra[extra_index]; | ||
| 3827 | extra_index += 1; | ||
| 3828 | break :blk decls_len; | ||
| 3829 | } else 0; | ||
| 3830 | extra_index += captures_len; | ||
| 3831 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3832 | }, | ||
| 3833 | .@"opaque" => decls: { | ||
| 3834 | assert(extended.opcode == .opaque_decl); | ||
| 3835 | const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small); | ||
| 3836 | const extra = zir.extraData(Zir.Inst.OpaqueDecl, extended.operand); | ||
| 3837 | var extra_index = extra.end; | ||
| 3838 | const captures_len = if (small.has_captures_len) blk: { | ||
| 3839 | const captures_len = zir.extra[extra_index]; | ||
| 3840 | extra_index += 1; | ||
| 3841 | break :blk captures_len; | ||
| 3842 | } else 0; | ||
| 3843 | const decls_len = if (small.has_decls_len) blk: { | ||
| 3844 | const decls_len = zir.extra[extra_index]; | ||
| 3845 | extra_index += 1; | ||
| 3846 | break :blk decls_len; | ||
| 3847 | } else 0; | ||
| 3848 | extra_index += captures_len; | ||
| 3849 | break :decls zir.bodySlice(extra_index, decls_len); | ||
| 3850 | }, | ||
| 3851 | }; | ||
| 3852 | |||
| 3853 | try pt.scanNamespace(namespace_index, decls); | ||
| 3854 | namespace.generation = zcu.generation; | ||
| 3855 | } | ||
| 3856 | |||
| 3370 | const Air = @import("../Air.zig"); | 3857 | const Air = @import("../Air.zig"); |
| 3371 | const Allocator = std.mem.Allocator; | 3858 | const Allocator = std.mem.Allocator; |
| 3372 | const assert = std.debug.assert; | 3859 | const assert = std.debug.assert; |
| ... | @@ -3379,6 +3866,7 @@ const builtin = @import("builtin"); | ... | @@ -3379,6 +3866,7 @@ const builtin = @import("builtin"); |
| 3379 | const Cache = std.Build.Cache; | 3866 | const Cache = std.Build.Cache; |
| 3380 | const dev = @import("../dev.zig"); | 3867 | const dev = @import("../dev.zig"); |
| 3381 | const InternPool = @import("../InternPool.zig"); | 3868 | const InternPool = @import("../InternPool.zig"); |
| 3869 | const AnalUnit = InternPool.AnalUnit; | ||
| 3382 | const isUpDir = @import("../introspect.zig").isUpDir; | 3870 | const isUpDir = @import("../introspect.zig").isUpDir; |
| 3383 | const Liveness = @import("../Liveness.zig"); | 3871 | const Liveness = @import("../Liveness.zig"); |
| 3384 | const log = std.log.scoped(.zcu); | 3872 | const log = std.log.scoped(.zcu); |