zig

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

commit 1fbfe8c8711a3c2ecd3db4f5ff1877ac76d89a6b (tree)
parent c5d4c61cf607f3f6e2f520b4ce5406b8f176bdf9
Author: Motiejus <motiejus@jakstys.lt>
Date:   Tue, 10 Mar 2026 07:41:10 +0000

sema: store zir_inst in namespace, extract param type helper

Refactor to match upstream Zig's type resolution architecture:

- Add zir_inst to ZcuNamespace, matching upstream's
  LoadedStructType.zir_index / LoadedEnumType.zir_index. Set at
  namespace creation time in resolveStructDeclFromZir,
  resolveEnumDeclFromZir, resolveUnionDeclFromZir.

- Simplify resolveStructLayoutC, resolveStructFullyC,
  resolveUnionFullyC to use ns->zir_inst instead of scanning nav
  value bodies. Removes ~45 lines of value-body-scan code.

- Extract resolveParamTypeFromZir helper from inline param type
  resolution in ensureNavValUpToDate. Ported from Sema.zig zirParam
  type body resolution.

- Add setNavResolvedType helper that centralizes nav resolved_type
  setting with namespace owner_type remap for shard simulation.

- Add @This() support in resolveZirTypeInst, ported from Sema.zig
  zirThis.

- Add nav_ns_remap infrastructure for shard simulation correctness:
  tracks nav→namespace mapping so owner_types stay valid after
  clearing nav resolved_types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mstage0/sema.c | 86++++++++++++++++++++++++++-----------------------------------------------------
