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:
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, ¶m_body, ¶m_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;
+}