zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 5d215838a79a24c21842fbc76fd77aca4c28b162 (tree)
parent 065c6e7946e712dc8563c975a4ca951927145da7
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date:   Sun, 15 Mar 2026 10:34:13 +0000

InternPool.Nav: fix race, refactor

I've realised that the cause of at least some of our weird CI flakiness
was a bug in how `Nav` values were resolved. Consider this scenario: the
frontend resolves the type of a `Nav`, and then sends a function to the
backend, which requires the backend to lower a pointer to that `Nav`.
The backend calls `InternPool.getNav` to determine the `Nav`'s type.
However, this races with the frontend resolving the *value* of that
`Nav`. This involves writing separately to two fields, `bits` and
`type_or_value`. If only one of these changes is observed, then the
backend will incorrectly interpret the type as the value or vice versa,
leading to a crash or even a miscompilation. (Of course, there's also
the straightforward issue that the racing loads were non-atomic, making
them illegal).

The only good solution to this was to make `Nav` 4 bytes bigger, giving
it separate `type` and `value` fields. In theory that's a quite small
change, but it ended up having a bunch of nice consequences which led to
this diff being a bit bulkier than expected:

* `Nav.Repr.Bits` was simplified, because it no longer has to track
  "resolution status": we can use `.none` for that. This frees up some
  bits to make things more consistent between the "type resolved" and
  "fully resolved" states.

* This consistency allowed the `Nav.status` union to be replaced with a
  simpler field `Nav.resolved`, which is a bit nicer to work with.

* Most of the "getter" functions were able to be removed from `Nav`
  because the state they were fetching had been moved to simple fields
  on `Nav.resolved`.

* There were still a handful of free bits in `Nav.Repr.Bits`, which
  could be used to represent the "const" and "threadlocal" flags rather
  than these being stored on `Key.Extern` and `Key.Variable`. This is a
  bit more convenient for linkers.

* With those bits gone, `Key.Variable` is a trivial wrapper around a
  type and an initial value, and the fact that a declaration is mutable
  can be represented solely through the "const" flag. Therefore,
  `Key.Variable` no longer served a purpose, and could be eliminated
  entirely in favour of storing the variable's initial value directly in
  the "value" field of the `Nav`.

So, I'm quite pleased with this refactor! But anyway, regarding the bug
fix which actually motivated this: if I've done my job correctly, this
should solve some crashes, such as these (which were what tipped me off
to this bug in the first place):

https://codeberg.org/ziglang/zig/actions/runs/2306/jobs/7/attempt/1
https://codeberg.org/ziglang/zig/actions/runs/2173/jobs/6/attempt/1

...and, who knows, perhaps even the random SIGSEGVs we've seen on some
targets! Probably not, but one can hope.

Diffstat:
Msrc/IncrementalDebugServer.zig | 21++++++++++++---------
Msrc/InternPool.zig | 584+++++++++++++++++++++++++------------------------------------------------------
Msrc/Sema.zig | 117+++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/Sema/bitcast.zig | 1-
Msrc/Sema/comptime_ptr_access.zig | 22++++++++++------------
Msrc/Sema/type_resolution.zig | 1-
Msrc/Type.zig | 10----------
Msrc/Value.zig | 10+---------
Msrc/Zcu.zig | 24+++++++++---------------
Msrc/Zcu/PerThread.zig | 186++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/codegen.zig | 12++++++------
Msrc/codegen/aarch64/Mir.zig | 2+-
Msrc/codegen/aarch64/Select.zig | 6++----
Msrc/codegen/c.zig | 72+++++++++++++++++++++++++++++++-----------------------------------------
Msrc/codegen/c/type.zig | 1-
Msrc/codegen/llvm.zig | 61+++++++++++++++++++++++++++----------------------------------
Msrc/codegen/spirv/CodeGen.zig | 97++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/codegen/spirv/Module.zig | 4++--
Msrc/codegen/wasm/CodeGen.zig | 3+--
Msrc/codegen/wasm/Emit.zig | 2+-
Msrc/codegen/x86_64/CodeGen.zig | 4++--
Msrc/codegen/x86_64/Emit.zig | 39++++++++++++++++-----------------------
Msrc/link.zig | 2+-
Msrc/link/C.zig | 13+++++++------
Msrc/link/Coff.zig | 55+++++++++++++++++++++----------------------------------
Msrc/link/Dwarf.zig | 19++++++++-----------
Msrc/link/Elf/ZigObject.zig | 36++++++++++++++++--------------------
Msrc/link/Elf2.zig | 60+++++++++++++++++++-----------------------------------------
Msrc/link/MachO/ZigObject.zig | 32+++++++++++++-------------------
Msrc/link/SpirV.zig | 2+-
Msrc/link/Wasm.zig | 57++++++++++++++++++++++++++++-----------------------------
Msrc/link/Wasm/Flush.zig | 2+-
Msrc/print_value.zig | 1-
33 files changed, 593 insertions(+), 965 deletions(-)