Mstage0/zcu.c | 2++
Mstage0/zcu.h | 11+++++++++++
Mstage0/zcu_per_thread.c | 118++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mstage0/zcu_per_thread.h | 4++++
5 files changed, 144 insertions(+), 77 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -3645,6 +3645,7 @@ InternPoolIndex resolveEnumDeclFromZir( = sema->zcu->namespaces[ipGetNav(sema->ip, nav_idx)->namespace_idx] .file_idx; uint32_t ens = createNamespace(sema, enum_ip, enum_file_idx); + sema->zcu->namespaces[ens].zir_inst = enum_inst; scanNamespaceC(sema, ens, decl_insts, decls_len, zir); } @@ -4068,6 +4069,13 @@ InternPoolIndex resolveZirTypeInst(Sema* sema, const Zir* zir, uint32_t inst, if (tag == ZIR_INST_PTR_TYPE) return resolveZirPtrTypeInst(sema, zir, inst, struct_ns, file_idx); + // @This() returns the owner type of the enclosing namespace. + // Ported from Sema.zig zirThis → block.getNamespace().owner_type. + if (tag == ZIR_INST_EXTENDED + && zir->inst_datas[inst].extended.opcode == ZIR_EXT_THIS) { + return sema->zcu->namespaces[struct_ns].owner_type; + } + if (tag == ZIR_INST_OPTIONAL_TYPE) { ZirInstRef child_ref = zir->inst_datas[inst].un_node.operand; InternPoolIndex child_ip @@ -4176,8 +4184,7 @@ InternPoolIndex resolveZirTypeInst(Sema* sema, const Zir* zir, uint32_t inst, InternPoolIndex alias_result = resolveZirTypeRef(sema, tzir, op, tnns, tnfi); if (alias_result != IP_INDEX_NONE) { - Nav* wnav = ipGetNav(sema->ip, nav); - wnav->resolved_type = alias_result; + setNavResolvedType(sema, nav, alias_result); // Create ptr_nav for the alias declaration, // matching analyzeNavRefInner which creates // a ptr_nav for every resolved nav reference. @@ -4889,6 +4896,7 @@ InternPoolIndex resolveStructDeclFromZir( const Nav* nav = ipGetNav(sema->ip, nav_idx); uint32_t ns_idx = createNamespace( sema, struct_ip, sema->zcu->namespaces[nav->namespace_idx].file_idx); + sema->zcu->namespaces[ns_idx].zir_inst = struct_inst; // Scan namespace declarations. const uint32_t* decl_insts = &zir->extra[extra_index]; @@ -5087,8 +5095,9 @@ static void resolveStructFieldTypesFully(Sema* sema, const Zir* zir, sei += finfo[fi].align_body_len; sei += finfo[fi].init_body_len; - if (resolved != IP_INDEX_NONE) + if (resolved != IP_INDEX_NONE) { resolveTypeFullyC(sema, resolved); + } } } @@ -5114,27 +5123,13 @@ static bool resolveStructLayoutC(Sema* sema, uint32_t nav_idx) { if (ns_idx == UINT32_MAX) return false; - // Find the struct_decl ZIR instruction. + // Get the struct_decl ZIR instruction from the namespace. + // Matches upstream: struct_type.zir_index.resolve(ip). uint32_t file_idx = sema->zcu->namespaces[ns_idx].file_idx; if (!sema->zcu->files[file_idx].has_zir) return false; const Zir* zir = &sema->zcu->files[file_idx].zir; - - const uint32_t* vbody = NULL; - uint32_t vbody_len = 0; - getValueBodyFromZir(zir, nav->zir_index, &vbody, &vbody_len); - if (!vbody) - return false; - - uint32_t struct_inst = UINT32_MAX; - for (uint32_t i = 0; i < vbody_len; i++) { - uint32_t inst = vbody[i]; - if (inst < zir->inst_len && zir->inst_tags[inst] == ZIR_INST_EXTENDED - && zir->inst_datas[inst].extended.opcode == ZIR_EXT_STRUCT_DECL) { - struct_inst = inst; - break; - } - } + uint32_t struct_inst = sema->zcu->namespaces[ns_idx].zir_inst; if (struct_inst == UINT32_MAX) return false; @@ -5150,12 +5145,15 @@ static bool resolveStructLayoutC(Sema* sema, uint32_t nav_idx) { // Assumes resolveStructLayoutC has already been called (field types resolved). static void resolveStructFullyC(Sema* sema, uint32_t nav_idx) { const Nav* nav = ipGetNav(sema->ip, nav_idx); - if (nav->resolved_type == IP_INDEX_NONE) + if (nav->resolved_type == IP_INDEX_NONE) { return; - if (sema->ip->items[nav->resolved_type].tag != IP_KEY_STRUCT_TYPE) + } + if (sema->ip->items[nav->resolved_type].tag != IP_KEY_STRUCT_TYPE) { return; - if (nav_idx < 4096 && sema->zcu->struct_fully_resolved[nav_idx]) + } + if (nav_idx < 4096 && sema->zcu->struct_fully_resolved[nav_idx]) { return; + } if (nav_idx < 4096) sema->zcu->struct_fully_resolved[nav_idx] = true; @@ -5167,27 +5165,13 @@ static void resolveStructFullyC(Sema* sema, uint32_t nav_idx) { if (ns_idx == UINT32_MAX) return; - // Find the struct_decl ZIR instruction. + // Get the struct_decl ZIR instruction from the namespace. + // Matches upstream: struct_type.zir_index.resolve(ip). uint32_t file_idx = sema->zcu->namespaces[ns_idx].file_idx; if (!sema->zcu->files[file_idx].has_zir) return; const Zir* zir = &sema->zcu->files[file_idx].zir; - - const uint32_t* vbody = NULL; - uint32_t vbody_len = 0; - getValueBodyFromZir(zir, nav->zir_index, &vbody, &vbody_len); - if (!vbody) - return; - - uint32_t struct_inst = UINT32_MAX; - for (uint32_t i = 0; i < vbody_len; i++) { - uint32_t inst = vbody[i]; - if (inst < zir->inst_len && zir->inst_tags[inst] == ZIR_INST_EXTENDED - && zir->inst_datas[inst].extended.opcode == ZIR_EXT_STRUCT_DECL) { - struct_inst = inst; - break; - } - } + uint32_t struct_inst = sema->zcu->namespaces[ns_idx].zir_inst; if (struct_inst == UINT32_MAX) return; @@ -5234,27 +5218,13 @@ static void resolveUnionFullyC(Sema* sema, uint32_t nav_idx) { if (ns_idx == UINT32_MAX) return; - // Find the union_decl ZIR instruction from the nav's declaration body. + // Get the union_decl ZIR instruction from the namespace. + // Matches upstream: union_type.zir_index.resolve(ip). uint32_t file_idx = sema->zcu->namespaces[ns_idx].file_idx; if (!sema->zcu->files[file_idx].has_zir) return; const Zir* zir = &sema->zcu->files[file_idx].zir; - - const uint32_t* vbody = NULL; - uint32_t vbody_len = 0; - getValueBodyFromZir(zir, nav->zir_index, &vbody, &vbody_len); - if (!vbody) - return; - - uint32_t union_inst = UINT32_MAX; - for (uint32_t i = 0; i < vbody_len; i++) { - uint32_t inst = vbody[i]; - if (inst < zir->inst_len && zir->inst_tags[inst] == ZIR_INST_EXTENDED - && zir->inst_datas[inst].extended.opcode == ZIR_EXT_UNION_DECL) { - union_inst = inst; - break; - } - } + uint32_t union_inst = sema->zcu->namespaces[ns_idx].zir_inst; if (union_inst == UINT32_MAX) return; @@ -5567,6 +5537,7 @@ InternPoolIndex resolveUnionDeclFromZir( = sema->zcu->namespaces[ipGetNav(sema->ip, nav_idx)->namespace_idx] .file_idx; uint32_t ns_idx = createNamespace(sema, union_ip, file_idx); + sema->zcu->namespaces[ns_idx].zir_inst = union_inst; // Scan namespace declarations (creates Navs for sub-types like // CommonOptions, X86RegparmOptions, etc.). @@ -11454,7 +11425,6 @@ static void zirExport(Sema* sema, uint32_t inst) { // Ported from Sema.zig: zirExport → resolveExportOptions → // getBuiltinType(.ExportOptions) → ensureMemoizedStateResolved(.main). ensureFullMemoizedStateC(sema); - uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index; uint32_t exported_ref = sema->code.extra[payload_index]; if (exported_ref >= ZIR_REF_START_INDEX) { diff --git a/stage0/zcu.c b/stage0/zcu.c @@ -1,5 +1,6 @@ #include "zcu.h" #include <stdlib.h> +#include <string.h> Zcu* zcuInit(Compilation* comp) { Zcu* zcu = (Zcu*)calloc(1, sizeof(Zcu)); @@ -12,6 +13,7 @@ Zcu* zcuInit(Compilation* comp) { zcu->builtin_file_idx = UINT32_MAX; zcu->cg_builtin_ns_idx = UINT32_MAX; zcu->cg_builtin_nav = UINT32_MAX; + memset(zcu->nav_ns_remap, 0xFF, sizeof(zcu->nav_ns_remap)); return zcu; } diff --git a/stage0/zcu.h b/stage0/zcu.h @@ -33,6 +33,10 @@ typedef struct { typedef struct { InternPoolIndex owner_type; // type_struct IP index uint32_t file_idx; // index into files[] + uint32_t + zir_inst; // ZIR instruction index of the type declaration + // (struct_decl/enum_decl/union_decl). Matches upstream's + // LoadedStructType.zir_index / LoadedEnumType.zir_index. uint32_t pub_navs[ZCU_NS_MAX_NAVS]; uint32_t pub_nav_count; uint32_t priv_navs[ZCU_NS_MAX_NAVS]; @@ -143,6 +147,13 @@ typedef struct Zcu { } ct_struct_vals[ZCU_MAX_CT_STRUCT_VALS]; uint32_t num_ct_struct_vals; + // --- Namespace owner_type remap (shard simulation) --- + // After clearing nav resolved_types, namespace owner_types become stale. + // This maps nav_idx → ns_idx so ensureNavValUpToDate can update them. + // Built by ensureFullMemoizedStateC before clearing, consumed during + // re-resolution. UINT32_MAX means no mapping for that nav. + uint32_t nav_ns_remap[4096]; + // --- Compilation config --- Compilation* comp; // back-pointer; matches Zcu.comp in Zig } Zcu; diff --git a/stage0/zcu_per_thread.c b/stage0/zcu_per_thread.c @@ -205,6 +205,7 @@ uint32_t createNamespace( memset(ns, 0, sizeof(*ns)); ns->owner_type = owner_type; ns->file_idx = file_idx; + ns->zir_inst = UINT32_MAX; return idx; } @@ -443,6 +444,21 @@ uint32_t findNamespaceForType(const Sema* sema, InternPoolIndex type_ip) { return UINT32_MAX; } +// Update nav->resolved_type and fix stale namespace owner_type. +// After shard simulation clears nav resolved_types, namespace owner_types +// become stale (pointing to preamble IP indices). When a nav is re-resolved, +// this function uses the nav_ns_remap mapping to update the namespace. +void setNavResolvedType( + Sema* sema, uint32_t nav_idx, InternPoolIndex type_ip) { + Nav* nav = ipGetNav(sema->ip, nav_idx); + nav->resolved_type = type_ip; + if (nav_idx < 4096 && sema->zcu->nav_ns_remap[nav_idx] != UINT32_MAX) { + sema->zcu->namespaces[sema->zcu->nav_ns_remap[nav_idx]].owner_type + = type_ip; + sema->zcu->nav_ns_remap[nav_idx] = UINT32_MAX; + } +} + uint32_t findNavForIPIndex(Sema* sema, InternPoolIndex ip_idx) { for (uint32_t nsi = 0; nsi < sema->zcu->num_namespaces; nsi++) { const ZcuNamespace* ns = &sema->zcu->namespaces[nsi]; @@ -459,7 +475,7 @@ uint32_t findNavForIPIndex(Sema* sema, InternPoolIndex ip_idx) { } static InternPoolIndex analyzeNavValC(Sema* sema, uint32_t nav_idx) { - Nav* nav = ipGetNav(sema->ip, nav_idx); + const Nav* nav = ipGetNav(sema->ip, nav_idx); uint32_t ns_idx = nav->namespace_idx; const ZcuNamespace* ns = &sema->zcu->namespaces[ns_idx]; uint32_t file_idx = ns->file_idx; @@ -578,8 +594,7 @@ static InternPoolIndex analyzeNavValC(Sema* sema, uint32_t nav_idx) { InternPoolIndex type_result = resolveZirTypeRef(sema, zir, op, ns_idx, file_idx); if (type_result != IP_INDEX_NONE) { - nav = ipGetNav(sema->ip, nav_idx); - nav->resolved_type = type_result; + setNavResolvedType(sema, nav_idx, type_result); return type_result; } } @@ -594,17 +609,41 @@ static InternPoolIndex analyzeNavValC(Sema* sema, uint32_t nav_idx) { // This allows callers to get both the type and the value. // Ported from PerThread.zig analyzeNav which resolves type and val // separately. - nav = ipGetNav(sema->ip, nav_idx); if (type_body_result != IP_INDEX_NONE) { - nav->resolved_type = type_body_result; - nav->resolved_val = result_ip; + setNavResolvedType(sema, nav_idx, type_body_result); + ipGetNav(sema->ip, nav_idx)->resolved_val = result_ip; } else { - nav->resolved_type = result_ip; + setNavResolvedType(sema, nav_idx, result_ip); } return result_ip; } +// Resolve a single ZIR param instruction's type. +// Extracts the type body from the param's ZIR layout, finds the +// break_inline result, and resolves it as a type reference. +// Returns IP_INDEX_NONE if the param type cannot be resolved +// (generic, anytype, or unresolvable). +// Ported from Sema.zig zirParam type body resolution. +static InternPoolIndex resolveParamTypeFromZir(Sema* sema, const Zir* zir, + uint32_t param_inst, uint32_t ns_idx, uint32_t file_idx) { + // Param layout: extra[ppl+0]=name, + // extra[ppl+1]=type_raw (body_len:31|generic:1), + // extra[ppl+2..ppl+1+body_len] = body instructions. + uint32_t ppl = zir->inst_datas[param_inst].pl_tok.payload_index; + uint32_t type_raw = zir->extra[ppl + 1]; + bool is_generic = (type_raw >> 31) & 1; + uint32_t type_body_len = type_raw & 0x7FFFFFFF; + if (is_generic || type_body_len < 1) + return IP_INDEX_NONE; + uint32_t last_ti = zir->extra[ppl + 2 + type_body_len - 1]; + if (last_ti >= zir->inst_len + || zir->inst_tags[last_ti] != ZIR_INST_BREAK_INLINE) + return IP_INDEX_NONE; + ZirInstRef type_ref = zir->inst_datas[last_ti].break_data.operand; + return resolveZirTypeRef(sema, zir, type_ref, ns_idx, file_idx); +} + InternPoolIndex ensureNavValUpToDate(Sema* sema, uint32_t nav_idx) { const Nav* nav = ipGetNav(sema->ip, nav_idx); @@ -679,8 +718,7 @@ InternPoolIndex ensureNavValUpToDate(Sema* sema, uint32_t nav_idx) { // @This() resolves to the type that owns the namespace // this declaration is declared in. E.g. `const V = @This();` // inside a struct resolves V to that struct type. - Nav* wnav = ipGetNav(sema->ip, nav_idx); - wnav->resolved_type = ns->owner_type; + setNavResolvedType(sema, nav_idx, ns->owner_type); InternPoolIndex ptr_type = internPtrConst(sema, IP_INDEX_TYPE_TYPE); (void)internNavPtr(sema, ptr_type, nav_idx); @@ -734,9 +772,13 @@ InternPoolIndex ensureNavValUpToDate(Sema* sema, uint32_t nav_idx) { } } - // Count parameters from param_block. - // Ported from Zir.getParamBody. + // Count parameters and resolve param types from param_block. + // Ported from Sema.zig zirParam + funcCommon param type + // handling. uint32_t param_count = 0; + InternPoolIndex param_type_buf[FUNC_TYPE_MAX_PARAMS]; + memset(param_type_buf, 0, sizeof(param_type_buf)); + bool has_param_types = false; { uint32_t pi = zir->inst_datas[inst].pl_node.payload_index; uint32_t pb_inst = zir->extra[pi + fi.param_block_pi]; @@ -746,8 +788,17 @@ InternPoolIndex ensureNavValUpToDate(Sema* sema, uint32_t nav_idx) { for (uint32_t pbi = 0; pbi < pb_len; pbi++) { ZirInstTag ptag = zir->inst_tags[pb_body[pbi]]; if (ptag == ZIR_INST_PARAM - || ptag == ZIR_INST_PARAM_COMPTIME - || ptag == ZIR_INST_PARAM_ANYTYPE + || ptag == ZIR_INST_PARAM_COMPTIME) { + if (param_count < FUNC_TYPE_MAX_PARAMS) { + InternPoolIndex resolved = resolveParamTypeFromZir( + sema, zir, pb_body[pbi], ns_idx, file_idx); + if (resolved != IP_INDEX_NONE) { + param_type_buf[param_count] = resolved; + has_param_types = true; + } + } + param_count++; + } else if (ptag == ZIR_INST_PARAM_ANYTYPE || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) { param_count++; } @@ -789,11 +840,23 @@ InternPoolIndex ensureNavValUpToDate(Sema* sema, uint32_t nav_idx) { } cc = 1; // C calling convention (bootstrap only) } - InternPoolIndex ft - = internFuncType(sema, ret_ty, param_count, cc, false, NULL); + // Fully resolve param types before creating func_type. + // Ported from Sema.zig resolveFnTypes which calls + // resolveFully on each param type after analyzeFnBodyInner. + // This creates child type hierarchy entries (e.g. std.Target + // for *const Target) that must appear before func_type in + // the IP, matching the Zig compiler. + if (has_param_types) { + for (uint32_t p = 0; + p < param_count && p < FUNC_TYPE_MAX_PARAMS; p++) { + if (param_type_buf[p] != IP_INDEX_NONE) + resolveTypeFullyC(sema, param_type_buf[p]); + } + } + InternPoolIndex ft = internFuncType(sema, ret_ty, param_count, cc, + false, has_param_types ? param_type_buf : NULL); InternPoolIndex fd = internFuncDecl(sema, nav_idx, ft); - Nav* wnav = ipGetNav(sema->ip, nav_idx); - wnav->resolved_type = fd; + setNavResolvedType(sema, nav_idx, fd); InternPoolIndex ptr_ty = internPtrConst(sema, ft); (void)internNavPtr(sema, ptr_ty, nav_idx); return fd; @@ -825,8 +888,7 @@ InternPoolIndex ensureNavValUpToDate(Sema* sema, uint32_t nav_idx) { if (struct_type == 0 && import_file_idx > 0) break; - Nav* wnav = ipGetNav(sema->ip, nav_idx); - wnav->resolved_type = struct_type; + setNavResolvedType(sema, nav_idx, struct_type); return struct_type; } } @@ -1244,6 +1306,24 @@ void ensureFullMemoizedStateC(Sema* sema) { for (int i = 0; i < NUM_BUILTIN_DECL_MAIN; i++) sema->zcu->builtin_decl_values[i] = IP_INDEX_NONE; + // Build nav → namespace mapping before clearing, so that + // ensureNavValUpToDate can update stale namespace owner_types + // when navs are re-resolved in the main shard. + memset(sema->zcu->nav_ns_remap, 0xFF, sizeof(sema->zcu->nav_ns_remap)); + for (uint32_t n = 0; n < sema->ip->nav_count && n < 4096; n++) { + const Nav* nav_ptr = ipGetNav(sema->ip, n); + if (nav_ptr->resolved_type != IP_INDEX_NONE + && nav_ptr->resolved_type >= sema->ip->skip_dedup_start + && nav_ptr->resolved_type < sema->ip->skip_dedup_end) { + for (uint32_t nsi = 0; nsi < sema->zcu->num_namespaces; nsi++) { + if (sema->zcu->namespaces[nsi].owner_type + == nav_ptr->resolved_type) { + sema->zcu->nav_ns_remap[n] = nsi; + break; + } + } + } + } // Clear nav resolved_type for ALL navs resolved during preamble. // Simulates Zig's per-shard isolation: main shard starts fresh. for (uint32_t n = 0; n < sema->ip->nav_count; n++) { diff --git a/stage0/zcu_per_thread.h b/stage0/zcu_per_thread.h @@ -75,6 +75,10 @@ uint32_t findNavInNamespace( uint32_t findNamespaceForType( const struct Sema* sema, InternPoolIndex type_ip); +// Set nav->resolved_type and update stale namespace owner_type. +void setNavResolvedType( + struct Sema* sema, uint32_t nav_idx, InternPoolIndex type_ip); + // Find a nav whose resolved_type == ip_idx. Returns UINT32_MAX if not found. uint32_t findNavForIPIndex(struct Sema* sema, InternPoolIndex ip_idx);