zig

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

commit 2c720fed4f42aa21c4b2f5b7e64d6384e564dd93 (tree)
parent 95e7c8c5eb85ca1c6468e6c903eabf3ab295dd1b
Author: Motiejus <motiejus@jakstys.lt>
Date:   Sat, 28 Feb 2026 14:20:08 +0000

sema: remove all type function cheats, replace with honest comptime eval

Remove all string-dispatched type function cheats from sema.c. The
evalComptimeTypeCall/comptimeFieldCall infrastructure evaluates function
bodies honestly via comptime ZIR analysis — all cheats were dead fallback
code that was never reached.

Removed cheats:
- strcmp dispatches: Int, Log2Int, PowerOfTwoSignificandZ, F16T, Complex, toFloat
- Magic struct IDs: 0xF80F80 (F80), 0xC0A100 (Complex)
- Hardcoded inst 755 memoization for floatFractionalBits
- ensureF80StructRegistered synthetic struct function
- Dead block pre-emission infrastructure (string-matched block creation,
  seen_call_names/nargs, type_fn_to_skip/created, skip_first_int)
- CT_TAG marker system (6 tags, ctTrack/ctLookup, magic marker constants
  0x7E100000/0x71040000/0x11140000, 4 Sema struct fields)
- 6 now-unused helper functions (cascading dead code)

Infrastructure changes:
- IP_KEY_UNION_VALUE extended from {tag} to {ty, tag, val} matching upstream
- evalComptimeTypeCall: added callee_source_dir for cross-module calls
- zirReifyComptime/zirTypeInfoComptime: simplified to return VOID (honest
  eval handles these through function body evaluation)
- Type-returning function detection: all go through honest comptime eval
  path (no more returns_type string-match gate)

Added sema_tests: type_identity_fn.zig, reify_int.zig

All 193 corpus tests + 5 sema tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
Mstage0/corpus.zig | 4+++-
Mstage0/intern_pool.c | 8++++++--
Mstage0/intern_pool.h | 6+++++-
Mstage0/sema.c | 1557+++++++++----------------------------------------------------------------------
Mstage0/sema.h | 32--------------------------------
Astage0/sema_tests/reify_int.zig | 4++++
Astage0/sema_tests/type_identity_fn.zig | 6++++++
7 files changed, 195 insertions(+), 1422 deletions(-)

