authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-22 21:16:29+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-24 02:18:41+00:00
log40aafcd6a85d3c517f445f17149c17523c832420
treeb8e1a5361c6a20ce9e3ba568b61b199aff1c8f13
parent18362ebe13ece2ea7c4f57303ec4687f55d2dba5
signature Commit is signed but in an unrecognized format.

compiler: remove Cau

The `Cau` abstraction originated from noting that one of the two primary roles of the legacy `Decl` type was to be the subject of comptime semantic analysis. However, the data stored in `Cau` has always had some level of redundancy. While preparing for #131, I went to remove that redundany, and realised that `Cau` now had exactly one field: `owner`. This led me to conclude that `Cau` is, in fact, an unnecessary level of abstraction over what are in reality *fundamentally different* kinds of analysis unit (`AnalUnit`). Types, `Nav` vals, and `comptime` declarations are all analyzed in different ways, and trying to treat them as the same thing is counterproductive! So, these 3 cases are now different alternatives in `AnalUnit`. To avoid stealing bits from `InternPool`-based IDs, which are already a little starved for bits due to the sharding datastructures, `AnalUnit` is expanded to 64 bits (30 of which are currently unused). This doesn't impact memory usage too much by default, because we don't store `AnalUnit`s all too often; however, we do store them a lot under `-fincremental`, so a non-trivial bump to peak RSS can be observed there. This will be improved in the future when I made `InternPool.DepEntry` less memory-inefficient. `Zcu.PerThread.ensureCauAnalyzed` is split into 3 functions, for each of the 3 new types of `AnalUnit`. The new logic is much easier to understand, because it avoids conflating the logic of these fundamentally different cases.

7 files changed, 1321 insertions(+), 1524 deletions(-)

