diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-08-11 15:07:06 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-11 15:07:06 -0700 |
| commit | fc2924080694d68945308d394751a2ec4841b3c0 (patch) | |
| tree | c4b372662b0253de33483225d17a8a79c735ada5 /src/Sema.zig | |
| parent | 531cd177e89c1edfcd2e52f74f220eb186a25f78 (diff) | |
| parent | 153e7d6235a7d74d0c02d51f84edc5c06ab7469d (diff) | |
| download | zig-fc2924080694d68945308d394751a2ec4841b3c0.tar.gz zig-fc2924080694d68945308d394751a2ec4841b3c0.zip | |
Merge pull request #20964 from mlugg/the-great-decl-split-mk2
compiler: split `Decl` into `Nav` and `Cau`
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 2142 |
1 files changed, 1054 insertions, 1088 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index c84692e7c5..20daa78e9a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -16,16 +16,14 @@ air_instructions: std.MultiArrayList(Air.Inst) = .{}, air_extra: std.ArrayListUnmanaged(u32) = .{}, /// Maps ZIR to AIR. inst_map: InstMap = .{}, -/// When analyzing an inline function call, owner_decl is the Decl of the caller. -owner_decl: *Decl, -owner_decl_index: InternPool.DeclIndex, -/// For an inline or comptime function call, this will be the root parent function -/// which contains the callsite. Corresponds to `owner_decl`. -/// This could be `none`, a `func_decl`, or a `func_instance`. -owner_func_index: InternPool.Index, +/// The "owner" of a `Sema` represents the root "thing" that is being analyzed. +/// This does not change throughout the entire lifetime of a `Sema`. For instance, +/// when analyzing a runtime function body, this is always `func` of that function, +/// even if an inline/comptime function call is being analyzed. +owner: AnalUnit, /// The function this ZIR code is the body of, according to the source code. -/// This starts out the same as `owner_func_index` and then diverges in the case of -/// an inline or comptime function call. +/// This starts out the same as `sema.owner.func` if applicable, and then diverges +/// in the case of an inline or comptime function call. /// This could be `none`, a `func_decl`, or a `func_instance`. func_index: InternPool.Index, /// Whether the type of func_index has a calling convention of `.Naked`. @@ -48,7 +46,6 @@ branch_count: u32 = 0, /// Populated when returning `error.ComptimeBreak`. Used to communicate the /// break instruction up the stack to find the corresponding Block. comptime_break_inst: Zir.Inst.Index = undefined, -decl_val_table: std.AutoHashMapUnmanaged(InternPool.DeclIndex, Air.Inst.Ref) = .{}, /// When doing a generic function instantiation, this array collects a value /// for each parameter of the generic owner. `none` for non-comptime parameters. /// This is a separate array from `block.params` so that it can be passed @@ -79,10 +76,6 @@ no_partial_func_ty: bool = false, /// here so the values can be dropped without any cleanup. unresolved_inferred_allocs: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{}, -/// This is populated when `@setAlignStack` occurs so that if there is a duplicate -/// one encountered, the conflicting source location can be shown. -prev_stack_alignment_src: ?LazySrcLoc = null, - /// While analyzing a type which has a special InternPool index, this is set to the index at which /// the struct/enum/union type created should be placed. Otherwise, it is `.none`. builtin_type_target_index: InternPool.Index = .none, @@ -177,7 +170,6 @@ const trace = @import("tracy.zig").trace; const Namespace = Module.Namespace; const CompileError = Module.CompileError; const SemaError = Module.SemaError; -const Decl = Module.Decl; const LazySrcLoc = Zcu.LazySrcLoc; const RangeSet = @import("RangeSet.zig"); const target_util = @import("target.zig"); @@ -394,7 +386,7 @@ pub const Block = struct { /// The name of the current "context" for naming namespace types. /// The interpretation of this depends on the name strategy in ZIR, but the name /// is always incorporated into the type name somehow. - /// See `Sema.createAnonymousDeclTypeNamed`. + /// See `Sema.createTypeName`. type_name_ctx: InternPool.NullTerminatedString, /// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block. @@ -440,8 +432,8 @@ pub const Block = struct { try sema.errNote(ci.src, parent, prefix ++ "it is inside a @cImport", .{}); }, .comptime_ret_ty => |rt| { - const ret_ty_src: LazySrcLoc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| .{ - .base_node_inst = fn_decl.zir_decl_index.unwrap().?, + const ret_ty_src: LazySrcLoc = if (try sema.funcDeclSrcInst(rt.func)) |fn_decl_inst| .{ + .base_node_inst = fn_decl_inst, .offset = .{ .node_offset_fn_type_ret_ty = 0 }, } else rt.func_src; if (rt.return_ty.isGenericPoison()) { @@ -871,7 +863,6 @@ pub fn deinit(sema: *Sema) void { sema.air_instructions.deinit(gpa); sema.air_extra.deinit(gpa); sema.inst_map.deinit(gpa); - sema.decl_val_table.deinit(gpa); { var it = sema.post_hoc_blocks.iterator(); while (it.next()) |entry| { @@ -2170,7 +2161,7 @@ fn resolveValueResolveLazy(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { const val = (try sema.resolveValue(inst)) orelse return null; if (sema.pt.zcu.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) { - .decl, .anon_decl, .comptime_alloc, .comptime_field => return null, + .nav, .uav, .comptime_alloc, .comptime_field => return null, .int => {}, .eu_payload, .opt_payload, .arr_elem, .field => unreachable, }; @@ -2503,7 +2494,6 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error @setCold(true); const gpa = sema.gpa; const mod = sema.pt.zcu; - const ip = &mod.intern_pool; if (build_options.enable_debug_extensions and mod.comp.debug_compile_errors) { var all_references = mod.resolveReferences() catch @panic("out of memory"); @@ -2531,10 +2521,10 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error const use_ref_trace = if (mod.comp.reference_trace) |n| n > 0 else mod.failed_analysis.count() == 0; if (use_ref_trace) { - err_msg.reference_trace_root = sema.ownerUnit().toOptional(); + err_msg.reference_trace_root = sema.owner.toOptional(); } - const gop = try mod.failed_analysis.getOrPut(gpa, sema.ownerUnit()); + const gop = try mod.failed_analysis.getOrPut(gpa, sema.owner); if (gop.found_existing) { // If there are multiple errors for the same Decl, prefer the first one added. sema.err = null; @@ -2544,16 +2534,6 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error gop.value_ptr.* = err_msg; } - if (sema.owner_func_index != .none) { - ip.funcSetAnalysisState(sema.owner_func_index, .sema_failure); - } else { - sema.owner_decl.analysis = .sema_failure; - } - - if (sema.func_index != .none) { - ip.funcSetAnalysisState(sema.func_index, .sema_failure); - } - return error.AnalysisFail; } @@ -2662,7 +2642,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).getType(zcu).getCaptures(zcu); + const parent_ty = Type.fromInterned(zcu.namespacePtr(block.namespace).owner_type); + const parent_captures: InternPool.CaptureValue.Slice = parent_ty.getCaptures(zcu); const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len); @@ -2704,8 +2685,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us sema.code.nullTerminatedString(str), .no_embedded_nulls, ); - const decl = try sema.lookupIdentifier(block, LazySrcLoc.unneeded, decl_name); // TODO: could we need this src loc? - break :capture InternPool.CaptureValue.wrap(.{ .decl_val = decl }); + const nav = try sema.lookupIdentifier(block, LazySrcLoc.unneeded, decl_name); // TODO: could we need this src loc? + break :capture InternPool.CaptureValue.wrap(.{ .nav_val = nav }); }, .decl_ref => |str| capture: { const decl_name = try ip.getOrPutString( @@ -2714,8 +2695,8 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us sema.code.nullTerminatedString(str), .no_embedded_nulls, ); - const decl = try sema.lookupIdentifier(block, LazySrcLoc.unneeded, decl_name); // TODO: could we need this src loc? - break :capture InternPool.CaptureValue.wrap(.{ .decl_ref = decl }); + const nav = try sema.lookupIdentifier(block, LazySrcLoc.unneeded, decl_name); // TODO: could we need this src loc? + break :capture InternPool.CaptureValue.wrap(.{ .nav_ref = nav }); }, }; } @@ -2740,19 +2721,24 @@ fn wrapWipTy(sema: *Sema, wip_ty: anytype) @TypeOf(wip_ty) { fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool { const pt = sema.pt; const zcu = pt.zcu; + const ip = &zcu.intern_pool; if (!zcu.comp.incremental) return false; - const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu); - const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index }); - const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or - zcu.potentially_outdated.swapRemove(decl_as_depender); + const cau_index = switch (ip.indexToKey(ty)) { + .struct_type => ip.loadStructType(ty).cau.unwrap().?, + .union_type => ip.loadUnionType(ty).cau, + .enum_type => ip.loadEnumType(ty).cau.unwrap().?, + else => unreachable, + }; + const cau_unit = AnalUnit.wrap(.{ .cau = cau_index }); + const was_outdated = zcu.outdated.swapRemove(cau_unit) or + zcu.potentially_outdated.swapRemove(cau_unit); if (!was_outdated) return false; - _ = zcu.outdated_ready.swapRemove(decl_as_depender); - zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index })); + _ = zcu.outdated_ready.swapRemove(cau_unit); + zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, cau_unit); zcu.intern_pool.remove(pt.tid, ty); - zcu.declPtr(decl_index).analysis = .dependency_failure; - try zcu.markDependeeOutdated(.{ .decl_val = decl_index }); + try zcu.markDependeeOutdated(.{ .interned = ty }); return true; } @@ -2816,7 +2802,6 @@ fn zirStructDecl( .any_default_inits = small.any_default_inits, .inits_resolved = false, .any_aligned_fields = small.any_aligned_fields, - .has_namespace = true or decls_len > 0, // TODO: see below .key = .{ .declared = .{ .zir_index = tracked_inst, .captures = captures, @@ -2831,73 +2816,65 @@ fn zirStructDecl( }); errdefer wip_ty.cancel(ip, pt.tid); - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + wip_ty.setName(ip, try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), small.name_strategy, "struct", inst, - ); - mod.declPtr(new_decl_index).owns_tv = true; - errdefer pt.abortAnonDecl(new_decl_index); + wip_ty.index, + )); + + const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ + .parent = block.namespace.toOptional(), + .owner_type = wip_ty.index, + .file_scope = block.getFileScopeIndex(mod), + }); + errdefer pt.destroyNamespace(new_namespace_index); + + const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); if (pt.zcu.comp.incremental) { try ip.addDependency( sema.gpa, - AnalUnit.wrap(.{ .decl = new_decl_index }), - .{ .src_hash = try block.trackZir(inst) }, + AnalUnit.wrap(.{ .cau = new_cau_index }), + .{ .src_hash = tracked_inst }, ); } - // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace. - const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try pt.createNamespace(.{ - .parent = block.namespace.toOptional(), - .decl_index = new_decl_index, - .file_scope = block.getFileScopeIndex(mod), - })).toOptional() else .none; - errdefer if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns); - - if (new_namespace_index.unwrap()) |ns| { - const decls = sema.code.bodySlice(extra_index, decls_len); - try pt.scanNamespace(ns, decls, mod.declPtr(new_decl_index)); - } + const decls = sema.code.bodySlice(extra_index, decls_len); + try pt.scanNamespace(new_namespace_index, decls); - try pt.finalizeAnonDecl(new_decl_index); try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index })); - return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index)); + try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); + try sema.declareDependency(.{ .interned = wip_ty.index }); + return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); } -fn createAnonymousDeclTypeNamed( +fn createTypeName( sema: *Sema, block: *Block, - val: Value, name_strategy: Zir.Inst.NameStrategy, anon_prefix: []const u8, inst: ?Zir.Inst.Index, -) !InternPool.DeclIndex { + /// This is used purely to give the type a unique name in the `anon` case. + type_index: InternPool.Index, +) !InternPool.NullTerminatedString { const pt = sema.pt; const zcu = pt.zcu; + const gpa = zcu.gpa; const ip = &zcu.intern_pool; - const gpa = sema.gpa; - const namespace = block.namespace; - const new_decl_index = try pt.allocateNewDecl(namespace); - errdefer pt.destroyDecl(new_decl_index); switch (name_strategy) { .anon => {}, // handled after switch - .parent => { - try pt.initNewAnonDecl(new_decl_index, val, block.type_name_ctx, .none); - return new_decl_index; - }, + .parent => return block.type_name_ctx, .func => func_strat: { const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip)); const zir_tags = sema.code.instructions.items(.tag); - var buf = std.ArrayList(u8).init(gpa); - defer buf.deinit(); + var buf: std.ArrayListUnmanaged(u8) = .{}; + defer buf.deinit(gpa); - const writer = buf.writer(); + const writer = buf.writer(gpa); try writer.print("{}(", .{block.type_name_ctx.fmt(ip)}); var arg_i: usize = 0; @@ -2931,23 +2908,18 @@ fn createAnonymousDeclTypeNamed( }; try writer.writeByte(')'); - const name = try ip.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls); - try pt.initNewAnonDecl(new_decl_index, val, name, .none); - return new_decl_index; + return ip.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls); }, .dbg_var => { + // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions. const ref = inst.?.toRef(); const zir_tags = sema.code.instructions.items(.tag); const zir_data = sema.code.instructions.items(.data); for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) { - .dbg_var_ptr, .dbg_var_val => { - if (zir_data[i].str_op.operand != ref) continue; - - const name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.{s}", .{ + .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { + return ip.getOrPutStringFmt(gpa, pt.tid, "{}.{s}", .{ block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), }, .no_embedded_nulls); - try pt.initNewAnonDecl(new_decl_index, val, name, .none); - return new_decl_index; }, else => {}, }; @@ -2955,20 +2927,19 @@ fn createAnonymousDeclTypeNamed( }, } - // anon strat handling. + // anon strat handling // It would be neat to have "struct:line:column" but this name has // to survive incremental updates, where it may have been shifted down // or up to a different line, but unchanged, and thus not unnecessarily // semantically analyzed. - // This name is also used as the key in the parent namespace so it cannot be - // renamed. + // TODO: that would be possible, by detecting line number changes and renaming + // types appropriately. However, `@typeName` becomes a problem then. If we remove + // that builtin from the language, we can consider this. - const name = ip.getOrPutStringFmt(gpa, pt.tid, "{}__{s}_{d}", .{ - block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(new_decl_index), - }, .no_embedded_nulls) catch unreachable; - try pt.initNewAnonDecl(new_decl_index, val, name, .none); - return new_decl_index; + return ip.getOrPutStringFmt(gpa, pt.tid, "{}__{s}_{d}", .{ + block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index), + }, .no_embedded_nulls); } fn zirEnumDecl( @@ -3040,7 +3011,6 @@ fn zirEnumDecl( } else false; const enum_init: InternPool.EnumTypeInit = .{ - .has_namespace = true or decls_len > 0, // TODO: see below .has_values = any_values, .tag_mode = if (small.nonexhaustive) .nonexhaustive @@ -3068,60 +3038,50 @@ fn zirEnumDecl( errdefer if (!done) wip_ty.cancel(ip, pt.tid); - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + const type_name = try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), small.name_strategy, "enum", inst, + wip_ty.index, ); - const new_decl = mod.declPtr(new_decl_index); - new_decl.owns_tv = true; - errdefer if (!done) pt.abortAnonDecl(new_decl_index); + wip_ty.setName(ip, type_name); + + const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ + .parent = block.namespace.toOptional(), + .owner_type = wip_ty.index, + .file_scope = block.getFileScopeIndex(mod), + }); + errdefer if (!done) pt.destroyNamespace(new_namespace_index); + + const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); if (pt.zcu.comp.incremental) { try mod.intern_pool.addDependency( gpa, - AnalUnit.wrap(.{ .decl = new_decl_index }), + AnalUnit.wrap(.{ .cau = new_cau_index }), .{ .src_hash = try block.trackZir(inst) }, ); } - // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace. - const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try pt.createNamespace(.{ - .parent = block.namespace.toOptional(), - .decl_index = new_decl_index, - .file_scope = block.getFileScopeIndex(mod), - })).toOptional() else .none; - errdefer if (!done) if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns); + try pt.scanNamespace(new_namespace_index, decls); - if (new_namespace_index.unwrap()) |ns| { - try pt.scanNamespace(ns, decls, new_decl); - } + try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); + try sema.declareDependency(.{ .interned = wip_ty.index }); // We've finished the initial construction of this type, and are about to perform analysis. - // Set the decl and namespace appropriately, and don't destroy anything on failure. - wip_ty.prepare(ip, new_decl_index, new_namespace_index); + // Set the Cau and namespace appropriately, and don't destroy anything on failure. + wip_ty.prepare(ip, new_cau_index, new_namespace_index); done = true; const int_tag_ty = ty: { // We create a block for the field type instructions because they // may need to reference Decls from inside the enum namespace. - // Within the field type, default value, and alignment expressions, the "owner decl" - // should be the enum itself. + // Within the field type, default value, and alignment expressions, the owner should be the enum's `Cau`. - const prev_owner_decl = sema.owner_decl; - const prev_owner_decl_index = sema.owner_decl_index; - sema.owner_decl = new_decl; - sema.owner_decl_index = new_decl_index; - defer { - sema.owner_decl = prev_owner_decl; - sema.owner_decl_index = prev_owner_decl_index; - } - - const prev_owner_func_index = sema.owner_func_index; - sema.owner_func_index = .none; - defer sema.owner_func_index = prev_owner_func_index; + const prev_owner = sema.owner; + sema.owner = AnalUnit.wrap(.{ .cau = new_cau_index }); + defer sema.owner = prev_owner; const prev_func_index = sema.func_index; sema.func_index = .none; @@ -3130,12 +3090,12 @@ fn zirEnumDecl( var enum_block: Block = .{ .parent = null, .sema = sema, - .namespace = new_namespace_index.unwrap() orelse block.namespace, + .namespace = new_namespace_index, .instructions = .{}, .inlining = null, .is_comptime = true, .src_base_inst = tracked_inst, - .type_name_ctx = new_decl.name, + .type_name_ctx = type_name, }; defer enum_block.instructions.deinit(sema.gpa); @@ -3253,7 +3213,6 @@ fn zirEnumDecl( } } - try pt.finalizeAnonDecl(new_decl_index); return Air.internedToRef(wip_ty.index); } @@ -3317,7 +3276,6 @@ fn zirUnionDecl( .assumed_pointer_aligned = false, .alignment = .none, }, - .has_namespace = true or decls_len != 0, // TODO: see below .fields_len = fields_len, .enum_tag_ty = .none, // set later .field_types = &.{}, // set later @@ -3336,41 +3294,38 @@ fn zirUnionDecl( }); errdefer wip_ty.cancel(ip, pt.tid); - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + wip_ty.setName(ip, try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), small.name_strategy, "union", inst, - ); - mod.declPtr(new_decl_index).owns_tv = true; - errdefer pt.abortAnonDecl(new_decl_index); + wip_ty.index, + )); + + const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ + .parent = block.namespace.toOptional(), + .owner_type = wip_ty.index, + .file_scope = block.getFileScopeIndex(mod), + }); + errdefer pt.destroyNamespace(new_namespace_index); + + const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); if (pt.zcu.comp.incremental) { try mod.intern_pool.addDependency( gpa, - AnalUnit.wrap(.{ .decl = new_decl_index }), + AnalUnit.wrap(.{ .cau = new_cau_index }), .{ .src_hash = try block.trackZir(inst) }, ); } - // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace. - const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try pt.createNamespace(.{ - .parent = block.namespace.toOptional(), - .decl_index = new_decl_index, - .file_scope = block.getFileScopeIndex(mod), - })).toOptional() else .none; - errdefer if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns); - - if (new_namespace_index.unwrap()) |ns| { - const decls = sema.code.bodySlice(extra_index, decls_len); - try pt.scanNamespace(ns, decls, mod.declPtr(new_decl_index)); - } + const decls = sema.code.bodySlice(extra_index, decls_len); + try pt.scanNamespace(new_namespace_index, decls); - try pt.finalizeAnonDecl(new_decl_index); try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index })); - return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index)); + try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); + try sema.declareDependency(.{ .interned = wip_ty.index }); + return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); } fn zirOpaqueDecl( @@ -3410,7 +3365,6 @@ fn zirOpaqueDecl( extra_index += captures_len; const opaque_init: InternPool.OpaqueTypeInit = .{ - .has_namespace = decls_len != 0, .key = .{ .declared = .{ .zir_index = tracked_inst, .captures = captures, @@ -3418,47 +3372,31 @@ fn zirOpaqueDecl( }; // No `wrapWipTy` needed as no std.builtin types are opaque. const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) { - .existing => |ty| wip: { - if (!try sema.maybeRemoveOutdatedType(ty)) return Air.internedToRef(ty); - break :wip (try ip.getOpaqueType(gpa, pt.tid, opaque_init)).wip; - }, + // No `maybeRemoveOutdatedType` as opaque types are never outdated. + .existing => |ty| return Air.internedToRef(ty), .wip => |wip| wip, }; errdefer wip_ty.cancel(ip, pt.tid); - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + wip_ty.setName(ip, try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), small.name_strategy, "opaque", inst, - ); - mod.declPtr(new_decl_index).owns_tv = true; - errdefer pt.abortAnonDecl(new_decl_index); + wip_ty.index, + )); - if (pt.zcu.comp.incremental) { - try ip.addDependency( - gpa, - AnalUnit.wrap(.{ .decl = new_decl_index }), - .{ .src_hash = try block.trackZir(inst) }, - ); - } - - const new_namespace_index: InternPool.OptionalNamespaceIndex = if (decls_len > 0) (try pt.createNamespace(.{ + const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), - .decl_index = new_decl_index, + .owner_type = wip_ty.index, .file_scope = block.getFileScopeIndex(mod), - })).toOptional() else .none; - errdefer if (new_namespace_index.unwrap()) |ns| pt.destroyNamespace(ns); - - if (new_namespace_index.unwrap()) |ns| { - const decls = sema.code.bodySlice(extra_index, decls_len); - try pt.scanNamespace(ns, decls, mod.declPtr(new_decl_index)); - } + }); + errdefer pt.destroyNamespace(new_namespace_index); - try pt.finalizeAnonDecl(new_decl_index); + const decls = sema.code.bodySlice(extra_index, decls_len); + try pt.scanNamespace(new_namespace_index, decls); - return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index)); + return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index)); } fn zirErrorSetDecl( @@ -3774,7 +3712,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro // might have already done our job and created an anon decl ref. switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { .ptr => |ptr| switch (ptr.base_addr) { - .anon_decl => { + .uav => { // The comptime-ification was already done for us. // Just make sure the pointer is const. return sema.makePtrConst(block, alloc); @@ -3799,7 +3737,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro // Promote the constant to an anon decl. const new_mut_ptr = Air.internedToRef(try pt.intern(.{ .ptr = .{ .ty = alloc_ty.toIntern(), - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = interned.toIntern(), .orig_ty = alloc_ty.toIntern(), } }, @@ -4097,7 +4035,7 @@ fn finishResolveComptimeKnownAllocPtr( } else { return try pt.intern(.{ .ptr = .{ .ty = alloc_ty.toIntern(), - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = alloc_ty.toIntern(), .val = result_val, } }, @@ -4250,7 +4188,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com } const val = switch (mod.intern_pool.indexToKey(resolved_ptr).ptr.base_addr) { - .anon_decl => |a| a.val, + .uav => |a| a.val, .comptime_alloc => |i| val: { const alloc = sema.getComptimeAlloc(i); break :val (try alloc.val.intern(pt, sema.arena)).toIntern(); @@ -5505,22 +5443,23 @@ fn failWithBadMemberAccess( field_name: InternPool.NullTerminatedString, ) CompileError { const pt = sema.pt; - const mod = pt.zcu; - const kw_name = switch (agg_ty.zigTypeTag(mod)) { + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + const kw_name = switch (agg_ty.zigTypeTag(zcu)) { .Union => "union", .Struct => "struct", .Opaque => "opaque", .Enum => "enum", else => unreachable, }; - if (agg_ty.getOwnerDeclOrNull(mod)) |some| if (mod.declIsRoot(some)) { + if (agg_ty.typeDeclInst(zcu)) |inst| if (inst.resolve(ip) == .main_struct_inst) { return sema.fail(block, field_src, "root struct of file '{}' has no member named '{}'", .{ - agg_ty.fmt(pt), field_name.fmt(&mod.intern_pool), + agg_ty.fmt(pt), field_name.fmt(ip), }); }; return sema.fail(block, field_src, "{s} '{}' has no member named '{}'", .{ - kw_name, agg_ty.fmt(pt), field_name.fmt(&mod.intern_pool), + kw_name, agg_ty.fmt(pt), field_name.fmt(ip), }); } @@ -5535,13 +5474,12 @@ fn failWithBadStructFieldAccess( const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - const decl = zcu.declPtr(struct_type.decl.unwrap().?); const msg = msg: { const msg = try sema.errMsg( field_src, "no field named '{}' in struct '{}'", - .{ field_name.fmt(ip), decl.fqn.fmt(ip) }, + .{ field_name.fmt(ip), struct_type.name.fmt(ip) }, ); errdefer msg.destroy(sema.gpa); try sema.errNote(struct_ty.srcLoc(zcu), msg, "struct declared here", .{}); @@ -5562,13 +5500,12 @@ fn failWithBadUnionFieldAccess( const zcu = pt.zcu; const ip = &zcu.intern_pool; const gpa = sema.gpa; - const decl = zcu.declPtr(union_obj.decl); const msg = msg: { const msg = try sema.errMsg( field_src, "no field named '{}' in union '{}'", - .{ field_name.fmt(ip), decl.fqn.fmt(ip) }, + .{ field_name.fmt(ip), union_obj.name.fmt(ip) }, ); errdefer msg.destroy(gpa); try sema.errNote(union_ty.srcLoc(zcu), msg, "union declared here", .{}); @@ -5659,7 +5596,7 @@ fn storeToInferredAllocComptime( if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) { iac.ptr = try pt.intern(.{ .ptr = .{ .ty = alloc_ty.toIntern(), - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = operand_val.toIntern(), .orig_ty = alloc_ty.toIntern(), } }, @@ -5748,11 +5685,11 @@ fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air. .ty = array_ty.toIntern(), .storage = .{ .bytes = string }, } }); - return anonDeclRef(sema, val); + return sema.uavRef(val); } -fn anonDeclRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref { - return Air.internedToRef(try refValue(sema, val)); +fn uavRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref { + return Air.internedToRef(try sema.refValue(val)); } fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index { @@ -5767,7 +5704,7 @@ fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index { })).toIntern(); return pt.intern(.{ .ptr = .{ .ty = ptr_ty, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = val, .orig_ty = ptr_ty, } }, @@ -5866,7 +5803,7 @@ fn zirCompileLog( } try writer.print("\n", .{}); - const gop = try mod.compile_log_sources.getOrPut(sema.gpa, sema.ownerUnit()); + const gop = try mod.compile_log_sources.getOrPut(sema.gpa, sema.owner); if (!gop.found_existing) gop.value_ptr.* = .{ .base_node_inst = block.src_base_inst, .node_offset = src_node, @@ -6021,7 +5958,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr if (!comp.config.link_libc) try sema.errNote(src, msg, "libc headers not available; compilation does not link against libc", .{}); - const gop = try zcu.cimport_errors.getOrPut(gpa, sema.ownerUnit()); + const gop = try zcu.cimport_errors.getOrPut(gpa, sema.owner); if (!gop.found_existing) { gop.value_ptr.* = c_import_res.errors; c_import_res.errors = std.zig.ErrorBundle.empty; @@ -6069,13 +6006,15 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); const path_digest = zcu.filePathDigest(result.file_index); - const root_decl = zcu.fileRootDecl(result.file_index); - pt.astGenFile(result.file, path_digest, root_decl) catch |err| + const old_root_type = zcu.fileRootType(result.file_index); + pt.astGenFile(result.file, path_digest, old_root_type) catch |err| return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); + // TODO: register some kind of dependency on the file. + // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to + // trigger re-analysis later. try pt.ensureFileAnalyzed(result.file_index); - const file_root_decl_index = zcu.fileRootDecl(result.file_index).unwrap().?; - return sema.analyzeDeclVal(parent_block, src, file_root_decl_index); + return Air.internedToRef(zcu.fileRootType(result.file_index)); } fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -6423,36 +6362,40 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void defer tracy.end(); const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; const src = block.nodeOffset(inst_data.src_node); const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); const options_src = block.builtinCallArgSrc(inst_data.src_node, 1); - const decl_name = try mod.intern_pool.getOrPutString( - mod.gpa, + const decl_name = try ip.getOrPutString( + zcu.gpa, pt.tid, sema.code.nullTerminatedString(extra.decl_name), .no_embedded_nulls, ); - const decl_index = if (extra.namespace != .none) index_blk: { + const nav_index = if (extra.namespace != .none) index_blk: { const container_ty = try sema.resolveType(block, operand_src, extra.namespace); - const container_namespace = container_ty.getNamespaceIndex(mod); + const container_namespace = container_ty.getNamespaceIndex(zcu); - const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false); - break :index_blk maybe_index orelse + const lookup = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false) orelse return sema.failWithBadMemberAccess(block, container_ty, operand_src, decl_name); + + break :index_blk lookup.nav; } else try sema.lookupIdentifier(block, operand_src, decl_name); const options = try sema.resolveExportOptions(block, options_src, extra.options); - { - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = decl_index })); - try sema.ensureDeclAnalyzed(decl_index); - const exported_decl = mod.declPtr(decl_index); - if (exported_decl.val.getFunction(mod)) |function| { - return sema.analyzeExport(block, src, options, function.owner_decl); - } - } - try sema.analyzeExport(block, src, options, decl_index); + + try sema.ensureNavResolved(src, nav_index); + + // Make sure to export the owner Nav if applicable. + const exported_nav = switch (ip.indexToKey(ip.getNav(nav_index).status.resolved.val)) { + .variable => |v| v.owner_nav, + .@"extern" => |e| e.owner_nav, + .func => |f| f.owner_nav, + else => nav_index, + }; + try sema.analyzeExport(block, src, options, exported_nav); } fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { @@ -6460,7 +6403,8 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError defer tracy.end(); const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data; const src = block.nodeOffset(inst_data.src_node); @@ -6472,17 +6416,24 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const options = try sema.resolveExportOptions(block, options_src, extra.options); if (options.linkage == .internal) return; - if (operand.getFunction(mod)) |function| { - const decl_index = function.owner_decl; - return sema.analyzeExport(block, src, options, decl_index); - } - try sema.exports.append(mod.gpa, .{ - .opts = options, - .src = src, - .exported = .{ .value = operand.toIntern() }, - .status = .in_progress, - }); + // If the value has an owner Nav, export that instead. + const maybe_owner_nav = switch (ip.indexToKey(operand.toIntern())) { + .variable => |v| v.owner_nav, + .@"extern" => |e| e.owner_nav, + .func => |f| f.owner_nav, + else => null, + }; + if (maybe_owner_nav) |owner_nav| { + return sema.analyzeExport(block, src, options, owner_nav); + } else { + try sema.exports.append(zcu.gpa, .{ + .opts = options, + .src = src, + .exported = .{ .uav = operand.toIntern() }, + .status = .in_progress, + }); + } } pub fn analyzeExport( @@ -6490,22 +6441,22 @@ pub fn analyzeExport( block: *Block, src: LazySrcLoc, options: Module.Export.Options, - exported_decl_index: InternPool.DeclIndex, + exported_nav_index: InternPool.Nav.Index, ) !void { const gpa = sema.gpa; const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; if (options.linkage == .internal) return; - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = exported_decl_index })); - try sema.ensureDeclAnalyzed(exported_decl_index); - const exported_decl = mod.declPtr(exported_decl_index); - const export_ty = exported_decl.typeOf(mod); + try sema.ensureNavResolved(src, exported_nav_index); + const exported_nav = ip.getNav(exported_nav_index); + const export_ty = Type.fromInterned(exported_nav.typeOf(ip)); if (!try sema.validateExternType(export_ty, .other)) { - const msg = msg: { + return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)}); errdefer msg.destroy(gpa); @@ -6513,59 +6464,50 @@ pub fn analyzeExport( try sema.addDeclaredHereNote(msg, export_ty); break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + }); } // TODO: some backends might support re-exporting extern decls - if (exported_decl.isExtern(mod)) { + if (exported_nav.isExtern(ip)) { return sema.fail(block, src, "export target cannot be extern", .{}); } - try sema.maybeQueueFuncBodyAnalysis(src, exported_decl_index); + try sema.maybeQueueFuncBodyAnalysis(src, exported_nav_index); try sema.exports.append(gpa, .{ .opts = options, .src = src, - .exported = .{ .decl_index = exported_decl_index }, + .exported = .{ .nav = exported_nav_index }, .status = .in_progress, }); } fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const operand_src = block.builtinCallArgSrc(extra.node, 0); const src = block.nodeOffset(extra.node); const alignment = try sema.resolveAlign(block, operand_src, extra.operand); + + const func = switch (sema.owner.unwrap()) { + .func => |func| func, + .cau => return sema.fail(block, src, "@setAlignStack outside of function scope", .{}), + }; + if (alignment.order(Alignment.fromNonzeroByteUnits(256)).compare(.gt)) { return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{ alignment.toByteUnits().?, }); } - const fn_owner_decl = mod.funcOwnerDeclPtr(sema.func_index); - switch (fn_owner_decl.typeOf(mod).fnCallingConvention(mod)) { + switch (Value.fromInterned(func).typeOf(zcu).fnCallingConvention(zcu)) { .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}), .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}), - else => if (block.inlining != null) { - return sema.fail(block, src, "@setAlignStack in inline call", .{}); - }, - } - - if (sema.prev_stack_alignment_src) |prev_src| { - const msg = msg: { - const msg = try sema.errMsg(src, "multiple @setAlignStack in the same function body", .{}); - errdefer msg.destroy(sema.gpa); - try sema.errNote(prev_src, msg, "other instance here", .{}); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + else => {}, } - sema.prev_stack_alignment_src = src; - mod.intern_pool.funcMaxStackAlignment(sema.func_index, alignment); + zcu.intern_pool.funcMaxStackAlignment(sema.func_index, alignment); } fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { @@ -6577,16 +6519,24 @@ fn zirSetCold(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) const is_cold = try sema.resolveConstBool(block, operand_src, extra.operand, .{ .needed_comptime_reason = "operand to @setCold must be comptime-known", }); - if (sema.func_index == .none) return; // does nothing outside a function - ip.funcSetCold(sema.func_index, is_cold); + // TODO: should `@setCold` apply to the parent in an inline call? + // See also #20642 and friends. + const func = switch (sema.owner.unwrap()) { + .func => |func| func, + .cau => return, // does nothing outside a function + }; + ip.funcSetCold(func, is_cold); } fn zirDisableInstrumentation(sema: *Sema) CompileError!void { const pt = sema.pt; const mod = pt.zcu; const ip = &mod.intern_pool; - if (sema.func_index == .none) return; // does nothing outside a function - ip.funcSetDisableInstrumentation(sema.func_index); + const func = switch (sema.owner.unwrap()) { + .func => |func| func, + .cau => return, // does nothing outside a function + }; + ip.funcSetDisableInstrumentation(func); } fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { @@ -6760,8 +6710,8 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air inst_data.get(sema.code), .no_embedded_nulls, ); - const decl_index = try sema.lookupIdentifier(block, src, decl_name); - return sema.analyzeDeclRef(src, decl_index); + const nav_index = try sema.lookupIdentifier(block, src, decl_name); + return sema.analyzeNavRef(src, nav_index); } fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -6775,17 +6725,18 @@ fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air inst_data.get(sema.code), .no_embedded_nulls, ); - const decl = try sema.lookupIdentifier(block, src, decl_name); - return sema.analyzeDeclVal(block, src, decl); + const nav = try sema.lookupIdentifier(block, src, decl_name); + return sema.analyzeNavVal(block, src, nav); } -fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: InternPool.NullTerminatedString) !InternPool.DeclIndex { +fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: InternPool.NullTerminatedString) !InternPool.Nav.Index { const pt = sema.pt; const mod = pt.zcu; var namespace = block.namespace; while (true) { - if (try sema.lookupInNamespace(block, src, namespace.toOptional(), name, false)) |decl_index| { - return decl_index; + if (try sema.lookupInNamespace(block, src, namespace, name, false)) |lookup| { + assert(lookup.accessible); + return lookup.nav; } namespace = mod.namespacePtr(namespace).parent.unwrap() orelse break; } @@ -6798,69 +6749,74 @@ fn lookupInNamespace( sema: *Sema, block: *Block, src: LazySrcLoc, - opt_namespace_index: InternPool.OptionalNamespaceIndex, + namespace_index: InternPool.NamespaceIndex, ident_name: InternPool.NullTerminatedString, observe_usingnamespace: bool, -) CompileError!?InternPool.DeclIndex { +) CompileError!?struct { + nav: InternPool.Nav.Index, + /// If `false`, the declaration is in a different file and is not `pub`. + /// We still return the declaration for better error reporting. + accessible: bool, +} { const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; - const namespace_index = opt_namespace_index.unwrap() orelse return null; - const namespace = mod.namespacePtr(namespace_index); - const namespace_decl = mod.declPtr(namespace.decl_index); - if (namespace_decl.analysis == .file_failure) { - return error.AnalysisFail; - } + const namespace = zcu.namespacePtr(namespace_index); - if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) { - const src_file = mod.namespacePtr(block.namespace).file_scope; + const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu }; + const src_file = zcu.namespacePtr(block.namespace).file_scope; + + if (observe_usingnamespace and (namespace.pub_usingnamespace.items.len != 0 or namespace.priv_usingnamespace.items.len != 0)) { const gpa = sema.gpa; - var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, bool) = .{}; + var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, void) = .{}; defer checked_namespaces.deinit(gpa); // Keep track of name conflicts for error notes. - var candidates: std.ArrayListUnmanaged(InternPool.DeclIndex) = .{}; + var candidates: std.ArrayListUnmanaged(InternPool.Nav.Index) = .{}; defer candidates.deinit(gpa); - try checked_namespaces.put(gpa, namespace, namespace.file_scope == src_file); + try checked_namespaces.put(gpa, namespace, {}); var check_i: usize = 0; while (check_i < checked_namespaces.count()) : (check_i += 1) { const check_ns = checked_namespaces.keys()[check_i]; - if (check_ns.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .zcu = mod })) |decl_index| { - // Skip decls which are not marked pub, which are in a different - // file than the `a.b`/`@hasDecl` syntax. - const decl = mod.declPtr(decl_index); - if (decl.is_pub or (src_file == decl.getFileScopeIndex(mod) and - checked_namespaces.values()[check_i])) - { - try candidates.append(gpa, decl_index); - } - } - var it = check_ns.usingnamespace_set.iterator(); - while (it.next()) |entry| { - const sub_usingnamespace_decl_index = entry.key_ptr.*; - // Skip the decl we're currently analysing. - if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue; - const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index); - const sub_is_pub = entry.value_ptr.*; - if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScopeIndex(mod)) { - // Skip usingnamespace decls which are not marked pub, which are in - // a different file than the `a.b`/`@hasDecl` syntax. + const Pass = enum { @"pub", priv }; + for ([2]Pass{ .@"pub", .priv }) |pass| { + if (pass == .priv and src_file != check_ns.file_scope) { continue; } - try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index); - const ns_ty = sub_usingnamespace_decl.val.toType(); - const sub_ns = mod.namespacePtrUnwrap(ns_ty.getNamespaceIndex(mod)) orelse continue; - try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScopeIndex(mod)); + + const decls, const usingnamespaces = switch (pass) { + .@"pub" => .{ &check_ns.pub_decls, &check_ns.pub_usingnamespace }, + .priv => .{ &check_ns.priv_decls, &check_ns.priv_usingnamespace }, + }; + + if (decls.getKeyAdapted(ident_name, adapter)) |nav_index| { + try candidates.append(gpa, nav_index); + } + + for (usingnamespaces.items) |sub_ns_nav| { + try sema.ensureNavResolved(src, sub_ns_nav); + const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.resolved.val); + const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu)); + try checked_namespaces.put(gpa, sub_ns, {}); + } } } - { + ignore_self: { + const skip_nav = switch (sema.owner.unwrap()) { + .func => break :ignore_self, + .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) { + .none, .type => break :ignore_self, + .nav => |nav| nav, + }, + }; var i: usize = 0; while (i < candidates.items.len) { - if (candidates.items[i] == sema.owner_decl_index) { + if (candidates.items[i] == skip_nav) { _ = candidates.orderedRemove(i); } else { i += 1; @@ -6870,48 +6826,50 @@ fn lookupInNamespace( switch (candidates.items.len) { 0 => {}, - 1 => { - const decl_index = candidates.items[0]; - return decl_index; - }, - else => { - const msg = msg: { - const msg = try sema.errMsg(src, "ambiguous reference", .{}); - errdefer msg.destroy(gpa); - for (candidates.items) |candidate_index| { - const candidate = mod.declPtr(candidate_index); - try sema.errNote(.{ - .base_node_inst = candidate.zir_decl_index.unwrap().?, - .offset = LazySrcLoc.Offset.nodeOffset(0), - }, msg, "declared here", .{}); - } - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + 1 => return .{ + .nav = candidates.items[0], + .accessible = true, }, + else => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(src, "ambiguous reference", .{}); + errdefer msg.destroy(gpa); + for (candidates.items) |candidate| { + try sema.errNote(zcu.navSrcLoc(candidate), msg, "declared here", .{}); + } + break :msg msg; + }), } - } else if (namespace.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .zcu = mod })) |decl_index| { - return decl_index; + } else if (namespace.pub_decls.getKeyAdapted(ident_name, adapter)) |nav_index| { + return .{ + .nav = nav_index, + .accessible = true, + }; + } else if (namespace.priv_decls.getKeyAdapted(ident_name, adapter)) |nav_index| { + return .{ + .nav = nav_index, + .accessible = src_file == namespace.file_scope, + }; } return null; } -fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { +fn funcDeclSrcInst(sema: *Sema, func_inst: Air.Inst.Ref) !?InternPool.TrackedInst.Index { const pt = sema.pt; - const mod = pt.zcu; - const func_val = (try sema.resolveValue(func_inst)) orelse return null; - if (func_val.isUndef(mod)) return null; - const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { - .extern_func => |extern_func| extern_func.decl, - .func => |func| func.owner_decl, + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + const func_val = try sema.resolveValue(func_inst) orelse return null; + if (func_val.isUndef(zcu)) return null; + const nav = switch (ip.indexToKey(func_val.toIntern())) { + .@"extern" => |e| e.owner_nav, + .func => |f| f.owner_nav, .ptr => |ptr| switch (ptr.base_addr) { - .decl => |decl| if (ptr.byte_offset == 0) mod.declPtr(decl).val.getFunction(mod).?.owner_decl else return null, + .nav => |nav| if (ptr.byte_offset == 0) nav else return null, else => return null, }, else => return null, }; - return mod.declPtr(owner_decl_index); + return ip.getNav(nav).srcInst(ip); } pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { @@ -7100,11 +7058,12 @@ fn zirCall( const call_dbg_node: Zir.Inst.Index = @enumFromInt(@intFromEnum(inst) - 1); const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); - if (sema.owner_func_index == .none or - !mod.intern_pool.funcAnalysisUnordered(sema.owner_func_index).calls_or_awaits_errorable_fn) - { - // No errorable fn actually called; we have no error return trace - input_is_error = false; + switch (sema.owner.unwrap()) { + .cau => input_is_error = false, + .func => |owner_func| if (!mod.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) { + // No errorable fn actually called; we have no error return trace + input_is_error = false; + }, } if (block.ownerModule().error_tracing and @@ -7199,7 +7158,7 @@ fn checkCallArgumentCount( return func_ty; } - const maybe_decl = try sema.funcDeclSrc(func); + const maybe_func_inst = try sema.funcDeclSrcInst(func); const member_str = if (member_fn) "member function " else ""; const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; const msg = msg: { @@ -7215,9 +7174,9 @@ fn checkCallArgumentCount( ); errdefer msg.destroy(sema.gpa); - if (maybe_decl) |fn_decl| { + if (maybe_func_inst) |func_inst| { try sema.errNote(.{ - .base_node_inst = fn_decl.zir_decl_index.unwrap().?, + .base_node_inst = func_inst, .offset = LazySrcLoc.Offset.nodeOffset(0), }, msg, "function declared here", .{}); } @@ -7544,7 +7503,7 @@ fn analyzeCall( if (func_val.isUndef(mod)) return sema.failWithUseOfUndef(block, call_src); if (cc == .Naked) { - const maybe_decl = try sema.funcDeclSrc(func); + const maybe_func_inst = try sema.funcDeclSrcInst(func); const msg = msg: { const msg = try sema.errMsg( func_src, @@ -7553,8 +7512,8 @@ fn analyzeCall( ); errdefer msg.destroy(sema.gpa); - if (maybe_decl) |fn_decl| try sema.errNote(.{ - .base_node_inst = fn_decl.zir_decl_index.unwrap().?, + if (maybe_func_inst) |func_inst| try sema.errNote(.{ + .base_node_inst = func_inst, .offset = LazySrcLoc.Offset.nodeOffset(0), }, msg, "function declared here", .{}); break :msg msg; @@ -7654,33 +7613,32 @@ fn analyzeCall( .block_comptime_reason = comptime_reason, }); const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { - .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{ + .@"extern" => return sema.fail(block, call_src, "{s} call of extern function", .{ @as([]const u8, if (is_comptime_call) "comptime" else "inline"), }), .func => func_val.toIntern(), .ptr => |ptr| blk: { switch (ptr.base_addr) { - .decl => |decl| if (ptr.byte_offset == 0) { - const func_val_ptr = mod.declPtr(decl).val.toIntern(); - const intern_index = mod.intern_pool.indexToKey(func_val_ptr); - if (intern_index == .extern_func or (intern_index == .variable and intern_index.variable.is_extern)) + .nav => |nav_index| if (ptr.byte_offset == 0) { + const nav = ip.getNav(nav_index); + if (nav.isExtern(ip)) return sema.fail(block, call_src, "{s} call of extern function pointer", .{ - @as([]const u8, if (is_comptime_call) "comptime" else "inline"), + if (is_comptime_call) "comptime" else "inline", }); - break :blk func_val_ptr; + break :blk nav.status.resolved.val; }, else => {}, } assert(callee_ty.isPtrAtRuntime(mod)); return sema.fail(block, call_src, "{s} call of function pointer", .{ - @as([]const u8, if (is_comptime_call) "comptime" else "inline"), + if (is_comptime_call) "comptime" else "inline", }); }, else => unreachable, }; if (func_ty_info.is_var_args) { return sema.fail(block, call_src, "{s} call of variadic function", .{ - @as([]const u8, if (is_comptime_call) "comptime" else "inline"), + if (is_comptime_call) "comptime" else "inline", }); } @@ -7712,7 +7670,12 @@ fn analyzeCall( }; const module_fn = mod.funcInfo(module_fn_index); - const fn_owner_decl = mod.declPtr(module_fn.owner_decl); + + // This is not a function instance, so the function's `Nav` has a + // `Cau` -- we don't need to check `generic_owner`. + const fn_nav = ip.getNav(module_fn.owner_nav); + const fn_cau_index = fn_nav.analysis_owner.unwrap().?; + const fn_cau = ip.getCau(fn_cau_index); // We effectively want a child Sema here, but can't literally do that, because we need AIR // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in @@ -7720,7 +7683,7 @@ fn analyzeCall( // whenever performing an operation where the difference matters. var ics = InlineCallSema.init( sema, - fn_owner_decl.getFileScope(mod).zir, + mod.cauFileScope(fn_cau_index).zir, module_fn_index, block.error_return_trace_index, ); @@ -7729,7 +7692,8 @@ fn analyzeCall( var child_block: Block = .{ .parent = null, .sema = sema, - .namespace = fn_owner_decl.src_namespace, + // The function body exists in the same namespace as the corresponding function declaration. + .namespace = fn_cau.namespace, .instructions = .{}, .label = null, .inlining = &inlining, @@ -7740,8 +7704,8 @@ fn analyzeCall( .runtime_cond = block.runtime_cond, .runtime_loop = block.runtime_loop, .runtime_index = block.runtime_index, - .src_base_inst = fn_owner_decl.zir_decl_index.unwrap().?, - .type_name_ctx = fn_owner_decl.name, + .src_base_inst = fn_cau.zir_index, + .type_name_ctx = fn_nav.fqn, }; const merges = &child_block.inlining.?.merges; @@ -7759,7 +7723,7 @@ fn analyzeCall( // comptime memory is mutated. const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); - const owner_info = mod.typeToFunc(fn_owner_decl.typeOf(mod)).?; + const owner_info = mod.typeToFunc(Type.fromInterned(module_fn.ty)).?; const new_param_types = try sema.arena.alloc(InternPool.Index, owner_info.param_types.len); var new_fn_info: InternPool.GetFuncTypeKey = .{ .param_types = new_param_types, @@ -7809,9 +7773,6 @@ fn analyzeCall( _ = ics.callee(); if (!inlining.has_comptime_args) { - if (module_fn.analysisUnordered(ip).state == .sema_failure) - return error.AnalysisFail; - var block_it = block; while (block_it.inlining) |parent_inlining| { if (!parent_inlining.has_comptime_args and parent_inlining.func == module_fn_index) { @@ -7957,8 +7918,11 @@ fn analyzeCall( if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); - if (sema.owner_func_index != .none and Type.fromInterned(func_ty_info.return_type).isError(mod)) { - ip.funcSetCallsOrAwaitsErrorableFn(sema.owner_func_index); + switch (sema.owner.unwrap()) { + .cau => {}, + .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(mod)) { + ip.funcSetCallsOrAwaitsErrorableFn(owner_func); + }, } if (try sema.resolveValue(func)) |func_val| { @@ -7994,7 +7958,7 @@ fn analyzeCall( switch (mod.intern_pool.indexToKey(func_val.toIntern())) { .func => break :skip_safety, .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { - .decl => |decl| if (!mod.declPtr(decl).isExtern(mod)) break :skip_safety, + .nav => |nav| if (!ip.getNav(nav).isExtern(ip)) break :skip_safety, else => {}, }, else => {}, @@ -8018,18 +7982,18 @@ fn analyzeCall( fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { const pt = sema.pt; - const mod = pt.zcu; - const target = mod.getTarget(); - const backend = mod.comp.getZigBackend(); + const zcu = pt.zcu; + const target = zcu.getTarget(); + const backend = zcu.comp.getZigBackend(); if (!target_util.supportsTailCall(target, backend)) { return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{ @tagName(backend), @tagName(target.cpu.arch), }); } - const func_decl = mod.funcOwnerDeclPtr(sema.owner_func_index); - if (!func_ty.eql(func_decl.typeOf(mod), mod)) { + const owner_func_ty = Type.fromInterned(zcu.funcInfo(sema.owner.unwrap().func).ty); + if (owner_func_ty.toIntern() != func_ty.toIntern()) { return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ - func_ty.fmt(pt), func_decl.typeOf(mod).fmt(pt), + func_ty.fmt(pt), owner_func_ty.fmt(pt), }); } _ = try block.addUnOp(.ret, result); @@ -8191,7 +8155,7 @@ fn instantiateGenericCall( }); const generic_owner = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) { .func => func_val.toIntern(), - .ptr => |ptr| zcu.declPtr(ptr.base_addr.decl).val.toIntern(), + .ptr => |ptr| ip.getNav(ptr.base_addr.nav).status.resolved.val, else => unreachable, }; const generic_owner_func = zcu.intern_pool.indexToKey(generic_owner).func; @@ -8207,10 +8171,10 @@ fn instantiateGenericCall( // The actual monomorphization happens via adding `func_instance` to // `InternPool`. - const fn_owner_decl = zcu.declPtr(generic_owner_func.owner_decl); - const namespace_index = fn_owner_decl.src_namespace; - const namespace = zcu.namespacePtr(namespace_index); - const fn_zir = namespace.fileScope(zcu).zir; + // Since we are looking at the generic owner here, it has a `Cau`. + const fn_nav = ip.getNav(generic_owner_func.owner_nav); + const fn_cau = ip.getCau(fn_nav.analysis_owner.unwrap().?); + const fn_zir = zcu.namespacePtr(fn_cau.namespace).fileScope(zcu).zir; const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip)); const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count()); @@ -8232,15 +8196,13 @@ fn instantiateGenericCall( // We pass the generic callsite's owner decl here because whatever `Decl` // dependencies are chased at this point should be attached to the // callsite, not the `Decl` associated with the `func_instance`. - .owner_decl = sema.owner_decl, - .owner_decl_index = sema.owner_decl_index, - .func_index = sema.owner_func_index, + .owner = sema.owner, + .func_index = sema.func_index, // This may not be known yet, since the calling convention could be generic, but there // should be no illegal instructions encountered while creating the function anyway. .func_is_naked = false, .fn_ret_ty = Type.void, .fn_ret_ty_ies = null, - .owner_func_index = .none, .comptime_args = comptime_args, .generic_owner = generic_owner, .generic_call_src = call_src, @@ -8253,12 +8215,12 @@ fn instantiateGenericCall( var child_block: Block = .{ .parent = null, .sema = &child_sema, - .namespace = namespace_index, + .namespace = fn_cau.namespace, .instructions = .{}, .inlining = null, .is_comptime = true, - .src_base_inst = fn_owner_decl.zir_decl_index.unwrap().?, - .type_name_ctx = fn_owner_decl.name, + .src_base_inst = fn_cau.zir_index, + .type_name_ctx = fn_nav.fqn, }; defer child_block.instructions.deinit(gpa); @@ -8421,10 +8383,11 @@ fn instantiateGenericCall( if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); - if (sema.owner_func_index != .none and - Type.fromInterned(func_ty_info.return_type).isError(zcu)) - { - ip.funcSetCallsOrAwaitsErrorableFn(sema.owner_func_index); + switch (sema.owner.unwrap()) { + .cau => {}, + .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) { + ip.funcSetCallsOrAwaitsErrorableFn(owner_func); + }, } try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = callee_index })); @@ -9366,10 +9329,11 @@ fn zirFunc( inferred_error_set: bool, ) CompileError!Air.Inst.Ref { const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); - const target = mod.getTarget(); + const target = zcu.getTarget(); const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = inst_data.src_node }); var extra_index = extra.end; @@ -9410,11 +9374,17 @@ fn zirFunc( // the callconv based on whether it is exported. Otherwise, the callconv defaults // to `.Unspecified`. const cc: std.builtin.CallingConvention = if (has_body) cc: { - const fn_is_exported = if (sema.generic_owner != .none) exported: { - const generic_owner_fn = mod.funcInfo(sema.generic_owner); - const generic_owner_decl = mod.declPtr(generic_owner_fn.owner_decl); - break :exported generic_owner_decl.is_exported; - } else sema.owner_decl.is_exported; + const func_decl_cau = if (sema.generic_owner != .none) cau: { + const generic_owner_fn = zcu.funcInfo(sema.generic_owner); + // The generic owner definitely has a `Cau` for the corresponding function declaration. + const generic_owner_nav = ip.getNav(generic_owner_fn.owner_nav); + break :cau generic_owner_nav.analysis_owner.unwrap().?; + } else sema.owner.unwrap().cau; + const fn_is_exported = exported: { + const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip); + const zir_decl = sema.code.getDeclaration(decl_inst)[0]; + break :exported zir_decl.flags.is_export; + }; break :cc if (fn_is_exported) .C else .Unspecified; } else .Unspecified; @@ -9613,10 +9583,10 @@ fn funcCommon( is_noinline: bool, ) CompileError!Air.Inst.Ref { const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; const gpa = sema.gpa; - const target = mod.getTarget(); - const ip = &mod.intern_pool; + const target = zcu.getTarget(); + const ip = &zcu.intern_pool; const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset }); const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset }); const func_src = block.nodeOffset(src_node_offset); @@ -9664,8 +9634,8 @@ fn funcCommon( if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved)) { return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc_resolved)}); } - if (!param_ty.isValidParamType(mod)) { - const opaque_str = if (param_ty.zigTypeTag(mod) == .Opaque) "opaque " else ""; + if (!param_ty.isValidParamType(zcu)) { + const opaque_str = if (param_ty.zigTypeTag(zcu) == .Opaque) "opaque " else ""; return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{ opaque_str, param_ty.fmt(pt), }); @@ -9699,7 +9669,7 @@ fn funcCommon( return sema.failWithOwnedErrorMsg(block, msg); } if (is_source_decl and !this_generic and is_noalias and - !(param_ty.zigTypeTag(mod) == .Pointer or param_ty.isPtrLikeOptional(mod))) + !(param_ty.zigTypeTag(zcu) == .Pointer or param_ty.isPtrLikeOptional(zcu))) { return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{}); } @@ -9707,7 +9677,7 @@ fn funcCommon( .Interrupt => if (target.cpu.arch.isX86()) { const err_code_size = target.ptrBitWidth(); switch (i) { - 0 => if (param_ty.zigTypeTag(mod) != .Pointer) return sema.fail(block, param_src, "first parameter of function with 'Interrupt' calling convention must be a pointer type", .{}), + 0 => if (param_ty.zigTypeTag(zcu) != .Pointer) return sema.fail(block, param_src, "first parameter of function with 'Interrupt' calling convention must be a pointer type", .{}), 1 => if (param_ty.bitSize(pt) != err_code_size) return sema.fail(block, param_src, "second parameter of function with 'Interrupt' calling convention must be a {d}-bit integer", .{err_code_size}), else => return sema.fail(block, param_src, "'Interrupt' calling convention supports up to 2 parameters, found {d}", .{i + 1}), } @@ -9769,14 +9739,11 @@ fn funcCommon( ); } - // extern_func and func_decl functions take ownership of `sema.owner_decl`. - sema.owner_decl.@"linksection" = switch (section) { + const section_name: InternPool.OptionalNullTerminatedString = switch (section) { .generic => .none, .default => .none, - .explicit => |section_name| section_name.toOptional(), + .explicit => |name| name.toOptional(), }; - sema.owner_decl.alignment = alignment orelse .none; - sema.owner_decl.@"addrspace" = address_space orelse .generic; if (inferred_error_set) { assert(!is_extern); @@ -9784,7 +9751,7 @@ fn funcCommon( if (!ret_poison) try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{ - .owner_decl = sema.owner_decl_index, + .owner_nav = sema.getOwnerCauNav(), .param_types = param_types, .noalias_bits = noalias_bits, @@ -9804,6 +9771,13 @@ fn funcCommon( .lbrace_column = @as(u16, @truncate(src_locs.columns)), .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), }); + // func_decl functions take ownership of the `Nav` of Sema'a owner `Cau`. + ip.resolveNavValue(sema.getOwnerCauNav(), .{ + .val = func_index, + .alignment = alignment orelse .none, + .@"linksection" = section_name, + .@"addrspace" = address_space orelse .generic, + }); return finishFunc( sema, block, @@ -9846,11 +9820,20 @@ fn funcCommon( if (opt_lib_name) |lib_name| try sema.handleExternLibName(block, block.src(.{ .node_offset_lib_name = src_node_offset, }), lib_name); - const func_index = try ip.getExternFunc(gpa, pt.tid, .{ + const func_index = try pt.getExtern(.{ + .name = sema.getOwnerCauNavName(), .ty = func_ty, - .decl = sema.owner_decl_index, - .lib_name = try mod.intern_pool.getOrPutStringOpt(gpa, pt.tid, opt_lib_name, .no_embedded_nulls), + .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, opt_lib_name, .no_embedded_nulls), + .is_const = true, + .is_threadlocal = false, + .is_weak_linkage = false, + .alignment = alignment orelse .none, + .@"addrspace" = address_space orelse .generic, + .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction + .owner_nav = undefined, // ignored by `getExtern` }); + // Note that unlike function declaration, extern functions don't touch the + // Sema's owner Cau's owner Nav. The alignment etc were passed above. return finishFunc( sema, block, @@ -9872,7 +9855,7 @@ fn funcCommon( if (has_body) { const func_index = try ip.getFuncDecl(gpa, pt.tid, .{ - .owner_decl = sema.owner_decl_index, + .owner_nav = sema.getOwnerCauNav(), .ty = func_ty, .cc = cc, .is_noinline = is_noinline, @@ -9882,6 +9865,13 @@ fn funcCommon( .lbrace_column = @as(u16, @truncate(src_locs.columns)), .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)), }); + // func_decl functions take ownership of the `Nav` of Sema'a owner `Cau`. + ip.resolveNavValue(sema.getOwnerCauNav(), .{ + .val = func_index, + .alignment = alignment orelse .none, + .@"linksection" = section_name, + .@"addrspace" = address_space orelse .generic, + }); return finishFunc( sema, block, @@ -11179,7 +11169,7 @@ const SwitchProngAnalysis = struct { return block.addStructFieldVal(spa.operand, field_index, field_ty); } } else if (capture_byref) { - return anonDeclRef(sema, item_val.toIntern()); + return sema.uavRef(item_val.toIntern()); } else { return inline_case_capture; } @@ -13946,10 +13936,9 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } }); } - const namespace = container_type.getNamespaceIndex(mod); - if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { - const decl = mod.declPtr(decl_index); - if (decl.is_pub or decl.getFileScope(mod) == block.getFileScope(mod)) { + const namespace = container_type.getNamespace(mod).unwrap() orelse return .bool_false; + if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |lookup| { + if (lookup.accessible) { return .bool_true; } } @@ -13981,9 +13970,11 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) }); }, }; + // TODO: register some kind of dependency on the file. + // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to + // trigger re-analysis later. try pt.ensureFileAnalyzed(result.file_index); - const file_root_decl_index = zcu.fileRootDecl(result.file_index).unwrap().?; - return sema.analyzeDeclVal(block, operand_src, file_root_decl_index); + return Air.internedToRef(zcu.fileRootType(result.file_index)); } fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -16970,7 +16961,7 @@ fn analyzeArithmetic( if (block.wantSafety() and want_safety and scalar_tag == .Int) { if (mod.backendSupportsFeature(.safety_checked_instructions)) { if (air_tag != air_tag_safe) { - _ = try sema.preparePanicId(block, .integer_overflow); + _ = try sema.preparePanicId(block, src, .integer_overflow); } return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs); } else { @@ -17158,13 +17149,11 @@ fn zirAsm( if (is_volatile) { return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{}); } - try mod.addGlobalAssembly(sema.owner_decl_index, asm_source); + try mod.addGlobalAssembly(sema.owner.unwrap().cau, asm_source); return .void_value; } - if (block.is_comptime) { - try sema.requireRuntimeBlock(block, src, null); - } + try sema.requireRuntimeBlock(block, src, null); var extra_i = extra.end; var output_type_bits = extra.data.output_type_bits; @@ -17646,18 +17635,17 @@ fn zirThis( block: *Block, extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { + _ = extended; const pt = sema.pt; - const mod = pt.zcu; - const this_decl_index = mod.namespacePtr(block.namespace).decl_index; - const src = block.nodeOffset(@bitCast(extended.operand)); - return sema.analyzeDeclVal(block, src, this_decl_index); + const namespace = pt.zcu.namespacePtr(block.namespace); + return Air.internedToRef(namespace.owner_type); } fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { const pt = sema.pt; const mod = pt.zcu; const ip = &mod.intern_pool; - const captures = mod.namespacePtr(block.namespace).getType(mod).getCaptures(mod); + const captures = Type.fromInterned(mod.namespacePtr(block.namespace).owner_type).getCaptures(mod); const src_node: i32 = @bitCast(extended.operand); const src = block.nodeOffset(src_node); @@ -17665,8 +17653,8 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) { .@"comptime" => |index| return Air.internedToRef(index), .runtime => |index| index, - .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index), - .decl_ref => |decl_index| return sema.analyzeDeclRef(src, decl_index), + .nav_val => |nav| return sema.analyzeNavVal(block, src, nav), + .nav_ref => |nav| return sema.analyzeNavRef(src, nav), }; // The comptime case is handled already above. Runtime case below. @@ -17764,20 +17752,19 @@ fn zirBuiltinSrc( block: *Block, extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { - _ = block; const tracy = trace(@src()); defer tracy.end(); const pt = sema.pt; const zcu = pt.zcu; - const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data; - const fn_owner_decl = zcu.funcOwnerDeclPtr(sema.func_index); const ip = &zcu.intern_pool; + const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data; + const fn_name = ip.getNav(zcu.funcInfo(sema.func_index).owner_nav).name; const gpa = sema.gpa; - const file_scope = fn_owner_decl.getFileScope(zcu); + const file_scope = block.getFileScope(zcu); const func_name_val = v: { - const func_name_len = fn_owner_decl.name.length(ip); + const func_name_len = fn_name.length(ip); const array_ty = try pt.intern(.{ .array_type = .{ .len = func_name_len, .sentinel = .zero_u8, @@ -17787,11 +17774,11 @@ fn zirBuiltinSrc( .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = .slice_const_u8_sentinel_0_type, .val = try pt.intern(.{ .aggregate = .{ .ty = array_ty, - .storage = .{ .bytes = fn_owner_decl.name.toString() }, + .storage = .{ .bytes = fn_name.toString() }, } }), } }, .byte_offset = 0, @@ -17811,7 +17798,7 @@ fn zirBuiltinSrc( .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = .slice_const_u8_sentinel_0_type, .val = try pt.intern(.{ .aggregate = .{ .ty = array_ty, @@ -17837,7 +17824,7 @@ fn zirBuiltinSrc( .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = .slice_const_u8_sentinel_0_type, .val = try pt.intern(.{ .aggregate = .{ .ty = array_ty, @@ -17902,25 +17889,23 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .val = .void_value, } }))), .Fn => { - const fn_info_decl_index = (try sema.namespaceLookup( + const fn_info_nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Fn", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(fn_info_decl_index); - const fn_info_decl = mod.declPtr(fn_info_decl_index); - const fn_info_ty = fn_info_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, fn_info_nav); + const fn_info_ty = Type.fromInterned(ip.getNav(fn_info_nav).status.resolved.val); - const param_info_decl_index = (try sema.namespaceLookup( + const param_info_nav = try sema.namespaceLookup( block, src, fn_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Param", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(param_info_decl_index); - const param_info_decl = mod.declPtr(param_info_decl_index); - const param_info_ty = param_info_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, param_info_nav); + const param_info_ty = Type.fromInterned(ip.getNav(param_info_nav).status.resolved.val); const func_ty_info = mod.typeToFunc(ty).?; const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); @@ -17972,7 +17957,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = slice_ty, .ptr = try pt.intern(.{ .ptr = .{ .ty = manyptr_ty, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = manyptr_ty, .val = new_decl_val, } }, @@ -18014,15 +17999,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }))); }, .Int => { - const int_info_decl_index = (try sema.namespaceLookup( + const int_info_nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Int", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(int_info_decl_index); - const int_info_decl = mod.declPtr(int_info_decl_index); - const int_info_ty = int_info_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, int_info_nav); + const int_info_ty = Type.fromInterned(ip.getNav(int_info_nav).status.resolved.val); const signedness_ty = try pt.getBuiltinType("Signedness"); const info = ty.intInfo(mod); @@ -18042,15 +18026,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }))); }, .Float => { - const float_info_decl_index = (try sema.namespaceLookup( + const float_info_nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Float", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(float_info_decl_index); - const float_info_decl = mod.declPtr(float_info_decl_index); - const float_info_ty = float_info_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, float_info_nav); + const float_info_ty = Type.fromInterned(ip.getNav(float_info_nav).status.resolved.val); const field_vals = .{ // bits: u16, @@ -18074,26 +18057,24 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const addrspace_ty = try pt.getBuiltinType("AddressSpace"); const pointer_ty = t: { - const decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, (try pt.getBuiltinType("Type")).getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Pointer", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(decl_index); - const decl = mod.declPtr(decl_index); - break :t decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const ptr_size_ty = t: { - const decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, pointer_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Size", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(decl_index); - const decl = mod.declPtr(decl_index); - break :t decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const field_values = .{ @@ -18128,15 +18109,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .Array => { const array_field_ty = t: { - const array_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Array", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(array_field_ty_decl_index); - const array_field_ty_decl = mod.declPtr(array_field_ty_decl_index); - break :t array_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const info = ty.arrayInfo(mod); @@ -18159,15 +18139,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .Vector => { const vector_field_ty = t: { - const vector_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Vector", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(vector_field_ty_decl_index); - const vector_field_ty_decl = mod.declPtr(vector_field_ty_decl_index); - break :t vector_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const info = ty.arrayInfo(mod); @@ -18188,15 +18167,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .Optional => { const optional_field_ty = t: { - const optional_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Optional", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(optional_field_ty_decl_index); - const optional_field_ty_decl = mod.declPtr(optional_field_ty_decl_index); - break :t optional_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const field_values = .{ @@ -18215,15 +18193,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ErrorSet => { // Get the Error type const error_field_ty = t: { - const set_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Error", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(set_field_ty_decl_index); - const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index); - break :t set_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; // Build our list of Error values @@ -18251,7 +18228,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = new_decl_val, .orig_ty = .slice_const_u8_sentinel_0_type, } }, @@ -18298,7 +18275,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = slice_errors_ty.toIntern(), .ptr = try pt.intern(.{ .ptr = .{ .ty = manyptr_errors_ty, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = manyptr_errors_ty, .val = new_decl_val, } }, @@ -18321,15 +18298,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .ErrorUnion => { const error_union_field_ty = t: { - const error_union_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "ErrorUnion", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index); - const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index); - break :t error_union_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const field_values = .{ @@ -18351,15 +18327,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive); const enum_field_ty = t: { - const enum_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "EnumField", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); - const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index); - break :t enum_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len); @@ -18392,7 +18367,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = new_decl_val, .orig_ty = .slice_const_u8_sentinel_0_type, } }, @@ -18435,7 +18410,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = slice_ty, .ptr = try pt.intern(.{ .ptr = .{ .ty = manyptr_ty, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = new_decl_val, .orig_ty = manyptr_ty, } }, @@ -18445,18 +18420,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.loadEnumType(ty.toIntern()).namespace); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.loadEnumType(ty.toIntern()).namespace.toOptional()); const type_enum_ty = t: { - const type_enum_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Enum", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(type_enum_ty_decl_index); - const type_enum_ty_decl = mod.declPtr(type_enum_ty_decl_index); - break :t type_enum_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const field_values = .{ @@ -18480,27 +18454,25 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .Union => { const type_union_ty = t: { - const type_union_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Union", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(type_union_ty_decl_index); - const type_union_ty_decl = mod.declPtr(type_union_ty_decl_index); - break :t type_union_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const union_field_ty = t: { - const union_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "UnionField", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(union_field_ty_decl_index); - const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index); - break :t union_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; try ty.resolveLayout(pt); // Getting alignment requires type layout @@ -18528,7 +18500,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = new_decl_val, .orig_ty = .slice_const_u8_sentinel_0_type, } }, @@ -18579,7 +18551,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = slice_ty, .ptr = try pt.intern(.{ .ptr = .{ .ty = manyptr_ty, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = manyptr_ty, .val = new_decl_val, } }, @@ -18589,7 +18561,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod).toOptional()); const enum_tag_ty_val = try pt.intern(.{ .opt = .{ .ty = (try pt.optionalType(.type_type)).toIntern(), @@ -18597,15 +18569,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); const container_layout_ty = t: { - const decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, (try pt.getBuiltinType("Type")).getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "ContainerLayout", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(decl_index); - const decl = mod.declPtr(decl_index); - break :t decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const field_values = .{ @@ -18630,27 +18601,25 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .Struct => { const type_struct_ty = t: { - const type_struct_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Struct", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(type_struct_ty_decl_index); - const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index); - break :t type_struct_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const struct_field_ty = t: { - const struct_field_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "StructField", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); - const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index); - break :t struct_field_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; try ty.resolveLayout(pt); // Getting alignment requires type layout @@ -18683,7 +18652,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = new_decl_val, .orig_ty = .slice_const_u8_sentinel_0_type, } }, @@ -18747,7 +18716,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = .slice_const_u8_sentinel_0_type, .ptr = try pt.intern(.{ .ptr = .{ .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .val = new_decl_val, .orig_ty = .slice_const_u8_sentinel_0_type, } }, @@ -18809,7 +18778,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .ty = slice_ty, .ptr = try pt.intern(.{ .ptr = .{ .ty = manyptr_ty, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = manyptr_ty, .val = new_decl_val, } }, @@ -18819,7 +18788,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace(mod)); const backing_integer_val = try pt.intern(.{ .opt = .{ .ty = (try pt.optionalType(.type_type)).toIntern(), @@ -18830,15 +18799,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); const container_layout_ty = t: { - const decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, (try pt.getBuiltinType("Type")).getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "ContainerLayout", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(decl_index); - const decl = mod.declPtr(decl_index); - break :t decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; const layout = ty.containerLayout(mod); @@ -18866,19 +18834,18 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .Opaque => { const type_opaque_ty = t: { - const type_opaque_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, type_info_ty.getNamespaceIndex(mod), try ip.getOrPutString(gpa, pt.tid, "Opaque", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index); - const type_opaque_ty_decl = mod.declPtr(type_opaque_ty_decl_index); - break :t type_opaque_ty_decl.val.toType(); + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; try ty.resolveFields(pt); - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace(mod)); const field_values = .{ // decls: []const Declaration, @@ -18906,19 +18873,19 @@ fn typeInfoDecls( opt_namespace: InternPool.OptionalNamespaceIndex, ) CompileError!InternPool.Index { const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const gpa = sema.gpa; const declaration_ty = t: { - const declaration_ty_decl_index = (try sema.namespaceLookup( + const nav = try sema.namespaceLookup( block, src, - type_info_ty.getNamespaceIndex(mod), - try mod.intern_pool.getOrPutString(gpa, pt.tid, "Declaration", .no_embedded_nulls), - )).?; - try sema.ensureDeclAnalyzed(declaration_ty_decl_index); - const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index); - break :t declaration_ty_decl.val.toType(); + type_info_ty.getNamespaceIndex(zcu), + try ip.getOrPutString(gpa, pt.tid, "Declaration", .no_embedded_nulls), + ) orelse @panic("std.builtin.Type is corrupt"); + try sema.ensureNavResolved(src, nav); + break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); }; var decl_vals = std.ArrayList(InternPool.Index).init(gpa); @@ -18927,7 +18894,7 @@ fn typeInfoDecls( var seen_namespaces = std.AutoHashMap(*Namespace, void).init(gpa); defer seen_namespaces.deinit(); - try sema.typeInfoNamespaceDecls(block, opt_namespace, declaration_ty, &decl_vals, &seen_namespaces); + try sema.typeInfoNamespaceDecls(block, src, opt_namespace, declaration_ty, &decl_vals, &seen_namespaces); const array_decl_ty = try pt.arrayType(.{ .len = decl_vals.items.len, @@ -18944,12 +18911,12 @@ fn typeInfoDecls( .is_const = true, }, })).toIntern(); - const manyptr_ty = Type.fromInterned(slice_ty).slicePtrFieldType(mod).toIntern(); + const manyptr_ty = Type.fromInterned(slice_ty).slicePtrFieldType(zcu).toIntern(); return try pt.intern(.{ .slice = .{ .ty = slice_ty, .ptr = try pt.intern(.{ .ptr = .{ .ty = manyptr_ty, - .base_addr = .{ .anon_decl = .{ + .base_addr = .{ .uav = .{ .orig_ty = manyptr_ty, .val = new_decl_val, } }, @@ -18962,59 +18929,54 @@ fn typeInfoDecls( fn typeInfoNamespaceDecls( sema: *Sema, block: *Block, + src: LazySrcLoc, opt_namespace_index: InternPool.OptionalNamespaceIndex, declaration_ty: Type, decl_vals: *std.ArrayList(InternPool.Index), seen_namespaces: *std.AutoHashMap(*Namespace, void), ) !void { const pt = sema.pt; - const mod = pt.zcu; - const ip = &mod.intern_pool; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const namespace_index = opt_namespace_index.unwrap() orelse return; - const namespace = mod.namespacePtr(namespace_index); + const namespace = zcu.namespacePtr(namespace_index); const gop = try seen_namespaces.getOrPut(namespace); if (gop.found_existing) return; - const decls = namespace.decls.keys(); - for (decls) |decl_index| { - const decl = mod.declPtr(decl_index); - if (!decl.is_pub) continue; - if (decl.kind == .@"usingnamespace") { - if (decl.analysis == .in_progress) continue; - try sema.ensureDeclAnalyzed(decl_index); - try sema.typeInfoNamespaceDecls(block, decl.val.toType().getNamespaceIndex(mod), declaration_ty, decl_vals, seen_namespaces); - continue; - } - if (decl.kind != .named) continue; - const name_val = v: { - const decl_name_len = decl.name.length(ip); - const new_decl_ty = try pt.arrayType(.{ - .len = decl_name_len, + for (namespace.pub_decls.keys()) |nav| { + const name = ip.getNav(nav).name; + const name_val = name_val: { + const name_len = name.length(ip); + const array_ty = try pt.arrayType(.{ + .len = name_len, .sentinel = .zero_u8, .child = .u8_type, }); - const new_decl_val = try pt.intern(.{ .aggregate = .{ - .ty = new_decl_ty.toIntern(), - .storage = .{ .bytes = decl.name.toString() }, - } }); - break :v try pt.intern(.{ .slice = .{ - .ty = .slice_const_u8_sentinel_0_type, - .ptr = try pt.intern(.{ .ptr = .{ - .ty = .manyptr_const_u8_sentinel_0_type, - .base_addr = .{ .anon_decl = .{ - .orig_ty = .slice_const_u8_sentinel_0_type, - .val = new_decl_val, - } }, - .byte_offset = 0, - } }), - .len = (try pt.intValue(Type.usize, decl_name_len)).toIntern(), + const array_val = try pt.intern(.{ .aggregate = .{ + .ty = array_ty.toIntern(), + .storage = .{ .bytes = name.toString() }, } }); + break :name_val try pt.intern(.{ + .slice = .{ + .ty = .slice_const_u8_sentinel_0_type, // [:0]const u8 + .ptr = try pt.intern(.{ + .ptr = .{ + .ty = .manyptr_const_u8_sentinel_0_type, // [*:0]const u8 + .base_addr = .{ .uav = .{ + .orig_ty = .slice_const_u8_sentinel_0_type, + .val = array_val, + } }, + .byte_offset = 0, + }, + }), + .len = (try pt.intValue(Type.usize, name_len)).toIntern(), + }, + }); }; - - const fields = .{ - //name: [:0]const u8, + const fields = [_]InternPool.Index{ + // name: [:0]const u8, name_val, }; try decl_vals.append(try pt.intern(.{ .aggregate = .{ @@ -19022,6 +18984,17 @@ fn typeInfoNamespaceDecls( .storage = .{ .elems = &fields }, } })); } + + for (namespace.pub_usingnamespace.items) |nav| { + if (ip.getNav(nav).analysis_owner.unwrap()) |cau| { + if (zcu.analysis_in_progress.contains(AnalUnit.wrap(.{ .cau = cau }))) { + continue; + } + } + try sema.ensureNavResolved(src, nav); + const namespace_ty = Type.fromInterned(ip.getNav(nav).status.resolved.val); + try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces); + } } fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -19906,7 +19879,7 @@ fn restoreErrRetIndex(sema: *Sema, start_block: *Block, src: LazySrcLoc, target_ return; } - if (!mod.intern_pool.funcAnalysisUnordered(sema.owner_func_index).calls_or_awaits_errorable_fn) return; + if (!mod.intern_pool.funcAnalysisUnordered(sema.owner.unwrap().func).calls_or_awaits_errorable_fn) return; if (!start_block.ownerModule().error_tracing) return; assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere @@ -19928,7 +19901,7 @@ fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { }, else => if (ip.isInferredErrorSetType(err_set_ty)) { const ies = sema.fn_ret_ty_ies.?; - assert(ies.func == sema.func_index); + assert(ies.func == sema.owner.unwrap().func); try sema.addToInferredErrorSetPtr(ies, sema.typeOf(uncasted_operand)); }, } @@ -20232,7 +20205,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is if (is_byref) { const init_val = (try sema.resolveValue(init_ref)).?; - return anonDeclRef(sema, init_val.toIntern()); + return sema.uavRef(init_val.toIntern()); } else { return init_ref; } @@ -21056,7 +21029,7 @@ fn arrayInitAnon( } fn addConstantMaybeRef(sema: *Sema, val: InternPool.Index, is_ref: bool) !Air.Inst.Ref { - return if (is_ref) anonDeclRef(sema, val) else Air.internedToRef(val); + return if (is_ref) sema.uavRef(val) else Air.internedToRef(val); } fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -21163,16 +21136,16 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern()); - if (sema.owner_func_index != .none and - ip.funcAnalysisUnordered(sema.owner_func_index).calls_or_awaits_errorable_fn and - block.ownerModule().error_tracing) - { - return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); + switch (sema.owner.unwrap()) { + .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) { + return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); + }, + .cau => {}, } - return Air.internedToRef((try pt.intern(.{ .opt = .{ + return Air.internedToRef(try pt.intern(.{ .opt = .{ .ty = opt_ptr_stack_trace_ty.toIntern(), .val = .none, - } }))); + } })); } fn zirFrame( @@ -21369,24 +21342,24 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const operand = try sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); const pt = sema.pt; - const mod = pt.zcu; - const ip = &mod.intern_pool; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; try operand_ty.resolveLayout(pt); - const enum_ty = switch (operand_ty.zigTypeTag(mod)) { + const enum_ty = switch (operand_ty.zigTypeTag(zcu)) { .EnumLiteral => { const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, operand, undefined); const tag_name = ip.indexToKey(val.toIntern()).enum_literal; return sema.addNullTerminatedStrLit(tag_name); }, .Enum => operand_ty, - .Union => operand_ty.unionTagType(mod) orelse + .Union => operand_ty.unionTagType(zcu) orelse return sema.fail(block, src, "union '{}' is untagged", .{operand_ty.fmt(pt)}), else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{ operand_ty.fmt(pt), }), }; - if (enum_ty.enumFieldCount(mod) == 0) { + if (enum_ty.enumFieldCount(zcu) == 0) { // TODO I don't think this is the correct way to handle this but // it prevents a crash. // https://github.com/ziglang/zig/issues/15909 @@ -21394,26 +21367,25 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air enum_ty.fmt(pt), }); } - const enum_decl_index = enum_ty.getOwnerDecl(mod); const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { - const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse { + const field_index = enum_ty.enumTagFieldIndex(val, zcu) orelse { const msg = msg: { const msg = try sema.errMsg(src, "no field with value '{}' in enum '{}'", .{ - val.fmtValueSema(pt, sema), mod.declPtr(enum_decl_index).name.fmt(ip), + val.fmtValueSema(pt, sema), enum_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); - try sema.errNote(enum_ty.srcLoc(mod), msg, "declared here", .{}); + try sema.errNote(enum_ty.srcLoc(zcu), msg, "declared here", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); }; // TODO: write something like getCoercedInts to avoid needing to dupe - const field_name = enum_ty.enumFieldName(field_index, mod); + const field_name = enum_ty.enumFieldName(field_index, zcu); return sema.addNullTerminatedStrLit(field_name); } try sema.requireRuntimeBlock(block, src, operand_src); - if (block.wantSafety() and mod.backendSupportsFeature(.is_named_enum_value)) { + if (block.wantSafety() and zcu.backendSupportsFeature(.is_named_enum_value)) { const ok = try block.addUnOp(.is_named_enum_value, casted_operand); try sema.addSafetyCheck(block, src, ok, .invalid_enum_value); } @@ -21810,7 +21782,6 @@ fn zirReify( } const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, .{ - .has_namespace = false, .key = .{ .reified = .{ .zir_index = try block.trackZir(inst), } }, @@ -21820,19 +21791,21 @@ fn zirReify( }; errdefer wip_ty.cancel(ip, pt.tid); - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + wip_ty.setName(ip, try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), name_strategy, "opaque", inst, - ); - mod.declPtr(new_decl_index).owns_tv = true; - errdefer pt.abortAnonDecl(new_decl_index); + wip_ty.index, + )); - try pt.finalizeAnonDecl(new_decl_index); + const new_namespace_index = try pt.createNamespace(.{ + .parent = block.namespace.toOptional(), + .owner_type = wip_ty.index, + .file_scope = block.getFileScopeIndex(mod), + }); - return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none)); + return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index)); }, .Union => { const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); @@ -22001,13 +21974,14 @@ fn reifyEnum( }); } + const tracked_inst = try block.trackZir(inst); + const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{ - .has_namespace = false, .has_values = true, .tag_mode = if (is_exhaustive) .explicit else .nonexhaustive, .fields_len = fields_len, .key = .{ .reified = .{ - .zir_index = try block.trackZir(inst), + .zir_index = tracked_inst, .type_hash = hasher.final(), } }, })) { @@ -22020,17 +21994,23 @@ fn reifyEnum( return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); } - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + wip_ty.setName(ip, try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), name_strategy, "enum", inst, - ); - mod.declPtr(new_decl_index).owns_tv = true; - errdefer pt.abortAnonDecl(new_decl_index); + wip_ty.index, + )); - wip_ty.prepare(ip, new_decl_index, .none); + const new_namespace_index = try pt.createNamespace(.{ + .parent = block.namespace.toOptional(), + .owner_type = wip_ty.index, + .file_scope = block.getFileScopeIndex(mod), + }); + + const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); + + wip_ty.prepare(ip, new_cau_index, new_namespace_index); wip_ty.setTagTy(ip, tag_ty.toIntern()); for (0..fields_len) |field_idx| { @@ -22076,7 +22056,6 @@ fn reifyEnum( return sema.fail(block, src, "non-exhaustive enum specified every value", .{}); } - try pt.finalizeAnonDecl(new_decl_index); return Air.internedToRef(wip_ty.index); } @@ -22134,6 +22113,8 @@ fn reifyUnion( } } + const tracked_inst = try block.trackZir(inst); + const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{ .flags = .{ .layout = layout, @@ -22152,13 +22133,12 @@ fn reifyUnion( .assumed_pointer_aligned = false, .alignment = .none, }, - .has_namespace = false, .fields_len = fields_len, .enum_tag_ty = .none, // set later because not yet validated .field_types = &.{}, // set later .field_aligns = &.{}, // set later .key = .{ .reified = .{ - .zir_index = try block.trackZir(inst), + .zir_index = tracked_inst, .type_hash = hasher.final(), } }, })) { @@ -22167,15 +22147,14 @@ fn reifyUnion( }; errdefer wip_ty.cancel(ip, pt.tid); - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + const type_name = try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), name_strategy, "union", inst, + wip_ty.index, ); - mod.declPtr(new_decl_index).owns_tv = true; - errdefer pt.abortAnonDecl(new_decl_index); + wip_ty.setName(ip, type_name); const field_types = try sema.arena.alloc(InternPool.Index, fields_len); const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined; @@ -22268,7 +22247,7 @@ fn reifyUnion( } } - const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), mod.declPtr(new_decl_index)); + const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name); break :tag_ty .{ enum_tag_ty, false }; }; errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error @@ -22315,10 +22294,17 @@ fn reifyUnion( loaded_union.setTagType(ip, enum_tag_ty); loaded_union.setStatus(ip, .have_field_types); - try pt.finalizeAnonDecl(new_decl_index); + const new_namespace_index = try pt.createNamespace(.{ + .parent = block.namespace.toOptional(), + .owner_type = wip_ty.index, + .file_scope = block.getFileScopeIndex(mod), + }); + + const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); + try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index })); - return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none)); + try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); + return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); } fn reifyStruct( @@ -22399,6 +22385,8 @@ fn reifyStruct( } } + const tracked_inst = try block.trackZir(inst); + const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ .layout = layout, .fields_len = fields_len, @@ -22409,9 +22397,8 @@ fn reifyStruct( .any_default_inits = any_default_inits, .any_aligned_fields = any_aligned_fields, .inits_resolved = true, - .has_namespace = false, .key = .{ .reified = .{ - .zir_index = try block.trackZir(inst), + .zir_index = tracked_inst, .type_hash = hasher.final(), } }, })) { @@ -22426,15 +22413,13 @@ fn reifyStruct( .auto => {}, }; - const new_decl_index = try sema.createAnonymousDeclTypeNamed( + wip_ty.setName(ip, try sema.createTypeName( block, - Value.fromInterned(wip_ty.index), name_strategy, "struct", inst, - ); - mod.declPtr(new_decl_index).owns_tv = true; - errdefer pt.abortAnonDecl(new_decl_index); + wip_ty.index, + )); const struct_type = ip.loadStructType(wip_ty.index); @@ -22582,10 +22567,17 @@ fn reifyStruct( } } - try pt.finalizeAnonDecl(new_decl_index); + const new_namespace_index = try pt.createNamespace(.{ + .parent = block.namespace.toOptional(), + .owner_type = wip_ty.index, + .file_scope = block.getFileScopeIndex(mod), + }); + + const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); + try mod.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index })); - return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none)); + try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .cau = new_cau_index })); + return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index)); } fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { @@ -26028,7 +26020,8 @@ fn zirVarExtended( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 }); const init_src = block.src(.{ .node_offset_var_decl_init = 0 }); @@ -26075,16 +26068,62 @@ fn zirVarExtended( try sema.validateVarType(block, ty_src, var_ty, small.is_extern); - return Air.internedToRef((try pt.intern(.{ .variable = .{ + if (small.is_extern) { + // We need to resolve the alignment and addrspace early. + // Keep in sync with logic in `Zcu.PerThread.semaCau`. + const align_src = block.src(.{ .node_offset_var_decl_align = 0 }); + const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 }); + + const decl_inst, const decl_bodies = decl: { + const decl_inst = sema.getOwnerCauDeclInst().resolve(ip); + const zir_decl, const extra_end = sema.code.getDeclaration(decl_inst); + break :decl .{ decl_inst, zir_decl.getBodies(extra_end, sema.code) }; + }; + + const alignment: InternPool.Alignment = a: { + const align_body = decl_bodies.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); + }; + + const @"addrspace": std.builtin.AddressSpace = as: { + const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(var_ty.toIntern())) { + .func_type => .function, + else => .variable, + }; + const target = zcu.getTarget(); + const addrspace_body = decl_bodies.addrspace_body orelse break :as switch (addrspace_ctx) { + .function => target_util.defaultAddressSpace(target, .function), + .variable => target_util.defaultAddressSpace(target, .global_mutable), + .constant => target_util.defaultAddressSpace(target, .global_constant), + else => unreachable, + }; + const addrspace_ref = try sema.resolveInlineBody(block, addrspace_body, decl_inst); + break :as try sema.analyzeAsAddressSpace(block, addrspace_src, addrspace_ref, addrspace_ctx); + }; + + return Air.internedToRef(try pt.getExtern(.{ + .name = sema.getOwnerCauNavName(), + .ty = var_ty.toIntern(), + .lib_name = try ip.getOrPutStringOpt(sema.gpa, pt.tid, lib_name, .no_embedded_nulls), + .is_const = small.is_const, + .is_threadlocal = small.is_threadlocal, + .is_weak_linkage = false, + .alignment = alignment, + .@"addrspace" = @"addrspace", + .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction + .owner_nav = undefined, // ignored by `getExtern` + })); + } + assert(!small.is_const); // non-const non-extern variable is not legal + return Air.internedToRef(try pt.intern(.{ .variable = .{ .ty = var_ty.toIntern(), .init = init_val, - .decl = sema.owner_decl_index, - .lib_name = try mod.intern_pool.getOrPutStringOpt(sema.gpa, pt.tid, lib_name, .no_embedded_nulls), - .is_extern = small.is_extern, - .is_const = small.is_const, + .owner_nav = sema.getOwnerCauNav(), + .lib_name = try ip.getOrPutStringOpt(sema.gpa, pt.tid, lib_name, .no_embedded_nulls), .is_threadlocal = small.is_threadlocal, .is_weak_linkage = false, - } }))); + } })); } fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -26255,10 +26294,23 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A else => |e| return e, }; break :blk mod.toEnum(std.builtin.CallingConvention, cc_val); - } else if (sema.owner_decl.is_exported and has_body) - .C - else - .Unspecified; + } else cc: { + if (has_body) { + const decl_inst = if (sema.generic_owner != .none) decl_inst: { + // Generic instance -- use the original function declaration to + // look for the `export` syntax. + const nav = mod.intern_pool.getNav(mod.funcInfo(sema.generic_owner).owner_nav); + const cau = mod.intern_pool.getCau(nav.analysis_owner.unwrap().?); + break :decl_inst cau.zir_index; + } else sema.getOwnerCauDeclInst(); // not an instantiation so we're analyzing a function declaration Cau + + const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&mod.intern_pool))[0]; + if (zir_decl.flags.is_export) { + break :cc .C; + } + } + break :cc .Unspecified; + }; const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: { const body_len = sema.code.extra[extra_index]; @@ -26600,42 +26652,32 @@ fn zirBuiltinExtern( const options = try sema.resolveExternOptions(block, options_src, extra.rhs); + // TODO: error for threadlocal functions, non-const functions, etc + if (options.linkage == .weak and !ty.ptrAllowsZero(mod)) { ty = try pt.optionalType(ty.toIntern()); } const ptr_info = ty.ptrInfo(mod); - const new_decl_index = try pt.allocateNewDecl(sema.owner_decl.src_namespace); - errdefer pt.destroyDecl(new_decl_index); - const new_decl = mod.declPtr(new_decl_index); - try pt.initNewAnonDecl( - new_decl_index, - Value.fromInterned( - if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Fn) - try ip.getExternFunc(sema.gpa, pt.tid, .{ - .ty = ptr_info.child, - .decl = new_decl_index, - .lib_name = options.library_name, - }) - else - try pt.intern(.{ .variable = .{ - .ty = ptr_info.child, - .init = .none, - .decl = new_decl_index, - .lib_name = options.library_name, - .is_extern = true, - .is_const = ptr_info.flags.is_const, - .is_threadlocal = options.is_thread_local, - .is_weak_linkage = options.linkage == .weak, - } }), - ), - options.name, - .none, - ); - new_decl.owns_tv = true; - // Note that this will queue the anon decl for codegen, so that the backend can - // correctly handle the extern, including duplicate detection. - try pt.finalizeAnonDecl(new_decl_index); + const extern_val = try pt.getExtern(.{ + .name = options.name, + .ty = ptr_info.child, + .lib_name = options.library_name, + .is_const = ptr_info.flags.is_const, + .is_threadlocal = options.is_thread_local, + .is_weak_linkage = options.linkage == .weak, + .alignment = ptr_info.flags.alignment, + .@"addrspace" = ptr_info.flags.address_space, + // This instruction is just for source locations. + // `builtin_extern` doesn't provide enough information, and isn't currently tracked. + // So, for now, just use our containing `declaration`. + .zir_index = switch (sema.owner.unwrap()) { + .cau => sema.getOwnerCauDeclInst(), + .func => sema.getOwnerFuncDeclInst(), + }, + .owner_nav = undefined, // ignored by `getExtern` + }); + const extern_nav = ip.indexToKey(extern_val).@"extern".owner_nav; return Air.internedToRef((try pt.getCoerced(Value.fromInterned(try pt.intern(.{ .ptr = .{ .ty = switch (ip.indexToKey(ty.toIntern())) { @@ -26643,7 +26685,7 @@ fn zirBuiltinExtern( .opt_type => |child_type| child_type, else => unreachable, }, - .base_addr = .{ .decl = new_decl_index }, + .base_addr = .{ .nav = extern_nav }, .byte_offset = 0, } })), ty)).toIntern()); } @@ -27129,17 +27171,15 @@ fn explainWhyTypeIsNotPacked( } } -fn prepareSimplePanic(sema: *Sema) !void { +fn prepareSimplePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void { const pt = sema.pt; const mod = pt.zcu; if (mod.panic_func_index == .none) { - const decl_index = (try pt.getBuiltinDecl("panic")); - // decl_index may be an alias; we must find the decl that actually - // owns the function. - try sema.ensureDeclAnalyzed(decl_index); - const fn_val = try mod.declPtr(decl_index).valueOrFail(); - try sema.declareDependency(.{ .decl_val = decl_index }); + const fn_ref = try sema.analyzeNavVal(block, src, try pt.getBuiltinNav("panic")); + const fn_val = try sema.resolveConstValue(block, src, fn_ref, .{ + .needed_comptime_reason = "panic handler must be comptime-known", + }); assert(fn_val.typeOf(mod).zigTypeTag(mod) == .Fn); assert(try sema.fnHasRuntimeBits(fn_val.typeOf(mod))); try mod.ensureFuncBodyAnalysisQueued(fn_val.toIntern()); @@ -27167,16 +27207,16 @@ fn prepareSimplePanic(sema: *Sema) !void { /// Backends depend on panic decls being available when lowering safety-checked /// instructions. This function ensures the panic function will be available to /// be called during that time. -fn preparePanicId(sema: *Sema, block: *Block, panic_id: Module.PanicId) !InternPool.DeclIndex { +fn preparePanicId(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Module.PanicId) !InternPool.Nav.Index { const pt = sema.pt; const mod = pt.zcu; const gpa = sema.gpa; if (mod.panic_messages[@intFromEnum(panic_id)].unwrap()) |x| return x; - try sema.prepareSimplePanic(); + try sema.prepareSimplePanic(block, src); const panic_messages_ty = try pt.getBuiltinType("panic_messages"); - const msg_decl_index = (sema.namespaceLookup( + const msg_nav_index = (sema.namespaceLookup( block, LazySrcLoc.unneeded, panic_messages_ty.getNamespaceIndex(mod), @@ -27186,9 +27226,9 @@ fn preparePanicId(sema: *Sema, block: *Block, panic_id: Module.PanicId) !InternP error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, error.OutOfMemory => |e| return e, }).?; - try sema.ensureDeclAnalyzed(msg_decl_index); - mod.panic_messages[@intFromEnum(panic_id)] = msg_decl_index.toOptional(); - return msg_decl_index; + try sema.ensureNavResolved(src, msg_nav_index); + mod.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional(); + return msg_nav_index; } fn addSafetyCheck( @@ -27282,10 +27322,10 @@ fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst. return; } - try sema.prepareSimplePanic(); + try sema.prepareSimplePanic(block, src); const panic_func = mod.funcInfo(mod.panic_func_index); - const panic_fn = try sema.analyzeDeclVal(block, src, panic_func.owner_decl); + const panic_fn = try sema.analyzeNavVal(block, src, panic_func.owner_nav); const null_stack_trace = Air.internedToRef(mod.null_stack_trace); const opt_usize_ty = try pt.optionalType(.usize_type); @@ -27455,8 +27495,8 @@ fn safetyCheckFormatted( } fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Module.PanicId) CompileError!void { - const msg_decl_index = try sema.preparePanicId(block, panic_id); - const msg_inst = try sema.analyzeDeclVal(block, src, msg_decl_index); + const msg_nav_index = try sema.preparePanicId(block, src, panic_id); + const msg_inst = try sema.analyzeNavVal(block, src, msg_nav_index); try sema.panicWithMsg(block, src, msg_inst, .@"safety check"); } @@ -27628,21 +27668,21 @@ fn fieldVal( return Air.internedToRef(enum_val.toIntern()); }, .Struct, .Opaque => { - if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(mod), field_name)) |inst| { - return inst; + switch (child_type.toIntern()) { + .empty_struct_type, .anyopaque_type => {}, // no namespace + else => if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(mod), field_name)) |inst| { + return inst; + }, } return sema.failWithBadMemberAccess(block, child_type, src, field_name); }, - else => { - const msg = msg: { - const msg = try sema.errMsg(src, "type '{}' has no members", .{child_type.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - if (child_type.isSlice(mod)) try sema.errNote(src, msg, "slice values have 'len' and 'ptr' members", .{}); - if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(src, msg, "array values have 'len' member", .{}); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); - }, + else => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(src, "type '{}' has no members", .{child_type.fmt(pt)}); + errdefer msg.destroy(sema.gpa); + if (child_type.isSlice(mod)) try sema.errNote(src, msg, "slice values have 'len' and 'ptr' members", .{}); + if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(src, msg, "array values have 'len' member", .{}); + break :msg msg; + }), } }, .Struct => if (is_pointer_to) { @@ -27700,7 +27740,7 @@ fn fieldPtr( .Array => { if (field_name.eqlSlice("len", ip)) { const int_val = try pt.intValue(Type.usize, inner_ty.arrayLen(mod)); - return anonDeclRef(sema, int_val.toIntern()); + return uavRef(sema, int_val.toIntern()); } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { const ptr_info = object_ty.ptrInfo(mod); const new_ptr_ty = try pt.ptrTypeSema(.{ @@ -27839,7 +27879,7 @@ fn fieldPtr( child_type else try pt.singleErrorSetType(field_name); - return anonDeclRef(sema, try pt.intern(.{ .err = .{ + return uavRef(sema, try pt.intern(.{ .err = .{ .ty = error_set_type.toIntern(), .name = field_name, } })); @@ -27853,7 +27893,7 @@ fn fieldPtr( if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { const field_index_u32: u32 = @intCast(field_index); const idx_val = try pt.enumValueFieldIndex(enum_ty, field_index_u32); - return anonDeclRef(sema, idx_val.toIntern()); + return uavRef(sema, idx_val.toIntern()); } } return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); @@ -27867,7 +27907,7 @@ fn fieldPtr( }; const field_index_u32: u32 = @intCast(field_index); const idx_val = try pt.enumValueFieldIndex(child_type, field_index_u32); - return anonDeclRef(sema, idx_val.toIntern()); + return uavRef(sema, idx_val.toIntern()); }, .Struct, .Opaque => { if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(mod), field_name)) |inst| { @@ -27923,18 +27963,18 @@ fn fieldCallBind( // in `fieldVal`. This function takes a pointer and returns a pointer. const pt = sema.pt; - const mod = pt.zcu; - const ip = &mod.intern_pool; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const raw_ptr_src = src; // TODO better source location const raw_ptr_ty = sema.typeOf(raw_ptr); - const inner_ty = if (raw_ptr_ty.zigTypeTag(mod) == .Pointer and (raw_ptr_ty.ptrSize(mod) == .One or raw_ptr_ty.ptrSize(mod) == .C)) - raw_ptr_ty.childType(mod) + const inner_ty = if (raw_ptr_ty.zigTypeTag(zcu) == .Pointer and (raw_ptr_ty.ptrSize(zcu) == .One or raw_ptr_ty.ptrSize(zcu) == .C)) + raw_ptr_ty.childType(zcu) else return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(pt)}); // Optionally dereference a second pointer to get the concrete type. - const is_double_ptr = inner_ty.zigTypeTag(mod) == .Pointer and inner_ty.ptrSize(mod) == .One; - const concrete_ty = if (is_double_ptr) inner_ty.childType(mod) else inner_ty; + const is_double_ptr = inner_ty.zigTypeTag(zcu) == .Pointer and inner_ty.ptrSize(zcu) == .One; + const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty; const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; const object_ptr = if (is_double_ptr) try sema.analyzeLoad(block, src, raw_ptr, src) @@ -27942,36 +27982,36 @@ fn fieldCallBind( raw_ptr; find_field: { - switch (concrete_ty.zigTypeTag(mod)) { + switch (concrete_ty.zigTypeTag(zcu)) { .Struct => { try concrete_ty.resolveFields(pt); - if (mod.typeToStruct(concrete_ty)) |struct_type| { + if (zcu.typeToStruct(concrete_ty)) |struct_type| { const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field; const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]); return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr); - } else if (concrete_ty.isTuple(mod)) { + } else if (concrete_ty.isTuple(zcu)) { if (field_name.eqlSlice("len", ip)) { - return .{ .direct = try pt.intRef(Type.usize, concrete_ty.structFieldCount(mod)) }; + return .{ .direct = try pt.intRef(Type.usize, concrete_ty.structFieldCount(zcu)) }; } if (field_name.toUnsigned(ip)) |field_index| { - if (field_index >= concrete_ty.structFieldCount(mod)) break :find_field; - return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(field_index, mod), field_index, object_ptr); + if (field_index >= concrete_ty.structFieldCount(zcu)) break :find_field; + return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(field_index, zcu), field_index, object_ptr); } } else { - const max = concrete_ty.structFieldCount(mod); + const max = concrete_ty.structFieldCount(zcu); for (0..max) |i_usize| { const i: u32 = @intCast(i_usize); - if (field_name == concrete_ty.structFieldName(i, mod).unwrap().?) { - return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr); + if (field_name == concrete_ty.structFieldName(i, zcu).unwrap().?) { + return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, zcu), i, object_ptr); } } } }, .Union => { try concrete_ty.resolveFields(pt); - const union_obj = mod.typeToUnion(concrete_ty).?; + const union_obj = zcu.typeToUnion(concrete_ty).?; _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field; const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false); return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) }; @@ -27985,23 +28025,23 @@ fn fieldCallBind( } // If we get here, we need to look for a decl in the struct type instead. - const found_decl = found_decl: { - const namespace = concrete_ty.getNamespace(mod) orelse - break :found_decl null; - const decl_idx = (try sema.namespaceLookup(block, src, namespace, field_name)) orelse - break :found_decl null; + const found_nav = found_nav: { + const namespace = concrete_ty.getNamespace(zcu).unwrap() orelse + break :found_nav null; + const nav_index = try sema.namespaceLookup(block, src, namespace, field_name) orelse + break :found_nav null; - const decl_val = try sema.analyzeDeclVal(block, src, decl_idx); + const decl_val = try sema.analyzeNavVal(block, src, nav_index); const decl_type = sema.typeOf(decl_val); - if (mod.typeToFunc(decl_type)) |func_type| f: { + if (zcu.typeToFunc(decl_type)) |func_type| f: { if (func_type.param_types.len == 0) break :f; const first_param_type = Type.fromInterned(func_type.param_types.get(ip)[0]); if (first_param_type.isGenericPoison() or - (first_param_type.zigTypeTag(mod) == .Pointer and - (first_param_type.ptrSize(mod) == .One or - first_param_type.ptrSize(mod) == .C) and - first_param_type.childType(mod).eql(concrete_ty, mod))) + (first_param_type.zigTypeTag(zcu) == .Pointer and + (first_param_type.ptrSize(zcu) == .One or + first_param_type.ptrSize(zcu) == .C) and + first_param_type.childType(zcu).eql(concrete_ty, zcu))) { // Note that if the param type is generic poison, we know that it must // specifically be `anytype` since it's the first parameter, meaning we @@ -28012,31 +28052,31 @@ fn fieldCallBind( .func_inst = decl_val, .arg0_inst = object_ptr, } }; - } else if (first_param_type.eql(concrete_ty, mod)) { + } else if (first_param_type.eql(concrete_ty, zcu)) { const deref = try sema.analyzeLoad(block, src, object_ptr, src); return .{ .method = .{ .func_inst = decl_val, .arg0_inst = deref, } }; - } else if (first_param_type.zigTypeTag(mod) == .Optional) { - const child = first_param_type.optionalChild(mod); - if (child.eql(concrete_ty, mod)) { + } else if (first_param_type.zigTypeTag(zcu) == .Optional) { + const child = first_param_type.optionalChild(zcu); + if (child.eql(concrete_ty, zcu)) { const deref = try sema.analyzeLoad(block, src, object_ptr, src); return .{ .method = .{ .func_inst = decl_val, .arg0_inst = deref, } }; - } else if (child.zigTypeTag(mod) == .Pointer and - child.ptrSize(mod) == .One and - child.childType(mod).eql(concrete_ty, mod)) + } else if (child.zigTypeTag(zcu) == .Pointer and + child.ptrSize(zcu) == .One and + child.childType(zcu).eql(concrete_ty, zcu)) { return .{ .method = .{ .func_inst = decl_val, .arg0_inst = object_ptr, } }; } - } else if (first_param_type.zigTypeTag(mod) == .ErrorUnion and - first_param_type.errorUnionPayload(mod).eql(concrete_ty, mod)) + } else if (first_param_type.zigTypeTag(zcu) == .ErrorUnion and + first_param_type.errorUnionPayload(zcu).eql(concrete_ty, zcu)) { const deref = try sema.analyzeLoad(block, src, object_ptr, src); return .{ .method = .{ @@ -28045,7 +28085,7 @@ fn fieldCallBind( } }; } } - break :found_decl decl_idx; + break :found_nav nav_index; }; const msg = msg: { @@ -28055,14 +28095,15 @@ fn fieldCallBind( }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, concrete_ty); - if (found_decl) |decl_idx| { - const decl = mod.declPtr(decl_idx); - try sema.errNote(.{ - .base_node_inst = decl.zir_decl_index.unwrap().?, - .offset = LazySrcLoc.Offset.nodeOffset(0), - }, msg, "'{}' is not a member function", .{field_name.fmt(ip)}); + if (found_nav) |nav_index| { + try sema.errNote( + zcu.navSrcLoc(nav_index), + msg, + "'{}' is not a member function", + .{field_name.fmt(ip)}, + ); } - if (concrete_ty.zigTypeTag(mod) == .ErrorUnion) { + if (concrete_ty.zigTypeTag(zcu) == .ErrorUnion) { try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); } if (is_double_ptr) { @@ -28117,29 +28158,24 @@ fn namespaceLookup( sema: *Sema, block: *Block, src: LazySrcLoc, - opt_namespace: InternPool.OptionalNamespaceIndex, + namespace: InternPool.NamespaceIndex, decl_name: InternPool.NullTerminatedString, -) CompileError!?InternPool.DeclIndex { +) CompileError!?InternPool.Nav.Index { const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; const gpa = sema.gpa; - if (try sema.lookupInNamespace(block, src, opt_namespace, decl_name, true)) |decl_index| { - const decl = mod.declPtr(decl_index); - if (!decl.is_pub and decl.getFileScope(mod) != block.getFileScope(mod)) { - const msg = msg: { + if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |lookup| { + if (!lookup.accessible) { + return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "'{}' is not marked 'pub'", .{ - decl_name.fmt(&mod.intern_pool), + decl_name.fmt(&zcu.intern_pool), }); errdefer msg.destroy(gpa); - try sema.errNote(.{ - .base_node_inst = decl.zir_decl_index.unwrap().?, - .offset = LazySrcLoc.Offset.nodeOffset(0), - }, msg, "declared here", .{}); + try sema.errNote(zcu.navSrcLoc(lookup.nav), msg, "declared here", .{}); break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + }); } - return decl_index; + return lookup.nav; } return null; } @@ -28148,22 +28184,22 @@ fn namespaceLookupRef( sema: *Sema, block: *Block, src: LazySrcLoc, - opt_namespace: InternPool.OptionalNamespaceIndex, + namespace: InternPool.NamespaceIndex, decl_name: InternPool.NullTerminatedString, ) CompileError!?Air.Inst.Ref { - const decl = (try sema.namespaceLookup(block, src, opt_namespace, decl_name)) orelse return null; - return try sema.analyzeDeclRef(src, decl); + const nav = try sema.namespaceLookup(block, src, namespace, decl_name) orelse return null; + return try sema.analyzeNavRef(src, nav); } fn namespaceLookupVal( sema: *Sema, block: *Block, src: LazySrcLoc, - opt_namespace: InternPool.OptionalNamespaceIndex, + namespace: InternPool.NamespaceIndex, decl_name: InternPool.NullTerminatedString, ) CompileError!?Air.Inst.Ref { - const decl = (try sema.namespaceLookup(block, src, opt_namespace, decl_name)) orelse return null; - return try sema.analyzeDeclVal(block, src, decl); + const nav = try sema.namespaceLookup(block, src, namespace, decl_name) orelse return null; + return try sema.analyzeNavVal(block, src, nav); } fn structFieldPtr( @@ -29200,9 +29236,9 @@ const CoerceOpts = struct { fn get(info: @This(), sema: *Sema) !?LazySrcLoc { if (info.func_inst == .none) return null; - const fn_decl = try sema.funcDeclSrc(info.func_inst) orelse return null; + const func_inst = try sema.funcDeclSrcInst(info.func_inst) orelse return null; return .{ - .base_node_inst = fn_decl.zir_decl_index.unwrap().?, + .base_node_inst = func_inst, .offset = .{ .fn_proto_param_type = .{ .fn_proto_node_offset = 0, .param_index = info.param_i, @@ -29303,8 +29339,12 @@ fn coerceExtra( // Function body to function pointer. if (inst_ty.zigTypeTag(zcu) == .Fn) { const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); - const fn_decl = fn_val.pointerDecl(zcu).?; - const inst_as_ptr = try sema.analyzeDeclRef(inst_src, fn_decl); + const fn_nav = switch (zcu.intern_pool.indexToKey(fn_val.toIntern())) { + .func => |f| f.owner_nav, + .@"extern" => |e| e.owner_nav, + else => unreachable, + }; + const inst_as_ptr = try sema.analyzeNavRef(inst_src, fn_nav); return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); } @@ -29846,7 +29886,7 @@ fn coerceExtra( errdefer msg.destroy(sema.gpa); const ret_ty_src: LazySrcLoc = .{ - .base_node_inst = zcu.funcOwnerDeclPtr(sema.func_index).zir_decl_index.unwrap().?, + .base_node_inst = sema.getOwnerFuncDeclInst(), .offset = .{ .node_offset_fn_type_ret_ty = 0 }, }; try sema.errNote(ret_ty_src, msg, "'noreturn' declared here", .{}); @@ -29879,10 +29919,10 @@ fn coerceExtra( // Add notes about function return type if (opts.is_ret and - zcu.test_functions.get(zcu.funcOwnerDeclIndex(sema.func_index)) == null) + !zcu.test_functions.contains(zcu.funcInfo(sema.owner.unwrap().func).owner_nav)) { const ret_ty_src: LazySrcLoc = .{ - .base_node_inst = zcu.funcOwnerDeclPtr(sema.func_index).zir_decl_index.unwrap().?, + .base_node_inst = sema.getOwnerFuncDeclInst(), .offset = .{ .node_offset_fn_type_ret_ty = 0 }, }; if (inst_ty.isError(zcu) and !dest_ty.isError(zcu)) { @@ -30885,9 +30925,9 @@ fn coerceVarArgParam( if (block.is_typeof) return inst; const pt = sema.pt; - const mod = pt.zcu; + const zcu = pt.zcu; const uncasted_ty = sema.typeOf(inst); - const coerced = switch (uncasted_ty.zigTypeTag(mod)) { + const coerced = switch (uncasted_ty.zigTypeTag(zcu)) { // TODO consider casting to c_int/f64 if they fit .ComptimeInt, .ComptimeFloat => return sema.fail( block, @@ -30897,12 +30937,12 @@ fn coerceVarArgParam( ), .Fn => fn_ptr: { const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); - const fn_decl = fn_val.pointerDecl(mod).?; - break :fn_ptr try sema.analyzeDeclRef(inst_src, fn_decl); + const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav; + break :fn_ptr try sema.analyzeNavRef(inst_src, fn_nav); }, .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), .Float => float: { - const target = mod.getTarget(); + const target = zcu.getTarget(); const double_bits = target.c_type_bit_size(.double); const inst_bits = uncasted_ty.floatBits(target); if (inst_bits >= double_bits) break :float inst; @@ -30912,10 +30952,10 @@ fn coerceVarArgParam( else => unreachable, } }, - else => if (uncasted_ty.isAbiInt(mod)) int: { + else => if (uncasted_ty.isAbiInt(zcu)) int: { if (!try sema.validateExternType(uncasted_ty, .param_ty)) break :int inst; - const target = mod.getTarget(); - const uncasted_info = uncasted_ty.intInfo(mod); + const target = zcu.getTarget(); + const uncasted_info = uncasted_ty.intInfo(zcu); if (uncasted_info.bits <= target.c_type_bit_size(switch (uncasted_info.signedness) { .signed => .int, .unsigned => .uint, @@ -32117,23 +32157,14 @@ fn coerceTupleToTuple( } }))); } -fn analyzeDeclVal( +fn analyzeNavVal( sema: *Sema, block: *Block, src: LazySrcLoc, - decl_index: InternPool.DeclIndex, + nav_index: InternPool.Nav.Index, ) CompileError!Air.Inst.Ref { - if (sema.decl_val_table.get(decl_index)) |result| { - return result; - } - const decl_ref = try sema.analyzeDeclRefInner(src, decl_index, false); - const result = try sema.analyzeLoad(block, src, decl_ref, src); - if (result.toInterned() != null) { - if (!block.is_typeof) { - try sema.decl_val_table.put(sema.gpa, decl_index, result); - } - } - return result; + const ref = try sema.analyzeNavRefInner(src, nav_index, false); + return sema.analyzeLoad(block, src, ref, src); } fn addReferenceEntry( @@ -32148,44 +32179,37 @@ fn addReferenceEntry( // TODO: we need to figure out how to model inline calls here. // They aren't references in the analysis sense, but ought to show up in the reference trace! // Would representing inline calls in the reference table cause excessive memory usage? - try zcu.addUnitReference(sema.ownerUnit(), referenced_unit, src); + try zcu.addUnitReference(sema.owner, referenced_unit, src); } -pub fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void { +pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!void { const pt = sema.pt; - const mod = pt.zcu; - const ip = &mod.intern_pool; - const decl = mod.declPtr(decl_index); - if (decl.analysis == .in_progress) { - const msg = try sema.errMsg(.{ - .base_node_inst = decl.zir_decl_index.unwrap().?, - .offset = LazySrcLoc.Offset.nodeOffset(0), - }, "dependency loop detected", .{}); - return sema.failWithOwnedErrorMsg(null, msg); - } + const zcu = pt.zcu; + const ip = &zcu.intern_pool; - pt.ensureDeclAnalyzed(decl_index) catch |err| { - if (sema.owner_func_index != .none) { - ip.funcSetAnalysisState(sema.owner_func_index, .dependency_failure); - } else { - sema.owner_decl.analysis = .dependency_failure; - } - return err; - }; -} + const nav = ip.getNav(nav_index); -fn ensureFuncBodyAnalyzed(sema: *Sema, func: InternPool.Index) CompileError!void { - const pt = sema.pt; - const mod = pt.zcu; - const ip = &mod.intern_pool; - pt.ensureFuncBodyAnalyzed(func) catch |err| { - if (sema.owner_func_index != .none) { - ip.funcSetAnalysisState(sema.owner_func_index, .dependency_failure); - } else { - sema.owner_decl.analysis = .dependency_failure; - } - return err; + const cau_index = nav.analysis_owner.unwrap() orelse { + assert(nav.status == .resolved); + return; }; + + // Note that even if `nav.status == .resolved`, we must still trigger `ensureCauAnalyzed` + // to make sure the value is up-to-date on incremental updates. + + assert(ip.getCau(cau_index).owner.unwrap().nav == nav_index); + + const anal_unit = AnalUnit.wrap(.{ .cau = cau_index }); + try sema.addReferenceEntry(src, anal_unit); + + if (zcu.analysis_in_progress.contains(anal_unit)) { + return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{ + .base_node_inst = ip.getCau(cau_index).zir_index, + .offset = LazySrcLoc.Offset.nodeOffset(0), + }, "dependency loop detected", .{})); + } + + return pt.ensureCauAnalyzed(cau_index); } fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { @@ -32200,55 +32224,57 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { } })); } -fn analyzeDeclRef(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex) CompileError!Air.Inst.Ref { - return sema.analyzeDeclRefInner(src, decl_index, true); +fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref { + return sema.analyzeNavRefInner(src, nav_index, true); } -/// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but +/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed, but /// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a -/// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps +/// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeNavRef` wraps /// this function with `analyze_fn_body` set to true. -fn analyzeDeclRefInner(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex, analyze_fn_body: bool) CompileError!Air.Inst.Ref { +fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref { const pt = sema.pt; - const mod = pt.zcu; - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = decl_index })); - try sema.ensureDeclAnalyzed(decl_index); + const zcu = pt.zcu; + const ip = &zcu.intern_pool; - const decl_val = try mod.declPtr(decl_index).valueOrFail(); - const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_val.toIntern())) { - .variable => |variable| variable.decl, - .extern_func => |extern_func| extern_func.decl, - .func => |func| func.owner_decl, - else => decl_index, - }); - // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type - try sema.declareDependency(.{ .decl_val = decl_index }); + // TODO: if this is a `decl_ref` of a non-variable Nav, only depend on Nav type + try sema.declareDependency(.{ .nav_val = orig_nav_index }); + try sema.ensureNavResolved(src, orig_nav_index); + + const nav_val = zcu.navValue(orig_nav_index); + const nav_index, const is_const = switch (ip.indexToKey(nav_val.toIntern())) { + .variable => |v| .{ v.owner_nav, false }, + .func => |f| .{ f.owner_nav, true }, + .@"extern" => |e| .{ e.owner_nav, e.is_const }, + else => .{ orig_nav_index, true }, + }; + const nav_info = ip.getNav(nav_index).status.resolved; const ptr_ty = try pt.ptrTypeSema(.{ - .child = decl_val.typeOf(mod).toIntern(), + .child = nav_val.typeOf(zcu).toIntern(), .flags = .{ - .alignment = owner_decl.alignment, - .is_const = if (decl_val.getVariable(mod)) |variable| variable.is_const else true, - .address_space = owner_decl.@"addrspace", + .alignment = nav_info.alignment, + .is_const = is_const, + .address_space = nav_info.@"addrspace", }, }); if (analyze_fn_body) { - try sema.maybeQueueFuncBodyAnalysis(src, decl_index); + try sema.maybeQueueFuncBodyAnalysis(src, nav_index); } return Air.internedToRef((try pt.intern(.{ .ptr = .{ .ty = ptr_ty.toIntern(), - .base_addr = .{ .decl = decl_index }, + .base_addr = .{ .nav = nav_index }, .byte_offset = 0, } }))); } -fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex) !void { - const mod = sema.pt.zcu; - const decl = mod.declPtr(decl_index); - const decl_val = try decl.valueOrFail(); - if (!mod.intern_pool.isFuncBody(decl_val.toIntern())) return; - if (!try sema.fnHasRuntimeBits(decl_val.typeOf(mod))) return; - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = decl_val.toIntern() })); - try mod.ensureFuncBodyAnalysisQueued(decl_val.toIntern()); +fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void { + const zcu = sema.pt.zcu; + const ip = &zcu.intern_pool; + const nav_val = zcu.navValue(nav_index); + if (!ip.isFuncBody(nav_val.toIntern())) return; + if (!try sema.fnHasRuntimeBits(nav_val.typeOf(zcu))) return; + try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() })); + try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern()); } fn analyzeRef( @@ -32263,9 +32289,9 @@ fn analyzeRef( if (try sema.resolveValue(operand)) |val| { switch (mod.intern_pool.indexToKey(val.toIntern())) { - .extern_func => |extern_func| return sema.analyzeDeclRef(src, extern_func.decl), - .func => |func| return sema.analyzeDeclRef(src, func.owner_decl), - else => return anonDeclRef(sema, val.toIntern()), + .@"extern" => |e| return sema.analyzeNavRef(src, e.owner_nav), + .func => |f| return sema.analyzeNavRef(src, f.owner_nav), + else => return uavRef(sema, val.toIntern()), } } @@ -35198,7 +35224,7 @@ pub fn resolveStructAlignment( const ip = &mod.intern_pool; const target = mod.getTarget(); - assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?); + assert(sema.owner.unwrap().cau == struct_type.cau.unwrap().?); assert(struct_type.layout != .@"packed"); assert(struct_type.flagsUnordered(ip).alignment == .none); @@ -35242,7 +35268,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { const ip = &zcu.intern_pool; const struct_type = zcu.typeToStruct(ty) orelse return; - assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?); + assert(sema.owner.unwrap().cau == struct_type.cau.unwrap().?); if (struct_type.haveLayout(ip)) return; @@ -35384,8 +35410,7 @@ fn semaBackingIntType(pt: Zcu.PerThread, struct_type: InternPool.LoadedStructTyp const gpa = zcu.gpa; const ip = &zcu.intern_pool; - const decl_index = struct_type.decl.unwrap().?; - const decl = zcu.declPtr(decl_index); + const cau_index = struct_type.cau.unwrap().?; const zir = zcu.namespacePtr(struct_type.namespace.unwrap().?).fileScope(zcu).zir; @@ -35400,13 +35425,11 @@ fn semaBackingIntType(pt: Zcu.PerThread, struct_type: InternPool.LoadedStructTyp .gpa = gpa, .arena = analysis_arena.allocator(), .code = zir, - .owner_decl = decl, - .owner_decl_index = decl_index, + .owner = AnalUnit.wrap(.{ .cau = cau_index }), .func_index = .none, .func_is_naked = false, .fn_ret_ty = Type.void, .fn_ret_ty_ies = null, - .owner_func_index = .none, .comptime_err_ret_trace = &comptime_err_ret_trace, }; defer sema.deinit(); @@ -35414,12 +35437,12 @@ fn semaBackingIntType(pt: Zcu.PerThread, struct_type: InternPool.LoadedStructTyp var block: Block = .{ .parent = null, .sema = &sema, - .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace, + .namespace = ip.getCau(cau_index).namespace, .instructions = .{}, .inlining = null, .is_comptime = true, .src_base_inst = struct_type.zir_index.unwrap().?, - .type_name_ctx = decl.name, + .type_name_ctx = struct_type.name, }; defer assert(block.instructions.items.len == 0); @@ -35544,7 +35567,7 @@ pub fn resolveUnionAlignment( const ip = &zcu.intern_pool; const target = zcu.getTarget(); - assert(sema.ownerUnit().unwrap().decl == union_type.decl); + assert(sema.owner.unwrap().cau == union_type.cau); assert(!union_type.haveLayout(ip)); @@ -35584,7 +35607,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { // Load again, since the tag type might have changed due to resolution. const union_type = ip.loadUnionType(ty.ip_index); - assert(sema.ownerUnit().unwrap().decl == union_type.decl); + assert(sema.owner.unwrap().cau == union_type.cau); const old_flags = union_type.flagsUnordered(ip); switch (old_flags.status) { @@ -35697,7 +35720,7 @@ pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void { const ip = &mod.intern_pool; const struct_type = mod.typeToStruct(ty).?; - assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?); + assert(sema.owner.unwrap().cau == struct_type.cau.unwrap().?); if (struct_type.setFullyResolved(ip)) return; errdefer struct_type.clearFullyResolved(ip); @@ -35720,7 +35743,7 @@ pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void { const ip = &mod.intern_pool; const union_obj = mod.typeToUnion(ty).?; - assert(sema.ownerUnit().unwrap().decl == union_obj.decl); + assert(sema.owner.unwrap().cau == union_obj.cau); switch (union_obj.flagsUnordered(ip).status) { .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, @@ -35754,21 +35777,8 @@ pub fn resolveTypeFieldsStruct( const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - // If there is no owner decl it means the struct has no fields. - const owner_decl = struct_type.decl.unwrap() orelse return; - assert(sema.ownerUnit().unwrap().decl == owner_decl); - - switch (zcu.declPtr(owner_decl).analysis) { - .file_failure, - .dependency_failure, - .sema_failure, - => { - sema.owner_decl.analysis = .dependency_failure; - return error.AnalysisFail; - }, - else => {}, - } + assert(sema.owner.unwrap().cau == struct_type.cau.unwrap().?); if (struct_type.haveFieldTypes(ip)) return; @@ -35783,13 +35793,7 @@ pub fn resolveTypeFieldsStruct( defer struct_type.clearFieldTypesWip(ip); semaStructFields(pt, sema.arena, struct_type) catch |err| switch (err) { - error.AnalysisFail => { - if (zcu.declPtr(owner_decl).analysis == .complete) { - zcu.declPtr(owner_decl).analysis = .dependency_failure; - } - return error.AnalysisFail; - }, - error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail, error.OutOfMemory => |e| return e, error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, }; } @@ -35799,9 +35803,8 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; const struct_type = zcu.typeToStruct(ty) orelse return; - const owner_decl = struct_type.decl.unwrap() orelse return; - assert(sema.ownerUnit().unwrap().decl == owner_decl); + assert(sema.owner.unwrap().cau == struct_type.cau.unwrap().?); // Inits can start as resolved if (struct_type.haveFieldInits(ip)) return; @@ -35819,13 +35822,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { defer struct_type.clearInitsWip(ip); semaStructFieldInits(pt, sema.arena, struct_type) catch |err| switch (err) { - error.AnalysisFail => { - if (zcu.declPtr(owner_decl).analysis == .complete) { - zcu.declPtr(owner_decl).analysis = .dependency_failure; - } - return error.AnalysisFail; - }, - error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail, error.OutOfMemory => |e| return e, error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, }; struct_type.setHaveFieldInits(ip); @@ -35835,20 +35832,9 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Load const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - const owner_decl = zcu.declPtr(union_type.decl); - assert(sema.ownerUnit().unwrap().decl == union_type.decl); + assert(sema.owner.unwrap().cau == union_type.cau); - switch (owner_decl.analysis) { - .file_failure, - .dependency_failure, - .sema_failure, - => { - sema.owner_decl.analysis = .dependency_failure; - return error.AnalysisFail; - }, - else => {}, - } switch (union_type.flagsUnordered(ip).status) { .none => {}, .field_types_wip => { @@ -35869,14 +35855,8 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Load union_type.setStatus(ip, .field_types_wip); errdefer union_type.setStatus(ip, .none); - semaUnionFields(pt, sema.arena, union_type) catch |err| switch (err) { - error.AnalysisFail => { - if (owner_decl.analysis == .complete) { - owner_decl.analysis = .dependency_failure; - } - return error.AnalysisFail; - }, - error.OutOfMemory => return error.OutOfMemory, + semaUnionFields(pt, sema.arena, ty.toIntern(), union_type) catch |err| switch (err) { + error.AnalysisFail, error.OutOfMemory => |e| return e, error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, }; union_type.setStatus(ip, .have_field_types); @@ -35891,28 +35871,28 @@ fn resolveInferredErrorSet( ies_index: InternPool.Index, ) CompileError!InternPool.Index { const pt = sema.pt; - const mod = pt.zcu; - const ip = &mod.intern_pool; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; const func_index = ip.iesFuncIndex(ies_index); - const func = mod.funcInfo(func_index); + const func = zcu.funcInfo(func_index); - try sema.declareDependency(.{ .func_ies = func_index }); + try sema.declareDependency(.{ .interned = func_index }); // resolved IES // TODO: during an incremental update this might not be `.none`, but the // function might be out-of-date! const resolved_ty = func.resolvedErrorSetUnordered(ip); if (resolved_ty != .none) return resolved_ty; - if (func.analysisUnordered(ip).state == .in_progress) + if (zcu.analysis_in_progress.contains(AnalUnit.wrap(.{ .func = func_index }))) { return sema.fail(block, src, "unable to resolve inferred error set", .{}); + } // In order to ensure that all dependencies are properly added to the set, // we need to ensure the function body is analyzed of the inferred error // set. However, in the case of comptime/inline function calls with // inferred error sets, each call gets an adhoc InferredErrorSet object, which // has no corresponding function body. - const ies_func_owner_decl = mod.declPtr(func.owner_decl); - const ies_func_info = mod.typeToFunc(ies_func_owner_decl.typeOf(mod)).?; + const ies_func_info = zcu.typeToFunc(Type.fromInterned(func.ty)).?; // if ies declared by a inline function with generic return type, the return_type should be generic_poison, // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, // so here we can simply skip this case. @@ -35920,22 +35900,17 @@ fn resolveInferredErrorSet( assert(ies_func_info.cc == .Inline); } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) { if (ies_func_info.is_generic) { - const msg = msg: { + return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "unable to resolve inferred error set of generic function", .{}); errdefer msg.destroy(sema.gpa); - - try sema.errNote(.{ - .base_node_inst = ies_func_owner_decl.zir_decl_index.unwrap().?, - .offset = LazySrcLoc.Offset.nodeOffset(0), - }, msg, "generic function declared here", .{}); + try sema.errNote(zcu.navSrcLoc(func.owner_nav), msg, "generic function declared here", .{}); break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + }); } // In this case we are dealing with the actual InferredErrorSet object that // corresponds to the function, not one created to track an inline/comptime call. try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index })); - try sema.ensureFuncBodyAnalyzed(func_index); + try pt.ensureFuncBodyAnalyzed(func_index); } // This will now have been resolved by the logic at the end of `Module.analyzeFnBody` @@ -36092,9 +36067,8 @@ fn semaStructFields( const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; - const decl_index = struct_type.decl.unwrap() orelse return; - const decl = zcu.declPtr(decl_index); - const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace; + const cau_index = struct_type.cau.unwrap().?; + const namespace_index = ip.getCau(cau_index).namespace; const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); @@ -36119,13 +36093,11 @@ fn semaStructFields( .gpa = gpa, .arena = arena, .code = zir, - .owner_decl = decl, - .owner_decl_index = decl_index, + .owner = AnalUnit.wrap(.{ .cau = cau_index }), .func_index = .none, .func_is_naked = false, .fn_ret_ty = Type.void, .fn_ret_ty_ies = null, - .owner_func_index = .none, .comptime_err_ret_trace = &comptime_err_ret_trace, }; defer sema.deinit(); @@ -36138,7 +36110,7 @@ fn semaStructFields( .inlining = null, .is_comptime = true, .src_base_inst = struct_type.zir_index.unwrap().?, - .type_name_ctx = decl.name, + .type_name_ctx = struct_type.name, }; defer assert(block_scope.instructions.items.len == 0); @@ -36318,9 +36290,8 @@ fn semaStructFieldInits( assert(!struct_type.haveFieldInits(ip)); - const decl_index = struct_type.decl.unwrap() orelse return; - const decl = zcu.declPtr(decl_index); - const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace; + const cau_index = struct_type.cau.unwrap().?; + const namespace_index = ip.getCau(cau_index).namespace; const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); @@ -36333,13 +36304,11 @@ fn semaStructFieldInits( .gpa = gpa, .arena = arena, .code = zir, - .owner_decl = decl, - .owner_decl_index = decl_index, + .owner = AnalUnit.wrap(.{ .cau = cau_index }), .func_index = .none, .func_is_naked = false, .fn_ret_ty = Type.void, .fn_ret_ty_ies = null, - .owner_func_index = .none, .comptime_err_ret_trace = &comptime_err_ret_trace, }; defer sema.deinit(); @@ -36352,7 +36321,7 @@ fn semaStructFieldInits( .inlining = null, .is_comptime = true, .src_base_inst = struct_type.zir_index.unwrap().?, - .type_name_ctx = decl.name, + .type_name_ctx = struct_type.name, }; defer assert(block_scope.instructions.items.len == 0); @@ -36449,15 +36418,15 @@ fn semaStructFieldInits( try sema.flushExports(); } -fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void { +fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_ty: InternPool.Index, union_type: InternPool.LoadedUnionType) CompileError!void { const tracy = trace(@src()); defer tracy.end(); const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; - const decl_index = union_type.decl; - const zir = zcu.namespacePtr(union_type.namespace.unwrap().?).fileScope(zcu).zir; + const cau_index = union_type.cau; + const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir; const zir_index = union_type.zir_index.resolve(ip); const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; assert(extended.opcode == .union_decl); @@ -36501,8 +36470,6 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_type: InternPool.L const body = zir.bodySlice(extra_index, body_len); extra_index += body.len; - const decl = zcu.declPtr(decl_index); - var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa); defer comptime_err_ret_trace.deinit(); @@ -36511,13 +36478,11 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_type: InternPool.L .gpa = gpa, .arena = arena, .code = zir, - .owner_decl = decl, - .owner_decl_index = decl_index, + .owner = AnalUnit.wrap(.{ .cau = cau_index }), .func_index = .none, .func_is_naked = false, .fn_ret_ty = Type.void, .fn_ret_ty_ies = null, - .owner_func_index = .none, .comptime_err_ret_trace = &comptime_err_ret_trace, }; defer sema.deinit(); @@ -36525,12 +36490,12 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_type: InternPool.L var block_scope: Block = .{ .parent = null, .sema = &sema, - .namespace = union_type.namespace.unwrap().?, + .namespace = union_type.namespace, .instructions = .{}, .inlining = null, .is_comptime = true, .src_base_inst = union_type.zir_index, - .type_name_ctx = decl.name, + .type_name_ctx = union_type.name, }; defer assert(block_scope.instructions.items.len == 0); @@ -36817,10 +36782,10 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_type: InternPool.L return sema.failWithOwnedErrorMsg(&block_scope, msg); } } else if (enum_field_vals.count() > 0) { - const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), zcu.declPtr(union_type.decl)); + const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_ty, union_type.name); union_type.setTagType(ip, enum_ty); } else { - const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, zcu.declPtr(union_type.decl)); + const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_ty, union_type.name); union_type.setTagType(ip, enum_ty); } @@ -36839,36 +36804,25 @@ fn generateUnionTagTypeNumbered( block: *Block, enum_field_names: []const InternPool.NullTerminatedString, enum_field_vals: []const InternPool.Index, - union_owner_decl: *Module.Decl, + union_type: InternPool.Index, + union_name: InternPool.NullTerminatedString, ) !InternPool.Index { const pt = sema.pt; const mod = pt.zcu; const gpa = sema.gpa; const ip = &mod.intern_pool; - const new_decl_index = try pt.allocateNewDecl(block.namespace); - errdefer pt.destroyDecl(new_decl_index); const name = try ip.getOrPutStringFmt( gpa, pt.tid, "@typeInfo({}).Union.tag_type.?", - .{union_owner_decl.fqn.fmt(ip)}, + .{union_name.fmt(ip)}, .no_embedded_nulls, ); - try pt.initNewAnonDecl( - new_decl_index, - Value.@"unreachable", - name, - name.toOptional(), - ); - errdefer pt.abortAnonDecl(new_decl_index); - - const new_decl = mod.declPtr(new_decl_index); - new_decl.owns_tv = true; const enum_ty = try ip.getGeneratedTagEnumType(gpa, pt.tid, .{ - .decl = new_decl_index, - .owner_union_ty = union_owner_decl.val.toIntern(), + .name = name, + .owner_union_ty = union_type, .tag_ty = if (enum_field_vals.len == 0) (try pt.intType(.unsigned, 0)).toIntern() else @@ -36876,11 +36830,9 @@ fn generateUnionTagTypeNumbered( .names = enum_field_names, .values = enum_field_vals, .tag_mode = .explicit, + .parent_namespace = block.namespace, }); - new_decl.val = Value.fromInterned(enum_ty); - - try pt.finalizeAnonDecl(new_decl_index); return enum_ty; } @@ -36888,36 +36840,25 @@ fn generateUnionTagTypeSimple( sema: *Sema, block: *Block, enum_field_names: []const InternPool.NullTerminatedString, - union_owner_decl: *Module.Decl, + union_type: InternPool.Index, + union_name: InternPool.NullTerminatedString, ) !InternPool.Index { const pt = sema.pt; const mod = pt.zcu; const ip = &mod.intern_pool; const gpa = sema.gpa; - const new_decl_index = new_decl_index: { - const new_decl_index = try pt.allocateNewDecl(block.namespace); - errdefer pt.destroyDecl(new_decl_index); - const name = try ip.getOrPutStringFmt( - gpa, - pt.tid, - "@typeInfo({}).Union.tag_type.?", - .{union_owner_decl.fqn.fmt(ip)}, - .no_embedded_nulls, - ); - try pt.initNewAnonDecl( - new_decl_index, - Value.@"unreachable", - name, - name.toOptional(), - ); - break :new_decl_index new_decl_index; - }; - errdefer pt.abortAnonDecl(new_decl_index); + const name = try ip.getOrPutStringFmt( + gpa, + pt.tid, + "@typeInfo({}).Union.tag_type.?", + .{union_name.fmt(ip)}, + .no_embedded_nulls, + ); const enum_ty = try ip.getGeneratedTagEnumType(gpa, pt.tid, .{ - .decl = new_decl_index, - .owner_union_ty = union_owner_decl.val.toIntern(), + .name = name, + .owner_union_ty = union_type, .tag_ty = if (enum_field_names.len == 0) (try pt.intType(.unsigned, 0)).toIntern() else @@ -36925,13 +36866,9 @@ fn generateUnionTagTypeSimple( .names = enum_field_names, .values = &.{}, .tag_mode = .auto, + .parent_namespace = block.namespace, }); - const new_decl = mod.declPtr(new_decl_index); - new_decl.owns_tv = true; - new_decl.val = Value.fromInterned(enum_ty); - - try pt.finalizeAnonDecl(new_decl_index); return enum_ty; } @@ -37057,9 +36994,9 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { // values, not types .undef, .simple_value, - .ptr_decl, - .ptr_anon_decl, - .ptr_anon_decl_aligned, + .ptr_nav, + .ptr_uav, + .ptr_uav_aligned, .ptr_comptime_alloc, .ptr_comptime_field, .ptr_int, @@ -37096,7 +37033,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .float_c_longdouble_f128, .float_comptime_float, .variable, - .extern_func, + .@"extern", .func_decl, .func_instance, .func_coerced, @@ -37965,7 +37902,7 @@ fn intFitsInType( .zero_usize, .zero_u8 => return true, else => switch (mod.intern_pool.indexToKey(val.toIntern())) { .undef => return true, - .variable, .extern_func, .func, .ptr => { + .variable, .@"extern", .func, .ptr => { const target = mod.getTarget(); const ptr_bits = target.ptrBitWidth(); return switch (info.signedness) { @@ -38240,24 +38177,24 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve // the loop. - if (sema.owner_func_index == .none and dependee == .decl_val and dependee.decl_val == sema.owner_decl_index) { - return; + switch (sema.owner.unwrap()) { + .cau => |cau| switch (dependee) { + .nav_val => |nav| if (zcu.intern_pool.getNav(nav).analysis_owner == cau.toOptional()) { + return; + }, + else => {}, + }, + .func => {}, } - const depender = AnalUnit.wrap( - if (sema.owner_func_index != .none) - .{ .func = sema.owner_func_index } - else - .{ .decl = sema.owner_decl_index }, - ); - try zcu.intern_pool.addDependency(sema.gpa, depender, dependee); + try zcu.intern_pool.addDependency(sema.gpa, sema.owner, dependee); } fn isComptimeMutablePtr(sema: *Sema, val: Value) bool { return switch (sema.pt.zcu.intern_pool.indexToKey(val.toIntern())) { .slice => |slice| sema.isComptimeMutablePtr(Value.fromInterned(slice.ptr)), .ptr => |ptr| switch (ptr.base_addr) { - .anon_decl, .decl, .int => false, + .uav, .nav, .int => false, .comptime_field => true, .comptime_alloc => |alloc_index| !sema.getComptimeAlloc(alloc_index).is_const, .eu_payload, .opt_payload => |base| sema.isComptimeMutablePtr(Value.fromInterned(base)), @@ -38388,19 +38325,17 @@ pub fn flushExports(sema: *Sema) !void { const zcu = sema.pt.zcu; const gpa = zcu.gpa; - const unit = sema.ownerUnit(); - // There may be existing exports. For instance, a struct may export // things during both field type resolution and field default resolution. // // So, pick up and delete any existing exports. This strategy performs // redundant work, but that's okay, because this case is exceedingly rare. - if (zcu.single_exports.get(unit)) |export_idx| { + if (zcu.single_exports.get(sema.owner)) |export_idx| { try sema.exports.append(gpa, zcu.all_exports.items[export_idx]); - } else if (zcu.multi_exports.get(unit)) |info| { + } else if (zcu.multi_exports.get(sema.owner)) |info| { try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]); } - zcu.deleteUnitExports(unit); + zcu.deleteUnitExports(sema.owner); // `sema.exports` is completed; store the data into the `Zcu`. if (sema.exports.items.len == 1) { @@ -38410,24 +38345,55 @@ pub fn flushExports(sema: *Sema) !void { break :idx zcu.all_exports.items.len - 1; }; zcu.all_exports.items[export_idx] = sema.exports.items[0]; - zcu.single_exports.putAssumeCapacityNoClobber(unit, @intCast(export_idx)); + zcu.single_exports.putAssumeCapacityNoClobber(sema.owner, @intCast(export_idx)); } else { try zcu.multi_exports.ensureUnusedCapacity(gpa, 1); const exports_base = zcu.all_exports.items.len; try zcu.all_exports.appendSlice(gpa, sema.exports.items); - zcu.multi_exports.putAssumeCapacityNoClobber(unit, .{ + zcu.multi_exports.putAssumeCapacityNoClobber(sema.owner, .{ .index = @intCast(exports_base), .len = @intCast(sema.exports.items.len), }); } } -pub fn ownerUnit(sema: Sema) AnalUnit { - if (sema.owner_func_index != .none) { - return AnalUnit.wrap(.{ .func = sema.owner_func_index }); - } else { - return AnalUnit.wrap(.{ .decl = sema.owner_decl_index }); - } +/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches +/// the corresponding `Nav`. +fn getOwnerCauNav(sema: *Sema) InternPool.Nav.Index { + const cau = sema.owner.unwrap().cau; + return sema.pt.zcu.intern_pool.getCau(cau).owner.unwrap().nav; +} + +/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches +/// the declaration name from its corresponding `Nav`. +fn getOwnerCauNavName(sema: *Sema) InternPool.NullTerminatedString { + const nav = sema.getOwnerCauNav(); + return sema.pt.zcu.intern_pool.getNav(nav).name; +} + +/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches +/// the `TrackedInst` corresponding to this `declaration` instruction. +fn getOwnerCauDeclInst(sema: *Sema) InternPool.TrackedInst.Index { + const ip = &sema.pt.zcu.intern_pool; + const cau = ip.getCau(sema.owner.unwrap().cau); + assert(cau.owner.unwrap() == .nav); + return cau.zir_index; +} + +/// Given that this `Sema` is owned by a runtime function, fetches the +/// `TrackedInst` corresponding to its `declaration` instruction. +fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index { + const zcu = sema.pt.zcu; + const ip = &zcu.intern_pool; + const func = sema.owner.unwrap().func; + const func_info = zcu.funcInfo(func); + const cau = if (func_info.generic_owner == .none) cau: { + break :cau ip.getNav(func_info.owner_nav).analysis_owner.unwrap().?; + } else cau: { + const generic_owner = zcu.funcInfo(func_info.generic_owner); + break :cau ip.getNav(generic_owner.owner_nav).analysis_owner.unwrap().?; + }; + return ip.getCau(cau).zir_index; } pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; |
