Files
zig/stage0/intern_pool.c
Motiejus a35da223fb sema: add func_instance support for generic function monomorphization
Port IP_KEY_FUNC_INSTANCE from upstream InternPool.getFuncInstance.
When a generic non-inline function is called, create a monomorphized
func_type (runtime params only) and a func_instance entry referencing
the generic owner's func_decl. This matches the Zig compiler's IP
entry sequence for generic instantiations.

Bumps num_passing from 84 to 85.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 08:30:41 +00:00

1107 lines
40 KiB
C

#include "intern_pool.h"
#include "wyhash.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IP_INITIAL_CAP 256
#define IP_HASH_INITIAL_CAP 512
#define IP_STRING_INITIAL_CAP 1024
#define IP_EXTRA_INITIAL_CAP 256
// --- Hash helpers ---
static uint32_t ipHashKey(const InternPoolKey* key) {
Wyhash h;
wyhash_init(&h, (uint64_t)key->tag);
switch (key->tag) {
case IP_KEY_INT_TYPE:
wyhash_update_u32(&h, (uint32_t)key->data.int_type.bits);
wyhash_update_u32(&h, (uint32_t)key->data.int_type.signedness);
break;
case IP_KEY_PTR_TYPE:
return (uint32_t)wyhash_hash((uint64_t)key->tag, &key->data.ptr_type,
sizeof(key->data.ptr_type));
case IP_KEY_ARRAY_TYPE:
wyhash_update_u64(&h, key->data.array_type.len);
wyhash_update_u32(&h, key->data.array_type.child);
wyhash_update_u32(&h, key->data.array_type.sentinel);
break;
case IP_KEY_VECTOR_TYPE:
wyhash_update_u32(&h, key->data.vector_type.len);
wyhash_update_u32(&h, key->data.vector_type.child);
break;
case IP_KEY_OPT_TYPE:
wyhash_update_u32(&h, key->data.opt_type);
break;
case IP_KEY_ANYFRAME_TYPE:
wyhash_update_u32(&h, key->data.anyframe_type);
break;
case IP_KEY_ERROR_UNION_TYPE:
wyhash_update_u32(&h, key->data.error_union_type.error_set);
wyhash_update_u32(&h, key->data.error_union_type.payload);
break;
case IP_KEY_SIMPLE_TYPE:
wyhash_update_u32(&h, (uint32_t)key->data.simple_type);
break;
case IP_KEY_SIMPLE_VALUE:
wyhash_update_u32(&h, (uint32_t)key->data.simple_value);
break;
case IP_KEY_UNDEF:
wyhash_update_u32(&h, key->data.undef);
break;
case IP_KEY_INT:
wyhash_update_u32(&h, key->data.int_val.ty);
wyhash_update_u64(&h, key->data.int_val.value_lo);
wyhash_update_u64(&h, key->data.int_val.value_hi);
wyhash_update_u32(&h, (uint32_t)key->data.int_val.is_negative);
break;
case IP_KEY_TUPLE_TYPE:
wyhash_update_u32(&h, key->data.tuple_type);
break;
case IP_KEY_ENUM_LITERAL:
wyhash_update_u32(&h, key->data.enum_literal);
break;
case IP_KEY_ENUM_TAG:
wyhash_update_u32(&h, key->data.enum_tag.ty);
wyhash_update_u32(&h, key->data.enum_tag.int_val);
break;
case IP_KEY_FLOAT:
wyhash_update_u32(&h, key->data.float_val.ty);
wyhash_update(
&h, &key->data.float_val.val, sizeof(key->data.float_val.val));
break;
case IP_KEY_PTR_NAV:
wyhash_update_u32(&h, key->data.ptr_nav.ty);
wyhash_update_u32(&h, key->data.ptr_nav.nav);
break;
case IP_KEY_FUNC:
wyhash_update_u32(&h, key->data.func_decl.owner_nav);
wyhash_update_u32(&h, key->data.func_decl.ty);
break;
case IP_KEY_FUNC_INSTANCE:
wyhash_update_u32(&h, key->data.func_instance.generic_owner);
wyhash_update_u32(&h, key->data.func_instance.ty);
break;
case IP_KEY_MEMOIZED_CALL:
wyhash_update_u32(&h, key->data.memoized_call.func);
wyhash_update_u32(&h, key->data.memoized_call.result);
break;
case IP_KEY_BYTES:
wyhash_update_u32(&h, key->data.bytes.ty);
wyhash_update_u32(&h, key->data.bytes.str_idx);
break;
case IP_KEY_PTR_UAV:
wyhash_update_u32(&h, key->data.ptr_uav.ty);
wyhash_update_u32(&h, key->data.ptr_uav.val);
break;
case IP_KEY_PTR_UAV_ALIGNED:
wyhash_update_u32(&h, key->data.ptr_uav_aligned.ty);
wyhash_update_u32(&h, key->data.ptr_uav_aligned.val);
wyhash_update_u32(&h, key->data.ptr_uav_aligned.orig_ty);
break;
case IP_KEY_PTR_SLICE:
wyhash_update_u32(&h, key->data.ptr_slice.ty);
wyhash_update_u32(&h, key->data.ptr_slice.ptr);
wyhash_update_u32(&h, key->data.ptr_slice.len);
break;
case IP_KEY_OPT:
wyhash_update_u32(&h, key->data.opt);
break;
case IP_KEY_OPT_PAYLOAD:
wyhash_update_u32(&h, key->data.opt_payload.ty);
wyhash_update_u32(&h, key->data.opt_payload.val);
break;
case IP_KEY_PTR_COMPTIME_ALLOC:
wyhash_update_u32(&h, key->data.ptr_comptime_alloc.ty);
wyhash_update_u32(&h, key->data.ptr_comptime_alloc.alloc_index);
break;
case IP_KEY_PTR_FIELD:
wyhash_update_u32(&h, key->data.ptr_field.ty);
wyhash_update_u32(&h, key->data.ptr_field.base);
wyhash_update_u32(&h, key->data.ptr_field.field_index);
break;
case IP_KEY_PTR_OPT_PAYLOAD:
wyhash_update_u32(&h, key->data.ptr_opt_payload.ty);
wyhash_update_u32(&h, key->data.ptr_opt_payload.base);
break;
case IP_KEY_OPT_NULL:
wyhash_update_u32(&h, key->data.opt_null);
break;
case IP_KEY_REPEATED:
wyhash_update_u32(&h, key->data.repeated.ty);
wyhash_update_u32(&h, key->data.repeated.elem_val);
break;
case IP_KEY_INT_U16:
wyhash_update_u32(&h, key->data.int_u16);
break;
case IP_KEY_FUNC_TYPE:
wyhash_update_u32(&h, key->data.func_type.return_type);
wyhash_update_u32(&h, key->data.func_type.param_count);
wyhash_update_u32(&h, (uint32_t)key->data.func_type.cc);
wyhash_update_u32(&h, (uint32_t)key->data.func_type.is_var_args);
wyhash_update_u32(&h, (uint32_t)key->data.func_type.is_generic);
wyhash_update_u32(&h, (uint32_t)key->data.func_type.is_noinline);
wyhash_update_u32(&h, key->data.func_type.comptime_bits);
wyhash_update_u32(&h, key->data.func_type.noalias_bits);
for (uint32_t pi = 0;
pi < key->data.func_type.param_count && pi < FUNC_TYPE_MAX_PARAMS;
pi++)
wyhash_update_u32(&h, key->data.func_type.param_types[pi]);
break;
case IP_KEY_SLICE:
wyhash_update_u32(&h, key->data.slice);
break;
case IP_KEY_AGGREGATE:
wyhash_update_u32(&h, key->data.aggregate);
break;
case IP_KEY_UNION_VALUE:
wyhash_update_u32(&h, key->data.union_val.ty);
wyhash_update_u32(&h, key->data.union_val.tag);
wyhash_update_u32(&h, key->data.union_val.val);
break;
default:
/* For other tag types, just use the tag hash (seed only). */
break;
}
return (uint32_t)wyhash_final(&h);
}
static bool ipKeysEqual(const InternPoolKey* a, const InternPoolKey* b) {
if (a->tag != b->tag) {
return false;
}
switch (a->tag) {
case IP_KEY_INT_TYPE:
return a->data.int_type.bits == b->data.int_type.bits
&& a->data.int_type.signedness == b->data.int_type.signedness;
case IP_KEY_PTR_TYPE:
return a->data.ptr_type.child == b->data.ptr_type.child
&& a->data.ptr_type.sentinel == b->data.ptr_type.sentinel
&& a->data.ptr_type.flags == b->data.ptr_type.flags
&& a->data.ptr_type.packed_offset
== b->data.ptr_type.packed_offset;
case IP_KEY_ARRAY_TYPE:
return a->data.array_type.len == b->data.array_type.len
&& a->data.array_type.child == b->data.array_type.child
&& a->data.array_type.sentinel == b->data.array_type.sentinel;
case IP_KEY_VECTOR_TYPE:
return a->data.vector_type.len == b->data.vector_type.len
&& a->data.vector_type.child == b->data.vector_type.child;
case IP_KEY_OPT_TYPE:
return a->data.opt_type == b->data.opt_type;
case IP_KEY_ANYFRAME_TYPE:
return a->data.anyframe_type == b->data.anyframe_type;
case IP_KEY_ERROR_UNION_TYPE:
return a->data.error_union_type.error_set
== b->data.error_union_type.error_set
&& a->data.error_union_type.payload
== b->data.error_union_type.payload;
case IP_KEY_SIMPLE_TYPE:
return a->data.simple_type == b->data.simple_type;
case IP_KEY_SIMPLE_VALUE:
return a->data.simple_value == b->data.simple_value;
case IP_KEY_UNDEF:
return a->data.undef == b->data.undef;
case IP_KEY_INT:
return a->data.int_val.ty == b->data.int_val.ty
&& a->data.int_val.value_lo == b->data.int_val.value_lo
&& a->data.int_val.value_hi == b->data.int_val.value_hi
&& a->data.int_val.is_negative == b->data.int_val.is_negative;
case IP_KEY_TUPLE_TYPE:
return a->data.tuple_type == b->data.tuple_type;
case IP_KEY_ENUM_LITERAL:
return a->data.enum_literal == b->data.enum_literal;
case IP_KEY_ENUM_TAG:
return a->data.enum_tag.ty == b->data.enum_tag.ty
&& a->data.enum_tag.int_val == b->data.enum_tag.int_val;
case IP_KEY_FLOAT:
return a->data.float_val.ty == b->data.float_val.ty
&& memcmp(&a->data.float_val.val, &b->data.float_val.val,
sizeof(double))
== 0;
case IP_KEY_PTR_NAV:
return a->data.ptr_nav.ty == b->data.ptr_nav.ty
&& a->data.ptr_nav.nav == b->data.ptr_nav.nav;
case IP_KEY_FUNC:
return a->data.func_decl.owner_nav == b->data.func_decl.owner_nav
&& a->data.func_decl.ty == b->data.func_decl.ty;
case IP_KEY_FUNC_INSTANCE:
return a->data.func_instance.generic_owner
== b->data.func_instance.generic_owner
&& a->data.func_instance.ty == b->data.func_instance.ty;
case IP_KEY_MEMOIZED_CALL:
return a->data.memoized_call.func == b->data.memoized_call.func
&& a->data.memoized_call.result == b->data.memoized_call.result;
case IP_KEY_BYTES:
return a->data.bytes.ty == b->data.bytes.ty
&& a->data.bytes.str_idx == b->data.bytes.str_idx;
case IP_KEY_PTR_UAV:
return a->data.ptr_uav.ty == b->data.ptr_uav.ty
&& a->data.ptr_uav.val == b->data.ptr_uav.val;
case IP_KEY_PTR_UAV_ALIGNED:
return a->data.ptr_uav_aligned.ty == b->data.ptr_uav_aligned.ty
&& a->data.ptr_uav_aligned.val == b->data.ptr_uav_aligned.val
&& a->data.ptr_uav_aligned.orig_ty
== b->data.ptr_uav_aligned.orig_ty;
case IP_KEY_PTR_SLICE:
return a->data.ptr_slice.ty == b->data.ptr_slice.ty
&& a->data.ptr_slice.ptr == b->data.ptr_slice.ptr
&& a->data.ptr_slice.len == b->data.ptr_slice.len;
case IP_KEY_OPT:
return a->data.opt == b->data.opt;
case IP_KEY_OPT_PAYLOAD:
return a->data.opt_payload.ty == b->data.opt_payload.ty
&& a->data.opt_payload.val == b->data.opt_payload.val;
case IP_KEY_PTR_COMPTIME_ALLOC:
return a->data.ptr_comptime_alloc.ty == b->data.ptr_comptime_alloc.ty
&& a->data.ptr_comptime_alloc.alloc_index
== b->data.ptr_comptime_alloc.alloc_index;
case IP_KEY_PTR_FIELD:
return a->data.ptr_field.ty == b->data.ptr_field.ty
&& a->data.ptr_field.base == b->data.ptr_field.base
&& a->data.ptr_field.field_index == b->data.ptr_field.field_index;
case IP_KEY_PTR_OPT_PAYLOAD:
return a->data.ptr_opt_payload.ty == b->data.ptr_opt_payload.ty
&& a->data.ptr_opt_payload.base == b->data.ptr_opt_payload.base;
case IP_KEY_OPT_NULL:
return a->data.opt_null == b->data.opt_null;
case IP_KEY_REPEATED:
return a->data.repeated.ty == b->data.repeated.ty
&& a->data.repeated.elem_val == b->data.repeated.elem_val;
case IP_KEY_INT_U16:
return a->data.int_u16 == b->data.int_u16;
case IP_KEY_FUNC_TYPE:
if (a->data.func_type.return_type != b->data.func_type.return_type
|| a->data.func_type.param_count != b->data.func_type.param_count
|| a->data.func_type.cc != b->data.func_type.cc
|| a->data.func_type.is_var_args != b->data.func_type.is_var_args
|| a->data.func_type.is_generic != b->data.func_type.is_generic
|| a->data.func_type.is_noinline != b->data.func_type.is_noinline
|| a->data.func_type.comptime_bits
!= b->data.func_type.comptime_bits
|| a->data.func_type.noalias_bits
!= b->data.func_type.noalias_bits)
return false;
for (uint32_t pi = 0;
pi < a->data.func_type.param_count && pi < FUNC_TYPE_MAX_PARAMS;
pi++) {
if (a->data.func_type.param_types[pi]
!= b->data.func_type.param_types[pi])
return false;
}
return true;
case IP_KEY_SLICE:
return a->data.slice == b->data.slice;
case IP_KEY_AGGREGATE:
return a->data.aggregate == b->data.aggregate;
case IP_KEY_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;
}
}
// --- Helper to append an item directly (bypassing hash) ---
static void ipAppendItem(InternPool* ip, InternPoolKey key) {
if (ip->items_len >= ip->items_cap) {
uint32_t new_cap = ip->items_cap * 2;
InternPoolKey* new_items
= realloc(ip->items, new_cap * sizeof(InternPoolKey));
if (!new_items) {
exit(1);
}
ip->items = new_items;
ip->items_cap = new_cap;
}
ip->items[ip->items_len] = key;
ip->items_len++;
}
// --- Hash table rebuild ---
static void ipRebuildHash(InternPool* ip) {
memset(ip->hash_table, 0xFF, ip->hash_cap * sizeof(uint32_t));
for (uint32_t i = 0; i < ip->items_len; i++) {
uint32_t h = ipHashKey(&ip->items[i]) & (ip->hash_cap - 1);
while (ip->hash_table[h] != IP_INDEX_NONE) {
h = (h + 1) & (ip->hash_cap - 1);
}
ip->hash_table[h] = i;
}
}
// --- Hash table grow ---
static void ipGrowHash(InternPool* ip) {
uint32_t new_cap = ip->hash_cap * 2;
uint32_t* new_table = realloc(ip->hash_table, new_cap * sizeof(uint32_t));
if (!new_table) {
exit(1);
}
ip->hash_table = new_table;
ip->hash_cap = new_cap;
ipRebuildHash(ip);
}
// --- Pre-interned key builders ---
static InternPoolKey ipMakeIntType(uint16_t bits, uint8_t signedness) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_INT_TYPE;
key.data.int_type.bits = bits;
key.data.int_type.signedness = signedness;
return key;
}
static InternPoolKey ipMakeSimpleType(SimpleType st) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_SIMPLE_TYPE;
key.data.simple_type = st;
return key;
}
static InternPoolKey ipMakePtrType(
InternPoolIndex child, InternPoolIndex sentinel, uint32_t flags) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_PTR_TYPE;
key.data.ptr_type.child = child;
key.data.ptr_type.sentinel = sentinel;
key.data.ptr_type.flags = flags;
key.data.ptr_type.packed_offset = 0;
return key;
}
static InternPoolKey ipMakeVectorType(uint32_t len, InternPoolIndex child) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_VECTOR_TYPE;
key.data.vector_type.len = len;
key.data.vector_type.child = child;
return key;
}
static InternPoolKey ipMakeOptType(InternPoolIndex child) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_OPT_TYPE;
key.data.opt_type = child;
return key;
}
static InternPoolKey ipMakeErrorUnionType(
InternPoolIndex error_set, InternPoolIndex payload) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_ERROR_UNION_TYPE;
key.data.error_union_type.error_set = error_set;
key.data.error_union_type.payload = payload;
return key;
}
static InternPoolKey ipMakeTupleType(void) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_TUPLE_TYPE;
key.data.tuple_type = IP_INDEX_NONE;
return key;
}
static InternPoolKey ipMakeAnyframeType(InternPoolIndex return_type) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_ANYFRAME_TYPE;
key.data.anyframe_type = return_type;
return key;
}
static InternPoolKey ipMakeUndef(InternPoolIndex ty) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_UNDEF;
key.data.undef = ty;
return key;
}
static InternPoolKey ipMakeSimpleValue(SimpleValue sv) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_SIMPLE_VALUE;
key.data.simple_value = sv;
return key;
}
static InternPoolKey ipMakeTypedInt(
InternPoolIndex ty, uint64_t value, bool is_negative) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_INT;
key.data.int_val.ty = ty;
key.data.int_val.value_lo = value;
key.data.int_val.is_negative = is_negative;
return key;
}
// --- ipInit: Pre-populate with all 124 pre-interned types/values ---
InternPool ipInit(void) {
InternPool ip;
memset(&ip, 0, sizeof(ip));
ip.items = ARR_INIT(InternPoolKey, IP_INITIAL_CAP);
ip.items_cap = IP_INITIAL_CAP;
ip.hash_table = ARR_INIT(uint32_t, IP_HASH_INITIAL_CAP);
ip.hash_cap = IP_HASH_INITIAL_CAP;
memset(ip.hash_table, 0xFF, IP_HASH_INITIAL_CAP * sizeof(uint32_t));
ip.string_bytes = ARR_INIT(uint8_t, IP_STRING_INITIAL_CAP);
ip.string_bytes_cap = IP_STRING_INITIAL_CAP;
ip.extra = ARR_INIT(uint32_t, IP_EXTRA_INITIAL_CAP);
ip.extra_cap = IP_EXTRA_INITIAL_CAP;
ip.navs = ARR_INIT(Nav, 64);
ip.nav_cap = 64;
// Index 0: u0_type
ipAppendItem(&ip, ipMakeIntType(0, 0));
// Index 1: i0_type
ipAppendItem(&ip, ipMakeIntType(0, 1));
// Index 2: u1_type
ipAppendItem(&ip, ipMakeIntType(1, 0));
// Index 3: u8_type
ipAppendItem(&ip, ipMakeIntType(8, 0));
// Index 4: i8_type
ipAppendItem(&ip, ipMakeIntType(8, 1));
// Index 5: u16_type
ipAppendItem(&ip, ipMakeIntType(16, 0));
// Index 6: i16_type
ipAppendItem(&ip, ipMakeIntType(16, 1));
// Index 7: u29_type
ipAppendItem(&ip, ipMakeIntType(29, 0));
// Index 8: u32_type
ipAppendItem(&ip, ipMakeIntType(32, 0));
// Index 9: i32_type
ipAppendItem(&ip, ipMakeIntType(32, 1));
// Index 10: u64_type
ipAppendItem(&ip, ipMakeIntType(64, 0));
// Index 11: i64_type
ipAppendItem(&ip, ipMakeIntType(64, 1));
// Index 12: u80_type
ipAppendItem(&ip, ipMakeIntType(80, 0));
// Index 13: u128_type
ipAppendItem(&ip, ipMakeIntType(128, 0));
// Index 14: i128_type
ipAppendItem(&ip, ipMakeIntType(128, 1));
// Index 15: u256_type
ipAppendItem(&ip, ipMakeIntType(256, 0));
// Indices 16-27: simple types (usize..c_longdouble)
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_USIZE));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_ISIZE));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_CHAR));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_SHORT));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_USHORT));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_INT));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_UINT));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_LONG));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_ULONG));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_LONGLONG));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_ULONGLONG));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_C_LONGDOUBLE));
// Indices 28-32: float types
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_F16));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_F32));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_F64));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_F80));
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_F128));
// Index 33: anyopaque
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_ANYOPAQUE));
// Index 34: bool
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_BOOL));
// Index 35: void
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_VOID));
// Index 36: type
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_TYPE));
// Index 37: anyerror
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_ANYERROR));
// Index 38: comptime_int
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_COMPTIME_INT));
// Index 39: comptime_float
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_COMPTIME_FLOAT));
// Index 40: noreturn
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_NORETURN));
// Index 41: anyframe (with no return type = IP_INDEX_NONE)
ipAppendItem(&ip, ipMakeAnyframeType(IP_INDEX_NONE));
// Index 42: null type
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_NULL));
// Index 43: undefined type
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_UNDEFINED));
// Index 44: enum_literal type
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_ENUM_LITERAL));
// Index 45: *usize (single-item pointer to usize)
ipAppendItem(&ip,
ipMakePtrType(IP_INDEX_USIZE_TYPE, IP_INDEX_NONE, PTR_FLAGS_SIZE_ONE));
// Index 46: *const comptime_int
ipAppendItem(&ip,
ipMakePtrType(IP_INDEX_COMPTIME_INT_TYPE, IP_INDEX_NONE,
PTR_FLAGS_SIZE_ONE | PTR_FLAGS_IS_CONST));
// Index 47: [*]u8
ipAppendItem(&ip,
ipMakePtrType(IP_INDEX_U8_TYPE, IP_INDEX_NONE, PTR_FLAGS_SIZE_MANY));
// Index 48: [*]const u8
ipAppendItem(&ip,
ipMakePtrType(IP_INDEX_U8_TYPE, IP_INDEX_NONE,
PTR_FLAGS_SIZE_MANY | PTR_FLAGS_IS_CONST));
// Index 49: [*:0]const u8
ipAppendItem(&ip,
ipMakePtrType(IP_INDEX_U8_TYPE, IP_INDEX_ZERO_U8,
PTR_FLAGS_SIZE_MANY | PTR_FLAGS_IS_CONST));
// Index 50: []const u8 — stored as type_slice wrapping [*]const u8
{
InternPoolKey sk;
memset(&sk, 0, sizeof(sk));
sk.tag = IP_KEY_SLICE;
sk.data.slice = IP_INDEX_MANYPTR_CONST_U8_TYPE; // index 48
ipAppendItem(&ip, sk);
}
// Index 51: [:0]const u8 — stored as type_slice wrapping [*:0]const u8
{
InternPoolKey sk;
memset(&sk, 0, sizeof(sk));
sk.tag = IP_KEY_SLICE;
sk.data.slice = IP_INDEX_MANYPTR_CONST_U8_SENTINEL_0_TYPE; // 49
ipAppendItem(&ip, sk);
}
// Indices 52-98: vector types
// Matching InternPool.Index enum order exactly.
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_I8_TYPE)); // 52
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_I8_TYPE)); // 53
ipAppendItem(&ip, ipMakeVectorType(32, IP_INDEX_I8_TYPE)); // 54
ipAppendItem(&ip, ipMakeVectorType(64, IP_INDEX_I8_TYPE)); // 55
ipAppendItem(&ip, ipMakeVectorType(1, IP_INDEX_U8_TYPE)); // 56
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_U8_TYPE)); // 57
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_U8_TYPE)); // 58
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_U8_TYPE)); // 59
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_U8_TYPE)); // 60
ipAppendItem(&ip, ipMakeVectorType(32, IP_INDEX_U8_TYPE)); // 61
ipAppendItem(&ip, ipMakeVectorType(64, IP_INDEX_U8_TYPE)); // 62
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_I16_TYPE)); // 63
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_I16_TYPE)); // 64
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_I16_TYPE)); // 65
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_I16_TYPE)); // 66
ipAppendItem(&ip, ipMakeVectorType(32, IP_INDEX_I16_TYPE)); // 67
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_U16_TYPE)); // 68
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_U16_TYPE)); // 69
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_U16_TYPE)); // 70
ipAppendItem(&ip, ipMakeVectorType(32, IP_INDEX_U16_TYPE)); // 71
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_I32_TYPE)); // 72
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_I32_TYPE)); // 73
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_I32_TYPE)); // 74
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_I32_TYPE)); // 75
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_U32_TYPE)); // 76
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_U32_TYPE)); // 77
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_U32_TYPE)); // 78
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_I64_TYPE)); // 79
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_I64_TYPE)); // 80
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_I64_TYPE)); // 81
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_U64_TYPE)); // 82
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_U64_TYPE)); // 83
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_U64_TYPE)); // 84
ipAppendItem(&ip, ipMakeVectorType(1, IP_INDEX_U128_TYPE)); // 85
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_U128_TYPE)); // 86
ipAppendItem(&ip, ipMakeVectorType(1, IP_INDEX_U256_TYPE)); // 87
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_F16_TYPE)); // 88
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_F16_TYPE)); // 89
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_F16_TYPE)); // 90
ipAppendItem(&ip, ipMakeVectorType(32, IP_INDEX_F16_TYPE)); // 91
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_F32_TYPE)); // 92
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_F32_TYPE)); // 93
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_F32_TYPE)); // 94
ipAppendItem(&ip, ipMakeVectorType(16, IP_INDEX_F32_TYPE)); // 95
ipAppendItem(&ip, ipMakeVectorType(2, IP_INDEX_F64_TYPE)); // 96
ipAppendItem(&ip, ipMakeVectorType(4, IP_INDEX_F64_TYPE)); // 97
ipAppendItem(&ip, ipMakeVectorType(8, IP_INDEX_F64_TYPE)); // 98
// Index 99: ?noreturn
ipAppendItem(&ip, ipMakeOptType(IP_INDEX_NORETURN_TYPE));
// Index 100: anyerror!void
ipAppendItem(
&ip, ipMakeErrorUnionType(IP_INDEX_ANYERROR_TYPE, IP_INDEX_VOID_TYPE));
// Index 101: adhoc_inferred_error_set
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_ADHOC_INFERRED_ERROR_SET));
// Index 102: generic_poison
ipAppendItem(&ip, ipMakeSimpleType(SIMPLE_TYPE_GENERIC_POISON));
// Index 103: empty_tuple_type (tuple with zero elements)
ipAppendItem(&ip, ipMakeTupleType());
// Index 104: undef (untyped) -> simple_value undefined
ipAppendItem(&ip, ipMakeSimpleValue(SIMPLE_VALUE_UNDEFINED));
// Index 105: undef bool
ipAppendItem(&ip, ipMakeUndef(IP_INDEX_BOOL_TYPE));
// Index 106: undef usize
ipAppendItem(&ip, ipMakeUndef(IP_INDEX_USIZE_TYPE));
// Index 107: undef u1
ipAppendItem(&ip, ipMakeUndef(IP_INDEX_U1_TYPE));
// Index 108: zero (comptime_int)
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_COMPTIME_INT_TYPE, 0, false));
// Index 109: zero_usize
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_USIZE_TYPE, 0, false));
// Index 110: zero_u1
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_U1_TYPE, 0, false));
// Index 111: zero_u8
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_U8_TYPE, 0, false));
// Index 112: one (comptime_int)
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_COMPTIME_INT_TYPE, 1, false));
// Index 113: one_usize
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_USIZE_TYPE, 1, false));
// Index 114: one_u1
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_U1_TYPE, 1, false));
// Index 115: one_u8
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_U8_TYPE, 1, false));
// Index 116: four_u8
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_U8_TYPE, 4, false));
// Index 117: negative_one (comptime_int, -1)
ipAppendItem(&ip, ipMakeTypedInt(IP_INDEX_COMPTIME_INT_TYPE, 1, true));
// Index 118: void_value
ipAppendItem(&ip, ipMakeSimpleValue(SIMPLE_VALUE_VOID));
// Index 119: unreachable_value
ipAppendItem(&ip, ipMakeSimpleValue(SIMPLE_VALUE_UNREACHABLE));
// Index 120: null_value
ipAppendItem(&ip, ipMakeSimpleValue(SIMPLE_VALUE_NULL));
// Index 121: bool_true
ipAppendItem(&ip, ipMakeSimpleValue(SIMPLE_VALUE_TRUE));
// Index 122: bool_false
ipAppendItem(&ip, ipMakeSimpleValue(SIMPLE_VALUE_FALSE));
// Index 123: empty_tuple (value)
ipAppendItem(&ip, ipMakeSimpleValue(SIMPLE_VALUE_EMPTY_TUPLE));
// Build hash table from pre-interned entries.
ipRebuildHash(&ip);
return ip;
}
void ipDeinit(InternPool* ip) {
free(ip->items);
free(ip->hash_table);
free(ip->string_bytes);
free(ip->extra);
free(ip->navs);
ip->items = NULL;
ip->hash_table = NULL;
ip->string_bytes = NULL;
ip->extra = NULL;
ip->navs = NULL;
ip->items_len = 0;
ip->items_cap = 0;
ip->hash_cap = 0;
ip->string_bytes_len = 0;
ip->string_bytes_cap = 0;
ip->extra_len = 0;
ip->extra_cap = 0;
ip->nav_count = 0;
ip->nav_cap = 0;
}
InternPoolIndex ipIntern(InternPool* ip, InternPoolKey key) {
// Check load factor and grow if needed.
if (ip->items_len * 4 >= ip->hash_cap * 3) {
ipGrowHash(ip);
}
uint32_t h = ipHashKey(&key) & (ip->hash_cap - 1);
while (ip->hash_table[h] != IP_INDEX_NONE) {
uint32_t idx = ip->hash_table[h];
if (ipKeysEqual(&ip->items[idx], &key)) {
// Shard simulation: skip matches in the preamble memoized
// range, EXCEPT for:
// 1. Entries in the CC sub-range (in Zig's local shard)
// 2. comptime_int entries (shared across all shards)
// Ported from upstream Zig's sharded IP behavior.
if (idx >= ip->skip_dedup_start && idx < ip->skip_dedup_end
&& !(idx >= ip->cc_keep_start && idx < ip->cc_keep_end)
&& !(ip->items[idx].tag == IP_KEY_INT
&& ip->items[idx].data.int_val.ty
== IP_INDEX_COMPTIME_INT_TYPE)) {
h = (h + 1) & (ip->hash_cap - 1);
continue;
}
return idx;
}
h = (h + 1) & (ip->hash_cap - 1);
}
// Not found: append new item.
uint32_t new_index = ip->items_len;
ipAppendItem(ip, key);
ip->hash_table[h] = new_index;
return new_index;
}
InternPoolIndex ipForceIntern(InternPool* ip, InternPoolKey key) {
uint32_t new_index = ip->items_len;
ipAppendItem(ip, key);
return new_index;
}
InternPoolKey ipIndexToKey(const InternPool* ip, InternPoolIndex index) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
if (index < ip->items_len) {
key = ip->items[index];
}
return key;
}
InternPoolIndex ipTypeOf(const InternPool* ip, InternPoolIndex index) {
// Matching upstream InternPool.typeOf: hardcoded switch on pre-interned
// indices, then key-based lookup for dynamic entries.
switch (index) {
// All type indices (0-103) return type_type.
case IP_INDEX_U0_TYPE:
case IP_INDEX_I0_TYPE:
case IP_INDEX_U1_TYPE:
case IP_INDEX_U8_TYPE:
case IP_INDEX_I8_TYPE:
case IP_INDEX_U16_TYPE:
case IP_INDEX_I16_TYPE:
case IP_INDEX_U29_TYPE:
case IP_INDEX_U32_TYPE:
case IP_INDEX_I32_TYPE:
case IP_INDEX_U64_TYPE:
case IP_INDEX_I64_TYPE:
case IP_INDEX_U80_TYPE:
case IP_INDEX_U128_TYPE:
case IP_INDEX_I128_TYPE:
case IP_INDEX_U256_TYPE:
case IP_INDEX_USIZE_TYPE:
case IP_INDEX_ISIZE_TYPE:
case IP_INDEX_C_CHAR_TYPE:
case IP_INDEX_C_SHORT_TYPE:
case IP_INDEX_C_USHORT_TYPE:
case IP_INDEX_C_INT_TYPE:
case IP_INDEX_C_UINT_TYPE:
case IP_INDEX_C_LONG_TYPE:
case IP_INDEX_C_ULONG_TYPE:
case IP_INDEX_C_LONGLONG_TYPE:
case IP_INDEX_C_ULONGLONG_TYPE:
case IP_INDEX_C_LONGDOUBLE_TYPE:
case IP_INDEX_F16_TYPE:
case IP_INDEX_F32_TYPE:
case IP_INDEX_F64_TYPE:
case IP_INDEX_F80_TYPE:
case IP_INDEX_F128_TYPE:
case IP_INDEX_ANYOPAQUE_TYPE:
case IP_INDEX_BOOL_TYPE:
case IP_INDEX_VOID_TYPE:
case IP_INDEX_TYPE_TYPE:
case IP_INDEX_ANYERROR_TYPE:
case IP_INDEX_COMPTIME_INT_TYPE:
case IP_INDEX_COMPTIME_FLOAT_TYPE:
case IP_INDEX_NORETURN_TYPE:
case IP_INDEX_ANYFRAME_TYPE:
case IP_INDEX_NULL_TYPE:
case IP_INDEX_UNDEFINED_TYPE:
case IP_INDEX_ENUM_LITERAL_TYPE:
case IP_INDEX_PTR_USIZE_TYPE:
case IP_INDEX_PTR_CONST_COMPTIME_INT_TYPE:
case IP_INDEX_MANYPTR_U8_TYPE:
case IP_INDEX_MANYPTR_CONST_U8_TYPE:
case IP_INDEX_MANYPTR_CONST_U8_SENTINEL_0_TYPE:
case IP_INDEX_SLICE_CONST_U8_TYPE:
case IP_INDEX_SLICE_CONST_U8_SENTINEL_0_TYPE:
case IP_INDEX_VECTOR_8_I8_TYPE:
case IP_INDEX_VECTOR_16_I8_TYPE:
case IP_INDEX_VECTOR_32_I8_TYPE:
case IP_INDEX_VECTOR_64_I8_TYPE:
case IP_INDEX_VECTOR_1_U8_TYPE:
case IP_INDEX_VECTOR_2_U8_TYPE:
case IP_INDEX_VECTOR_4_U8_TYPE:
case IP_INDEX_VECTOR_8_U8_TYPE:
case IP_INDEX_VECTOR_16_U8_TYPE:
case IP_INDEX_VECTOR_32_U8_TYPE:
case IP_INDEX_VECTOR_64_U8_TYPE:
case IP_INDEX_VECTOR_2_I16_TYPE:
case IP_INDEX_VECTOR_4_I16_TYPE:
case IP_INDEX_VECTOR_8_I16_TYPE:
case IP_INDEX_VECTOR_16_I16_TYPE:
case IP_INDEX_VECTOR_32_I16_TYPE:
case IP_INDEX_VECTOR_4_U16_TYPE:
case IP_INDEX_VECTOR_8_U16_TYPE:
case IP_INDEX_VECTOR_16_U16_TYPE:
case IP_INDEX_VECTOR_32_U16_TYPE:
case IP_INDEX_VECTOR_2_I32_TYPE:
case IP_INDEX_VECTOR_4_I32_TYPE:
case IP_INDEX_VECTOR_8_I32_TYPE:
case IP_INDEX_VECTOR_16_I32_TYPE:
case IP_INDEX_VECTOR_4_U32_TYPE:
case IP_INDEX_VECTOR_8_U32_TYPE:
case IP_INDEX_VECTOR_16_U32_TYPE:
case IP_INDEX_VECTOR_2_I64_TYPE:
case IP_INDEX_VECTOR_4_I64_TYPE:
case IP_INDEX_VECTOR_8_I64_TYPE:
case IP_INDEX_VECTOR_2_U64_TYPE:
case IP_INDEX_VECTOR_4_U64_TYPE:
case IP_INDEX_VECTOR_8_U64_TYPE:
case IP_INDEX_VECTOR_1_U128_TYPE:
case IP_INDEX_VECTOR_2_U128_TYPE:
case IP_INDEX_VECTOR_1_U256_TYPE:
case IP_INDEX_VECTOR_4_F16_TYPE:
case IP_INDEX_VECTOR_8_F16_TYPE:
case IP_INDEX_VECTOR_16_F16_TYPE:
case IP_INDEX_VECTOR_32_F16_TYPE:
case IP_INDEX_VECTOR_2_F32_TYPE:
case IP_INDEX_VECTOR_4_F32_TYPE:
case IP_INDEX_VECTOR_8_F32_TYPE:
case IP_INDEX_VECTOR_16_F32_TYPE:
case IP_INDEX_VECTOR_2_F64_TYPE:
case IP_INDEX_VECTOR_4_F64_TYPE:
case IP_INDEX_VECTOR_8_F64_TYPE:
case IP_INDEX_OPTIONAL_NORETURN_TYPE:
case IP_INDEX_ANYERROR_VOID_ERROR_UNION_TYPE:
case IP_INDEX_ADHOC_INFERRED_ERROR_SET_TYPE:
case IP_INDEX_GENERIC_POISON_TYPE:
case IP_INDEX_EMPTY_TUPLE_TYPE:
return IP_INDEX_TYPE_TYPE;
// Pre-interned values with hardcoded types (matching upstream).
case IP_INDEX_UNDEF:
return IP_INDEX_UNDEFINED_TYPE;
case IP_INDEX_ZERO:
case IP_INDEX_ONE:
case IP_INDEX_NEGATIVE_ONE:
return IP_INDEX_COMPTIME_INT_TYPE;
case IP_INDEX_UNDEF_USIZE:
case IP_INDEX_ZERO_USIZE:
case IP_INDEX_ONE_USIZE:
return IP_INDEX_USIZE_TYPE;
case IP_INDEX_UNDEF_U1:
case IP_INDEX_ZERO_U1:
case IP_INDEX_ONE_U1:
return IP_INDEX_U1_TYPE;
case IP_INDEX_ZERO_U8:
case IP_INDEX_ONE_U8:
case IP_INDEX_FOUR_U8:
return IP_INDEX_U8_TYPE;
case IP_INDEX_VOID_VALUE:
return IP_INDEX_VOID_TYPE;
case IP_INDEX_UNREACHABLE_VALUE:
return IP_INDEX_NORETURN_TYPE;
case IP_INDEX_NULL_VALUE:
return IP_INDEX_NULL_TYPE;
case IP_INDEX_UNDEF_BOOL:
case IP_INDEX_BOOL_TRUE:
case IP_INDEX_BOOL_FALSE:
return IP_INDEX_BOOL_TYPE;
case IP_INDEX_EMPTY_TUPLE:
return IP_INDEX_EMPTY_TUPLE_TYPE;
default:
break;
}
// Dynamic entries: look up key and determine type from it.
if (index >= ip->items_len) {
return IP_INDEX_NONE;
}
InternPoolKey key = ip->items[index];
switch (key.tag) {
case IP_KEY_INT_TYPE:
case IP_KEY_PTR_TYPE:
case IP_KEY_ARRAY_TYPE:
case IP_KEY_VECTOR_TYPE:
case IP_KEY_OPT_TYPE:
case IP_KEY_ANYFRAME_TYPE:
case IP_KEY_ERROR_UNION_TYPE:
case IP_KEY_SIMPLE_TYPE:
case IP_KEY_STRUCT_TYPE:
case IP_KEY_TUPLE_TYPE:
case IP_KEY_UNION_TYPE:
case IP_KEY_OPAQUE_TYPE:
case IP_KEY_ENUM_TYPE:
case IP_KEY_FUNC_TYPE:
case IP_KEY_ERROR_SET_TYPE:
case IP_KEY_INFERRED_ERROR_SET_TYPE:
case IP_KEY_SLICE:
return IP_INDEX_TYPE_TYPE;
case IP_KEY_UNDEF:
return key.data.undef;
case IP_KEY_EMPTY_ENUM_VALUE:
return key.data.empty_enum_value;
case IP_KEY_SIMPLE_VALUE:
switch (key.data.simple_value) {
case SIMPLE_VALUE_UNDEFINED:
return IP_INDEX_UNDEFINED_TYPE;
case SIMPLE_VALUE_VOID:
return IP_INDEX_VOID_TYPE;
case SIMPLE_VALUE_NULL:
return IP_INDEX_NULL_TYPE;
case SIMPLE_VALUE_EMPTY_TUPLE:
return IP_INDEX_EMPTY_TUPLE_TYPE;
case SIMPLE_VALUE_TRUE:
case SIMPLE_VALUE_FALSE:
return IP_INDEX_BOOL_TYPE;
case SIMPLE_VALUE_UNREACHABLE:
return IP_INDEX_NORETURN_TYPE;
}
return IP_INDEX_NONE;
case IP_KEY_INT:
return key.data.int_val.ty;
case IP_KEY_FLOAT:
return key.data.float_val.ty;
case IP_KEY_ENUM_LITERAL:
return IP_INDEX_ENUM_LITERAL_TYPE;
case IP_KEY_ENUM_TAG:
return key.data.enum_tag.ty;
case IP_KEY_PTR_NAV:
return key.data.ptr_nav.ty;
case IP_KEY_FUNC:
return key.data.func_decl.ty;
case IP_KEY_FUNC_INSTANCE:
return key.data.func_instance.ty;
case IP_KEY_MEMOIZED_CALL:
return IP_INDEX_VOID_TYPE;
case IP_KEY_BYTES:
return key.data.bytes.ty;
case IP_KEY_PTR_UAV:
return key.data.ptr_uav.ty;
case IP_KEY_PTR_UAV_ALIGNED:
return key.data.ptr_uav_aligned.ty;
case IP_KEY_PTR_SLICE:
return key.data.ptr_slice.ty;
case IP_KEY_OPT:
return key.data.opt;
case IP_KEY_OPT_PAYLOAD:
return key.data.opt_payload.ty;
case IP_KEY_PTR_COMPTIME_ALLOC:
return key.data.ptr_comptime_alloc.ty;
case IP_KEY_PTR_FIELD:
return key.data.ptr_field.ty;
case IP_KEY_PTR_OPT_PAYLOAD:
return key.data.ptr_opt_payload.ty;
case IP_KEY_OPT_NULL:
return key.data.opt_null;
case IP_KEY_REPEATED:
return IP_INDEX_NONE; // type depends on context
case IP_KEY_INT_U16:
return IP_INDEX_U16_TYPE;
default:
break;
}
return IP_INDEX_NONE;
}
// --- Nav management ---
// Ported from InternPool.createDeclNav / InternPool.getNav.
uint32_t ipCreateDeclNav(InternPool* ip, uint32_t name, uint32_t fqn,
uint32_t zir_index, uint32_t namespace_idx, bool is_pub, bool is_const) {
assert(ip->nav_count < IP_MAX_NAVS);
if (ip->nav_count >= ip->nav_cap) {
uint32_t new_cap = ip->nav_cap * 2;
Nav* new_navs = realloc(ip->navs, new_cap * sizeof(Nav));
if (!new_navs)
exit(1);
ip->navs = new_navs;
ip->nav_cap = new_cap;
}
uint32_t idx = ip->nav_count++;
Nav* nav = &ip->navs[idx];
memset(nav, 0, sizeof(*nav));
nav->name = name;
nav->fqn = fqn;
nav->zir_index = zir_index;
nav->namespace_idx = namespace_idx;
nav->resolved_type = IP_INDEX_NONE;
nav->resolved_val = IP_INDEX_NONE;
nav->is_pub = is_pub;
nav->is_const = is_const;
return idx;
}
Nav* ipGetNav(InternPool* ip, uint32_t nav_index) {
assert(nav_index < ip->nav_count);
return &ip->navs[nav_index];
}
void ipResetNavs(InternPool* ip) { ip->nav_count = 0; }
uint32_t ipNavCount(const InternPool* ip) { return ip->nav_count; }
// --- String interning ---
// Add a null-terminated string to the IP string table. Returns the
// NullTerminatedString index. Searches for an existing copy first.
// Ported from InternPool.getOrPutString.
uint32_t ipGetOrPutString(InternPool* ip, const char* str) {
uint32_t slen = (uint32_t)strlen(str);
// Search for existing string.
for (uint32_t i = 0; i + slen < ip->string_bytes_len; i++) {
if (memcmp(&ip->string_bytes[i], str, slen) == 0
&& ip->string_bytes[i + slen] == 0) {
return i;
}
}
// Not found: append.
uint32_t needed = slen + 1; // include null terminator
while (ip->string_bytes_len + needed > ip->string_bytes_cap) {
uint32_t new_cap = ip->string_bytes_cap * 2;
if (new_cap == 0)
new_cap = 256;
ip->string_bytes = realloc(ip->string_bytes, new_cap);
ip->string_bytes_cap = new_cap;
}
uint32_t idx = ip->string_bytes_len;
memcpy(&ip->string_bytes[idx], str, slen);
ip->string_bytes[idx + slen] = 0;
ip->string_bytes_len += needed;
return idx;
}