diff --git a/src/IncrementalDebugServer.zig b/src/IncrementalDebugServer.zig @@ -215,22 +215,25 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const try w.print( \\name: '{f}' \\fqn: '{f}' - \\status: {s} \\created on generation: {d} \\ , .{ nav.name.fmt(ip), nav.fqn.fmt(ip), - @tagName(nav.status), create_gen, }); - switch (nav.status) { - .unresolved => {}, - .type_resolved, .fully_resolved => { - try w.writeAll("type: "); - try printType(.fromInterned(nav.typeOf(ip)), zcu, w); - try w.writeByte('\n'); - }, + if (nav.resolved) |r| { + try w.writeAll("status: resolved\n type: "); + try printType(.fromInterned(r.type), zcu, w); + try w.writeAll("\n value: "); + if (r.value == .none) { + try w.writeAll("(unresolved)"); + } else { + try printType(.fromInterned(r.type), zcu, w); + } + try w.writeByte('\n'); + } else { + try w.writeAll("status: unresolved\n"); } } else if (std.mem.eql(u8, cmd_str, "find_type")) { if (arg_str.len == 0) return w.writeAll("bad usage"); diff --git a/src/InternPool.zig b/src/InternPool.zig @@ -548,144 +548,61 @@ pub const Nav = struct { /// The fully-qualified name of this `Nav`. fqn: NullTerminatedString, /// This field is populated iff this `Nav` is resolved by semantic analysis. - /// If this is `null`, then `status == .fully_resolved` always. + /// If this is `null`, then `resolved` is *not* `null`. analysis: ?struct { namespace: NamespaceIndex, zir_index: TrackedInst.Index, /// Initially `false`. Set to `true` by `setWantNavAnalysis`. wanted: bool, }, - status: union(enum) { - /// This `Nav` is pending semantic analysis. - unresolved, - /// The type of this `Nav` is resolved; the value is queued for resolution. - type_resolved: struct { - type: InternPool.Index, - is_const: bool, - alignment: Alignment, - @"linksection": OptionalNullTerminatedString, - @"addrspace": std.builtin.AddressSpace, - is_threadlocal: bool, - /// This field is whether this `Nav` is a literal `extern` definition. - /// It does *not* tell you whether this might alias an extern fn (see #21027). - is_extern_decl: bool, - }, - /// The value of this `Nav` is resolved. - fully_resolved: struct { - val: InternPool.Index, - is_const: bool, - alignment: Alignment, - @"linksection": OptionalNullTerminatedString, - @"addrspace": std.builtin.AddressSpace, - }, - }, - - /// Asserts that `status != .unresolved`. - pub fn typeOf(nav: Nav, ip: *const InternPool) InternPool.Index { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => |r| r.type, - .fully_resolved => |r| ip.typeOf(r.val), - }; - } - - /// This function is intended to be used by code generation, since semantic - /// analysis will ensure that any `Nav` which is potentially `extern` is - /// fully resolved. - /// Asserts that `status == .fully_resolved`. - pub fn getResolvedExtern(nav: Nav, ip: *const InternPool) ?Key.Extern { - assert(nav.status == .fully_resolved); - return nav.getExtern(ip); - } - - /// Always returns `null` for `status == .type_resolved`. This function is inteded - /// to be used by code generation, since semantic analysis will ensure that any `Nav` - /// which is potentially `extern` is fully resolved. - /// Asserts that `status != .unresolved`. + /// If this is `null`, then `analysis` is *not* `null`, and semantic analysis is required to + /// resolve the type and value of this `Nav`. Otherwise, the type is resolved---therefore, + /// `Nav.resolved.?.type` is never `.none`. However, the *value* may not be resolved yet even + /// if this field is not `null`---see `Resolved.value` for details. + resolved: ?Resolved, + + pub const Resolved = struct { + /// This is never `.none` + type: InternPool.Index, + @"align": Alignment, + @"linksection": OptionalNullTerminatedString, + @"addrspace": std.builtin.AddressSpace, + @"const": bool, + @"threadlocal": bool, + /// This field is whether this `Nav` is a literal `extern` definition. + /// It does *not* tell you whether this might alias an extern fn (see #21027). + is_extern_decl: bool, + /// If the type is resolved but not the value, this is `.none`. In that case, the value will + /// be resolved by semantic analysis, so `Nav.analysis` is definitely not `null`. + /// + /// If this is an extern, the special key `Key.@"extern"` is used. + /// + /// If this is a variable (`Resolved.@"const" == false`) and not an extern, then this value + /// is the global variable's initializer; the value loaded from the variable at runtime may + /// of course be different. + value: InternPool.Index, + }; + + /// If the value of this `Nav` is resolved and is an extern, returns the `Key.Extern`. If the + /// value is *not* an extern, *or* if the value is not yet resolved (only the type is), returns + /// `null`. + /// + /// This logic works because the frontend ensures that if a `Nav` *might* be extern, its value + /// is resolved more eagerly (see logic in `Sema.analyzeNavRefInner`). Therefore, if we see that + /// the value is not yet resolved, we know the frontend determined that the `Nav` is definitely + /// *not* extern. + /// + /// This function is only intended be used by the compiler backend (codegen/link). The guarantee + /// mentioned above does not necessarily hold in the compiler frontend (if we haven't reached + /// `Sema.analyzeNavRefInner` yet). + /// + /// Asserts that `nav.resolved != null`. pub fn getExtern(nav: Nav, ip: *const InternPool) ?Key.Extern { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => null, - .fully_resolved => |r| switch (ip.indexToKey(r.val)) { - .@"extern" => |e| e, - else => null, - }, - }; - } - - /// Asserts that `status != .unresolved`. - pub fn getAddrspace(nav: Nav) std.builtin.AddressSpace { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => |r| r.@"addrspace", - .fully_resolved => |r| r.@"addrspace", - }; - } - - /// Asserts that `status != .unresolved`. - pub fn getAlignment(nav: Nav) Alignment { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => |r| r.alignment, - .fully_resolved => |r| r.alignment, - }; - } - - /// Asserts that `status != .unresolved`. - pub fn getLinkSection(nav: Nav) OptionalNullTerminatedString { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => |r| r.@"linksection", - .fully_resolved => |r| r.@"linksection", - }; - } - - /// Asserts that `status != .unresolved`. - pub fn isThreadlocal(nav: Nav, ip: *const InternPool) bool { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => |r| r.is_threadlocal, - .fully_resolved => |r| switch (ip.indexToKey(r.val)) { - .@"extern" => |e| e.is_threadlocal, - .variable => |v| v.is_threadlocal, - else => false, - }, - }; - } - - pub fn isFn(nav: Nav, ip: *const InternPool) bool { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => |r| { - const tag = ip.zigTypeTag(r.type); - return tag == .@"fn"; - }, - .fully_resolved => |r| { - const tag = ip.zigTypeTag(ip.typeOf(r.val)); - return tag == .@"fn"; - }, - }; - } - - /// If this returns `true`, then a pointer to this `Nav` might actually be encoded as a pointer - /// to some other `Nav` due to an extern definition or extern alias (see #21027). - /// This query is valid on `Nav`s for whom only the type is resolved. - /// Asserts that `status != .unresolved`. - pub fn isExternOrFn(nav: Nav, ip: *const InternPool) bool { - return switch (nav.status) { - .unresolved => unreachable, - .type_resolved => |r| { - if (r.is_extern_decl) return true; - const tag = ip.zigTypeTag(r.type); - if (tag == .@"fn") return true; - return false; - }, - .fully_resolved => |r| { - if (ip.indexToKey(r.val) == .@"extern") return true; - const tag = ip.zigTypeTag(ip.typeOf(r.val)); - if (tag == .@"fn") return true; - return false; - }, + const r = nav.resolved.?; + if (r.value == .none) return null; + return switch (ip.indexToKey(r.value)) { + .@"extern" => |e| e, + else => null, }; } @@ -696,7 +613,7 @@ pub const Nav = struct { return a.zir_index; } // A `Nav` which does not undergo analysis always has a resolved value. - return switch (ip.indexToKey(nav.status.fully_resolved.val)) { + return switch (ip.indexToKey(nav.resolved.?.value)) { .func => |func| { // Since `analysis` was not populated, this must be an instantiation. // Go up to the generic owner and consult *its* `analysis` field. @@ -747,30 +664,26 @@ pub const Nav = struct { }; /// The compact in-memory representation of a `Nav`. - /// 26 bytes. + /// 30 bytes. const Repr = struct { name: NullTerminatedString, fqn: NullTerminatedString, // The following 2 fields are either both populated, or both `.none`. analysis_namespace: OptionalNamespaceIndex, analysis_zir_index: TrackedInst.Index.Optional, - /// Populated only if `bits.status != .unresolved`. - type_or_val: InternPool.Index, - /// Populated only if `bits.status != .unresolved`. + type: InternPool.Index, + value: InternPool.Index, @"linksection": OptionalNullTerminatedString, bits: Bits, const Bits = packed struct(u16) { - status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl }, - /// Populated only if `bits.status != .unresolved`. - is_const: bool, - /// Populated only if `bits.status != .unresolved`. - alignment: Alignment, - /// Populated only if `bits.status != .unresolved`. + @"align": Alignment, @"addrspace": std.builtin.AddressSpace, - /// Populated only if `bits.status == .type_resolved`. - is_threadlocal: bool, + @"const": bool, + @"threadlocal": bool, + is_extern_decl: bool, want_analysis: bool, + _: u1 = 0, }; fn unpack(repr: Repr) Nav { @@ -785,72 +698,46 @@ pub const Nav = struct { assert(repr.analysis_zir_index == .none); break :a null; }, - .status = switch (repr.bits.status) { - .unresolved => .unresolved, - .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{ - .type = repr.type_or_val, - .is_const = repr.bits.is_const, - .alignment = repr.bits.alignment, - .@"linksection" = repr.@"linksection", - .@"addrspace" = repr.bits.@"addrspace", - .is_threadlocal = repr.bits.is_threadlocal, - .is_extern_decl = repr.bits.status == .type_resolved_extern_decl, - } }, - .fully_resolved => .{ .fully_resolved = .{ - .val = repr.type_or_val, - .is_const = repr.bits.is_const, - .alignment = repr.bits.alignment, - .@"linksection" = repr.@"linksection", - .@"addrspace" = repr.bits.@"addrspace", - } }, + .resolved = if (repr.type == .none) null else .{ + .type = repr.type, + .@"align" = repr.bits.@"align", + .@"linksection" = repr.@"linksection", + .@"addrspace" = repr.bits.@"addrspace", + .@"const" = repr.bits.@"const", + .@"threadlocal" = repr.bits.@"threadlocal", + .is_extern_decl = repr.bits.is_extern_decl, + .value = repr.value, }, }; } }; fn pack(nav: Nav) Repr { - // Note that in the `unresolved` case, we do not mark fields as `undefined`, even though they should not be used. - // This is to avoid writing undefined bytes to disk when serializing buffers. + // Note that even if `nav.resolved == null`, we do not set any fields to `undefined`, even + // though they should not be used. This is to avoid writing undefined bytes to disk when + // serializing buffers. return .{ .name = nav.name, .fqn = nav.fqn, .analysis_namespace = if (nav.analysis) |a| a.namespace.toOptional() else .none, .analysis_zir_index = if (nav.analysis) |a| a.zir_index.toOptional() else .none, - .type_or_val = switch (nav.status) { - .unresolved => .none, - .type_resolved => |r| r.type, - .fully_resolved => |r| r.val, - }, - .@"linksection" = switch (nav.status) { - .unresolved => .none, - .type_resolved => |r| r.@"linksection", - .fully_resolved => |r| r.@"linksection", - }, - .bits = switch (nav.status) { - .unresolved => .{ - .status = .unresolved, - .is_const = false, - .alignment = .none, - .@"addrspace" = .generic, - .is_threadlocal = false, - .want_analysis = if (nav.analysis) |a| a.wanted else false, - }, - .type_resolved => |r| .{ - .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved, - .is_const = r.is_const, - .alignment = r.alignment, - .@"addrspace" = r.@"addrspace", - .is_threadlocal = r.is_threadlocal, - .want_analysis = if (nav.analysis) |a| a.wanted else false, - }, - .fully_resolved => |r| .{ - .status = .fully_resolved, - .is_const = r.is_const, - .alignment = r.alignment, - .@"addrspace" = r.@"addrspace", - .is_threadlocal = false, - .want_analysis = if (nav.analysis) |a| a.wanted else false, - }, + .type = if (nav.resolved) |r| r.type else .none, + .value = if (nav.resolved) |r| r.value else .none, + .@"linksection" = if (nav.resolved) |r| r.@"linksection" else .none, + .bits = if (nav.resolved) |r| .{ + .@"align" = r.@"align", + .@"addrspace" = r.@"addrspace", + .@"const" = r.@"const", + .@"threadlocal" = r.@"threadlocal", + .is_extern_decl = r.is_extern_decl, + .want_analysis = if (nav.analysis) |a| a.wanted else false, + } else .{ + .@"align" = .none, + .@"addrspace" = .generic, + .@"const" = false, + .@"threadlocal" = false, + .is_extern_decl = false, + .want_analysis = if (nav.analysis) |a| a.wanted else false, }, }; } @@ -2110,7 +1997,6 @@ pub const Key = union(enum) { /// via `simple_value` and has a named `Index` tag for it. undef: Index, simple_value: SimpleValue, - variable: Variable, @"extern": Extern, func: Func, int: Key.Int, @@ -2311,14 +2197,6 @@ pub const Key = union(enum) { } }; - /// A runtime variable defined in this `Zcu`. - pub const Variable = struct { - ty: Index, - init: Index, - owner_nav: Nav.Index, - is_threadlocal: bool, - }; - pub const Extern = struct { /// The name of the extern symbol. name: NullTerminatedString, @@ -2543,7 +2421,7 @@ pub const Key = union(enum) { pub const BaseAddr = union(enum) { const Tag = @typeInfo(BaseAddr).@"union".tag_type.?; - /// Points to the value of a single `Nav`, which may be constant or a `variable`. + /// Points to the value of a single `Nav`. nav: Nav.Index, /// Points to the value of a single comptime alloc stored in `Sema`. @@ -2735,8 +2613,6 @@ pub const Key = union(enum) { .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)), }, - .variable => |variable| Hash.hash(seed, asBytes(&variable.owner_nav)), - .opaque_type, .enum_type, .union_type, @@ -3011,13 +2887,6 @@ pub const Key = union(enum) { return a_info.ty == b_info.ty and a_info.backing_int_val == b_info.backing_int_val; }, - .variable => |a_info| { - const b_info = b.variable; - return a_info.ty == b_info.ty and - a_info.init == b_info.init and - a_info.owner_nav == b_info.owner_nav and - a_info.is_threadlocal == b_info.is_threadlocal; - }, .@"extern" => |a_info| { const b_info = b.@"extern"; return a_info.name == b_info.name and @@ -3277,7 +3146,6 @@ pub const Key = union(enum) { .int, .float, .opt, - .variable, .@"extern", .func, .err, @@ -4390,8 +4258,6 @@ pub const Index = enum(u32) { float_c_longdouble_f80: struct { data: *Float80 }, float_c_longdouble_f128: struct { data: *Float128 }, float_comptime_float: struct { data: *Float128 }, - variable: struct { data: *Tag.Variable }, - threadlocal_variable: struct { data: *Tag.Variable }, @"extern": struct { data: *Tag.Extern }, func_decl: struct { const @"data.analysis.inferred_error_set" = opaque {}; @@ -5115,12 +4981,6 @@ pub const Tag = enum(u8) { /// A comptime_float value. /// data is extra index to Float128. float_comptime_float, - /// A global variable. - /// data is extra index to Variable. - variable, - /// A global threadlocal variable. - /// data is extra index to Variable. - threadlocal_variable, /// An extern function or variable. /// data is extra index to Extern. /// Some parts of the key are stored in `owner_nav`. @@ -5457,8 +5317,6 @@ pub const Tag = enum(u8) { .float_c_longdouble_f80 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f80 }, .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 }, .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 }, - .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable }, - .threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable }, .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern }, .func_decl = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", @@ -5505,13 +5363,6 @@ pub const Tag = enum(u8) { return @field(encodings, @tagName(tag)).payload; } - pub const Variable = struct { - ty: Index, - /// May be `none`. - init: Index, - owner_nav: Nav.Index, - }; - pub const Extern = struct { // name, is_const, alignment, addrspace come from `owner_nav`. ty: Index, @@ -5525,12 +5376,11 @@ pub const Tag = enum(u8) { pub const Flags = packed struct(u32) { linkage: std.builtin.GlobalLinkage, visibility: std.builtin.SymbolVisibility, - is_threadlocal: bool, is_dll_import: bool, relocation: std.builtin.ExternOptions.Relocation, source: Source, decoration_type: DecorationType, - _: u22 = 0, + _: u23 = 0, pub const Source = enum(u1) { builtin, syntax }; pub const DecorationType = enum(u2) { none, location, descriptor }; @@ -6894,19 +6744,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .ty = .comptime_float_type, .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() }, } }, - .variable, .threadlocal_variable => { - const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data); - return .{ .variable = .{ - .ty = extra.ty, - .init = extra.init, - .owner_nav = extra.owner_nav, - .is_threadlocal = switch (item.tag) { - else => unreachable, - .variable => false, - .threadlocal_variable => true, - }, - } }; - }, .@"extern" => { const extra = extraData(unwrapped_index.getExtra(ip), Tag.Extern, data); const nav = ip.getNav(extra.owner_nav); @@ -6916,13 +6753,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .lib_name = extra.lib_name, .linkage = extra.flags.linkage, .visibility = extra.flags.visibility, - .is_threadlocal = extra.flags.is_threadlocal, + .is_threadlocal = nav.resolved.?.@"threadlocal", .is_dll_import = extra.flags.is_dll_import, .relocation = extra.flags.relocation, .decoration = extra.decoration(), - .is_const = nav.status.fully_resolved.is_const, - .alignment = nav.status.fully_resolved.alignment, - .@"addrspace" = nav.status.fully_resolved.@"addrspace", + .is_const = nav.resolved.?.@"const", + .alignment = nav.resolved.?.@"align", + .@"addrspace" = nav.resolved.?.@"addrspace", .zir_index = extra.zir_index, .owner_nav = extra.owner_nav, .source = extra.flags.source, @@ -7516,22 +7353,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: .func => unreachable, // use getFuncInstance() or getFuncDecl() instead .un => unreachable, // use getUnion instead - .variable => |variable| { - const has_init = variable.init != .none; - if (has_init) assert(variable.ty == ip.typeOf(variable.init)); - items.appendAssumeCapacity(.{ - .tag = switch (variable.is_threadlocal) { - false => .variable, - true => .threadlocal_variable, - }, - .data = try addExtra(extra, Tag.Variable{ - .ty = variable.ty, - .init = variable.init, - .owner_nav = variable.owner_nav, - }), - }); - }, - .slice => |slice| { assert(ip.indexToKey(slice.ty).ptr_type.flags.size == .slice); assert(ip.indexToKey(ip.typeOf(slice.ptr)).ptr_type.flags.size == .many); @@ -9245,14 +9066,15 @@ pub fn getExtern( .tid = tid, .index = items.mutate.len, }, ip); - const owner_nav = ip.createNav(gpa, io, tid, .{ - .name = key.name, - .fqn = key.name, - .val = extern_index, - .is_const = key.is_const, - .alignment = key.alignment, + const owner_nav = ip.createNav(gpa, io, tid, key.name, key.name, .{ + .type = key.ty, + .@"align" = key.alignment, .@"linksection" = .none, .@"addrspace" = key.@"addrspace", + .@"const" = key.is_const, + .@"threadlocal" = key.is_threadlocal, + .is_extern_decl = true, + .value = extern_index, }) catch unreachable; // capacity asserted above const decoration_type, const location_or_descriptor_set, const descriptor_binding = if (key.decoration) |decoration| switch (decoration) { .location => |location| .{ Tag.Extern.Flags.DecorationType.location, location, undefined }, @@ -9266,7 +9088,6 @@ pub fn getExtern( .flags = .{ .linkage = key.linkage, .visibility = key.visibility, - .is_threadlocal = key.is_threadlocal, .is_dll_import = key.is_dll_import, .relocation = key.relocation, .decoration_type = decoration_type, @@ -9846,14 +9667,16 @@ fn finishFuncInstance( const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{ fn_owner_nav.name.fmt(ip), @intFromEnum(func_index), }, .no_embedded_nulls); - const nav_index = try ip.createNav(gpa, io, tid, .{ - .name = nav_name, - .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name), - .val = func_index, - .is_const = fn_owner_nav.status.fully_resolved.is_const, - .alignment = fn_owner_nav.status.fully_resolved.alignment, - .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection", - .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace", + const nav_fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name); + const nav_index = try ip.createNav(gpa, io, tid, nav_name, nav_fqn, .{ + .type = ip.typeOf(func_index), + .@"align" = fn_owner_nav.resolved.?.@"align", + .@"linksection" = fn_owner_nav.resolved.?.@"linksection", + .@"addrspace" = fn_owner_nav.resolved.?.@"addrspace", + .@"const" = true, + .@"threadlocal" = false, + .is_extern_decl = false, + .value = func_index, }); // Populate the owner_nav field which was left undefined until now. @@ -10616,20 +10439,6 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index { return ip.indexToKey(ty).error_union_type.payload_type; } -/// The is only legal because the initializer is not part of the hash. -pub fn mutateVarInit(ip: *InternPool, io: Io, index: Index, init_index: Index) void { - const unwrapped_index = index.unwrap(ip); - - const local = ip.getLocal(unwrapped_index.tid); - local.mutate.extra.mutex.lockUncancelable(io); - defer local.mutate.extra.mutex.unlock(io); - - const extra_items = local.shared.extra.view().items(.@"0"); - const item = unwrapped_index.getItem(ip); - assert(item.tag == .variable); - @atomicStore(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.Variable, "init").?], @intFromEnum(init_index), .release); -} - pub fn dump(ip: *const InternPool) void { var buffer: [4096]u8 = undefined; const stderr = std.debug.lockStderr(&buffer); @@ -10969,7 +10778,6 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo .float_c_longdouble_f80 => @sizeOf(Float80), .float_c_longdouble_f128 => @sizeOf(Float128), .float_comptime_float => @sizeOf(Float128), - .variable, .threadlocal_variable => @sizeOf(Tag.Variable), .@"extern" => @sizeOf(Tag.Extern), .func_decl => @sizeOf(Tag.FuncDecl), .func_instance => b: { @@ -11089,8 +10897,6 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { .float_c_longdouble_f80, .float_c_longdouble_f128, .float_comptime_float, - .variable, - .threadlocal_variable, .@"extern", .func_decl, .func_instance, @@ -11175,8 +10981,24 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator, pub fn getNav(ip: *const InternPool, index: Nav.Index) Nav { const unwrapped = index.unwrap(ip); - const navs = ip.getLocalShared(unwrapped.tid).navs.acquire(); - return navs.view().get(unwrapped.index).unpack(); + const view = ip.getLocalShared(unwrapped.tid).navs.acquire().view(); + // We can't just call `view.get(unwrapped.index)`, because a concurrent call to `resolveNav` + // could be writing to fields, making a non-atomic load illegal. Instead, atomically load + // each field. We don't need any ordering guarantees because if we need to see (e.g.) the + // resolved type of a `Nav`, that information should have already been released to our caller. + const repr: Nav.Repr = .{ + // Load the first few fields non-atomically---they are never mutated after `Nav` creation. + .name = view.items(.name)[unwrapped.index], + .fqn = view.items(.fqn)[unwrapped.index], + .analysis_namespace = view.items(.analysis_namespace)[unwrapped.index], + .analysis_zir_index = view.items(.analysis_zir_index)[unwrapped.index], + // The last few fields are populated by `resolveNav` so must be loaded atomically. + .type = @atomicLoad(InternPool.Index, &view.items(.type)[unwrapped.index], .monotonic), + .value = @atomicLoad(InternPool.Index, &view.items(.value)[unwrapped.index], .monotonic), + .@"linksection" = @atomicLoad(OptionalNullTerminatedString, &view.items(.@"linksection")[unwrapped.index], .monotonic), + .bits = @atomicLoad(Nav.Repr.Bits, &view.items(.bits)[unwrapped.index], .monotonic), + }; + return repr.unpack(); } pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Namespace { @@ -11220,15 +11042,9 @@ fn createNav( gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, - opts: struct { - name: NullTerminatedString, - fqn: NullTerminatedString, - val: InternPool.Index, - is_const: bool, - alignment: Alignment, - @"linksection": OptionalNullTerminatedString, - @"addrspace": std.builtin.AddressSpace, - }, + name: NullTerminatedString, + fqn: NullTerminatedString, + resolved: @typeInfo(@FieldType(Nav, "resolved")).optional.child, ) Allocator.Error!Nav.Index { const navs = ip.getLocal(tid).getMutableNavs(gpa, io); const index_unwrapped: Nav.Index.Unwrapped = .{ @@ -11236,16 +11052,10 @@ fn createNav( .index = navs.mutate.len, }; try navs.append(Nav.pack(.{ - .name = opts.name, - .fqn = opts.fqn, + .name = name, + .fqn = fqn, .analysis = null, - .status = .{ .fully_resolved = .{ - .val = opts.val, - .is_const = opts.is_const, - .alignment = opts.alignment, - .@"linksection" = opts.@"linksection", - .@"addrspace" = opts.@"addrspace", - } }, + .resolved = resolved, })); return index_unwrapped.wrap(ip); } @@ -11279,27 +11089,19 @@ pub fn createDeclNav( .zir_index = zir_index, .wanted = false, }, - .status = .unresolved, + .resolved = null, })); return nav; } -/// Resolve the type of a `Nav` with an analysis owner. +/// Resolve the type (and possibly the value) of a `Nav` with an analysis owner. /// If its status is already `resolved`, the old value is discarded. -pub fn resolveNavType( +pub fn resolveNav( ip: *InternPool, io: Io, nav: Nav.Index, - resolved: struct { - type: InternPool.Index, - is_const: bool, - alignment: Alignment, - @"linksection": OptionalNullTerminatedString, - @"addrspace": std.builtin.AddressSpace, - is_threadlocal: bool, - is_extern_decl: bool, - }, + resolved: @typeInfo(@FieldType(Nav, "resolved")).optional.child, ) void { const unwrapped = nav.unwrap(ip); @@ -11311,65 +11113,45 @@ pub fn resolveNavType( const nav_analysis_namespace = navs.items(.analysis_namespace); const nav_analysis_zir_index = navs.items(.analysis_zir_index); - const nav_types = navs.items(.type_or_val); + const nav_types = navs.items(.type); + const nav_values = navs.items(.value); const nav_linksections = navs.items(.@"linksection"); const nav_bits = navs.items(.bits); assert(nav_analysis_namespace[unwrapped.index] != .none); assert(nav_analysis_zir_index[unwrapped.index] != .none); - @atomicStore(InternPool.Index, &nav_types[unwrapped.index], resolved.type, .release); - @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release); - - var bits = nav_bits[unwrapped.index]; - bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved; - bits.is_const = resolved.is_const; - bits.alignment = resolved.alignment; - bits.@"addrspace" = resolved.@"addrspace"; - bits.is_threadlocal = resolved.is_threadlocal; - @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release); -} - -/// Resolve the value of a `Nav` with an analysis owner. -/// If its status is already `resolved`, the old value is discarded. -pub fn resolveNavValue( - ip: *InternPool, - io: Io, - nav: Nav.Index, - resolved: struct { - val: InternPool.Index, - is_const: bool, - alignment: Alignment, - @"linksection": OptionalNullTerminatedString, - @"addrspace": std.builtin.AddressSpace, - }, -) void { - const unwrapped = nav.unwrap(ip); - - const local = ip.getLocal(unwrapped.tid); - local.mutate.extra.mutex.lockUncancelable(io); - defer local.mutate.extra.mutex.unlock(io); - - const navs = local.shared.navs.view(); - - const nav_analysis_namespace = navs.items(.analysis_namespace); - const nav_analysis_zir_index = navs.items(.analysis_zir_index); - const nav_vals = navs.items(.type_or_val); - const nav_linksections = navs.items(.@"linksection"); - const nav_bits = navs.items(.bits); - - assert(nav_analysis_namespace[unwrapped.index] != .none); - assert(nav_analysis_zir_index[unwrapped.index] != .none); + @atomicStore( + OptionalNullTerminatedString, + &nav_linksections[unwrapped.index], + resolved.@"linksection", + .monotonic, + ); - @atomicStore(InternPool.Index, &nav_vals[unwrapped.index], resolved.val, .release); - @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release); + const bits = &nav_bits[unwrapped.index]; + assert(@atomicLoad(Nav.Repr.Bits, bits, .monotonic).want_analysis); // otherwise we wouldn't be resolving `nav` at all + @atomicStore(Nav.Repr.Bits, bits, .{ + .@"align" = resolved.@"align", + .@"addrspace" = resolved.@"addrspace", + .@"const" = resolved.@"const", + .@"threadlocal" = resolved.@"threadlocal", + .is_extern_decl = resolved.is_extern_decl, + .want_analysis = true, // asserted above that this is already `true` + }, .monotonic); + + @atomicStore( + InternPool.Index, + &nav_types[unwrapped.index], + resolved.type, + .monotonic, + ); - var bits = nav_bits[unwrapped.index]; - bits.status = .fully_resolved; - bits.is_const = resolved.is_const; - bits.alignment = resolved.alignment; - bits.@"addrspace" = resolved.@"addrspace"; - @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release); + @atomicStore( + InternPool.Index, + &nav_values[unwrapped.index], + resolved.value, + .monotonic, + ); } pub fn createNamespace( @@ -11841,8 +11623,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { .error_set_error, .error_union_error, .enum_tag, - .variable, - .threadlocal_variable, .@"extern", .func_decl, .func_instance, @@ -11949,11 +11729,7 @@ pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index { } pub fn isUndef(ip: *const InternPool, val: Index) bool { - return val == .undef or val.unwrap(ip).getTag(ip) == .undef; -} - -pub fn isVariable(ip: *const InternPool, val: Index) bool { - return val.unwrap(ip).getTag(ip) == .variable; + return val.unwrap(ip).getTag(ip) == .undef; } pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Tag { @@ -12220,8 +11996,6 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId { .float_c_longdouble_f80, .float_c_longdouble_f128, .float_comptime_float, - .variable, - .threadlocal_variable, .@"extern", .func_decl, .func_instance, @@ -13001,11 +12775,17 @@ pub fn setWantNavAnalysis(ip: *InternPool, io: Io, nav_index: Nav.Index) bool { return false; } - const bits = &navs.items(.bits)[unwrapped.index]; - if (bits.want_analysis) { - return false; - } else { - bits.want_analysis = true; - return true; - } + // Mutate `bits` atomically so that we don't introduce an illegal data race with `getNav`. + const old_bits = @atomicRmw( + Nav.Repr.Bits, + &navs.items(.bits)[unwrapped.index], + .Or, + mask: { + var mask: Nav.Repr.Bits = @bitCast(@as(u16, 0)); + mask.want_analysis = true; + break :mask mask; + }, + .monotonic, + ); + return !old_bits.want_analysis; } diff --git a/src/Sema.zig b/src/Sema.zig @@ -2276,28 +2276,26 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) ?Value { assert(inst != .none); if (inst.toInterned()) |ip_index| { - const val: Value = .fromInterned(ip_index); - assert(val.getVariable(zcu) == null); - return val; - } else { - // Runtime-known value. - const air_tags = sema.air_instructions.items(.tag); - switch (air_tags[@intFromEnum(inst.toIndex().?)]) { - .inferred_alloc => unreachable, // assertion failure - .inferred_alloc_comptime => unreachable, // assertion failure - else => {}, - } - // LLVM fails to eliminate this `classify` call in ReleaseFast, which hurts performance, so - // we must explicitly check for `std.debug.runtime_safety`. - if (std.debug.runtime_safety) switch (sema.typeOf(inst).classify(zcu)) { - .no_possible_value => unreachable, // values of this type do not exist - .one_possible_value => unreachable, // the value should be comptime-known - .partially_comptime => unreachable, // the value should be comptime-known - .fully_comptime => unreachable, // the value should be comptime-known - .runtime => {}, - }; - return null; + return .fromInterned(ip_index); } + + // Runtime-known value. We'll be returning `null`, but first, some assertions. + const air_tags = sema.air_instructions.items(.tag); + switch (air_tags[@intFromEnum(inst.toIndex().?)]) { + .inferred_alloc => unreachable, // assertion failure + .inferred_alloc_comptime => unreachable, // assertion failure + else => {}, + } + // LLVM fails to eliminate this `classify` call in ReleaseFast, which hurts performance, so + // we must explicitly check for `std.debug.runtime_safety`. + if (std.debug.runtime_safety) switch (sema.typeOf(inst).classify(zcu)) { + .no_possible_value => unreachable, // values of this type do not exist + .one_possible_value => unreachable, // the value should be comptime-known + .partially_comptime => unreachable, // the value should be comptime-known + .fully_comptime => unreachable, // the value should be comptime-known + .runtime => {}, + }; + return null; } /// Like `resolveValue`, but emits an error if the value is not comptime-known. @@ -5738,8 +5736,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void .uav => |uav| .{ .uav = uav.val }, .nav => |orig_nav| target: { try sema.ensureNavResolved(block, src, orig_nav, .fully); - const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).status.fully_resolved.val)) { - .variable => |v| v.owner_nav, + const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).resolved.?.value)) { .@"extern" => |e| e.owner_nav, .func => |f| f.owner_nav, else => orig_nav, @@ -5778,7 +5775,7 @@ pub fn analyzeExportSelfNav( const ip = &zcu.intern_pool; const orig_nav = sema.owner.unwrap().nav_val; - const export_val: Value = .fromInterned(ip.getNav(orig_nav).status.fully_resolved.val); + const export_val: Value = .fromInterned(ip.getNav(orig_nav).resolved.?.value); const export_ty = export_val.typeOf(zcu); if (!export_ty.validateExtern(.other, zcu)) { @@ -5792,7 +5789,6 @@ pub fn analyzeExportSelfNav( } const export_nav = switch (ip.indexToKey(export_val.toIntern())) { - .variable => |v| v.owner_nav, .@"extern" => |e| e.owner_nav, .func => |f| export_nav: { assert(export_ty.fnHasRuntimeBits(zcu)); // otherwise `validateExtern` failed above @@ -30005,7 +30001,7 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: const nav = ip.getNav(nav_index); if (nav.analysis == null) { - assert(nav.status == .fully_resolved); + assert(nav.resolved.?.value != .none); return; } @@ -30066,11 +30062,20 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde try sema.ensureNavResolved(block, src, orig_nav_index, if (is_ref) .type else .fully); const nav_index = nav: { - if (ip.getNav(orig_nav_index).isExternOrFn(ip)) { - // Getting a pointer to this `Nav` might mean we actually get a pointer to something else! - // We need to resolve the value to know for sure. - if (is_ref) try sema.ensureNavResolved(block, src, orig_nav_index, .fully); - switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) { + const orig_nav = ip.getNav(orig_nav_index); + if (orig_nav.resolved.?.is_extern_decl or ip.zigTypeTag(orig_nav.resolved.?.type) == .@"fn") { + // A pointer to this `Nav` might actually be encoded as a pointer to a different `Nav` + // because this is either an `extern` definition or an `extern` alias. (The latter case + // is unsolved language weirdness; see https://github.com/ziglang/zig/issues/21027.) To + // know for sure how to encode this pointer, we need to check the *value* of this `Nav`. + const orig_nav_value = switch (is_ref) { + false => orig_nav.resolved.?.value, + true => orig_val: { + try sema.ensureNavResolved(block, src, orig_nav_index, .fully); + break :orig_val ip.getNav(orig_nav_index).resolved.?.value; + }, + }; + switch (ip.indexToKey(orig_nav_value)) { .func => |f| break :nav f.owner_nav, .@"extern" => |e| break :nav e.owner_nav, else => {}, @@ -30079,33 +30084,31 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde break :nav orig_nav_index; }; - const nav_status = ip.getNav(nav_index).status; + const nav_resolved = ip.getNav(nav_index).resolved.?; - const is_runtime = switch (nav_status) { - .unresolved => unreachable, - // dllimports go straight to `fully_resolved`; the only option is threadlocal - .type_resolved => |r| r.is_threadlocal, - .fully_resolved => |r| switch (ip.indexToKey(r.val)) { - .@"extern" => |e| e.is_threadlocal or e.is_dll_import or switch (e.relocation) { - .any => false, - .pcrel => true, - }, - .variable => |v| v.is_threadlocal, - else => false, - }, + const is_runtime: bool = runtime: { + if (nav_resolved.@"threadlocal") break :runtime true; + if (nav_resolved.value == .none) { + // This didn't come from `@extern`, so even if extern it couldn't be dllimport or pcrel. + break :runtime false; + } + const @"extern" = switch (ip.indexToKey(nav_resolved.value)) { + .@"extern" => |e| e, + else => break :runtime false, + }; + if (@"extern".is_dll_import) break :runtime true; + break :runtime switch (@"extern".relocation) { + .any => false, + .pcrel => true, + }; }; - const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) { - .unresolved => unreachable, - .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const }, - .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const }, - }; const ptr_ty = try pt.ptrType(.{ - .child = ty, + .child = nav_resolved.type, .flags = .{ - .alignment = alignment, - .is_const = is_const, - .address_space = @"addrspace", + .alignment = nav_resolved.@"align", + .is_const = nav_resolved.@"const", + .address_space = nav_resolved.@"addrspace", }, }); @@ -30140,7 +30143,7 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_i // If it is, we can resolve the *value*, and queue analysis as needed. try sema.ensureNavResolved(block, src, nav_index, .type); - const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip)); + const nav_ty: Type = .fromInterned(ip.getNav(nav_index).resolved.?.type); if (nav_ty.zigTypeTag(zcu) != .@"fn") return; if (!nav_ty.fnHasRuntimeBits(zcu)) return; @@ -34006,7 +34009,7 @@ pub fn getBuiltin(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError } pub const NavPtrModifiers = struct { - alignment: Alignment, + @"align": Alignment, @"linksection": InternPool.OptionalNullTerminatedString, @"addrspace": std.builtin.AddressSpace, }; @@ -34029,7 +34032,7 @@ pub fn resolveNavPtrModifiers( const section_src = block.src(.{ .node_offset_var_decl_section = .zero }); const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = .zero }); - const alignment: InternPool.Alignment = a: { + const @"align": InternPool.Alignment = a: { const align_body = zir_decl.align_body orelse break :a .none; const align_ref = try sema.resolveInlineBody(block, align_body, decl_inst); break :a try sema.analyzeAsAlign(block, align_src, align_ref); @@ -34067,7 +34070,7 @@ pub fn resolveNavPtrModifiers( }; return .{ - .alignment = alignment, + .@"align" = @"align", .@"linksection" = @"linksection", .@"addrspace" = @"addrspace", }; diff --git a/src/Sema/bitcast.zig b/src/Sema/bitcast.zig @@ -253,7 +253,6 @@ const UnpackValueBits = struct { .func_type, .error_set_type, .inferred_error_set_type, - .variable, .@"extern", .func, .err, diff --git a/src/Sema/comptime_ptr_access.zig b/src/Sema/comptime_ptr_access.zig @@ -225,19 +225,17 @@ fn loadComptimePtrInner( }; const base_val: MutableValue = switch (ptr.base_addr) { - .nav => |nav| val: { - try sema.ensureNavResolved(block, src, nav, .fully); - const val = ip.getNav(nav).status.fully_resolved.val; - switch (ip.indexToKey(val)) { - .variable => return .runtime_load, - // We let `.@"extern"` through here if it's a function. - // This allows you to alias `extern fn`s. - .@"extern" => |e| if (Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn") - break :val .{ .interned = val } - else - return .runtime_load, - else => break :val .{ .interned = val }, + .nav => |nav_id| val: { + try sema.ensureNavResolved(block, src, nav_id, .fully); + const nav = ip.getNav(nav_id); + if (!nav.resolved.?.@"const") return .runtime_load; + // We let `.@"extern"` through here if it's a fn. This allows aliasing `extern fn`s. + if (ip.indexToKey(nav.resolved.?.value) == .@"extern" and + Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu) != .@"fn") + { + return .runtime_load; } + break :val .{ .interned = nav.resolved.?.value }; }, .comptime_alloc => |alloc_index| sema.getComptimeAlloc(alloc_index).val, .uav => |uav| .{ .interned = uav.val }, diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig @@ -115,7 +115,6 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, diff --git a/src/Type.zig b/src/Type.zig @@ -239,7 +239,6 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -675,7 +674,6 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari // values, not types .simple_value, - .variable, .@"extern", .func, .int, @@ -814,7 +812,6 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -1046,7 +1043,6 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -1187,7 +1183,6 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -1311,7 +1306,6 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -1867,7 +1861,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -2162,7 +2155,6 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -3284,7 +3276,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { // values, not types .simple_value, - .variable, .@"extern", .func, .int, @@ -3362,7 +3353,6 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn // values, not types .simple_value, - .variable, .@"extern", .func, .int, diff --git a/src/Value.zig b/src/Value.zig @@ -176,13 +176,6 @@ pub fn getFunction(val: Value, zcu: *Zcu) ?InternPool.Key.Func { }; } -pub fn getVariable(val: Value, mod: *Zcu) ?InternPool.Key.Variable { - return switch (mod.intern_pool.indexToKey(val.toIntern())) { - .variable => |variable| variable, - else => null, - }; -} - /// Asserts the value is a (defined) integer and it fits in a u64. pub fn toUnsignedInt(val: Value, zcu: *const Zcu) u64 { return getUnsignedInt(val, zcu).?; @@ -808,7 +801,6 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool { pub fn pointerNav(val: Value, zcu: *const Zcu) ?InternPool.Nav.Index { return switch (zcu.intern_pool.indexToKey(val.toIntern())) { // TODO: these 3 cases are weird; these aren't pointer values! - .variable => |v| v.owner_nav, .@"extern" => |e| e.owner_nav, .func => |func| func.owner_nav, .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { @@ -2539,7 +2531,7 @@ pub fn intFitsInType( .zero_usize, .zero_u8 => return true, else => switch (zcu.intern_pool.indexToKey(val.toIntern())) { .undef => return true, - .variable, .@"extern", .func, .ptr => { + .@"extern", .func, .ptr => { const target = zcu.getTarget(); const ptr_bits = target.ptrBitWidth(); return switch (info.signedness) { diff --git a/src/Zcu.zig b/src/Zcu.zig @@ -723,11 +723,7 @@ pub const Exported = union(enum) { pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment { return switch (exported) { - .nav => |nav| switch (zcu.intern_pool.getNav(nav).status) { - .unresolved => unreachable, - .type_resolved => |r| r.alignment, - .fully_resolved => |r| r.alignment, - }, + .nav => |nav| zcu.intern_pool.getNav(nav).resolved.?.@"align", .uav => .none, }; } @@ -4252,8 +4248,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanag } } // Non-fatal AstGen errors could mean this test decl failed - if (nav.status == .fully_resolved) { - const gop = try units.getOrPut(gpa, .wrap(.{ .func = nav.status.fully_resolved.val })); + if (nav.resolved != null and nav.resolved.?.value != .none) { + const gop = try units.getOrPut(gpa, .wrap(.{ .func = nav.resolved.?.value })); if (!gop.found_existing) gop.value_ptr.* = referencer; } } @@ -4419,7 +4415,7 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 { } pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value { - return Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.fully_resolved.val); + return .fromInterned(zcu.intern_pool.getNav(nav_index).resolved.?.value); } pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index { @@ -4431,14 +4427,12 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); } -pub fn navAlignment(zcu: *Zcu, nav_index: InternPool.Nav.Index) InternPool.Alignment { - const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) { - .unresolved => unreachable, - .type_resolved => |r| .{ .fromInterned(r.type), r.alignment }, - .fully_resolved => |r| .{ Value.fromInterned(r.val).typeOf(zcu), r.alignment }, +pub fn navAlignment(zcu: *Zcu, nav_id: InternPool.Nav.Index) InternPool.Alignment { + const resolved = zcu.intern_pool.getNav(nav_id).resolved.?; + return switch (resolved.@"align") { + else => |a| a, + .none => Type.fromInterned(resolved.type).abiAlignment(zcu), }; - if (alignment != .none) return alignment; - return ty.abiAlignment(zcu); } pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) { diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig @@ -1584,10 +1584,6 @@ pub fn ensureNavValUpToDate( try zcu.ensureNavValAnalysisQueued(nav_id); - // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the - // status is `.unresolved`, which indicates that the value is outdated because it has *never* - // been analyzed so far. - // // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to // ensure that the unit is definitely up-to-date when this function returns. This mechanism could // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by @@ -1603,7 +1599,7 @@ pub fn ensureNavValUpToDate( } else { // We can trust the current information about this unit. if (prev_failed) return error.AnalysisFail; - assert(nav.status == .fully_resolved); + assert(nav.resolved.?.value != .none); return; } @@ -1740,7 +1736,7 @@ fn analyzeNavVal( const maybe_ty: ?Type = if (zir_decl.type_body != null) ty: { // Since we have a type body, the type is resolved separately! try sema.ensureNavResolved(&block, init_src, nav_id, .type); - break :ty .fromInterned(ip.getNav(nav_id).typeOf(ip)); + break :ty .fromInterned(ip.getNav(nav_id).resolved.?.type); } else null; const final_val: ?Value = if (zir_decl.value_body) |value_body| val: { @@ -1786,14 +1782,12 @@ fn analyzeNavVal( const modifiers: Sema.NavPtrModifiers = if (zir_decl.type_body != null) m: { // `analyzeNavType` (from the `ensureNavTypeUpToDate` call above) has already populated this data into // the `Nav`. Load the new one, and pull the modifiers out. - switch (ip.getNav(nav_id).status) { - .unresolved => unreachable, // `analyzeNavType` will never leave us in this state - inline .type_resolved, .fully_resolved => |r| break :m .{ - .alignment = r.alignment, - .@"linksection" = r.@"linksection", - .@"addrspace" = r.@"addrspace", - }, - } + const r = ip.getNav(nav_id).resolved.?; + break :m .{ + .@"align" = r.@"align", + .@"linksection" = r.@"linksection", + .@"addrspace" = r.@"addrspace", + }; } else m: { // `analyzeNavType` is essentially a stub which calls us. We are responsible for resolving this data. break :m try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, nav_ty); @@ -1803,15 +1797,7 @@ fn analyzeNavVal( // This isn't necessarily the same as `final_val`! const nav_val: Value = switch (zir_decl.linkage) { - .normal, .@"export" => switch (zir_decl.kind) { - .@"var" => .fromInterned(try pt.intern(.{ .variable = .{ - .ty = nav_ty.toIntern(), - .init = final_val.?.toIntern(), - .owner_nav = nav_id, - .is_threadlocal = zir_decl.is_threadlocal, - } })), - else => final_val.?, - }, + .normal, .@"export" => final_val.?, .@"extern" => val: { assert(final_val == null); // extern decls do not have a value body const lib_name: ?[]const u8 = if (zir_decl.lib_name != .empty) l: { @@ -1832,7 +1818,7 @@ fn analyzeNavVal( .relocation = .any, .decoration = null, .is_const = is_const, - .alignment = modifiers.alignment, + .alignment = modifiers.@"align", .@"addrspace" = modifiers.@"addrspace", .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction .owner_nav = undefined, // ignored by `getExtern` @@ -1852,11 +1838,7 @@ fn analyzeNavVal( const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) { .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen - .variable => |v| .{ v.owner_nav == nav_id, false }, - .@"extern" => |e| .{ - false, - Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn" and zir_decl.linkage == .@"extern", - }, + .@"extern" => .{ false, nav_ty.zigTypeTag(zcu) == .@"fn" and zir_decl.linkage == .@"extern" }, else => .{ true, false }, }; @@ -1895,23 +1877,22 @@ fn analyzeNavVal( info.last_update_gen = zcu.generation; info.deps.clearRetainingCapacity(); } - const type_changed: bool = switch (old_nav.status) { - .unresolved => true, - .type_resolved => |old| old.type != nav_ty.toIntern(), - .fully_resolved => |old| ip.typeOf(old.val) != nav_ty.toIntern(), - }; + const type_changed: bool = if (old_nav.resolved) |r| r.type != nav_ty.toIntern() else true; if (type_changed) { try zcu.markDependeeOutdated(.marked_po, .{ .nav_ty = nav_id }); } else { try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav_id }); } } - ip.resolveNavValue(io, nav_id, .{ - .val = nav_val.toIntern(), - .is_const = is_const, - .alignment = modifiers.alignment, + ip.resolveNav(io, nav_id, .{ + .type = nav_ty.toIntern(), + .@"align" = modifiers.@"align", .@"linksection" = modifiers.@"linksection", .@"addrspace" = modifiers.@"addrspace", + .@"const" = is_const, + .@"threadlocal" = zir_decl.is_threadlocal, + .is_extern_decl = zir_decl.linkage == .@"extern", + .value = nav_val.toIntern(), }); if (zir_decl.linkage == .@"export") { @@ -1943,9 +1924,10 @@ fn analyzeNavVal( try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern()); } - return switch (old_nav.status) { - .unresolved, .type_resolved => .{ .val_changed = true }, - .fully_resolved => |old| .{ .val_changed = old.val != nav_val.toIntern() }, + return if (old_nav.resolved) |old_resolved| .{ + .val_changed = old_resolved.value != nav_val.toIntern(), + } else .{ + .val_changed = true, }; } @@ -1971,10 +1953,6 @@ pub fn ensureNavTypeUpToDate( try zcu.ensureNavValAnalysisQueued(nav_id); - // Determine whether or not this `Nav`'s type is outdated. This also includes checking if the - // status is `.unresolved`, which indicates that the value is outdated because it has *never* - // been analyzed so far. - // // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to // ensure that the unit is definitely up-to-date when this function returns. This mechanism could // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by @@ -1990,7 +1968,7 @@ pub fn ensureNavTypeUpToDate( } else { // We can trust the current information about this unit. if (prev_failed) return error.AnalysisFail; - assert(nav.status != .unresolved); + assert(nav.resolved != null); return; } @@ -2124,24 +2102,16 @@ fn analyzeNavType( // the previous update. As such, after this call, we will be able to determine whether the // type changed. try sema.ensureNavResolved(&block, init_src, nav_id, .fully); - const new = ip.getNav(nav_id).status.fully_resolved; - const new_is_extern_decl = ip.indexToKey(new.val) == .@"extern"; - const changed = switch (old_nav.status) { - .unresolved => true, - .type_resolved => |r| r.type != ip.typeOf(new.val) or - r.alignment != new.alignment or - r.@"linksection" != new.@"linksection" or - r.@"addrspace" != new.@"addrspace" or - r.is_const != new.is_const or - r.is_extern_decl != new_is_extern_decl, - .fully_resolved => |r| ip.typeOf(r.val) != ip.typeOf(new.val) or - r.alignment != new.alignment or - r.@"linksection" != new.@"linksection" or - r.@"addrspace" != new.@"addrspace" or - r.is_const != new.is_const or - (old_nav.getExtern(ip) != null) != new_is_extern_decl, - }; - return .{ .type_changed = changed }; + const new = ip.getNav(nav_id).resolved.?; + return if (old_nav.resolved) |old| .{ + .type_changed = old.type != new.type or + old.@"align" != new.@"align" or + old.@"linksection" != new.@"linksection" or + old.@"addrspace" != new.@"addrspace" or + old.@"const" != new.@"const" or + old.@"threadlocal" != new.@"threadlocal" or + old.is_extern_decl != new.is_extern_decl, + } else .{ .type_changed = true }; }; block.comptime_reason = .{ .reason = .{ @@ -2169,37 +2139,34 @@ fn analyzeNavType( const is_extern_decl = zir_decl.linkage == .@"extern"; - // Now for the question of the day: are the type and modifiers the same as before? - // If they are, then we should actually keep the `Nav` as `fully_resolved` if it currently is. - // That's because `analyzeNavVal` will later want to look at the resolved value to figure out - // whether it's changed: if we threw that data away now, it would have to assume that the value - // had changed, potentially spinning off loads of unnecessary re-analysis! - const changed = switch (old_nav.status) { - .unresolved => true, - .type_resolved => |r| r.type != resolved_ty.toIntern() or - r.alignment != modifiers.alignment or - r.@"linksection" != modifiers.@"linksection" or - r.@"addrspace" != modifiers.@"addrspace" or - r.is_const != is_const or - r.is_extern_decl != is_extern_decl, - .fully_resolved => |r| ip.typeOf(r.val) != resolved_ty.toIntern() or - r.alignment != modifiers.alignment or - r.@"linksection" != modifiers.@"linksection" or - r.@"addrspace" != modifiers.@"addrspace" or - r.is_const != is_const or - (old_nav.getExtern(ip) != null) != is_extern_decl, - }; + // Now for the question of the day: are the type and modifiers the same as before? If they are, + // then we should actually avoid calling `ip.resolveNav`. This is because `analyzeNavVal` will + // later wanmt to look at the resolved *value* to figure out whether *that* has changed: if we + // threw that data away now, it would have to assume the value *had* changed even if it actually + // hadn't, which could spin off a bunch of unnecessary re-analysis! OTOH, if the type *has* + // changed, then we obviously know that the value will also have changed, so resetting the value + // to `.none` is fine in that case. + const changed: bool = if (old_nav.resolved) |old| changed: { + break :changed old.type != resolved_ty.toIntern() or + old.@"align" != modifiers.@"align" or + old.@"linksection" != modifiers.@"linksection" or + old.@"addrspace" != modifiers.@"addrspace" or + old.@"const" != is_const or + old.@"threadlocal" != zir_decl.is_threadlocal or + old.is_extern_decl != is_extern_decl; + } else true; if (!changed) return .{ .type_changed = false }; - ip.resolveNavType(io, nav_id, .{ + ip.resolveNav(io, nav_id, .{ .type = resolved_ty.toIntern(), - .is_const = is_const, - .alignment = modifiers.alignment, + .@"align" = modifiers.@"align", .@"linksection" = modifiers.@"linksection", .@"addrspace" = modifiers.@"addrspace", - .is_threadlocal = zir_decl.is_threadlocal, + .@"const" = is_const, + .@"threadlocal" = zir_decl.is_threadlocal, .is_extern_decl = is_extern_decl, + .value = .none, }); return .{ .type_changed = true }; @@ -3358,13 +3325,13 @@ fn analyzeFuncBodyInner( if (func.generic_owner == .none) { try pt.ensureNavValUpToDate(func.owner_nav, reason); - if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) { + if (ip.getNav(func.owner_nav).resolved.?.value != func_index) { return error.AnalysisFail; } } else { const go_nav = zcu.funcInfo(func.generic_owner).owner_nav; try pt.ensureNavValUpToDate(go_nav, reason); - if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) { + if (ip.getNav(go_nav).resolved.?.value != func.generic_owner) { return error.AnalysisFail; } } @@ -3757,9 +3724,9 @@ fn processExportsInner( if (zcu.failed_analysis.contains(unit)) break :failed true; if (zcu.transitive_failed_analysis.contains(unit)) break :failed true; } - const val = switch (nav.status) { - .unresolved, .type_resolved => break :failed true, - .fully_resolved => |r| Value.fromInterned(r.val), + const val: Value = switch ((nav.resolved orelse break :failed true).value) { + .none => break :failed true, + else => |val| .fromInterned(val), }; // If the value is a function, we also need to check if that function succeeded analysis. if (val.typeOf(zcu).zigTypeTag(zcu) == .@"fn") { @@ -3805,14 +3772,16 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void { if (builtin_root_type == .none) return; // `@import("builtin")` never analyzed const builtin_namespace = Type.fromInterned(builtin_root_type).getNamespace(zcu).unwrap().?; // We know that the namespace has a `test_functions`... - const nav_index = zcu.namespacePtr(builtin_namespace).pub_decls.getKeyAdapted( + const test_fns_nav_index = zcu.namespacePtr(builtin_namespace).pub_decls.getKeyAdapted( try ip.getOrPutString(gpa, io, pt.tid, "test_functions", .no_embedded_nulls), Zcu.Namespace.NameAdapter{ .zcu = zcu }, ).?; + const test_fns_nav = ip.getNav(test_fns_nav_index); // ...but it might not be populated, so let's check that! - if (zcu.failed_analysis.contains(.wrap(.{ .nav_val = nav_index })) or - zcu.transitive_failed_analysis.contains(.wrap(.{ .nav_val = nav_index })) or - ip.getNav(nav_index).status != .fully_resolved) + if (zcu.failed_analysis.contains(.wrap(.{ .nav_val = test_fns_nav_index })) or + zcu.transitive_failed_analysis.contains(.wrap(.{ .nav_val = test_fns_nav_index })) or + test_fns_nav.resolved == null or + test_fns_nav.resolved.?.value == .none) { // The value of `builtin.test_functions` was either never referenced, or failed analysis. // Either way, we don't need to do anything. @@ -3822,8 +3791,7 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void { // Okay, `builtin.test_functions` is (potentially) referenced and valid. Our job now is to swap // its placeholder `&.{}` value for the actual list of all test functions. - const test_fns_val = zcu.navValue(nav_index); - const test_fn_ty = test_fns_val.typeOf(zcu).slicePtrFieldType(zcu).childType(zcu); + const test_fn_ty = Type.fromInterned(test_fns_nav.resolved.?.type).slicePtrFieldType(zcu).childType(zcu); const array_anon_decl: InternPool.Key.Ptr.BaseAddr.Uav = array: { // Add zcu.test_functions to an array decl then make the test_functions @@ -3914,10 +3882,12 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void { } }), .len = (try pt.intValue(Type.usize, zcu.test_functions.count())).toIntern(), } }); - ip.mutateVarInit(io, test_fns_val.toIntern(), new_init); + var new_resolved_test_fns = test_fns_nav.resolved.?; + new_resolved_test_fns.value = new_init; + ip.resolveNav(io, test_fns_nav_index, new_resolved_test_fns); } // The linker thread is not running, so we actually need to dispatch this task directly. - @import("../link.zig").linkTestFunctionsNav(pt, nav_index); + @import("../link.zig").linkTestFunctionsNav(pt, test_fns_nav_index); } /// Stores an error in `pt.zcu.failed_files` for this file, and sets the file @@ -4402,17 +4372,13 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 { pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type { const zcu = pt.zcu; const ip = &zcu.intern_pool; - const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) { - .unresolved => unreachable, - .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const }, - .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const }, - }; + const resolved_nav = ip.getNav(nav_id).resolved.?; return pt.ptrType(.{ - .child = ty, + .child = resolved_nav.type, .flags = .{ - .alignment = alignment, - .address_space = @"addrspace", - .is_const = is_const, + .alignment = resolved_nav.@"align", + .address_space = resolved_nav.@"addrspace", + .is_const = resolved_nav.@"const", }, }); } diff --git a/src/codegen.zig b/src/codegen.zig @@ -352,7 +352,6 @@ pub fn generateSymbol( else => unreachable, }), }, - .variable, .@"extern", .func, .enum_literal, @@ -787,7 +786,7 @@ fn lowerNavRef( const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8); const is_obj = lf.comp.config.output_mode == .Obj; - const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip)); + const nav_ty = Type.fromInterned(ip.getNav(nav_index).resolved.?.type); if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) { try w.splatByteAll(0xaa, ptr_width_bytes); @@ -876,10 +875,11 @@ pub fn genNavRef( const nav = ip.getNav(nav_index); log.debug("genNavRef({f})", .{nav.fqn.fmt(ip)}); - const lib_name, const linkage, const is_threadlocal = if (nav.getExtern(ip)) |e| - .{ e.lib_name, e.linkage, e.is_threadlocal and zcu.comp.config.any_non_single_threaded } + const is_threadlocal = nav.resolved.?.@"threadlocal" and zcu.comp.config.any_non_single_threaded; + const lib_name, const linkage = if (nav.getExtern(ip)) |e| + .{ e.lib_name, e.linkage } else - .{ .none, .internal, false }; + .{ .none, .internal }; if (lf.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; switch (linkage) { @@ -1038,7 +1038,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo .nav => |nav_index| { const nav = ip.getNav(nav_index); - const nav_ty: Type = .fromInterned(nav.typeOf(ip)); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) or nav.getExtern(ip) != null) { return .{ .lea_nav = nav_index }; } else { diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig @@ -69,7 +69,7 @@ pub fn emit( const target = &mod.resolved_target.result; mir_log.debug("{f}:", .{nav.fqn.fmt(ip)}); - const func_align = switch (nav.status.fully_resolved.alignment) { + const func_align = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), .ReleaseSmall => target_util.minFunctionAlignment(target), diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig @@ -7207,7 +7207,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; const ty_nav = air.data(air.inst_index).ty_nav; - if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) { + if (ZigType.fromInterned(ip.getNav(ty_nav.nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) { false => { try isel.nav_relocs.append(gpa, .{ .nav = ty_nav.nav, @@ -10577,7 +10577,6 @@ pub const Value = struct { => continue :type_key .{ .simple_type = .anyerror }, .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -10914,7 +10913,7 @@ pub const Value = struct { .ptr => |ptr| { assert(offset == 0 and size == 8); break :free switch (ptr.base_addr) { - .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) { + .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) { false => { try isel.nav_relocs.append(zcu.gpa, .{ .nav = nav, @@ -12300,7 +12299,6 @@ pub const CallAbiIterator = struct { => continue :type_key .{ .simple_type = .anyerror }, .undef, .simple_value, - .variable, .@"extern", .func, .int, diff --git a/src/codegen/c.zig b/src/codegen/c.zig @@ -669,11 +669,9 @@ pub const DeclGen = struct { return dg.renderUndefValue(w, ptr_ty, location); } - // Chase function values in order to be able to reference the original function. switch (ip.indexToKey(uav.val)) { - .variable => unreachable, - .func => |func| return dg.renderNav(w, func.owner_nav, location), - .@"extern" => |@"extern"| return dg.renderNav(w, @"extern".owner_nav, location), + .func => unreachable, + .@"extern" => unreachable, else => {}, } @@ -721,10 +719,9 @@ pub const DeclGen = struct { const ip = &zcu.intern_pool; // Chase function values in order to be able to reference the original function. - const owner_nav = switch (ip.getNav(nav_index).status) { - .unresolved => unreachable, - .type_resolved => nav_index, // this can't be an extern or a function - .fully_resolved => |r| switch (ip.indexToKey(r.val)) { + const owner_nav = switch (ip.getNav(nav_index).resolved.?.value) { + .none => nav_index, // this can't be an extern or a function + else => |value| switch (ip.indexToKey(value)) { .func => |f| f.owner_nav, .@"extern" => |e| e.owner_nav, else => nav_index, @@ -732,7 +729,7 @@ pub const DeclGen = struct { }; // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. - const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip)); + const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).resolved.?.type); const ptr_ty = try pt.navPtrType(owner_nav); if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { return dg.renderUndefValue(w, ptr_ty, location); @@ -924,7 +921,6 @@ pub const DeclGen = struct { .false => try w.writeAll("false"), .true => try w.writeAll("true"), }, - .variable, .@"extern", .func, .enum_literal, @@ -1575,7 +1571,6 @@ pub const DeclGen = struct { .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -2276,13 +2271,13 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E try f.dg.renderFunctionSignature( fwd_decl_writer, nav_val, - nav.status.fully_resolved.alignment, + nav.resolved.?.@"align", .forward_decl, .{ .nav = nav_index }, ); try fwd_decl_writer.writeAll(";\n"); - if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s| + if (nav.resolved.?.@"linksection".toSlice(ip)) |s| try header_writer.print("zig_linksection_fn({f}) ", .{fmtStringLiteral(s, null)}); try f.dg.renderFunctionSignature( header_writer, @@ -2360,28 +2355,26 @@ pub fn genDecl(dg: *DeclGen, w: *Writer) Error!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(dg.owner_nav.unwrap().?); - const nav_ty: Type = .fromInterned(nav.typeOf(ip)); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); - const is_const: bool, const is_threadlocal: bool, const init_val: Value = switch (ip.indexToKey(nav.status.fully_resolved.val)) { - else => .{ true, false, .fromInterned(nav.status.fully_resolved.val) }, - .variable => |v| .{ false, v.is_threadlocal, .fromInterned(v.init) }, - .@"extern" => return, - }; + if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return; - if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s| { + const init_val: Value = .fromInterned(nav.resolved.?.value); + + if (nav.resolved.?.@"linksection".toSlice(ip)) |s| { try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)}); } // We don't bother underaligning---it's unnecessary and hurts compatibility. - const a = nav.status.fully_resolved.alignment; + const a = nav.resolved.?.@"align"; if (a != .none and a.compareStrict(.gt, nav_ty.abiAlignment(zcu))) { try w.print("zig_align({d}) ", .{a.toByteUnits().?}); } try genDeclValue(dg, w, .{ .name = .{ .nav = dg.owner_nav.unwrap().? }, - .@"const" = is_const, - .@"threadlocal" = is_threadlocal, + .@"const" = nav.resolved.?.@"const", + .@"threadlocal" = nav.resolved.?.@"threadlocal", .init_val = init_val, }); } @@ -2393,19 +2386,18 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(dg.owner_nav.unwrap().?); - const nav_ty: Type = .fromInterned(nav.typeOf(ip)); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); - const is_const: bool, const is_threadlocal: bool, const init_val: Value = switch (ip.indexToKey(nav.status.fully_resolved.val)) { - else => .{ true, false, .fromInterned(nav.status.fully_resolved.val) }, - .variable => |v| .{ false, v.is_threadlocal, .fromInterned(v.init) }, + const init_val: Value = switch (ip.indexToKey(nav.resolved.?.value)) { + else => .fromInterned(nav.resolved.?.value), .@"extern" => |@"extern"| switch (nav_ty.zigTypeTag(zcu)) { .@"fn" => { try w.writeAll("zig_extern "); try dg.renderFunctionSignature( w, - Value.fromInterned(nav.status.fully_resolved.val), - nav.status.fully_resolved.alignment, + .fromInterned(nav.resolved.?.value), + nav.resolved.?.@"align", .forward_decl, .{ .@"export" = .{ .main_name = nav.name, @@ -2422,15 +2414,15 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void { .weak => try w.print("zig_extern zig_weak_linkage zig_visibility({t}) ", .{@"extern".visibility}), .link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}), } - if (@"extern".is_threadlocal and !dg.mod.single_threaded) { + if (nav.resolved.?.@"threadlocal" and !dg.mod.single_threaded) { try w.writeAll("zig_threadlocal "); } try dg.renderTypeAndName( w, - .fromInterned(nav.typeOf(ip)), + .fromInterned(nav.resolved.?.type), .{ .nav = dg.owner_nav.unwrap().? }, - .{ .@"const" = @"extern".is_const }, - nav.getAlignment(), + .{ .@"const" = nav.resolved.?.@"const" }, + nav.resolved.?.@"align", ); try w.writeAll(";\n"); return; @@ -2439,15 +2431,15 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void { }; // We don't bother underaligning---it's unnecessary and hurts compatibility. - const a = nav.status.fully_resolved.alignment; + const a = nav.resolved.?.@"align"; if (a != .none and a.compareStrict(.gt, nav_ty.abiAlignment(zcu))) { try w.print("zig_align({d}) ", .{a.toByteUnits().?}); } try genDeclValueFwd(dg, w, .{ .name = .{ .nav = dg.owner_nav.unwrap().? }, - .@"const" = is_const, - .@"threadlocal" = is_threadlocal, + .@"const" = nav.resolved.?.@"const", + .@"threadlocal" = nav.resolved.?.@"threadlocal", .init_val = init_val, }); } @@ -2514,11 +2506,9 @@ pub fn genExports(dg: *DeclGen, w: *Writer, exported: Zcu.Exported, export_indic ); try w.writeAll(";\n"); }; - const is_const = switch (ip.indexToKey(exported_val.toIntern())) { - .func => unreachable, - .@"extern" => |@"extern"| @"extern".is_const, - .variable => false, - else => true, + const is_const = switch (exported) { + .nav => |nav| ip.getNav(nav).resolved.?.@"const", + .uav => true, }; for (export_indices) |export_index| { const @"export" = export_index.ptr(zcu); diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig @@ -990,7 +990,6 @@ pub const CType = union(enum) { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig @@ -1279,7 +1279,7 @@ pub const Object = struct { } }, &o.builder); } - if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |section| + if (nav.resolved.?.@"linksection".toSlice(ip)) |section| function_index.setSection(try o.builder.string(section), &o.builder); var deinit_wip = true; @@ -1487,7 +1487,7 @@ pub const Object = struct { const file = try o.getDebugFile(pt, file_scope); const line_number = zcu.navSrcLine(func.owner_nav) + 1; - const is_internal_linkage = ip.indexToKey(nav.status.fully_resolved.val) != .@"extern"; + const is_internal_linkage = ip.indexToKey(nav.resolved.?.value) != .@"extern"; const debug_decl_type = try o.getDebugType(pt, fn_ty); const subprogram = try o.builder.debugSubprogram( @@ -1662,7 +1662,7 @@ pub const Object = struct { .elf, .wasm => break :coff_export_flags, .coff => |*coff| coff, }; - if (!ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) break :coff_export_flags; + if (!ip.isFunctionType(ip.getNav(nav_index).resolved.?.type)) break :coff_export_flags; const flags = &coff.lld_export_flags; for (export_indices) |export_index| { const name = export_index.ptr(zcu).opts.name; @@ -2677,7 +2677,7 @@ pub const Object = struct { const gpa = o.gpa; const nav = ip.getNav(nav_index); const owner_mod = zcu.navFileScope(nav_index).mod.?; - const ty: Type = .fromInterned(nav.typeOf(ip)); + const ty: Type = .fromInterned(nav.resolved.?.type); const gop = try o.nav_map.getOrPut(gpa, nav_index); if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function; @@ -2692,7 +2692,7 @@ pub const Object = struct { const function_index = try o.builder.addFunction( try o.lowerType(pt, ty), try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)), - toLlvmAddressSpace(nav.getAddrspace(), target), + toLlvmAddressSpace(nav.resolved.?.@"addrspace", target), ); gop.value_ptr.* = function_index.ptrConst(&o.builder).global; @@ -2809,8 +2809,8 @@ pub const Object = struct { } } - if (nav.getAlignment() != .none) - function_index.setAlignment(nav.getAlignment().toLlvm(), &o.builder); + if (nav.resolved.?.@"align" != .none) + function_index.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder); // Function attributes that are independent of analysis results of the function body. try o.addCommonFnAttributes( @@ -2951,15 +2951,12 @@ pub const Object = struct { const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import = switch (nav.status) { - .unresolved => unreachable, - .fully_resolved => |r| switch (ip.indexToKey(r.val)) { - .variable => |variable| .{ .internal, .default, variable.is_threadlocal, false }, - .@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import }, - else => .{ .internal, .default, false, false }, + const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_dll_import: bool = switch (nav.resolved.?.value) { + .none => .{ .internal, .default, false }, // this is a source declaration which is *not* marked `extern` + else => |val| switch (ip.indexToKey(val)) { + else => .{ .internal, .default, false }, + .@"extern" => |e| .{ e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import }, }, - // This means it's a source declaration which is not `extern`! - .type_resolved => |r| .{ .internal, .default, r.is_threadlocal, false }, }; const variable_index = try o.builder.addVariable( @@ -2968,8 +2965,8 @@ pub const Object = struct { .strong, .weak => nav.name, .link_once => unreachable, }.toSlice(ip)), - try o.lowerType(pt, Type.fromInterned(nav.typeOf(ip))), - toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()), + try o.lowerType(pt, .fromInterned(nav.resolved.?.type)), + toLlvmGlobalAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget()), ); gop.value_ptr.* = variable_index.ptrConst(&o.builder).global; @@ -2987,7 +2984,7 @@ pub const Object = struct { .link_once => unreachable, }, &o.builder); variable_index.setUnnamedAddr(.default, &o.builder); - if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded) + if (nav.resolved.?.@"threadlocal" and !zcu.navFileScope(nav_index).mod.?.single_threaded) variable_index.setThreadLocal(.generaldynamic, &o.builder); if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder); }, @@ -3422,7 +3419,6 @@ pub const Object = struct { // values, not types .undef, .simple_value, - .variable, .@"extern", .func, .int, @@ -3553,9 +3549,7 @@ pub const Object = struct { .false => .false, .true => .true, }, - .variable, - .enum_literal, - => unreachable, // non-runtime values + .enum_literal => unreachable, // non-runtime value .@"extern" => |@"extern"| { const function_index = try o.resolveLlvmFunction(pt, @"extern".owner_nav); return function_index.ptrConst(&o.builder).global.toConst(); @@ -4131,7 +4125,7 @@ pub const Object = struct { const nav = ip.getNav(nav_index); - const nav_ty = Type.fromInterned(nav.typeOf(ip)); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); const ptr_ty = try pt.navPtrType(nav_index); if (nav.getExtern(ip) == null and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) { @@ -4145,7 +4139,7 @@ pub const Object = struct { const llvm_val = try o.builder.convConst( llvm_global.toConst(), - try o.builder.ptrType(toLlvmAddressSpace(nav.getAddrspace(), zcu.getTarget())), + try o.builder.ptrType(toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget())), ); return o.builder.convConst(llvm_val, try o.lowerType(pt, ptr_ty)); @@ -4398,14 +4392,13 @@ pub const NavGen = struct { const ip = &zcu.intern_pool; const nav_index = ng.nav_index; const nav = ip.getNav(nav_index); - const resolved = nav.status.fully_resolved; + const resolved = nav.resolved.?; - const lib_name, const linkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) { - .variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, false, false, variable.init, variable.owner_nav }, - .@"extern" => |@"extern"| .{ @"extern".lib_name, @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav }, - else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index }, + const lib_name, const linkage, const visibility: Builder.Visibility, const is_dll_import, const init_val, const owner_nav = switch (ip.indexToKey(resolved.value)) { + else => .{ .none, .internal, .default, false, resolved.value, nav_index }, + .@"extern" => |e| .{ e.lib_name, e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import, .none, e.owner_nav }, }; - const ty = Type.fromInterned(nav.typeOf(ip)); + const ty: Type = .fromInterned(nav.resolved.?.type); if (linkage != .internal and ip.isFunctionType(ty.toIntern())) { const function_index = try o.resolveLlvmFunction(pt, owner_nav); @@ -4448,7 +4441,7 @@ pub const NavGen = struct { variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder); if (resolved.@"linksection".toSlice(ip)) |section| variable_index.setSection(try o.builder.string(section), &o.builder); - if (is_const) variable_index.setMutability(.constant, &o.builder); + if (resolved.@"const") variable_index.setMutability(.constant, &o.builder); try variable_index.setInitializer(switch (init_val) { .none => .no_init, else => try o.lowerValue(pt, init_val), @@ -4457,7 +4450,7 @@ pub const NavGen = struct { const file_scope = zcu.navFileScopeIndex(nav_index); const mod = zcu.fileByIndex(file_scope).mod.?; - if (is_threadlocal and !mod.single_threaded) + if (resolved.@"threadlocal" and !mod.single_threaded) variable_index.setThreadLocal(.generaldynamic, &o.builder); const line_number = zcu.navSrcLine(nav_index) + 1; @@ -5475,7 +5468,7 @@ pub const FuncGen = struct { _ = try self.wip.retVoid(); return; } - const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).typeOf(ip))).?; + const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).resolved.?.type)).?; if (!ret_ty.hasRuntimeBits(zcu)) { if (Type.fromInterned(fn_info.return_type).isError(zcu)) { // Functions with an empty error set are emitted with an error code @@ -5540,7 +5533,7 @@ pub const FuncGen = struct { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ptr_ty = self.typeOf(un_op); const ret_ty = ptr_ty.childType(zcu); - const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).typeOf(ip))).?; + const fn_info = zcu.typeToFunc(.fromInterned(ip.getNav(self.ng.nav_index).resolved.?.type)).?; if (!ret_ty.hasRuntimeBits(zcu)) { if (Type.fromInterned(fn_info.return_type).isError(zcu)) { // Functions with an empty error set are emitted with an error code diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig @@ -256,7 +256,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { .global => { const key = ip.indexToKey(val.toIntern()).@"extern"; - const storage_class = cg.module.storageClass(nav.getAddrspace()); + const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace"); assert(storage_class != .generic); // These should be instance globals const ty_id = try cg.resolveType(ty, .indirect); @@ -314,64 +314,47 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { try cg.module.debugName(result_id, nav.fqn.toSlice(ip)); }, .invocation_global => { - const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) { - .func => unreachable, - .variable => |variable| .fromInterned(variable.init), - .@"extern" => null, - else => val, - }; - const ty_id = try cg.resolveType(ty, .indirect); const ptr_ty_id = try cg.module.ptrType(ty_id, .function); - if (maybe_init_val) |init_val| { - // TODO: Combine with resolveAnonDecl? - const void_ty_id = try cg.resolveType(.void, .direct); - const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{}); - - const initializer_id = cg.module.allocId(); - try cg.prologue.emit(gpa, .OpFunction, .{ - .id_result_type = try cg.resolveType(.void, .direct), - .id_result = initializer_id, - .function_control = .{}, - .function_type = initializer_proto_ty_id, - }); + // TODO: Combine with resolveAnonDecl? + const void_ty_id = try cg.resolveType(.void, .direct); + const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{}); - const root_block_id = cg.module.allocId(); - try cg.prologue.emit(gpa, .OpLabel, .{ - .id_result = root_block_id, - }); - cg.block_label = root_block_id; + const initializer_id = cg.module.allocId(); + try cg.prologue.emit(gpa, .OpFunction, .{ + .id_result_type = try cg.resolveType(.void, .direct), + .id_result = initializer_id, + .function_control = .{}, + .function_type = initializer_proto_ty_id, + }); - const val_id = try cg.constant(ty, init_val, .indirect); - try cg.body.emit(gpa, .OpStore, .{ - .pointer = result_id, - .object = val_id, - }); + const root_block_id = cg.module.allocId(); + try cg.prologue.emit(gpa, .OpLabel, .{ + .id_result = root_block_id, + }); + cg.block_label = root_block_id; - try cg.body.emit(gpa, .OpReturn, {}); - try cg.body.emit(gpa, .OpFunctionEnd, {}); - try cg.module.sections.functions.append(gpa, cg.prologue); - try cg.module.sections.functions.append(gpa, cg.body); + const val_id = try cg.constant(ty, val, .indirect); + try cg.body.emit(gpa, .OpStore, .{ + .pointer = result_id, + .object = val_id, + }); - try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)}); + try cg.body.emit(gpa, .OpReturn, {}); + try cg.body.emit(gpa, .OpFunctionEnd, {}); + try cg.module.sections.functions.append(gpa, cg.prologue); + try cg.module.sections.functions.append(gpa, cg.body); - try cg.module.sections.globals.emit(gpa, .OpExtInst, .{ - .id_result_type = ptr_ty_id, - .id_result = result_id, - .set = try cg.module.importInstructionSet(.zig), - .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, - .id_ref_4 = &.{initializer_id}, - }); - } else { - try cg.module.sections.globals.emit(gpa, .OpExtInst, .{ - .id_result_type = ptr_ty_id, - .id_result = result_id, - .set = try cg.module.importInstructionSet(.zig), - .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, - .id_ref_4 = &.{}, - }); - } + try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)}); + + try cg.module.sections.globals.emit(gpa, .OpExtInst, .{ + .id_result_type = ptr_ty_id, + .id_result = result_id, + .set = try cg.module.importInstructionSet(.zig), + .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, + .id_ref_4 = &.{initializer_id}, + }); }, } @@ -810,7 +793,6 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { .undef => unreachable, // handled above - .variable, .@"extern", .func, .enum_literal, @@ -1170,12 +1152,11 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { const ip = &zcu.intern_pool; const ty_id = try cg.resolveType(ty, .direct); const nav = ip.getNav(nav_index); - const nav_ty: Type = .fromInterned(nav.typeOf(ip)); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); - switch (nav.status) { - .unresolved => unreachable, - .type_resolved => {}, // this is not a function or extern - .fully_resolved => |r| switch (ip.indexToKey(r.val)) { + switch (nav.resolved.?.value) { + .none => {}, // this is not a function or extern + else => |value| switch (ip.indexToKey(value)) { .func => { // TODO: Properly lower function pointers. For now we are going to hack around it and // just generate an empty pointer. Function pointers are represented by a pointer to usize. @@ -1196,7 +1177,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { const spv_decl_result_id = spv_decl.result_id; assert(spv_decl.kind != .func); - const storage_class = cg.module.storageClass(nav.getAddrspace()); + const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace"); try cg.addFunctionDep(spv_decl_index, storage_class); const nav_ty_id = try cg.resolveType(nav_ty, .indirect); diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig @@ -252,9 +252,9 @@ pub fn resolveNav(module: *Module, ip: *InternPool, nav_index: InternPool.Nav.In if (!entry.found_existing) { const nav = ip.getNav(nav_index); // TODO: Extern fn? - const kind: Decl.Kind = if (ip.isFunctionType(nav.typeOf(ip))) + const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type)) .func - else switch (nav.getAddrspace()) { + else switch (nav.resolved.?.@"addrspace") { .generic => .invocation_global, else => .global, }; diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig @@ -575,7 +575,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { .nav_ref => |nav_ref| { const zcu = cg.pt.zcu; const ip = &zcu.intern_pool; - if (ip.getNav(nav_ref.nav_index).isFn(ip)) { + if (ip.zigTypeTag(ip.getNav(nav_ref.nav_index).resolved.?.type) == .@"fn") { assert(nav_ref.offset == 0); try cg.mir_indirect_function_set.put(cg.gpa, nav_ref.nav_index, {}); try cg.addInst(.{ .tag = .func_ref, .data = .{ .nav_index = nav_ref.nav_index } }); @@ -4401,7 +4401,6 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { else => unreachable, } }, }, - .variable, .@"extern", .func, .enum_literal, diff --git a/src/codegen/wasm/Emit.zig b/src/codegen/wasm/Emit.zig @@ -970,7 +970,7 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32: const ip = &zcu.intern_pool; const gpa = comp.gpa; const is_obj = comp.config.output_mode == .Obj; - const nav_ty = ip.getNav(data.nav_index).typeOf(ip); + const nav_ty = ip.getNav(data.nav_index).resolved.?.type; assert(!ip.isFunctionType(nav_ty)); try code.ensureUnusedCapacity(gpa, 11); diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig @@ -173046,7 +173046,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .runtime_nav_ptr => { const ty_nav = air_datas[@intFromEnum(inst)].ty_nav; const nav = ip.getNav(ty_nav.nav); - const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip); + const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.resolved.?.@"threadlocal"; if (is_threadlocal) switch (cg.target.ofmt) { .elf => if (cg.mod.pic) { @@ -179146,7 +179146,7 @@ fn genSetMem( .off = disp, }).compare(.gte, src_align), .table, .rip_inst, .lazy_sym, .extern_func => unreachable, - .nav => |nav| ip.getNav(nav).getAlignment().compare(.gte, src_align), + .nav => |nav| ip.getNav(nav).resolved.?.@"align".compare(.gte, src_align), .uav => |uav| Type.fromInterned(uav.orig_ty).ptrAlignment(zcu).compare(.gte, src_align), })).write(self, .{ .base = base, diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig @@ -115,33 +115,26 @@ pub fn emitMir(emit: *Emit) Error!void { return error.EmitFail; }, }; - break :target switch (ip.getNav(nav).status) { - .unresolved => unreachable, - .type_resolved => |type_resolved| .{ + const resolved_nav = ip.getNav(nav).resolved.?; + if (resolved_nav.value != .none) switch (ip.indexToKey(resolved_nav.value)) { + .@"extern" => |@"extern"| break :target .{ .index = sym_index, - .is_extern = false, - .type = if (type_resolved.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol, - }, - .fully_resolved => |fully_resolved| switch (ip.indexToKey(fully_resolved.val)) { - .@"extern" => |@"extern"| .{ - .index = sym_index, - .is_extern = switch (@"extern".visibility) { - .default => true, - .hidden, .protected => false, - }, - .type = if (@"extern".is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol, - .force_pcrel_direct = switch (@"extern".relocation) { - .any => false, - .pcrel => true, - }, + .is_extern = switch (@"extern".visibility) { + .default => true, + .hidden, .protected => false, }, - .variable => |variable| .{ - .index = sym_index, - .is_extern = false, - .type = if (variable.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol, + .type = if (resolved_nav.@"threadlocal" and comp.config.any_non_single_threaded) .tlv else .symbol, + .force_pcrel_direct = switch (@"extern".relocation) { + .any => false, + .pcrel => true, }, - else => .{ .index = sym_index, .is_extern = false, .type = .symbol }, }, + else => {}, + }; + break :target .{ + .index = sym_index, + .is_extern = false, + .type = if (resolved_nav.@"threadlocal" and comp.config.any_non_single_threaded) .tlv else .symbol, }; }, .uav => |uav| .{ diff --git a/src/link.zig b/src/link.zig @@ -781,7 +781,7 @@ pub const File = struct { fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void { assert(base.comp.zcu.?.llvm_object == null); const nav = pt.zcu.intern_pool.getNav(nav_index); - assert(nav.status == .fully_resolved); + assert(nav.resolved.?.value != .none); switch (base.tag) { .lld => unreachable, .plan9 => unreachable, diff --git a/src/link/C.zig b/src/link/C.zig @@ -534,11 +534,11 @@ pub fn updateNav( const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - switch (ip.indexToKey(nav.status.fully_resolved.val)) { + switch (ip.indexToKey(nav.resolved.?.value)) { .func => return, .@"extern" => {}, else => { - const nav_ty: Type = .fromInterned(nav.typeOf(ip)); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); if (!nav_ty.hasRuntimeBits(zcu)) { if (c.navs.fetchSwapRemove(nav_index)) |kv| { var old_rendered = kv.value; @@ -762,7 +762,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog { const unit_references = try zcu.resolveReferences(); for (c.navs.keys()) |nav| { - const nav_val = ip.getNav(nav).status.fully_resolved.val; + const nav_val = ip.getNav(nav).resolved.?.value; const check_unit: ?InternPool.AnalUnit = switch (ip.indexToKey(nav_val)) { else => .wrap(.{ .nav_val = nav }), .func => .wrap(.{ .func = nav_val }), @@ -1092,8 +1092,9 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog // NAV forward declarations for (need_navs.keys()) |nav| { if (c.exported_navs.contains(nav)) continue; // the export was the declaration - if (ip.getNav(nav).getExtern(ip)) |e| { - if (export_names.contains(e.name)) continue; + switch (ip.indexToKey(ip.getNav(nav).resolved.?.value)) { + .@"extern" => |e| if (export_names.contains(e.name)) continue, + else => {}, } const fwd_decl = c.navs.getPtr(nav).?.fwd_decl; f.appendBufAssumeCapacity(fwd_decl.get(c)); @@ -1200,7 +1201,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog const code = c.navs.getPtr(nav).?.code; if (code.len == 0) continue; if (!c.exported_navs.contains(nav)) { - const is_extern = ip.getNav(nav).getExtern(ip) != null; + const is_extern = ip.indexToKey(ip.getNav(nav).resolved.?.value) == .@"extern"; f.appendBufAssumeCapacity(if (is_extern) "zig_extern " else "static "); } f.appendBufAssumeCapacity(code.get(c)); diff --git a/src/link/Coff.zig b/src/link/Coff.zig @@ -1226,34 +1226,26 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo fn navSection( coff: *Coff, zcu: *Zcu, - nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"), + nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child, ) !Symbol.Index { const ip = &zcu.intern_pool; const default: String, const attributes: ObjectSectionAttributes = - switch (ip.indexToKey(nav_fr.val)) { - else => .{ .@".rdata", .{ .read = true } }, - .variable => |variable| if (variable.is_threadlocal and - coff.base.comp.config.any_non_single_threaded) - .{ .@".tls$", .{ .read = true, .write = true } } - else - .{ .@".data", .{ .read = true, .write = true } }, - .@"extern" => |@"extern"| if (@"extern".is_threadlocal and - coff.base.comp.config.any_non_single_threaded) - .{ .@".tls$", .{ .read = true, .write = true } } - else if (ip.isFunctionType(@"extern".ty)) - .{ .@".text", .{ .read = true, .execute = true } } - else if (@"extern".is_const) - .{ .@".rdata", .{ .read = true } } - else - .{ .@".data", .{ .read = true, .write = true } }, - .func => .{ .@".text", .{ .read = true, .execute = true } }, + if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{ + .@".tls$", .{ .read = true, .write = true }, + } else if (ip.isFunctionType(nav_resolved.type)) .{ + .@".text", .{ .read = true, .execute = true }, + } else if (nav_resolved.@"const") .{ + .@".rdata", .{ .read = true }, + } else .{ + .@".data", .{ .read = true, .write = true }, }; + return (try coff.objectSectionMapIndex( - (try coff.getOrPutOptionalString(nav_fr.@"linksection".toSlice(ip))).unwrap() orelse default, - switch (nav_fr.@"linksection") { + (try coff.getOrPutOptionalString(nav_resolved.@"linksection".toSlice(ip))).unwrap() orelse default, + switch (nav_resolved.@"linksection") { .none => coff.mf.flags.block_size, - else => switch (nav_fr.alignment) { - .none => Type.fromInterned(ip.typeOf(nav_fr.val)).abiAlignment(zcu), + else => switch (nav_resolved.@"align") { + .none => Type.fromInterned(ip.typeOf(nav_resolved.value)).abiAlignment(zcu), else => |alignment| alignment, }.toStdMem(), }, @@ -1536,20 +1528,15 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - const nav_val = nav.status.fully_resolved.val; - const nav_init = switch (ip.indexToKey(nav_val)) { - else => nav_val, - .variable => |variable| variable.init, - .@"extern", .func => .none, - }; - if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; + if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return; + if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return; const nmi = try coff.navMapIndex(zcu, nav_index); const si = nmi.symbol(coff); const ni = ni: { switch (si.get(coff).ni) { .none => { - const sec_si = try coff.navSection(zcu, nav.status.fully_resolved); + const sec_si = try coff.navSection(zcu, nav.resolved.?); try coff.nodes.ensureUnusedCapacity(gpa, 1); const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ .alignment = zcu.navAlignment(nav_index).toStdMem(), @@ -1576,7 +1563,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde &coff.base, pt, zcu.navSrcLoc(nav_index), - .fromInterned(nav_init), + .fromInterned(nav.resolved.?.value), &nw.interface, .{ .atom_index = @intFromEnum(si) }, ) catch |err| switch (err) { @@ -1587,7 +1574,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde si.applyLocationRelocs(coff); } - if (nav.status.fully_resolved.@"linksection".unwrap()) |_| { + if (nav.resolved.?.@"linksection".unwrap()) |_| { try ni.resize(&coff.mf, gpa, si.get(coff).size); var parent_ni = ni; while (true) { @@ -1674,12 +1661,12 @@ fn updateFuncInner( const ni = ni: { switch (si.get(coff).ni) { .none => { - const sec_si = try coff.navSection(zcu, nav.status.fully_resolved); + const sec_si = try coff.navSection(zcu, nav.resolved.?); try coff.nodes.ensureUnusedCapacity(gpa, 1); const mod = zcu.navFileScope(func.owner_nav).mod.?; const target = &mod.resolved_target.result; const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ - .alignment = switch (nav.status.fully_resolved.alignment) { + .alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { .Debug, .ReleaseSafe, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig @@ -2681,7 +2681,7 @@ fn initWipNavInner( } else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index }); }, .syntax => switch (ip.isFunctionType(@"extern".ty)) { - false => continue :nav_val .{ .variable = undefined }, + false => continue :nav_val .{ .undef = @"extern".ty }, true => { const func_type = ip.indexToKey(@"extern".ty).func_type; const diw = &wip_nav.debug_info.writer; @@ -2777,7 +2777,7 @@ fn initWipNavInner( wip_nav.func_high_pc = @intCast(diw.end); try diw.writeInt(u32, 0, dwarf.endian); const target = &mod.resolved_target.result; - try diw.writeUleb128(switch (nav.status.fully_resolved.alignment) { + try diw.writeUleb128(switch (nav.resolved.?.@"align") { .none => target_info.defaultFunctionAlignment(target), else => |a| a.maxStrict(target_info.minFunctionAlignment(target)), }.toByteUnits().?); @@ -2845,7 +2845,7 @@ fn initWipNavInner( .@"const" => { const const_ty_reloc_index = try wip_nav.refForward(); try wip_nav.infoExprLoc(loc); - try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse + try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse ty.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromBool(decl.linkage != .normal)); wip_nav.finishForward(const_ty_reloc_index); @@ -2855,7 +2855,7 @@ fn initWipNavInner( .@"var" => { try wip_nav.refType(ty); try wip_nav.infoExprLoc(loc); - try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse + try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse ty.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromBool(decl.linkage != .normal)); }, @@ -3028,10 +3028,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav_src_loc = zcu.navSrcLoc(nav_index); - const nav_val = zcu.navValue(nav_index); const nav = ip.getNav(nav_index); const inst_info = nav.srcInst(ip).resolveFull(ip).?; + const nav_val: Value = .fromInterned(nav.resolved.?.value); const file = zcu.fileByIndex(inst_info.file); const decl = file.zir.?.getDeclaration(inst_info.inst); log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{ @@ -3127,9 +3127,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .aggregate, .un, .bitpack, - => .@"const", - - .variable => .@"var", + => if (nav.resolved.?.@"const") .@"const" else .@"var", .@"extern" => unreachable, @@ -3210,7 +3208,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const nav_ty = nav_val.typeOf(zcu); try wip_nav.refType(nav_ty); try wip_nav.blockValue(nav_src_loc, nav_val); - try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse + try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse nav_ty.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromBool(decl.linkage != .normal)); }, @@ -3240,7 +3238,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .@"extern", .@"export" => nav.name, }.toSlice(ip)); const nav_ty_reloc_index = try wip_nav.refForward(); - try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse + try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse nav_ty.abiAlignment(zcu).toByteUnits().?); try diw.writeByte(@intFromBool(decl.linkage != .normal)); if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val); @@ -4281,7 +4279,6 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co try wip_nav.refType(.null); }, }, - .variable => unreachable, // not a value .int => |int| { try wip_nav.bigIntConstValue(.{ .sdata = .sdata_comptime_value, diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig @@ -1113,7 +1113,7 @@ pub fn getOrCreateMetadataForNav(self: *ZigObject, zcu: *Zcu, nav_index: InternP if (!gop.found_existing) { const symbol_index = try self.newSymbolWithAtom(gpa, 0); const sym = self.symbol(symbol_index); - if (ip.getNav(nav_index).isThreadlocal(ip) and zcu.comp.config.any_non_single_threaded) { + if (ip.getNav(nav_index).resolved.?.@"threadlocal" and zcu.comp.config.any_non_single_threaded) { sym.flags.is_tls = true; } gop.value_ptr.* = .{ .symbol_index = symbol_index }; @@ -1143,9 +1143,10 @@ fn getNavShdrIndex( const gpa = elf_file.base.comp.gpa; const ptr_size = elf_file.ptrWidthBytes(); const ip = &zcu.intern_pool; - const nav_val = zcu.navValue(nav_index); + const nav = ip.getNav(nav_index); + const nav_val: Value = .fromInterned(nav.resolved.?.value); const is_func = ip.isFunctionType(nav_val.typeOf(zcu).toIntern()); - if (ip.getNav(nav_index).getLinkSection().unwrap()) |@"linksection"| { + if (ip.getNav(nav_index).resolved.?.@"linksection".unwrap()) |@"linksection"| { const section_name = @"linksection".toSlice(ip); if (elf_file.sectionByName(section_name)) |osec| { if (is_func) { @@ -1258,13 +1259,8 @@ fn getNavShdrIndex( self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec); return osec; } - const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .variable => |variable| .{ false, variable.is_threadlocal, variable.init }, - .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, - else => .{ true, false, nav_val.toIntern() }, - }; const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0; - if (is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) { + if (nav.resolved.?.@"threadlocal" and elf_file.base.comp.config.any_non_single_threaded) { const is_bss = !has_relocs and for (code) |byte| { if (byte != 0) break false; } else true; @@ -1291,7 +1287,7 @@ fn getNavShdrIndex( self.tdata_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".tdata"), osec); return osec; } - if (is_const) { + if (nav.resolved.?.@"const") { if (self.data_relro_index) |symbol_index| return self.symbol(symbol_index).outputShndx(elf_file).?; const osec = try elf_file.addSection(.{ @@ -1303,7 +1299,7 @@ fn getNavShdrIndex( self.data_relro_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data.rel.ro"), osec); return osec; } - if (nav_init != .none and Value.fromInterned(nav_init).isUndef(zcu)) + if (nav_val.isUndef(zcu)) return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) { .Debug, .ReleaseSafe => { if (self.data_index) |symbol_index| @@ -1378,7 +1374,7 @@ fn updateNavCode( const mod = zcu.navFileScope(nav_index).mod.?; const target = &mod.resolved_target.result; - const required_alignment = switch (nav.status.fully_resolved.alignment) { + const required_alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), .ReleaseSmall => target_util.minFunctionAlignment(target), @@ -1647,16 +1643,17 @@ pub fn updateNav( log.debug("updateNav {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); - const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) { - .func => .none, - .variable => |variable| variable.init, + switch (ip.indexToKey(nav.resolved.?.value)) { + else => {}, .@"extern" => |@"extern"| { const sym_index = try self.getGlobalSymbol( elf_file, nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip), ); - if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true; + if (nav.resolved.?.@"threadlocal" and elf_file.base.comp.config.any_non_single_threaded) { + self.symbol(sym_index).flags.is_tls = true; + } if (self.dwarf) |*dwarf| { var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index); defer debug_wip_nav.deinit(); @@ -1668,10 +1665,9 @@ pub fn updateNav( } return; }, - else => nav.status.fully_resolved.val, - }; + } - if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) { + if (Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) { const sym_index = try self.getOrCreateMetadataForNav(zcu, nav_index); self.symbol(sym_index).atom(elf_file).?.freeRelocs(self); @@ -1685,7 +1681,7 @@ pub fn updateNav( &elf_file.base, pt, zcu.navSrcLoc(nav_index), - Value.fromInterned(nav_init), + .fromInterned(nav.resolved.?.value), &aw.writer, .{ .atom_index = sym_index }, ) catch |err| switch (err) { diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig @@ -1876,32 +1876,15 @@ pub fn globalSymbol(elf: *Elf, opts: struct { fn navType( ip: *const InternPool, - nav_status: @FieldType(InternPool.Nav, "status"), + nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child, any_non_single_threaded: bool, ) std.elf.STT { - return switch (nav_status) { - .unresolved => unreachable, - .type_resolved => |tr| if (any_non_single_threaded and tr.is_threadlocal) - .TLS - else if (ip.isFunctionType(tr.type)) - .FUNC - else - .OBJECT, - .fully_resolved => |fr| switch (ip.indexToKey(fr.val)) { - else => .OBJECT, - .variable => |variable| if (any_non_single_threaded and variable.is_threadlocal) - .TLS - else - .OBJECT, - .@"extern" => |@"extern"| if (any_non_single_threaded and @"extern".is_threadlocal) - .TLS - else if (ip.isFunctionType(@"extern".ty)) - .FUNC - else - .OBJECT, - .func => .FUNC, - }, - }; + return if (any_non_single_threaded and nav_resolved.@"threadlocal") + .TLS + else if (ip.isFunctionType(nav_resolved.type)) + .FUNC + else + .OBJECT; } fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index { if (std.mem.eql(u8, name, ".rodata") or @@ -1917,13 +1900,13 @@ fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index { fn navSection( elf: *Elf, ip: *const InternPool, - nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"), + nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child, ) Symbol.Index { - if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| + if (nav_resolved.@"linksection".toSlice(ip)) |@"linksection"| if (elf.namedSection(@"linksection")) |si| return si; return switch (navType( ip, - .{ .fully_resolved = nav_fr }, + nav_resolved, elf.base.comp.config.any_non_single_threaded, )) { else => unreachable, @@ -1940,7 +1923,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavM const nav_gop = try elf.navs.getOrPut(gpa, nav_index); if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .name = nav.fqn.toSlice(ip), - .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), + .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded), }); return @enumFromInt(nav_gop.index); } @@ -1950,7 +1933,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol. if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ .name = @"extern".name.toSlice(ip), .lib_name = @"extern".lib_name.toSlice(ip), - .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), + .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded), .bind = switch (@"extern".linkage) { .internal => .LOCAL, .strong => .GLOBAL, @@ -2889,13 +2872,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - const nav_val = nav.status.fully_resolved.val; - const nav_init = switch (ip.indexToKey(nav_val)) { - else => nav_val, - .variable => |variable| variable.init, - .@"extern", .func => .none, - }; - if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; + if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return; + if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return; const nmi = try elf.navMapIndex(zcu, nav_index); const si = nmi.symbol(elf); @@ -2904,7 +2882,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) switch (sym.ni) { .none => { try elf.nodes.ensureUnusedCapacity(gpa, 1); - const sec_si = elf.navSection(ip, nav.status.fully_resolved); + const sec_si = elf.navSection(ip, nav.resolved.?); const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .alignment = zcu.navAlignment(nav_index).toStdMem(), .moved = true, @@ -2930,7 +2908,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) &elf.base, pt, zcu.navSrcLoc(nav_index), - .fromInterned(nav_init), + .fromInterned(nav.resolved.?.value), &nw.interface, .{ .atom_index = @intFromEnum(si) }, ) catch |err| switch (err) { @@ -3021,11 +2999,11 @@ fn updateFuncInner( switch (sym.ni) { .none => { try elf.nodes.ensureUnusedCapacity(gpa, 1); - const sec_si = elf.navSection(ip, nav.status.fully_resolved); + const sec_si = elf.navSection(ip, nav.resolved.?); const mod = zcu.navFileScope(func.owner_nav).mod.?; const target = &mod.resolved_target.result; const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ - .alignment = switch (nav.status.fully_resolved.alignment) { + .alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { .Debug, .ReleaseSafe, @@ -3677,7 +3655,7 @@ fn updateExportsInner( const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) { .nav => |nav| .{ try elf.navSymbol(zcu, nav), - navType(ip, ip.getNav(nav).status, elf.base.comp.config.any_non_single_threaded), + navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded), }, .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav( pt, diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig @@ -877,15 +877,14 @@ pub fn updateNav( const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) { - .func => .none, - .variable => |variable| variable.init, + switch (ip.indexToKey(nav.resolved.?.value)) { + else => {}, .@"extern" => |@"extern"| { // Extern variable gets a __got entry only const name = @"extern".name.toSlice(ip); const lib_name = @"extern".lib_name.toSlice(ip); const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name); - if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true; + if (nav.resolved.?.@"threadlocal" and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true; if (self.dwarf) |*dwarf| { var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index); defer debug_wip_nav.deinit(); @@ -897,10 +896,9 @@ pub fn updateNav( } return; }, - else => nav.status.fully_resolved.val, - }; + } - if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) { + if (Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) { const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index); self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); @@ -914,7 +912,7 @@ pub fn updateNav( &macho_file.base, pt, zcu.navSrcLoc(nav_index), - Value.fromInterned(nav_init), + .fromInterned(nav.resolved.?.value), &aw.writer, .{ .atom_index = sym_index }, ) catch |err| switch (err) { @@ -959,7 +957,7 @@ fn updateNavCode( const mod = zcu.navFileScope(nav_index).mod.?; const target = &mod.resolved_target.result; - const required_alignment = switch (nav.status.fully_resolved.alignment) { + const required_alignment = switch (nav.resolved.?.@"align") { .none => switch (mod.optimize_mode) { .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), .ReleaseSmall => target_util.minFunctionAlignment(target), @@ -1167,14 +1165,10 @@ fn getNavOutputSection( ) error{OutOfMemory}!u8 { _ = self; const ip = &zcu.intern_pool; - const nav_val = zcu.navValue(nav_index); + const nav = ip.getNav(nav_index); + const nav_val: Value = .fromInterned(nav.resolved.?.value); if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return macho_file.zig_text_sect_index.?; - const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { - .variable => |variable| .{ false, variable.is_threadlocal, variable.init }, - .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, - else => .{ true, false, nav_val.toIntern() }, - }; - if (is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) { + if (nav.resolved.?.@"threadlocal" and macho_file.base.comp.config.any_non_single_threaded) { for (code) |byte| { if (byte != 0) break; } else return macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection( @@ -1188,8 +1182,8 @@ fn getNavOutputSection( .{ .flags = macho.S_THREAD_LOCAL_REGULAR }, ); } - if (is_const) return macho_file.zig_const_sect_index.?; - if (nav_init != .none and Value.fromInterned(nav_init).isUndef(zcu)) + if (nav.resolved.?.@"const") return macho_file.zig_const_sect_index.?; + if (nav_val.isUndef(zcu)) return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) { .Debug, .ReleaseSafe => macho_file.zig_data_sect_index.?, .ReleaseFast, .ReleaseSmall => macho_file.zig_bss_sect_index.?, @@ -1550,7 +1544,7 @@ fn isThreadlocal(macho_file: *MachO, nav_index: InternPool.Nav.Index) bool { if (!macho_file.base.comp.config.any_non_single_threaded) return false; const ip = &macho_file.base.comp.zcu.?.intern_pool; - return ip.getNav(nav_index).isThreadlocal(ip); + return ip.getNav(nav_index).resolved.?.@"threadlocal"; } fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index { diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig @@ -189,7 +189,7 @@ pub fn updateExports( @panic("TODO: implement Linker linker code for exporting a constant value"); }, }; - const nav_ty = ip.getNav(nav_index).typeOf(ip); + const nav_ty = ip.getNav(nav_index).resolved.?.type; const target = zcu.getTarget(); if (ip.isFunctionType(nav_ty)) { const spv_decl_index = try linker.module.resolveNav(ip, nav_index); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig @@ -420,7 +420,7 @@ pub const OutputFunctionIndex = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - return fromIpIndex(wasm, nav.status.fully_resolved.val); + return fromIpIndex(wasm, nav.resolved.?.value); } pub fn fromTagNameType(wasm: *const Wasm, tag_type: InternPool.Index) OutputFunctionIndex { @@ -1022,7 +1022,7 @@ pub const FunctionImport = extern struct { pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; - return fromIpIndex(wasm, ip.getNav(nav_index).status.fully_resolved.val); + return fromIpIndex(wasm, ip.getNav(nav_index).resolved.?.value); } pub fn fromZcuFunc(wasm: *const Wasm, i: ZcuFunc.Index) Resolution { @@ -1885,7 +1885,7 @@ pub const DataSegmentId = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(i.key(wasm).*); - if (nav.isThreadlocal(ip)) return .tls; + if (nav.resolved.?.@"threadlocal") return .tls; const code = i.value(wasm).code; return if (code.off == .none) .zero else .data; }, @@ -1908,7 +1908,7 @@ pub const DataSegmentId = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(i.key(wasm).*); - return nav.isThreadlocal(ip); + return nav.resolved.?.@"threadlocal"; }, }; } @@ -1934,7 +1934,7 @@ pub const DataSegmentId = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(i.key(wasm).*); - return nav.getLinkSection().toSlice(ip) orelse switch (category(id, wasm)) { + return nav.resolved.?.@"linksection".toSlice(ip) orelse switch (category(id, wasm)) { .tls => ".tdata", .data => ".data", .zero => ".bss", @@ -1962,9 +1962,9 @@ pub const DataSegmentId = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(i.key(wasm).*); - const explicit = nav.getAlignment(); + const explicit = nav.resolved.?.@"align"; if (explicit != .none) return explicit; - const ty: Zcu.Type = .fromInterned(nav.typeOf(ip)); + const ty: Zcu.Type = .fromInterned(nav.resolved.?.type); const result = ty.abiAlignment(zcu); assert(result != .none); return result; @@ -2269,7 +2269,7 @@ pub const ZcuImportIndex = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav_index = index.ptr(wasm).*; - const ext = ip.getNav(nav_index).getResolvedExtern(ip).?; + const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern"; const name_slice = ext.name.toSlice(ip); return wasm.getExistingString(name_slice).?; } @@ -2278,7 +2278,7 @@ pub const ZcuImportIndex = enum(u32) { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav_index = index.ptr(wasm).*; - const ext = ip.getNav(nav_index).getResolvedExtern(ip).?; + const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern"; const lib_name = ext.lib_name.toSlice(ip) orelse return .none; return wasm.getExistingString(lib_name).?.toOptional(); } @@ -2289,7 +2289,7 @@ pub const ZcuImportIndex = enum(u32) { const zcu = comp.zcu.?; const ip = &zcu.intern_pool; const nav_index = index.ptr(wasm).*; - const ext = ip.getNav(nav_index).getResolvedExtern(ip).?; + const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern"; const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?; return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?; } @@ -2381,7 +2381,7 @@ pub const FunctionImportId = enum(u32) { .zcu_import => |i| { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; - const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?; + const ext = ip.indexToKey(ip.getNav(i.ptr(wasm).*).resolved.?.value).@"extern"; return ext.linkage != .weak and ext.lib_name != .none; }, }; @@ -3288,7 +3288,8 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index const is_obj = comp.config.output_mode == .Obj; const target = &comp.root_mod.resolved_target.result; - const nav_init, const chased_nav_index = switch (ip.indexToKey(nav.status.fully_resolved.val)) { + switch (ip.indexToKey(nav.resolved.?.value)) { + else => {}, .func => return, // global const which is a function alias .@"extern" => |ext| { if (is_obj) { @@ -3302,7 +3303,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index try wasm.function_imports.ensureUnusedCapacity(gpa, 1); try wasm.data_imports.ensureUnusedCapacity(gpa, 1); const zcu_import = wasm.addZcuImportReserved(ext.owner_nav); - if (ip.isFunctionType(nav.typeOf(ip))) { + if (ip.isFunctionType(nav.resolved.?.type)) { wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm)); // Ensure there is a corresponding function type table entry. const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?; @@ -3312,31 +3313,29 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index } return; }, - .variable => |variable| .{ variable.init, variable.owner_nav }, - else => .{ nav.status.fully_resolved.val, nav_index }, - }; - //log.debug("updateNav {f} {d}", .{ nav.fqn.fmt(ip), chased_nav_index }); - assert(!wasm.imports.contains(chased_nav_index)); + } + //log.debug("updateNav {f} {d}", .{ nav.fqn.fmt(ip), nav_index }); + assert(!wasm.imports.contains(nav_index)); - if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) { + if (!Zcu.Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) { if (is_obj) { - assert(!wasm.navs_obj.contains(chased_nav_index)); + assert(!wasm.navs_obj.contains(nav_index)); } else { - assert(!wasm.navs_exe.contains(chased_nav_index)); + assert(!wasm.navs_exe.contains(nav_index)); } return; } if (is_obj) { const zcu_data_starts: ZcuDataStarts = .initObj(wasm); - const navs_i = try refNavObj(wasm, chased_nav_index); - const zcu_data = try lowerZcuData(wasm, pt, nav_init); + const navs_i = try refNavObj(wasm, nav_index); + const zcu_data = try lowerZcuData(wasm, pt, nav.resolved.?.value); navs_i.value(wasm).* = zcu_data; try zcu_data_starts.finishObj(wasm, pt); } else { const zcu_data_starts: ZcuDataStarts = .initExe(wasm); - const navs_i = try refNavExe(wasm, chased_nav_index); - const zcu_data = try lowerZcuData(wasm, pt, nav_init); + const navs_i = try refNavExe(wasm, nav_index); + const zcu_data = try lowerZcuData(wasm, pt, nav.resolved.?.value); navs_i.value(wasm).code = zcu_data.code; try zcu_data_starts.finishExe(wasm, pt); } @@ -4173,9 +4172,8 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 { } const zcu = comp.zcu.?; const ip = &zcu.intern_pool; - const nav = ip.getNav(nav_index); - if (nav.getResolvedExtern(ip)) |ext| { - if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| { + switch (ip.indexToKey(ip.getNav(nav_index).resolved.?.value)) { + .@"extern" => |ext| if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| { if (wasm.object_data_imports.getPtr(symbol_name)) |import| { switch (import.resolution.unpack(wasm)) { .unresolved => unreachable, @@ -4195,7 +4193,8 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 { .nav_obj => @panic("TODO"), } } - } + }, + else => {}, } // Otherwise it's a zero bit type; any address will do. return 0; diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig @@ -211,7 +211,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { } for (wasm.nav_exports.keys(), wasm.nav_exports.values()) |*nav_export, export_index| { - if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) { + if (ip.isFunctionType(ip.getNav(nav_export.nav_index).resolved.?.type)) { log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index }); const function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?; const explicit = f.missing_exports.swapRemove(nav_export.name); diff --git a/src/print_value.zig b/src/print_value.zig @@ -74,7 +74,6 @@ pub fn print( .@"unreachable", => try writer.writeAll(@tagName(simple_value)), }, - .variable => try writer.writeAll("(variable)"), .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}), .func => |func| try writer.print("(function '{f}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}), .int => |int| switch (int.storage) {