| author | |
| committer | |
| log | 40aafcd6a85d3c517f445f17149c17523c832420 |
| tree | b8e1a5361c6a20ce9e3ba568b61b199aff1c8f13 |
| parent | 18362ebe13ece2ea7c4f57303ec4687f55d2dba5 |
| signature | Commit is signed but in an unrecognized format. |
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) { |
| 348 | 348 | /// Corresponds to the task in `link.Task`. |
| 349 | 349 | /// Only needed for backends that haven't yet been updated to not race against Sema. |
| 350 | 350 | 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. | |
| 352 | 356 | /// 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. | |
| 355 | 357 | /// After analysis, a `codegen_func` job will be queued. |
| 356 | 358 | /// 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. | |
| 357 | 360 | analyze_func: InternPool.Index, |
| 358 | 361 | /// The main source file for the module needs to be analyzed. |
| 359 | 362 | analyze_mod: *Package.Module, |
| ... | ... | @@ -3141,8 +3144,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3141 | 3144 | } |
| 3142 | 3145 | |
| 3143 | 3146 | 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), | |
| 3146 | 3151 | }; |
| 3147 | 3152 | |
| 3148 | 3153 | // Skip errors for AnalUnits within files that had a parse failure. |
| ... | ... | @@ -3374,11 +3379,9 @@ pub fn addModuleErrorMsg( |
| 3374 | 3379 | const rt_file_path = try src.file_scope.fullPath(gpa); |
| 3375 | 3380 | defer gpa.free(rt_file_path); |
| 3376 | 3381 | 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), | |
| 3382 | 3385 | .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), |
| 3383 | 3386 | }; |
| 3384 | 3387 | try ref_traces.append(gpa, .{ |
| ... | ... | @@ -3641,10 +3644,13 @@ fn performAllTheWorkInner( |
| 3641 | 3644 | // If there's no work queued, check if there's anything outdated |
| 3642 | 3645 | // which we need to work on, and queue it if so. |
| 3643 | 3646 | 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 | }); | |
| 3648 | 3654 | continue; |
| 3649 | 3655 | } |
| 3650 | 3656 | } |
| ... | ... | @@ -3667,8 +3673,8 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre |
| 3667 | 3673 | .codegen_nav => |nav_index| { |
| 3668 | 3674 | const zcu = comp.zcu.?; |
| 3669 | 3675 | 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 }); | |
| 3672 | 3678 | if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) { |
| 3673 | 3679 | return; |
| 3674 | 3680 | } |
| ... | ... | @@ -3688,36 +3694,47 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre |
| 3688 | 3694 | |
| 3689 | 3695 | const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); |
| 3690 | 3696 | 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, | |
| 3693 | 3700 | error.AnalysisFail => return, |
| 3694 | 3701 | }; |
| 3695 | 3702 | }, |
| 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 | ||
| 3697 | 3707 | const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); |
| 3698 | 3708 | 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, | |
| 3701 | 3718 | error.AnalysisFail => return, |
| 3702 | 3719 | }; |
| 3720 | ||
| 3703 | 3721 | queue_test_analysis: { |
| 3704 | 3722 | 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 | }; | |
| 3705 | 3727 | |
| 3706 | 3728 | // Check if this is a test function. |
| 3707 | 3729 | 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)) { | |
| 3714 | 3731 | break :queue_test_analysis; |
| 3715 | 3732 | } |
| 3716 | 3733 | |
| 3717 | 3734 | // Tests are always emitted in test binaries. The decl_refs are created by |
| 3718 | 3735 | // Zcu.populateTestFunctions, but this will not queue body analysis, so do |
| 3719 | 3736 | // 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); | |
| 3721 | 3738 | } |
| 3722 | 3739 | }, |
| 3723 | 3740 | .resolve_type_fully => |ty| { |
src/InternPool.zig+154-275| ... | ... | @@ -363,33 +363,53 @@ pub fn rehashTrackedInsts( |
| 363 | 363 | } |
| 364 | 364 | |
| 365 | 365 | /// 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. | |
| 368 | 366 | /// This is the "source" of an incremental dependency edge. |
| 369 | pub const AnalUnit = packed struct(u32) { | |
| 370 | kind: enum(u1) { cau, func }, | |
| 371 | index: u31, | |
| 372 | pub const Unwrapped = union(enum) { | |
| 373 | cau: Cau.Index, | |
| 367 | pub 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. | |
| 374 | 387 | func: InternPool.Index, |
| 375 | 388 | }; |
| 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 | ), | |
| 380 | 397 | }; |
| 381 | 398 | } |
| 382 | 399 | pub fn wrap(raw: Unwrapped) AnalUnit { |
| 383 | 400 | 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 | }, | |
| 386 | 405 | }; |
| 387 | 406 | } |
| 407 | ||
| 388 | 408 | pub fn toOptional(as: AnalUnit) Optional { |
| 389 | return @enumFromInt(@as(u32, @bitCast(as))); | |
| 409 | return @enumFromInt(@as(u64, @bitCast(as))); | |
| 390 | 410 | } |
| 391 | pub const Optional = enum(u32) { | |
| 392 | none = std.math.maxInt(u32), | |
| 411 | pub const Optional = enum(u64) { | |
| 412 | none = std.math.maxInt(u64), | |
| 393 | 413 | _, |
| 394 | 414 | pub fn unwrap(opt: Optional) ?AnalUnit { |
| 395 | 415 | return switch (opt) { |
| ... | ... | @@ -400,97 +420,30 @@ pub const AnalUnit = packed struct(u32) { |
| 400 | 420 | }; |
| 401 | 421 | }; |
| 402 | 422 | |
| 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. | |
| 415 | pub const Cau = struct { | |
| 416 | /// The `declaration`, `struct_decl`, `enum_decl`, or `union_decl` instruction which this `Cau` analyzes. | |
| 423 | pub const ComptimeUnit = extern struct { | |
| 417 | 424 | zir_index: TrackedInst.Index, |
| 418 | /// The namespace which this `Cau` should be analyzed within. | |
| 419 | 425 | 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 | }; | |
| 442 | 426 | |
| 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 | } | |
| 461 | 430 | |
| 462 | pub const Index = enum(u32) { | |
| 431 | pub const Id = enum(u32) { | |
| 463 | 432 | _, |
| 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 | } | |
| 479 | 433 | const Unwrapped = struct { |
| 480 | 434 | tid: Zcu.PerThread.Id, |
| 481 | 435 | index: u32, |
| 482 | ||
| 483 | fn wrap(unwrapped: Unwrapped, ip: *const InternPool) Cau.Index { | |
| 436 | fn wrap(unwrapped: Unwrapped, ip: *const InternPool) ComptimeUnit.Id { | |
| 484 | 437 | 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 | | |
| 487 | 440 | unwrapped.index); |
| 488 | 441 | } |
| 489 | 442 | }; |
| 490 | fn unwrap(cau_index: Cau.Index, ip: *const InternPool) Unwrapped { | |
| 443 | fn unwrap(id: Id, ip: *const InternPool) Unwrapped { | |
| 491 | 444 | 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), | |
| 494 | 447 | }; |
| 495 | 448 | } |
| 496 | 449 | |
| ... | ... | @@ -507,6 +460,11 @@ pub const Cau = struct { |
| 507 | 460 | /// * Generic instances have a `Nav` corresponding to the instantiated function. |
| 508 | 461 | /// * `@extern` calls create a `Nav` whose value is a `.@"extern"`. |
| 509 | 462 | /// |
| 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 | /// | |
| 510 | 468 | /// `Nav.Repr` is the in-memory representation. |
| 511 | 469 | pub const Nav = struct { |
| 512 | 470 | /// 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 { |
| 514 | 472 | name: NullTerminatedString, |
| 515 | 473 | /// The fully-qualified name of this `Nav`. |
| 516 | 474 | 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 | }, | |
| 520 | 481 | /// TODO: this is a hack! If #20663 isn't accepted, let's figure out something a bit better. |
| 521 | 482 | is_usingnamespace: bool, |
| 522 | 483 | status: union(enum) { |
| 523 | /// This `Nav` is pending semantic analysis through `analysis_owner`. | |
| 484 | /// This `Nav` is pending semantic analysis. | |
| 524 | 485 | unresolved, |
| 525 | 486 | /// The value of this `Nav` is resolved. |
| 526 | 487 | resolved: struct { |
| ... | ... | @@ -544,17 +505,16 @@ pub const Nav = struct { |
| 544 | 505 | /// Get the ZIR instruction corresponding to this `Nav`, used to resolve source locations. |
| 545 | 506 | /// This is a `declaration`. |
| 546 | 507 | 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; | |
| 549 | 510 | } |
| 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. | |
| 551 | 512 | return switch (ip.indexToKey(nav.status.resolved.val)) { |
| 552 | 513 | .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. | |
| 555 | 516 | 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; | |
| 558 | 518 | }, |
| 559 | 519 | .@"extern" => |@"extern"| @"extern".zir_index, // extern / @extern |
| 560 | 520 | else => unreachable, |
| ... | ... | @@ -600,11 +560,13 @@ pub const Nav = struct { |
| 600 | 560 | }; |
| 601 | 561 | |
| 602 | 562 | /// The compact in-memory representation of a `Nav`. |
| 603 | /// 18 bytes. | |
| 563 | /// 26 bytes. | |
| 604 | 564 | const Repr = struct { |
| 605 | 565 | name: NullTerminatedString, |
| 606 | 566 | 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, | |
| 608 | 570 | /// Populated only if `bits.status == .resolved`. |
| 609 | 571 | val: InternPool.Index, |
| 610 | 572 | /// Populated only if `bits.status == .resolved`. |
| ... | ... | @@ -625,7 +587,13 @@ pub const Nav = struct { |
| 625 | 587 | return .{ |
| 626 | 588 | .name = repr.name, |
| 627 | 589 | .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 | }, | |
| 629 | 597 | .is_usingnamespace = repr.bits.is_usingnamespace, |
| 630 | 598 | .status = switch (repr.bits.status) { |
| 631 | 599 | .unresolved => .unresolved, |
| ... | ... | @@ -646,7 +614,8 @@ pub const Nav = struct { |
| 646 | 614 | return .{ |
| 647 | 615 | .name = nav.name, |
| 648 | 616 | .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, | |
| 650 | 619 | .val = switch (nav.status) { |
| 651 | 620 | .unresolved => .none, |
| 652 | 621 | .resolved => |r| r.val, |
| ... | ... | @@ -862,8 +831,8 @@ const Local = struct { |
| 862 | 831 | tracked_insts: ListMutate, |
| 863 | 832 | files: ListMutate, |
| 864 | 833 | maps: ListMutate, |
| 865 | caus: ListMutate, | |
| 866 | 834 | navs: ListMutate, |
| 835 | comptime_units: ListMutate, | |
| 867 | 836 | |
| 868 | 837 | namespaces: BucketListMutate, |
| 869 | 838 | } align(std.atomic.cache_line), |
| ... | ... | @@ -876,8 +845,8 @@ const Local = struct { |
| 876 | 845 | tracked_insts: TrackedInsts, |
| 877 | 846 | files: List(File), |
| 878 | 847 | maps: Maps, |
| 879 | caus: Caus, | |
| 880 | 848 | navs: Navs, |
| 849 | comptime_units: ComptimeUnits, | |
| 881 | 850 | |
| 882 | 851 | namespaces: Namespaces, |
| 883 | 852 | |
| ... | ... | @@ -899,8 +868,8 @@ const Local = struct { |
| 899 | 868 | const Strings = List(struct { u8 }); |
| 900 | 869 | const TrackedInsts = List(struct { TrackedInst.MaybeLost }); |
| 901 | 870 | const Maps = List(struct { FieldMap }); |
| 902 | const Caus = List(struct { Cau }); | |
| 903 | 871 | const Navs = List(Nav.Repr); |
| 872 | const ComptimeUnits = List(struct { ComptimeUnit }); | |
| 904 | 873 | |
| 905 | 874 | const namespaces_bucket_width = 8; |
| 906 | 875 | const namespaces_bucket_mask = (1 << namespaces_bucket_width) - 1; |
| ... | ... | @@ -1275,21 +1244,21 @@ const Local = struct { |
| 1275 | 1244 | }; |
| 1276 | 1245 | } |
| 1277 | 1246 | |
| 1278 | pub fn getMutableCaus(local: *Local, gpa: Allocator) Caus.Mutable { | |
| 1247 | pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable { | |
| 1279 | 1248 | return .{ |
| 1280 | 1249 | .gpa = gpa, |
| 1281 | 1250 | .arena = &local.mutate.arena, |
| 1282 | .mutate = &local.mutate.caus, | |
| 1283 | .list = &local.shared.caus, | |
| 1251 | .mutate = &local.mutate.navs, | |
| 1252 | .list = &local.shared.navs, | |
| 1284 | 1253 | }; |
| 1285 | 1254 | } |
| 1286 | 1255 | |
| 1287 | pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable { | |
| 1256 | pub fn getMutableComptimeUnits(local: *Local, gpa: Allocator) ComptimeUnits.Mutable { | |
| 1288 | 1257 | return .{ |
| 1289 | 1258 | .gpa = gpa, |
| 1290 | 1259 | .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, | |
| 1293 | 1262 | }; |
| 1294 | 1263 | } |
| 1295 | 1264 | |
| ... | ... | @@ -3052,8 +3021,6 @@ pub const LoadedUnionType = struct { |
| 3052 | 3021 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3053 | 3022 | /// The name of this union type. |
| 3054 | 3023 | name: NullTerminatedString, |
| 3055 | /// The `Cau` within which type resolution occurs. | |
| 3056 | cau: Cau.Index, | |
| 3057 | 3024 | /// Represents the declarations inside this union. |
| 3058 | 3025 | namespace: NamespaceIndex, |
| 3059 | 3026 | /// The enum tag type. |
| ... | ... | @@ -3370,7 +3337,6 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3370 | 3337 | .tid = unwrapped_index.tid, |
| 3371 | 3338 | .extra_index = data, |
| 3372 | 3339 | .name = type_union.data.name, |
| 3373 | .cau = type_union.data.cau, | |
| 3374 | 3340 | .namespace = type_union.data.namespace, |
| 3375 | 3341 | .enum_tag_ty = type_union.data.tag_ty, |
| 3376 | 3342 | .field_types = field_types, |
| ... | ... | @@ -3387,8 +3353,6 @@ pub const LoadedStructType = struct { |
| 3387 | 3353 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3388 | 3354 | /// The name of this struct type. |
| 3389 | 3355 | name: NullTerminatedString, |
| 3390 | /// The `Cau` within which type resolution occurs. | |
| 3391 | cau: Cau.Index, | |
| 3392 | 3356 | namespace: NamespaceIndex, |
| 3393 | 3357 | /// Index of the `struct_decl` or `reify` ZIR instruction. |
| 3394 | 3358 | zir_index: TrackedInst.Index, |
| ... | ... | @@ -3979,7 +3943,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3979 | 3943 | switch (item.tag) { |
| 3980 | 3944 | .type_struct => { |
| 3981 | 3945 | 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").?]); | |
| 3983 | 3946 | const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]); |
| 3984 | 3947 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]); |
| 3985 | 3948 | 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 { |
| 4066 | 4029 | .tid = unwrapped_index.tid, |
| 4067 | 4030 | .extra_index = item.data, |
| 4068 | 4031 | .name = name, |
| 4069 | .cau = cau, | |
| 4070 | 4032 | .namespace = namespace, |
| 4071 | 4033 | .zir_index = zir_index, |
| 4072 | 4034 | .layout = if (flags.is_extern) .@"extern" else .auto, |
| ... | ... | @@ -4083,7 +4045,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 4083 | 4045 | }, |
| 4084 | 4046 | .type_struct_packed, .type_struct_packed_inits => { |
| 4085 | 4047 | 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").?]); | |
| 4087 | 4048 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]); |
| 4088 | 4049 | const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?]; |
| 4089 | 4050 | 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 { |
| 4130 | 4091 | .tid = unwrapped_index.tid, |
| 4131 | 4092 | .extra_index = item.data, |
| 4132 | 4093 | .name = name, |
| 4133 | .cau = cau, | |
| 4134 | 4094 | .namespace = namespace, |
| 4135 | 4095 | .zir_index = zir_index, |
| 4136 | 4096 | .layout = .@"packed", |
| ... | ... | @@ -4153,9 +4113,6 @@ pub const LoadedEnumType = struct { |
| 4153 | 4113 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 4154 | 4114 | /// The name of this enum type. |
| 4155 | 4115 | name: NullTerminatedString, |
| 4156 | /// The `Cau` within which type resolution occurs. | |
| 4157 | /// `null` if this is a generated tag type. | |
| 4158 | cau: Cau.Index.Optional, | |
| 4159 | 4116 | /// Represents the declarations inside this enum. |
| 4160 | 4117 | namespace: NamespaceIndex, |
| 4161 | 4118 | /// 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 { |
| 4232 | 4189 | .type_enum_auto => { |
| 4233 | 4190 | const extra = extraDataTrail(extra_list, EnumAuto, item.data); |
| 4234 | 4191 | 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) { | |
| 4236 | 4193 | 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 | } | |
| 4243 | 4195 | const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: { |
| 4244 | 4196 | extra_index += 2; // type_hash: PackedU64 |
| 4245 | 4197 | break :c 0; |
| 4246 | 4198 | } else extra.data.captures_len; |
| 4247 | 4199 | return .{ |
| 4248 | 4200 | .name = extra.data.name, |
| 4249 | .cau = cau, | |
| 4250 | 4201 | .namespace = extra.data.namespace, |
| 4251 | 4202 | .tag_ty = extra.data.int_tag_type, |
| 4252 | 4203 | .names = .{ |
| ... | ... | @@ -4272,21 +4223,15 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { |
| 4272 | 4223 | }; |
| 4273 | 4224 | const extra = extraDataTrail(extra_list, EnumExplicit, item.data); |
| 4274 | 4225 | 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) { | |
| 4276 | 4227 | 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 | } | |
| 4283 | 4229 | const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: { |
| 4284 | 4230 | extra_index += 2; // type_hash: PackedU64 |
| 4285 | 4231 | break :c 0; |
| 4286 | 4232 | } else extra.data.captures_len; |
| 4287 | 4233 | return .{ |
| 4288 | 4234 | .name = extra.data.name, |
| 4289 | .cau = cau, | |
| 4290 | 4235 | .namespace = extra.data.namespace, |
| 4291 | 4236 | .tag_ty = extra.data.int_tag_type, |
| 4292 | 4237 | .names = .{ |
| ... | ... | @@ -5256,7 +5201,6 @@ pub const Tag = enum(u8) { |
| 5256 | 5201 | .payload = EnumExplicit, |
| 5257 | 5202 | .trailing = struct { |
| 5258 | 5203 | owner_union: Index, |
| 5259 | cau: ?Cau.Index, | |
| 5260 | 5204 | captures: ?[]CaptureValue, |
| 5261 | 5205 | type_hash: ?u64, |
| 5262 | 5206 | field_names: []NullTerminatedString, |
| ... | ... | @@ -5302,7 +5246,6 @@ pub const Tag = enum(u8) { |
| 5302 | 5246 | .payload = EnumAuto, |
| 5303 | 5247 | .trailing = struct { |
| 5304 | 5248 | owner_union: ?Index, |
| 5305 | cau: ?Cau.Index, | |
| 5306 | 5249 | captures: ?[]CaptureValue, |
| 5307 | 5250 | type_hash: ?u64, |
| 5308 | 5251 | field_names: []NullTerminatedString, |
| ... | ... | @@ -5679,7 +5622,6 @@ pub const Tag = enum(u8) { |
| 5679 | 5622 | size: u32, |
| 5680 | 5623 | /// Only valid after .have_layout |
| 5681 | 5624 | padding: u32, |
| 5682 | cau: Cau.Index, | |
| 5683 | 5625 | namespace: NamespaceIndex, |
| 5684 | 5626 | /// The enum that provides the list of field names and values. |
| 5685 | 5627 | tag_ty: Index, |
| ... | ... | @@ -5710,7 +5652,6 @@ pub const Tag = enum(u8) { |
| 5710 | 5652 | /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits |
| 5711 | 5653 | pub const TypeStructPacked = struct { |
| 5712 | 5654 | name: NullTerminatedString, |
| 5713 | cau: Cau.Index, | |
| 5714 | 5655 | zir_index: TrackedInst.Index, |
| 5715 | 5656 | fields_len: u32, |
| 5716 | 5657 | namespace: NamespaceIndex, |
| ... | ... | @@ -5758,7 +5699,6 @@ pub const Tag = enum(u8) { |
| 5758 | 5699 | /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved |
| 5759 | 5700 | pub const TypeStruct = struct { |
| 5760 | 5701 | name: NullTerminatedString, |
| 5761 | cau: Cau.Index, | |
| 5762 | 5702 | zir_index: TrackedInst.Index, |
| 5763 | 5703 | namespace: NamespaceIndex, |
| 5764 | 5704 | fields_len: u32, |
| ... | ... | @@ -6088,11 +6028,10 @@ pub const Array = struct { |
| 6088 | 6028 | |
| 6089 | 6029 | /// Trailing: |
| 6090 | 6030 | /// 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 | |
| 6096 | 6035 | pub const EnumExplicit = struct { |
| 6097 | 6036 | name: NullTerminatedString, |
| 6098 | 6037 | /// `std.math.maxInt(u32)` indicates this type is reified. |
| ... | ... | @@ -6115,10 +6054,9 @@ pub const EnumExplicit = struct { |
| 6115 | 6054 | |
| 6116 | 6055 | /// Trailing: |
| 6117 | 6056 | /// 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 | |
| 6122 | 6060 | pub const EnumAuto = struct { |
| 6123 | 6061 | name: NullTerminatedString, |
| 6124 | 6062 | /// `std.math.maxInt(u32)` indicates this type is reified. |
| ... | ... | @@ -6408,32 +6346,32 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void { |
| 6408 | 6346 | ip.locals = try gpa.alloc(Local, used_threads); |
| 6409 | 6347 | @memset(ip.locals, .{ |
| 6410 | 6348 | .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, | |
| 6422 | 6360 | }, |
| 6423 | 6361 | .mutate = .{ |
| 6424 | 6362 | .arena = .{}, |
| 6425 | 6363 | |
| 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, | |
| 6435 | 6373 | |
| 6436 | .namespaces = Local.BucketListMutate.empty, | |
| 6374 | .namespaces = .empty, | |
| 6437 | 6375 | }, |
| 6438 | 6376 | }); |
| 6439 | 6377 | |
| ... | ... | @@ -6506,7 +6444,8 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 6506 | 6444 | namespace.priv_decls.deinit(gpa); |
| 6507 | 6445 | namespace.pub_usingnamespace.deinit(gpa); |
| 6508 | 6446 | namespace.priv_usingnamespace.deinit(gpa); |
| 6509 | namespace.other_decls.deinit(gpa); | |
| 6447 | namespace.comptime_decls.deinit(gpa); | |
| 6448 | namespace.test_decls.deinit(gpa); | |
| 6510 | 6449 | } |
| 6511 | 6450 | }; |
| 6512 | 6451 | const maps = local.getMutableMaps(gpa); |
| ... | ... | @@ -6525,8 +6464,6 @@ pub fn activate(ip: *const InternPool) void { |
| 6525 | 6464 | _ = OptionalString.debug_state; |
| 6526 | 6465 | _ = NullTerminatedString.debug_state; |
| 6527 | 6466 | _ = OptionalNullTerminatedString.debug_state; |
| 6528 | _ = Cau.Index.debug_state; | |
| 6529 | _ = Cau.Index.Optional.debug_state; | |
| 6530 | 6467 | _ = Nav.Index.debug_state; |
| 6531 | 6468 | _ = Nav.Index.Optional.debug_state; |
| 6532 | 6469 | std.debug.assert(debug_state.intern_pool == null); |
| ... | ... | @@ -6711,14 +6648,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6711 | 6648 | if (extra.data.captures_len == std.math.maxInt(u32)) { |
| 6712 | 6649 | break :ns .{ .reified = .{ |
| 6713 | 6650 | .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(), | |
| 6715 | 6652 | } }; |
| 6716 | 6653 | } |
| 6717 | 6654 | break :ns .{ .declared = .{ |
| 6718 | 6655 | .zir_index = zir_index, |
| 6719 | 6656 | .captures = .{ .owned = .{ |
| 6720 | 6657 | .tid = unwrapped_index.tid, |
| 6721 | .start = extra.end + 1, | |
| 6658 | .start = extra.end, | |
| 6722 | 6659 | .len = extra.data.captures_len, |
| 6723 | 6660 | } }, |
| 6724 | 6661 | } }; |
| ... | ... | @@ -6735,14 +6672,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6735 | 6672 | if (extra.data.captures_len == std.math.maxInt(u32)) { |
| 6736 | 6673 | break :ns .{ .reified = .{ |
| 6737 | 6674 | .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(), | |
| 6739 | 6676 | } }; |
| 6740 | 6677 | } |
| 6741 | 6678 | break :ns .{ .declared = .{ |
| 6742 | 6679 | .zir_index = zir_index, |
| 6743 | 6680 | .captures = .{ .owned = .{ |
| 6744 | 6681 | .tid = unwrapped_index.tid, |
| 6745 | .start = extra.end + 1, | |
| 6682 | .start = extra.end, | |
| 6746 | 6683 | .len = extra.data.captures_len, |
| 6747 | 6684 | } }, |
| 6748 | 6685 | } }; |
| ... | ... | @@ -8323,7 +8260,6 @@ pub fn getUnionType( |
| 8323 | 8260 | .size = std.math.maxInt(u32), |
| 8324 | 8261 | .padding = std.math.maxInt(u32), |
| 8325 | 8262 | .name = undefined, // set by `finish` |
| 8326 | .cau = undefined, // set by `finish` | |
| 8327 | 8263 | .namespace = undefined, // set by `finish` |
| 8328 | 8264 | .tag_ty = ini.enum_tag_ty, |
| 8329 | 8265 | .zir_index = switch (ini.key) { |
| ... | ... | @@ -8375,7 +8311,6 @@ pub fn getUnionType( |
| 8375 | 8311 | .tid = tid, |
| 8376 | 8312 | .index = gop.put(), |
| 8377 | 8313 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, |
| 8378 | .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "cau").?, | |
| 8379 | 8314 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, |
| 8380 | 8315 | } }; |
| 8381 | 8316 | } |
| ... | ... | @@ -8384,7 +8319,6 @@ pub const WipNamespaceType = struct { |
| 8384 | 8319 | tid: Zcu.PerThread.Id, |
| 8385 | 8320 | index: Index, |
| 8386 | 8321 | type_name_extra_index: u32, |
| 8387 | cau_extra_index: ?u32, | |
| 8388 | 8322 | namespace_extra_index: u32, |
| 8389 | 8323 | |
| 8390 | 8324 | pub fn setName( |
| ... | ... | @@ -8400,18 +8334,11 @@ pub const WipNamespaceType = struct { |
| 8400 | 8334 | pub fn finish( |
| 8401 | 8335 | wip: WipNamespaceType, |
| 8402 | 8336 | ip: *InternPool, |
| 8403 | analysis_owner: Cau.Index.Optional, | |
| 8404 | 8337 | namespace: NamespaceIndex, |
| 8405 | 8338 | ) Index { |
| 8406 | 8339 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); |
| 8407 | 8340 | const extra_items = extra.view().items(.@"0"); |
| 8408 | 8341 | |
| 8409 | if (wip.cau_extra_index) |i| { | |
| 8410 | extra_items[i] = @intFromEnum(analysis_owner.unwrap().?); | |
| 8411 | } else { | |
| 8412 | assert(analysis_owner == .none); | |
| 8413 | } | |
| 8414 | ||
| 8415 | 8342 | extra_items[wip.namespace_extra_index] = @intFromEnum(namespace); |
| 8416 | 8343 | |
| 8417 | 8344 | return wip.index; |
| ... | ... | @@ -8510,7 +8437,6 @@ pub fn getStructType( |
| 8510 | 8437 | ini.fields_len); // inits |
| 8511 | 8438 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ |
| 8512 | 8439 | .name = undefined, // set by `finish` |
| 8513 | .cau = undefined, // set by `finish` | |
| 8514 | 8440 | .zir_index = zir_index, |
| 8515 | 8441 | .fields_len = ini.fields_len, |
| 8516 | 8442 | .namespace = undefined, // set by `finish` |
| ... | ... | @@ -8555,7 +8481,6 @@ pub fn getStructType( |
| 8555 | 8481 | .tid = tid, |
| 8556 | 8482 | .index = gop.put(), |
| 8557 | 8483 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, |
| 8558 | .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "cau").?, | |
| 8559 | 8484 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, |
| 8560 | 8485 | } }; |
| 8561 | 8486 | }, |
| ... | ... | @@ -8578,7 +8503,6 @@ pub fn getStructType( |
| 8578 | 8503 | 1); // names_map |
| 8579 | 8504 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ |
| 8580 | 8505 | .name = undefined, // set by `finish` |
| 8581 | .cau = undefined, // set by `finish` | |
| 8582 | 8506 | .zir_index = zir_index, |
| 8583 | 8507 | .namespace = undefined, // set by `finish` |
| 8584 | 8508 | .fields_len = ini.fields_len, |
| ... | ... | @@ -8647,7 +8571,6 @@ pub fn getStructType( |
| 8647 | 8571 | .tid = tid, |
| 8648 | 8572 | .index = gop.put(), |
| 8649 | 8573 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, |
| 8650 | .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "cau").?, | |
| 8651 | 8574 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?, |
| 8652 | 8575 | } }; |
| 8653 | 8576 | } |
| ... | ... | @@ -9383,7 +9306,7 @@ fn finishFuncInstance( |
| 9383 | 9306 | func_extra_index: u32, |
| 9384 | 9307 | ) Allocator.Error!void { |
| 9385 | 9308 | 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; | |
| 9387 | 9310 | |
| 9388 | 9311 | // TODO: improve this name |
| 9389 | 9312 | const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{}__anon_{d}", .{ |
| ... | ... | @@ -9429,7 +9352,6 @@ pub const WipEnumType = struct { |
| 9429 | 9352 | index: Index, |
| 9430 | 9353 | tag_ty_index: u32, |
| 9431 | 9354 | type_name_extra_index: u32, |
| 9432 | cau_extra_index: u32, | |
| 9433 | 9355 | namespace_extra_index: u32, |
| 9434 | 9356 | names_map: MapIndex, |
| 9435 | 9357 | names_start: u32, |
| ... | ... | @@ -9449,13 +9371,11 @@ pub const WipEnumType = struct { |
| 9449 | 9371 | pub fn prepare( |
| 9450 | 9372 | wip: WipEnumType, |
| 9451 | 9373 | ip: *InternPool, |
| 9452 | analysis_owner: Cau.Index, | |
| 9453 | 9374 | namespace: NamespaceIndex, |
| 9454 | 9375 | ) void { |
| 9455 | 9376 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); |
| 9456 | 9377 | const extra_items = extra.view().items(.@"0"); |
| 9457 | 9378 | |
| 9458 | extra_items[wip.cau_extra_index] = @intFromEnum(analysis_owner); | |
| 9459 | 9379 | extra_items[wip.namespace_extra_index] = @intFromEnum(namespace); |
| 9460 | 9380 | } |
| 9461 | 9381 | |
| ... | ... | @@ -9556,7 +9476,6 @@ pub fn getEnumType( |
| 9556 | 9476 | .reified => 2, // type_hash: PackedU64 |
| 9557 | 9477 | } + |
| 9558 | 9478 | // zig fmt: on |
| 9559 | 1 + // cau | |
| 9560 | 9479 | ini.fields_len); // field types |
| 9561 | 9480 | |
| 9562 | 9481 | const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ |
| ... | ... | @@ -9577,8 +9496,6 @@ pub fn getEnumType( |
| 9577 | 9496 | .tag = .type_enum_auto, |
| 9578 | 9497 | .data = extra_index, |
| 9579 | 9498 | }); |
| 9580 | const cau_extra_index = extra.view().len; | |
| 9581 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | |
| 9582 | 9499 | switch (ini.key) { |
| 9583 | 9500 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9584 | 9501 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), |
| ... | ... | @@ -9591,7 +9508,6 @@ pub fn getEnumType( |
| 9591 | 9508 | .index = gop.put(), |
| 9592 | 9509 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, |
| 9593 | 9510 | .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?, |
| 9594 | .cau_extra_index = @intCast(cau_extra_index), | |
| 9595 | 9511 | .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?, |
| 9596 | 9512 | .names_map = names_map, |
| 9597 | 9513 | .names_start = @intCast(names_start), |
| ... | ... | @@ -9616,7 +9532,6 @@ pub fn getEnumType( |
| 9616 | 9532 | .reified => 2, // type_hash: PackedU64 |
| 9617 | 9533 | } + |
| 9618 | 9534 | // zig fmt: on |
| 9619 | 1 + // cau | |
| 9620 | 9535 | ini.fields_len + // field types |
| 9621 | 9536 | ini.fields_len * @intFromBool(ini.has_values)); // field values |
| 9622 | 9537 | |
| ... | ... | @@ -9643,8 +9558,6 @@ pub fn getEnumType( |
| 9643 | 9558 | }, |
| 9644 | 9559 | .data = extra_index, |
| 9645 | 9560 | }); |
| 9646 | const cau_extra_index = extra.view().len; | |
| 9647 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | |
| 9648 | 9561 | switch (ini.key) { |
| 9649 | 9562 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9650 | 9563 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), |
| ... | ... | @@ -9661,7 +9574,6 @@ pub fn getEnumType( |
| 9661 | 9574 | .index = gop.put(), |
| 9662 | 9575 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, |
| 9663 | 9576 | .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?, |
| 9664 | .cau_extra_index = @intCast(cau_extra_index), | |
| 9665 | 9577 | .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?, |
| 9666 | 9578 | .names_map = names_map, |
| 9667 | 9579 | .names_start = @intCast(names_start), |
| ... | ... | @@ -9858,7 +9770,6 @@ pub fn getOpaqueType( |
| 9858 | 9770 | .tid = tid, |
| 9859 | 9771 | .index = gop.put(), |
| 9860 | 9772 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, |
| 9861 | .cau_extra_index = null, // opaques do not undergo type resolution | |
| 9862 | 9773 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, |
| 9863 | 9774 | }, |
| 9864 | 9775 | }; |
| ... | ... | @@ -9974,7 +9885,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { |
| 9974 | 9885 | inline for (@typeInfo(@TypeOf(item)).@"struct".fields) |field| { |
| 9975 | 9886 | extra.appendAssumeCapacity(.{switch (field.type) { |
| 9976 | 9887 | Index, |
| 9977 | Cau.Index, | |
| 9978 | 9888 | Nav.Index, |
| 9979 | 9889 | NamespaceIndex, |
| 9980 | 9890 | OptionalNamespaceIndex, |
| ... | ... | @@ -10037,7 +9947,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat |
| 10037 | 9947 | const extra_item = extra_items[extra_index]; |
| 10038 | 9948 | @field(result, field.name) = switch (field.type) { |
| 10039 | 9949 | Index, |
| 10040 | Cau.Index, | |
| 10041 | 9950 | Nav.Index, |
| 10042 | 9951 | NamespaceIndex, |
| 10043 | 9952 | OptionalNamespaceIndex, |
| ... | ... | @@ -11058,12 +10967,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) |
| 11058 | 10967 | try bw.flush(); |
| 11059 | 10968 | } |
| 11060 | 10969 | |
| 11061 | pub 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 | ||
| 11067 | 10970 | pub fn getNav(ip: *const InternPool, index: Nav.Index) Nav { |
| 11068 | 10971 | const unwrapped = index.unwrap(ip); |
| 11069 | 10972 | const navs = ip.getLocalShared(unwrapped.tid).navs.acquire(); |
| ... | ... | @@ -11077,51 +10980,34 @@ pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Names |
| 11077 | 10980 | return &namespaces_bucket[unwrapped_namespace_index.index]; |
| 11078 | 10981 | } |
| 11079 | 10982 | |
| 11080 | /// Create a `Cau` associated with the type at the given `InternPool.Index`. | |
| 11081 | pub fn createTypeCau( | |
| 10983 | /// Create a `ComptimeUnit`, forming an `AnalUnit` for a `comptime` declaration. | |
| 10984 | pub fn createComptimeUnit( | |
| 11082 | 10985 | ip: *InternPool, |
| 11083 | 10986 | gpa: Allocator, |
| 11084 | 10987 | tid: Zcu.PerThread.Id, |
| 11085 | 10988 | zir_index: TrackedInst.Index, |
| 11086 | 10989 | 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 = .{ | |
| 11091 | 10993 | .tid = tid, |
| 11092 | .index = caus.mutate.len, | |
| 10994 | .index = comptime_units.mutate.len, | |
| 11093 | 10995 | }; |
| 11094 | try caus.append(.{.{ | |
| 10996 | try comptime_units.append(.{.{ | |
| 11095 | 10997 | .zir_index = zir_index, |
| 11096 | 10998 | .namespace = namespace, |
| 11097 | .owner = Cau.Owner.wrap(.{ .type = owner_type }), | |
| 11098 | 10999 | }}); |
| 11099 | return index_unwrapped.wrap(ip); | |
| 11000 | return id_unwrapped.wrap(ip); | |
| 11100 | 11001 | } |
| 11101 | 11002 | |
| 11102 | /// Create a `Cau` for a `comptime` declaration. | |
| 11103 | pub 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); | |
| 11003 | pub 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]; | |
| 11121 | 11007 | } |
| 11122 | 11008 | |
| 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. | |
| 11125 | 11011 | pub fn createNav( |
| 11126 | 11012 | ip: *InternPool, |
| 11127 | 11013 | gpa: Allocator, |
| ... | ... | @@ -11143,7 +11029,7 @@ pub fn createNav( |
| 11143 | 11029 | try navs.append(Nav.pack(.{ |
| 11144 | 11030 | .name = opts.name, |
| 11145 | 11031 | .fqn = opts.fqn, |
| 11146 | .analysis_owner = .none, | |
| 11032 | .analysis = null, | |
| 11147 | 11033 | .status = .{ .resolved = .{ |
| 11148 | 11034 | .val = opts.val, |
| 11149 | 11035 | .alignment = opts.alignment, |
| ... | ... | @@ -11155,10 +11041,9 @@ pub fn createNav( |
| 11155 | 11041 | return index_unwrapped.wrap(ip); |
| 11156 | 11042 | } |
| 11157 | 11043 | |
| 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. | |
| 11161 | pub 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. | |
| 11046 | pub fn createDeclNav( | |
| 11162 | 11047 | ip: *InternPool, |
| 11163 | 11048 | gpa: Allocator, |
| 11164 | 11049 | tid: Zcu.PerThread.Id, |
| ... | ... | @@ -11168,36 +11053,28 @@ pub fn createPairedCauNav( |
| 11168 | 11053 | namespace: NamespaceIndex, |
| 11169 | 11054 | /// TODO: this is hacky! See `Nav.is_usingnamespace`. |
| 11170 | 11055 | is_usingnamespace: bool, |
| 11171 | ) Allocator.Error!struct { Cau.Index, Nav.Index } { | |
| 11172 | const caus = ip.getLocal(tid).getMutableCaus(gpa); | |
| 11056 | ) Allocator.Error!Nav.Index { | |
| 11173 | 11057 | const navs = ip.getLocal(tid).getMutableNavs(gpa); |
| 11174 | 11058 | |
| 11175 | try caus.ensureUnusedCapacity(1); | |
| 11176 | 11059 | try navs.ensureUnusedCapacity(1); |
| 11177 | 11060 | |
| 11178 | const cau = Cau.Index.Unwrapped.wrap(.{ | |
| 11179 | .tid = tid, | |
| 11180 | .index = caus.mutate.len, | |
| 11181 | }, ip); | |
| 11182 | 11061 | const nav = Nav.Index.Unwrapped.wrap(.{ |
| 11183 | 11062 | .tid = tid, |
| 11184 | 11063 | .index = navs.mutate.len, |
| 11185 | 11064 | }, ip); |
| 11186 | 11065 | |
| 11187 | caus.appendAssumeCapacity(.{.{ | |
| 11188 | .zir_index = zir_index, | |
| 11189 | .namespace = namespace, | |
| 11190 | .owner = Cau.Owner.wrap(.{ .nav = nav }), | |
| 11191 | }}); | |
| 11192 | 11066 | navs.appendAssumeCapacity(Nav.pack(.{ |
| 11193 | 11067 | .name = name, |
| 11194 | 11068 | .fqn = fqn, |
| 11195 | .analysis_owner = cau.toOptional(), | |
| 11069 | .analysis = .{ | |
| 11070 | .namespace = namespace, | |
| 11071 | .zir_index = zir_index, | |
| 11072 | }, | |
| 11196 | 11073 | .status = .unresolved, |
| 11197 | 11074 | .is_usingnamespace = is_usingnamespace, |
| 11198 | 11075 | })); |
| 11199 | 11076 | |
| 11200 | return .{ cau, nav }; | |
| 11077 | return nav; | |
| 11201 | 11078 | } |
| 11202 | 11079 | |
| 11203 | 11080 | /// Resolve the value of a `Nav` with an analysis owner. |
| ... | ... | @@ -11220,12 +11097,14 @@ pub fn resolveNavValue( |
| 11220 | 11097 | |
| 11221 | 11098 | const navs = local.shared.navs.view(); |
| 11222 | 11099 | |
| 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); | |
| 11224 | 11102 | const nav_vals = navs.items(.val); |
| 11225 | 11103 | const nav_linksections = navs.items(.@"linksection"); |
| 11226 | 11104 | const nav_bits = navs.items(.bits); |
| 11227 | 11105 | |
| 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); | |
| 11229 | 11108 | |
| 11230 | 11109 | @atomicStore(InternPool.Index, &nav_vals[unwrapped.index], resolved.val, .release); |
| 11231 | 11110 | @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release); |
src/Sema.zig+85-143| ... | ... | @@ -2870,7 +2870,7 @@ fn zirStructDecl( |
| 2870 | 2870 | }; |
| 2871 | 2871 | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) { |
| 2872 | 2872 | .existing => |ty| { |
| 2873 | const new_ty = try pt.ensureTypeUpToDate(ty, false); | |
| 2873 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 2874 | 2874 | |
| 2875 | 2875 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 2876 | 2876 | // up on e.g. changed comptime decls. |
| ... | ... | @@ -2900,12 +2900,10 @@ fn zirStructDecl( |
| 2900 | 2900 | }); |
| 2901 | 2901 | errdefer pt.destroyNamespace(new_namespace_index); |
| 2902 | 2902 | |
| 2903 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 2904 | ||
| 2905 | 2903 | if (pt.zcu.comp.incremental) { |
| 2906 | 2904 | try ip.addDependency( |
| 2907 | 2905 | sema.gpa, |
| 2908 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 2906 | AnalUnit.wrap(.{ .type = wip_ty.index }), | |
| 2909 | 2907 | .{ .src_hash = tracked_inst }, |
| 2910 | 2908 | ); |
| 2911 | 2909 | } |
| ... | ... | @@ -2922,7 +2920,7 @@ fn zirStructDecl( |
| 2922 | 2920 | } |
| 2923 | 2921 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 2924 | 2922 | 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)); | |
| 2926 | 2924 | } |
| 2927 | 2925 | |
| 2928 | 2926 | fn createTypeName( |
| ... | ... | @@ -3100,7 +3098,7 @@ fn zirEnumDecl( |
| 3100 | 3098 | }; |
| 3101 | 3099 | const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) { |
| 3102 | 3100 | .existing => |ty| { |
| 3103 | const new_ty = try pt.ensureTypeUpToDate(ty, false); | |
| 3101 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 3104 | 3102 | |
| 3105 | 3103 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 3106 | 3104 | // up on e.g. changed comptime decls. |
| ... | ... | @@ -3136,16 +3134,14 @@ fn zirEnumDecl( |
| 3136 | 3134 | }); |
| 3137 | 3135 | errdefer if (!done) pt.destroyNamespace(new_namespace_index); |
| 3138 | 3136 | |
| 3139 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 3140 | ||
| 3141 | 3137 | try pt.scanNamespace(new_namespace_index, decls); |
| 3142 | 3138 | |
| 3143 | 3139 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 3144 | 3140 | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 3145 | 3141 | |
| 3146 | 3142 | // 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); | |
| 3149 | 3145 | done = true; |
| 3150 | 3146 | |
| 3151 | 3147 | try Sema.resolveDeclaredEnum( |
| ... | ... | @@ -3155,7 +3151,6 @@ fn zirEnumDecl( |
| 3155 | 3151 | tracked_inst, |
| 3156 | 3152 | new_namespace_index, |
| 3157 | 3153 | type_name, |
| 3158 | new_cau_index, | |
| 3159 | 3154 | small, |
| 3160 | 3155 | body, |
| 3161 | 3156 | tag_type_ref, |
| ... | ... | @@ -3245,7 +3240,7 @@ fn zirUnionDecl( |
| 3245 | 3240 | }; |
| 3246 | 3241 | const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) { |
| 3247 | 3242 | .existing => |ty| { |
| 3248 | const new_ty = try pt.ensureTypeUpToDate(ty, false); | |
| 3243 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 3249 | 3244 | |
| 3250 | 3245 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 3251 | 3246 | // up on e.g. changed comptime decls. |
| ... | ... | @@ -3275,12 +3270,10 @@ fn zirUnionDecl( |
| 3275 | 3270 | }); |
| 3276 | 3271 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3277 | 3272 | |
| 3278 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 3279 | ||
| 3280 | 3273 | if (pt.zcu.comp.incremental) { |
| 3281 | 3274 | try zcu.intern_pool.addDependency( |
| 3282 | 3275 | gpa, |
| 3283 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 3276 | AnalUnit.wrap(.{ .type = wip_ty.index }), | |
| 3284 | 3277 | .{ .src_hash = tracked_inst }, |
| 3285 | 3278 | ); |
| 3286 | 3279 | } |
| ... | ... | @@ -3297,7 +3290,7 @@ fn zirUnionDecl( |
| 3297 | 3290 | } |
| 3298 | 3291 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 3299 | 3292 | 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)); | |
| 3301 | 3294 | } |
| 3302 | 3295 | |
| 3303 | 3296 | fn zirOpaqueDecl( |
| ... | ... | @@ -3382,7 +3375,7 @@ fn zirOpaqueDecl( |
| 3382 | 3375 | try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 3383 | 3376 | } |
| 3384 | 3377 | 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)); | |
| 3386 | 3379 | } |
| 3387 | 3380 | |
| 3388 | 3381 | fn zirErrorSetDecl( |
| ... | ... | @@ -6547,7 +6540,10 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| 6547 | 6540 | const ip = &zcu.intern_pool; |
| 6548 | 6541 | const func = switch (sema.owner.unwrap()) { |
| 6549 | 6542 | .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 | |
| 6551 | 6547 | }; |
| 6552 | 6548 | ip.funcSetDisableInstrumentation(func); |
| 6553 | 6549 | sema.allow_memoize = false; |
| ... | ... | @@ -6868,11 +6864,8 @@ fn lookupInNamespace( |
| 6868 | 6864 | |
| 6869 | 6865 | ignore_self: { |
| 6870 | 6866 | 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, | |
| 6876 | 6869 | }; |
| 6877 | 6870 | var i: usize = 0; |
| 6878 | 6871 | while (i < candidates.items.len) { |
| ... | ... | @@ -7132,7 +7125,7 @@ fn zirCall( |
| 7132 | 7125 | const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); |
| 7133 | 7126 | |
| 7134 | 7127 | switch (sema.owner.unwrap()) { |
| 7135 | .cau => input_is_error = false, | |
| 7128 | .@"comptime", .type, .nav_val => input_is_error = false, | |
| 7136 | 7129 | .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) { |
| 7137 | 7130 | // No errorable fn actually called; we have no error return trace |
| 7138 | 7131 | input_is_error = false; |
| ... | ... | @@ -7747,11 +7740,9 @@ fn analyzeCall( |
| 7747 | 7740 | // The call site definitely depends on the function's signature. |
| 7748 | 7741 | try sema.declareDependency(.{ .src_hash = module_fn.zir_body_inst }); |
| 7749 | 7742 | |
| 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`. | |
| 7752 | 7745 | 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); | |
| 7755 | 7746 | |
| 7756 | 7747 | // We effectively want a child Sema here, but can't literally do that, because we need AIR |
| 7757 | 7748 | // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in |
| ... | ... | @@ -7759,7 +7750,7 @@ fn analyzeCall( |
| 7759 | 7750 | // whenever performing an operation where the difference matters. |
| 7760 | 7751 | var ics = InlineCallSema.init( |
| 7761 | 7752 | sema, |
| 7762 | zcu.cauFileScope(fn_cau_index).zir, | |
| 7753 | zcu.navFileScope(module_fn.owner_nav).zir, | |
| 7763 | 7754 | module_fn_index, |
| 7764 | 7755 | block.error_return_trace_index, |
| 7765 | 7756 | ); |
| ... | ... | @@ -7769,7 +7760,7 @@ fn analyzeCall( |
| 7769 | 7760 | .parent = null, |
| 7770 | 7761 | .sema = sema, |
| 7771 | 7762 | // The function body exists in the same namespace as the corresponding function declaration. |
| 7772 | .namespace = fn_cau.namespace, | |
| 7763 | .namespace = fn_nav.analysis.?.namespace, | |
| 7773 | 7764 | .instructions = .{}, |
| 7774 | 7765 | .label = null, |
| 7775 | 7766 | .inlining = &inlining, |
| ... | ... | @@ -7780,7 +7771,7 @@ fn analyzeCall( |
| 7780 | 7771 | .runtime_cond = block.runtime_cond, |
| 7781 | 7772 | .runtime_loop = block.runtime_loop, |
| 7782 | 7773 | .runtime_index = block.runtime_index, |
| 7783 | .src_base_inst = fn_cau.zir_index, | |
| 7774 | .src_base_inst = fn_nav.analysis.?.zir_index, | |
| 7784 | 7775 | .type_name_ctx = fn_nav.fqn, |
| 7785 | 7776 | }; |
| 7786 | 7777 | |
| ... | ... | @@ -7795,7 +7786,7 @@ fn analyzeCall( |
| 7795 | 7786 | // mutate comptime state. |
| 7796 | 7787 | // TODO: comptime call memoization is currently not supported under incremental compilation |
| 7797 | 7788 | // 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`. | |
| 7799 | 7790 | var should_memoize = !zcu.comp.incremental; |
| 7800 | 7791 | |
| 7801 | 7792 | // If it's a comptime function call, we need to memoize it as long as no external |
| ... | ... | @@ -7904,7 +7895,7 @@ fn analyzeCall( |
| 7904 | 7895 | |
| 7905 | 7896 | // Since we're doing an inline call, we depend on the source code of the whole |
| 7906 | 7897 | // function declaration. |
| 7907 | try sema.declareDependency(.{ .src_hash = fn_cau.zir_index }); | |
| 7898 | try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index }); | |
| 7908 | 7899 | |
| 7909 | 7900 | new_fn_info.return_type = sema.fn_ret_ty.toIntern(); |
| 7910 | 7901 | if (!is_comptime_call and !block.is_typeof) { |
| ... | ... | @@ -8016,7 +8007,7 @@ fn analyzeCall( |
| 8016 | 8007 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 8017 | 8008 | |
| 8018 | 8009 | switch (sema.owner.unwrap()) { |
| 8019 | .cau => {}, | |
| 8010 | .@"comptime", .nav_val, .type => {}, | |
| 8020 | 8011 | .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) { |
| 8021 | 8012 | ip.funcSetCallsOrAwaitsErrorableFn(owner_func); |
| 8022 | 8013 | }, |
| ... | ... | @@ -8268,10 +8259,9 @@ fn instantiateGenericCall( |
| 8268 | 8259 | // The actual monomorphization happens via adding `func_instance` to |
| 8269 | 8260 | // `InternPool`. |
| 8270 | 8261 | |
| 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. | |
| 8272 | 8263 | 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; | |
| 8275 | 8265 | const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip) orelse return error.AnalysisFail); |
| 8276 | 8266 | |
| 8277 | 8267 | const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count()); |
| ... | ... | @@ -8312,11 +8302,11 @@ fn instantiateGenericCall( |
| 8312 | 8302 | var child_block: Block = .{ |
| 8313 | 8303 | .parent = null, |
| 8314 | 8304 | .sema = &child_sema, |
| 8315 | .namespace = fn_cau.namespace, | |
| 8305 | .namespace = fn_nav.analysis.?.namespace, | |
| 8316 | 8306 | .instructions = .{}, |
| 8317 | 8307 | .inlining = null, |
| 8318 | 8308 | .is_comptime = true, |
| 8319 | .src_base_inst = fn_cau.zir_index, | |
| 8309 | .src_base_inst = fn_nav.analysis.?.zir_index, | |
| 8320 | 8310 | .type_name_ctx = fn_nav.fqn, |
| 8321 | 8311 | }; |
| 8322 | 8312 | defer child_block.instructions.deinit(gpa); |
| ... | ... | @@ -8481,7 +8471,7 @@ fn instantiateGenericCall( |
| 8481 | 8471 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 8482 | 8472 | |
| 8483 | 8473 | switch (sema.owner.unwrap()) { |
| 8484 | .cau => {}, | |
| 8474 | .@"comptime", .nav_val, .type => {}, | |
| 8485 | 8475 | .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) { |
| 8486 | 8476 | ip.funcSetCallsOrAwaitsErrorableFn(owner_func); |
| 8487 | 8477 | }, |
| ... | ... | @@ -9510,14 +9500,11 @@ fn zirFunc( |
| 9510 | 9500 | // the callconv based on whether it is exported. Otherwise, the callconv defaults |
| 9511 | 9501 | // to `.auto`. |
| 9512 | 9502 | 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; | |
| 9519 | 9506 | 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; | |
| 9521 | 9508 | const zir_decl = sema.code.getDeclaration(decl_inst); |
| 9522 | 9509 | break :exported zir_decl.linkage == .@"export"; |
| 9523 | 9510 | }; |
| ... | ... | @@ -9991,7 +9978,7 @@ fn funcCommon( |
| 9991 | 9978 | if (!ret_poison) |
| 9992 | 9979 | try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); |
| 9993 | 9980 | const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{ |
| 9994 | .owner_nav = sema.getOwnerCauNav(), | |
| 9981 | .owner_nav = sema.owner.unwrap().nav_val, | |
| 9995 | 9982 | |
| 9996 | 9983 | .param_types = param_types, |
| 9997 | 9984 | .noalias_bits = noalias_bits, |
| ... | ... | @@ -10040,7 +10027,7 @@ fn funcCommon( |
| 10040 | 10027 | |
| 10041 | 10028 | if (has_body) { |
| 10042 | 10029 | const func_index = try ip.getFuncDecl(gpa, pt.tid, .{ |
| 10043 | .owner_nav = sema.getOwnerCauNav(), | |
| 10030 | .owner_nav = sema.owner.unwrap().nav_val, | |
| 10044 | 10031 | .ty = func_ty, |
| 10045 | 10032 | .cc = cc, |
| 10046 | 10033 | .is_noinline = is_noinline, |
| ... | ... | @@ -17664,7 +17651,7 @@ fn zirAsm( |
| 17664 | 17651 | if (is_volatile) { |
| 17665 | 17652 | return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{}); |
| 17666 | 17653 | } |
| 17667 | try zcu.addGlobalAssembly(sema.owner.unwrap().cau, asm_source); | |
| 17654 | try zcu.addGlobalAssembly(sema.owner, asm_source); | |
| 17668 | 17655 | return .void_value; |
| 17669 | 17656 | } |
| 17670 | 17657 | |
| ... | ... | @@ -18155,7 +18142,7 @@ fn zirThis( |
| 18155 | 18142 | _ = extended; |
| 18156 | 18143 | const pt = sema.pt; |
| 18157 | 18144 | 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); | |
| 18159 | 18146 | switch (pt.zcu.intern_pool.indexToKey(new_ty)) { |
| 18160 | 18147 | .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }), |
| 18161 | 18148 | .opaque_type => {}, |
| ... | ... | @@ -19321,10 +19308,8 @@ fn typeInfoNamespaceDecls( |
| 19321 | 19308 | } |
| 19322 | 19309 | |
| 19323 | 19310 | 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; | |
| 19328 | 19313 | } |
| 19329 | 19314 | try sema.ensureNavResolved(src, nav); |
| 19330 | 19315 | const namespace_ty = Type.fromInterned(ip.getNav(nav).status.resolved.val); |
| ... | ... | @@ -21187,14 +21172,13 @@ fn structInitAnon( |
| 21187 | 21172 | .file_scope = block.getFileScopeIndex(zcu), |
| 21188 | 21173 | .generation = zcu.generation, |
| 21189 | 21174 | }); |
| 21190 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip.index); | |
| 21191 | 21175 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip.index }); |
| 21192 | 21176 | codegen_type: { |
| 21193 | 21177 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 21194 | 21178 | if (block.ownerModule().strip) break :codegen_type; |
| 21195 | 21179 | try zcu.comp.queueJob(.{ .codegen_type = wip.index }); |
| 21196 | 21180 | } |
| 21197 | break :ty wip.finish(ip, new_cau_index.toOptional(), new_namespace_index); | |
| 21181 | break :ty wip.finish(ip, new_namespace_index); | |
| 21198 | 21182 | }, |
| 21199 | 21183 | .existing => |ty| ty, |
| 21200 | 21184 | }; |
| ... | ... | @@ -21618,7 +21602,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 21618 | 21602 | .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) { |
| 21619 | 21603 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); |
| 21620 | 21604 | }, |
| 21621 | .cau => {}, | |
| 21605 | .@"comptime", .nav_val, .type => {}, | |
| 21622 | 21606 | } |
| 21623 | 21607 | return Air.internedToRef(try pt.intern(.{ .opt = .{ |
| 21624 | 21608 | .ty = opt_ptr_stack_trace_ty.toIntern(), |
| ... | ... | @@ -22296,7 +22280,7 @@ fn zirReify( |
| 22296 | 22280 | }); |
| 22297 | 22281 | |
| 22298 | 22282 | 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)); | |
| 22300 | 22284 | }, |
| 22301 | 22285 | .@"union" => { |
| 22302 | 22286 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | ... | @@ -22505,11 +22489,9 @@ fn reifyEnum( |
| 22505 | 22489 | .generation = zcu.generation, |
| 22506 | 22490 | }); |
| 22507 | 22491 | |
| 22508 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 22509 | ||
| 22510 | 22492 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 22511 | 22493 | 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); | |
| 22513 | 22495 | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 22514 | 22496 | done = true; |
| 22515 | 22497 | |
| ... | ... | @@ -22811,8 +22793,6 @@ fn reifyUnion( |
| 22811 | 22793 | .generation = zcu.generation, |
| 22812 | 22794 | }); |
| 22813 | 22795 | |
| 22814 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 22815 | ||
| 22816 | 22796 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 22817 | 22797 | codegen_type: { |
| 22818 | 22798 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| ... | ... | @@ -22822,7 +22802,7 @@ fn reifyUnion( |
| 22822 | 22802 | } |
| 22823 | 22803 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 22824 | 22804 | 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)); | |
| 22826 | 22806 | } |
| 22827 | 22807 | |
| 22828 | 22808 | fn reifyTuple( |
| ... | ... | @@ -23170,8 +23150,6 @@ fn reifyStruct( |
| 23170 | 23150 | .generation = zcu.generation, |
| 23171 | 23151 | }); |
| 23172 | 23152 | |
| 23173 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 23174 | ||
| 23175 | 23153 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 23176 | 23154 | codegen_type: { |
| 23177 | 23155 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| ... | ... | @@ -23181,7 +23159,7 @@ fn reifyStruct( |
| 23181 | 23159 | } |
| 23182 | 23160 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 23183 | 23161 | 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)); | |
| 23185 | 23163 | } |
| 23186 | 23164 | |
| 23187 | 23165 | fn 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 |
| 26713 | 26691 | break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val); |
| 26714 | 26692 | } else cc: { |
| 26715 | 26693 | 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: { | |
| 26717 | 26695 | // Generic instance -- use the original function declaration to |
| 26718 | 26696 | // 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); | |
| 26725 | 26701 | if (zir_decl.linkage == .@"export") { |
| 26726 | 26702 | break :cc target.cCallingConvention() orelse { |
| 26727 | 26703 | // This target has no default C calling convention. We sometimes trigger a similar |
| ... | ... | @@ -27108,8 +27084,16 @@ fn zirBuiltinExtern( |
| 27108 | 27084 | // `builtin_extern` doesn't provide enough information, and isn't currently tracked. |
| 27109 | 27085 | // So, for now, just use our containing `declaration`. |
| 27110 | 27086 | .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 | }, | |
| 27113 | 27097 | }, |
| 27114 | 27098 | .owner_nav = undefined, // ignored by `getExtern` |
| 27115 | 27099 | }); |
| ... | ... | @@ -32670,28 +32654,25 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav |
| 32670 | 32654 | const ip = &zcu.intern_pool; |
| 32671 | 32655 | |
| 32672 | 32656 | const nav = ip.getNav(nav_index); |
| 32673 | ||
| 32674 | const cau_index = nav.analysis_owner.unwrap() orelse { | |
| 32657 | if (nav.analysis == null) { | |
| 32675 | 32658 | assert(nav.status == .resolved); |
| 32676 | 32659 | return; |
| 32677 | }; | |
| 32660 | } | |
| 32678 | 32661 | |
| 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` | |
| 32680 | 32663 | // to make sure the value is up-to-date on incremental updates. |
| 32681 | 32664 | |
| 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 }); | |
| 32685 | 32666 | try sema.addReferenceEntry(src, anal_unit); |
| 32686 | 32667 | |
| 32687 | 32668 | if (zcu.analysis_in_progress.contains(anal_unit)) { |
| 32688 | 32669 | 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, | |
| 32690 | 32671 | .offset = LazySrcLoc.Offset.nodeOffset(0), |
| 32691 | 32672 | }, "dependency loop detected", .{})); |
| 32692 | 32673 | } |
| 32693 | 32674 | |
| 32694 | return pt.ensureCauAnalyzed(cau_index); | |
| 32675 | return pt.ensureNavValUpToDate(nav_index); | |
| 32695 | 32676 | } |
| 32696 | 32677 | |
| 32697 | 32678 | fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { |
| ... | ... | @@ -35641,7 +35622,7 @@ pub fn resolveStructAlignment( |
| 35641 | 35622 | const ip = &zcu.intern_pool; |
| 35642 | 35623 | const target = zcu.getTarget(); |
| 35643 | 35624 | |
| 35644 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 35625 | assert(sema.owner.unwrap().type == ty); | |
| 35645 | 35626 | |
| 35646 | 35627 | assert(struct_type.layout != .@"packed"); |
| 35647 | 35628 | assert(struct_type.flagsUnordered(ip).alignment == .none); |
| ... | ... | @@ -35684,7 +35665,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { |
| 35684 | 35665 | const ip = &zcu.intern_pool; |
| 35685 | 35666 | const struct_type = zcu.typeToStruct(ty) orelse return; |
| 35686 | 35667 | |
| 35687 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 35668 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 35688 | 35669 | |
| 35689 | 35670 | if (struct_type.haveLayout(ip)) |
| 35690 | 35671 | return; |
| ... | ... | @@ -35831,15 +35812,13 @@ fn backingIntType( |
| 35831 | 35812 | const gpa = zcu.gpa; |
| 35832 | 35813 | const ip = &zcu.intern_pool; |
| 35833 | 35814 | |
| 35834 | const cau_index = struct_type.cau; | |
| 35835 | ||
| 35836 | 35815 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 35837 | 35816 | defer analysis_arena.deinit(); |
| 35838 | 35817 | |
| 35839 | 35818 | var block: Block = .{ |
| 35840 | 35819 | .parent = null, |
| 35841 | 35820 | .sema = sema, |
| 35842 | .namespace = ip.getCau(cau_index).namespace, | |
| 35821 | .namespace = struct_type.namespace, | |
| 35843 | 35822 | .instructions = .{}, |
| 35844 | 35823 | .inlining = null, |
| 35845 | 35824 | .is_comptime = true, |
| ... | ... | @@ -35971,7 +35950,7 @@ pub fn resolveUnionAlignment( |
| 35971 | 35950 | const ip = &zcu.intern_pool; |
| 35972 | 35951 | const target = zcu.getTarget(); |
| 35973 | 35952 | |
| 35974 | assert(sema.owner.unwrap().cau == union_type.cau); | |
| 35953 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 35975 | 35954 | |
| 35976 | 35955 | assert(!union_type.haveLayout(ip)); |
| 35977 | 35956 | |
| ... | ... | @@ -36011,7 +35990,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { |
| 36011 | 35990 | // Load again, since the tag type might have changed due to resolution. |
| 36012 | 35991 | const union_type = ip.loadUnionType(ty.ip_index); |
| 36013 | 35992 | |
| 36014 | assert(sema.owner.unwrap().cau == union_type.cau); | |
| 35993 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36015 | 35994 | |
| 36016 | 35995 | const old_flags = union_type.flagsUnordered(ip); |
| 36017 | 35996 | switch (old_flags.status) { |
| ... | ... | @@ -36126,7 +36105,7 @@ pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void { |
| 36126 | 36105 | const ip = &zcu.intern_pool; |
| 36127 | 36106 | const struct_type = zcu.typeToStruct(ty).?; |
| 36128 | 36107 | |
| 36129 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 36108 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36130 | 36109 | |
| 36131 | 36110 | if (struct_type.setFullyResolved(ip)) return; |
| 36132 | 36111 | errdefer struct_type.clearFullyResolved(ip); |
| ... | ... | @@ -36149,7 +36128,7 @@ pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void { |
| 36149 | 36128 | const ip = &zcu.intern_pool; |
| 36150 | 36129 | const union_obj = zcu.typeToUnion(ty).?; |
| 36151 | 36130 | |
| 36152 | assert(sema.owner.unwrap().cau == union_obj.cau); | |
| 36131 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36153 | 36132 | |
| 36154 | 36133 | switch (union_obj.flagsUnordered(ip).status) { |
| 36155 | 36134 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, |
| ... | ... | @@ -36184,7 +36163,7 @@ pub fn resolveStructFieldTypes( |
| 36184 | 36163 | const zcu = pt.zcu; |
| 36185 | 36164 | const ip = &zcu.intern_pool; |
| 36186 | 36165 | |
| 36187 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 36166 | assert(sema.owner.unwrap().type == ty); | |
| 36188 | 36167 | |
| 36189 | 36168 | if (struct_type.haveFieldTypes(ip)) return; |
| 36190 | 36169 | |
| ... | ... | @@ -36210,7 +36189,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { |
| 36210 | 36189 | const ip = &zcu.intern_pool; |
| 36211 | 36190 | const struct_type = zcu.typeToStruct(ty) orelse return; |
| 36212 | 36191 | |
| 36213 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 36192 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36214 | 36193 | |
| 36215 | 36194 | // Inits can start as resolved |
| 36216 | 36195 | if (struct_type.haveFieldInits(ip)) return; |
| ... | ... | @@ -36239,7 +36218,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load |
| 36239 | 36218 | const zcu = pt.zcu; |
| 36240 | 36219 | const ip = &zcu.intern_pool; |
| 36241 | 36220 | |
| 36242 | assert(sema.owner.unwrap().cau == union_type.cau); | |
| 36221 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36243 | 36222 | |
| 36244 | 36223 | switch (union_type.flagsUnordered(ip).status) { |
| 36245 | 36224 | .none => {}, |
| ... | ... | @@ -36315,7 +36294,7 @@ fn resolveInferredErrorSet( |
| 36315 | 36294 | // In this case we are dealing with the actual InferredErrorSet object that |
| 36316 | 36295 | // corresponds to the function, not one created to track an inline/comptime call. |
| 36317 | 36296 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index })); |
| 36318 | try pt.ensureFuncBodyAnalyzed(func_index); | |
| 36297 | try pt.ensureFuncBodyUpToDate(func_index); | |
| 36319 | 36298 | } |
| 36320 | 36299 | |
| 36321 | 36300 | // This will now have been resolved by the logic at the end of `Zcu.analyzeFnBody` |
| ... | ... | @@ -36472,8 +36451,7 @@ fn structFields( |
| 36472 | 36451 | const zcu = pt.zcu; |
| 36473 | 36452 | const gpa = zcu.gpa; |
| 36474 | 36453 | 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; | |
| 36477 | 36455 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; |
| 36478 | 36456 | const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail; |
| 36479 | 36457 | |
| ... | ... | @@ -36671,8 +36649,7 @@ fn structFieldInits( |
| 36671 | 36649 | |
| 36672 | 36650 | assert(!struct_type.haveFieldInits(ip)); |
| 36673 | 36651 | |
| 36674 | const cau_index = struct_type.cau; | |
| 36675 | const namespace_index = ip.getCau(cau_index).namespace; | |
| 36652 | const namespace_index = struct_type.namespace; | |
| 36676 | 36653 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; |
| 36677 | 36654 | const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail; |
| 36678 | 36655 | const fields_len, _, var extra_index = structZirInfo(zir, zir_index); |
| ... | ... | @@ -38474,13 +38451,11 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { |
| 38474 | 38451 | // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve |
| 38475 | 38452 | // the loop. |
| 38476 | 38453 | 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, | |
| 38481 | 38456 | else => {}, |
| 38482 | 38457 | }, |
| 38483 | .func => {}, | |
| 38458 | else => {}, | |
| 38484 | 38459 | } |
| 38485 | 38460 | |
| 38486 | 38461 | try zcu.intern_pool.addDependency(sema.gpa, sema.owner, dependee); |
| ... | ... | @@ -38659,38 +38634,6 @@ pub fn flushExports(sema: *Sema) !void { |
| 38659 | 38634 | } |
| 38660 | 38635 | } |
| 38661 | 38636 | |
| 38662 | /// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches | |
| 38663 | /// the corresponding `Nav`. | |
| 38664 | fn 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. | |
| 38671 | fn 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. | |
| 38680 | fn 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 | ||
| 38694 | 38637 | /// Called as soon as a `declared` enum type is created. |
| 38695 | 38638 | /// Resolves the tag type and field inits. |
| 38696 | 38639 | /// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this. |
| ... | ... | @@ -38701,7 +38644,6 @@ pub fn resolveDeclaredEnum( |
| 38701 | 38644 | tracked_inst: InternPool.TrackedInst.Index, |
| 38702 | 38645 | namespace: InternPool.NamespaceIndex, |
| 38703 | 38646 | type_name: InternPool.NullTerminatedString, |
| 38704 | enum_cau: InternPool.Cau.Index, | |
| 38705 | 38647 | small: Zir.Inst.EnumDecl.Small, |
| 38706 | 38648 | body: []const Zir.Inst.Index, |
| 38707 | 38649 | tag_type_ref: Zir.Inst.Ref, |
| ... | ... | @@ -38719,7 +38661,7 @@ pub fn resolveDeclaredEnum( |
| 38719 | 38661 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; |
| 38720 | 38662 | const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } }; |
| 38721 | 38663 | |
| 38722 | const anal_unit = AnalUnit.wrap(.{ .cau = enum_cau }); | |
| 38664 | const anal_unit = AnalUnit.wrap(.{ .type = wip_ty.index }); | |
| 38723 | 38665 | |
| 38724 | 38666 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 38725 | 38667 | defer arena.deinit(); |
| ... | ... | @@ -38943,6 +38885,6 @@ fn getBuiltin(sema: *Sema, name: []const u8) SemaError!Air.Inst.Ref { |
| 38943 | 38885 | const zcu = pt.zcu; |
| 38944 | 38886 | const ip = &zcu.intern_pool; |
| 38945 | 38887 | const nav = try pt.getBuiltinNav(name); |
| 38946 | try pt.ensureCauAnalyzed(ip.getNav(nav).analysis_owner.unwrap().?); | |
| 38888 | try pt.ensureNavValUpToDate(nav); | |
| 38947 | 38889 | return Air.internedToRef(ip.getNav(nav).status.resolved.val); |
| 38948 | 38890 | } |
src/Type.zig+2-2| ... | ... | @@ -3851,7 +3851,7 @@ fn resolveStructInner( |
| 3851 | 3851 | const gpa = zcu.gpa; |
| 3852 | 3852 | |
| 3853 | 3853 | 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() }); | |
| 3855 | 3855 | |
| 3856 | 3856 | if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) { |
| 3857 | 3857 | return error.AnalysisFail; |
| ... | ... | @@ -3905,7 +3905,7 @@ fn resolveUnionInner( |
| 3905 | 3905 | const gpa = zcu.gpa; |
| 3906 | 3906 | |
| 3907 | 3907 | 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() }); | |
| 3909 | 3909 | |
| 3910 | 3910 | if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) { |
| 3911 | 3911 | return error.AnalysisFail; |
src/Zcu.zig+86-96| ... | ... | @@ -192,7 +192,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .empty, |
| 192 | 192 | |
| 193 | 193 | test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, |
| 194 | 194 | |
| 195 | global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .empty, | |
| 195 | global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty, | |
| 196 | 196 | |
| 197 | 197 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 198 | 198 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| ... | ... | @@ -344,9 +344,12 @@ pub const Namespace = struct { |
| 344 | 344 | pub_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty, |
| 345 | 345 | /// All `usingnamespace` declarations in this namespace which are *not* marked `pub`. |
| 346 | 346 | 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, | |
| 350 | 353 | |
| 351 | 354 | pub const Index = InternPool.NamespaceIndex; |
| 352 | 355 | pub const OptionalIndex = InternPool.OptionalNamespaceIndex; |
| ... | ... | @@ -2436,11 +2439,9 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2436 | 2439 | // If this is a Decl, we must recursively mark dependencies on its tyval |
| 2437 | 2440 | // as no longer PO. |
| 2438 | 2441 | 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 }), | |
| 2444 | 2445 | .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }), |
| 2445 | 2446 | } |
| 2446 | 2447 | } |
| ... | ... | @@ -2451,11 +2452,9 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2451 | 2452 | fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void { |
| 2452 | 2453 | const ip = &zcu.intern_pool; |
| 2453 | 2454 | 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 }, | |
| 2459 | 2458 | .func => |func_index| .{ .interned = func_index }, // IES |
| 2460 | 2459 | }; |
| 2461 | 2460 | log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)}); |
| ... | ... | @@ -2512,14 +2511,14 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2512 | 2511 | } |
| 2513 | 2512 | |
| 2514 | 2513 | // 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! | |
| 2519 | 2518 | |
| 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 | |
| 2521 | 2520 | // 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 | |
| 2523 | 2522 | // which the most things depend on - the idea is that this will resolve a lot of loops (but this |
| 2524 | 2523 | // is only a heuristic). |
| 2525 | 2524 | |
| ... | ... | @@ -2530,33 +2529,28 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2530 | 2529 | |
| 2531 | 2530 | const ip = &zcu.intern_pool; |
| 2532 | 2531 | |
| 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; | |
| 2535 | 2534 | |
| 2536 | 2535 | inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| { |
| 2537 | 2536 | 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 | ||
| 2544 | 2537 | 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 | |
| 2547 | 2541 | .type => |ty| .{ .interned = ty }, |
| 2548 | .nav => |nav| .{ .nav_val = nav }, | |
| 2542 | .nav_val => |nav| .{ .nav_val = nav }, | |
| 2549 | 2543 | }); |
| 2550 | 2544 | while (it.next()) |_| n += 1; |
| 2551 | 2545 | |
| 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; | |
| 2555 | 2549 | } |
| 2556 | 2550 | } |
| 2557 | 2551 | } |
| 2558 | 2552 | |
| 2559 | if (chosen_cau == null) { | |
| 2553 | if (chosen_unit == null) { | |
| 2560 | 2554 | for (zcu.outdated.keys(), zcu.outdated.values()) |o, opod| { |
| 2561 | 2555 | const func = o.unwrap().func; |
| 2562 | 2556 | const nav = zcu.funcInfo(func).owner_nav; |
| ... | ... | @@ -2570,11 +2564,11 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2570 | 2564 | } |
| 2571 | 2565 | |
| 2572 | 2566 | 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, | |
| 2575 | 2569 | }); |
| 2576 | 2570 | |
| 2577 | return AnalUnit.wrap(.{ .cau = chosen_cau.? }); | |
| 2571 | return chosen_unit.?; | |
| 2578 | 2572 | } |
| 2579 | 2573 | |
| 2580 | 2574 | /// During an incremental update, before semantic analysis, call this to flush all values from |
| ... | ... | @@ -3019,9 +3013,9 @@ pub fn handleUpdateExports( |
| 3019 | 3013 | }; |
| 3020 | 3014 | } |
| 3021 | 3015 | |
| 3022 | pub fn addGlobalAssembly(zcu: *Zcu, cau: InternPool.Cau.Index, source: []const u8) !void { | |
| 3016 | pub fn addGlobalAssembly(zcu: *Zcu, unit: AnalUnit, source: []const u8) !void { | |
| 3023 | 3017 | const gpa = zcu.gpa; |
| 3024 | const gop = try zcu.global_assembly.getOrPut(gpa, cau); | |
| 3018 | const gop = try zcu.global_assembly.getOrPut(gpa, unit); | |
| 3025 | 3019 | if (gop.found_existing) { |
| 3026 | 3020 | const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source }); |
| 3027 | 3021 | gpa.free(gop.value_ptr.*); |
| ... | ... | @@ -3304,23 +3298,22 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3304 | 3298 | |
| 3305 | 3299 | log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); |
| 3306 | 3300 | |
| 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, | |
| 3313 | 3306 | else => unreachable, |
| 3314 | 3307 | }; |
| 3315 | if (resolution_cau.unwrap()) |cau| { | |
| 3308 | if (has_resolution) { | |
| 3316 | 3309 | // this should only be referenced by the type |
| 3317 | const unit = AnalUnit.wrap(.{ .cau = cau }); | |
| 3310 | const unit: AnalUnit = .wrap(.{ .type = ty }); | |
| 3318 | 3311 | assert(!result.contains(unit)); |
| 3319 | 3312 | try unit_queue.putNoClobber(gpa, unit, referencer); |
| 3320 | 3313 | } |
| 3321 | 3314 | |
| 3322 | 3315 | // 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. | |
| 3324 | 3317 | if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| { |
| 3325 | 3318 | const tag_ty = union_obj.enum_tag_ty; |
| 3326 | 3319 | if (tag_ty != .none) { |
| ... | ... | @@ -3335,24 +3328,35 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3335 | 3328 | // Queue any decls within this type which would be automatically analyzed. |
| 3336 | 3329 | // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`. |
| 3337 | 3330 | 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; | |
| 3342 | 3346 | const file = zcu.fileByIndex(inst_info.file); |
| 3343 | 3347 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. |
| 3344 | 3348 | const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*; |
| 3345 | 3349 | const decl = zir.getDeclaration(inst_info.inst); |
| 3350 | ||
| 3351 | if (!comp.config.is_test or file.mod != zcu.main_mod) continue; | |
| 3352 | ||
| 3346 | 3353 | const want_analysis = switch (decl.kind) { |
| 3347 | 3354 | .@"usingnamespace" => unreachable, |
| 3348 | 3355 | .@"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, | |
| 3351 | 3358 | .@"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); | |
| 3356 | 3360 | for (comp.test_filters) |test_filter| { |
| 3357 | 3361 | if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break; |
| 3358 | 3362 | } else break :a false; |
| ... | ... | @@ -3360,28 +3364,25 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3360 | 3364 | }, |
| 3361 | 3365 | }; |
| 3362 | 3366 | 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); | |
| 3371 | 3373 | } |
| 3372 | 3374 | } |
| 3373 | 3375 | for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| { |
| 3374 | 3376 | // 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; | |
| 3377 | 3378 | const file = zcu.fileByIndex(inst_info.file); |
| 3378 | 3379 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. |
| 3379 | 3380 | const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*; |
| 3380 | 3381 | const decl = zir.getDeclaration(inst_info.inst); |
| 3381 | 3382 | if (decl.linkage == .@"export") { |
| 3382 | const unit = AnalUnit.wrap(.{ .cau = cau }); | |
| 3383 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); | |
| 3383 | 3384 | if (!result.contains(unit)) { |
| 3384 | log.debug("type '{}': ref cau %{}", .{ | |
| 3385 | log.debug("type '{}': ref named %{}", .{ | |
| 3385 | 3386 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 3386 | 3387 | @intFromEnum(inst_info.inst), |
| 3387 | 3388 | }); |
| ... | ... | @@ -3391,16 +3392,15 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3391 | 3392 | } |
| 3392 | 3393 | for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| { |
| 3393 | 3394 | // 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; | |
| 3396 | 3396 | const file = zcu.fileByIndex(inst_info.file); |
| 3397 | 3397 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. |
| 3398 | 3398 | const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*; |
| 3399 | 3399 | const decl = zir.getDeclaration(inst_info.inst); |
| 3400 | 3400 | if (decl.linkage == .@"export") { |
| 3401 | const unit = AnalUnit.wrap(.{ .cau = cau }); | |
| 3401 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); | |
| 3402 | 3402 | if (!result.contains(unit)) { |
| 3403 | log.debug("type '{}': ref cau %{}", .{ | |
| 3403 | log.debug("type '{}': ref named %{}", .{ | |
| 3404 | 3404 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 3405 | 3405 | @intFromEnum(inst_info.inst), |
| 3406 | 3406 | }); |
| ... | ... | @@ -3411,13 +3411,11 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3411 | 3411 | // Incremental compilation does not support `usingnamespace`. |
| 3412 | 3412 | // These are only included to keep good reference traces in non-incremental updates. |
| 3413 | 3413 | 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 }); | |
| 3416 | 3415 | if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer); |
| 3417 | 3416 | } |
| 3418 | 3417 | 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 }); | |
| 3421 | 3419 | if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer); |
| 3422 | 3420 | } |
| 3423 | 3421 | continue; |
| ... | ... | @@ -3527,12 +3525,6 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { |
| 3527 | 3525 | return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); |
| 3528 | 3526 | } |
| 3529 | 3527 | |
| 3530 | pub 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 | ||
| 3536 | 3528 | pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) { |
| 3537 | 3529 | return .{ .data = .{ .unit = unit, .zcu = zcu } }; |
| 3538 | 3530 | } |
| ... | ... | @@ -3545,19 +3537,17 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co |
| 3545 | 3537 | const zcu = data.zcu; |
| 3546 | 3538 | const ip = &zcu.intern_pool; |
| 3547 | 3539 | 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>)"); | |
| 3559 | 3547 | } |
| 3560 | 3548 | }, |
| 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)}), | |
| 3561 | 3551 | .func => |func| { |
| 3562 | 3552 | const nav = zcu.funcInfo(func).owner_nav; |
| 3563 | 3553 | 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 { |
| 545 | 545 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 546 | 546 | const file_root_type = pt.zcu.fileRootType(file_index); |
| 547 | 547 | if (file_root_type != .none) { |
| 548 | _ = try pt.ensureTypeUpToDate(file_root_type, false); | |
| 548 | _ = try pt.ensureTypeUpToDate(file_root_type); | |
| 549 | 549 | } else { |
| 550 | 550 | return pt.semaFile(file_index); |
| 551 | 551 | } |
| 552 | 552 | } |
| 553 | 553 | |
| 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. | |
| 557 | pub 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. | |
| 557 | pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void { | |
| 558 | 558 | const tracy = trace(@src()); |
| 559 | 559 | defer tracy.end(); |
| 560 | 560 | |
| 561 | 561 | const zcu = pt.zcu; |
| 562 | 562 | const gpa = zcu.gpa; |
| 563 | const ip = &zcu.intern_pool; | |
| 564 | 563 | |
| 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 }); | |
| 567 | 565 | |
| 568 | log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 566 | log.debug("ensureComptimeUnitUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 569 | 567 | |
| 570 | 568 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 571 | 569 | |
| 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`. | |
| 581 | 578 | |
| 582 | const cau_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 579 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 583 | 580 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 584 | 581 | |
| 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) { | |
| 588 | 583 | _ = 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); | |
| 602 | 592 | } |
| 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; | |
| 603 | 598 | } |
| 604 | 599 | |
| 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 => { | |
| 614 | 605 | 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`. | |
| 616 | 607 | // Since it does not, this must be a transitive failure. |
| 617 | 608 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); |
| 618 | 609 | log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 619 | 610 | } |
| 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; | |
| 631 | 612 | }, |
| 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; | |
| 647 | 621 | }, |
| 622 | error.GenericPoison => unreachable, | |
| 623 | error.ComptimeReturn => unreachable, | |
| 624 | error.ComptimeBreak => unreachable, | |
| 648 | 625 | }; |
| 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; | |
| 672 | 626 | } |
| 673 | 627 | |
| 674 | fn 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. | |
| 632 | fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void { | |
| 679 | 633 | const zcu = pt.zcu; |
| 634 | const gpa = zcu.gpa; | |
| 680 | 635 | const ip = &zcu.intern_pool; |
| 681 | 636 | |
| 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 | } | |
| 684 | 708 | |
| 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. | |
| 712 | pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void { | |
| 713 | const tracy = trace(@src()); | |
| 714 | defer tracy.end(); | |
| 686 | 715 | |
| 687 | 716 | // TODO: document this elsewhere mlugg! |
| 688 | 717 | // For my own benefit, here's how a namespace update for a normal (non-file-root) type works: |
| ... | ... | @@ -692,821 +721,826 @@ fn ensureCauAnalyzedInner( |
| 692 | 721 | // * Any change to the `struct` body -- including changing a declaration -- invalidates this |
| 693 | 722 | // * `S` is re-analyzed, but notes: |
| 694 | 723 | // * 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) | |
| 696 | 725 | // * so, it uses the same `struct` |
| 697 | 726 | // * but this doesn't stop it from updating the namespace! |
| 698 | 727 | // * we basically do `scanDecls`, updating the namespace as needed |
| 699 | 728 | // * so everyone lived happily ever after |
| 700 | 729 | |
| 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 | ||
| 731 | pub 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 | ||
| 737 | 730 | const zcu = pt.zcu; |
| 738 | 731 | const gpa = zcu.gpa; |
| 739 | 732 | const ip = &zcu.intern_pool; |
| 740 | 733 | |
| 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); | |
| 744 | 736 | |
| 745 | log.debug("ensureFuncBodyAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 737 | log.debug("ensureNavUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 746 | 738 | |
| 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`. | |
| 748 | 747 | |
| 749 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 748 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 750 | 749 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 751 | 750 | |
| 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); | |
| 753 | 753 | |
| 754 | if (func_outdated) { | |
| 754 | if (was_outdated) { | |
| 755 | dev.check(.incremental); | |
| 755 | 756 | _ = 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); | |
| 765 | 761 | } |
| 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; | |
| 766 | 767 | } |
| 767 | 768 | |
| 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) { | |
| 771 | 782 | error.AnalysisFail => res: { |
| 772 | 783 | 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`. | |
| 774 | 785 | // Since it does not, this must be a transitive failure. |
| 775 | 786 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); |
| 776 | 787 | log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 777 | 788 | } |
| 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 }; | |
| 782 | 793 | }, |
| 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, | |
| 784 | 806 | }; |
| 785 | 807 | |
| 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); | |
| 789 | 817 | } 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); | |
| 791 | 821 | } |
| 792 | 822 | } |
| 793 | 823 | |
| 794 | if (analysis_fail) return error.AnalysisFail; | |
| 824 | if (new_failed) return error.AnalysisFail; | |
| 795 | 825 | } |
| 796 | 826 | |
| 797 | fn ensureFuncBodyAnalyzedInner( | |
| 798 | pt: Zcu.PerThread, | |
| 799 | func_index: InternPool.Index, | |
| 800 | func_outdated: bool, | |
| 801 | ) Zcu.SemaError!struct { ies_outdated: bool } { | |
| 827 | const 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 | ||
| 834 | fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!SemaNavResult { | |
| 802 | 835 | const zcu = pt.zcu; |
| 803 | 836 | const gpa = zcu.gpa; |
| 804 | 837 | const ip = &zcu.intern_pool; |
| 805 | 838 | |
| 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); | |
| 808 | 841 | |
| 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)}); | |
| 812 | 843 | |
| 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; | |
| 831 | 851 | |
| 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); | |
| 838 | 854 | |
| 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); | |
| 848 | 857 | |
| 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(); | |
| 860 | 860 | |
| 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(); | |
| 865 | 863 | |
| 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(); | |
| 868 | 877 | |
| 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 }); | |
| 871 | 880 | |
| 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); | |
| 873 | 892 | |
| 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); | |
| 876 | 894 | |
| 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")); | |
| 881 | 896 | |
| 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 }); | |
| 887 | 902 | |
| 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. | |
| 890 | 905 | |
| 891 | /// Takes ownership of `air`, even on error. | |
| 892 | /// If any types referenced by `air` are unresolved, marks the codegen as failed. | |
| 893 | pub 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 | }; | |
| 898 | 918 | |
| 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 | ), | |
| 902 | 930 | } |
| 903 | 931 | |
| 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. | |
| 910 | 934 | |
| 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 | }; | |
| 916 | 940 | |
| 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 | }; | |
| 925 | 954 | |
| 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, | |
| 936 | 961 | }, |
| 937 | 962 | }; |
| 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 => {}, | |
| 938 | 1028 | } |
| 939 | 1029 | |
| 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); | |
| 942 | 1033 | |
| 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, | |
| 969 | 1053 | }; |
| 970 | 1054 | } |
| 971 | } | |
| 972 | 1055 | |
| 973 | /// https://github.com/ziglang/zig/issues/14307 | |
| 974 | pub 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 | }; | |
| 982 | 1065 | |
| 983 | fn 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 | } | |
| 1012 | 1087 | |
| 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", | |
| 1016 | 1093 | }); |
| 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); | |
| 1039 | 1094 | |
| 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)); | |
| 1047 | 1097 | |
| 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); | |
| 1055 | 1103 | } |
| 1056 | zcu.setFileRootType(file_index, wip_ty.index); | |
| 1057 | return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index); | |
| 1058 | } | |
| 1059 | 1104 | |
| 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. | |
| 1065 | fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void { | |
| 1066 | const zcu = pt.zcu; | |
| 1105 | try sema.flushExports(); | |
| 1067 | 1106 | |
| 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; | |
| 1072 | 1109 | |
| 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 | } | |
| 1077 | 1114 | |
| 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 | } | |
| 1082 | 1118 | |
| 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 | } | |
| 1094 | 1135 | } |
| 1095 | 1136 | |
| 1096 | fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | |
| 1137 | pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void { | |
| 1138 | dev.check(.sema); | |
| 1139 | ||
| 1097 | 1140 | const tracy = trace(@src()); |
| 1098 | 1141 | defer tracy.end(); |
| 1099 | 1142 | |
| 1100 | 1143 | const zcu = pt.zcu; |
| 1101 | 1144 | const gpa = zcu.gpa; |
| 1102 | const file = zcu.fileByIndex(file_index); | |
| 1103 | assert(zcu.fileRootType(file_index) == .none); | |
| 1145 | const ip = &zcu.intern_pool; | |
| 1104 | 1146 | |
| 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 }); | |
| 1109 | 1150 | |
| 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)}); | |
| 1118 | 1152 | |
| 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); | |
| 1125 | 1154 | |
| 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); | |
| 1135 | 1157 | |
| 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 }; | |
| 1145 | 1198 | }, |
| 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 | } | |
| 1147 | 1216 | } |
| 1148 | } | |
| 1149 | 1217 | |
| 1150 | const 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 | } | |
| 1156 | 1220 | |
| 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. | |
| 1161 | fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult { | |
| 1221 | fn analyzeFuncBody( | |
| 1222 | pt: Zcu.PerThread, | |
| 1223 | func_index: InternPool.Index, | |
| 1224 | ) Zcu.SemaError!struct { ies_outdated: bool } { | |
| 1162 | 1225 | const zcu = pt.zcu; |
| 1163 | 1226 | const gpa = zcu.gpa; |
| 1164 | 1227 | const ip = &zcu.intern_pool; |
| 1165 | 1228 | |
| 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 }); | |
| 1176 | 1231 | |
| 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. | |
| 1179 | 1235 | |
| 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 | } | |
| 1194 | 1253 | } |
| 1195 | 1254 | |
| 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; | |
| 1200 | 1261 | |
| 1201 | log.debug("semaCau {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1262 | log.debug("analyze and generate fn body {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1202 | 1263 | |
| 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); | |
| 1205 | 1266 | |
| 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; | |
| 1208 | 1269 | |
| 1209 | var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa); | |
| 1210 | defer comptime_err_ret_trace.deinit(); | |
| 1270 | const comp = zcu.comp; | |
| 1211 | 1271 | |
| 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); | |
| 1225 | 1274 | |
| 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 | } | |
| 1228 | 1279 | |
| 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 | } }); | |
| 1246 | 1285 | |
| 1247 | const zir_decl = zir.getDeclaration(inst_info.inst); | |
| 1286 | return .{ .ies_outdated = ies_outdated }; | |
| 1287 | } | |
| 1248 | 1288 | |
| 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. | |
| 1291 | pub 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; | |
| 1256 | 1296 | |
| 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 | } | |
| 1262 | 1301 | |
| 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); | |
| 1265 | 1305 | |
| 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); | |
| 1278 | 1308 | |
| 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)}); | |
| 1290 | 1313 | } |
| 1291 | 1314 | |
| 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(); | |
| 1294 | 1323 | |
| 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 | } | |
| 1300 | 1337 | |
| 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(); | |
| 1314 | 1340 | |
| 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 })); | |
| 1321 | 1362 | }, |
| 1322 | 1363 | }; |
| 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, | |
| 1329 | 1367 | }; |
| 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 | } | |
| 1343 | 1370 | |
| 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 | |
| 1372 | pub 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 | } | |
| 1347 | 1380 | |
| 1348 | // TODO: missing validation? | |
| 1381 | fn 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; | |
| 1349 | 1410 | |
| 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, | |
| 1384 | 1431 | }; |
| 1432 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 1385 | 1433 | |
| 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; | |
| 1400 | 1436 | |
| 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 | ); | |
| 1405 | 1443 | } |
| 1406 | 1444 | |
| 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 }); | |
| 1431 | 1452 | } |
| 1453 | zcu.setFileRootType(file_index, wip_ty.index); | |
| 1454 | return wip_ty.finish(ip, namespace_index); | |
| 1455 | } | |
| 1432 | 1456 | |
| 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. | |
| 1462 | fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void { | |
| 1463 | const zcu = pt.zcu; | |
| 1441 | 1464 | |
| 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; | |
| 1463 | 1469 | |
| 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, | |
| 1469 | 1473 | }); |
| 1470 | 1474 | |
| 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); | |
| 1480 | 1479 | |
| 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 | } | |
| 1482 | 1492 | |
| 1483 | queue_codegen: { | |
| 1484 | if (!queue_linker_work) break :queue_codegen; | |
| 1493 | fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | |
| 1494 | const tracy = trace(@src()); | |
| 1495 | defer tracy.end(); | |
| 1485 | 1496 | |
| 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); | |
| 1490 | 1501 | |
| 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; | |
| 1493 | 1504 | } |
| 1505 | assert(file.zir_loaded); | |
| 1494 | 1506 | |
| 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 | }, | |
| 1508 | 1541 | }; |
| 1509 | 1542 | }, |
| 1543 | .incremental => {}, | |
| 1510 | 1544 | } |
| 1511 | 1545 | } |
| 1512 | 1546 | |
| ... | ... | @@ -1880,45 +1914,42 @@ pub fn scanNamespace( |
| 1880 | 1914 | |
| 1881 | 1915 | // For incremental updates, `scanDecl` wants to look up existing decls by their ZIR index rather |
| 1882 | 1916 | // 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; | |
| 1885 | 1919 | defer existing_by_inst.deinit(gpa); |
| 1886 | 1920 | |
| 1887 | 1921 | try existing_by_inst.ensureTotalCapacity(gpa, @intCast( |
| 1888 | 1922 | namespace.pub_decls.count() + namespace.priv_decls.count() + |
| 1889 | 1923 | 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, | |
| 1891 | 1926 | )); |
| 1892 | 1927 | |
| 1893 | 1928 | 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 })); | |
| 1897 | 1931 | } |
| 1898 | 1932 | 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 })); | |
| 1902 | 1935 | } |
| 1903 | 1936 | 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 })); | |
| 1907 | 1939 | } |
| 1908 | 1940 | 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); | |
| 1922 | 1953 | } |
| 1923 | 1954 | |
| 1924 | 1955 | var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty; |
| ... | ... | @@ -1928,7 +1959,8 @@ pub fn scanNamespace( |
| 1928 | 1959 | namespace.priv_decls.clearRetainingCapacity(); |
| 1929 | 1960 | namespace.pub_usingnamespace.clearRetainingCapacity(); |
| 1930 | 1961 | namespace.priv_usingnamespace.clearRetainingCapacity(); |
| 1931 | namespace.other_decls.clearRetainingCapacity(); | |
| 1962 | namespace.comptime_decls.clearRetainingCapacity(); | |
| 1963 | namespace.test_decls.clearRetainingCapacity(); | |
| 1932 | 1964 | |
| 1933 | 1965 | var scan_decl_iter: ScanDeclIter = .{ |
| 1934 | 1966 | .pt = pt, |
| ... | ... | @@ -1950,7 +1982,7 @@ const ScanDeclIter = struct { |
| 1950 | 1982 | pt: Zcu.PerThread, |
| 1951 | 1983 | namespace_index: Zcu.Namespace.Index, |
| 1952 | 1984 | 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), | |
| 1954 | 1986 | /// Decl scanning is run in two passes, so that we can detect when a generated |
| 1955 | 1987 | /// name would clash with an explicit name and use a different one. |
| 1956 | 1988 | pass: enum { named, unnamed }, |
| ... | ... | @@ -1988,48 +2020,30 @@ const ScanDeclIter = struct { |
| 1988 | 2020 | |
| 1989 | 2021 | const decl = zir.getDeclaration(decl_inst); |
| 1990 | 2022 | |
| 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: { | |
| 1995 | 2025 | if (iter.pass != .unnamed) return; |
| 1996 | break :info .{ | |
| 1997 | .none, | |
| 1998 | .@"comptime", | |
| 1999 | false, | |
| 2000 | }; | |
| 2026 | break :name .none; | |
| 2001 | 2027 | }, |
| 2002 | .@"usingnamespace" => info: { | |
| 2028 | .@"usingnamespace" => name: { | |
| 2003 | 2029 | if (iter.pass != .unnamed) return; |
| 2004 | 2030 | const i = iter.usingnamespace_index; |
| 2005 | 2031 | 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(); | |
| 2011 | 2033 | }, |
| 2012 | .unnamed_test => info: { | |
| 2034 | .unnamed_test => name: { | |
| 2013 | 2035 | if (iter.pass != .unnamed) return; |
| 2014 | 2036 | const i = iter.unnamed_test_index; |
| 2015 | 2037 | 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(); | |
| 2021 | 2039 | }, |
| 2022 | .@"test", .decltest => |kind| info: { | |
| 2040 | .@"test", .decltest => |kind| name: { | |
| 2023 | 2041 | // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary. |
| 2024 | 2042 | if (iter.pass != .unnamed) return; |
| 2025 | 2043 | 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(); | |
| 2031 | 2045 | }, |
| 2032 | .@"const", .@"var" => info: { | |
| 2046 | .@"const", .@"var" => name: { | |
| 2033 | 2047 | if (iter.pass != .named) return; |
| 2034 | 2048 | const name = try ip.getOrPutString( |
| 2035 | 2049 | gpa, |
| ... | ... | @@ -2038,11 +2052,7 @@ const ScanDeclIter = struct { |
| 2038 | 2052 | .no_embedded_nulls, |
| 2039 | 2053 | ); |
| 2040 | 2054 | try iter.seen_decls.putNoClobber(gpa, name, {}); |
| 2041 | break :info .{ | |
| 2042 | name.toOptional(), | |
| 2043 | .named, | |
| 2044 | false, | |
| 2045 | }; | |
| 2055 | break :name name.toOptional(); | |
| 2046 | 2056 | }, |
| 2047 | 2057 | }; |
| 2048 | 2058 | |
| ... | ... | @@ -2051,46 +2061,44 @@ const ScanDeclIter = struct { |
| 2051 | 2061 | .inst = decl_inst, |
| 2052 | 2062 | }); |
| 2053 | 2063 | |
| 2054 | const existing_cau = iter.existing_by_inst.get(tracked_inst); | |
| 2064 | const existing_unit = iter.existing_by_inst.get(tracked_inst); | |
| 2055 | 2065 | |
| 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); | |
| 2059 | 2072 | |
| 2060 | try namespace.other_decls.append(gpa, cau); | |
| 2073 | const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); | |
| 2061 | 2074 | |
| 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, {}); | |
| 2079 | 2084 | } |
| 2080 | 2085 | |
| 2081 | break :cau .{ cau, true }; | |
| 2086 | break :unit .{ unit, true }; | |
| 2082 | 2087 | }, |
| 2083 | else => cau: { | |
| 2088 | else => unit: { | |
| 2084 | 2089 | const name = maybe_name.unwrap().?; |
| 2085 | 2090 | 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) { | |
| 2094 | 2102 | .@"comptime" => unreachable, |
| 2095 | 2103 | .@"usingnamespace" => a: { |
| 2096 | 2104 | if (comp.incremental) { |
| ... | ... | @@ -2103,8 +2111,9 @@ const ScanDeclIter = struct { |
| 2103 | 2111 | } |
| 2104 | 2112 | break :a true; |
| 2105 | 2113 | }, |
| 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); | |
| 2108 | 2117 | // TODO: incremental compilation! |
| 2109 | 2118 | // * remove from `test_functions` if no longer matching filter |
| 2110 | 2119 | // * add to `test_functions` if newly passing filter |
| ... | ... | @@ -2112,7 +2121,7 @@ const ScanDeclIter = struct { |
| 2112 | 2121 | // Perhaps we should add all test indiscriminately and filter at the end of the update. |
| 2113 | 2122 | if (!comp.config.is_test) break :a false; |
| 2114 | 2123 | 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) { | |
| 2116 | 2125 | const fqn_slice = fqn.toSlice(ip); |
| 2117 | 2126 | for (comp.test_filters) |test_filter| { |
| 2118 | 2127 | if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break; |
| ... | ... | @@ -2121,7 +2130,7 @@ const ScanDeclIter = struct { |
| 2121 | 2130 | try zcu.test_functions.put(gpa, nav, {}); |
| 2122 | 2131 | break :a true; |
| 2123 | 2132 | }, |
| 2124 | .named => a: { | |
| 2133 | .@"const", .@"var" => a: { | |
| 2125 | 2134 | if (decl.is_pub) { |
| 2126 | 2135 | try namespace.pub_decls.putContext(gpa, nav, {}, .{ .zcu = zcu }); |
| 2127 | 2136 | } else { |
| ... | ... | @@ -2130,23 +2139,23 @@ const ScanDeclIter = struct { |
| 2130 | 2139 | break :a false; |
| 2131 | 2140 | }, |
| 2132 | 2141 | }; |
| 2133 | break :cau .{ cau, want_analysis }; | |
| 2142 | break :unit .{ unit, want_analysis }; | |
| 2134 | 2143 | }, |
| 2135 | 2144 | }; |
| 2136 | 2145 | |
| 2137 | if (existing_cau == null and (want_analysis or decl.linkage == .@"export")) { | |
| 2146 | if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) { | |
| 2138 | 2147 | 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) }, | |
| 2141 | 2150 | ); |
| 2142 | try comp.queueJob(.{ .analyze_cau = cau }); | |
| 2151 | try comp.queueJob(.{ .analyze_comptime_unit = unit }); | |
| 2143 | 2152 | } |
| 2144 | 2153 | |
| 2145 | 2154 | // TODO: we used to do line number updates here, but this is an inappropriate place for this logic to live. |
| 2146 | 2155 | } |
| 2147 | 2156 | }; |
| 2148 | 2157 | |
| 2149 | fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air { | |
| 2158 | fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air { | |
| 2150 | 2159 | const tracy = trace(@src()); |
| 2151 | 2160 | defer tracy.end(); |
| 2152 | 2161 | |
| ... | ... | @@ -2168,21 +2177,14 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2168 | 2177 | func.setResolvedErrorSet(ip, .none); |
| 2169 | 2178 | } |
| 2170 | 2179 | |
| 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); | |
| 2180 | 2185 | |
| 2181 | 2186 | const func_nav = ip.getNav(func.owner_nav); |
| 2182 | 2187 | |
| 2183 | const decl_prog_node = zcu.sema_prog_node.start(func_nav.fqn.toSlice(ip), 0); | |
| 2184 | defer decl_prog_node.end(); | |
| 2185 | ||
| 2186 | 2188 | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); |
| 2187 | 2189 | |
| 2188 | 2190 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| ... | ... | @@ -2216,7 +2218,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2216 | 2218 | |
| 2217 | 2219 | // Every runtime function has a dependency on the source of the Decl it originates from. |
| 2218 | 2220 | // 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 }); | |
| 2220 | 2222 | try sema.declareDependency(.{ .nav_val = func.owner_nav }); |
| 2221 | 2223 | |
| 2222 | 2224 | if (func.analysisUnordered(ip).inferred_error_set) { |
| ... | ... | @@ -2236,11 +2238,11 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2236 | 2238 | var inner_block: Sema.Block = .{ |
| 2237 | 2239 | .parent = null, |
| 2238 | 2240 | .sema = &sema, |
| 2239 | .namespace = decl_cau.namespace, | |
| 2241 | .namespace = decl_nav.analysis.?.namespace, | |
| 2240 | 2242 | .instructions = .{}, |
| 2241 | 2243 | .inlining = null, |
| 2242 | 2244 | .is_comptime = false, |
| 2243 | .src_base_inst = decl_cau.zir_index, | |
| 2245 | .src_base_inst = decl_nav.analysis.?.zir_index, | |
| 2244 | 2246 | .type_name_ctx = func_nav.fqn, |
| 2245 | 2247 | }; |
| 2246 | 2248 | defer inner_block.instructions.deinit(gpa); |
| ... | ... | @@ -2542,10 +2544,10 @@ fn processExportsInner( |
| 2542 | 2544 | .nav => |nav_index| if (failed: { |
| 2543 | 2545 | const nav = ip.getNav(nav_index); |
| 2544 | 2546 | 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; | |
| 2549 | 2551 | } |
| 2550 | 2552 | const val = switch (nav.status) { |
| 2551 | 2553 | .unresolved => break :failed true, |
| ... | ... | @@ -2593,15 +2595,14 @@ pub fn populateTestFunctions( |
| 2593 | 2595 | Zcu.Namespace.NameAdapter{ .zcu = zcu }, |
| 2594 | 2596 | ).?; |
| 2595 | 2597 | { |
| 2596 | // We have to call `ensureCauAnalyzed` here in case `builtin.test_functions` | |
| 2598 | // We have to call `ensureNavValUpToDate` here in case `builtin.test_functions` | |
| 2597 | 2599 | // was not referenced by start code. |
| 2598 | 2600 | zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); |
| 2599 | 2601 | defer { |
| 2600 | 2602 | zcu.sema_prog_node.end(); |
| 2601 | 2603 | zcu.sema_prog_node = std.Progress.Node.none; |
| 2602 | 2604 | } |
| 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) { | |
| 2605 | 2606 | error.AnalysisFail => return, |
| 2606 | 2607 | error.OutOfMemory => return error.OutOfMemory, |
| 2607 | 2608 | }; |
| ... | ... | @@ -2622,8 +2623,7 @@ pub fn populateTestFunctions( |
| 2622 | 2623 | { |
| 2623 | 2624 | // The test declaration might have failed; if that's the case, just return, as we'll |
| 2624 | 2625 | // 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 }); | |
| 2627 | 2627 | if (zcu.failed_analysis.contains(anal_unit) or |
| 2628 | 2628 | zcu.transitive_failed_analysis.contains(anal_unit)) |
| 2629 | 2629 | { |
| ... | ... | @@ -2748,8 +2748,8 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error |
| 2748 | 2748 | "unable to codegen: {s}", |
| 2749 | 2749 | .{@errorName(err)}, |
| 2750 | 2750 | )); |
| 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 })); | |
| 2753 | 2753 | } else { |
| 2754 | 2754 | // TODO: we don't have a way to indicate that this failure is retryable! |
| 2755 | 2755 | // 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 |
| 3255 | 3255 | const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls); |
| 3256 | 3256 | const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse |
| 3257 | 3257 | @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"); | |
| 3259 | 3259 | const builtin_type = Type.fromInterned(ip.getNav(builtin_nav).status.resolved.val); |
| 3260 | 3260 | const builtin_namespace = zcu.namespacePtr(builtin_type.getNamespace(zcu).unwrap() orelse @panic("std.builtin is corrupt")); |
| 3261 | 3261 | 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 |
| 3307 | 3307 | /// Given a container type requiring resolution, ensures that it is up-to-date. |
| 3308 | 3308 | /// If not, the type is recreated at a new `InternPool.Index`. |
| 3309 | 3309 | /// 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`. | |
| 3311 | pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updating: bool) Zcu.SemaError!InternPool.Index { | |
| 3310 | pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index { | |
| 3312 | 3311 | const zcu = pt.zcu; |
| 3312 | const gpa = zcu.gpa; | |
| 3313 | 3313 | 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 | ||
| 3314 | 3337 | 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), | |
| 3364 | 3341 | else => unreachable, |
| 3365 | 3342 | } |
| 3366 | 3343 | } |
| 3367 | 3344 | |
| 3368 | 3345 | fn recreateStructType( |
| 3369 | 3346 | pt: Zcu.PerThread, |
| 3347 | old_ty: InternPool.Index, | |
| 3370 | 3348 | full_key: InternPool.Key.NamespaceType, |
| 3371 | struct_obj: InternPool.LoadedStructType, | |
| 3372 | 3349 | ) Zcu.SemaError!InternPool.Index { |
| 3373 | 3350 | const zcu = pt.zcu; |
| 3374 | 3351 | const gpa = zcu.gpa; |
| ... | ... | @@ -3405,8 +3382,7 @@ fn recreateStructType( |
| 3405 | 3382 | |
| 3406 | 3383 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; |
| 3407 | 3384 | |
| 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); | |
| 3410 | 3386 | |
| 3411 | 3387 | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ |
| 3412 | 3388 | .layout = small.layout, |
| ... | ... | @@ -3428,17 +3404,16 @@ fn recreateStructType( |
| 3428 | 3404 | errdefer wip_ty.cancel(ip, pt.tid); |
| 3429 | 3405 | |
| 3430 | 3406 | 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); | |
| 3432 | 3407 | try ip.addDependency( |
| 3433 | 3408 | gpa, |
| 3434 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 3409 | .wrap(.{ .type = wip_ty.index }), | |
| 3435 | 3410 | .{ .src_hash = key.zir_index }, |
| 3436 | 3411 | ); |
| 3437 | 3412 | zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index; |
| 3438 | 3413 | // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive. |
| 3439 | 3414 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 3440 | 3415 | |
| 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); | |
| 3442 | 3417 | if (inst_info.inst == .main_struct_inst) { |
| 3443 | 3418 | // This is the root type of a file! Update the reference. |
| 3444 | 3419 | zcu.setFileRootType(inst_info.file, new_ty); |
| ... | ... | @@ -3448,8 +3423,8 @@ fn recreateStructType( |
| 3448 | 3423 | |
| 3449 | 3424 | fn recreateUnionType( |
| 3450 | 3425 | pt: Zcu.PerThread, |
| 3426 | old_ty: InternPool.Index, | |
| 3451 | 3427 | full_key: InternPool.Key.NamespaceType, |
| 3452 | union_obj: InternPool.LoadedUnionType, | |
| 3453 | 3428 | ) Zcu.SemaError!InternPool.Index { |
| 3454 | 3429 | const zcu = pt.zcu; |
| 3455 | 3430 | const gpa = zcu.gpa; |
| ... | ... | @@ -3488,8 +3463,7 @@ fn recreateUnionType( |
| 3488 | 3463 | |
| 3489 | 3464 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; |
| 3490 | 3465 | |
| 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); | |
| 3493 | 3467 | |
| 3494 | 3468 | const namespace_index = union_obj.namespace; |
| 3495 | 3469 | |
| ... | ... | @@ -3526,22 +3500,21 @@ fn recreateUnionType( |
| 3526 | 3500 | errdefer wip_ty.cancel(ip, pt.tid); |
| 3527 | 3501 | |
| 3528 | 3502 | 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); | |
| 3530 | 3503 | try ip.addDependency( |
| 3531 | 3504 | gpa, |
| 3532 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 3505 | .wrap(.{ .type = wip_ty.index }), | |
| 3533 | 3506 | .{ .src_hash = key.zir_index }, |
| 3534 | 3507 | ); |
| 3535 | 3508 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; |
| 3536 | 3509 | // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive. |
| 3537 | 3510 | 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); | |
| 3539 | 3512 | } |
| 3540 | 3513 | |
| 3541 | 3514 | fn recreateEnumType( |
| 3542 | 3515 | pt: Zcu.PerThread, |
| 3516 | old_ty: InternPool.Index, | |
| 3543 | 3517 | full_key: InternPool.Key.NamespaceType, |
| 3544 | enum_obj: InternPool.LoadedEnumType, | |
| 3545 | 3518 | ) Zcu.SemaError!InternPool.Index { |
| 3546 | 3519 | const zcu = pt.zcu; |
| 3547 | 3520 | const gpa = zcu.gpa; |
| ... | ... | @@ -3610,8 +3583,7 @@ fn recreateEnumType( |
| 3610 | 3583 | if (bag != 0) break true; |
| 3611 | 3584 | } else false; |
| 3612 | 3585 | |
| 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); | |
| 3615 | 3587 | |
| 3616 | 3588 | const namespace_index = enum_obj.namespace; |
| 3617 | 3589 | |
| ... | ... | @@ -3637,12 +3609,10 @@ fn recreateEnumType( |
| 3637 | 3609 | |
| 3638 | 3610 | wip_ty.setName(ip, enum_obj.name); |
| 3639 | 3611 | |
| 3640 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | |
| 3641 | ||
| 3642 | 3612 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; |
| 3643 | 3613 | // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive. |
| 3644 | 3614 | |
| 3645 | wip_ty.prepare(ip, new_cau_index, namespace_index); | |
| 3615 | wip_ty.prepare(ip, namespace_index); | |
| 3646 | 3616 | done = true; |
| 3647 | 3617 | |
| 3648 | 3618 | Sema.resolveDeclaredEnum( |
| ... | ... | @@ -3652,7 +3622,6 @@ fn recreateEnumType( |
| 3652 | 3622 | key.zir_index, |
| 3653 | 3623 | namespace_index, |
| 3654 | 3624 | enum_obj.name, |
| 3655 | new_cau_index, | |
| 3656 | 3625 | small, |
| 3657 | 3626 | body, |
| 3658 | 3627 | 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 |
| 2261 | 2261 | assert(file.zir_loaded); |
| 2262 | 2262 | const decl = file.zir.getDeclaration(inst_info.inst); |
| 2263 | 2263 | |
| 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); | |
| 2266 | 2266 | break :parent .{ |
| 2267 | 2267 | parent_namespace_ptr.owner_type, |
| 2268 | 2268 | 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 |
| 2292 | 2292 | assert(file.zir_loaded); |
| 2293 | 2293 | const decl = file.zir.getDeclaration(inst_info.inst); |
| 2294 | 2294 | |
| 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); | |
| 2297 | 2297 | break :parent .{ |
| 2298 | 2298 | parent_namespace_ptr.owner_type, |
| 2299 | 2299 | 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 |
| 2321 | 2321 | assert(file.zir_loaded); |
| 2322 | 2322 | const decl = file.zir.getDeclaration(inst_info.inst); |
| 2323 | 2323 | |
| 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); | |
| 2326 | 2326 | break :parent .{ |
| 2327 | 2327 | parent_namespace_ptr.owner_type, |
| 2328 | 2328 | 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 |
| 2563 | 2563 | return; |
| 2564 | 2564 | } |
| 2565 | 2565 | |
| 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); | |
| 2568 | 2568 | break :parent .{ |
| 2569 | 2569 | parent_namespace_ptr.owner_type, |
| 2570 | 2570 | if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private, |