src/Compilation.zig+45-28
......@@ -348,12 +348,15 @@ const Job = union(enum) {
348348 /// Corresponds to the task in `link.Task`.
349349 /// Only needed for backends that haven't yet been updated to not race against Sema.
350350 codegen_type: InternPool.Index,
351 /// The `Cau` must be semantically analyzed (and possibly export itself).
351 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
352 /// This may be its first time being analyzed, or it may be outdated.
353 /// If the unit is a function, a `codegen_func` job will then be queued.
354 analyze_comptime_unit: InternPool.AnalUnit,
355 /// This function must be semantically analyzed.
352356 /// This may be its first time being analyzed, or it may be outdated.
353 analyze_cau: InternPool.Cau.Index,
354 /// Analyze the body of a runtime function.
355357 /// After analysis, a `codegen_func` job will be queued.
356358 /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
359 /// This job is separate from `analyze_comptime_unit` because it has a different priority.
357360 analyze_func: InternPool.Index,
358361 /// The main source file for the module needs to be analyzed.
359362 analyze_mod: *Package.Module,
......@@ -3141,8 +3144,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
31413144 }
31423145
31433146 const file_index = switch (anal_unit.unwrap()) {
3144 .cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope,
3145 .func => |ip_index| (zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip) orelse continue).file,
3147 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
3148 .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
3149 .type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
3150 .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
31463151 };
31473152
31483153 // Skip errors for AnalUnits within files that had a parse failure.
......@@ -3374,11 +3379,9 @@ pub fn addModuleErrorMsg(
33743379 const rt_file_path = try src.file_scope.fullPath(gpa);
33753380 defer gpa.free(rt_file_path);
33763381 const name = switch (ref.referencer.unwrap()) {
3377 .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
3378 .nav => |nav| ip.getNav(nav).name.toSlice(ip),
3379 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
3380 .none => "comptime",
3381 },
3382 .@"comptime" => "comptime",
3383 .nav_val => |nav| ip.getNav(nav).name.toSlice(ip),
3384 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
33823385 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
33833386 };
33843387 try ref_traces.append(gpa, .{
......@@ -3641,10 +3644,13 @@ fn performAllTheWorkInner(
36413644 // If there's no work queued, check if there's anything outdated
36423645 // which we need to work on, and queue it if so.
36433646 if (try zcu.findOutdatedToAnalyze()) |outdated| {
3644 switch (outdated.unwrap()) {
3645 .cau => |cau| try comp.queueJob(.{ .analyze_cau = cau }),
3646 .func => |func| try comp.queueJob(.{ .analyze_func = func }),
3647 }
3647 try comp.queueJob(switch (outdated.unwrap()) {
3648 .func => |f| .{ .analyze_func = f },
3649 .@"comptime",
3650 .nav_val,
3651 .type,
3652 => .{ .analyze_comptime_unit = outdated },
3653 });
36483654 continue;
36493655 }
36503656 }
......@@ -3667,8 +3673,8 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
36673673 .codegen_nav => |nav_index| {
36683674 const zcu = comp.zcu.?;
36693675 const nav = zcu.intern_pool.getNav(nav_index);
3670 if (nav.analysis_owner.unwrap()) |cau| {
3671 const unit = InternPool.AnalUnit.wrap(.{ .cau = cau });
3676 if (nav.analysis != null) {
3677 const unit: InternPool.AnalUnit = .wrap(.{ .nav_val = nav_index });
36723678 if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) {
36733679 return;
36743680 }
......@@ -3688,36 +3694,47 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
36883694
36893695 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
36903696 defer pt.deactivate();
3691 pt.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
3692 error.OutOfMemory => return error.OutOfMemory,
3697
3698 pt.ensureFuncBodyUpToDate(func) catch |err| switch (err) {
3699 error.OutOfMemory => |e| return e,
36933700 error.AnalysisFail => return,
36943701 };
36953702 },
3696 .analyze_cau => |cau_index| {
3703 .analyze_comptime_unit => |unit| {
3704 const named_frame = tracy.namedFrame("analyze_comptime_unit");
3705 defer named_frame.end();
3706
36973707 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
36983708 defer pt.deactivate();
3699 pt.ensureCauAnalyzed(cau_index) catch |err| switch (err) {
3700 error.OutOfMemory => return error.OutOfMemory,
3709
3710 const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
3711 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
3712 .nav_val => |nav| pt.ensureNavValUpToDate(nav),
3713 .type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,
3714 .func => unreachable,
3715 };
3716 maybe_err catch |err| switch (err) {
3717 error.OutOfMemory => |e| return e,
37013718 error.AnalysisFail => return,
37023719 };
3720
37033721 queue_test_analysis: {
37043722 if (!comp.config.is_test) break :queue_test_analysis;
3723 const nav = switch (unit.unwrap()) {
3724 .nav_val => |nav| nav,
3725 else => break :queue_test_analysis,
3726 };
37053727
37063728 // Check if this is a test function.
37073729 const ip = &pt.zcu.intern_pool;
3708 const cau = ip.getCau(cau_index);
3709 const nav_index = switch (cau.owner.unwrap()) {
3710 .none, .type => break :queue_test_analysis,
3711 .nav => |nav| nav,
3712 };
3713 if (!pt.zcu.test_functions.contains(nav_index)) {
3730 if (!pt.zcu.test_functions.contains(nav)) {
37143731 break :queue_test_analysis;
37153732 }
37163733
37173734 // Tests are always emitted in test binaries. The decl_refs are created by
37183735 // Zcu.populateTestFunctions, but this will not queue body analysis, so do
37193736 // that now.
3720 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav_index).status.resolved.val);
3737 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.resolved.val);
37213738 }
37223739 },
37233740 .resolve_type_fully => |ty| {
src/InternPool.zig+154-275
......@@ -363,33 +363,53 @@ pub fn rehashTrackedInsts(
363363}
364364
365365/// Analysis Unit. Represents a single entity which undergoes semantic analysis.
366/// This is either a `Cau` or a runtime function.
367/// The LSB is used as a tag bit.
368366/// This is the "source" of an incremental dependency edge.
369pub const AnalUnit = packed struct(u32) {
370 kind: enum(u1) { cau, func },
371 index: u31,
372 pub const Unwrapped = union(enum) {
373 cau: Cau.Index,
367pub const AnalUnit = packed struct(u64) {
368 kind: Kind,
369 id: u32,
370
371 pub const Kind = enum(u32) {
372 @"comptime",
373 nav_val,
374 type,
375 func,
376 };
377
378 pub const Unwrapped = union(Kind) {
379 /// This `AnalUnit` analyzes the body of the given `comptime` declaration.
380 @"comptime": ComptimeUnit.Id,
381 /// This `AnalUnit` resolves the value of the given `Nav`.
382 nav_val: Nav.Index,
383 /// This `AnalUnit` resolves the given `struct`/`union`/`enum` type.
384 /// Generated tag enums are never used here (they do not undergo type resolution).
385 type: InternPool.Index,
386 /// This `AnalUnit` analyzes the body of the given runtime function.
374387 func: InternPool.Index,
375388 };
376 pub fn unwrap(as: AnalUnit) Unwrapped {
377 return switch (as.kind) {
378 .cau => .{ .cau = @enumFromInt(as.index) },
379 .func => .{ .func = @enumFromInt(as.index) },
389
390 pub fn unwrap(au: AnalUnit) Unwrapped {
391 return switch (au.kind) {
392 inline else => |tag| @unionInit(
393 Unwrapped,
394 @tagName(tag),
395 @enumFromInt(au.id),
396 ),
380397 };
381398 }
382399 pub fn wrap(raw: Unwrapped) AnalUnit {
383400 return switch (raw) {
384 .cau => |cau| .{ .kind = .cau, .index = @intCast(@intFromEnum(cau)) },
385 .func => |func| .{ .kind = .func, .index = @intCast(@intFromEnum(func)) },
401 inline else => |id, tag| .{
402 .kind = tag,
403 .id = @intFromEnum(id),
404 },
386405 };
387406 }
407
388408 pub fn toOptional(as: AnalUnit) Optional {
389 return @enumFromInt(@as(u32, @bitCast(as)));
409 return @enumFromInt(@as(u64, @bitCast(as)));
390410 }
391 pub const Optional = enum(u32) {
392 none = std.math.maxInt(u32),
411 pub const Optional = enum(u64) {
412 none = std.math.maxInt(u64),
393413 _,
394414 pub fn unwrap(opt: Optional) ?AnalUnit {
395415 return switch (opt) {
......@@ -400,97 +420,30 @@ pub const AnalUnit = packed struct(u32) {
400420 };
401421};
402422
403/// Comptime Analysis Unit. This is the "subject" of semantic analysis where the root context is
404/// comptime; every `Sema` is owned by either a `Cau` or a runtime function (see `AnalUnit`).
405/// The state stored here is immutable.
406///
407/// * Every ZIR `declaration` has a `Cau` (post-instantiation) to analyze the declaration body.
408/// * Every `struct`, `union`, and `enum` has a `Cau` for type resolution.
409///
410/// The analysis status of a `Cau` is known only from state in `Zcu`.
411/// An entry in `Zcu.failed_analysis` indicates an analysis failure with associated error message.
412/// An entry in `Zcu.transitive_failed_analysis` indicates a transitive analysis failure.
413///
414/// 12 bytes.
415pub const Cau = struct {
416 /// The `declaration`, `struct_decl`, `enum_decl`, or `union_decl` instruction which this `Cau` analyzes.
423pub const ComptimeUnit = extern struct {
417424 zir_index: TrackedInst.Index,
418 /// The namespace which this `Cau` should be analyzed within.
419425 namespace: NamespaceIndex,
420 /// This field essentially tells us what to do with the information resulting from
421 /// semantic analysis. See `Owner.Unwrapped` for details.
422 owner: Owner,
423
424 /// See `Owner.Unwrapped` for details. In terms of representation, the `InternPool.Index`
425 /// or `Nav.Index` is cast to a `u31` and stored in `index`. As a special case, if
426 /// `@as(u32, @bitCast(owner)) == 0xFFFF_FFFF`, then the value is treated as `.none`.
427 pub const Owner = packed struct(u32) {
428 kind: enum(u1) { type, nav },
429 index: u31,
430
431 pub const Unwrapped = union(enum) {
432 /// This `Cau` exists in isolation. It is a global `comptime` declaration, or (TODO ANYTHING ELSE?).
433 /// After semantic analysis completes, the result is discarded.
434 none,
435 /// This `Cau` is owned by the given type for type resolution.
436 /// This is a `struct`, `union`, or `enum` type.
437 type: InternPool.Index,
438 /// This `Cau` is owned by the given `Nav` to resolve its value.
439 /// When analyzing the `Cau`, the resulting value is stored as the value of this `Nav`.
440 nav: Nav.Index,
441 };
442426
443 pub fn unwrap(owner: Owner) Unwrapped {
444 if (@as(u32, @bitCast(owner)) == std.math.maxInt(u32)) {
445 return .none;
446 }
447 return switch (owner.kind) {
448 .type => .{ .type = @enumFromInt(owner.index) },
449 .nav => .{ .nav = @enumFromInt(owner.index) },
450 };
451 }
452
453 fn wrap(raw: Unwrapped) Owner {
454 return switch (raw) {
455 .none => @bitCast(@as(u32, std.math.maxInt(u32))),
456 .type => |ty| .{ .kind = .type, .index = @intCast(@intFromEnum(ty)) },
457 .nav => |nav| .{ .kind = .nav, .index = @intCast(@intFromEnum(nav)) },
458 };
459 }
460 };
427 comptime {
428 assert(std.meta.hasUniqueRepresentation(ComptimeUnit));
429 }
461430
462 pub const Index = enum(u32) {
431 pub const Id = enum(u32) {
463432 _,
464 pub const Optional = enum(u32) {
465 none = std.math.maxInt(u32),
466 _,
467 pub fn unwrap(opt: Optional) ?Cau.Index {
468 return switch (opt) {
469 .none => null,
470 _ => @enumFromInt(@intFromEnum(opt)),
471 };
472 }
473
474 const debug_state = InternPool.debug_state;
475 };
476 pub fn toOptional(i: Cau.Index) Optional {
477 return @enumFromInt(@intFromEnum(i));
478 }
479433 const Unwrapped = struct {
480434 tid: Zcu.PerThread.Id,
481435 index: u32,
482
483 fn wrap(unwrapped: Unwrapped, ip: *const InternPool) Cau.Index {
436 fn wrap(unwrapped: Unwrapped, ip: *const InternPool) ComptimeUnit.Id {
484437 assert(@intFromEnum(unwrapped.tid) <= ip.getTidMask());
485 assert(unwrapped.index <= ip.getIndexMask(u31));
486 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_31 |
438 assert(unwrapped.index <= ip.getIndexMask(u32));
439 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_32 |
487440 unwrapped.index);
488441 }
489442 };
490 fn unwrap(cau_index: Cau.Index, ip: *const InternPool) Unwrapped {
443 fn unwrap(id: Id, ip: *const InternPool) Unwrapped {
491444 return .{
492 .tid = @enumFromInt(@intFromEnum(cau_index) >> ip.tid_shift_31 & ip.getTidMask()),
493 .index = @intFromEnum(cau_index) & ip.getIndexMask(u31),
445 .tid = @enumFromInt(@intFromEnum(id) >> ip.tid_shift_32 & ip.getTidMask()),
446 .index = @intFromEnum(id) & ip.getIndexMask(u31),
494447 };
495448 }
496449
......@@ -507,6 +460,11 @@ pub const Cau = struct {
507460/// * Generic instances have a `Nav` corresponding to the instantiated function.
508461/// * `@extern` calls create a `Nav` whose value is a `.@"extern"`.
509462///
463/// This data structure is optimized for the `analysis_info != null` case, because this is much more
464/// common in practice; the other case is used only for externs and for generic instances. At the time
465/// of writing, in the compiler itself, around 74% of all `Nav`s have `analysis_info != null`.
466/// (Specifically, 104225 / 140923)
467///
510468/// `Nav.Repr` is the in-memory representation.
511469pub const Nav = struct {
512470 /// The unqualified name of this `Nav`. Namespace lookups use this name, and error messages may use it.
......@@ -514,13 +472,16 @@ pub const Nav = struct {
514472 name: NullTerminatedString,
515473 /// The fully-qualified name of this `Nav`.
516474 fqn: NullTerminatedString,
517 /// If the value of this `Nav` is resolved by semantic analysis, it is within this `Cau`.
518 /// If this is `.none`, then `status == .resolved` always.
519 analysis_owner: Cau.Index.Optional,
475 /// This field is populated iff this `Nav` is resolved by semantic analysis.
476 /// If this is `null`, then `status == .resolved` always.
477 analysis: ?struct {
478 namespace: NamespaceIndex,
479 zir_index: TrackedInst.Index,
480 },
520481 /// TODO: this is a hack! If #20663 isn't accepted, let's figure out something a bit better.
521482 is_usingnamespace: bool,
522483 status: union(enum) {
523 /// This `Nav` is pending semantic analysis through `analysis_owner`.
484 /// This `Nav` is pending semantic analysis.
524485 unresolved,
525486 /// The value of this `Nav` is resolved.
526487 resolved: struct {
......@@ -544,17 +505,16 @@ pub const Nav = struct {
544505 /// Get the ZIR instruction corresponding to this `Nav`, used to resolve source locations.
545506 /// This is a `declaration`.
546507 pub fn srcInst(nav: Nav, ip: *const InternPool) TrackedInst.Index {
547 if (nav.analysis_owner.unwrap()) |cau| {
548 return ip.getCau(cau).zir_index;
508 if (nav.analysis) |a| {
509 return a.zir_index;
549510 }
550 // A `Nav` with no corresponding `Cau` always has a resolved value.
511 // A `Nav` which does not undergo analysis always has a resolved value.
551512 return switch (ip.indexToKey(nav.status.resolved.val)) {
552513 .func => |func| {
553 // Since there was no `analysis_owner`, this must be an instantiation.
554 // Go up to the generic owner and consult *its* `analysis_owner`.
514 // Since `analysis` was not populated, this must be an instantiation.
515 // Go up to the generic owner and consult *its* `analysis` field.
555516 const go_nav = ip.getNav(ip.indexToKey(func.generic_owner).func.owner_nav);
556 const go_cau = ip.getCau(go_nav.analysis_owner.unwrap().?);
557 return go_cau.zir_index;
517 return go_nav.analysis.?.zir_index;
558518 },
559519 .@"extern" => |@"extern"| @"extern".zir_index, // extern / @extern
560520 else => unreachable,
......@@ -600,11 +560,13 @@ pub const Nav = struct {
600560 };
601561
602562 /// The compact in-memory representation of a `Nav`.
603 /// 18 bytes.
563 /// 26 bytes.
604564 const Repr = struct {
605565 name: NullTerminatedString,
606566 fqn: NullTerminatedString,
607 analysis_owner: Cau.Index.Optional,
567 // The following 1 fields are either both populated, or both `.none`.
568 analysis_namespace: OptionalNamespaceIndex,
569 analysis_zir_index: TrackedInst.Index.Optional,
608570 /// Populated only if `bits.status == .resolved`.
609571 val: InternPool.Index,
610572 /// Populated only if `bits.status == .resolved`.
......@@ -625,7 +587,13 @@ pub const Nav = struct {
625587 return .{
626588 .name = repr.name,
627589 .fqn = repr.fqn,
628 .analysis_owner = repr.analysis_owner,
590 .analysis = if (repr.analysis_namespace.unwrap()) |namespace| .{
591 .namespace = namespace,
592 .zir_index = repr.analysis_zir_index.unwrap().?,
593 } else a: {
594 assert(repr.analysis_zir_index == .none);
595 break :a null;
596 },
629597 .is_usingnamespace = repr.bits.is_usingnamespace,
630598 .status = switch (repr.bits.status) {
631599 .unresolved => .unresolved,
......@@ -646,7 +614,8 @@ pub const Nav = struct {
646614 return .{
647615 .name = nav.name,
648616 .fqn = nav.fqn,
649 .analysis_owner = nav.analysis_owner,
617 .analysis_namespace = if (nav.analysis) |a| a.namespace.toOptional() else .none,
618 .analysis_zir_index = if (nav.analysis) |a| a.zir_index.toOptional() else .none,
650619 .val = switch (nav.status) {
651620 .unresolved => .none,
652621 .resolved => |r| r.val,
......@@ -862,8 +831,8 @@ const Local = struct {
862831 tracked_insts: ListMutate,
863832 files: ListMutate,
864833 maps: ListMutate,
865 caus: ListMutate,
866834 navs: ListMutate,
835 comptime_units: ListMutate,
867836
868837 namespaces: BucketListMutate,
869838 } align(std.atomic.cache_line),
......@@ -876,8 +845,8 @@ const Local = struct {
876845 tracked_insts: TrackedInsts,
877846 files: List(File),
878847 maps: Maps,
879 caus: Caus,
880848 navs: Navs,
849 comptime_units: ComptimeUnits,
881850
882851 namespaces: Namespaces,
883852
......@@ -899,8 +868,8 @@ const Local = struct {
899868 const Strings = List(struct { u8 });
900869 const TrackedInsts = List(struct { TrackedInst.MaybeLost });
901870 const Maps = List(struct { FieldMap });
902 const Caus = List(struct { Cau });
903871 const Navs = List(Nav.Repr);
872 const ComptimeUnits = List(struct { ComptimeUnit });
904873
905874 const namespaces_bucket_width = 8;
906875 const namespaces_bucket_mask = (1 << namespaces_bucket_width) - 1;
......@@ -1275,21 +1244,21 @@ const Local = struct {
12751244 };
12761245 }
12771246
1278 pub fn getMutableCaus(local: *Local, gpa: Allocator) Caus.Mutable {
1247 pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable {
12791248 return .{
12801249 .gpa = gpa,
12811250 .arena = &local.mutate.arena,
1282 .mutate = &local.mutate.caus,
1283 .list = &local.shared.caus,
1251 .mutate = &local.mutate.navs,
1252 .list = &local.shared.navs,
12841253 };
12851254 }
12861255
1287 pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable {
1256 pub fn getMutableComptimeUnits(local: *Local, gpa: Allocator) ComptimeUnits.Mutable {
12881257 return .{
12891258 .gpa = gpa,
12901259 .arena = &local.mutate.arena,
1291 .mutate = &local.mutate.navs,
1292 .list = &local.shared.navs,
1260 .mutate = &local.mutate.comptime_units,
1261 .list = &local.shared.comptime_units,
12931262 };
12941263 }
12951264
......@@ -3052,8 +3021,6 @@ pub const LoadedUnionType = struct {
30523021 // TODO: the non-fqn will be needed by the new dwarf structure
30533022 /// The name of this union type.
30543023 name: NullTerminatedString,
3055 /// The `Cau` within which type resolution occurs.
3056 cau: Cau.Index,
30573024 /// Represents the declarations inside this union.
30583025 namespace: NamespaceIndex,
30593026 /// The enum tag type.
......@@ -3370,7 +3337,6 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
33703337 .tid = unwrapped_index.tid,
33713338 .extra_index = data,
33723339 .name = type_union.data.name,
3373 .cau = type_union.data.cau,
33743340 .namespace = type_union.data.namespace,
33753341 .enum_tag_ty = type_union.data.tag_ty,
33763342 .field_types = field_types,
......@@ -3387,8 +3353,6 @@ pub const LoadedStructType = struct {
33873353 // TODO: the non-fqn will be needed by the new dwarf structure
33883354 /// The name of this struct type.
33893355 name: NullTerminatedString,
3390 /// The `Cau` within which type resolution occurs.
3391 cau: Cau.Index,
33923356 namespace: NamespaceIndex,
33933357 /// Index of the `struct_decl` or `reify` ZIR instruction.
33943358 zir_index: TrackedInst.Index,
......@@ -3979,7 +3943,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
39793943 switch (item.tag) {
39803944 .type_struct => {
39813945 const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]);
3982 const cau: Cau.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "cau").?]);
39833946 const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]);
39843947 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]);
39853948 const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "fields_len").?];
......@@ -4066,7 +4029,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
40664029 .tid = unwrapped_index.tid,
40674030 .extra_index = item.data,
40684031 .name = name,
4069 .cau = cau,
40704032 .namespace = namespace,
40714033 .zir_index = zir_index,
40724034 .layout = if (flags.is_extern) .@"extern" else .auto,
......@@ -4083,7 +4045,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
40834045 },
40844046 .type_struct_packed, .type_struct_packed_inits => {
40854047 const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?]);
4086 const cau: Cau.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "cau").?]);
40874048 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]);
40884049 const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?];
40894050 const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?]);
......@@ -4130,7 +4091,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
41304091 .tid = unwrapped_index.tid,
41314092 .extra_index = item.data,
41324093 .name = name,
4133 .cau = cau,
41344094 .namespace = namespace,
41354095 .zir_index = zir_index,
41364096 .layout = .@"packed",
......@@ -4153,9 +4113,6 @@ pub const LoadedEnumType = struct {
41534113 // TODO: the non-fqn will be needed by the new dwarf structure
41544114 /// The name of this enum type.
41554115 name: NullTerminatedString,
4156 /// The `Cau` within which type resolution occurs.
4157 /// `null` if this is a generated tag type.
4158 cau: Cau.Index.Optional,
41594116 /// Represents the declarations inside this enum.
41604117 namespace: NamespaceIndex,
41614118 /// An integer type which is used for the numerical value of the enum.
......@@ -4232,21 +4189,15 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
42324189 .type_enum_auto => {
42334190 const extra = extraDataTrail(extra_list, EnumAuto, item.data);
42344191 var extra_index: u32 = @intCast(extra.end);
4235 const cau: Cau.Index.Optional = if (extra.data.zir_index == .none) cau: {
4192 if (extra.data.zir_index == .none) {
42364193 extra_index += 1; // owner_union
4237 break :cau .none;
4238 } else cau: {
4239 const cau: Cau.Index = @enumFromInt(extra_list.view().items(.@"0")[extra_index]);
4240 extra_index += 1; // cau
4241 break :cau cau.toOptional();
4242 };
4194 }
42434195 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
42444196 extra_index += 2; // type_hash: PackedU64
42454197 break :c 0;
42464198 } else extra.data.captures_len;
42474199 return .{
42484200 .name = extra.data.name,
4249 .cau = cau,
42504201 .namespace = extra.data.namespace,
42514202 .tag_ty = extra.data.int_tag_type,
42524203 .names = .{
......@@ -4272,21 +4223,15 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
42724223 };
42734224 const extra = extraDataTrail(extra_list, EnumExplicit, item.data);
42744225 var extra_index: u32 = @intCast(extra.end);
4275 const cau: Cau.Index.Optional = if (extra.data.zir_index == .none) cau: {
4226 if (extra.data.zir_index == .none) {
42764227 extra_index += 1; // owner_union
4277 break :cau .none;
4278 } else cau: {
4279 const cau: Cau.Index = @enumFromInt(extra_list.view().items(.@"0")[extra_index]);
4280 extra_index += 1; // cau
4281 break :cau cau.toOptional();
4282 };
4228 }
42834229 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
42844230 extra_index += 2; // type_hash: PackedU64
42854231 break :c 0;
42864232 } else extra.data.captures_len;
42874233 return .{
42884234 .name = extra.data.name,
4289 .cau = cau,
42904235 .namespace = extra.data.namespace,
42914236 .tag_ty = extra.data.int_tag_type,
42924237 .names = .{
......@@ -5256,7 +5201,6 @@ pub const Tag = enum(u8) {
52565201 .payload = EnumExplicit,
52575202 .trailing = struct {
52585203 owner_union: Index,
5259 cau: ?Cau.Index,
52605204 captures: ?[]CaptureValue,
52615205 type_hash: ?u64,
52625206 field_names: []NullTerminatedString,
......@@ -5302,7 +5246,6 @@ pub const Tag = enum(u8) {
53025246 .payload = EnumAuto,
53035247 .trailing = struct {
53045248 owner_union: ?Index,
5305 cau: ?Cau.Index,
53065249 captures: ?[]CaptureValue,
53075250 type_hash: ?u64,
53085251 field_names: []NullTerminatedString,
......@@ -5679,7 +5622,6 @@ pub const Tag = enum(u8) {
56795622 size: u32,
56805623 /// Only valid after .have_layout
56815624 padding: u32,
5682 cau: Cau.Index,
56835625 namespace: NamespaceIndex,
56845626 /// The enum that provides the list of field names and values.
56855627 tag_ty: Index,
......@@ -5710,7 +5652,6 @@ pub const Tag = enum(u8) {
57105652 /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits
57115653 pub const TypeStructPacked = struct {
57125654 name: NullTerminatedString,
5713 cau: Cau.Index,
57145655 zir_index: TrackedInst.Index,
57155656 fields_len: u32,
57165657 namespace: NamespaceIndex,
......@@ -5758,7 +5699,6 @@ pub const Tag = enum(u8) {
57585699 /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved
57595700 pub const TypeStruct = struct {
57605701 name: NullTerminatedString,
5761 cau: Cau.Index,
57625702 zir_index: TrackedInst.Index,
57635703 namespace: NamespaceIndex,
57645704 fields_len: u32,
......@@ -6088,11 +6028,10 @@ pub const Array = struct {
60886028
60896029/// Trailing:
60906030/// 0. owner_union: Index // if `zir_index == .none`
6091/// 1. cau: Cau.Index // if `zir_index != .none`
6092/// 2. capture: CaptureValue // for each `captures_len`
6093/// 3. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6094/// 4. field name: NullTerminatedString for each fields_len; declaration order
6095/// 5. tag value: Index for each fields_len; declaration order
6031/// 1. capture: CaptureValue // for each `captures_len`
6032/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6033/// 3. field name: NullTerminatedString for each fields_len; declaration order
6034/// 4. tag value: Index for each fields_len; declaration order
60966035pub const EnumExplicit = struct {
60976036 name: NullTerminatedString,
60986037 /// `std.math.maxInt(u32)` indicates this type is reified.
......@@ -6115,10 +6054,9 @@ pub const EnumExplicit = struct {
61156054
61166055/// Trailing:
61176056/// 0. owner_union: Index // if `zir_index == .none`
6118/// 1. cau: Cau.Index // if `zir_index != .none`
6119/// 2. capture: CaptureValue // for each `captures_len`
6120/// 3. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6121/// 4. field name: NullTerminatedString for each fields_len; declaration order
6057/// 1. capture: CaptureValue // for each `captures_len`
6058/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6059/// 3. field name: NullTerminatedString for each fields_len; declaration order
61226060pub const EnumAuto = struct {
61236061 name: NullTerminatedString,
61246062 /// `std.math.maxInt(u32)` indicates this type is reified.
......@@ -6408,32 +6346,32 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
64086346 ip.locals = try gpa.alloc(Local, used_threads);
64096347 @memset(ip.locals, .{
64106348 .shared = .{
6411 .items = Local.List(Item).empty,
6412 .extra = Local.Extra.empty,
6413 .limbs = Local.Limbs.empty,
6414 .strings = Local.Strings.empty,
6415 .tracked_insts = Local.TrackedInsts.empty,
6416 .files = Local.List(File).empty,
6417 .maps = Local.Maps.empty,
6418 .caus = Local.Caus.empty,
6419 .navs = Local.Navs.empty,
6420
6421 .namespaces = Local.Namespaces.empty,
6349 .items = .empty,
6350 .extra = .empty,
6351 .limbs = .empty,
6352 .strings = .empty,
6353 .tracked_insts = .empty,
6354 .files = .empty,
6355 .maps = .empty,
6356 .navs = .empty,
6357 .comptime_units = .empty,
6358
6359 .namespaces = .empty,
64226360 },
64236361 .mutate = .{
64246362 .arena = .{},
64256363
6426 .items = Local.ListMutate.empty,
6427 .extra = Local.ListMutate.empty,
6428 .limbs = Local.ListMutate.empty,
6429 .strings = Local.ListMutate.empty,
6430 .tracked_insts = Local.ListMutate.empty,
6431 .files = Local.ListMutate.empty,
6432 .maps = Local.ListMutate.empty,
6433 .caus = Local.ListMutate.empty,
6434 .navs = Local.ListMutate.empty,
6364 .items = .empty,
6365 .extra = .empty,
6366 .limbs = .empty,
6367 .strings = .empty,
6368 .tracked_insts = .empty,
6369 .files = .empty,
6370 .maps = .empty,
6371 .navs = .empty,
6372 .comptime_units = .empty,
64356373
6436 .namespaces = Local.BucketListMutate.empty,
6374 .namespaces = .empty,
64376375 },
64386376 });
64396377
......@@ -6506,7 +6444,8 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
65066444 namespace.priv_decls.deinit(gpa);
65076445 namespace.pub_usingnamespace.deinit(gpa);
65086446 namespace.priv_usingnamespace.deinit(gpa);
6509 namespace.other_decls.deinit(gpa);
6447 namespace.comptime_decls.deinit(gpa);
6448 namespace.test_decls.deinit(gpa);
65106449 }
65116450 };
65126451 const maps = local.getMutableMaps(gpa);
......@@ -6525,8 +6464,6 @@ pub fn activate(ip: *const InternPool) void {
65256464 _ = OptionalString.debug_state;
65266465 _ = NullTerminatedString.debug_state;
65276466 _ = OptionalNullTerminatedString.debug_state;
6528 _ = Cau.Index.debug_state;
6529 _ = Cau.Index.Optional.debug_state;
65306467 _ = Nav.Index.debug_state;
65316468 _ = Nav.Index.Optional.debug_state;
65326469 std.debug.assert(debug_state.intern_pool == null);
......@@ -6711,14 +6648,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
67116648 if (extra.data.captures_len == std.math.maxInt(u32)) {
67126649 break :ns .{ .reified = .{
67136650 .zir_index = zir_index,
6714 .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(),
6651 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
67156652 } };
67166653 }
67176654 break :ns .{ .declared = .{
67186655 .zir_index = zir_index,
67196656 .captures = .{ .owned = .{
67206657 .tid = unwrapped_index.tid,
6721 .start = extra.end + 1,
6658 .start = extra.end,
67226659 .len = extra.data.captures_len,
67236660 } },
67246661 } };
......@@ -6735,14 +6672,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
67356672 if (extra.data.captures_len == std.math.maxInt(u32)) {
67366673 break :ns .{ .reified = .{
67376674 .zir_index = zir_index,
6738 .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(),
6675 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
67396676 } };
67406677 }
67416678 break :ns .{ .declared = .{
67426679 .zir_index = zir_index,
67436680 .captures = .{ .owned = .{
67446681 .tid = unwrapped_index.tid,
6745 .start = extra.end + 1,
6682 .start = extra.end,
67466683 .len = extra.data.captures_len,
67476684 } },
67486685 } };
......@@ -8323,7 +8260,6 @@ pub fn getUnionType(
83238260 .size = std.math.maxInt(u32),
83248261 .padding = std.math.maxInt(u32),
83258262 .name = undefined, // set by `finish`
8326 .cau = undefined, // set by `finish`
83278263 .namespace = undefined, // set by `finish`
83288264 .tag_ty = ini.enum_tag_ty,
83298265 .zir_index = switch (ini.key) {
......@@ -8375,7 +8311,6 @@ pub fn getUnionType(
83758311 .tid = tid,
83768312 .index = gop.put(),
83778313 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8378 .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "cau").?,
83798314 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
83808315 } };
83818316}
......@@ -8384,7 +8319,6 @@ pub const WipNamespaceType = struct {
83848319 tid: Zcu.PerThread.Id,
83858320 index: Index,
83868321 type_name_extra_index: u32,
8387 cau_extra_index: ?u32,
83888322 namespace_extra_index: u32,
83898323
83908324 pub fn setName(
......@@ -8400,18 +8334,11 @@ pub const WipNamespaceType = struct {
84008334 pub fn finish(
84018335 wip: WipNamespaceType,
84028336 ip: *InternPool,
8403 analysis_owner: Cau.Index.Optional,
84048337 namespace: NamespaceIndex,
84058338 ) Index {
84068339 const extra = ip.getLocalShared(wip.tid).extra.acquire();
84078340 const extra_items = extra.view().items(.@"0");
84088341
8409 if (wip.cau_extra_index) |i| {
8410 extra_items[i] = @intFromEnum(analysis_owner.unwrap().?);
8411 } else {
8412 assert(analysis_owner == .none);
8413 }
8414
84158342 extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
84168343
84178344 return wip.index;
......@@ -8510,7 +8437,6 @@ pub fn getStructType(
85108437 ini.fields_len); // inits
85118438 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
85128439 .name = undefined, // set by `finish`
8513 .cau = undefined, // set by `finish`
85148440 .zir_index = zir_index,
85158441 .fields_len = ini.fields_len,
85168442 .namespace = undefined, // set by `finish`
......@@ -8555,7 +8481,6 @@ pub fn getStructType(
85558481 .tid = tid,
85568482 .index = gop.put(),
85578483 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8558 .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "cau").?,
85598484 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
85608485 } };
85618486 },
......@@ -8578,7 +8503,6 @@ pub fn getStructType(
85788503 1); // names_map
85798504 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
85808505 .name = undefined, // set by `finish`
8581 .cau = undefined, // set by `finish`
85828506 .zir_index = zir_index,
85838507 .namespace = undefined, // set by `finish`
85848508 .fields_len = ini.fields_len,
......@@ -8647,7 +8571,6 @@ pub fn getStructType(
86478571 .tid = tid,
86488572 .index = gop.put(),
86498573 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8650 .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "cau").?,
86518574 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
86528575 } };
86538576}
......@@ -9383,7 +9306,7 @@ fn finishFuncInstance(
93839306 func_extra_index: u32,
93849307) Allocator.Error!void {
93859308 const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav);
9386 const fn_namespace = ip.getCau(fn_owner_nav.analysis_owner.unwrap().?).namespace;
9309 const fn_namespace = fn_owner_nav.analysis.?.namespace;
93879310
93889311 // TODO: improve this name
93899312 const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{}__anon_{d}", .{
......@@ -9429,7 +9352,6 @@ pub const WipEnumType = struct {
94299352 index: Index,
94309353 tag_ty_index: u32,
94319354 type_name_extra_index: u32,
9432 cau_extra_index: u32,
94339355 namespace_extra_index: u32,
94349356 names_map: MapIndex,
94359357 names_start: u32,
......@@ -9449,13 +9371,11 @@ pub const WipEnumType = struct {
94499371 pub fn prepare(
94509372 wip: WipEnumType,
94519373 ip: *InternPool,
9452 analysis_owner: Cau.Index,
94539374 namespace: NamespaceIndex,
94549375 ) void {
94559376 const extra = ip.getLocalShared(wip.tid).extra.acquire();
94569377 const extra_items = extra.view().items(.@"0");
94579378
9458 extra_items[wip.cau_extra_index] = @intFromEnum(analysis_owner);
94599379 extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
94609380 }
94619381
......@@ -9556,7 +9476,6 @@ pub fn getEnumType(
95569476 .reified => 2, // type_hash: PackedU64
95579477 } +
95589478 // zig fmt: on
9559 1 + // cau
95609479 ini.fields_len); // field types
95619480
95629481 const extra_index = addExtraAssumeCapacity(extra, EnumAuto{
......@@ -9577,8 +9496,6 @@ pub fn getEnumType(
95779496 .tag = .type_enum_auto,
95789497 .data = extra_index,
95799498 });
9580 const cau_extra_index = extra.view().len;
9581 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`
95829499 switch (ini.key) {
95839500 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
95849501 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
......@@ -9591,7 +9508,6 @@ pub fn getEnumType(
95919508 .index = gop.put(),
95929509 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
95939510 .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?,
9594 .cau_extra_index = @intCast(cau_extra_index),
95959511 .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?,
95969512 .names_map = names_map,
95979513 .names_start = @intCast(names_start),
......@@ -9616,7 +9532,6 @@ pub fn getEnumType(
96169532 .reified => 2, // type_hash: PackedU64
96179533 } +
96189534 // zig fmt: on
9619 1 + // cau
96209535 ini.fields_len + // field types
96219536 ini.fields_len * @intFromBool(ini.has_values)); // field values
96229537
......@@ -9643,8 +9558,6 @@ pub fn getEnumType(
96439558 },
96449559 .data = extra_index,
96459560 });
9646 const cau_extra_index = extra.view().len;
9647 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`
96489561 switch (ini.key) {
96499562 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
96509563 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
......@@ -9661,7 +9574,6 @@ pub fn getEnumType(
96619574 .index = gop.put(),
96629575 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
96639576 .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?,
9664 .cau_extra_index = @intCast(cau_extra_index),
96659577 .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?,
96669578 .names_map = names_map,
96679579 .names_start = @intCast(names_start),
......@@ -9858,7 +9770,6 @@ pub fn getOpaqueType(
98589770 .tid = tid,
98599771 .index = gop.put(),
98609772 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
9861 .cau_extra_index = null, // opaques do not undergo type resolution
98629773 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
98639774 },
98649775 };
......@@ -9974,7 +9885,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
99749885 inline for (@typeInfo(@TypeOf(item)).@"struct".fields) |field| {
99759886 extra.appendAssumeCapacity(.{switch (field.type) {
99769887 Index,
9977 Cau.Index,
99789888 Nav.Index,
99799889 NamespaceIndex,
99809890 OptionalNamespaceIndex,
......@@ -10037,7 +9947,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
100379947 const extra_item = extra_items[extra_index];
100389948 @field(result, field.name) = switch (field.type) {
100399949 Index,
10040 Cau.Index,
100419950 Nav.Index,
100429951 NamespaceIndex,
100439952 OptionalNamespaceIndex,
......@@ -11058,12 +10967,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
1105810967 try bw.flush();
1105910968}
1106010969
11061pub fn getCau(ip: *const InternPool, index: Cau.Index) Cau {
11062 const unwrapped = index.unwrap(ip);
11063 const caus = ip.getLocalShared(unwrapped.tid).caus.acquire();
11064 return caus.view().items(.@"0")[unwrapped.index];
11065}
11066
1106710970pub fn getNav(ip: *const InternPool, index: Nav.Index) Nav {
1106810971 const unwrapped = index.unwrap(ip);
1106910972 const navs = ip.getLocalShared(unwrapped.tid).navs.acquire();
......@@ -11077,51 +10980,34 @@ pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Names
1107710980 return &namespaces_bucket[unwrapped_namespace_index.index];
1107810981}
1107910982
11080/// Create a `Cau` associated with the type at the given `InternPool.Index`.
11081pub fn createTypeCau(
10983/// Create a `ComptimeUnit`, forming an `AnalUnit` for a `comptime` declaration.
10984pub fn createComptimeUnit(
1108210985 ip: *InternPool,
1108310986 gpa: Allocator,
1108410987 tid: Zcu.PerThread.Id,
1108510988 zir_index: TrackedInst.Index,
1108610989 namespace: NamespaceIndex,
11087 owner_type: InternPool.Index,
11088) Allocator.Error!Cau.Index {
11089 const caus = ip.getLocal(tid).getMutableCaus(gpa);
11090 const index_unwrapped: Cau.Index.Unwrapped = .{
10990) Allocator.Error!ComptimeUnit.Id {
10991 const comptime_units = ip.getLocal(tid).getMutableComptimeUnits(gpa);
10992 const id_unwrapped: ComptimeUnit.Id.Unwrapped = .{
1109110993 .tid = tid,
11092 .index = caus.mutate.len,
10994 .index = comptime_units.mutate.len,
1109310995 };
11094 try caus.append(.{.{
10996 try comptime_units.append(.{.{
1109510997 .zir_index = zir_index,
1109610998 .namespace = namespace,
11097 .owner = Cau.Owner.wrap(.{ .type = owner_type }),
1109810999 }});
11099 return index_unwrapped.wrap(ip);
11000 return id_unwrapped.wrap(ip);
1110011001}
1110111002
11102/// Create a `Cau` for a `comptime` declaration.
11103pub fn createComptimeCau(
11104 ip: *InternPool,
11105 gpa: Allocator,
11106 tid: Zcu.PerThread.Id,
11107 zir_index: TrackedInst.Index,
11108 namespace: NamespaceIndex,
11109) Allocator.Error!Cau.Index {
11110 const caus = ip.getLocal(tid).getMutableCaus(gpa);
11111 const index_unwrapped: Cau.Index.Unwrapped = .{
11112 .tid = tid,
11113 .index = caus.mutate.len,
11114 };
11115 try caus.append(.{.{
11116 .zir_index = zir_index,
11117 .namespace = namespace,
11118 .owner = Cau.Owner.wrap(.none),
11119 }});
11120 return index_unwrapped.wrap(ip);
11003pub fn getComptimeUnit(ip: *const InternPool, id: ComptimeUnit.Id) ComptimeUnit {
11004 const unwrapped = id.unwrap(ip);
11005 const comptime_units = ip.getLocalShared(unwrapped.tid).comptime_units.acquire();
11006 return comptime_units.view().items(.@"0")[unwrapped.index];
1112111007}
1112211008
11123/// Create a `Nav` not associated with any `Cau`.
11124/// Since there is no analysis owner, the `Nav`'s value must be known at creation time.
11009/// Create a `Nav` which does not undergo semantic analysis.
11010/// Since it is never analyzed, the `Nav`'s value must be known at creation time.
1112511011pub fn createNav(
1112611012 ip: *InternPool,
1112711013 gpa: Allocator,
......@@ -11143,7 +11029,7 @@ pub fn createNav(
1114311029 try navs.append(Nav.pack(.{
1114411030 .name = opts.name,
1114511031 .fqn = opts.fqn,
11146 .analysis_owner = .none,
11032 .analysis = null,
1114711033 .status = .{ .resolved = .{
1114811034 .val = opts.val,
1114911035 .alignment = opts.alignment,
......@@ -11155,10 +11041,9 @@ pub fn createNav(
1115511041 return index_unwrapped.wrap(ip);
1115611042}
1115711043
11158/// Create a `Cau` and `Nav` which are paired. The value of the `Nav` is
11159/// determined by semantic analysis of the `Cau`. The value of the `Nav`
11160/// is initially unresolved.
11161pub fn createPairedCauNav(
11044/// Create a `Nav` which undergoes semantic analysis because it corresponds to a source declaration.
11045/// The value of the `Nav` is initially unresolved.
11046pub fn createDeclNav(
1116211047 ip: *InternPool,
1116311048 gpa: Allocator,
1116411049 tid: Zcu.PerThread.Id,
......@@ -11168,36 +11053,28 @@ pub fn createPairedCauNav(
1116811053 namespace: NamespaceIndex,
1116911054 /// TODO: this is hacky! See `Nav.is_usingnamespace`.
1117011055 is_usingnamespace: bool,
11171) Allocator.Error!struct { Cau.Index, Nav.Index } {
11172 const caus = ip.getLocal(tid).getMutableCaus(gpa);
11056) Allocator.Error!Nav.Index {
1117311057 const navs = ip.getLocal(tid).getMutableNavs(gpa);
1117411058
11175 try caus.ensureUnusedCapacity(1);
1117611059 try navs.ensureUnusedCapacity(1);
1117711060
11178 const cau = Cau.Index.Unwrapped.wrap(.{
11179 .tid = tid,
11180 .index = caus.mutate.len,
11181 }, ip);
1118211061 const nav = Nav.Index.Unwrapped.wrap(.{
1118311062 .tid = tid,
1118411063 .index = navs.mutate.len,
1118511064 }, ip);
1118611065
11187 caus.appendAssumeCapacity(.{.{
11188 .zir_index = zir_index,
11189 .namespace = namespace,
11190 .owner = Cau.Owner.wrap(.{ .nav = nav }),
11191 }});
1119211066 navs.appendAssumeCapacity(Nav.pack(.{
1119311067 .name = name,
1119411068 .fqn = fqn,
11195 .analysis_owner = cau.toOptional(),
11069 .analysis = .{
11070 .namespace = namespace,
11071 .zir_index = zir_index,
11072 },
1119611073 .status = .unresolved,
1119711074 .is_usingnamespace = is_usingnamespace,
1119811075 }));
1119911076
11200 return .{ cau, nav };
11077 return nav;
1120111078}
1120211079
1120311080/// Resolve the value of a `Nav` with an analysis owner.
......@@ -11220,12 +11097,14 @@ pub fn resolveNavValue(
1122011097
1122111098 const navs = local.shared.navs.view();
1122211099
11223 const nav_analysis_owners = navs.items(.analysis_owner);
11100 const nav_analysis_namespace = navs.items(.analysis_namespace);
11101 const nav_analysis_zir_index = navs.items(.analysis_zir_index);
1122411102 const nav_vals = navs.items(.val);
1122511103 const nav_linksections = navs.items(.@"linksection");
1122611104 const nav_bits = navs.items(.bits);
1122711105
11228 assert(nav_analysis_owners[unwrapped.index] != .none);
11106 assert(nav_analysis_namespace[unwrapped.index] != .none);
11107 assert(nav_analysis_zir_index[unwrapped.index] != .none);
1122911108
1123011109 @atomicStore(InternPool.Index, &nav_vals[unwrapped.index], resolved.val, .release);
1123111110 @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);
src/Sema.zig+85-143
......@@ -2870,7 +2870,7 @@ fn zirStructDecl(
28702870 };
28712871 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) {
28722872 .existing => |ty| {
2873 const new_ty = try pt.ensureTypeUpToDate(ty, false);
2873 const new_ty = try pt.ensureTypeUpToDate(ty);
28742874
28752875 // Make sure we update the namespace if the declaration is re-analyzed, to pick
28762876 // up on e.g. changed comptime decls.
......@@ -2900,12 +2900,10 @@ fn zirStructDecl(
29002900 });
29012901 errdefer pt.destroyNamespace(new_namespace_index);
29022902
2903 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
2904
29052903 if (pt.zcu.comp.incremental) {
29062904 try ip.addDependency(
29072905 sema.gpa,
2908 AnalUnit.wrap(.{ .cau = new_cau_index }),
2906 AnalUnit.wrap(.{ .type = wip_ty.index }),
29092907 .{ .src_hash = tracked_inst },
29102908 );
29112909 }
......@@ -2922,7 +2920,7 @@ fn zirStructDecl(
29222920 }
29232921 try sema.declareDependency(.{ .interned = wip_ty.index });
29242922 try sema.addTypeReferenceEntry(src, wip_ty.index);
2925 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
2923 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
29262924}
29272925
29282926fn createTypeName(
......@@ -3100,7 +3098,7 @@ fn zirEnumDecl(
31003098 };
31013099 const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) {
31023100 .existing => |ty| {
3103 const new_ty = try pt.ensureTypeUpToDate(ty, false);
3101 const new_ty = try pt.ensureTypeUpToDate(ty);
31043102
31053103 // Make sure we update the namespace if the declaration is re-analyzed, to pick
31063104 // up on e.g. changed comptime decls.
......@@ -3136,16 +3134,14 @@ fn zirEnumDecl(
31363134 });
31373135 errdefer if (!done) pt.destroyNamespace(new_namespace_index);
31383136
3139 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
3140
31413137 try pt.scanNamespace(new_namespace_index, decls);
31423138
31433139 try sema.declareDependency(.{ .interned = wip_ty.index });
31443140 try sema.addTypeReferenceEntry(src, wip_ty.index);
31453141
31463142 // We've finished the initial construction of this type, and are about to perform analysis.
3147 // Set the Cau and namespace appropriately, and don't destroy anything on failure.
3148 wip_ty.prepare(ip, new_cau_index, new_namespace_index);
3143 // Set the namespace appropriately, and don't destroy anything on failure.
3144 wip_ty.prepare(ip, new_namespace_index);
31493145 done = true;
31503146
31513147 try Sema.resolveDeclaredEnum(
......@@ -3155,7 +3151,6 @@ fn zirEnumDecl(
31553151 tracked_inst,
31563152 new_namespace_index,
31573153 type_name,
3158 new_cau_index,
31593154 small,
31603155 body,
31613156 tag_type_ref,
......@@ -3245,7 +3240,7 @@ fn zirUnionDecl(
32453240 };
32463241 const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) {
32473242 .existing => |ty| {
3248 const new_ty = try pt.ensureTypeUpToDate(ty, false);
3243 const new_ty = try pt.ensureTypeUpToDate(ty);
32493244
32503245 // Make sure we update the namespace if the declaration is re-analyzed, to pick
32513246 // up on e.g. changed comptime decls.
......@@ -3275,12 +3270,10 @@ fn zirUnionDecl(
32753270 });
32763271 errdefer pt.destroyNamespace(new_namespace_index);
32773272
3278 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
3279
32803273 if (pt.zcu.comp.incremental) {
32813274 try zcu.intern_pool.addDependency(
32823275 gpa,
3283 AnalUnit.wrap(.{ .cau = new_cau_index }),
3276 AnalUnit.wrap(.{ .type = wip_ty.index }),
32843277 .{ .src_hash = tracked_inst },
32853278 );
32863279 }
......@@ -3297,7 +3290,7 @@ fn zirUnionDecl(
32973290 }
32983291 try sema.declareDependency(.{ .interned = wip_ty.index });
32993292 try sema.addTypeReferenceEntry(src, wip_ty.index);
3300 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
3293 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
33013294}
33023295
33033296fn zirOpaqueDecl(
......@@ -3382,7 +3375,7 @@ fn zirOpaqueDecl(
33823375 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
33833376 }
33843377 try sema.addTypeReferenceEntry(src, wip_ty.index);
3385 return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index));
3378 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
33863379}
33873380
33883381fn zirErrorSetDecl(
......@@ -6547,7 +6540,10 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
65476540 const ip = &zcu.intern_pool;
65486541 const func = switch (sema.owner.unwrap()) {
65496542 .func => |func| func,
6550 .cau => return, // does nothing outside a function
6543 .@"comptime",
6544 .nav_val,
6545 .type,
6546 => return, // does nothing outside a function
65516547 };
65526548 ip.funcSetDisableInstrumentation(func);
65536549 sema.allow_memoize = false;
......@@ -6868,11 +6864,8 @@ fn lookupInNamespace(
68686864
68696865 ignore_self: {
68706866 const skip_nav = switch (sema.owner.unwrap()) {
6871 .func => break :ignore_self,
6872 .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
6873 .none, .type => break :ignore_self,
6874 .nav => |nav| nav,
6875 },
6867 .@"comptime", .type, .func => break :ignore_self,
6868 .nav_val => |nav| nav,
68766869 };
68776870 var i: usize = 0;
68786871 while (i < candidates.items.len) {
......@@ -7132,7 +7125,7 @@ fn zirCall(
71327125 const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);
71337126
71347127 switch (sema.owner.unwrap()) {
7135 .cau => input_is_error = false,
7128 .@"comptime", .type, .nav_val => input_is_error = false,
71367129 .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) {
71377130 // No errorable fn actually called; we have no error return trace
71387131 input_is_error = false;
......@@ -7747,11 +7740,9 @@ fn analyzeCall(
77477740 // The call site definitely depends on the function's signature.
77487741 try sema.declareDependency(.{ .src_hash = module_fn.zir_body_inst });
77497742
7750 // This is not a function instance, so the function's `Nav` has a
7751 // `Cau` -- we don't need to check `generic_owner`.
7743 // This is not a function instance, so the function's `Nav` has analysis
7744 // state -- we don't need to check `generic_owner`.
77527745 const fn_nav = ip.getNav(module_fn.owner_nav);
7753 const fn_cau_index = fn_nav.analysis_owner.unwrap().?;
7754 const fn_cau = ip.getCau(fn_cau_index);
77557746
77567747 // We effectively want a child Sema here, but can't literally do that, because we need AIR
77577748 // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in
......@@ -7759,7 +7750,7 @@ fn analyzeCall(
77597750 // whenever performing an operation where the difference matters.
77607751 var ics = InlineCallSema.init(
77617752 sema,
7762 zcu.cauFileScope(fn_cau_index).zir,
7753 zcu.navFileScope(module_fn.owner_nav).zir,
77637754 module_fn_index,
77647755 block.error_return_trace_index,
77657756 );
......@@ -7769,7 +7760,7 @@ fn analyzeCall(
77697760 .parent = null,
77707761 .sema = sema,
77717762 // The function body exists in the same namespace as the corresponding function declaration.
7772 .namespace = fn_cau.namespace,
7763 .namespace = fn_nav.analysis.?.namespace,
77737764 .instructions = .{},
77747765 .label = null,
77757766 .inlining = &inlining,
......@@ -7780,7 +7771,7 @@ fn analyzeCall(
77807771 .runtime_cond = block.runtime_cond,
77817772 .runtime_loop = block.runtime_loop,
77827773 .runtime_index = block.runtime_index,
7783 .src_base_inst = fn_cau.zir_index,
7774 .src_base_inst = fn_nav.analysis.?.zir_index,
77847775 .type_name_ctx = fn_nav.fqn,
77857776 };
77867777
......@@ -7795,7 +7786,7 @@ fn analyzeCall(
77957786 // mutate comptime state.
77967787 // TODO: comptime call memoization is currently not supported under incremental compilation
77977788 // since dependencies are not marked on callers. If we want to keep this around (we should
7798 // check that it's worthwhile first!), each memoized call needs a `Cau`.
7789 // check that it's worthwhile first!), each memoized call needs an `AnalUnit`.
77997790 var should_memoize = !zcu.comp.incremental;
78007791
78017792 // If it's a comptime function call, we need to memoize it as long as no external
......@@ -7904,7 +7895,7 @@ fn analyzeCall(
79047895
79057896 // Since we're doing an inline call, we depend on the source code of the whole
79067897 // function declaration.
7907 try sema.declareDependency(.{ .src_hash = fn_cau.zir_index });
7898 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });
79087899
79097900 new_fn_info.return_type = sema.fn_ret_ty.toIntern();
79107901 if (!is_comptime_call and !block.is_typeof) {
......@@ -8016,7 +8007,7 @@ fn analyzeCall(
80168007 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
80178008
80188009 switch (sema.owner.unwrap()) {
8019 .cau => {},
8010 .@"comptime", .nav_val, .type => {},
80208011 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
80218012 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
80228013 },
......@@ -8268,10 +8259,9 @@ fn instantiateGenericCall(
82688259 // The actual monomorphization happens via adding `func_instance` to
82698260 // `InternPool`.
82708261
8271 // Since we are looking at the generic owner here, it has a `Cau`.
8262 // Since we are looking at the generic owner here, it has analysis state.
82728263 const fn_nav = ip.getNav(generic_owner_func.owner_nav);
8273 const fn_cau = ip.getCau(fn_nav.analysis_owner.unwrap().?);
8274 const fn_zir = zcu.namespacePtr(fn_cau.namespace).fileScope(zcu).zir;
8264 const fn_zir = zcu.navFileScope(generic_owner_func.owner_nav).zir;
82758265 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip) orelse return error.AnalysisFail);
82768266
82778267 const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());
......@@ -8312,11 +8302,11 @@ fn instantiateGenericCall(
83128302 var child_block: Block = .{
83138303 .parent = null,
83148304 .sema = &child_sema,
8315 .namespace = fn_cau.namespace,
8305 .namespace = fn_nav.analysis.?.namespace,
83168306 .instructions = .{},
83178307 .inlining = null,
83188308 .is_comptime = true,
8319 .src_base_inst = fn_cau.zir_index,
8309 .src_base_inst = fn_nav.analysis.?.zir_index,
83208310 .type_name_ctx = fn_nav.fqn,
83218311 };
83228312 defer child_block.instructions.deinit(gpa);
......@@ -8481,7 +8471,7 @@ fn instantiateGenericCall(
84818471 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
84828472
84838473 switch (sema.owner.unwrap()) {
8484 .cau => {},
8474 .@"comptime", .nav_val, .type => {},
84858475 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
84868476 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
84878477 },
......@@ -9510,14 +9500,11 @@ fn zirFunc(
95109500 // the callconv based on whether it is exported. Otherwise, the callconv defaults
95119501 // to `.auto`.
95129502 const cc: std.builtin.CallingConvention = if (has_body) cc: {
9513 const func_decl_cau = if (sema.generic_owner != .none) cau: {
9514 const generic_owner_fn = zcu.funcInfo(sema.generic_owner);
9515 // The generic owner definitely has a `Cau` for the corresponding function declaration.
9516 const generic_owner_nav = ip.getNav(generic_owner_fn.owner_nav);
9517 break :cau generic_owner_nav.analysis_owner.unwrap().?;
9518 } else sema.owner.unwrap().cau;
9503 const func_decl_nav = if (sema.generic_owner != .none) nav: {
9504 break :nav zcu.funcInfo(sema.generic_owner).owner_nav;
9505 } else sema.owner.unwrap().nav_val;
95199506 const fn_is_exported = exported: {
9520 const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip) orelse return error.AnalysisFail;
9507 const decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(ip) orelse return error.AnalysisFail;
95219508 const zir_decl = sema.code.getDeclaration(decl_inst);
95229509 break :exported zir_decl.linkage == .@"export";
95239510 };
......@@ -9991,7 +9978,7 @@ fn funcCommon(
99919978 if (!ret_poison)
99929979 try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
99939980 const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{
9994 .owner_nav = sema.getOwnerCauNav(),
9981 .owner_nav = sema.owner.unwrap().nav_val,
99959982
99969983 .param_types = param_types,
99979984 .noalias_bits = noalias_bits,
......@@ -10040,7 +10027,7 @@ fn funcCommon(
1004010027
1004110028 if (has_body) {
1004210029 const func_index = try ip.getFuncDecl(gpa, pt.tid, .{
10043 .owner_nav = sema.getOwnerCauNav(),
10030 .owner_nav = sema.owner.unwrap().nav_val,
1004410031 .ty = func_ty,
1004510032 .cc = cc,
1004610033 .is_noinline = is_noinline,
......@@ -17664,7 +17651,7 @@ fn zirAsm(
1766417651 if (is_volatile) {
1766517652 return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{});
1766617653 }
17667 try zcu.addGlobalAssembly(sema.owner.unwrap().cau, asm_source);
17654 try zcu.addGlobalAssembly(sema.owner, asm_source);
1766817655 return .void_value;
1766917656 }
1767017657
......@@ -18155,7 +18142,7 @@ fn zirThis(
1815518142 _ = extended;
1815618143 const pt = sema.pt;
1815718144 const namespace = pt.zcu.namespacePtr(block.namespace);
18158 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type, false);
18145 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type);
1815918146 switch (pt.zcu.intern_pool.indexToKey(new_ty)) {
1816018147 .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }),
1816118148 .opaque_type => {},
......@@ -19321,10 +19308,8 @@ fn typeInfoNamespaceDecls(
1932119308 }
1932219309
1932319310 for (namespace.pub_usingnamespace.items) |nav| {
19324 if (ip.getNav(nav).analysis_owner.unwrap()) |cau| {
19325 if (zcu.analysis_in_progress.contains(AnalUnit.wrap(.{ .cau = cau }))) {
19326 continue;
19327 }
19311 if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
19312 continue;
1932819313 }
1932919314 try sema.ensureNavResolved(src, nav);
1933019315 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.resolved.val);
......@@ -21187,14 +21172,13 @@ fn structInitAnon(
2118721172 .file_scope = block.getFileScopeIndex(zcu),
2118821173 .generation = zcu.generation,
2118921174 });
21190 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip.index);
2119121175 try zcu.comp.queueJob(.{ .resolve_type_fully = wip.index });
2119221176 codegen_type: {
2119321177 if (zcu.comp.config.use_llvm) break :codegen_type;
2119421178 if (block.ownerModule().strip) break :codegen_type;
2119521179 try zcu.comp.queueJob(.{ .codegen_type = wip.index });
2119621180 }
21197 break :ty wip.finish(ip, new_cau_index.toOptional(), new_namespace_index);
21181 break :ty wip.finish(ip, new_namespace_index);
2119821182 },
2119921183 .existing => |ty| ty,
2120021184 };
......@@ -21618,7 +21602,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
2161821602 .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) {
2161921603 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
2162021604 },
21621 .cau => {},
21605 .@"comptime", .nav_val, .type => {},
2162221606 }
2162321607 return Air.internedToRef(try pt.intern(.{ .opt = .{
2162421608 .ty = opt_ptr_stack_trace_ty.toIntern(),
......@@ -22296,7 +22280,7 @@ fn zirReify(
2229622280 });
2229722281
2229822282 try sema.addTypeReferenceEntry(src, wip_ty.index);
22299 return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index));
22283 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
2230022284 },
2230122285 .@"union" => {
2230222286 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
......@@ -22505,11 +22489,9 @@ fn reifyEnum(
2250522489 .generation = zcu.generation,
2250622490 });
2250722491
22508 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
22509
2251022492 try sema.declareDependency(.{ .interned = wip_ty.index });
2251122493 try sema.addTypeReferenceEntry(src, wip_ty.index);
22512 wip_ty.prepare(ip, new_cau_index, new_namespace_index);
22494 wip_ty.prepare(ip, new_namespace_index);
2251322495 wip_ty.setTagTy(ip, tag_ty.toIntern());
2251422496 done = true;
2251522497
......@@ -22811,8 +22793,6 @@ fn reifyUnion(
2281122793 .generation = zcu.generation,
2281222794 });
2281322795
22814 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
22815
2281622796 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
2281722797 codegen_type: {
2281822798 if (zcu.comp.config.use_llvm) break :codegen_type;
......@@ -22822,7 +22802,7 @@ fn reifyUnion(
2282222802 }
2282322803 try sema.declareDependency(.{ .interned = wip_ty.index });
2282422804 try sema.addTypeReferenceEntry(src, wip_ty.index);
22825 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
22805 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
2282622806}
2282722807
2282822808fn reifyTuple(
......@@ -23170,8 +23150,6 @@ fn reifyStruct(
2317023150 .generation = zcu.generation,
2317123151 });
2317223152
23173 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
23174
2317523153 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
2317623154 codegen_type: {
2317723155 if (zcu.comp.config.use_llvm) break :codegen_type;
......@@ -23181,7 +23159,7 @@ fn reifyStruct(
2318123159 }
2318223160 try sema.declareDependency(.{ .interned = wip_ty.index });
2318323161 try sema.addTypeReferenceEntry(src, wip_ty.index);
23184 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
23162 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
2318523163}
2318623164
2318723165fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
......@@ -26713,15 +26691,13 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2671326691 break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val);
2671426692 } else cc: {
2671526693 if (has_body) {
26716 const decl_inst = if (sema.generic_owner != .none) decl_inst: {
26694 const func_decl_nav = if (sema.generic_owner != .none) nav: {
2671726695 // Generic instance -- use the original function declaration to
2671826696 // look for the `export` syntax.
26719 const nav = zcu.intern_pool.getNav(zcu.funcInfo(sema.generic_owner).owner_nav);
26720 const cau = zcu.intern_pool.getCau(nav.analysis_owner.unwrap().?);
26721 break :decl_inst cau.zir_index;
26722 } else sema.getOwnerCauDeclInst(); // not an instantiation so we're analyzing a function declaration Cau
26723
26724 const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&zcu.intern_pool) orelse return error.AnalysisFail);
26697 break :nav zcu.funcInfo(sema.generic_owner).owner_nav;
26698 } else sema.owner.unwrap().nav_val;
26699 const func_decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(&zcu.intern_pool) orelse return error.AnalysisFail;
26700 const zir_decl = sema.code.getDeclaration(func_decl_inst);
2672526701 if (zir_decl.linkage == .@"export") {
2672626702 break :cc target.cCallingConvention() orelse {
2672726703 // This target has no default C calling convention. We sometimes trigger a similar
......@@ -27108,8 +27084,16 @@ fn zirBuiltinExtern(
2710827084 // `builtin_extern` doesn't provide enough information, and isn't currently tracked.
2710927085 // So, for now, just use our containing `declaration`.
2711027086 .zir_index = switch (sema.owner.unwrap()) {
27111 .cau => sema.getOwnerCauDeclInst(),
27112 .func => sema.getOwnerFuncDeclInst(),
27087 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,
27088 .type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?,
27089 .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
27090 .func => |func| zir_index: {
27091 const func_info = zcu.funcInfo(func);
27092 const owner_func_info = if (func_info.generic_owner != .none) owner: {
27093 break :owner zcu.funcInfo(func_info.generic_owner);
27094 } else func_info;
27095 break :zir_index ip.getNav(owner_func_info.owner_nav).analysis.?.zir_index;
27096 },
2711327097 },
2711427098 .owner_nav = undefined, // ignored by `getExtern`
2711527099 });
......@@ -32670,28 +32654,25 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav
3267032654 const ip = &zcu.intern_pool;
3267132655
3267232656 const nav = ip.getNav(nav_index);
32673
32674 const cau_index = nav.analysis_owner.unwrap() orelse {
32657 if (nav.analysis == null) {
3267532658 assert(nav.status == .resolved);
3267632659 return;
32677 };
32660 }
3267832661
32679 // Note that even if `nav.status == .resolved`, we must still trigger `ensureCauAnalyzed`
32662 // Note that even if `nav.status == .resolved`, we must still trigger `ensureNavValUpToDate`
3268032663 // to make sure the value is up-to-date on incremental updates.
3268132664
32682 assert(ip.getCau(cau_index).owner.unwrap().nav == nav_index);
32683
32684 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
32665 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_index });
3268532666 try sema.addReferenceEntry(src, anal_unit);
3268632667
3268732668 if (zcu.analysis_in_progress.contains(anal_unit)) {
3268832669 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{
32689 .base_node_inst = ip.getCau(cau_index).zir_index,
32670 .base_node_inst = nav.analysis.?.zir_index,
3269032671 .offset = LazySrcLoc.Offset.nodeOffset(0),
3269132672 }, "dependency loop detected", .{}));
3269232673 }
3269332674
32694 return pt.ensureCauAnalyzed(cau_index);
32675 return pt.ensureNavValUpToDate(nav_index);
3269532676}
3269632677
3269732678fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
......@@ -35641,7 +35622,7 @@ pub fn resolveStructAlignment(
3564135622 const ip = &zcu.intern_pool;
3564235623 const target = zcu.getTarget();
3564335624
35644 assert(sema.owner.unwrap().cau == struct_type.cau);
35625 assert(sema.owner.unwrap().type == ty);
3564535626
3564635627 assert(struct_type.layout != .@"packed");
3564735628 assert(struct_type.flagsUnordered(ip).alignment == .none);
......@@ -35684,7 +35665,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3568435665 const ip = &zcu.intern_pool;
3568535666 const struct_type = zcu.typeToStruct(ty) orelse return;
3568635667
35687 assert(sema.owner.unwrap().cau == struct_type.cau);
35668 assert(sema.owner.unwrap().type == ty.toIntern());
3568835669
3568935670 if (struct_type.haveLayout(ip))
3569035671 return;
......@@ -35831,15 +35812,13 @@ fn backingIntType(
3583135812 const gpa = zcu.gpa;
3583235813 const ip = &zcu.intern_pool;
3583335814
35834 const cau_index = struct_type.cau;
35835
3583635815 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3583735816 defer analysis_arena.deinit();
3583835817
3583935818 var block: Block = .{
3584035819 .parent = null,
3584135820 .sema = sema,
35842 .namespace = ip.getCau(cau_index).namespace,
35821 .namespace = struct_type.namespace,
3584335822 .instructions = .{},
3584435823 .inlining = null,
3584535824 .is_comptime = true,
......@@ -35971,7 +35950,7 @@ pub fn resolveUnionAlignment(
3597135950 const ip = &zcu.intern_pool;
3597235951 const target = zcu.getTarget();
3597335952
35974 assert(sema.owner.unwrap().cau == union_type.cau);
35953 assert(sema.owner.unwrap().type == ty.toIntern());
3597535954
3597635955 assert(!union_type.haveLayout(ip));
3597735956
......@@ -36011,7 +35990,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
3601135990 // Load again, since the tag type might have changed due to resolution.
3601235991 const union_type = ip.loadUnionType(ty.ip_index);
3601335992
36014 assert(sema.owner.unwrap().cau == union_type.cau);
35993 assert(sema.owner.unwrap().type == ty.toIntern());
3601535994
3601635995 const old_flags = union_type.flagsUnordered(ip);
3601735996 switch (old_flags.status) {
......@@ -36126,7 +36105,7 @@ pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void {
3612636105 const ip = &zcu.intern_pool;
3612736106 const struct_type = zcu.typeToStruct(ty).?;
3612836107
36129 assert(sema.owner.unwrap().cau == struct_type.cau);
36108 assert(sema.owner.unwrap().type == ty.toIntern());
3613036109
3613136110 if (struct_type.setFullyResolved(ip)) return;
3613236111 errdefer struct_type.clearFullyResolved(ip);
......@@ -36149,7 +36128,7 @@ pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void {
3614936128 const ip = &zcu.intern_pool;
3615036129 const union_obj = zcu.typeToUnion(ty).?;
3615136130
36152 assert(sema.owner.unwrap().cau == union_obj.cau);
36131 assert(sema.owner.unwrap().type == ty.toIntern());
3615336132
3615436133 switch (union_obj.flagsUnordered(ip).status) {
3615536134 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
......@@ -36184,7 +36163,7 @@ pub fn resolveStructFieldTypes(
3618436163 const zcu = pt.zcu;
3618536164 const ip = &zcu.intern_pool;
3618636165
36187 assert(sema.owner.unwrap().cau == struct_type.cau);
36166 assert(sema.owner.unwrap().type == ty);
3618836167
3618936168 if (struct_type.haveFieldTypes(ip)) return;
3619036169
......@@ -36210,7 +36189,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3621036189 const ip = &zcu.intern_pool;
3621136190 const struct_type = zcu.typeToStruct(ty) orelse return;
3621236191
36213 assert(sema.owner.unwrap().cau == struct_type.cau);
36192 assert(sema.owner.unwrap().type == ty.toIntern());
3621436193
3621536194 // Inits can start as resolved
3621636195 if (struct_type.haveFieldInits(ip)) return;
......@@ -36239,7 +36218,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load
3623936218 const zcu = pt.zcu;
3624036219 const ip = &zcu.intern_pool;
3624136220
36242 assert(sema.owner.unwrap().cau == union_type.cau);
36221 assert(sema.owner.unwrap().type == ty.toIntern());
3624336222
3624436223 switch (union_type.flagsUnordered(ip).status) {
3624536224 .none => {},
......@@ -36315,7 +36294,7 @@ fn resolveInferredErrorSet(
3631536294 // In this case we are dealing with the actual InferredErrorSet object that
3631636295 // corresponds to the function, not one created to track an inline/comptime call.
3631736296 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index }));
36318 try pt.ensureFuncBodyAnalyzed(func_index);
36297 try pt.ensureFuncBodyUpToDate(func_index);
3631936298 }
3632036299
3632136300 // This will now have been resolved by the logic at the end of `Zcu.analyzeFnBody`
......@@ -36472,8 +36451,7 @@ fn structFields(
3647236451 const zcu = pt.zcu;
3647336452 const gpa = zcu.gpa;
3647436453 const ip = &zcu.intern_pool;
36475 const cau_index = struct_type.cau;
36476 const namespace_index = ip.getCau(cau_index).namespace;
36454 const namespace_index = struct_type.namespace;
3647736455 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;
3647836456 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
3647936457
......@@ -36671,8 +36649,7 @@ fn structFieldInits(
3667136649
3667236650 assert(!struct_type.haveFieldInits(ip));
3667336651
36674 const cau_index = struct_type.cau;
36675 const namespace_index = ip.getCau(cau_index).namespace;
36652 const namespace_index = struct_type.namespace;
3667636653 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;
3667736654 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
3667836655 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
......@@ -38474,13 +38451,11 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3847438451 // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve
3847538452 // the loop.
3847638453 switch (sema.owner.unwrap()) {
38477 .cau => |cau| switch (dependee) {
38478 .nav_val => |nav| if (zcu.intern_pool.getNav(nav).analysis_owner == cau.toOptional()) {
38479 return;
38480 },
38454 .nav_val => |this_nav| switch (dependee) {
38455 .nav_val => |other_nav| if (this_nav == other_nav) return,
3848138456 else => {},
3848238457 },
38483 .func => {},
38458 else => {},
3848438459 }
3848538460
3848638461 try zcu.intern_pool.addDependency(sema.gpa, sema.owner, dependee);
......@@ -38659,38 +38634,6 @@ pub fn flushExports(sema: *Sema) !void {
3865938634 }
3866038635}
3866138636
38662/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches
38663/// the corresponding `Nav`.
38664fn getOwnerCauNav(sema: *Sema) InternPool.Nav.Index {
38665 const cau = sema.owner.unwrap().cau;
38666 return sema.pt.zcu.intern_pool.getCau(cau).owner.unwrap().nav;
38667}
38668
38669/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches
38670/// the `TrackedInst` corresponding to this `declaration` instruction.
38671fn getOwnerCauDeclInst(sema: *Sema) InternPool.TrackedInst.Index {
38672 const ip = &sema.pt.zcu.intern_pool;
38673 const cau = ip.getCau(sema.owner.unwrap().cau);
38674 assert(cau.owner.unwrap() == .nav);
38675 return cau.zir_index;
38676}
38677
38678/// Given that this `Sema` is owned by a runtime function, fetches the
38679/// `TrackedInst` corresponding to its `declaration` instruction.
38680fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index {
38681 const zcu = sema.pt.zcu;
38682 const ip = &zcu.intern_pool;
38683 const func = sema.owner.unwrap().func;
38684 const func_info = zcu.funcInfo(func);
38685 const cau = if (func_info.generic_owner == .none) cau: {
38686 break :cau ip.getNav(func_info.owner_nav).analysis_owner.unwrap().?;
38687 } else cau: {
38688 const generic_owner = zcu.funcInfo(func_info.generic_owner);
38689 break :cau ip.getNav(generic_owner.owner_nav).analysis_owner.unwrap().?;
38690 };
38691 return ip.getCau(cau).zir_index;
38692}
38693
3869438637/// Called as soon as a `declared` enum type is created.
3869538638/// Resolves the tag type and field inits.
3869638639/// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this.
......@@ -38701,7 +38644,6 @@ pub fn resolveDeclaredEnum(
3870138644 tracked_inst: InternPool.TrackedInst.Index,
3870238645 namespace: InternPool.NamespaceIndex,
3870338646 type_name: InternPool.NullTerminatedString,
38704 enum_cau: InternPool.Cau.Index,
3870538647 small: Zir.Inst.EnumDecl.Small,
3870638648 body: []const Zir.Inst.Index,
3870738649 tag_type_ref: Zir.Inst.Ref,
......@@ -38719,7 +38661,7 @@ pub fn resolveDeclaredEnum(
3871938661 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) };
3872038662 const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } };
3872138663
38722 const anal_unit = AnalUnit.wrap(.{ .cau = enum_cau });
38664 const anal_unit = AnalUnit.wrap(.{ .type = wip_ty.index });
3872338665
3872438666 var arena = std.heap.ArenaAllocator.init(gpa);
3872538667 defer arena.deinit();
......@@ -38943,6 +38885,6 @@ fn getBuiltin(sema: *Sema, name: []const u8) SemaError!Air.Inst.Ref {
3894338885 const zcu = pt.zcu;
3894438886 const ip = &zcu.intern_pool;
3894538887 const nav = try pt.getBuiltinNav(name);
38946 try pt.ensureCauAnalyzed(ip.getNav(nav).analysis_owner.unwrap().?);
38888 try pt.ensureNavValUpToDate(nav);
3894738889 return Air.internedToRef(ip.getNav(nav).status.resolved.val);
3894838890}
src/Type.zig+2-2
......@@ -3851,7 +3851,7 @@ fn resolveStructInner(
38513851 const gpa = zcu.gpa;
38523852
38533853 const struct_obj = zcu.typeToStruct(ty).?;
3854 const owner = InternPool.AnalUnit.wrap(.{ .cau = struct_obj.cau });
3854 const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
38553855
38563856 if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
38573857 return error.AnalysisFail;
......@@ -3905,7 +3905,7 @@ fn resolveUnionInner(
39053905 const gpa = zcu.gpa;
39063906
39073907 const union_obj = zcu.typeToUnion(ty).?;
3908 const owner = InternPool.AnalUnit.wrap(.{ .cau = union_obj.cau });
3908 const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
39093909
39103910 if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
39113911 return error.AnalysisFail;
src/Zcu.zig+86-96
......@@ -192,7 +192,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .empty,
192192
193193test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
194194
195global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .empty,
195global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty,
196196
197197/// Key is the `AnalUnit` *performing* the reference. This representation allows
198198/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
......@@ -344,9 +344,12 @@ pub const Namespace = struct {
344344 pub_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
345345 /// All `usingnamespace` declarations in this namespace which are *not* marked `pub`.
346346 priv_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
347 /// All `comptime` and `test` declarations in this namespace. We store these purely so that
348 /// incremental compilation can re-use the existing `Cau`s when a namespace changes.
349 other_decls: std.ArrayListUnmanaged(InternPool.Cau.Index) = .empty,
347 /// All `comptime` declarations in this namespace. We store these purely so that incremental
348 /// compilation can re-use the existing `ComptimeUnit`s when a namespace changes.
349 comptime_decls: std.ArrayListUnmanaged(InternPool.ComptimeUnit.Id) = .empty,
350 /// All `test` declarations in this namespace. We store these purely so that incremental
351 /// compilation can re-use the existing `Nav`s when a namespace changes.
352 test_decls: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
350353
351354 pub const Index = InternPool.NamespaceIndex;
352355 pub const OptionalIndex = InternPool.OptionalNamespaceIndex;
......@@ -2436,11 +2439,9 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
24362439 // If this is a Decl, we must recursively mark dependencies on its tyval
24372440 // as no longer PO.
24382441 switch (depender.unwrap()) {
2439 .cau => |cau| switch (zcu.intern_pool.getCau(cau).owner.unwrap()) {
2440 .nav => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
2441 .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
2442 .none => {},
2443 },
2442 .@"comptime" => {},
2443 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
2444 .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
24442445 .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),
24452446 }
24462447 }
......@@ -2451,11 +2452,9 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
24512452fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
24522453 const ip = &zcu.intern_pool;
24532454 const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) {
2454 .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
2455 .nav => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced
2456 .type => |ty| .{ .interned = ty },
2457 .none => return, // analysis of this `Cau` can't outdate any dependencies
2458 },
2455 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies
2456 .nav_val => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced
2457 .type => |ty| .{ .interned = ty },
24592458 .func => |func_index| .{ .interned = func_index }, // IES
24602459 };
24612460 log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)});
......@@ -2512,14 +2511,14 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
25122511 }
25132512
25142513 // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some
2515 // Cau with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
2516 // A or B. We should select a Cau, since a Cau is definitely responsible for the loop in the
2517 // dependency graph (since IES dependencies can't have loops). We should also, of course, not
2518 // select a Cau owned by a `comptime` declaration, since you can't depend on those!
2514 // AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
2515 // A or B. We should definitely not select a function, since a function can't be responsible for the
2516 // loop (IES dependencies can't have loops). We should also, of course, not select a `comptime`
2517 // declaration, since you can't depend on those!
25192518
2520 // The choice of this Cau could have a big impact on how much total analysis we perform, since
2519 // The choice of this unit could have a big impact on how much total analysis we perform, since
25212520 // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit
2522 // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a Decl
2521 // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit
25232522 // which the most things depend on - the idea is that this will resolve a lot of loops (but this
25242523 // is only a heuristic).
25252524
......@@ -2530,33 +2529,28 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
25302529
25312530 const ip = &zcu.intern_pool;
25322531
2533 var chosen_cau: ?InternPool.Cau.Index = null;
2534 var chosen_cau_dependers: u32 = undefined;
2532 var chosen_unit: ?AnalUnit = null;
2533 var chosen_unit_dependers: u32 = undefined;
25352534
25362535 inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {
25372536 for (outdated_units) |unit| {
2538 const cau = switch (unit.unwrap()) {
2539 .cau => |cau| cau,
2540 .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
2541 };
2542 const cau_owner = ip.getCau(cau).owner;
2543
25442537 var n: u32 = 0;
2545 var it = ip.dependencyIterator(switch (cau_owner.unwrap()) {
2546 .none => continue, // there can be no dependencies on this `Cau` so it is a terrible choice
2538 var it = ip.dependencyIterator(switch (unit.unwrap()) {
2539 .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
2540 .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice
25472541 .type => |ty| .{ .interned = ty },
2548 .nav => |nav| .{ .nav_val = nav },
2542 .nav_val => |nav| .{ .nav_val = nav },
25492543 });
25502544 while (it.next()) |_| n += 1;
25512545
2552 if (chosen_cau == null or n > chosen_cau_dependers) {
2553 chosen_cau = cau;
2554 chosen_cau_dependers = n;
2546 if (chosen_unit == null or n > chosen_unit_dependers) {
2547 chosen_unit = unit;
2548 chosen_unit_dependers = n;
25552549 }
25562550 }
25572551 }
25582552
2559 if (chosen_cau == null) {
2553 if (chosen_unit == null) {
25602554 for (zcu.outdated.keys(), zcu.outdated.values()) |o, opod| {
25612555 const func = o.unwrap().func;
25622556 const nav = zcu.funcInfo(func).owner_nav;
......@@ -2570,11 +2564,11 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
25702564 }
25712565
25722566 log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{
2573 zcu.fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? })),
2574 chosen_cau_dependers,
2567 zcu.fmtAnalUnit(chosen_unit.?),
2568 chosen_unit_dependers,
25752569 });
25762570
2577 return AnalUnit.wrap(.{ .cau = chosen_cau.? });
2571 return chosen_unit.?;
25782572}
25792573
25802574/// During an incremental update, before semantic analysis, call this to flush all values from
......@@ -3019,9 +3013,9 @@ pub fn handleUpdateExports(
30193013 };
30203014}
30213015
3022pub fn addGlobalAssembly(zcu: *Zcu, cau: InternPool.Cau.Index, source: []const u8) !void {
3016pub fn addGlobalAssembly(zcu: *Zcu, unit: AnalUnit, source: []const u8) !void {
30233017 const gpa = zcu.gpa;
3024 const gop = try zcu.global_assembly.getOrPut(gpa, cau);
3018 const gop = try zcu.global_assembly.getOrPut(gpa, unit);
30253019 if (gop.found_existing) {
30263020 const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
30273021 gpa.free(gop.value_ptr.*);
......@@ -3304,23 +3298,22 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
33043298
33053299 log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
33063300
3307 // If this type has a `Cau` for resolution, it's automatically referenced.
3308 const resolution_cau: InternPool.Cau.Index.Optional = switch (ip.indexToKey(ty)) {
3309 .struct_type => ip.loadStructType(ty).cau.toOptional(),
3310 .union_type => ip.loadUnionType(ty).cau.toOptional(),
3311 .enum_type => ip.loadEnumType(ty).cau,
3312 .opaque_type => .none,
3301 // If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced.
3302 const has_resolution: bool = switch (ip.indexToKey(ty)) {
3303 .struct_type, .union_type => true,
3304 .enum_type => |k| k != .generated_tag,
3305 .opaque_type => false,
33133306 else => unreachable,
33143307 };
3315 if (resolution_cau.unwrap()) |cau| {
3308 if (has_resolution) {
33163309 // this should only be referenced by the type
3317 const unit = AnalUnit.wrap(.{ .cau = cau });
3310 const unit: AnalUnit = .wrap(.{ .type = ty });
33183311 assert(!result.contains(unit));
33193312 try unit_queue.putNoClobber(gpa, unit, referencer);
33203313 }
33213314
33223315 // If this is a union with a generated tag, its tag type is automatically referenced.
3323 // We don't add this reference for non-generated tags, as those will already be referenced via the union's `Cau`, with a better source location.
3316 // We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location.
33243317 if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| {
33253318 const tag_ty = union_obj.enum_tag_ty;
33263319 if (tag_ty != .none) {
......@@ -3335,24 +3328,35 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
33353328 // Queue any decls within this type which would be automatically analyzed.
33363329 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.
33373330 const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?;
3338 for (zcu.namespacePtr(ns).other_decls.items) |cau| {
3339 // These are `comptime` and `test` declarations.
3340 // `comptime` decls are always analyzed; `test` declarations are analyzed depending on the test filter.
3341 const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
3331 for (zcu.namespacePtr(ns).comptime_decls.items) |cu| {
3332 // `comptime` decls are always analyzed.
3333 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
3334 if (!result.contains(unit)) {
3335 log.debug("type '{}': ref comptime %{}", .{
3336 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
3337 @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
3338 });
3339 try unit_queue.put(gpa, unit, referencer);
3340 }
3341 }
3342 for (zcu.namespacePtr(ns).test_decls.items) |nav_id| {
3343 const nav = ip.getNav(nav_id);
3344 // `test` declarations are analyzed depending on the test filter.
3345 const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue;
33423346 const file = zcu.fileByIndex(inst_info.file);
33433347 // If the file failed AstGen, the TrackedInst refers to the old ZIR.
33443348 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
33453349 const decl = zir.getDeclaration(inst_info.inst);
3350
3351 if (!comp.config.is_test or file.mod != zcu.main_mod) continue;
3352
33463353 const want_analysis = switch (decl.kind) {
33473354 .@"usingnamespace" => unreachable,
33483355 .@"const", .@"var" => unreachable,
3349 .@"comptime" => true,
3350 .unnamed_test => comp.config.is_test and file.mod == zcu.main_mod,
3356 .@"comptime" => unreachable,
3357 .unnamed_test => true,
33513358 .@"test", .decltest => a: {
3352 if (!comp.config.is_test) break :a false;
3353 if (file.mod != zcu.main_mod) break :a false;
3354 const nav = ip.getCau(cau).owner.unwrap().nav;
3355 const fqn_slice = ip.getNav(nav).fqn.toSlice(ip);
3359 const fqn_slice = nav.fqn.toSlice(ip);
33563360 for (comp.test_filters) |test_filter| {
33573361 if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
33583362 } else break :a false;
......@@ -3360,28 +3364,25 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
33603364 },
33613365 };
33623366 if (want_analysis) {
3363 const unit = AnalUnit.wrap(.{ .cau = cau });
3364 if (!result.contains(unit)) {
3365 log.debug("type '{}': ref cau %{}", .{
3366 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
3367 @intFromEnum(inst_info.inst),
3368 });
3369 try unit_queue.put(gpa, unit, referencer);
3370 }
3367 log.debug("type '{}': ref test %{}", .{
3368 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
3369 @intFromEnum(inst_info.inst),
3370 });
3371 const unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
3372 try unit_queue.put(gpa, unit, referencer);
33713373 }
33723374 }
33733375 for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| {
33743376 // These are named declarations. They are analyzed only if marked `export`.
3375 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3376 const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
3377 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
33773378 const file = zcu.fileByIndex(inst_info.file);
33783379 // If the file failed AstGen, the TrackedInst refers to the old ZIR.
33793380 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
33803381 const decl = zir.getDeclaration(inst_info.inst);
33813382 if (decl.linkage == .@"export") {
3382 const unit = AnalUnit.wrap(.{ .cau = cau });
3383 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
33833384 if (!result.contains(unit)) {
3384 log.debug("type '{}': ref cau %{}", .{
3385 log.debug("type '{}': ref named %{}", .{
33853386 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
33863387 @intFromEnum(inst_info.inst),
33873388 });
......@@ -3391,16 +3392,15 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
33913392 }
33923393 for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| {
33933394 // These are named declarations. They are analyzed only if marked `export`.
3394 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3395 const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
3395 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
33963396 const file = zcu.fileByIndex(inst_info.file);
33973397 // If the file failed AstGen, the TrackedInst refers to the old ZIR.
33983398 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
33993399 const decl = zir.getDeclaration(inst_info.inst);
34003400 if (decl.linkage == .@"export") {
3401 const unit = AnalUnit.wrap(.{ .cau = cau });
3401 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
34023402 if (!result.contains(unit)) {
3403 log.debug("type '{}': ref cau %{}", .{
3403 log.debug("type '{}': ref named %{}", .{
34043404 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
34053405 @intFromEnum(inst_info.inst),
34063406 });
......@@ -3411,13 +3411,11 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
34113411 // Incremental compilation does not support `usingnamespace`.
34123412 // These are only included to keep good reference traces in non-incremental updates.
34133413 for (zcu.namespacePtr(ns).pub_usingnamespace.items) |nav| {
3414 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3415 const unit = AnalUnit.wrap(.{ .cau = cau });
3414 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
34163415 if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
34173416 }
34183417 for (zcu.namespacePtr(ns).priv_usingnamespace.items) |nav| {
3419 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3420 const unit = AnalUnit.wrap(.{ .cau = cau });
3418 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
34213419 if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
34223420 }
34233421 continue;
......@@ -3527,12 +3525,6 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
35273525 return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
35283526}
35293527
3530pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File {
3531 const ip = &zcu.intern_pool;
3532 const file_index = ip.getCau(cau).zir_index.resolveFile(ip);
3533 return zcu.fileByIndex(file_index);
3534}
3535
35363528pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) {
35373529 return .{ .data = .{ .unit = unit, .zcu = zcu } };
35383530}
......@@ -3545,19 +3537,17 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
35453537 const zcu = data.zcu;
35463538 const ip = &zcu.intern_pool;
35473539 switch (data.unit.unwrap()) {
3548 .cau => |cau_index| {
3549 const cau = ip.getCau(cau_index);
3550 switch (cau.owner.unwrap()) {
3551 .nav => |nav| return writer.print("cau(decl='{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
3552 .type => |ty| return writer.print("cau(ty='{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),
3553 .none => if (cau.zir_index.resolveFull(ip)) |resolved| {
3554 const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
3555 return writer.print("cau(inst=('{s}', %{}))", .{ file_path, @intFromEnum(resolved.inst) });
3556 } else {
3557 return writer.writeAll("cau(inst=<lost>)");
3558 },
3540 .@"comptime" => |cu_id| {
3541 const cu = ip.getComptimeUnit(cu_id);
3542 if (cu.zir_index.resolveFull(ip)) |resolved| {
3543 const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
3544 return writer.print("comptime(inst=('{s}', %{}))", .{ file_path, @intFromEnum(resolved.inst) });
3545 } else {
3546 return writer.writeAll("comptime(inst=<list>)");
35593547 }
35603548 },
3549 .nav_val => |nav| return writer.print("nav_val('{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
3550 .type => |ty| return writer.print("ty('{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),
35613551 .func => |func| {
35623552 const nav = zcu.funcInfo(func).owner_nav;
35633553 return writer.print("func('{}')", .{ip.getNav(nav).fqn.fmt(ip)});
src/Zcu/PerThread.zig+941-972
......@@ -545,144 +545,173 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
545545pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
546546 const file_root_type = pt.zcu.fileRootType(file_index);
547547 if (file_root_type != .none) {
548 _ = try pt.ensureTypeUpToDate(file_root_type, false);
548 _ = try pt.ensureTypeUpToDate(file_root_type);
549549 } else {
550550 return pt.semaFile(file_index);
551551 }
552552}
553553
554/// This ensures that the state of the `Cau`, and of its corresponding `Nav` or type,
555/// is fully up-to-date. Note that the type of the `Nav` may not be fully resolved.
556/// Returns `error.AnalysisFail` if the `Cau` has an error.
557pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu.SemaError!void {
554/// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis
555/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
556/// free to ignore this, since the error is already registered.
557pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void {
558558 const tracy = trace(@src());
559559 defer tracy.end();
560560
561561 const zcu = pt.zcu;
562562 const gpa = zcu.gpa;
563 const ip = &zcu.intern_pool;
564563
565 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
566 const cau = ip.getCau(cau_index);
564 const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id });
567565
568 log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)});
566 log.debug("ensureComptimeUnitUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
569567
570568 assert(!zcu.analysis_in_progress.contains(anal_unit));
571569
572 // Determine whether or not this Cau is outdated, i.e. requires re-analysis
573 // even if `complete`. If a Cau is PO, we pessismistically assume that it
574 // *does* require re-analysis, to ensure that the Cau is definitely
575 // up-to-date when this function returns.
576
577 // If analysis occurs in a poor order, this could result in over-analysis.
578 // We do our best to avoid this by the other dependency logic in this file
579 // which tries to limit re-analysis to Caus whose previously listed
580 // dependencies are all up-to-date.
570 // Determine whether or not this `ComptimeUnit` is outdated. For this kind of `AnalUnit`, that's
571 // the only indicator as to whether or not analysis is required; when a `ComptimeUnit` is first
572 // created, it's marked as outdated.
573 //
574 // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
575 // ensure that the unit is definitely up-to-date when this function returns. This mechanism could
576 // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
577 // carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
581578
582 const cau_outdated = zcu.outdated.swapRemove(anal_unit) or
579 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
583580 zcu.potentially_outdated.swapRemove(anal_unit);
584581
585 const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
586
587 if (cau_outdated) {
582 if (was_outdated) {
588583 _ = zcu.outdated_ready.swapRemove(anal_unit);
589 } else {
590 // We can trust the current information about this `Cau`.
591 if (prev_failed) {
592 return error.AnalysisFail;
593 }
594 // If it wasn't failed and wasn't marked outdated, then either...
595 // * it is a type and is up-to-date, or
596 // * it is a `comptime` decl and is up-to-date, or
597 // * it is another decl and is EITHER up-to-date OR never-referenced (so unresolved)
598 // We just need to check for that last case.
599 switch (cau.owner.unwrap()) {
600 .type, .none => return,
601 .nav => |nav| if (ip.getNav(nav).status == .resolved) return,
584 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
585 if (dev.env.supports(.incremental)) {
586 zcu.deleteUnitExports(anal_unit);
587 zcu.deleteUnitReferences(anal_unit);
588 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
589 kv.value.destroy(gpa);
590 }
591 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
602592 }
593 } else {
594 // We can trust the current information about this unit.
595 if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
596 if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail;
597 return;
603598 }
604599
605 const sema_result: SemaCauResult, const analysis_fail = if (pt.ensureCauAnalyzedInner(cau_index, cau_outdated)) |result|
606 // This `Cau` has gone from failed to success, so even if the value of the owner `Nav` didn't actually
607 // change, we need to invalidate the dependencies anyway.
608 .{ .{
609 .invalidate_decl_val = result.invalidate_decl_val or prev_failed,
610 .invalidate_decl_ref = result.invalidate_decl_ref or prev_failed,
611 }, false }
612 else |err| switch (err) {
613 error.AnalysisFail => res: {
600 const unit_prog_node = zcu.sema_prog_node.start("comptime", 0);
601 defer unit_prog_node.end();
602
603 return pt.analyzeComptimeUnit(cu_id) catch |err| switch (err) {
604 error.AnalysisFail => {
614605 if (!zcu.failed_analysis.contains(anal_unit)) {
615 // If this `Cau` caused the error, it would have an entry in `failed_analysis`.
606 // If this unit caused the error, it would have an entry in `failed_analysis`.
616607 // Since it does not, this must be a transitive failure.
617608 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
618609 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
619610 }
620 // We consider this `Cau` to be outdated if:
621 // * Previous analysis succeeded; in this case, we need to re-analyze dependants to ensure
622 // they hit a transitive error here, rather than reporting a different error later (which
623 // may now be invalid).
624 // * The `Cau` is a type; in this case, the declaration site may require re-analysis to
625 // construct a valid type.
626 const outdated = !prev_failed or cau.owner.unwrap() == .type;
627 break :res .{ .{
628 .invalidate_decl_val = outdated,
629 .invalidate_decl_ref = outdated,
630 }, true };
611 return error.AnalysisFail;
631612 },
632 error.OutOfMemory => res: {
633 try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
634 try zcu.retryable_failures.ensureUnusedCapacity(gpa, 1);
635 const msg = try Zcu.ErrorMsg.create(
636 gpa,
637 .{ .base_node_inst = cau.zir_index, .offset = Zcu.LazySrcLoc.Offset.nodeOffset(0) },
638 "unable to analyze: OutOfMemory",
639 .{},
640 );
641 zcu.retryable_failures.appendAssumeCapacity(anal_unit);
642 zcu.failed_analysis.putAssumeCapacityNoClobber(anal_unit, msg);
643 break :res .{ .{
644 .invalidate_decl_val = true,
645 .invalidate_decl_ref = true,
646 }, true };
613 error.OutOfMemory => {
614 // TODO: it's unclear how to gracefully handle this.
615 // To report the error cleanly, we need to add a message to `failed_analysis` and a
616 // corresponding entry to `retryable_failures`; but either of these things is quite
617 // likely to OOM at this point.
618 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
619 // for reporting OOM errors without allocating.
620 return error.OutOfMemory;
647621 },
622 error.GenericPoison => unreachable,
623 error.ComptimeReturn => unreachable,
624 error.ComptimeBreak => unreachable,
648625 };
649
650 if (cau_outdated) {
651 // TODO: we do not yet have separate dependencies for decl values vs types.
652 const invalidate = sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref;
653 const dependee: InternPool.Dependee = switch (cau.owner.unwrap()) {
654 .none => return, // there are no dependencies on a `comptime` decl!
655 .nav => |nav_index| .{ .nav_val = nav_index },
656 .type => |ty| .{ .interned = ty },
657 };
658
659 if (invalidate) {
660 // This dependency was marked as PO, meaning dependees were waiting
661 // on its analysis result, and it has turned out to be outdated.
662 // Update dependees accordingly.
663 try zcu.markDependeeOutdated(.marked_po, dependee);
664 } else {
665 // This dependency was previously PO, but turned out to be up-to-date.
666 // We do not need to queue successive analysis.
667 try zcu.markPoDependeeUpToDate(dependee);
668 }
669 }
670
671 if (analysis_fail) return error.AnalysisFail;
672626}
673627
674fn ensureCauAnalyzedInner(
675 pt: Zcu.PerThread,
676 cau_index: InternPool.Cau.Index,
677 cau_outdated: bool,
678) Zcu.SemaError!SemaCauResult {
628/// Re-analyzes a `ComptimeUnit`. The unit has already been determined to be out-of-date, and old
629/// side effects (exports/references/etc) have been dropped. If semantic analysis fails, this
630/// function will return `error.AnalysisFail`, and it is the caller's reponsibility to add an entry
631/// to `transitive_failed_analysis` if necessary.
632fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void {
679633 const zcu = pt.zcu;
634 const gpa = zcu.gpa;
680635 const ip = &zcu.intern_pool;
681636
682 const cau = ip.getCau(cau_index);
683 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
637 const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id });
638 const comptime_unit = ip.getComptimeUnit(cu_id);
639
640 log.debug("analyzeComptimeUnit {}", .{zcu.fmtAnalUnit(anal_unit)});
641
642 const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
643 const file = zcu.fileByIndex(inst_resolved.file);
644 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
645 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
646 // in `ensureComptimeUnitUpToDate`.
647 if (file.status != .success_zir) return error.AnalysisFail;
648 const zir = file.zir;
649
650 // We are about to re-analyze this unit; drop its depenndencies.
651 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
652
653 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
654 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
655
656 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
657 defer analysis_arena.deinit();
658
659 var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
660 defer comptime_err_ret_trace.deinit();
661
662 var sema: Sema = .{
663 .pt = pt,
664 .gpa = gpa,
665 .arena = analysis_arena.allocator(),
666 .code = zir,
667 .owner = anal_unit,
668 .func_index = .none,
669 .func_is_naked = false,
670 .fn_ret_ty = .void,
671 .fn_ret_ty_ies = null,
672 .comptime_err_ret_trace = &comptime_err_ret_trace,
673 };
674 defer sema.deinit();
675
676 // The comptime unit declares on the source of the corresponding `comptime` declaration.
677 try sema.declareDependency(.{ .src_hash = comptime_unit.zir_index });
678
679 var block: Sema.Block = .{
680 .parent = null,
681 .sema = &sema,
682 .namespace = comptime_unit.namespace,
683 .instructions = .{},
684 .inlining = null,
685 .is_comptime = true,
686 .src_base_inst = comptime_unit.zir_index,
687 .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.comptime", .{
688 Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip).fmt(ip),
689 }, .no_embedded_nulls),
690 };
691 defer block.instructions.deinit(gpa);
692
693 const zir_decl = zir.getDeclaration(inst_resolved.inst);
694 assert(zir_decl.kind == .@"comptime");
695 assert(zir_decl.type_body == null);
696 assert(zir_decl.align_body == null);
697 assert(zir_decl.linksection_body == null);
698 assert(zir_decl.addrspace_body == null);
699 const value_body = zir_decl.value_body.?;
700
701 const result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
702 assert(result_ref == .void_value); // AstGen should always uphold this
703
704 // Nothing else to do -- for a comptime decl, all we care about are the side effects.
705 // Just make sure to `flushExports`.
706 try sema.flushExports();
707}
684708
685 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
709/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis
710/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
711/// free to ignore this, since the error is already registered.
712pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {
713 const tracy = trace(@src());
714 defer tracy.end();
686715
687716 // TODO: document this elsewhere mlugg!
688717 // For my own benefit, here's how a namespace update for a normal (non-file-root) type works:
......@@ -692,821 +721,826 @@ fn ensureCauAnalyzedInner(
692721 // * Any change to the `struct` body -- including changing a declaration -- invalidates this
693722 // * `S` is re-analyzed, but notes:
694723 // * there is an existing struct instance (at this `TrackedInst` with these captures)
695 // * the struct's `Cau` is up-to-date (because nothing about the fields changed)
724 // * the struct's resolution is up-to-date (because nothing about the fields changed)
696725 // * so, it uses the same `struct`
697726 // * but this doesn't stop it from updating the namespace!
698727 // * we basically do `scanDecls`, updating the namespace as needed
699728 // * so everyone lived happily ever after
700729
701 if (zcu.fileByIndex(inst_info.file).status != .success_zir) {
702 return error.AnalysisFail;
703 }
704
705 // `cau_outdated` can be true in the initial update for `comptime` declarations,
706 // so this isn't a `dev.check`.
707 if (cau_outdated and dev.env.supports(.incremental)) {
708 // The exports this `Cau` performs will be re-discovered, so we remove them here
709 // prior to re-analysis.
710 zcu.deleteUnitExports(anal_unit);
711 zcu.deleteUnitReferences(anal_unit);
712 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
713 kv.value.destroy(zcu.gpa);
714 }
715 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
716 }
717
718 const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) {
719 .nav => |nav| ip.getNav(nav).fqn.toSlice(ip),
720 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
721 .none => "comptime",
722 }, 0);
723 defer decl_prog_node.end();
724
725 return pt.semaCau(cau_index) catch |err| switch (err) {
726 error.GenericPoison, error.ComptimeBreak, error.ComptimeReturn => unreachable,
727 error.AnalysisFail, error.OutOfMemory => |e| return e,
728 };
729}
730
731pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void {
732 dev.check(.sema);
733
734 const tracy = trace(@src());
735 defer tracy.end();
736
737730 const zcu = pt.zcu;
738731 const gpa = zcu.gpa;
739732 const ip = &zcu.intern_pool;
740733
741 // We only care about the uncoerced function.
742 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
743 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
734 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
735 const nav = ip.getNav(nav_id);
744736
745 log.debug("ensureFuncBodyAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)});
737 log.debug("ensureNavUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
746738
747 const func = zcu.funcInfo(maybe_coerced_func_index);
739 // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the
740 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
741 // been analyzed so far.
742 //
743 // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
744 // ensure that the unit is definitely up-to-date when this function returns. This mechanism could
745 // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
746 // carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
748747
749 const func_outdated = zcu.outdated.swapRemove(anal_unit) or
748 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
750749 zcu.potentially_outdated.swapRemove(anal_unit);
751750
752 const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
751 const prev_failed = zcu.failed_analysis.contains(anal_unit) or
752 zcu.transitive_failed_analysis.contains(anal_unit);
753753
754 if (func_outdated) {
754 if (was_outdated) {
755 dev.check(.incremental);
755756 _ = zcu.outdated_ready.swapRemove(anal_unit);
756 } else {
757 // We can trust the current information about this function.
758 if (prev_failed) {
759 return error.AnalysisFail;
760 }
761 switch (func.analysisUnordered(ip).state) {
762 .unreferenced => {}, // this is the first reference
763 .queued => {}, // we're waiting on first-time analysis
764 .analyzed => return, // up-to-date
757 zcu.deleteUnitExports(anal_unit);
758 zcu.deleteUnitReferences(anal_unit);
759 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
760 kv.value.destroy(gpa);
765761 }
762 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
763 } else {
764 // We can trust the current information about this unit.
765 if (prev_failed) return error.AnalysisFail;
766 if (nav.status == .resolved) return;
766767 }
767768
768 const ies_outdated, const analysis_fail = if (pt.ensureFuncBodyAnalyzedInner(func_index, func_outdated)) |result|
769 .{ result.ies_outdated, false }
770 else |err| switch (err) {
769 const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0);
770 defer unit_prog_node.end();
771
772 const sema_result: SemaNavResult, const new_failed: bool = if (pt.analyzeNavVal(nav_id)) |result| res: {
773 break :res .{
774 .{
775 // If the unit has gone from failed to success, we still need to invalidate the dependencies.
776 .invalidate_nav_val = result.invalidate_nav_val or prev_failed,
777 .invalidate_nav_ref = result.invalidate_nav_ref or prev_failed,
778 },
779 false,
780 };
781 } else |err| switch (err) {
771782 error.AnalysisFail => res: {
772783 if (!zcu.failed_analysis.contains(anal_unit)) {
773 // If this function caused the error, it would have an entry in `failed_analysis`.
784 // If this unit caused the error, it would have an entry in `failed_analysis`.
774785 // Since it does not, this must be a transitive failure.
775786 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
776787 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
777788 }
778 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
779 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting
780 // a different error later (which may now be invalid).
781 break :res .{ !prev_failed, true };
789 break :res .{ .{
790 .invalidate_nav_val = !prev_failed,
791 .invalidate_nav_ref = !prev_failed,
792 }, true };
782793 },
783 error.OutOfMemory => return error.OutOfMemory, // TODO: graceful handling like `ensureCauAnalyzed`
794 error.OutOfMemory => {
795 // TODO: it's unclear how to gracefully handle this.
796 // To report the error cleanly, we need to add a message to `failed_analysis` and a
797 // corresponding entry to `retryable_failures`; but either of these things is quite
798 // likely to OOM at this point.
799 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
800 // for reporting OOM errors without allocating.
801 return error.OutOfMemory;
802 },
803 error.GenericPoison => unreachable,
804 error.ComptimeReturn => unreachable,
805 error.ComptimeBreak => unreachable,
784806 };
785807
786 if (func_outdated) {
787 if (ies_outdated) {
788 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });
808 if (was_outdated) {
809 // TODO: we do not yet have separate dependencies for Nav values vs types.
810 const invalidate = sema_result.invalidate_nav_val or sema_result.invalidate_nav_ref;
811 const dependee: InternPool.Dependee = .{ .nav_val = nav_id };
812 if (invalidate) {
813 // This dependency was marked as PO, meaning dependees were waiting
814 // on its analysis result, and it has turned out to be outdated.
815 // Update dependees accordingly.
816 try zcu.markDependeeOutdated(.marked_po, dependee);
789817 } else {
790 try zcu.markPoDependeeUpToDate(.{ .interned = func_index });
818 // This dependency was previously PO, but turned out to be up-to-date.
819 // We do not need to queue successive analysis.
820 try zcu.markPoDependeeUpToDate(dependee);
791821 }
792822 }
793823
794 if (analysis_fail) return error.AnalysisFail;
824 if (new_failed) return error.AnalysisFail;
795825}
796826
797fn ensureFuncBodyAnalyzedInner(
798 pt: Zcu.PerThread,
799 func_index: InternPool.Index,
800 func_outdated: bool,
801) Zcu.SemaError!struct { ies_outdated: bool } {
827const SemaNavResult = packed struct {
828 /// Whether the value of a `decl_val` of the corresponding Nav changed.
829 invalidate_nav_val: bool,
830 /// Whether the type of a `decl_ref` of the corresponding Nav changed.
831 invalidate_nav_ref: bool,
832};
833
834fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!SemaNavResult {
802835 const zcu = pt.zcu;
803836 const gpa = zcu.gpa;
804837 const ip = &zcu.intern_pool;
805838
806 const func = zcu.funcInfo(func_index);
807 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
839 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
840 const old_nav = ip.getNav(nav_id);
808841
809 // Make sure that this function is still owned by the same `Nav`. Otherwise, analyzing
810 // it would be a waste of time in the best case, and could cause codegen to give bogus
811 // results in the worst case.
842 log.debug("analyzeNavVal {}", .{zcu.fmtAnalUnit(anal_unit)});
812843
813 if (func.generic_owner == .none) {
814 // Among another things, this ensures that the function's `zir_body_inst` is correct.
815 try pt.ensureCauAnalyzed(ip.getNav(func.owner_nav).analysis_owner.unwrap().?);
816 if (ip.getNav(func.owner_nav).status.resolved.val != func_index) {
817 // This function is no longer referenced! There's no point in re-analyzing it.
818 // Just mark a transitive failure and move on.
819 return error.AnalysisFail;
820 }
821 } else {
822 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
823 // Among another things, this ensures that the function's `zir_body_inst` is correct.
824 try pt.ensureCauAnalyzed(ip.getNav(go_nav).analysis_owner.unwrap().?);
825 if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) {
826 // The generic owner is no longer referenced, so this function is also unreferenced.
827 // There's no point in re-analyzing it. Just mark a transitive failure and move on.
828 return error.AnalysisFail;
829 }
830 }
844 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
845 const file = zcu.fileByIndex(inst_resolved.file);
846 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
847 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
848 // in `ensureComptimeUnitUpToDate`.
849 if (file.status != .success_zir) return error.AnalysisFail;
850 const zir = file.zir;
831851
832 // We'll want to remember what the IES used to be before the update for
833 // dependency invalidation purposes.
834 const old_resolved_ies = if (func.analysisUnordered(ip).inferred_error_set)
835 func.resolvedErrorSetUnordered(ip)
836 else
837 .none;
852 // We are about to re-analyze this unit; drop its depenndencies.
853 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
838854
839 if (func_outdated) {
840 dev.check(.incremental);
841 zcu.deleteUnitExports(anal_unit);
842 zcu.deleteUnitReferences(anal_unit);
843 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
844 kv.value.destroy(gpa);
845 }
846 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
847 }
855 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
856 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
848857
849 if (!func_outdated) {
850 // We can trust the current information about this function.
851 if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) {
852 return error.AnalysisFail;
853 }
854 switch (func.analysisUnordered(ip).state) {
855 .unreferenced => {}, // this is the first reference
856 .queued => {}, // we're waiting on first-time analysis
857 .analyzed => return .{ .ies_outdated = false }, // up-to-date
858 }
859 }
858 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
859 defer analysis_arena.deinit();
860860
861 log.debug("analyze and generate fn body {}; reason='{s}'", .{
862 zcu.fmtAnalUnit(anal_unit),
863 if (func_outdated) "outdated" else "never analyzed",
864 });
861 var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
862 defer comptime_err_ret_trace.deinit();
865863
866 var air = try pt.analyzeFnBody(func_index);
867 errdefer air.deinit(gpa);
864 var sema: Sema = .{
865 .pt = pt,
866 .gpa = gpa,
867 .arena = analysis_arena.allocator(),
868 .code = zir,
869 .owner = anal_unit,
870 .func_index = .none,
871 .func_is_naked = false,
872 .fn_ret_ty = .void,
873 .fn_ret_ty_ies = null,
874 .comptime_err_ret_trace = &comptime_err_ret_trace,
875 };
876 defer sema.deinit();
868877
869 const ies_outdated = func_outdated and
870 (!func.analysisUnordered(ip).inferred_error_set or func.resolvedErrorSetUnordered(ip) != old_resolved_ies);
878 // The comptime unit declares on the source of the corresponding declaration.
879 try sema.declareDependency(.{ .src_hash = old_nav.analysis.?.zir_index });
871880
872 const comp = zcu.comp;
881 var block: Sema.Block = .{
882 .parent = null,
883 .sema = &sema,
884 .namespace = old_nav.analysis.?.namespace,
885 .instructions = .{},
886 .inlining = null,
887 .is_comptime = true,
888 .src_base_inst = old_nav.analysis.?.zir_index,
889 .type_name_ctx = old_nav.fqn,
890 };
891 defer block.instructions.deinit(gpa);
873892
874 const dump_air = build_options.enable_debug_extensions and comp.verbose_air;
875 const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
893 const zir_decl = zir.getDeclaration(inst_resolved.inst);
876894
877 if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {
878 air.deinit(gpa);
879 return .{ .ies_outdated = ies_outdated };
880 }
895 assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));
881896
882 // This job depends on any resolve_type_fully jobs queued up before it.
883 try comp.queueJob(.{ .codegen_func = .{
884 .func = func_index,
885 .air = air,
886 } });
897 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
898 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
899 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
900 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
901 const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
887902
888 return .{ .ies_outdated = ies_outdated };
889}
903 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
904 // or otherwise, we analyze the value body, populating `early_val` in the process.
890905
891/// Takes ownership of `air`, even on error.
892/// If any types referenced by `air` are unresolved, marks the codegen as failed.
893pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Air) Allocator.Error!void {
894 const zcu = pt.zcu;
895 const gpa = zcu.gpa;
896 const ip = &zcu.intern_pool;
897 const comp = zcu.comp;
906 const nav_ty: Type, const early_val: ?Value = if (zir_decl.type_body) |type_body| ty: {
907 // We evaluate only the type now; no need for the value yet.
908 const uncoerced_type_ref = try sema.resolveInlineBody(&block, type_body, inst_resolved.inst);
909 const type_ref = try sema.coerce(&block, .type, uncoerced_type_ref, ty_src);
910 break :ty .{ .fromInterned(type_ref.toInterned().?), null };
911 } else ty: {
912 // We don't have a type body, so we need to evaluate the value immediately.
913 const value_body = zir_decl.value_body.?;
914 const result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
915 const val = try sema.resolveFinalDeclValue(&block, init_src, result_ref);
916 break :ty .{ val.typeOf(zcu), val };
917 };
898918
899 defer {
900 var air_mut = air;
901 air_mut.deinit(gpa);
919 switch (zir_decl.kind) {
920 .@"comptime" => unreachable, // this is not a Nav
921 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),
922 .@"usingnamespace" => {},
923 .@"const" => {},
924 .@"var" => try sema.validateVarType(
925 &block,
926 if (zir_decl.type_body != null) ty_src else init_src,
927 nav_ty,
928 zir_decl.linkage == .@"extern",
929 ),
902930 }
903931
904 const func = zcu.funcInfo(func_index);
905 const nav_index = func.owner_nav;
906 const nav = ip.getNav(nav_index);
907
908 var liveness = try Liveness.analyze(gpa, air, ip);
909 defer liveness.deinit(gpa);
932 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
933 // the full pointer type of this declaration.
910934
911 if (build_options.enable_debug_extensions and comp.verbose_air) {
912 std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});
913 @import("../print_air.zig").dump(pt, air, liveness);
914 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
915 }
935 const alignment: InternPool.Alignment = a: {
936 const align_body = zir_decl.align_body orelse break :a .none;
937 const align_ref = try sema.resolveInlineBody(&block, align_body, inst_resolved.inst);
938 break :a try sema.analyzeAsAlign(&block, align_src, align_ref);
939 };
916940
917 if (std.debug.runtime_safety) {
918 var verify: Liveness.Verify = .{
919 .gpa = gpa,
920 .air = air,
921 .liveness = liveness,
922 .intern_pool = ip,
923 };
924 defer verify.deinit();
941 const @"linksection": InternPool.OptionalNullTerminatedString = ls: {
942 const linksection_body = zir_decl.linksection_body orelse break :ls .none;
943 const linksection_ref = try sema.resolveInlineBody(&block, linksection_body, inst_resolved.inst);
944 const bytes = try sema.toConstString(&block, section_src, linksection_ref, .{
945 .needed_comptime_reason = "linksection must be comptime-known",
946 });
947 if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
948 return sema.fail(&block, section_src, "linksection cannot contain null bytes", .{});
949 } else if (bytes.len == 0) {
950 return sema.fail(&block, section_src, "linksection cannot be empty", .{});
951 }
952 break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
953 };
925954
926 verify.verify() catch |err| switch (err) {
927 error.OutOfMemory => return error.OutOfMemory,
928 else => {
929 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
930 gpa,
931 zcu.navSrcLoc(nav_index),
932 "invalid liveness: {s}",
933 .{@errorName(err)},
934 ));
935 return;
955 const @"addrspace": std.builtin.AddressSpace = as: {
956 const addrspace_ctx: Sema.AddressSpaceContext = switch (zir_decl.kind) {
957 .@"var" => .variable,
958 else => switch (nav_ty.zigTypeTag(zcu)) {
959 .@"fn" => .function,
960 else => .constant,
936961 },
937962 };
963 const target = zcu.getTarget();
964 const addrspace_body = zir_decl.addrspace_body orelse break :as switch (addrspace_ctx) {
965 .function => target_util.defaultAddressSpace(target, .function),
966 .variable => target_util.defaultAddressSpace(target, .global_mutable),
967 .constant => target_util.defaultAddressSpace(target, .global_constant),
968 else => unreachable,
969 };
970 const addrspace_ref = try sema.resolveInlineBody(&block, addrspace_body, inst_resolved.inst);
971 break :as try sema.analyzeAsAddressSpace(&block, addrspace_src, addrspace_ref, addrspace_ctx);
972 };
973
974 // Lastly, we must evaluate the value if we have not already done so. Note, however, that extern declarations
975 // don't have an associated value body.
976
977 const final_val: ?Value = early_val orelse if (zir_decl.value_body) |value_body| val: {
978 // Put the resolved type into `inst_map` to be used as the result type of the init.
979 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{inst_resolved.inst});
980 sema.inst_map.putAssumeCapacity(inst_resolved.inst, Air.internedToRef(nav_ty.toIntern()));
981 const uncoerced_result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
982 assert(sema.inst_map.remove(inst_resolved.inst));
983
984 const result_ref = try sema.coerce(&block, nav_ty, uncoerced_result_ref, init_src);
985 break :val try sema.resolveFinalDeclValue(&block, init_src, result_ref);
986 } else null;
987
988 const nav_val: Value = switch (zir_decl.linkage) {
989 .normal, .@"export" => switch (zir_decl.kind) {
990 .@"var" => .fromInterned(try pt.intern(.{ .variable = .{
991 .ty = nav_ty.toIntern(),
992 .init = final_val.?.toIntern(),
993 .owner_nav = nav_id,
994 .is_threadlocal = zir_decl.is_threadlocal,
995 .is_weak_linkage = false,
996 } })),
997 else => final_val.?,
998 },
999 .@"extern" => val: {
1000 assert(final_val == null); // extern decls do not have a value body
1001 const lib_name: ?[]const u8 = if (zir_decl.lib_name != .empty) l: {
1002 break :l zir.nullTerminatedString(zir_decl.lib_name);
1003 } else null;
1004 if (lib_name) |l| {
1005 const lib_name_src = block.src(.{ .node_offset_lib_name = 0 });
1006 try sema.handleExternLibName(&block, lib_name_src, l);
1007 }
1008 break :val .fromInterned(try pt.getExtern(.{
1009 .name = old_nav.name,
1010 .ty = nav_ty.toIntern(),
1011 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
1012 .is_const = zir_decl.kind == .@"const",
1013 .is_threadlocal = zir_decl.is_threadlocal,
1014 .is_weak_linkage = false,
1015 .is_dll_import = false,
1016 .alignment = alignment,
1017 .@"addrspace" = @"addrspace",
1018 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
1019 .owner_nav = undefined, // ignored by `getExtern`
1020 }));
1021 },
1022 };
1023
1024 switch (nav_val.toIntern()) {
1025 .generic_poison => unreachable, // assertion failure
1026 .unreachable_value => unreachable, // assertion failure
1027 else => {},
9381028 }
9391029
940 const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0);
941 defer codegen_prog_node.end();
1030 // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type,
1031 // this resolves the type `type` (which needs no resolution), not the struct itself.
1032 try nav_ty.resolveLayout(pt);
9421033
943 if (!air.typesFullyResolved(zcu)) {
944 // A type we depend on failed to resolve. This is a transitive failure.
945 // Correcting this failure will involve changing a type this function
946 // depends on, hence triggering re-analysis of this function, so this
947 // interacts correctly with incremental compilation.
948 // TODO: do we need to mark this failure anywhere? I don't think so, since compilation
949 // will fail due to the type error anyway.
950 } else if (comp.bin_file) |lf| {
951 lf.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) {
952 error.OutOfMemory => return error.OutOfMemory,
953 error.AnalysisFail => {
954 assert(zcu.failed_codegen.contains(nav_index));
955 },
956 else => {
957 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
958 gpa,
959 zcu.navSrcLoc(nav_index),
960 "unable to codegen: {s}",
961 .{@errorName(err)},
962 ));
963 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index }));
964 },
965 };
966 } else if (zcu.llvm_object) |llvm_object| {
967 llvm_object.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) {
968 error.OutOfMemory => return error.OutOfMemory,
1034 // TODO: this is jank. If #20663 is rejected, let's think about how to better model `usingnamespace`.
1035 if (zir_decl.kind == .@"usingnamespace") {
1036 if (nav_ty.toIntern() != .type_type) {
1037 return sema.fail(&block, ty_src, "expected type, found {}", .{nav_ty.fmt(pt)});
1038 }
1039 if (nav_val.toType().getNamespace(zcu) == .none) {
1040 return sema.fail(&block, ty_src, "type {} has no namespace", .{nav_val.toType().fmt(pt)});
1041 }
1042 ip.resolveNavValue(nav_id, .{
1043 .val = nav_val.toIntern(),
1044 .alignment = .none,
1045 .@"linksection" = .none,
1046 .@"addrspace" = .generic,
1047 });
1048 // TODO: usingnamespace cannot participate in incremental compilation
1049 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1050 return .{
1051 .invalidate_nav_val = true,
1052 .invalidate_nav_ref = true,
9691053 };
9701054 }
971}
9721055
973/// https://github.com/ziglang/zig/issues/14307
974pub fn semaPkg(pt: Zcu.PerThread, pkg: *Module) !void {
975 dev.check(.sema);
976 const import_file_result = try pt.importPkg(pkg);
977 const root_type = pt.zcu.fileRootType(import_file_result.file_index);
978 if (root_type == .none) {
979 return pt.semaFile(import_file_result.file_index);
980 }
981}
1056 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
1057 .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen
1058 .variable => |v| .{ v.owner_nav == nav_id, false },
1059 .@"extern" => |e| .{
1060 false,
1061 Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn" and zir_decl.linkage == .@"extern",
1062 },
1063 else => .{ true, false },
1064 };
9821065
983fn createFileRootStruct(
984 pt: Zcu.PerThread,
985 file_index: Zcu.File.Index,
986 namespace_index: Zcu.Namespace.Index,
987 replace_existing: bool,
988) Allocator.Error!InternPool.Index {
989 const zcu = pt.zcu;
990 const gpa = zcu.gpa;
991 const ip = &zcu.intern_pool;
992 const file = zcu.fileByIndex(file_index);
993 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
994 assert(extended.opcode == .struct_decl);
995 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
996 assert(!small.has_captures_len);
997 assert(!small.has_backing_int);
998 assert(small.layout == .auto);
999 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1000 const fields_len = if (small.has_fields_len) blk: {
1001 const fields_len = file.zir.extra[extra_index];
1002 extra_index += 1;
1003 break :blk fields_len;
1004 } else 0;
1005 const decls_len = if (small.has_decls_len) blk: {
1006 const decls_len = file.zir.extra[extra_index];
1007 extra_index += 1;
1008 break :blk decls_len;
1009 } else 0;
1010 const decls = file.zir.bodySlice(extra_index, decls_len);
1011 extra_index += decls_len;
1066 if (is_owned_fn) {
1067 // linksection etc are legal, except some targets do not support function alignment.
1068 if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
1069 return sema.fail(&block, align_src, "target does not support function alignment", .{});
1070 }
1071 } else if (try nav_ty.comptimeOnlySema(pt)) {
1072 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.
1073 const reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {
1074 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
1075 else => "comptime-only type",
1076 };
1077 if (zir_decl.align_body != null) {
1078 return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{reason});
1079 }
1080 if (zir_decl.linksection_body != null) {
1081 return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{reason});
1082 }
1083 if (zir_decl.addrspace_body != null) {
1084 return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{reason});
1085 }
1086 }
10121087
1013 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{
1014 .file = file_index,
1015 .inst = .main_struct_inst,
1088 ip.resolveNavValue(nav_id, .{
1089 .val = nav_val.toIntern(),
1090 .alignment = alignment,
1091 .@"linksection" = @"linksection",
1092 .@"addrspace" = @"addrspace",
10161093 });
1017 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
1018 .layout = .auto,
1019 .fields_len = fields_len,
1020 .known_non_opv = small.known_non_opv,
1021 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
1022 .any_comptime_fields = small.any_comptime_fields,
1023 .any_default_inits = small.any_default_inits,
1024 .inits_resolved = false,
1025 .any_aligned_fields = small.any_aligned_fields,
1026 .key = .{ .declared = .{
1027 .zir_index = tracked_inst,
1028 .captures = &.{},
1029 } },
1030 }, replace_existing)) {
1031 .existing => unreachable, // we wouldn't be analysing the file root if this type existed
1032 .wip => |wip| wip,
1033 };
1034 errdefer wip_ty.cancel(ip, pt.tid);
1035
1036 wip_ty.setName(ip, try file.internFullyQualifiedName(pt));
1037 ip.namespacePtr(namespace_index).owner_type = wip_ty.index;
1038 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, namespace_index, wip_ty.index);
10391094
1040 if (zcu.comp.incremental) {
1041 try ip.addDependency(
1042 gpa,
1043 AnalUnit.wrap(.{ .cau = new_cau_index }),
1044 .{ .src_hash = tracked_inst },
1045 );
1046 }
1095 // Mark the unit as completed before evaluating the export!
1096 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
10471097
1048 try pt.scanNamespace(namespace_index, decls);
1049 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
1050 codegen_type: {
1051 if (zcu.comp.config.use_llvm) break :codegen_type;
1052 if (file.mod.strip) break :codegen_type;
1053 // This job depends on any resolve_type_fully jobs queued up before it.
1054 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
1098 if (zir_decl.linkage == .@"export") {
1099 const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.is_pub) });
1100 const name_slice = zir.nullTerminatedString(zir_decl.name);
1101 const name_ip = try ip.getOrPutString(gpa, pt.tid, name_slice, .no_embedded_nulls);
1102 try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_id);
10551103 }
1056 zcu.setFileRootType(file_index, wip_ty.index);
1057 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
1058}
10591104
1060/// Re-scan the namespace of a file's root struct type on an incremental update.
1061/// The file must have successfully populated ZIR.
1062/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.
1063/// This is called by `updateZirRefs` for all updated files before the main work loop.
1064/// This function does not perform any semantic analysis.
1065fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void {
1066 const zcu = pt.zcu;
1105 try sema.flushExports();
10671106
1068 const file = zcu.fileByIndex(file_index);
1069 assert(file.status == .success_zir);
1070 const file_root_type = zcu.fileRootType(file_index);
1071 if (file_root_type == .none) return;
1107 queue_codegen: {
1108 if (!queue_linker_work) break :queue_codegen;
10721109
1073 log.debug("updateFileNamespace mod={s} sub_file_path={s}", .{
1074 file.mod.fully_qualified_name,
1075 file.sub_file_path,
1076 });
1110 if (!try nav_ty.hasRuntimeBitsSema(pt)) {
1111 if (zcu.comp.config.use_llvm) break :queue_codegen;
1112 if (file.mod.strip) break :queue_codegen;
1113 }
10771114
1078 const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);
1079 const decls = decls: {
1080 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
1081 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
1115 // This job depends on any resolve_type_fully jobs queued up before it.
1116 try zcu.comp.queueJob(.{ .codegen_nav = nav_id });
1117 }
10821118
1083 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1084 extra_index += @intFromBool(small.has_fields_len);
1085 const decls_len = if (small.has_decls_len) blk: {
1086 const decls_len = file.zir.extra[extra_index];
1087 extra_index += 1;
1088 break :blk decls_len;
1089 } else 0;
1090 break :decls file.zir.bodySlice(extra_index, decls_len);
1091 };
1092 try pt.scanNamespace(namespace_index, decls);
1093 zcu.namespacePtr(namespace_index).generation = zcu.generation;
1119 switch (old_nav.status) {
1120 .unresolved => return .{
1121 .invalidate_nav_val = true,
1122 .invalidate_nav_ref = true,
1123 },
1124 .resolved => |old| {
1125 const new = ip.getNav(nav_id).status.resolved;
1126 return .{
1127 .invalidate_nav_val = new.val != old.val,
1128 .invalidate_nav_ref = ip.typeOf(new.val) != ip.typeOf(old.val) or
1129 new.alignment != old.alignment or
1130 new.@"linksection" != old.@"linksection" or
1131 new.@"addrspace" != old.@"addrspace",
1132 };
1133 },
1134 }
10941135}
10951136
1096fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1137pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void {
1138 dev.check(.sema);
1139
10971140 const tracy = trace(@src());
10981141 defer tracy.end();
10991142
11001143 const zcu = pt.zcu;
11011144 const gpa = zcu.gpa;
1102 const file = zcu.fileByIndex(file_index);
1103 assert(zcu.fileRootType(file_index) == .none);
1145 const ip = &zcu.intern_pool;
11041146
1105 if (file.status != .success_zir) {
1106 return error.AnalysisFail;
1107 }
1108 assert(file.zir_loaded);
1147 // We only care about the uncoerced function.
1148 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
1149 const anal_unit: AnalUnit = .wrap(.{ .func = func_index });
11091150
1110 const new_namespace_index = try pt.createNamespace(.{
1111 .parent = .none,
1112 .owner_type = undefined, // set in `createFileRootStruct`
1113 .file_scope = file_index,
1114 .generation = zcu.generation,
1115 });
1116 const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);
1117 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
1151 log.debug("ensureFuncBodyUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
11181152
1119 switch (zcu.comp.cache_use) {
1120 .whole => |whole| if (whole.cache_manifest) |man| {
1121 const source = file.getSource(gpa) catch |err| {
1122 try pt.reportRetryableFileError(file_index, "unable to load source: {s}", .{@errorName(err)});
1123 return error.AnalysisFail;
1124 };
1153 const func = zcu.funcInfo(maybe_coerced_func_index);
11251154
1126 const resolved_path = std.fs.path.resolve(gpa, &.{
1127 file.mod.root.root_dir.path orelse ".",
1128 file.mod.root.sub_path,
1129 file.sub_file_path,
1130 }) catch |err| {
1131 try pt.reportRetryableFileError(file_index, "unable to resolve path: {s}", .{@errorName(err)});
1132 return error.AnalysisFail;
1133 };
1134 errdefer gpa.free(resolved_path);
1155 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
1156 zcu.potentially_outdated.swapRemove(anal_unit);
11351157
1136 whole.cache_manifest_mutex.lock();
1137 defer whole.cache_manifest_mutex.unlock();
1138 man.addFilePostContents(resolved_path, source.bytes, source.stat) catch |err| switch (err) {
1139 error.OutOfMemory => |e| return e,
1140 else => {
1141 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
1142 return error.AnalysisFail;
1143 },
1144 };
1158 const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
1159
1160 if (was_outdated) {
1161 dev.check(.incremental);
1162 _ = zcu.outdated_ready.swapRemove(anal_unit);
1163 zcu.deleteUnitExports(anal_unit);
1164 zcu.deleteUnitReferences(anal_unit);
1165 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1166 kv.value.destroy(gpa);
1167 }
1168 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1169 } else {
1170 // We can trust the current information about this function.
1171 if (prev_failed) {
1172 return error.AnalysisFail;
1173 }
1174 switch (func.analysisUnordered(ip).state) {
1175 .unreferenced => {}, // this is the first reference
1176 .queued => {}, // we're waiting on first-time analysis
1177 .analyzed => return, // up-to-date
1178 }
1179 }
1180
1181 const func_prog_node = zcu.sema_prog_node.start(ip.getNav(func.owner_nav).fqn.toSlice(ip), 0);
1182 defer func_prog_node.end();
1183
1184 const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index)) |result|
1185 .{ prev_failed or result.ies_outdated, false }
1186 else |err| switch (err) {
1187 error.AnalysisFail => res: {
1188 if (!zcu.failed_analysis.contains(anal_unit)) {
1189 // If this function caused the error, it would have an entry in `failed_analysis`.
1190 // Since it does not, this must be a transitive failure.
1191 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1192 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
1193 }
1194 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
1195 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting
1196 // a different error later (which may now be invalid).
1197 break :res .{ !prev_failed, true };
11451198 },
1146 .incremental => {},
1199 error.OutOfMemory => {
1200 // TODO: it's unclear how to gracefully handle this.
1201 // To report the error cleanly, we need to add a message to `failed_analysis` and a
1202 // corresponding entry to `retryable_failures`; but either of these things is quite
1203 // likely to OOM at this point.
1204 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
1205 // for reporting OOM errors without allocating.
1206 return error.OutOfMemory;
1207 },
1208 };
1209
1210 if (was_outdated) {
1211 if (ies_outdated) {
1212 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });
1213 } else {
1214 try zcu.markPoDependeeUpToDate(.{ .interned = func_index });
1215 }
11471216 }
1148}
11491217
1150const SemaCauResult = packed struct {
1151 /// Whether the value of a `decl_val` of the corresponding Nav changed.
1152 invalidate_decl_val: bool,
1153 /// Whether the type of a `decl_ref` of the corresponding Nav changed.
1154 invalidate_decl_ref: bool,
1155};
1218 if (new_failed) return error.AnalysisFail;
1219}
11561220
1157/// Performs semantic analysis on the given `Cau`, storing results to its owner `Nav` if needed.
1158/// If analysis fails, returns `error.AnalysisFail`, storing an error in `zcu.failed_analysis` unless
1159/// the error is transitive.
1160/// On success, returns information about whether the `Nav` value changed.
1161fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
1221fn analyzeFuncBody(
1222 pt: Zcu.PerThread,
1223 func_index: InternPool.Index,
1224) Zcu.SemaError!struct { ies_outdated: bool } {
11621225 const zcu = pt.zcu;
11631226 const gpa = zcu.gpa;
11641227 const ip = &zcu.intern_pool;
11651228
1166 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
1167
1168 const cau = ip.getCau(cau_index);
1169 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1170 const file = zcu.fileByIndex(inst_info.file);
1171 const zir = file.zir;
1172
1173 if (file.status != .success_zir) {
1174 return error.AnalysisFail;
1175 }
1229 const func = zcu.funcInfo(func_index);
1230 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
11761231
1177 // We are about to re-analyze this `Cau`; drop its depenndencies.
1178 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1232 // Make sure that this function is still owned by the same `Nav`. Otherwise, analyzing
1233 // it would be a waste of time in the best case, and could cause codegen to give bogus
1234 // results in the worst case.
11791235
1180 switch (cau.owner.unwrap()) {
1181 .none => {}, // `comptime` decl -- we will re-analyze its body.
1182 .nav => {}, // Other decl -- we will re-analyze its value.
1183 .type => |ty| {
1184 // This is an incremental update, and this type is being re-analyzed because it is outdated.
1185 // Create a new type in its place, and mark the old one as outdated so that use sites will
1186 // be re-analyzed and discover an up-to-date type.
1187 const new_ty = try pt.ensureTypeUpToDate(ty, true);
1188 assert(new_ty != ty);
1189 return .{
1190 .invalidate_decl_val = true,
1191 .invalidate_decl_ref = true,
1192 };
1193 },
1236 if (func.generic_owner == .none) {
1237 // Among another things, this ensures that the function's `zir_body_inst` is correct.
1238 try pt.ensureNavValUpToDate(func.owner_nav);
1239 if (ip.getNav(func.owner_nav).status.resolved.val != func_index) {
1240 // This function is no longer referenced! There's no point in re-analyzing it.
1241 // Just mark a transitive failure and move on.
1242 return error.AnalysisFail;
1243 }
1244 } else {
1245 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
1246 // Among another things, this ensures that the function's `zir_body_inst` is correct.
1247 try pt.ensureNavValUpToDate(go_nav);
1248 if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) {
1249 // The generic owner is no longer referenced, so this function is also unreferenced.
1250 // There's no point in re-analyzing it. Just mark a transitive failure and move on.
1251 return error.AnalysisFail;
1252 }
11941253 }
11951254
1196 const is_usingnamespace = switch (cau.owner.unwrap()) {
1197 .nav => |nav| ip.getNav(nav).is_usingnamespace,
1198 .none, .type => false,
1199 };
1255 // We'll want to remember what the IES used to be before the update for
1256 // dependency invalidation purposes.
1257 const old_resolved_ies = if (func.analysisUnordered(ip).inferred_error_set)
1258 func.resolvedErrorSetUnordered(ip)
1259 else
1260 .none;
12001261
1201 log.debug("semaCau {}", .{zcu.fmtAnalUnit(anal_unit)});
1262 log.debug("analyze and generate fn body {}", .{zcu.fmtAnalUnit(anal_unit)});
12021263
1203 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1204 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
1264 var air = try pt.analyzeFnBodyInner(func_index);
1265 errdefer air.deinit(gpa);
12051266
1206 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
1207 defer analysis_arena.deinit();
1267 const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or
1268 func.resolvedErrorSetUnordered(ip) != old_resolved_ies;
12081269
1209 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
1210 defer comptime_err_ret_trace.deinit();
1270 const comp = zcu.comp;
12111271
1212 var sema: Sema = .{
1213 .pt = pt,
1214 .gpa = gpa,
1215 .arena = analysis_arena.allocator(),
1216 .code = zir,
1217 .owner = anal_unit,
1218 .func_index = .none,
1219 .func_is_naked = false,
1220 .fn_ret_ty = Type.void,
1221 .fn_ret_ty_ies = null,
1222 .comptime_err_ret_trace = &comptime_err_ret_trace,
1223 };
1224 defer sema.deinit();
1272 const dump_air = build_options.enable_debug_extensions and comp.verbose_air;
1273 const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
12251274
1226 // Every `Cau` has a dependency on the source of its own ZIR instruction.
1227 try sema.declareDependency(.{ .src_hash = cau.zir_index });
1275 if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {
1276 air.deinit(gpa);
1277 return .{ .ies_outdated = ies_outdated };
1278 }
12281279
1229 var block: Sema.Block = .{
1230 .parent = null,
1231 .sema = &sema,
1232 .namespace = cau.namespace,
1233 .instructions = .{},
1234 .inlining = null,
1235 .is_comptime = true,
1236 .src_base_inst = cau.zir_index,
1237 .type_name_ctx = switch (cau.owner.unwrap()) {
1238 .nav => |nav| ip.getNav(nav).fqn,
1239 .type => |ty| Type.fromInterned(ty).containerTypeName(ip),
1240 .none => try ip.getOrPutStringFmt(gpa, pt.tid, "{}.comptime", .{
1241 Type.fromInterned(zcu.namespacePtr(cau.namespace).owner_type).containerTypeName(ip).fmt(ip),
1242 }, .no_embedded_nulls),
1243 },
1244 };
1245 defer block.instructions.deinit(gpa);
1280 // This job depends on any resolve_type_fully jobs queued up before it.
1281 try comp.queueJob(.{ .codegen_func = .{
1282 .func = func_index,
1283 .air = air,
1284 } });
12461285
1247 const zir_decl = zir.getDeclaration(inst_info.inst);
1286 return .{ .ies_outdated = ies_outdated };
1287}
12481288
1249 // We have to fetch this state before resolving the body because of the `nav_already_populated`
1250 // case below. We might change the language in future so that align/linksection/etc for functions
1251 // work in a way more in line with other declarations, in which case that logic will go away.
1252 const old_nav_info = switch (cau.owner.unwrap()) {
1253 .none, .type => undefined, // we'll never use `old_nav_info`
1254 .nav => |nav| ip.getNav(nav),
1255 };
1289/// Takes ownership of `air`, even on error.
1290/// If any types referenced by `air` are unresolved, marks the codegen as failed.
1291pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Air) Allocator.Error!void {
1292 const zcu = pt.zcu;
1293 const gpa = zcu.gpa;
1294 const ip = &zcu.intern_pool;
1295 const comp = zcu.comp;
12561296
1257 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
1258 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
1259 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
1260 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
1261 const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
1297 defer {
1298 var air_mut = air;
1299 air_mut.deinit(gpa);
1300 }
12621301
1263 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
1264 // or otherwise, we analyze the value body, populating `early_val` in the process.
1302 const func = zcu.funcInfo(func_index);
1303 const nav_index = func.owner_nav;
1304 const nav = ip.getNav(nav_index);
12651305
1266 const decl_ty: Type, const early_val: ?Value = if (zir_decl.type_body) |type_body| ty: {
1267 // We evaluate only the type now; no need for the value yet.
1268 const uncoerced_type_ref = try sema.resolveInlineBody(&block, type_body, inst_info.inst);
1269 const type_ref = try sema.coerce(&block, .type, uncoerced_type_ref, ty_src);
1270 break :ty .{ .fromInterned(type_ref.toInterned().?), null };
1271 } else ty: {
1272 // We don't have a type body, so we need to evaluate the value immediately.
1273 const value_body = zir_decl.value_body.?;
1274 const result_ref = try sema.resolveInlineBody(&block, value_body, inst_info.inst);
1275 const val = try sema.resolveFinalDeclValue(&block, init_src, result_ref);
1276 break :ty .{ val.typeOf(zcu), val };
1277 };
1306 var liveness = try Liveness.analyze(gpa, air, ip);
1307 defer liveness.deinit(gpa);
12781308
1279 switch (zir_decl.kind) {
1280 .unnamed_test, .@"test", .decltest => assert(decl_ty.zigTypeTag(zcu) == .@"fn"),
1281 .@"comptime" => assert(decl_ty.toIntern() == .void_type),
1282 .@"usingnamespace" => {},
1283 .@"const" => {},
1284 .@"var" => try sema.validateVarType(
1285 &block,
1286 if (zir_decl.type_body != null) ty_src else init_src,
1287 decl_ty,
1288 zir_decl.linkage == .@"extern",
1289 ),
1309 if (build_options.enable_debug_extensions and comp.verbose_air) {
1310 std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});
1311 @import("../print_air.zig").dump(pt, air, liveness);
1312 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
12901313 }
12911314
1292 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
1293 // the full pointer type of this declaration.
1315 if (std.debug.runtime_safety) {
1316 var verify: Liveness.Verify = .{
1317 .gpa = gpa,
1318 .air = air,
1319 .liveness = liveness,
1320 .intern_pool = ip,
1321 };
1322 defer verify.deinit();
12941323
1295 const alignment: InternPool.Alignment = a: {
1296 const align_body = zir_decl.align_body orelse break :a .none;
1297 const align_ref = try sema.resolveInlineBody(&block, align_body, inst_info.inst);
1298 break :a try sema.analyzeAsAlign(&block, align_src, align_ref);
1299 };
1324 verify.verify() catch |err| switch (err) {
1325 error.OutOfMemory => return error.OutOfMemory,
1326 else => {
1327 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
1328 gpa,
1329 zcu.navSrcLoc(nav_index),
1330 "invalid liveness: {s}",
1331 .{@errorName(err)},
1332 ));
1333 return;
1334 },
1335 };
1336 }
13001337
1301 const @"linksection": InternPool.OptionalNullTerminatedString = ls: {
1302 const linksection_body = zir_decl.linksection_body orelse break :ls .none;
1303 const linksection_ref = try sema.resolveInlineBody(&block, linksection_body, inst_info.inst);
1304 const bytes = try sema.toConstString(&block, section_src, linksection_ref, .{
1305 .needed_comptime_reason = "linksection must be comptime-known",
1306 });
1307 if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
1308 return sema.fail(&block, section_src, "linksection cannot contain null bytes", .{});
1309 } else if (bytes.len == 0) {
1310 return sema.fail(&block, section_src, "linksection cannot be empty", .{});
1311 }
1312 break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
1313 };
1338 const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0);
1339 defer codegen_prog_node.end();
13141340
1315 const @"addrspace": std.builtin.AddressSpace = as: {
1316 const addrspace_ctx: Sema.AddressSpaceContext = switch (zir_decl.kind) {
1317 .@"var" => .variable,
1318 else => switch (decl_ty.zigTypeTag(zcu)) {
1319 .@"fn" => .function,
1320 else => .constant,
1341 if (!air.typesFullyResolved(zcu)) {
1342 // A type we depend on failed to resolve. This is a transitive failure.
1343 // Correcting this failure will involve changing a type this function
1344 // depends on, hence triggering re-analysis of this function, so this
1345 // interacts correctly with incremental compilation.
1346 // TODO: do we need to mark this failure anywhere? I don't think so, since compilation
1347 // will fail due to the type error anyway.
1348 } else if (comp.bin_file) |lf| {
1349 lf.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) {
1350 error.OutOfMemory => return error.OutOfMemory,
1351 error.AnalysisFail => {
1352 assert(zcu.failed_codegen.contains(nav_index));
1353 },
1354 else => {
1355 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
1356 gpa,
1357 zcu.navSrcLoc(nav_index),
1358 "unable to codegen: {s}",
1359 .{@errorName(err)},
1360 ));
1361 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index }));
13211362 },
13221363 };
1323 const target = zcu.getTarget();
1324 const addrspace_body = zir_decl.addrspace_body orelse break :as switch (addrspace_ctx) {
1325 .function => target_util.defaultAddressSpace(target, .function),
1326 .variable => target_util.defaultAddressSpace(target, .global_mutable),
1327 .constant => target_util.defaultAddressSpace(target, .global_constant),
1328 else => unreachable,
1364 } else if (zcu.llvm_object) |llvm_object| {
1365 llvm_object.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) {
1366 error.OutOfMemory => return error.OutOfMemory,
13291367 };
1330 const addrspace_ref = try sema.resolveInlineBody(&block, addrspace_body, inst_info.inst);
1331 break :as try sema.analyzeAsAddressSpace(&block, addrspace_src, addrspace_ref, addrspace_ctx);
1332 };
1333
1334 // Lastly, we must evaluate the value if we have not already done so. Note, however, that extern declarations
1335 // don't have an associated value body.
1336
1337 const final_val: ?Value = early_val orelse if (zir_decl.value_body) |value_body| val: {
1338 // Put the resolved type into `inst_map` to be used as the result type of the init.
1339 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{inst_info.inst});
1340 sema.inst_map.putAssumeCapacity(inst_info.inst, Air.internedToRef(decl_ty.toIntern()));
1341 const uncoerced_result_ref = try sema.resolveInlineBody(&block, value_body, inst_info.inst);
1342 assert(sema.inst_map.remove(inst_info.inst));
1368 }
1369}
13431370
1344 const result_ref = try sema.coerce(&block, decl_ty, uncoerced_result_ref, init_src);
1345 break :val try sema.resolveFinalDeclValue(&block, init_src, result_ref);
1346 } else null;
1371/// https://github.com/ziglang/zig/issues/14307
1372pub fn semaPkg(pt: Zcu.PerThread, pkg: *Module) !void {
1373 dev.check(.sema);
1374 const import_file_result = try pt.importPkg(pkg);
1375 const root_type = pt.zcu.fileRootType(import_file_result.file_index);
1376 if (root_type == .none) {
1377 return pt.semaFile(import_file_result.file_index);
1378 }
1379}
13471380
1348 // TODO: missing validation?
1381fn createFileRootStruct(
1382 pt: Zcu.PerThread,
1383 file_index: Zcu.File.Index,
1384 namespace_index: Zcu.Namespace.Index,
1385 replace_existing: bool,
1386) Allocator.Error!InternPool.Index {
1387 const zcu = pt.zcu;
1388 const gpa = zcu.gpa;
1389 const ip = &zcu.intern_pool;
1390 const file = zcu.fileByIndex(file_index);
1391 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
1392 assert(extended.opcode == .struct_decl);
1393 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
1394 assert(!small.has_captures_len);
1395 assert(!small.has_backing_int);
1396 assert(small.layout == .auto);
1397 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1398 const fields_len = if (small.has_fields_len) blk: {
1399 const fields_len = file.zir.extra[extra_index];
1400 extra_index += 1;
1401 break :blk fields_len;
1402 } else 0;
1403 const decls_len = if (small.has_decls_len) blk: {
1404 const decls_len = file.zir.extra[extra_index];
1405 extra_index += 1;
1406 break :blk decls_len;
1407 } else 0;
1408 const decls = file.zir.bodySlice(extra_index, decls_len);
1409 extra_index += decls_len;
13491410
1350 const decl_val: Value = switch (zir_decl.linkage) {
1351 .normal, .@"export" => switch (zir_decl.kind) {
1352 .@"var" => .fromInterned(try pt.intern(.{ .variable = .{
1353 .ty = decl_ty.toIntern(),
1354 .init = final_val.?.toIntern(),
1355 .owner_nav = cau.owner.unwrap().nav,
1356 .is_threadlocal = zir_decl.is_threadlocal,
1357 .is_weak_linkage = false,
1358 } })),
1359 else => final_val.?,
1360 },
1361 .@"extern" => val: {
1362 assert(final_val == null); // extern decls do not have a value body
1363 const lib_name: ?[]const u8 = if (zir_decl.lib_name != .empty) l: {
1364 break :l zir.nullTerminatedString(zir_decl.lib_name);
1365 } else null;
1366 if (lib_name) |l| {
1367 const lib_name_src = block.src(.{ .node_offset_lib_name = 0 });
1368 try sema.handleExternLibName(&block, lib_name_src, l);
1369 }
1370 break :val .fromInterned(try pt.getExtern(.{
1371 .name = old_nav_info.name,
1372 .ty = decl_ty.toIntern(),
1373 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
1374 .is_const = zir_decl.kind == .@"const",
1375 .is_threadlocal = zir_decl.is_threadlocal,
1376 .is_weak_linkage = false,
1377 .is_dll_import = false,
1378 .alignment = alignment,
1379 .@"addrspace" = @"addrspace",
1380 .zir_index = cau.zir_index, // `declaration` instruction
1381 .owner_nav = undefined, // ignored by `getExtern`
1382 }));
1383 },
1411 const tracked_inst = try ip.trackZir(gpa, pt.tid, .{
1412 .file = file_index,
1413 .inst = .main_struct_inst,
1414 });
1415 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
1416 .layout = .auto,
1417 .fields_len = fields_len,
1418 .known_non_opv = small.known_non_opv,
1419 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
1420 .any_comptime_fields = small.any_comptime_fields,
1421 .any_default_inits = small.any_default_inits,
1422 .inits_resolved = false,
1423 .any_aligned_fields = small.any_aligned_fields,
1424 .key = .{ .declared = .{
1425 .zir_index = tracked_inst,
1426 .captures = &.{},
1427 } },
1428 }, replace_existing)) {
1429 .existing => unreachable, // we wouldn't be analysing the file root if this type existed
1430 .wip => |wip| wip,
13841431 };
1432 errdefer wip_ty.cancel(ip, pt.tid);
13851433
1386 const nav_index = switch (cau.owner.unwrap()) {
1387 .none => {
1388 // This is a `comptime` decl, so we are done -- the side effects are all we care about.
1389 // Just make sure to `flushExports`.
1390 try sema.flushExports();
1391 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1392 return .{
1393 .invalidate_decl_val = false,
1394 .invalidate_decl_ref = false,
1395 };
1396 },
1397 .nav => |nav| nav, // We will resolve this `Nav` below.
1398 .type => unreachable, // Handled at top of function.
1399 };
1434 wip_ty.setName(ip, try file.internFullyQualifiedName(pt));
1435 ip.namespacePtr(namespace_index).owner_type = wip_ty.index;
14001436
1401 switch (decl_val.toIntern()) {
1402 .generic_poison => unreachable, // assertion failure
1403 .unreachable_value => unreachable, // assertion failure
1404 else => {},
1437 if (zcu.comp.incremental) {
1438 try ip.addDependency(
1439 gpa,
1440 .wrap(.{ .type = wip_ty.index }),
1441 .{ .src_hash = tracked_inst },
1442 );
14051443 }
14061444
1407 // This resolves the type of the resolved value, not that value itself. If `decl_val` is a struct type,
1408 // this resolves the type `type` (which needs no resolution), not the struct itself.
1409 try decl_ty.resolveLayout(pt);
1410
1411 // TODO: this is jank. If #20663 is rejected, let's think about how to better model `usingnamespace`.
1412 if (is_usingnamespace) {
1413 if (decl_ty.toIntern() != .type_type) {
1414 return sema.fail(&block, ty_src, "expected type, found {}", .{decl_ty.fmt(pt)});
1415 }
1416 if (decl_val.toType().getNamespace(zcu) == .none) {
1417 return sema.fail(&block, ty_src, "type {} has no namespace", .{decl_val.toType().fmt(pt)});
1418 }
1419 ip.resolveNavValue(nav_index, .{
1420 .val = decl_val.toIntern(),
1421 .alignment = .none,
1422 .@"linksection" = .none,
1423 .@"addrspace" = .generic,
1424 });
1425 // TODO: usingnamespace cannot participate in incremental compilation
1426 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1427 return .{
1428 .invalidate_decl_val = true,
1429 .invalidate_decl_ref = true,
1430 };
1445 try pt.scanNamespace(namespace_index, decls);
1446 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
1447 codegen_type: {
1448 if (zcu.comp.config.use_llvm) break :codegen_type;
1449 if (file.mod.strip) break :codegen_type;
1450 // This job depends on any resolve_type_fully jobs queued up before it.
1451 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
14311452 }
1453 zcu.setFileRootType(file_index, wip_ty.index);
1454 return wip_ty.finish(ip, namespace_index);
1455}
14321456
1433 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(decl_val.toIntern())) {
1434 .func => |f| .{ true, f.owner_nav == nav_index }, // note that this lets function aliases reach codegen
1435 .variable => |v| .{ v.owner_nav == nav_index, false },
1436 .@"extern" => |e| .{ false, Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn" },
1437 else => .{ true, false },
1438 };
1439
1440 // Keep in sync with logic in `Sema.zirVarExtended`.
1457/// Re-scan the namespace of a file's root struct type on an incremental update.
1458/// The file must have successfully populated ZIR.
1459/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.
1460/// This is called by `updateZirRefs` for all updated files before the main work loop.
1461/// This function does not perform any semantic analysis.
1462fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void {
1463 const zcu = pt.zcu;
14411464
1442 if (is_owned_fn) {
1443 // linksection etc are legal, except some targets do not support function alignment.
1444 if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
1445 return sema.fail(&block, align_src, "target does not support function alignment", .{});
1446 }
1447 } else if (try decl_ty.comptimeOnlySema(pt)) {
1448 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.
1449 const reason: []const u8 = switch (ip.indexToKey(decl_val.toIntern())) {
1450 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
1451 else => "comptime-only type",
1452 };
1453 if (zir_decl.align_body != null) {
1454 return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{reason});
1455 }
1456 if (zir_decl.linksection_body != null) {
1457 return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{reason});
1458 }
1459 if (zir_decl.addrspace_body != null) {
1460 return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{reason});
1461 }
1462 }
1465 const file = zcu.fileByIndex(file_index);
1466 assert(file.status == .success_zir);
1467 const file_root_type = zcu.fileRootType(file_index);
1468 if (file_root_type == .none) return;
14631469
1464 ip.resolveNavValue(nav_index, .{
1465 .val = decl_val.toIntern(),
1466 .alignment = alignment,
1467 .@"linksection" = @"linksection",
1468 .@"addrspace" = @"addrspace",
1470 log.debug("updateFileNamespace mod={s} sub_file_path={s}", .{
1471 file.mod.fully_qualified_name,
1472 file.sub_file_path,
14691473 });
14701474
1471 // Mark the `Cau` as completed before evaluating the export!
1472 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1473
1474 if (zir_decl.linkage == .@"export") {
1475 const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.is_pub) });
1476 const name_slice = zir.nullTerminatedString(zir_decl.name);
1477 const name_ip = try ip.getOrPutString(gpa, pt.tid, name_slice, .no_embedded_nulls);
1478 try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_index);
1479 }
1475 const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);
1476 const decls = decls: {
1477 const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
1478 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
14801479
1481 try sema.flushExports();
1480 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1481 extra_index += @intFromBool(small.has_fields_len);
1482 const decls_len = if (small.has_decls_len) blk: {
1483 const decls_len = file.zir.extra[extra_index];
1484 extra_index += 1;
1485 break :blk decls_len;
1486 } else 0;
1487 break :decls file.zir.bodySlice(extra_index, decls_len);
1488 };
1489 try pt.scanNamespace(namespace_index, decls);
1490 zcu.namespacePtr(namespace_index).generation = zcu.generation;
1491}
14821492
1483 queue_codegen: {
1484 if (!queue_linker_work) break :queue_codegen;
1493fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1494 const tracy = trace(@src());
1495 defer tracy.end();
14851496
1486 if (!try decl_ty.hasRuntimeBitsSema(pt)) {
1487 if (zcu.comp.config.use_llvm) break :queue_codegen;
1488 if (file.mod.strip) break :queue_codegen;
1489 }
1497 const zcu = pt.zcu;
1498 const gpa = zcu.gpa;
1499 const file = zcu.fileByIndex(file_index);
1500 assert(zcu.fileRootType(file_index) == .none);
14901501
1491 // This job depends on any resolve_type_fully jobs queued up before it.
1492 try zcu.comp.queueJob(.{ .codegen_nav = nav_index });
1502 if (file.status != .success_zir) {
1503 return error.AnalysisFail;
14931504 }
1505 assert(file.zir_loaded);
14941506
1495 switch (old_nav_info.status) {
1496 .unresolved => return .{
1497 .invalidate_decl_val = true,
1498 .invalidate_decl_ref = true,
1499 },
1500 .resolved => |old| {
1501 const new = ip.getNav(nav_index).status.resolved;
1502 return .{
1503 .invalidate_decl_val = new.val != old.val,
1504 .invalidate_decl_ref = ip.typeOf(new.val) != ip.typeOf(old.val) or
1505 new.alignment != old.alignment or
1506 new.@"linksection" != old.@"linksection" or
1507 new.@"addrspace" != old.@"addrspace",
1507 const new_namespace_index = try pt.createNamespace(.{
1508 .parent = .none,
1509 .owner_type = undefined, // set in `createFileRootStruct`
1510 .file_scope = file_index,
1511 .generation = zcu.generation,
1512 });
1513 const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);
1514 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
1515
1516 switch (zcu.comp.cache_use) {
1517 .whole => |whole| if (whole.cache_manifest) |man| {
1518 const source = file.getSource(gpa) catch |err| {
1519 try pt.reportRetryableFileError(file_index, "unable to load source: {s}", .{@errorName(err)});
1520 return error.AnalysisFail;
1521 };
1522
1523 const resolved_path = std.fs.path.resolve(gpa, &.{
1524 file.mod.root.root_dir.path orelse ".",
1525 file.mod.root.sub_path,
1526 file.sub_file_path,
1527 }) catch |err| {
1528 try pt.reportRetryableFileError(file_index, "unable to resolve path: {s}", .{@errorName(err)});
1529 return error.AnalysisFail;
1530 };
1531 errdefer gpa.free(resolved_path);
1532
1533 whole.cache_manifest_mutex.lock();
1534 defer whole.cache_manifest_mutex.unlock();
1535 man.addFilePostContents(resolved_path, source.bytes, source.stat) catch |err| switch (err) {
1536 error.OutOfMemory => |e| return e,
1537 else => {
1538 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
1539 return error.AnalysisFail;
1540 },
15081541 };
15091542 },
1543 .incremental => {},
15101544 }
15111545}
15121546
......@@ -1880,45 +1914,42 @@ pub fn scanNamespace(
18801914
18811915 // For incremental updates, `scanDecl` wants to look up existing decls by their ZIR index rather
18821916 // than their name. We'll build an efficient mapping now, then discard the current `decls`.
1883 // We map to the `Cau`, since not every declaration has a `Nav`.
1884 var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.Cau.Index) = .empty;
1917 // We map to the `AnalUnit`, since not every declaration has a `Nav`.
1918 var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.AnalUnit) = .empty;
18851919 defer existing_by_inst.deinit(gpa);
18861920
18871921 try existing_by_inst.ensureTotalCapacity(gpa, @intCast(
18881922 namespace.pub_decls.count() + namespace.priv_decls.count() +
18891923 namespace.pub_usingnamespace.items.len + namespace.priv_usingnamespace.items.len +
1890 namespace.other_decls.items.len,
1924 namespace.comptime_decls.items.len +
1925 namespace.test_decls.items.len,
18911926 ));
18921927
18931928 for (namespace.pub_decls.keys()) |nav| {
1894 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1895 const zir_index = ip.getCau(cau_index).zir_index;
1896 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
1929 const zir_index = ip.getNav(nav).analysis.?.zir_index;
1930 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
18971931 }
18981932 for (namespace.priv_decls.keys()) |nav| {
1899 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1900 const zir_index = ip.getCau(cau_index).zir_index;
1901 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
1933 const zir_index = ip.getNav(nav).analysis.?.zir_index;
1934 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
19021935 }
19031936 for (namespace.pub_usingnamespace.items) |nav| {
1904 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1905 const zir_index = ip.getCau(cau_index).zir_index;
1906 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
1937 const zir_index = ip.getNav(nav).analysis.?.zir_index;
1938 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
19071939 }
19081940 for (namespace.priv_usingnamespace.items) |nav| {
1909 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1910 const zir_index = ip.getCau(cau_index).zir_index;
1911 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
1912 }
1913 for (namespace.other_decls.items) |cau_index| {
1914 const cau = ip.getCau(cau_index);
1915 existing_by_inst.putAssumeCapacityNoClobber(cau.zir_index, cau_index);
1916 // If this is a test, it'll be re-added to `test_functions` later on
1917 // if still alive. Remove it for now.
1918 switch (cau.owner.unwrap()) {
1919 .none, .type => {},
1920 .nav => |nav| _ = zcu.test_functions.swapRemove(nav),
1921 }
1941 const zir_index = ip.getNav(nav).analysis.?.zir_index;
1942 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
1943 }
1944 for (namespace.comptime_decls.items) |cu| {
1945 const zir_index = ip.getComptimeUnit(cu).zir_index;
1946 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .@"comptime" = cu }));
1947 }
1948 for (namespace.test_decls.items) |nav| {
1949 const zir_index = ip.getNav(nav).analysis.?.zir_index;
1950 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
1951 // This test will be re-added to `test_functions` later on if it's still alive. Remove it for now.
1952 _ = zcu.test_functions.swapRemove(nav);
19221953 }
19231954
19241955 var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
......@@ -1928,7 +1959,8 @@ pub fn scanNamespace(
19281959 namespace.priv_decls.clearRetainingCapacity();
19291960 namespace.pub_usingnamespace.clearRetainingCapacity();
19301961 namespace.priv_usingnamespace.clearRetainingCapacity();
1931 namespace.other_decls.clearRetainingCapacity();
1962 namespace.comptime_decls.clearRetainingCapacity();
1963 namespace.test_decls.clearRetainingCapacity();
19321964
19331965 var scan_decl_iter: ScanDeclIter = .{
19341966 .pt = pt,
......@@ -1950,7 +1982,7 @@ const ScanDeclIter = struct {
19501982 pt: Zcu.PerThread,
19511983 namespace_index: Zcu.Namespace.Index,
19521984 seen_decls: *std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
1953 existing_by_inst: *const std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.Cau.Index),
1985 existing_by_inst: *const std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.AnalUnit),
19541986 /// Decl scanning is run in two passes, so that we can detect when a generated
19551987 /// name would clash with an explicit name and use a different one.
19561988 pass: enum { named, unnamed },
......@@ -1988,48 +2020,30 @@ const ScanDeclIter = struct {
19882020
19892021 const decl = zir.getDeclaration(decl_inst);
19902022
1991 const Kind = enum { @"comptime", @"usingnamespace", @"test", named };
1992
1993 const maybe_name: InternPool.OptionalNullTerminatedString, const kind: Kind, const is_named_test: bool = switch (decl.kind) {
1994 .@"comptime" => info: {
2023 const maybe_name: InternPool.OptionalNullTerminatedString = switch (decl.kind) {
2024 .@"comptime" => name: {
19952025 if (iter.pass != .unnamed) return;
1996 break :info .{
1997 .none,
1998 .@"comptime",
1999 false,
2000 };
2026 break :name .none;
20012027 },
2002 .@"usingnamespace" => info: {
2028 .@"usingnamespace" => name: {
20032029 if (iter.pass != .unnamed) return;
20042030 const i = iter.usingnamespace_index;
20052031 iter.usingnamespace_index += 1;
2006 break :info .{
2007 (try iter.avoidNameConflict("usingnamespace_{d}", .{i})).toOptional(),
2008 .@"usingnamespace",
2009 false,
2010 };
2032 break :name (try iter.avoidNameConflict("usingnamespace_{d}", .{i})).toOptional();
20112033 },
2012 .unnamed_test => info: {
2034 .unnamed_test => name: {
20132035 if (iter.pass != .unnamed) return;
20142036 const i = iter.unnamed_test_index;
20152037 iter.unnamed_test_index += 1;
2016 break :info .{
2017 (try iter.avoidNameConflict("test_{d}", .{i})).toOptional(),
2018 .@"test",
2019 false,
2020 };
2038 break :name (try iter.avoidNameConflict("test_{d}", .{i})).toOptional();
20212039 },
2022 .@"test", .decltest => |kind| info: {
2040 .@"test", .decltest => |kind| name: {
20232041 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
20242042 if (iter.pass != .unnamed) return;
20252043 const prefix = @tagName(kind);
2026 break :info .{
2027 (try iter.avoidNameConflict("{s}.{s}", .{ prefix, zir.nullTerminatedString(decl.name) })).toOptional(),
2028 .@"test",
2029 true,
2030 };
2044 break :name (try iter.avoidNameConflict("{s}.{s}", .{ prefix, zir.nullTerminatedString(decl.name) })).toOptional();
20312045 },
2032 .@"const", .@"var" => info: {
2046 .@"const", .@"var" => name: {
20332047 if (iter.pass != .named) return;
20342048 const name = try ip.getOrPutString(
20352049 gpa,
......@@ -2038,11 +2052,7 @@ const ScanDeclIter = struct {
20382052 .no_embedded_nulls,
20392053 );
20402054 try iter.seen_decls.putNoClobber(gpa, name, {});
2041 break :info .{
2042 name.toOptional(),
2043 .named,
2044 false,
2045 };
2055 break :name name.toOptional();
20462056 },
20472057 };
20482058
......@@ -2051,46 +2061,44 @@ const ScanDeclIter = struct {
20512061 .inst = decl_inst,
20522062 });
20532063
2054 const existing_cau = iter.existing_by_inst.get(tracked_inst);
2064 const existing_unit = iter.existing_by_inst.get(tracked_inst);
20552065
2056 const cau, const want_analysis = switch (kind) {
2057 .@"comptime" => cau: {
2058 const cau = existing_cau orelse try ip.createComptimeCau(gpa, pt.tid, tracked_inst, namespace_index);
2066 const unit, const want_analysis = switch (decl.kind) {
2067 .@"comptime" => unit: {
2068 const cu = if (existing_unit) |eu|
2069 eu.unwrap().@"comptime"
2070 else
2071 try ip.createComptimeUnit(gpa, pt.tid, tracked_inst, namespace_index);
20592072
2060 try namespace.other_decls.append(gpa, cau);
2073 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
20612074
2062 if (existing_cau == null) {
2063 // For a `comptime` declaration, whether to analyze is based solely on whether the
2064 // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already.
2065 const unit = AnalUnit.wrap(.{ .cau = cau });
2066 if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| {
2067 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2068 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2069 zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value);
2070 if (kv.value == 0) { // no PO deps
2071 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
2072 }
2073 } else if (!zcu.outdated.contains(unit)) {
2074 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2075 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2076 zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
2077 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
2078 }
2075 try namespace.comptime_decls.append(gpa, cu);
2076
2077 if (existing_unit == null) {
2078 // For a `comptime` declaration, whether to analyze is based solely on whether the unit
2079 // is outdated. So, add this fresh one to `outdated` and `outdated_ready`.
2080 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2081 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2082 zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
2083 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
20792084 }
20802085
2081 break :cau .{ cau, true };
2086 break :unit .{ unit, true };
20822087 },
2083 else => cau: {
2088 else => unit: {
20842089 const name = maybe_name.unwrap().?;
20852090 const fqn = try namespace.internFullyQualifiedName(ip, gpa, pt.tid, name);
2086 const cau, const nav = if (existing_cau) |cau_index| cau_nav: {
2087 const nav_index = ip.getCau(cau_index).owner.unwrap().nav;
2088 const nav = ip.getNav(nav_index);
2089 assert(nav.name == name);
2090 assert(nav.fqn == fqn);
2091 break :cau_nav .{ cau_index, nav_index };
2092 } else try ip.createPairedCauNav(gpa, pt.tid, name, fqn, tracked_inst, namespace_index, kind == .@"usingnamespace");
2093 const want_analysis = switch (kind) {
2091 const nav = if (existing_unit) |eu|
2092 eu.unwrap().nav_val
2093 else
2094 try ip.createDeclNav(gpa, pt.tid, name, fqn, tracked_inst, namespace_index, decl.kind == .@"usingnamespace");
2095
2096 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
2097
2098 assert(ip.getNav(nav).name == name);
2099 assert(ip.getNav(nav).fqn == fqn);
2100
2101 const want_analysis = switch (decl.kind) {
20942102 .@"comptime" => unreachable,
20952103 .@"usingnamespace" => a: {
20962104 if (comp.incremental) {
......@@ -2103,8 +2111,9 @@ const ScanDeclIter = struct {
21032111 }
21042112 break :a true;
21052113 },
2106 .@"test" => a: {
2107 try namespace.other_decls.append(gpa, cau);
2114 .unnamed_test, .@"test", .decltest => a: {
2115 const is_named = decl.kind != .unnamed_test;
2116 try namespace.test_decls.append(gpa, nav);
21082117 // TODO: incremental compilation!
21092118 // * remove from `test_functions` if no longer matching filter
21102119 // * add to `test_functions` if newly passing filter
......@@ -2112,7 +2121,7 @@ const ScanDeclIter = struct {
21122121 // Perhaps we should add all test indiscriminately and filter at the end of the update.
21132122 if (!comp.config.is_test) break :a false;
21142123 if (file.mod != zcu.main_mod) break :a false;
2115 if (is_named_test and comp.test_filters.len > 0) {
2124 if (is_named and comp.test_filters.len > 0) {
21162125 const fqn_slice = fqn.toSlice(ip);
21172126 for (comp.test_filters) |test_filter| {
21182127 if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
......@@ -2121,7 +2130,7 @@ const ScanDeclIter = struct {
21212130 try zcu.test_functions.put(gpa, nav, {});
21222131 break :a true;
21232132 },
2124 .named => a: {
2133 .@"const", .@"var" => a: {
21252134 if (decl.is_pub) {
21262135 try namespace.pub_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
21272136 } else {
......@@ -2130,23 +2139,23 @@ const ScanDeclIter = struct {
21302139 break :a false;
21312140 },
21322141 };
2133 break :cau .{ cau, want_analysis };
2142 break :unit .{ unit, want_analysis };
21342143 },
21352144 };
21362145
2137 if (existing_cau == null and (want_analysis or decl.linkage == .@"export")) {
2146 if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) {
21382147 log.debug(
2139 "scanDecl queue analyze_cau file='{s}' cau_index={d}",
2140 .{ namespace.fileScope(zcu).sub_file_path, cau },
2148 "scanDecl queue analyze_comptime_unit file='{s}' unit={}",
2149 .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) },
21412150 );
2142 try comp.queueJob(.{ .analyze_cau = cau });
2151 try comp.queueJob(.{ .analyze_comptime_unit = unit });
21432152 }
21442153
21452154 // TODO: we used to do line number updates here, but this is an inappropriate place for this logic to live.
21462155 }
21472156};
21482157
2149fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {
2158fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {
21502159 const tracy = trace(@src());
21512160 defer tracy.end();
21522161
......@@ -2168,21 +2177,14 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
21682177 func.setResolvedErrorSet(ip, .none);
21692178 }
21702179
2171 // This is the `Cau` corresponding to the `declaration` instruction which the function or its generic owner originates from.
2172 const decl_cau = ip.getCau(cau: {
2173 const orig_nav = if (func.generic_owner == .none)
2174 func.owner_nav
2175 else
2176 zcu.funcInfo(func.generic_owner).owner_nav;
2177
2178 break :cau ip.getNav(orig_nav).analysis_owner.unwrap().?;
2179 });
2180 // This is the `Nau` corresponding to the `declaration` instruction which the function or its generic owner originates from.
2181 const decl_nav = ip.getNav(if (func.generic_owner == .none)
2182 func.owner_nav
2183 else
2184 zcu.funcInfo(func.generic_owner).owner_nav);
21802185
21812186 const func_nav = ip.getNav(func.owner_nav);
21822187
2183 const decl_prog_node = zcu.sema_prog_node.start(func_nav.fqn.toSlice(ip), 0);
2184 defer decl_prog_node.end();
2185
21862188 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
21872189
21882190 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
......@@ -2216,7 +2218,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
22162218
22172219 // Every runtime function has a dependency on the source of the Decl it originates from.
22182220 // It also depends on the value of its owner Decl.
2219 try sema.declareDependency(.{ .src_hash = decl_cau.zir_index });
2221 try sema.declareDependency(.{ .src_hash = decl_nav.analysis.?.zir_index });
22202222 try sema.declareDependency(.{ .nav_val = func.owner_nav });
22212223
22222224 if (func.analysisUnordered(ip).inferred_error_set) {
......@@ -2236,11 +2238,11 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
22362238 var inner_block: Sema.Block = .{
22372239 .parent = null,
22382240 .sema = &sema,
2239 .namespace = decl_cau.namespace,
2241 .namespace = decl_nav.analysis.?.namespace,
22402242 .instructions = .{},
22412243 .inlining = null,
22422244 .is_comptime = false,
2243 .src_base_inst = decl_cau.zir_index,
2245 .src_base_inst = decl_nav.analysis.?.zir_index,
22442246 .type_name_ctx = func_nav.fqn,
22452247 };
22462248 defer inner_block.instructions.deinit(gpa);
......@@ -2542,10 +2544,10 @@ fn processExportsInner(
25422544 .nav => |nav_index| if (failed: {
25432545 const nav = ip.getNav(nav_index);
25442546 if (zcu.failed_codegen.contains(nav_index)) break :failed true;
2545 if (nav.analysis_owner.unwrap()) |cau| {
2546 const cau_unit = AnalUnit.wrap(.{ .cau = cau });
2547 if (zcu.failed_analysis.contains(cau_unit)) break :failed true;
2548 if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true;
2547 if (nav.analysis != null) {
2548 const unit: AnalUnit = .wrap(.{ .nav_val = nav_index });
2549 if (zcu.failed_analysis.contains(unit)) break :failed true;
2550 if (zcu.transitive_failed_analysis.contains(unit)) break :failed true;
25492551 }
25502552 const val = switch (nav.status) {
25512553 .unresolved => break :failed true,
......@@ -2593,15 +2595,14 @@ pub fn populateTestFunctions(
25932595 Zcu.Namespace.NameAdapter{ .zcu = zcu },
25942596 ).?;
25952597 {
2596 // We have to call `ensureCauAnalyzed` here in case `builtin.test_functions`
2598 // We have to call `ensureNavValUpToDate` here in case `builtin.test_functions`
25972599 // was not referenced by start code.
25982600 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
25992601 defer {
26002602 zcu.sema_prog_node.end();
26012603 zcu.sema_prog_node = std.Progress.Node.none;
26022604 }
2603 const cau_index = ip.getNav(nav_index).analysis_owner.unwrap().?;
2604 pt.ensureCauAnalyzed(cau_index) catch |err| switch (err) {
2605 pt.ensureNavValUpToDate(nav_index) catch |err| switch (err) {
26052606 error.AnalysisFail => return,
26062607 error.OutOfMemory => return error.OutOfMemory,
26072608 };
......@@ -2622,8 +2623,7 @@ pub fn populateTestFunctions(
26222623 {
26232624 // The test declaration might have failed; if that's the case, just return, as we'll
26242625 // be emitting a compile error anyway.
2625 const cau = test_nav.analysis_owner.unwrap().?;
2626 const anal_unit: AnalUnit = .wrap(.{ .cau = cau });
2626 const anal_unit: AnalUnit = .wrap(.{ .nav_val = test_nav_index });
26272627 if (zcu.failed_analysis.contains(anal_unit) or
26282628 zcu.transitive_failed_analysis.contains(anal_unit))
26292629 {
......@@ -2748,8 +2748,8 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error
27482748 "unable to codegen: {s}",
27492749 .{@errorName(err)},
27502750 ));
2751 if (nav.analysis_owner.unwrap()) |cau| {
2752 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .cau = cau }));
2751 if (nav.analysis != null) {
2752 try zcu.retryable_failures.append(zcu.gpa, .wrap(.{ .nav_val = nav_index }));
27532753 } else {
27542754 // TODO: we don't have a way to indicate that this failure is retryable!
27552755 // Since these are really rare, we could as a cop-out retry the whole build next update.
......@@ -3255,7 +3255,7 @@ pub fn getBuiltinNav(pt: Zcu.PerThread, name: []const u8) Allocator.Error!Intern
32553255 const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls);
32563256 const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse
32573257 @panic("lib/std.zig is corrupt and missing 'builtin'");
3258 pt.ensureCauAnalyzed(ip.getNav(builtin_nav).analysis_owner.unwrap().?) catch @panic("std.builtin is corrupt");
3258 pt.ensureNavValUpToDate(builtin_nav) catch @panic("std.builtin is corrupt");
32593259 const builtin_type = Type.fromInterned(ip.getNav(builtin_nav).status.resolved.val);
32603260 const builtin_namespace = zcu.namespacePtr(builtin_type.getNamespace(zcu).unwrap() orelse @panic("std.builtin is corrupt"));
32613261 const name_str = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
......@@ -3307,68 +3307,45 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo
33073307/// Given a container type requiring resolution, ensures that it is up-to-date.
33083308/// If not, the type is recreated at a new `InternPool.Index`.
33093309/// The new index is returned. This is the same as the old index if the fields were up-to-date.
3310/// If `already_updating` is set, assumes the type is already outdated and undergoing re-analysis rather than checking `zcu.outdated`.
3311pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updating: bool) Zcu.SemaError!InternPool.Index {
3310pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index {
33123311 const zcu = pt.zcu;
3312 const gpa = zcu.gpa;
33133313 const ip = &zcu.intern_pool;
3314
3315 const anal_unit: AnalUnit = .wrap(.{ .type = ty });
3316 const outdated = zcu.outdated.swapRemove(anal_unit) or
3317 zcu.potentially_outdated.swapRemove(anal_unit);
3318
3319 if (!outdated) return ty;
3320
3321 // We will recreate the type at a new `InternPool.Index`.
3322
3323 _ = zcu.outdated_ready.swapRemove(anal_unit);
3324 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3325
3326 // Delete old state which is no longer in use. Technically, this is not necessary: these exports,
3327 // references, etc, will be ignored because the type itself is unreferenced. However, it allows
3328 // reusing the memory which is currently being used to track this state.
3329 zcu.deleteUnitExports(anal_unit);
3330 zcu.deleteUnitReferences(anal_unit);
3331 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
3332 kv.value.destroy(gpa);
3333 }
3334 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
3335 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
3336
33143337 switch (ip.indexToKey(ty)) {
3315 .struct_type => |key| {
3316 const struct_obj = ip.loadStructType(ty);
3317 const outdated = already_updating or o: {
3318 const anal_unit = AnalUnit.wrap(.{ .cau = struct_obj.cau });
3319 const o = zcu.outdated.swapRemove(anal_unit) or
3320 zcu.potentially_outdated.swapRemove(anal_unit);
3321 if (o) {
3322 _ = zcu.outdated_ready.swapRemove(anal_unit);
3323 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3324 }
3325 break :o o;
3326 };
3327 if (!outdated) return ty;
3328 return pt.recreateStructType(key, struct_obj);
3329 },
3330 .union_type => |key| {
3331 const union_obj = ip.loadUnionType(ty);
3332 const outdated = already_updating or o: {
3333 const anal_unit = AnalUnit.wrap(.{ .cau = union_obj.cau });
3334 const o = zcu.outdated.swapRemove(anal_unit) or
3335 zcu.potentially_outdated.swapRemove(anal_unit);
3336 if (o) {
3337 _ = zcu.outdated_ready.swapRemove(anal_unit);
3338 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3339 }
3340 break :o o;
3341 };
3342 if (!outdated) return ty;
3343 return pt.recreateUnionType(key, union_obj);
3344 },
3345 .enum_type => |key| {
3346 const enum_obj = ip.loadEnumType(ty);
3347 const outdated = already_updating or o: {
3348 const anal_unit = AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? });
3349 const o = zcu.outdated.swapRemove(anal_unit) or
3350 zcu.potentially_outdated.swapRemove(anal_unit);
3351 if (o) {
3352 _ = zcu.outdated_ready.swapRemove(anal_unit);
3353 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3354 }
3355 break :o o;
3356 };
3357 if (!outdated) return ty;
3358 return pt.recreateEnumType(key, enum_obj);
3359 },
3360 .opaque_type => {
3361 assert(!already_updating);
3362 return ty;
3363 },
3338 .struct_type => |key| return pt.recreateStructType(ty, key),
3339 .union_type => |key| return pt.recreateUnionType(ty, key),
3340 .enum_type => |key| return pt.recreateEnumType(ty, key),
33643341 else => unreachable,
33653342 }
33663343}
33673344
33683345fn recreateStructType(
33693346 pt: Zcu.PerThread,
3347 old_ty: InternPool.Index,
33703348 full_key: InternPool.Key.NamespaceType,
3371 struct_obj: InternPool.LoadedStructType,
33723349) Zcu.SemaError!InternPool.Index {
33733350 const zcu = pt.zcu;
33743351 const gpa = zcu.gpa;
......@@ -3405,8 +3382,7 @@ fn recreateStructType(
34053382
34063383 if (captures_len != key.captures.owned.len) return error.AnalysisFail;
34073384
3408 // The old type will be unused, so drop its dependency information.
3409 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = struct_obj.cau }));
3385 const struct_obj = ip.loadStructType(old_ty);
34103386
34113387 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
34123388 .layout = small.layout,
......@@ -3428,17 +3404,16 @@ fn recreateStructType(
34283404 errdefer wip_ty.cancel(ip, pt.tid);
34293405
34303406 wip_ty.setName(ip, struct_obj.name);
3431 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, struct_obj.namespace, wip_ty.index);
34323407 try ip.addDependency(
34333408 gpa,
3434 AnalUnit.wrap(.{ .cau = new_cau_index }),
3409 .wrap(.{ .type = wip_ty.index }),
34353410 .{ .src_hash = key.zir_index },
34363411 );
34373412 zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index;
34383413 // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive.
34393414 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
34403415
3441 const new_ty = wip_ty.finish(ip, new_cau_index.toOptional(), struct_obj.namespace);
3416 const new_ty = wip_ty.finish(ip, struct_obj.namespace);
34423417 if (inst_info.inst == .main_struct_inst) {
34433418 // This is the root type of a file! Update the reference.
34443419 zcu.setFileRootType(inst_info.file, new_ty);
......@@ -3448,8 +3423,8 @@ fn recreateStructType(
34483423
34493424fn recreateUnionType(
34503425 pt: Zcu.PerThread,
3426 old_ty: InternPool.Index,
34513427 full_key: InternPool.Key.NamespaceType,
3452 union_obj: InternPool.LoadedUnionType,
34533428) Zcu.SemaError!InternPool.Index {
34543429 const zcu = pt.zcu;
34553430 const gpa = zcu.gpa;
......@@ -3488,8 +3463,7 @@ fn recreateUnionType(
34883463
34893464 if (captures_len != key.captures.owned.len) return error.AnalysisFail;
34903465
3491 // The old type will be unused, so drop its dependency information.
3492 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = union_obj.cau }));
3466 const union_obj = ip.loadUnionType(old_ty);
34933467
34943468 const namespace_index = union_obj.namespace;
34953469
......@@ -3526,22 +3500,21 @@ fn recreateUnionType(
35263500 errdefer wip_ty.cancel(ip, pt.tid);
35273501
35283502 wip_ty.setName(ip, union_obj.name);
3529 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index);
35303503 try ip.addDependency(
35313504 gpa,
3532 AnalUnit.wrap(.{ .cau = new_cau_index }),
3505 .wrap(.{ .type = wip_ty.index }),
35333506 .{ .src_hash = key.zir_index },
35343507 );
35353508 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
35363509 // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive.
35373510 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
3538 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
3511 return wip_ty.finish(ip, namespace_index);
35393512}
35403513
35413514fn recreateEnumType(
35423515 pt: Zcu.PerThread,
3516 old_ty: InternPool.Index,
35433517 full_key: InternPool.Key.NamespaceType,
3544 enum_obj: InternPool.LoadedEnumType,
35453518) Zcu.SemaError!InternPool.Index {
35463519 const zcu = pt.zcu;
35473520 const gpa = zcu.gpa;
......@@ -3610,8 +3583,7 @@ fn recreateEnumType(
36103583 if (bag != 0) break true;
36113584 } else false;
36123585
3613 // The old type will be unused, so drop its dependency information.
3614 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? }));
3586 const enum_obj = ip.loadEnumType(old_ty);
36153587
36163588 const namespace_index = enum_obj.namespace;
36173589
......@@ -3637,12 +3609,10 @@ fn recreateEnumType(
36373609
36383610 wip_ty.setName(ip, enum_obj.name);
36393611
3640 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index);
3641
36423612 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
36433613 // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive.
36443614
3645 wip_ty.prepare(ip, new_cau_index, namespace_index);
3615 wip_ty.prepare(ip, namespace_index);
36463616 done = true;
36473617
36483618 Sema.resolveDeclaredEnum(
......@@ -3652,7 +3622,6 @@ fn recreateEnumType(
36523622 key.zir_index,
36533623 namespace_index,
36543624 enum_obj.name,
3655 new_cau_index,
36563625 small,
36573626 body,
36583627 tag_type_ref,
src/link/Dwarf.zig+8-8
......@@ -2261,8 +2261,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
22612261 assert(file.zir_loaded);
22622262 const decl = file.zir.getDeclaration(inst_info.inst);
22632263
2264 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2265 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2264 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2265 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
22662266 break :parent .{
22672267 parent_namespace_ptr.owner_type,
22682268 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
......@@ -2292,8 +2292,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
22922292 assert(file.zir_loaded);
22932293 const decl = file.zir.getDeclaration(inst_info.inst);
22942294
2295 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2296 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2295 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2296 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
22972297 break :parent .{
22982298 parent_namespace_ptr.owner_type,
22992299 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
......@@ -2321,8 +2321,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
23212321 assert(file.zir_loaded);
23222322 const decl = file.zir.getDeclaration(inst_info.inst);
23232323
2324 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2325 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2324 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2325 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
23262326 break :parent .{
23272327 parent_namespace_ptr.owner_type,
23282328 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
......@@ -2563,8 +2563,8 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
25632563 return;
25642564 }
25652565
2566 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2567 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2566 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2567 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
25682568 break :parent .{
25692569 parent_namespace_ptr.owner_type,
25702570 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,