diff --git a/stage0/corpus.zig b/stage0/corpus.zig @@ -202,12 +202,14 @@ pub const files = [_][]const u8{ "lib/std/math/expo2.zig", // 995 }; -pub const num_sema_passing: usize = 3; +pub const num_sema_passing: usize = 5; pub const sema_unit_tests = [_][]const u8{ "stage0/sema_tests/empty.zig", "stage0/sema_tests/const_decl.zig", "stage0/sema_tests/empty_void_function.zig", + "stage0/sema_tests/type_identity_fn.zig", + "stage0/sema_tests/reify_int.zig", "stage0/sema_tests/return_integer.zig", "stage0/sema_tests/identity_function.zig", "stage0/sema_tests/add_two_args.zig", diff --git a/stage0/intern_pool.c b/stage0/intern_pool.c @@ -161,7 +161,9 @@ static uint32_t ipHashKey(const InternPoolKey* key) { h = ipHashCombine(h, key->data.aggregate); break; case IP_KEY_UNION_VALUE: - h = ipHashCombine(h, key->data.union_value); + h = ipHashCombine(h, key->data.union_val.ty); + h = ipHashCombine(h, key->data.union_val.tag); + h = ipHashCombine(h, key->data.union_val.val); break; default: /* For other tag types, just use the tag hash. */ @@ -286,7 +288,9 @@ static bool ipKeysEqual(const InternPoolKey* a, const InternPoolKey* b) { case IP_KEY_AGGREGATE: return a->data.aggregate == b->data.aggregate; case IP_KEY_UNION_VALUE: - return a->data.union_value == b->data.union_value; + return a->data.union_val.ty == b->data.union_val.ty + && a->data.union_val.tag == b->data.union_val.tag + && a->data.union_val.val == b->data.union_val.val; default: /* Fallback: memcmp the entire data union. */ return memcmp(&a->data, &b->data, sizeof(a->data)) == 0; diff --git a/stage0/intern_pool.h b/stage0/intern_pool.h @@ -365,7 +365,11 @@ typedef struct { InternPoolIndex slice; InternPoolIndex opt; InternPoolIndex aggregate; - InternPoolIndex union_value; + struct { + InternPoolIndex ty; // union type + InternPoolIndex tag; // enum_tag for active field + InternPoolIndex val; // payload value + } union_val; struct { InternPoolIndex func; // func_decl IP index InternPoolIndex result; // result value IP index diff --git a/stage0/sema.c b/stage0/sema.c @@ -204,45 +204,11 @@ static void instMapPut(InstMap* map, uint32_t zir_inst, AirInstRef ref) { map->items[zir_inst - map->start] = ref; } -// --- Comptime tracker helpers --- -// Track comptime type-info values for cross-module inline evaluation. -// tag: 0=none, 1=type_info(type), 2=float_info(bits), -// 3=int_info(signedness<<16|bits), 4=reify_int(int_info_ip), -// 5=target_ptr(ptr_nav IP), 6=struct_field_ptr(base_ip) -#define CT_TAG_NONE 0 -#define CT_TAG_TYPE_INFO 1 -#define CT_TAG_FLOAT_INFO 2 -#define CT_TAG_INT_INFO 3 -#define CT_TAG_REIFY_INT 4 -#define CT_TAG_TARGET_PTR 5 -#define CT_TAG_STRUCT_FIELD_PTR 6 - // Helper to read a bool through a pointer, preventing cppcheck from // assuming the value is unchanged across function calls that receive // the pointer indirectly (via a struct field). static bool readBool(const bool* p) { return *p; } -static void ctTrack( - Sema* sema, InternPoolIndex ip_idx, uint8_t tag_val, uint32_t val) { - if (sema->ct_len < 16) { - sema->ct_keys[sema->ct_len] = ip_idx; - sema->ct_tags[sema->ct_len] = tag_val; - sema->ct_vals[sema->ct_len] = val; - sema->ct_len++; - } -} - -static uint8_t ctLookup( - const Sema* sema, InternPoolIndex ip_idx, uint32_t* val_out) { - for (uint32_t i = 0; i < sema->ct_len; i++) { - if (sema->ct_keys[i] == ip_idx) { - *val_out = sema->ct_vals[i]; - return sema->ct_tags[i]; - } - } - return CT_TAG_NONE; -} - // --- resolveInst --- // Ported from src/Sema.zig resolveInst. // Maps a ZIR Inst.Ref to an AIR Inst.Ref. @@ -3709,168 +3675,6 @@ static void resolveStructFieldTypesC(const Zir* zir, uint32_t struct_inst, } // --- findStructFieldIndexFromZir --- -// Parse a struct_decl ZIR instruction to find a field by name. -// Returns the 0-based field index, or UINT32_MAX if not found. -// Ported from the field iteration in resolveStructFieldTypesC. -static uint32_t findStructFieldIndexFromZir( - const Zir* zir, uint32_t struct_inst, const char* field_name) { - if (zir->inst_tags[struct_inst] != ZIR_INST_EXTENDED) - return UINT32_MAX; - if (zir->inst_datas[struct_inst].extended.opcode != ZIR_EXT_STRUCT_DECL) - return UINT32_MAX; - - uint16_t small = zir->inst_datas[struct_inst].extended.small; - uint32_t operand = zir->inst_datas[struct_inst].extended.operand; - - uint32_t ei - = operand + 6; // skip header (fields_hash×4, src_line, src_node) - - bool has_captures = (small & (1 << 0)) != 0; - bool has_fields = (small & (1 << 1)) != 0; - bool has_decls = (small & (1 << 2)) != 0; - bool has_backing_int = (small & (1 << 3)) != 0; - - uint32_t captures_len = 0; - uint32_t fields_len = 0; - uint32_t decls_len = 0; - if (has_captures) - captures_len = zir->extra[ei++]; - if (has_fields) - fields_len = zir->extra[ei++]; - if (has_decls) - decls_len = zir->extra[ei++]; - - if (fields_len == 0) - return UINT32_MAX; - - ei += captures_len * 2; - if (has_backing_int) { - uint32_t bi_body = zir->extra[ei++]; - ei += (bi_body == 0) ? 1 : bi_body; - } - ei += decls_len; - - // Parse field bit bags. - uint32_t bags_start = ei; - uint32_t bags_count = (fields_len + 7) / 8; - ei += bags_count; - - bool any_default_inits = (small & (1 << 10)) != 0; - - // Iterate fields to find the matching name. - for (uint32_t fi = 0; fi < fields_len; fi++) { - uint32_t bag_i = fi / 8; - uint32_t bit_off = (fi % 8) * 4; - uint32_t bits = (zir->extra[bags_start + bag_i] >> bit_off) & 0xf; - bool f_has_align = (bits & 1) != 0; - bool f_has_init = ((bits >> 1) & 1) != 0; - bool f_has_type_body = ((bits >> 3) & 1) != 0; - - uint32_t name_idx = zir->extra[ei++]; - const char* fname = (const char*)&zir->string_bytes[name_idx]; - - uint32_t type_body_len = 0; - if (f_has_type_body) - type_body_len = zir->extra[ei]; - ei++; // skip field type ref or type body len - if (f_has_align) - ei++; - if (f_has_init && any_default_inits) - ei++; - - if (strcmp(fname, field_name) == 0) - return fi; - - // Skip body instructions for this field. - (void)type_body_len; // used indirectly via resolveStructFieldType - } - return UINT32_MAX; -} - -// --- findStructDeclInst --- -// Find the ZIR struct_decl instruction for a struct type. -// For file root structs, returns 0 (the root instruction). -// For nested structs, finds the nav whose resolved_type matches and -// parses its declaration's value body to find the struct_decl. -// Sets *out_zir to the ZIR containing the declaration. -// Returns UINT32_MAX on failure. -static uint32_t findStructDeclInst( - InternPoolIndex struct_type, const Zir** out_zir) { - uint32_t ns_idx = findNamespaceForType(struct_type); - if (ns_idx == UINT32_MAX) - return UINT32_MAX; - uint32_t file_idx = s_namespaces[ns_idx].file_idx; - if (file_idx >= s_num_loaded_modules - || !s_loaded_modules[file_idx].has_zir) - return UINT32_MAX; - const Zir* zir = &s_loaded_modules[file_idx].zir; - *out_zir = zir; - if (zir->inst_len == 0) - return UINT32_MAX; - - // File root struct: instruction 0. - if (s_file_root_type[file_idx] == struct_type) - return 0; - - // Nested struct: find the nav with this resolved_type and parse - // its declaration to locate the struct_decl instruction. - for (uint32_t ni = 0; ni < s_num_namespaces; ni++) { - if (s_namespaces[ni].file_idx != file_idx) - continue; - for (uint32_t pi = 0; pi < s_namespaces[ni].pub_nav_count; pi++) { - uint32_t nv = s_namespaces[ni].pub_navs[pi]; - const Nav* n = ipGetNav(nv); - if (n->resolved_type != struct_type) - continue; - const uint32_t* vb = NULL; - uint32_t vb_len = 0; - getValueBodyFromZir(zir, n->zir_index, &vb, &vb_len); - for (uint32_t vi = 0; vi < vb_len; vi++) { - if (zir->inst_tags[vb[vi]] != ZIR_INST_EXTENDED) - continue; - if (zir->inst_datas[vb[vi]].extended.opcode - == ZIR_EXT_STRUCT_DECL) - return vb[vi]; - } - } - } - return UINT32_MAX; -} - -// --- findStructFieldIndexByType --- -// Find a field index by name in a struct type, looking up through -// the namespace → file → ZIR. Handles both root and nested structs. -// Returns UINT32_MAX if not found. -static uint32_t findStructFieldIndexByType( - InternPoolIndex struct_type, const char* field_name) { - const Zir* zir = NULL; - uint32_t inst = findStructDeclInst(struct_type, &zir); - if (inst == UINT32_MAX) - return UINT32_MAX; - return findStructFieldIndexFromZir(zir, inst, field_name); -} - -// Forward declaration (defined after resolveStructFieldType). -static InternPoolIndex resolveStructFieldType(const Zir* zir, - uint32_t struct_inst, uint32_t target_field, uint32_t struct_ns, - uint32_t file_idx); - -// --- resolveFieldTypeByIP --- -// Resolve the type of a struct field given the struct type and field index. -// Returns IP_INDEX_NONE on failure. -static InternPoolIndex resolveFieldTypeByIP( - InternPoolIndex struct_type, uint32_t field_idx) { - const Zir* zir = NULL; - uint32_t inst = findStructDeclInst(struct_type, &zir); - if (inst == UINT32_MAX) - return IP_INDEX_NONE; - uint32_t ns_idx = findNamespaceForType(struct_type); - if (ns_idx == UINT32_MAX) - return IP_INDEX_NONE; - uint32_t file_idx = s_namespaces[ns_idx].file_idx; - return resolveStructFieldType(zir, inst, field_idx, ns_idx, file_idx); -} - // --- findEnumDeclForNav --- // Find the ZIR enum_decl instruction for an enum type nav. // Parses the nav's declaration value body to find the EXTENDED/ENUM_DECL. @@ -3899,109 +3703,6 @@ static uint32_t findEnumDeclForNav(uint32_t nav_idx, const Zir** out_zir) { return UINT32_MAX; } -// --- resolveStructFieldType --- -// Resolve the type of a specific struct field from ZIR. -// Returns the IP index of the field's type, or IP_INDEX_NONE on failure. -// Ported from resolveStructFieldTypesC (single-field version). -static InternPoolIndex resolveStructFieldType(const Zir* zir, - uint32_t struct_inst, uint32_t target_field, uint32_t struct_ns, - 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; - - uint32_t ei = operand + 6; - bool has_captures = (small & (1 << 0)) != 0; - bool has_fields = (small & (1 << 1)) != 0; - bool has_decls = (small & (1 << 2)) != 0; - bool has_backing_int = (small & (1 << 3)) != 0; - - uint32_t captures_len = 0; - uint32_t fields_len = 0; - uint32_t decls_len = 0; - if (has_captures) - captures_len = zir->extra[ei++]; - if (has_fields) - fields_len = zir->extra[ei++]; - if (has_decls) - decls_len = zir->extra[ei++]; - - if (target_field >= fields_len) - return IP_INDEX_NONE; - - ei += captures_len * 2; - if (has_backing_int) { - uint32_t bi_body = zir->extra[ei++]; - ei += (bi_body == 0) ? 1 : bi_body; - } - ei += decls_len; - - uint32_t bags_start = ei; - uint32_t bags_count = (fields_len + 7) / 8; - ei += bags_count; - - bool any_default_inits = (small & (1 << 10)) != 0; - - // Skip fields until we reach target_field, recording body lengths. - uint32_t body_skip = 0; - for (uint32_t fi = 0; fi <= target_field; fi++) { - uint32_t bag_i = fi / 8; - uint32_t bit_off = (fi % 8) * 4; - uint32_t bits = (zir->extra[bags_start + bag_i] >> bit_off) & 0xf; - bool f_has_align = (bits & 1) != 0; - bool f_has_init = ((bits >> 1) & 1) != 0; - bool f_has_type_body = ((bits >> 3) & 1) != 0; - - ei++; // skip field_name - - uint32_t type_body_len = 0; - uint32_t type_ref = 0; - if (f_has_type_body) { - type_body_len = zir->extra[ei]; - } else { - type_ref = zir->extra[ei]; - } - ei++; - - uint32_t align_body_len = 0; - uint32_t init_body_len = 0; - if (f_has_align) { - align_body_len = zir->extra[ei++]; - } - if (f_has_init && any_default_inits) { - init_body_len = zir->extra[ei++]; - } - - if (fi == target_field) { - // This is the field we want. Skip the body data - // accumulated from previous fields, then resolve type. - ei += body_skip; - if (f_has_type_body && type_body_len > 0) { - uint32_t last_zi = zir->extra[ei + type_body_len - 1]; - if (last_zi < zir->inst_len - && zir->inst_tags[last_zi] == ZIR_INST_BREAK_INLINE) { - ZirInstRef op - = zir->inst_datas[last_zi].break_data.operand; - return resolveZirTypeRef(zir, op, struct_ns, file_idx); - } - } else if (!f_has_type_body && type_ref < ZIR_REF_START_INDEX) { - // Simple type reference (pre-interned). - return type_ref; - } else if (!f_has_type_body && type_ref >= ZIR_REF_START_INDEX) { - return resolveZirTypeRef(zir, type_ref, struct_ns, file_idx); - } - return IP_INDEX_NONE; - } - - body_skip += type_body_len + align_body_len + init_body_len; - } - return IP_INDEX_NONE; -} - // --- resolveStructFieldInitsC --- // Evaluate struct field default values from ZIR init bodies. // For each field with an init body, reads the break_inline operand, @@ -6657,15 +6358,7 @@ static AirInstRef comptimeFieldCall(Sema* sema, SemaBlock* block, // For field_call, the first param is the object (self). // Ported from Sema.zig analyzeCall line 7773-7776. if (param_count > 0) { - // Transfer CT tracking from the outer sema to the inner sema. - // This allows the inner function body to resolve field accesses - // on tracked comptime values (e.g. target pointer). - uint32_t ct_val; - uint8_t ct_tag = ctLookup(sema, AIR_REF_TO_IP(obj_ref), &ct_val); instMapPut(&fn_sema.inst_map, param_insts[0], obj_ref); - if (ct_tag != CT_TAG_NONE) { - ctTrack(&fn_sema, AIR_REF_TO_IP(obj_ref), ct_tag, ct_val); - } } // Evaluate the function body. @@ -6715,6 +6408,109 @@ static AirInstRef comptimeFieldCall(Sema* sema, SemaBlock* block, return result; } +// evalComptimeTypeCall: evaluate a comptime call to a type-returning +// inline function. The callee's ZIR must already be loaded in sema->code. +// Returns the computed type ref, or VOID_VALUE if evaluation fails. +// Ported from src/Sema.zig analyzeCall comptime path (lines 7639-7906). +static AirInstRef evalComptimeTypeCall(Sema* sema, uint32_t func_inst, + const FuncZirInfo* fi, const AirInstRef* arg_refs, uint32_t args_len, + const char* callee_source_dir) { + uint32_t payload_index + = sema->code.inst_datas[func_inst].pl_node.payload_index; + + // Get param body. + uint32_t param_block_inst + = sema->code.extra[payload_index + fi->param_block_pi]; + const uint32_t* param_body; + uint32_t param_body_len; + getParamBody(sema, param_block_inst, &param_body, &param_body_len); + + // Get function body. + const uint32_t* fn_body = &sema->code.extra[fi->extra_index]; + uint32_t fn_body_len = fi->body_len; + + // Save sema state. + InstMap saved_map = sema->inst_map; + uint32_t saved_cbi = sema->comptime_break_inst; + TypeIndex saved_fn_ret_ty = sema->fn_ret_ty; + const char* saved_source_dir = sema->source_dir; + + // For cross-module calls, set source_dir and populate decl table + // from the callee's ZIR so nested imports resolve correctly. + uint32_t saved_decl_names[64]; + uint32_t saved_decl_insts[64]; + uint32_t saved_num_decls = 0; + if (callee_source_dir) { + sema->source_dir = callee_source_dir; + saved_num_decls = sema->num_decls; + memcpy(saved_decl_names, sema->decl_names, + saved_num_decls * sizeof(uint32_t)); + memcpy(saved_decl_insts, sema->decl_insts, + saved_num_decls * sizeof(uint32_t)); + populateDeclTableFromZir(sema, &sema->code); + } + + // Set up fresh inst_map covering both params and body. + memset(&sema->inst_map, 0, sizeof(sema->inst_map)); + instMapEnsureSpaceForBody(&sema->inst_map, param_body, param_body_len); + instMapEnsureSpaceForBody(&sema->inst_map, fn_body, fn_body_len); + + // Map all params to arg values. + uint32_t arg_idx = 0; + for (uint32_t p = 0; p < param_body_len; p++) { + ZirInstTag ptag = sema->code.inst_tags[param_body[p]]; + if (ptag == ZIR_INST_PARAM || ptag == ZIR_INST_PARAM_COMPTIME + || ptag == ZIR_INST_PARAM_ANYTYPE + || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) { + if (arg_idx < args_len) + instMapPut(&sema->inst_map, param_body[p], arg_refs[arg_idx]); + arg_idx++; + } + } + + // Set return type to `type`. + sema->fn_ret_ty = IP_INDEX_TYPE_TYPE; + + // Create comptime block with inlining to capture return value. + // Ported from Sema.zig resolveInlineBody: the inline block captures + // return values via the inlining struct. + SemaBlock ct_block; + semaBlockInit(&ct_block, sema, NULL); + ct_block.is_comptime = true; + + SemaBlockInlining inlining; + memset(&inlining, 0, sizeof(inlining)); + ct_block.inlining = &inlining; + + sema->comptime_break_inst = UINT32_MAX; + (void)analyzeBodyInner(sema, &ct_block, fn_body, fn_body_len); + + AirInstRef result = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); + if (inlining.comptime_returned) { + result = inlining.comptime_result; + } else if (sema->comptime_break_inst != UINT32_MAX) { + ZirInstRef operand = sema->code.inst_datas[sema->comptime_break_inst] + .break_data.operand; + result = resolveInst(sema, operand); + } + + semaBlockDeinit(&ct_block); + free(sema->inst_map.items); + sema->inst_map = saved_map; + sema->comptime_break_inst = saved_cbi; + sema->fn_ret_ty = saved_fn_ret_ty; + sema->source_dir = saved_source_dir; + if (callee_source_dir) { + sema->num_decls = saved_num_decls; + memcpy(sema->decl_names, saved_decl_names, + saved_num_decls * sizeof(uint32_t)); + memcpy(sema->decl_insts, saved_decl_insts, + saved_num_decls * sizeof(uint32_t)); + } + + return result; +} + // zirCall: handle call/field_call ZIR instruction for inline functions. // Ported from src/Sema.zig zirCall / analyzeCall (inline-only subset). // For inline functions from the same module, analyzes the function body @@ -7341,212 +7137,7 @@ static AirInstRef zirCall( } if (func_inst == UINT32_MAX) { - // Handle non-inline method calls on runtime struct values. - // E.g., dst.toFloat() where dst is a local F80 variable. - // Ported from Sema.zig analyzeCall: for field calls on runtime - // struct values, emit load + call (non-inline). - if (is_field_call && callee_name_idx != 0 - && callee_ref >= ZIR_REF_START_INDEX) { - AirInstRef obj_air = resolveInst(sema, callee_ref); - if (!AIR_REF_IS_IP(obj_air)) { - TypeIndex obj_ty = semaTypeOf(sema, obj_air); - const char* mn - = (const char*)&sema->code.string_bytes[callee_name_idx]; - for (uint32_t si = 0; si < sema->num_struct_info; si++) { - if (sema->struct_info[si].ptr_type != obj_ty) - continue; - // Determine method return type. - InternPoolIndex method_ret = IP_INDEX_VOID_TYPE; - if (strcmp(mn, "toFloat") == 0) - method_ret = IP_INDEX_F80_TYPE; - if (method_ret == IP_INDEX_VOID_TYPE) - break; - - TypeIndex struct_ty = sema->struct_info[si].struct_type; - - // Load struct value from pointer. - AirInstData ld; - memset(&ld, 0, sizeof(ld)); - ld.ty_op.ty_ref = AIR_REF_FROM_IP(struct_ty); - ld.ty_op.operand = obj_air; - AirInstRef loaded = semaAddInst(block, AIR_INST_LOAD, ld); - - // Emit dbg_stmt before call (inst-1 is the - // preceding dbg_stmt in the ZIR). - zirDbgStmt(sema, block, inst - 1); - - // Intern function type: fn(struct) -> ret. - InternPoolKey ftk; - memset(&ftk, 0, sizeof(ftk)); - ftk.tag = IP_KEY_FUNC_TYPE; - ftk.data.func_type.return_type = method_ret; - ftk.data.func_type.param_count = 1; - InternPoolIndex fti = ipIntern(sema->ip, ftk); - - // Intern function value (unique per method). - InternPoolKey fvk; - memset(&fvk, 0, sizeof(fvk)); - fvk.tag = IP_KEY_FUNC; - fvk.data.func_decl.owner_nav = 0xF80F80; - fvk.data.func_decl.ty = fti; - InternPoolIndex fvi = ipIntern(sema->ip, fvk); - - // Emit CALL extra: {args_len=1, loaded}. - uint32_t ce = semaAddExtra(sema, 1); - semaAddExtra(sema, loaded); - - AirInstData cd; - memset(&cd, 0, sizeof(cd)); - cd.pl_op.operand = AIR_REF_FROM_IP(fvi); - cd.pl_op.payload = ce; - AirInstRef cr = semaAddInst(block, AIR_INST_CALL, cd); - - if (sema->num_calls < 16) { - sema->call_air_insts[sema->num_calls] - = AIR_REF_TO_INST(cr); - sema->call_ret_types[sema->num_calls] = method_ret; - sema->num_calls++; - } - return cr; - } - } - } - - // Can't resolve callee; return void (fallback). - // For known type-returning functions (Int, Log2Int, - // PowerOfTwoSignificandZ), create a dead BLOCK to match - // upstream's AIR layout where every inline call creates - // a block instruction, and compute the type result from args. - if (callee_name_idx != 0) { - const char* cn - = (const char*)&sema->code.string_bytes[callee_name_idx]; - if (strcmp(cn, "Int") == 0 || strcmp(cn, "Log2Int") == 0 - || strcmp(cn, "PowerOfTwoSignificandZ") == 0 - || strcmp(cn, "F16T") == 0) { - // Check if this function's dead block was pre-emitted - // during generic param type resolution. - // In comptime context (e.g. param type body evaluation), - // no dead blocks are created — matches upstream behavior - // where comptime resolveInlineBody doesn't emit runtime AIR. - bool skip_block = block->is_comptime; - // Check global seen-calls for cross-function dedup. - if (!skip_block) { - for (uint32_t k = 0; k < sema->num_seen_calls; k++) { - if (sema->seen_call_names[k] == callee_name_idx - && sema->seen_call_nargs[k] == args_len) { - skip_block = true; - break; - } - } - } - if (!skip_block) { - for (uint32_t k = 0; k < sema->num_type_fn_to_skip; k++) { - if (strcmp(sema->type_fn_to_skip[k], cn) == 0) { - sema->type_fn_to_skip[k] - = sema->type_fn_to_skip[--sema - ->num_type_fn_to_skip]; - skip_block = true; - break; - } - } - } - if (!skip_block) { - AirInstData dead; - memset(&dead, 0, sizeof(dead)); - (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, dead); - // Register in global seen-calls. - if (sema->num_seen_calls < 16) { - sema->seen_call_names[sema->num_seen_calls] - = callee_name_idx; - sema->seen_call_nargs[sema->num_seen_calls] = args_len; - sema->num_seen_calls++; - } - } - // Log2Int called from comptime sub-block with runtime - // parent: create 2 dead blocks (Log2Int + nested Int). - if (skip_block && block->is_comptime && block->parent - && !block->parent->is_comptime - && strcmp(cn, "Log2Int") == 0) { - AirInstData dead1; - memset(&dead1, 0, sizeof(dead1)); - (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, dead1); - AirInstData dead2; - memset(&dead2, 0, sizeof(dead2)); - (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, dead2); - } - // Track that this function has had its dead block created. - if (sema->num_type_fn_created < 16) - sema->type_fn_created[sema->num_type_fn_created++] = cn; - // Resolve args and compute the type result. - // Same logic as the returns_type handler below. - AirInstRef ur_arg_refs[16]; - uint32_t ur_prev_end = args_len; - for (uint32_t a = 0; a < args_len && a < 16; a++) { - uint32_t end_off = sema->code.extra[arg_data_start + a]; - uint32_t body_start = arg_data_start + ur_prev_end; - uint32_t body_len = end_off - ur_prev_end; - if (body_len > 1) { - (void)analyzeBodyInner(sema, block, - &sema->code.extra[body_start], body_len - 1); - } - if (body_len >= 1) { - uint32_t li - = sema->code.extra[body_start + body_len - 1]; - ZirInstRef op - = sema->code.inst_datas[li].break_data.operand; - ur_arg_refs[a] = resolveInst(sema, op); - } else { - ur_arg_refs[a] = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); - } - ur_prev_end = end_off; - } - InternPoolIndex ur_result = IP_INDEX_VOID_VALUE; - if (strcmp(cn, "Int") == 0 && args_len >= 2) { - uint8_t signedness = 0; - uint16_t bits_val = 0; - if (AIR_REF_IS_IP(ur_arg_refs[1])) { - InternPoolKey k = ipIndexToKey( - sema->ip, AIR_REF_TO_IP(ur_arg_refs[1])); - if (k.tag == IP_KEY_INT) - bits_val = (uint16_t)k.data.int_val.value_lo; - } - // Resolve signedness from enum_literal in arg 0. - { - uint32_t a0_end = sema->code.extra[arg_data_start + 0]; - uint32_t a0_start = arg_data_start + args_len; - uint32_t a0_body_end = arg_data_start + a0_end; - for (uint32_t ai = a0_start; ai < a0_body_end; ai++) { - uint32_t zi = sema->code.extra[ai]; - if (zi < sema->code.inst_len - && sema->code.inst_tags[zi] - == ZIR_INST_ENUM_LITERAL) { - uint32_t si - = sema->code.inst_datas[zi].str_tok.start; - const char* lit = (const char*)&sema->code - .string_bytes[si]; - if (strcmp(lit, "signed") == 0) - signedness = 1; - break; - } - } - } - if (bits_val > 0) { - InternPoolKey ik; - memset(&ik, 0, sizeof(ik)); - ik.tag = IP_KEY_INT_TYPE; - ik.data.int_type.bits = bits_val; - ik.data.int_type.signedness = signedness; - ur_result = ipIntern(sema->ip, ik); - } - } else if (strcmp(cn, "F16T") == 0) { - ur_result = IP_INDEX_U16_TYPE; - } - return AIR_REF_FROM_IP(ur_result); - } - } - // Non-type unresolved callees: don't create dead blocks here. - // They are handled by the inline expansion path when the callee - // is resolved via cross-module import. + // Can't resolve callee; return void. return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); } @@ -7560,38 +7151,54 @@ static AirInstRef zirCall( return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); } - // Skip comptime-only functions that return `type` — we can't - // evaluate @Type and similar builtins, so inlining would produce - // garbage. Return void (same as the unresolved fallback). - // Exception: known type-returning functions whose result can be - // computed from comptime arguments: std.meta.Int, Log2Int, - // PowerOfTwoSignificandZ. - bool returns_type = false; - const char* type_fn_name = NULL; + // Type-returning functions (return `type`): evaluate via comptime + // evaluation. Ported from src/Sema.zig analyzeCall comptime path. if (func_info.ret_ty_body_len == 1) { uint32_t ret_ref = sema->code.extra[func_info.ret_ty_ref_pos]; if (ret_ref == IP_INDEX_TYPE_TYPE) { - type_fn_name = callee_name_idx - ? (is_cross_module ? (const char*)&saved_code - .string_bytes[callee_name_idx] - : (const char*)&sema->code - .string_bytes[callee_name_idx]) - : NULL; - if (type_fn_name - && (strcmp(type_fn_name, "Int") == 0 - || strcmp(type_fn_name, "Log2Int") == 0 - || strcmp(type_fn_name, "PowerOfTwoSignificandZ") == 0 - || strcmp(type_fn_name, "F16T") == 0 - || strcmp(type_fn_name, "Complex") == 0)) { - returns_type = true; - } else { - if (is_cross_module) { + // Resolve args in the caller's ZIR context first. + AirInstRef ct_arg_refs[16]; + memset(ct_arg_refs, 0, sizeof(ct_arg_refs)); + assert(args_len <= 16); + { + Zir fn_zir = sema->code; + if (is_cross_module) sema->code = saved_code; - zirDeinit(&import_zir); - astDeinit(&import_ast); + uint32_t prev_end = args_len; + for (uint32_t a = 0; a < args_len; a++) { + uint32_t end_off = sema->code.extra[arg_data_start + a]; + uint32_t body_start = arg_data_start + prev_end; + uint32_t body_len = end_off - prev_end; + if (body_len > 1) { + (void)analyzeBodyInner(sema, block, + &sema->code.extra[body_start], body_len - 1); + } + if (body_len >= 1) { + uint32_t li + = sema->code.extra[body_start + body_len - 1]; + ZirInstRef op + = sema->code.inst_datas[li].break_data.operand; + ct_arg_refs[a] = resolveInst(sema, op); + } else { + ct_arg_refs[a] = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); + } + prev_end = end_off; } - return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); - } + if (is_cross_module) + sema->code = fn_zir; + } + AirInstRef honest_result = evalComptimeTypeCall(sema, func_inst, + &func_info, ct_arg_refs, args_len, + is_cross_module ? import_source_dir : NULL); + if (is_cross_module) { + sema->code = saved_code; + zirDeinit(&import_zir); + astDeinit(&import_ast); + } + if (AIR_REF_IS_IP(honest_result) + && AIR_REF_TO_IP(honest_result) != IP_INDEX_VOID_VALUE) + return honest_result; + return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); } } @@ -7646,144 +7253,6 @@ static AirInstRef zirCall( } } - // Ported from src/Sema.zig lines 7316-7353: generic param type - // evaluation. In the upstream, generic param type bodies are evaluated - // via resolveInlineBody in a comptime generic_block. For type bodies - // containing calls to inline type-returning functions (e.g. Int), - // this creates dead BLOCK instructions at the current AIR position - // (before arg and inline body processing). If the type function was - // already called earlier (memoized), no new block is created. - // We simulate this by pre-emitting dead blocks only for type functions - // that haven't been called yet, and skipping the corresponding - // returns_type dead block during inline body processing. - if (is_generic) { - for (uint32_t a = 0; a < args_len; a++) { - if (!is_ct_param[a] && has_generic_type[a]) { - // Find the param ZIR instruction for arg 'a'. - uint32_t early_pb_inst2 - = sema->code.extra[sema->code.inst_datas[func_inst] - .pl_node.payload_index - + func_info.param_block_pi]; - const uint32_t* early_pb2; - uint32_t early_pb_len2; - getParamBody(sema, early_pb_inst2, &early_pb2, &early_pb_len2); - uint32_t pi2 = 0; - uint32_t param_zir = 0; - for (uint32_t p2 = 0; p2 < early_pb_len2; p2++) { - ZirInstTag pt2 = sema->code.inst_tags[early_pb2[p2]]; - if (pt2 == ZIR_INST_PARAM || pt2 == ZIR_INST_PARAM_COMPTIME - || pt2 == ZIR_INST_PARAM_ANYTYPE - || pt2 == ZIR_INST_PARAM_ANYTYPE_COMPTIME) { - if (pi2 == a) { - param_zir = early_pb2[p2]; - break; - } - pi2++; - } - } - if (param_zir == 0) - continue; - uint32_t ppl - = sema->code.inst_datas[param_zir].pl_tok.payload_index; - uint32_t type_raw2 = sema->code.extra[ppl + 1]; - uint32_t tbody_len = type_raw2 & 0x7FFFFFFF; - // Scan the param type body for call/field_call instructions - // and extract the callee name. - for (uint32_t ti = 0; ti < tbody_len; ti++) { - uint32_t tzi = sema->code.extra[ppl + 2 + ti]; - if (tzi >= sema->code.inst_len) - continue; - ZirInstTag ttag = sema->code.inst_tags[tzi]; - const char* callee_name = NULL; - uint32_t scan_name_idx = 0; - uint32_t scan_nargs = 0; - if (ttag == ZIR_INST_FIELD_CALL) { - uint32_t tpi - = sema->code.inst_datas[tzi].pl_node.payload_index; - uint32_t fn_start = sema->code.extra[tpi + 2]; - callee_name - = (const char*)&sema->code.string_bytes[fn_start]; - scan_name_idx = fn_start; - scan_nargs = sema->code.extra[tpi] >> 5; - } else if (ttag == ZIR_INST_CALL) { - uint32_t tpi - = sema->code.inst_datas[tzi].pl_node.payload_index; - uint32_t cref = sema->code.extra[tpi + 1]; - scan_nargs = sema->code.extra[tpi] >> 5; - if (cref >= ZIR_REF_START_INDEX) { - uint32_t ci = cref - ZIR_REF_START_INDEX; - ZirInstTag ctag = sema->code.inst_tags[ci]; - if (ctag == ZIR_INST_DECL_VAL - || ctag == ZIR_INST_DECL_REF) { - scan_name_idx - = sema->code.inst_datas[ci].str_tok.start; - callee_name = (const char*)&sema->code - .string_bytes[scan_name_idx]; - } - } - } - if (callee_name == NULL) - continue; - if (strcmp(callee_name, "Int") != 0 - && strcmp(callee_name, "Log2Int") != 0 - && strcmp(callee_name, "PowerOfTwoSignificandZ") != 0 - && strcmp(callee_name, "F16T") != 0) - continue; - // Check if this function already had a dead block - // created (memoized in upstream). - bool already_created = false; - for (uint32_t k = 0; k < sema->num_type_fn_created; k++) { - if (strcmp(sema->type_fn_created[k], callee_name) - == 0) { - already_created = true; - break; - } - } - // Also check global seen-calls for cross-function dedup. - if (!already_created) { - for (uint32_t k = 0; k < sema->num_seen_calls; k++) { - if (sema->seen_call_names[k] == scan_name_idx - && sema->seen_call_nargs[k] == scan_nargs) { - already_created = true; - break; - } - } - } - if (!already_created) { - AirInstData dead; - memset(&dead, 0, sizeof(dead)); - (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, dead); - if (sema->num_type_fn_to_skip < 4) - sema->type_fn_to_skip[sema->num_type_fn_to_skip++] - = callee_name; - } - // Always register in global seen-calls, even when - // skipped (type_fn_created match). This ensures - // that subsequent calls after type_fn_created is - // reset (by analyzeFuncBodyAndRecord) still dedup. - if (scan_name_idx != 0 && sema->num_seen_calls < 16) { - bool in_seen = false; - for (uint32_t k = 0; k < sema->num_seen_calls; k++) { - if (sema->seen_call_names[k] == scan_name_idx - && sema->seen_call_nargs[k] == scan_nargs) { - in_seen = true; - break; - } - } - if (!in_seen) { - sema->seen_call_names[sema->num_seen_calls] - = scan_name_idx; - sema->seen_call_nargs[sema->num_seen_calls] - = scan_nargs; - sema->num_seen_calls++; - } - } - break; // only handle first call in type body - } - } - } - } - // Resolve the argument values (from the ORIGINAL module's ZIR). // Each arg has a body that produces the argument value via // break_inline. @@ -7845,361 +7314,6 @@ static AirInstRef zirCall( sema->code = arg_code; } - // Handle type-returning functions whose result can be computed from - // the comptime arguments without inlining. - // Upstream always reserves a dead BLOCK before inlining; we match - // that here so the AIR tag array stays consistent. - if (returns_type) { - // returns_type functions return `type` which is comptime-only. - // Upstream evaluates these in comptime context, so - // need_debug_scope is always false → BLOCK tag. - // Upstream (Sema.zig:7247) sets block to comptime for - // comptime-only ret types, enabling memoization (line 7724). - // Memoized calls return BEFORE block pre-allocation, so - // repeated calls with same args don't create dead blocks. - // Check memo first to match upstream behavior. - if (!block->is_comptime) { - bool all_ct = (args_len > 0); - for (uint32_t a = 0; a < args_len && all_ct; a++) { - if (!AIR_REF_IS_IP(arg_refs[a])) - all_ct = false; - } - if (all_ct) { - for (uint32_t mi = 0; mi < sema->num_memo; mi++) { - if (sema->memo_func_inst[mi] != func_inst) - continue; - if (sema->memo_args_len[mi] != args_len) - continue; - bool match = true; - for (uint32_t a = 0; a < args_len && a < 4; a++) { - if (sema->memo_args[mi][a] != arg_refs[a]) { - match = false; - break; - } - } - if (match) { - AirInstRef mr = sema->memo_result[mi]; - if (is_cross_module) { - sema->code = saved_code; - zirDeinit(&import_zir); - astDeinit(&import_ast); - } - return mr; - } - } - } - } - // Check if this function's dead block was pre-emitted during - // generic param type resolution. - // In comptime context (e.g. param type body evaluation), - // no dead blocks are created — matches upstream behavior. - bool skip_block = block->is_comptime; - // Check global seen-calls for cross-function dedup. - if (!skip_block) { - for (uint32_t k = 0; k < sema->num_seen_calls; k++) { - if (sema->seen_call_names[k] == callee_name_idx - && sema->seen_call_nargs[k] == args_len) { - skip_block = true; - break; - } - } - } - // skip_first_int: upstream memoizes Int during param type - // resolution (finishFuncInstance). Consume once. - if (!skip_block && type_fn_name && strcmp(type_fn_name, "Int") == 0 - && sema->skip_first_int) { - sema->skip_first_int = false; - skip_block = true; - } - if (!skip_block && type_fn_name) { - for (uint32_t k = 0; k < sema->num_type_fn_to_skip; k++) { - if (strcmp(sema->type_fn_to_skip[k], type_fn_name) == 0) { - sema->type_fn_to_skip[k] - = sema->type_fn_to_skip[--sema->num_type_fn_to_skip]; - skip_block = true; - break; - } - } - } - if (!skip_block) { - AirInstData rt_dead; - memset(&rt_dead, 0, sizeof(rt_dead)); - (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, rt_dead); - // Register in global seen-calls. - if (sema->num_seen_calls < 16) { - sema->seen_call_names[sema->num_seen_calls] = callee_name_idx; - sema->seen_call_nargs[sema->num_seen_calls] = args_len; - sema->num_seen_calls++; - } - } - // Log2Int called from comptime sub-block with runtime parent - // (e.g. @as(Log2Int(T), ...) in a runtime function body): - // upstream always pre-allocates the dead block for inline - // calls, and InternPool doesn't memoize Log2Int since it - // wasn't called during param type resolution. Create 2 dead - // blocks: 1 for Log2Int itself + 1 for its nested Int call. - if (skip_block && block->is_comptime && block->parent - && !block->parent->is_comptime && type_fn_name - && strcmp(type_fn_name, "Log2Int") == 0) { - AirInstData dead1; - memset(&dead1, 0, sizeof(dead1)); - (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, dead1); - AirInstData dead2; - memset(&dead2, 0, sizeof(dead2)); - (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, dead2); - } - // Track that this function has had its dead block created. - if (!skip_block && !block->is_comptime && type_fn_name - && sema->num_type_fn_created < 16) - sema->type_fn_created[sema->num_type_fn_created++] = type_fn_name; - InternPoolIndex result_type = IP_INDEX_NONE; - - if (type_fn_name && strcmp(type_fn_name, "Int") == 0) { - // std.meta.Int(signedness, bits): create integer type. - uint8_t signedness = 0; - uint16_t bits_val = 0; - if (args_len >= 2 && AIR_REF_IS_IP(arg_refs[1])) { - InternPoolKey k - = ipIndexToKey(sema->ip, AIR_REF_TO_IP(arg_refs[1])); - if (k.tag == IP_KEY_INT) - bits_val = (uint16_t)k.data.int_val.value_lo; - } - if (args_len >= 1) { - Zir caller_zir = is_cross_module ? saved_code : sema->code; - uint32_t arg0_end = caller_zir.extra[arg_data_start + 0]; - uint32_t arg0_body_start = arg_data_start + args_len; - uint32_t arg0_body_end = arg_data_start + arg0_end; - for (uint32_t ai = arg0_body_start; ai < arg0_body_end; ai++) { - uint32_t zi = caller_zir.extra[ai]; - if (zi < caller_zir.inst_len - && caller_zir.inst_tags[zi] == ZIR_INST_ENUM_LITERAL) { - uint32_t str_idx - = caller_zir.inst_datas[zi].str_tok.start; - const char* lit - = (const char*)&caller_zir.string_bytes[str_idx]; - if (strcmp(lit, "signed") == 0) - signedness = 1; - break; - } - } - } - if (bits_val > 0) { - InternPoolKey int_key; - memset(&int_key, 0, sizeof(int_key)); - int_key.tag = IP_KEY_INT_TYPE; - int_key.data.int_type.bits = bits_val; - int_key.data.int_type.signedness = signedness; - result_type = ipIntern(sema->ip, int_key); - } - } else if (type_fn_name && strcmp(type_fn_name, "Log2Int") == 0) { - // std.math.Log2Int(T): Int(.unsigned, log2_int_ceil(bits)) - // where bits = @typeInfo(T).int.bits. - if (args_len >= 1 && AIR_REF_IS_IP(arg_refs[0])) { - InternPoolIndex ty_ip = AIR_REF_TO_IP(arg_refs[0]); - InternPoolKey ty_key = sema->ip->items[ty_ip]; - uint32_t type_bits = 0; - if (ty_key.tag == IP_KEY_INT_TYPE) - type_bits = ty_key.data.int_type.bits; - if (type_bits > 0) { - // log2_int_ceil: smallest n such that 2^n >= bits. - uint32_t n = 0; - uint32_t v = type_bits - 1; - while (v > 0) { - n++; - v >>= 1; - } - if (n == 0) - n = 1; // Log2Int minimum is u1 - InternPoolKey int_key; - memset(&int_key, 0, sizeof(int_key)); - int_key.tag = IP_KEY_INT_TYPE; - int_key.data.int_type.bits = (uint16_t)n; - int_key.data.int_type.signedness = 0; - result_type = ipIntern(sema->ip, int_key); - } - } - } else if (type_fn_name - && strcmp(type_fn_name, "PowerOfTwoSignificandZ") == 0) { - // PowerOfTwoSignificandZ(T): - // Int(.unsigned, ceilPowerOfTwo(floatFractionalBits(T)+1)) - if (args_len >= 1 && AIR_REF_IS_IP(arg_refs[0])) { - InternPoolIndex ty_ip = AIR_REF_TO_IP(arg_refs[0]); - uint32_t frac_bits = 0; - switch (ty_ip) { - case IP_INDEX_F16_TYPE: - frac_bits = 10; - break; - case IP_INDEX_F32_TYPE: - frac_bits = 23; - break; - case IP_INDEX_F64_TYPE: - frac_bits = 52; - break; - case IP_INDEX_F80_TYPE: - frac_bits = 63; - break; - case IP_INDEX_F128_TYPE: - frac_bits = 112; - break; - default: - break; - } - if (frac_bits > 0) { - // ceilPowerOfTwo(frac_bits + 1) - uint32_t n = frac_bits + 1; - n--; - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - n |= n >> 16; - n++; - InternPoolKey int_key; - memset(&int_key, 0, sizeof(int_key)); - int_key.tag = IP_KEY_INT_TYPE; - int_key.data.int_type.bits = (uint16_t)n; - int_key.data.int_type.signedness = 0; - result_type = ipIntern(sema->ip, int_key); - // Upstream inlines PowerOfTwoSignificandZ fully, - // which creates dead blocks for each nested inline - // call: floatFractionalBits+switch, - // ceilPowerOfTwoAssert, ceilPowerOfTwo, Int, - // ceilPowerOfTwoPromote, Int, Log2Int(→Int). - // That's 7 nested dead blocks normally. - // When n != typeWidth (e.g. f80: n=64, width=80), - // the final Int(.unsigned, n) in - // PowerOfTwoSignificandZ is not memoized with the - // earlier Int(.unsigned, typeWidth) call, producing - // 8 dead blocks instead. - uint32_t exp_bits = 0; - switch (ty_ip) { - case IP_INDEX_F16_TYPE: - exp_bits = 5; - break; - case IP_INDEX_F32_TYPE: - exp_bits = 8; - break; - case IP_INDEX_F64_TYPE: - exp_bits = 11; - break; - case IP_INDEX_F80_TYPE: - exp_bits = 15; - break; - case IP_INDEX_F128_TYPE: - exp_bits = 15; - break; - default: - break; - } - uint32_t type_width = frac_bits + exp_bits + 1; - int num_dead = (n == type_width) ? 7 : 8; - AirInstData extra_dead; - memset(&extra_dead, 0, sizeof(extra_dead)); - for (int i = 0; i < num_dead; i++) - semaAddInstAsIndex(sema, AIR_INST_BLOCK, extra_dead); - // Upstream also memoizes floatFractionalBits(T) - // during this inline call, so later calls (from nan - // expansion) are memo hits. Pre-seed the memo to - // match: func_inst 755 = floatFractionalBits in - // float.zig's ZIR. - { - InternPoolKey frac_key; - memset(&frac_key, 0, sizeof(frac_key)); - frac_key.tag = IP_KEY_INT; - frac_key.data.int_val.ty = IP_INDEX_COMPTIME_INT_TYPE; - frac_key.data.int_val.value_lo = frac_bits; - InternPoolIndex frac_ip = ipIntern(sema->ip, frac_key); - if (sema->num_memo < 32) { - uint32_t mi = sema->num_memo++; - sema->memo_func_inst[mi] = 755; - sema->memo_args_len[mi] = 1; - sema->memo_args[mi][0] = arg_refs[0]; - sema->memo_result[mi] = AIR_REF_FROM_IP(frac_ip); - } - } - } - } - } else if (type_fn_name && strcmp(type_fn_name, "F16T") == 0) { - // F16T(T): returns u16 on wasm32-wasi (test target). - // Ported from lib/compiler_rt/common.zig F16T. - result_type = IP_INDEX_U16_TYPE; - } else if (type_fn_name && strcmp(type_fn_name, "Complex") == 0) { - // Complex(T): returns extern struct { real: T, imag: T }. - // Ported from lib/compiler_rt/mulc3.zig Complex. - if (args_len >= 1 && AIR_REF_IS_IP(arg_refs[0])) { - InternPoolIndex elem_ty = AIR_REF_TO_IP(arg_refs[0]); - // Use unique struct ID based on element type. - uint32_t struct_id = 0xC0A100 + (uint32_t)elem_ty; - // Check if already registered. - bool found = false; - for (uint32_t si = 0; si < sema->num_struct_info; si++) { - if (sema->struct_info[si].num_fields == 2 - && strcmp(sema->struct_info[si].fields[0].name, "real") - == 0 - && sema->struct_info[si].fields[0].type == elem_ty) { - result_type = sema->struct_info[si].struct_type; - found = true; - break; - } - } - if (!found) { - InternPoolKey skey; - memset(&skey, 0, sizeof(skey)); - skey.tag = IP_KEY_STRUCT_TYPE; - skey.data.struct_type = struct_id; - InternPoolIndex struct_ip = ipIntern(sema->ip, skey); - - InternPoolKey pkey; - memset(&pkey, 0, sizeof(pkey)); - pkey.tag = IP_KEY_PTR_TYPE; - pkey.data.ptr_type.child = struct_ip; - pkey.data.ptr_type.flags = 0; - InternPoolIndex ptr_ip = ipIntern(sema->ip, pkey); - - if (sema->num_struct_info < 32) { - StructFieldInfo* info - = &sema->struct_info[sema->num_struct_info++]; - info->struct_type = struct_ip; - info->ptr_type = ptr_ip; - info->num_fields = 2; - info->fields[0].name = "real"; - info->fields[0].type = elem_ty; - info->fields[1].name = "imag"; - info->fields[1].type = elem_ty; - } - result_type = struct_ip; - } - } - } - - if (is_cross_module) { - sema->code = saved_code; - zirDeinit(&import_zir); - astDeinit(&import_ast); - } - // Memoize type function result for future calls with same args. - // Matches upstream behavior where memoized calls skip block - // pre-allocation (Sema.zig:7724-7744, 7891-7896). - if (result_type != IP_INDEX_NONE && !block->is_comptime) { - bool all_ct = (args_len > 0); - for (uint32_t a = 0; a < args_len && all_ct; a++) { - if (!AIR_REF_IS_IP(arg_refs[a])) - all_ct = false; - } - if (all_ct && sema->num_memo < 32) { - uint32_t mi = sema->num_memo++; - sema->memo_func_inst[mi] = func_inst; - sema->memo_args_len[mi] = args_len; - for (uint32_t a = 0; a < args_len && a < 4; a++) - sema->memo_args[mi][a] = arg_refs[a]; - sema->memo_result[mi] = AIR_REF_FROM_IP(result_type); - } - } - if (result_type != IP_INDEX_NONE) - return AIR_REF_FROM_IP(result_type); - return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); - } - // Parse the inline function's parameter body. uint32_t param_block_inst = sema->code @@ -8992,8 +8106,6 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, memset(&sema->inst_map, 0, sizeof(sema->inst_map)); sema->num_ia = 0; sema->num_calls = 0; - sema->num_type_fn_created = 0; - sema->num_type_fn_to_skip = 0; sema->num_memo = 0; // Reserve extra[0] for main_block index. @@ -9181,44 +8293,6 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, arg_index++; } - // In upstream, finishFuncInstance evaluates param type bodies and - // memoizes type function calls (e.g. Int) in InternPool. When - // call_arg_types is provided, the C port skips evaluation. - // Detect generic params whose type body contains *Int(...) (both - // ptr_type and a call instruction) and set skip_first_int so the - // body's identical Int call skips its dead block. - bool saved_skip_first_int = sema->skip_first_int; - sema->skip_first_int = false; - if (call_args && call_arg_types) { - for (uint32_t p = 0; p < param_body_len; p++) { - uint32_t pi2 = param_body[p]; - ZirInstTag pt2 = sema->code.inst_tags[pi2]; - if (pt2 != ZIR_INST_PARAM) - continue; - uint32_t ppl2 = sema->code.inst_datas[pi2].pl_tok.payload_index; - uint32_t traw = sema->code.extra[ppl2 + 1]; - if (!((traw >> 31) & 1)) - continue; - uint32_t tlen = traw & 0x7FFFFFFF; - bool has_ptr = false; - bool has_call = false; - for (uint32_t ti = 0; ti < tlen; ti++) { - uint32_t tzi = sema->code.extra[ppl2 + 2 + ti]; - if (tzi >= sema->code.inst_len) - continue; - ZirInstTag t = sema->code.inst_tags[tzi]; - if (t == ZIR_INST_PTR_TYPE) - has_ptr = true; - if (t == ZIR_INST_FIELD_CALL || t == ZIR_INST_CALL) - has_call = true; - } - if (has_ptr && has_call) { - sema->skip_first_int = true; - break; - } - } - } - // Analyze the function body. const uint32_t* body = &sema->code.extra[fi.extra_index]; (void)analyzeBodyInner(sema, &fn_block, body, fi.body_len); @@ -9309,7 +8383,6 @@ static void analyzeFuncBodyAndRecord(Sema* sema, SemaBlock* block, sema->fn_ret_ty = saved_fn_ret_ty; sema->num_ia = saved_num_ia; sema->num_calls = saved_num_calls; - sema->skip_first_int = saved_skip_first_int; } // zirFunc: analyze a function declaration. @@ -10147,21 +9220,11 @@ static AirInstRef zirTypeInfoComptime(Sema* sema, uint32_t inst) { if (!AIR_REF_IS_IP(operand)) return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); - InternPoolIndex type_ip = AIR_REF_TO_IP(operand); - - // Intern a unique marker value for this type_info result. - // Use an aggregate-like IP entry to hold the marker. - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_INT; - key.data.int_val.ty = IP_INDEX_COMPTIME_INT_TYPE; - // Use a distinctive value unlikely to collide with real ints. - key.data.int_val.value_lo = 0x7E100000 + type_ip; - key.data.int_val.is_negative = false; - InternPoolIndex marker = ipIntern(sema->ip, key); - - ctTrack(sema, marker, CT_TAG_TYPE_INFO, type_ip); - return AIR_REF_FROM_IP(marker); + (void)operand; + // @typeInfo is evaluated honestly via evalComptimeTypeCall/ + // comptimeFieldCall — the result is used only within comptime + // function bodies, not by the caller. + return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE); } // floatTypeBits: get the bit count for a float type IP index. @@ -10234,47 +9297,6 @@ static const StructFieldInfo* lookupStructField(const Sema* sema, return NULL; } -// ensureF80StructRegistered: ensure the std.math.F80 struct type is -// registered in the sema. Returns the F80 struct IP index. -// The struct has two fields: fraction (u64, index 0) and exp (u16, index 1). -// Ported from lib/std/math.zig F80 definition. -static InternPoolIndex ensureF80StructRegistered(Sema* sema) { - // Check if already registered. - for (uint32_t i = 0; i < sema->num_struct_info; i++) { - if (sema->struct_info[i].num_fields == 2 - && strcmp(sema->struct_info[i].fields[0].name, "fraction") == 0 - && strcmp(sema->struct_info[i].fields[1].name, "exp") == 0) { - return sema->struct_info[i].struct_type; - } - } - // Register new F80 struct. - // Use a unique struct ID (0xF80F80) to distinguish from ZIR-based IDs. - InternPoolKey skey; - memset(&skey, 0, sizeof(skey)); - skey.tag = IP_KEY_STRUCT_TYPE; - skey.data.struct_type = 0xF80F80; - InternPoolIndex struct_ip = ipIntern(sema->ip, skey); - - InternPoolKey pkey; - memset(&pkey, 0, sizeof(pkey)); - pkey.tag = IP_KEY_PTR_TYPE; - pkey.data.ptr_type.child = struct_ip; - pkey.data.ptr_type.flags = 0; - InternPoolIndex ptr_ip = ipIntern(sema->ip, pkey); - - if (sema->num_struct_info >= 32) - return IP_INDEX_VOID_TYPE; - StructFieldInfo* info = &sema->struct_info[sema->num_struct_info++]; - info->struct_type = struct_ip; - info->ptr_type = ptr_ip; - info->num_fields = 2; - info->fields[0].name = "fraction"; - info->fields[0].type = IP_INDEX_U64_TYPE; - info->fields[1].name = "exp"; - info->fields[1].type = IP_INDEX_U16_TYPE; - return struct_ip; -} - // getValueBodyFromZir: extract value body from a ZIR_INST_DECLARATION in an // arbitrary Zir. Like getParamBody but works on a raw Zir* instead of // sema->code. @@ -10433,138 +9455,6 @@ static AirInstRef zirFieldValComptime( } InternPoolIndex obj_ip = AIR_REF_TO_IP(obj); - uint32_t ct_val; - uint8_t ct_tag = ctLookup(sema, obj_ip, &ct_val); - - if (ct_tag == CT_TAG_TYPE_INFO && strcmp(field_name, "float") == 0) { - // Access .float on a type_info result. - // ct_val is the type IP index. - uint32_t bits = floatTypeBits(ct_val); - if (bits > 0) { - // Intern a marker for float_info. - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_INT; - key.data.int_val.ty = IP_INDEX_COMPTIME_INT_TYPE; - key.data.int_val.value_lo = 0x71040000 + bits; - key.data.int_val.is_negative = false; - InternPoolIndex marker = ipIntern(sema->ip, key); - ctTrack(sema, marker, CT_TAG_FLOAT_INFO, bits); - return AIR_REF_FROM_IP(marker); - } - } else if (ct_tag == CT_TAG_TYPE_INFO && strcmp(field_name, "int") == 0) { - // Access .int on a type_info result for integer types. - // ct_val is the type IP index. - InternPoolKey type_key = sema->ip->items[ct_val]; - if (type_key.tag == IP_KEY_INT_TYPE) { - uint32_t s = type_key.data.int_type.signedness; - uint32_t b = type_key.data.int_type.bits; - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_INT; - key.data.int_val.ty = IP_INDEX_COMPTIME_INT_TYPE; - key.data.int_val.value_lo = 0x11140000 + ct_val; - key.data.int_val.is_negative = false; - InternPoolIndex marker = ipIntern(sema->ip, key); - ctTrack(sema, marker, CT_TAG_INT_INFO, (s << 16) | b); - return AIR_REF_FROM_IP(marker); - } - } else if ((ct_tag == CT_TAG_FLOAT_INFO || ct_tag == CT_TAG_INT_INFO) - && strcmp(field_name, "bits") == 0) { - // Access .bits on a float_info or int_info result. - // For float_info: ct_val is the bits count directly. - // For int_info: ct_val encodes (signedness << 16) | bits. - uint32_t bits - = (ct_tag == CT_TAG_FLOAT_INFO) ? ct_val : (ct_val & 0xFFFF); - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_INT; - key.data.int_val.ty = IP_INDEX_U16_TYPE; - key.data.int_val.value_lo = bits; - key.data.int_val.is_negative = false; - return AIR_REF_FROM_IP(ipIntern(sema->ip, key)); - } else if (ct_tag == CT_TAG_INT_INFO - && strcmp(field_name, "signedness") == 0) { - // Access .signedness on an int_info result. - // Return an enum_literal matching std.builtin.Signedness. - uint32_t s = (ct_val >> 16) & 0xFFFF; - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_ENUM_LITERAL; - key.data.enum_literal = simpleStringHash(s ? "signed" : "unsigned"); - return AIR_REF_FROM_IP(ipIntern(sema->ip, key)); - } - - // Comptime field access on target pointer: target.cpu, target.cpu.arch. - // When the body of cCallingConvention evaluates target.cpu.arch, - // the Zig compiler creates ptr_type, ptr_nav, ptr_field, and enum_tag - // entries. Ported from Sema.zig fieldVal / fieldPtr comptime path. - if (ct_tag == CT_TAG_TARGET_PTR && strcmp(field_name, "cpu") == 0) { - // Access .cpu on the comptime target pointer. - // ct_val = Target struct type IP index. - InternPoolIndex target_ty = ct_val; - - // Find the "cpu" field in Target struct. - uint32_t cpu_fidx = findStructFieldIndexByType(target_ty, "cpu"); - if (cpu_fidx != UINT32_MAX) { - InternPoolIndex cpu_type - = resolveFieldTypeByIP(target_ty, cpu_fidx); - if (cpu_type != IP_INDEX_NONE) { - // Create *const Cpu pointer type ($680). - InternPoolIndex const_cpu_ptr = internPtrConst(cpu_type); - // Create *mut Target pointer type ($681). - InternPoolIndex mut_tgt_ptr = internPtrMutable(target_ty); - // Create ptr_nav for the target ($682). - // Use the CG builtin "target" nav with *mut Target type. - uint32_t tgt_nav - = findNavInNamespace(s_cg_builtin_ns_idx, "target"); - if (tgt_nav != UINT32_MAX) { - InternPoolIndex nav_ptr - = internNavPtr(mut_tgt_ptr, tgt_nav); - // Create ptr_field ($683). - InternPoolIndex pf - = internPtrField(const_cpu_ptr, nav_ptr, cpu_fidx); - ctTrack(sema, pf, CT_TAG_STRUCT_FIELD_PTR, cpu_type); - return AIR_REF_FROM_IP(pf); - } - } - } - } - - if (ct_tag == CT_TAG_STRUCT_FIELD_PTR && strcmp(field_name, "arch") == 0 - && s_target_cpu_arch_name != NULL) { - // Access .arch on the Cpu struct (from target.cpu.arch). - // ct_val = Cpu struct type IP index. - InternPoolIndex cpu_type = ct_val; - uint32_t cpu_ns = findNamespaceForType(cpu_type); - if (cpu_ns != UINT32_MAX) { - // Find the Arch enum type in Cpu namespace. - uint32_t arch_nav = findNavInNamespace(cpu_ns, "Arch"); - if (arch_nav != UINT32_MAX) { - const Nav* arch_n = ipGetNav(arch_nav); - InternPoolIndex arch_ty = arch_n->resolved_type; - if (arch_ty != IP_INDEX_NONE) { - // Find the target arch field in the Arch enum ZIR. - const Zir* arch_zir = NULL; - uint32_t enum_inst - = findEnumDeclForNav(arch_nav, &arch_zir); - if (enum_inst != UINT32_MAX) { - uint32_t arch_fidx = findEnumFieldByName( - arch_zir, enum_inst, s_target_cpu_arch_name); - if (arch_fidx != UINT32_MAX) { - InternPoolIndex int_val = getEnumFieldIntVal( - arch_zir, enum_inst, arch_fidx); - if (int_val != IP_INDEX_NONE) { - InternPoolIndex tag - = internEnumTag(arch_ty, int_val); - return AIR_REF_FROM_IP(tag); - } - } - } - } - } - } - } // General namespace lookup: when the base object is a struct/union type, // look up the field name as a declaration in its namespace. @@ -10600,9 +9490,6 @@ static AirInstRef zirFieldValComptime( // Handle cross-module struct type resolution: // std.math.F80 → register the F80 struct (fraction: u64, exp: u16). // Ported from lib/std/math.zig F80 definition. - if (strcmp(field_name, "F80") == 0 && obj_ip == IP_INDEX_VOID_VALUE) { - return AIR_REF_FROM_IP(ensureF80StructRegistered(sema)); - } // Cross-module comptime constant resolution. // When the object is from a cross-module import (decl_val of @import), @@ -10647,8 +9534,6 @@ static AirInstRef zirFieldValComptime( pk.data.ptr_nav.ty = ptr_ty; pk.data.ptr_nav.nav = field_nav; InternPoolIndex pn = ipIntern(sema->ip, pk); - ctTrack(sema, pn, CT_TAG_TARGET_PTR, - tn->resolved_type); return AIR_REF_FROM_IP(pn); } } @@ -10733,8 +9618,6 @@ static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) { pk.data.ptr_nav.ty = ptr_ty; pk.data.ptr_nav.nav = field_nav; InternPoolIndex pn = ipIntern(sema->ip, pk); - ctTrack(sema, pn, CT_TAG_TARGET_PTR, - tn->resolved_type); return AIR_REF_FROM_IP(pn); } } @@ -10793,51 +9676,6 @@ static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) { // When the base pointer is a tracked comptime value (e.g. target // pointer), create ptr_field IP entries and track the result. // Ported from Sema.zig fieldPtr → comptime pointer path. - if (AIR_REF_IS_IP(obj) && block->is_comptime) { - InternPoolIndex obj_ip = AIR_REF_TO_IP(obj); - uint32_t ct_val; - uint8_t ct_tag = ctLookup(sema, obj_ip, &ct_val); - if (ct_tag == CT_TAG_TARGET_PTR || ct_tag == CT_TAG_STRUCT_FIELD_PTR) { - // Get the pointee struct type from the pointer type. - InternPoolIndex ptr_type = ipTypeOf(sema->ip, obj_ip); - if (ptr_type != IP_INDEX_NONE - && sema->ip->items[ptr_type].tag == IP_KEY_PTR_TYPE) { - InternPoolIndex struct_type_ip - = sema->ip->items[ptr_type].data.ptr_type.child; - // Look up the field index from ZIR. - uint32_t fidx - = findStructFieldIndexByType(struct_type_ip, field_name); - if (fidx != UINT32_MAX) { - // Look up the field type by finding the struct's - // ZIR and resolving the field type reference. - // For now, find the namespace's file, parse the - // struct_decl, and get the field's type. - uint32_t ns = findNamespaceForType(struct_type_ip); - InternPoolIndex field_type = IP_INDEX_NONE; - if (ns != UINT32_MAX) { - uint32_t fid = s_namespaces[ns].file_idx; - if (fid < s_num_loaded_modules - && s_loaded_modules[fid].has_zir) { - field_type = resolveStructFieldType( - &s_loaded_modules[fid].zir, 0, fidx, ns, fid); - } - } - if (field_type != IP_INDEX_NONE) { - // Create *const field_type pointer. - InternPoolIndex fld_ptr_ty - = internPtrConst(field_type); - // Create ptr_field entry. - InternPoolIndex pf - = internPtrField(fld_ptr_ty, obj_ip, fidx); - // Track so subsequent accesses can resolve. - ctTrack(sema, pf, CT_TAG_STRUCT_FIELD_PTR, field_type); - return AIR_REF_FROM_IP(pf); - } - } - } - } - } - // Comptime union field init through comptime alloc-derived pointer. // Ported from Sema.zig unionFieldPtr comptime initializing path // (src/Sema.zig lines 27571-27692). @@ -10868,12 +9706,14 @@ static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) { etk.data.enum_tag.int_val = int_val; InternPoolIndex field_tag = ipForceIntern(sema->ip, etk); // 3. Create undef(FieldType) (matches upstream undefValue). - (void)internUndef(field_type); + InternPoolIndex undef_val = internUndef(field_type); // 4. Create union_value (matches upstream unionValue). InternPoolKey uvk; memset(&uvk, 0, sizeof(uvk)); uvk.tag = IP_KEY_UNION_VALUE; - uvk.data.union_value = field_tag; + uvk.data.union_val.ty = union_ty; + uvk.data.union_val.tag = field_tag; + uvk.data.union_val.val = undef_val; InternPoolIndex uv = ipForceIntern(sema->ip, uvk); // 5. Store to comptime alloc (simplified storePtrVal). sema->comptime_ret_val = uv; @@ -10945,30 +9785,6 @@ static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) { return semaAddInst(block, AIR_INST_STRUCT_FIELD_PTR, data); } -// resolveUnsignedIntType: given a bits count, return the IP index -// for the corresponding unsigned integer type. -static InternPoolIndex resolveUnsignedIntType(InternPool* ip, uint32_t bits) { - switch (bits) { - case 8: - return IP_INDEX_U8_TYPE; - case 16: - return IP_INDEX_U16_TYPE; - case 32: - return IP_INDEX_U32_TYPE; - case 64: - return IP_INDEX_U64_TYPE; - default: { - // Intern a new int type. - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_INT_TYPE; - key.data.int_type.signedness = 0; // unsigned - key.data.int_type.bits = (uint16_t)bits; - return ipIntern(ip, key); - } - } -} - // zirStructInit: handle struct_init ZIR instruction. // Comptime case: @Type(.{.int = .{.signedness = .unsigned, .bits = N}}) // Runtime case: emits AIR_INST_AGGREGATE_INIT with field values. @@ -11003,13 +9819,18 @@ static AirInstRef zirStructInit(Sema* sema, SemaBlock* block, uint32_t inst) { if (strcmp(name, "signedness") == 0) { has_signedness = true; // The init should resolve to 0 (unsigned) or 1 (signed). - // It comes from decl_literal(.unsigned) or - // a comptime int. + // It comes from decl_literal(.unsigned), a comptime int, + // or an enum_literal passed through a comptime parameter. if (AIR_REF_IS_IP(init_air)) { InternPoolIndex ip_idx = AIR_REF_TO_IP(init_air); InternPoolKey key_val = sema->ip->items[ip_idx]; if (key_val.tag == IP_KEY_INT) { signedness = (uint32_t)key_val.data.int_val.value_lo; + } else if (key_val.tag == IP_KEY_ENUM_LITERAL) { + // Enum literal: hash of "signed" → 1, else 0. + if (key_val.data.enum_literal + == simpleStringHash("signed")) + signedness = 1; } } } else if (strcmp(name, "bits") == 0) { @@ -11040,7 +9861,6 @@ static AirInstRef zirStructInit(Sema* sema, SemaBlock* block, uint32_t inst) { key.data.int_val.value_lo = 0x51F70000 | ((uint64_t)signedness << 16) | bits_val; InternPoolIndex marker = ipIntern(sema->ip, key); - ctTrack(sema, marker, CT_TAG_INT_INFO, (signedness << 16) | bits_val); return AIR_REF_FROM_IP(marker); } @@ -11048,7 +9868,6 @@ static AirInstRef zirStructInit(Sema* sema, SemaBlock* block, uint32_t inst) { // Outer struct: .{.int = <inner>} key.data.int_val.value_lo = 0x52E10000 + inner_ip; InternPoolIndex marker = ipIntern(sema->ip, key); - ctTrack(sema, marker, CT_TAG_REIFY_INT, inner_ip); return AIR_REF_FROM_IP(marker); } @@ -11093,44 +9912,9 @@ static AirInstRef zirReifyComptime(Sema* sema, uint32_t inst) { if (!AIR_REF_IS_IP(operand)) return AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE); - InternPoolIndex op_ip = AIR_REF_TO_IP(operand); - uint32_t ct_val; - uint8_t ct_tag = ctLookup(sema, op_ip, &ct_val); - - if (ct_tag == CT_TAG_REIFY_INT) { - // The operand is .{.int = <inner>}. - // Look up the inner int_info. - uint32_t inner_val; - uint8_t inner_tag = ctLookup(sema, ct_val, &inner_val); - if (inner_tag == CT_TAG_INT_INFO) { - uint32_t s = (inner_val >> 16) & 0xFFFF; - uint32_t b = inner_val & 0xFFFF; - if (s == 0) { - return AIR_REF_FROM_IP(resolveUnsignedIntType(sema->ip, b)); - } - // Signed int type. - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_INT_TYPE; - key.data.int_type.signedness = 1; - key.data.int_type.bits = (uint16_t)b; - return AIR_REF_FROM_IP(ipIntern(sema->ip, key)); - } - } else if (ct_tag == CT_TAG_INT_INFO) { - // Direct int_info (no outer wrapping). - uint32_t s = (ct_val >> 16) & 0xFFFF; - uint32_t b = ct_val & 0xFFFF; - if (s == 0) { - return AIR_REF_FROM_IP(resolveUnsignedIntType(sema->ip, b)); - } - InternPoolKey key; - memset(&key, 0, sizeof(key)); - key.tag = IP_KEY_INT_TYPE; - key.data.int_type.signedness = 1; - key.data.int_type.bits = (uint16_t)b; - return AIR_REF_FROM_IP(ipIntern(sema->ip, key)); - } - + (void)operand; + // @Type is evaluated honestly via evalComptimeTypeCall — the reify + // result is computed within the callee's comptime body evaluation. return AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE); } @@ -11642,14 +10426,15 @@ static void zirValidatePtrStructInit(Sema* sema, uint32_t inst) { (void)rep; // Create final union_value with actual payload (not undef). - // This replaces the initial union_value($933) that had undef payload. + // This replaces the initial union_value that had undef payload. // Ported from validateUnionInit storing the finalized value. - InternPoolIndex existing_tag - = sema->ip->items[sema->comptime_ret_val].data.union_value; + InternPoolKey existing = sema->ip->items[sema->comptime_ret_val]; InternPoolKey uvk; memset(&uvk, 0, sizeof(uvk)); uvk.tag = IP_KEY_UNION_VALUE; - uvk.data.union_value = existing_tag; + uvk.data.union_val.ty = existing.data.union_val.ty; + uvk.data.union_val.tag = existing.data.union_val.tag; + uvk.data.union_val.val = rep; InternPoolIndex final_uv = ipForceIntern(sema->ip, uvk); sema->comptime_ret_val = final_uv; } diff --git a/stage0/sema.h b/stage0/sema.h @@ -218,13 +218,6 @@ typedef struct Sema { // Used for lib/std/ files compiled as part of std.zig root, so that // C sema FQNs match Zig FQNs. NULL = no prefix. const char* module_prefix; - // Comptime type-info tracker: maps IP indices returned by type_info - // and field_val to their semantic meaning. - // tag: 0=none, 1=type_info(type), 2=float_info(bits) - uint8_t ct_tags[16]; - uint32_t ct_vals[16]; // type IP index or bits count - InternPoolIndex ct_keys[16]; // the IP index this entry describes - uint32_t ct_len; // Branch hint for the current branch of runtime control flow. // -1 = not set; 0..4 = std.builtin.BranchHint values // (none=0, likely=1, unlikely=2, cold=3, unpredictable=4). @@ -251,36 +244,11 @@ typedef struct Sema { uint32_t memo_args_len[32]; AirInstRef memo_result[32]; uint32_t num_memo; - // Track type-returning function names that have had dead BLOCK - // instructions created (for memoization simulation). - // When a returns_type function is called for the first time, a dead - // BLOCK is emitted. Subsequent calls with the same name are - // considered "memoized" and don't emit new blocks. - const char* type_fn_created[16]; - uint32_t num_type_fn_created; - // Names of type-returning functions pre-emitted during generic param - // type resolution. The returns_type handler skips dead block creation - // for these, since the block was already emitted at the correct - // (earlier) position. - const char* type_fn_to_skip[4]; - uint32_t num_type_fn_to_skip; // Known struct types with runtime field information. // Populated by zirCall when a call returns a struct type. // Used by zirFieldVal/zirFieldPtr for runtime field access. StructFieldInfo struct_info[32]; uint32_t num_struct_info; - // Set by analyzeFuncBodyAndRecord when a generic param type body - // contains both ptr_type and a call (e.g. *Int(...)). In upstream, - // finishFuncInstance memoizes such calls, so the body's identical - // call skips dead block creation. Consumed once by site2. - bool skip_first_int; - // Global call dedup for dead block emission (persists across functions). - // Keyed by callee name string_bytes index + arg count. - // NOT reset in analyzeFuncBodyAndRecord. - // Matches upstream InternPool memoization which persists globally. - uint32_t seen_call_names[16]; - uint32_t seen_call_nargs[16]; - uint32_t num_seen_calls; // When true, test declarations are analyzed (test blocks become // analyzeable functions). Set by the caller before semaAnalyze. bool is_test; diff --git a/stage0/sema_tests/reify_int.zig b/stage0/sema_tests/reify_int.zig @@ -0,0 +1,4 @@ +const U32 = @Type(.{ .int = .{ .signedness = .unsigned, .bits = 32 } }); +export fn f(x: U32) U32 { + return x; +} diff --git a/stage0/sema_tests/type_identity_fn.zig b/stage0/sema_tests/type_identity_fn.zig @@ -0,0 +1,6 @@ +inline fn identity(comptime T: type) type { + return T; +} +export fn f(x: identity(u32)) identity(u32) { + return x; +}