zig

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

commit 58eb5f6f3c3e7a286ac85bf65c3d9472624ae2f3 (tree)
parent e83257bed5f286117a8cbaf4d2efe491e0bb2a1b
Author: Motiejus <motiejus@jakstys.lt>
Date:   Fri, 27 Feb 2026 00:22:53 +0000

sema: remove hardcoded IP entries from resolveUnionFullyC

Remove hardcoded ?u64 / opt_null(?u64) creation and inline
resolveStructFieldsRecursive / resolveStructFieldInitsC from
resolveUnionFullyC. These created IP entries at wrong positions,
causing ordering divergences with the Zig compiler.

Struct field resolution is now deferred to resolveBuiltinDeclTypes
which calls resolveStructFullyC for each nested type in the correct
order via resolveNestedTypeDecl.

Also remove the now-dead resolveStructFieldsRecursive function.

IP tag comparison: first mismatch moves from position 133 (index 257)
to position 317 (index 441), matching 455/561 entries (up from 423).

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

Diffstat:
Mstage0/sema.c | 163++++++-------------------------------------------------------------------------
1 file changed, 12 insertions(+), 151 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -3515,89 +3515,6 @@ static void resolveStructFieldTypesC(const Zir* zir, uint32_t struct_inst, } } -// --- resolveStructFieldsRecursive --- -// Recursively resolve a struct type: resolve its field types, then -// for any new struct types created during field resolution, recursively -// resolve them too. Matches Sema.zig resolveStructFully which calls -// field_ty.resolveFully(pt) on each struct field type. -static void resolveStructFieldsRecursive(uint32_t nav_idx, - const Zir* unused_zir, uint32_t unused_file, uint32_t depth) { - (void)unused_zir; - (void)unused_file; - if (depth > 16) - return; - const Nav* nav = ipGetNav(nav_idx); - if (nav->resolved_type == IP_INDEX_NONE) - return; - if (nav->resolved_type >= s_module_ip->items_len) - return; - if (s_module_ip->items[nav->resolved_type].tag != IP_KEY_STRUCT_TYPE) - return; - - // Use the struct's OWN file ZIR, not the caller's, because tracked - // structs may be in different files (e.g. SemanticVersion.Range is - // in SemanticVersion.zig, not Target.zig). - uint32_t struct_ns = findNamespaceForType(nav->resolved_type); - if (struct_ns == UINT32_MAX) - return; - uint32_t file_idx = s_namespaces[struct_ns].file_idx; - if (!s_loaded_modules[file_idx].has_zir) - return; - const Zir* zir = &s_loaded_modules[file_idx].zir; - - // Find the struct_decl ZIR instruction. - const uint32_t* vbody = NULL; - uint32_t vbody_len = 0; - getValueBodyFromZir(zir, nav->zir_index, &vbody, &vbody_len); - uint32_t sd_inst = UINT32_MAX; - for (uint32_t vi = 0; vi < vbody_len; vi++) { - uint32_t vinst = vbody[vi]; - if (vinst < zir->inst_len && zir->inst_tags[vinst] == ZIR_INST_EXTENDED - && zir->inst_datas[vinst].extended.opcode == ZIR_EXT_STRUCT_DECL) { - sd_inst = vinst; - break; - } - } - if (sd_inst == UINT32_MAX) - return; - - // Record IP position before resolving field types. - uint32_t ip_before = s_module_ip->items_len; - - // Resolve field types (creates ptr_type, opt_type, and triggers - // ensureNavValUpToDate for referenced inner types). - resolveStructFieldTypesC(zir, sd_inst, struct_ns, file_idx); - - // Scan newly created IP entries for struct types, and recursively - // resolve them. The Zig compiler does this via resolveFully on - // each field type. - for (uint32_t i = ip_before; i < s_module_ip->items_len; i++) { - if (s_module_ip->items[i].tag != IP_KEY_STRUCT_TYPE) - continue; - // Find the nav that owns this struct type. - for (uint32_t nsi = 0; nsi < s_num_namespaces; nsi++) { - const SemaNamespace* ns = &s_namespaces[nsi]; - for (uint32_t k = 0; k < ns->pub_nav_count; k++) { - if (ipGetNav(ns->pub_navs[k])->resolved_type - == (InternPoolIndex)i) { - resolveStructFieldsRecursive( - ns->pub_navs[k], NULL, 0, depth + 1); - goto next_entry; - } - } - for (uint32_t k = 0; k < ns->priv_nav_count; k++) { - if (ipGetNav(ns->priv_navs[k])->resolved_type - == (InternPoolIndex)i) { - resolveStructFieldsRecursive( - ns->priv_navs[k], NULL, 0, depth + 1); - goto next_entry; - } - } - } - next_entry:; - } -} - // --- resolveStructFieldInitsC --- // Evaluate struct field default values from ZIR init bodies. // For each field with an init body, reads the break_inline operand, @@ -4118,10 +4035,13 @@ static void resolveUnionFullyC(uint32_t nav_idx) { ZirInstRef type_ref = zir->extra[cursor++]; InternPoolIndex resolved = resolveZirTypeRef(zir, type_ref, ns_idx, file_idx); - // Track struct field types for Phase 3 deep resolution. - // Search ALL namespaces since field types may be in parent - // or sibling namespaces (e.g. Os.HurdVersionRange for - // Os.VersionRange union). + // Track struct-typed fields for deferred resolution in + // Phase 3. The Zig compiler creates all struct_type + + // ptr_nav pairs consecutively during union field + // iteration, then resolves their fields later. We must + // NOT call resolveStructFullyC here — that would create + // compound type entries (opt_type, ptr_type, slice) + // interleaved with the struct entries. if (resolved != IP_INDEX_NONE && num_resolved_structs < 64 && s_module_ip->items[resolved].tag == IP_KEY_STRUCT_TYPE) { @@ -4173,70 +4093,11 @@ static void resolveUnionFullyC(uint32_t nav_idx) { (void)ipIntern(s_module_ip, ek); } - // Create ?u64 (from CommonOptions.incoming_stack_alignment). - InternPoolIndex opt_u64_ty; - { - InternPoolKey ok; - memset(&ok, 0, sizeof(ok)); - ok.tag = IP_KEY_OPT_TYPE; - ok.data.opt_type = IP_INDEX_U64_TYPE; - opt_u64_ty = ipIntern(s_module_ip, ok); - } - - // Phase 3: Recursively resolve struct field types of inner structs. - for (uint32_t r = 0; r < num_resolved_structs; r++) { - resolveStructFieldsRecursive( - resolved_struct_navs[r], zir, file_idx, 0); - } - - // Create opt_null(?u64) for default field values. - { - InternPoolKey onk; - memset(&onk, 0, sizeof(onk)); - onk.tag = IP_KEY_OPT; - onk.data.opt = opt_u64_ty; - (void)ipIntern(s_module_ip, onk); - } - - // Resolve struct field defaults (inits) for inner structs. - { - const SemaNamespace* uns = &s_namespaces[ns_idx]; - for (uint32_t i = 0; i < uns->pub_nav_count; i++) { - const Nav* subnav = ipGetNav(uns->pub_navs[i]); - if (subnav->resolved_type == IP_INDEX_NONE) - continue; - if (s_module_ip->items[subnav->resolved_type].tag - != IP_KEY_STRUCT_TYPE) - continue; - { - const uint32_t* svbody = NULL; - uint32_t svbody_len = 0; - getValueBodyFromZir( - zir, subnav->zir_index, &svbody, &svbody_len); - uint32_t sd_inst = UINT32_MAX; - for (uint32_t vi = 0; vi < svbody_len; vi++) { - uint32_t vinst = svbody[vi]; - if (vinst < zir->inst_len - && zir->inst_tags[vinst] == ZIR_INST_EXTENDED - && zir->inst_datas[vinst].extended.opcode - == ZIR_EXT_STRUCT_DECL) { - sd_inst = vinst; - break; - } - } - if (sd_inst != UINT32_MAX) { - for (uint32_t nsi = 0; nsi < s_num_namespaces; nsi++) { - if (s_namespaces[nsi].owner_type - == subnav->resolved_type) { - resolveStructFieldInitsC( - zir, sd_inst, nsi, file_idx); - break; - } - } - } - } - } - } + // Phase 3: Struct field resolution is deferred to resolveBuiltinDeclTypes + // which calls resolveStructFullyC for each nested type in the correct + // order, matching the Zig compiler's processing sequence. + (void)resolved_struct_navs; + (void)num_resolved_structs; } // --- resolveUnionDeclFromZir ---