zig

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

commit edf1ec738ef0b6601a4ad55fb58e8a72fe5d27b4 (tree)
parent 688da55f70942d0c71ddaf467096ec70ae922402
Author: Motiejus <motiejus@jakstys.lt>
Date:   Fri, 27 Feb 2026 15:28:45 +0000

sema: evaluate FeatureSetFns(Feature) generic call

Add resolveAnonStructDeclFromZir for anonymous struct types returned from
comptime generic function calls. In triggerArchModuleCascade, after
resolving FeatureSetFns and Feature, evaluate the generic call by:
1. Finding the struct_decl in FeatureSetFns's function body ZIR
2. Creating the anonymous struct type and scanning its namespace
3. Creating a memoized_call entry
4. Resolving featureSet with correct param types ([]const Feature)
   and return type (Feature.Set)

Closes 8 IP entries ([699-706]) in the neghf2 gap.

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

Diffstat:
Mstage0/sema.c | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 193 insertions(+), 10 deletions(-)

diff --git a/stage0/sema.c b/stage0/sema.c @@ -4281,6 +4281,72 @@ static InternPoolIndex resolveStructDeclFromZir( return struct_ip; } +// --- resolveAnonStructDeclFromZir --- +// Like resolveStructDeclFromZir but for anonymous struct types returned from +// comptime generic function calls (e.g. FeatureSetFns(Feature)). +// Does NOT create ptr_nav for the struct (anonymous — no owning nav). +// Takes file_idx directly instead of deriving it from a nav. +// Returns the IP index of the struct type, or IP_INDEX_NONE on failure. +static InternPoolIndex resolveAnonStructDeclFromZir( + const Zir* zir, uint32_t struct_inst, uint32_t file_idx) { + if (zir->inst_tags[struct_inst] != ZIR_INST_EXTENDED) + return IP_INDEX_NONE; + if (zir->inst_datas[struct_inst].extended.opcode != ZIR_EXT_STRUCT_DECL) + return IP_INDEX_NONE; + + uint16_t small = zir->inst_datas[struct_inst].extended.small; + uint32_t operand = zir->inst_datas[struct_inst].extended.operand; + + // Skip 6 u32 header (fields_hash×4, src_line, src_node). + uint32_t extra_index = operand + 6; + + // Parse StructDecl.Small flags. + bool has_captures_len = (small & (1 << 0)) != 0; + bool has_fields_len = (small & (1 << 1)) != 0; + bool has_decls_len = (small & (1 << 2)) != 0; + + uint32_t captures_len = 0; + if (has_captures_len) { + captures_len = zir->extra[extra_index++]; + } + if (has_fields_len) { + extra_index++; // skip fields_len + } + uint32_t decls_len = 0; + if (has_decls_len) { + decls_len = zir->extra[extra_index++]; + } + + extra_index += captures_len * 2; // skip captures + + // Skip backing_int if present (bit 3 of small). + bool has_backing_int = (small & (1 << 3)) != 0; + if (has_backing_int) { + uint32_t backing_int_body_len = zir->extra[extra_index++]; + if (backing_int_body_len == 0) { + extra_index++; // skip backing_int_ref + } else { + extra_index += backing_int_body_len; // skip body instructions + } + } + + // Create type_struct IP entry. + InternPoolKey key; + memset(&key, 0, sizeof(key)); + key.tag = IP_KEY_STRUCT_TYPE; + key.data.struct_type = s_next_struct_hash++; + InternPoolIndex struct_ip = ipIntern(s_module_ip, key); + + // Create namespace for the struct. + uint32_t ns_idx = createNamespace(struct_ip, file_idx); + + // Scan namespace declarations. + const uint32_t* decl_insts = &zir->extra[extra_index]; + scanNamespaceC(ns_idx, decl_insts, decls_len, zir); + + return struct_ip; +} + // --- findNamespaceForType --- // Find the namespace owned by a given type IP index. static uint32_t findNamespaceForType(InternPoolIndex type_ip) { @@ -5702,6 +5768,8 @@ static void triggerArchModuleCascade( // $692: "CpuFeature" (private const = std.Target.Cpu.Feature). uint32_t cpufeat = findNavInNamespace(arch_ns, "CpuFeature"); + uint32_t fsf_nav = UINT32_MAX; + uint32_t cpufeat_ns = UINT32_MAX; if (cpufeat != UINT32_MAX) { (void)resolveNavRef(cpufeat); @@ -5709,10 +5777,9 @@ static void triggerArchModuleCascade( // (Not in Feature.Set — FeatureSetFns is at Feature's level.) const Nav* cf = ipGetNav(cpufeat); if (cf->resolved_type != IP_INDEX_NONE) { - uint32_t feat_ns = findNamespaceForType(cf->resolved_type); - if (feat_ns != UINT32_MAX) { - uint32_t fsf_nav - = findNavInNamespace(feat_ns, "FeatureSetFns"); + cpufeat_ns = findNamespaceForType(cf->resolved_type); + if (cpufeat_ns != UINT32_MAX) { + fsf_nav = findNavInNamespace(cpufeat_ns, "FeatureSetFns"); if (fsf_nav != UINT32_MAX) (void)resolveNavRef(fsf_nav); } @@ -5724,12 +5791,128 @@ static void triggerArchModuleCascade( if (feature != UINT32_MAX) (void)resolveNavRef(feature); - // NOTE: featureSet resolution requires FeatureSetFns(Feature) generic - // call evaluation, which the C sema can't do yet. The Zig compiler - // creates entries $699-$706 (type_struct, memoized_call, type_function, - // func_decl, type_pointer, ptr_nav) for this call. Attempting to resolve - // featureSet without proper generic function evaluation creates wrong - // side-effect entries, so skip it for now. + // $699-$706: Evaluate FeatureSetFns(Feature) generic call. + // Creates type_struct (the anonymous return struct), memoized_call, + // then resolves featureSet from the struct's namespace creating + // type_pointer, type_slice, type_function, func_decl, ptr entries. + // Ported from Sema.zig analyzeCall for comptime generic functions + // that return struct types. + if (fsf_nav != UINT32_MAX && feature != UINT32_MAX) { + const Nav* fsf = ipGetNav(fsf_nav); + InternPoolIndex fsf_func_decl = fsf->resolved_type; + InternPoolIndex feature_type = ipGetNav(feature)->resolved_type; + + if (fsf_func_decl != IP_INDEX_NONE && feature_type != IP_INDEX_NONE) { + // Get FeatureSetFns's ZIR to find the inner struct_decl. + uint32_t fsf_file = s_namespaces[fsf->namespace_idx].file_idx; + const Zir* fsf_zir = &s_loaded_modules[fsf_file].zir; + + // Find the func instruction in FeatureSetFns's value body. + const uint32_t* vb = NULL; + uint32_t vb_len = 0; + getValueBodyFromZir(fsf_zir, fsf->zir_index, &vb, &vb_len); + + uint32_t func_inst = UINT32_MAX; + for (uint32_t i = 0; i < vb_len; i++) { + if (vb[i] < fsf_zir->inst_len) { + ZirInstTag t = fsf_zir->inst_tags[vb[i]]; + if (t == ZIR_INST_FUNC || t == ZIR_INST_FUNC_FANCY) { + func_inst = vb[i]; + break; + } + } + } + + if (func_inst != UINT32_MAX) { + // Parse func to get function body. + Sema tmp; + semaInit(&tmp, s_module_ip, *fsf_zir); + FuncZirInfo fi = parseFuncZir(&tmp, func_inst); + semaDeinit(&tmp); + + // Search function body for struct_decl. + const uint32_t* fb = &fsf_zir->extra[fi.extra_index]; + uint32_t struct_inst = UINT32_MAX; + for (uint32_t i = 0; i < fi.body_len; i++) { + uint32_t bi = fb[i]; + if (bi < fsf_zir->inst_len + && fsf_zir->inst_tags[bi] == ZIR_INST_EXTENDED + && fsf_zir->inst_datas[bi].extended.opcode + == ZIR_EXT_STRUCT_DECL) { + struct_inst = bi; + break; + } + } + + if (struct_inst != UINT32_MAX) { + // $699: type_struct — the anonymous struct returned + // by FeatureSetFns(Feature). + InternPoolIndex anon_struct = resolveAnonStructDeclFromZir( + fsf_zir, struct_inst, fsf_file); + + if (anon_struct != IP_INDEX_NONE) { + // $700: memoized_call — cache the generic call + // result. + InternPoolKey mck; + memset(&mck, 0, sizeof(mck)); + mck.tag = IP_KEY_MEMOIZED_CALL; + mck.data.memoized_call.func = fsf_func_decl; + mck.data.memoized_call.result = anon_struct; + (void)ipIntern(s_module_ip, mck); + + // $701-$706: Resolve featureSet from the + // struct namespace. The param type []const F + // resolves to []const Feature via capture. + uint32_t anon_ns = findNamespaceForType(anon_struct); + if (anon_ns != UINT32_MAX) { + uint32_t fs_nav + = findNavInNamespace(anon_ns, "featureSet"); + if (fs_nav != UINT32_MAX) { + // $701: *const Feature (param child + // ptr type for []const Feature). + (void)internPtrConst(feature_type); + // $702: []const Feature (slice type). + InternPoolKey sk; + memset(&sk, 0, sizeof(sk)); + sk.tag = IP_KEY_PTR_TYPE; + sk.data.ptr_type.child = feature_type; + sk.data.ptr_type.sentinel = IP_INDEX_NONE; + sk.data.ptr_type.flags = PTR_FLAGS_SIZE_SLICE + | PTR_FLAGS_IS_CONST; + sk.data.ptr_type.packed_offset = 0; + (void)ipIntern(s_module_ip, sk); + + // Get Set type for return type. + InternPoolIndex set_type = IP_INDEX_VOID_TYPE; + if (cpufeat_ns != UINT32_MAX) { + uint32_t set_nav = findNavInNamespace( + cpufeat_ns, "Set"); + if (set_nav != UINT32_MAX) { + InternPoolIndex st + = ipGetNav(set_nav)->resolved_type; + if (st != IP_INDEX_NONE) + set_type = st; + } + } + // $703: func_type for featureSet. + InternPoolIndex ft + = internFuncType(set_type, 1, 0, false); + // $704: func_decl for featureSet. + InternPoolIndex fd + = internFuncDecl(fs_nav, ft); + Nav* fsn = ipGetNav(fs_nav); + fsn->resolved_type = fd; + // $705: ptr_type(*const fn_type). + InternPoolIndex pt = internPtrConst(ft); + // $706: ptr_nav for featureSet. + (void)internNavPtr(pt, fs_nav); + } + } + } + } + } + } + } (void)target_file_idx; }