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>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
/// `num_passing` controls how many files are tested and pre-generated.
|
||||
/// Both build.zig and stages_test.zig import this file.
|
||||
/// To enable more tests: just increment `num_passing`.
|
||||
pub const num_passing: usize = 84;
|
||||
pub const num_passing: usize = 85;
|
||||
|
||||
pub const files = [_][]const u8{
|
||||
"stage0/sema_tests/empty.zig",
|
||||
|
||||
@@ -80,6 +80,10 @@ static uint32_t ipHashKey(const InternPoolKey* key) {
|
||||
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);
|
||||
@@ -223,6 +227,10 @@ static bool ipKeysEqual(const InternPoolKey* a, const InternPoolKey* b) {
|
||||
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;
|
||||
@@ -982,6 +990,9 @@ InternPoolIndex ipTypeOf(const InternPool* ip, InternPoolIndex index) {
|
||||
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;
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ typedef enum {
|
||||
IP_KEY_OPT_NULL,
|
||||
IP_KEY_REPEATED,
|
||||
IP_KEY_INT_U16,
|
||||
IP_KEY_FUNC_INSTANCE,
|
||||
} InternPoolKeyTag;
|
||||
|
||||
// --- InternPoolKey (tagged union) ---
|
||||
@@ -351,6 +352,11 @@ typedef struct {
|
||||
uint32_t owner_nav; // Nav index
|
||||
InternPoolIndex ty; // function type IP index
|
||||
} func_decl;
|
||||
struct {
|
||||
InternPoolIndex generic_owner; // func_decl IP index
|
||||
InternPoolIndex ty; // monomorphized function type IP index
|
||||
uint32_t owner_nav; // Nav index
|
||||
} func_instance;
|
||||
TypedInt int_val;
|
||||
InternPoolIndex err;
|
||||
InternPoolIndex error_union;
|
||||
|
||||
@@ -5933,6 +5933,7 @@ static AirInstRef semaAnalyzeCall(Sema* sema, SemaBlock* block, uint32_t inst,
|
||||
// Ported from src/Sema.zig analyzeCall (Sema.zig:7575-7601).
|
||||
uint32_t runtime_args_count = 0;
|
||||
AirInstRef runtime_arg_refs[16];
|
||||
TypeIndex runtime_param_types[16];
|
||||
uint32_t pi = 0;
|
||||
for (uint32_t p = 0; p < param_body_len; p++) {
|
||||
ZirInstTag ptag = sema->code.inst_tags[param_body[p]];
|
||||
@@ -5969,6 +5970,8 @@ static AirInstRef semaAnalyzeCall(Sema* sema, SemaBlock* block, uint32_t inst,
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime_param_types[runtime_args_count]
|
||||
= semaTypeOf(sema, arg);
|
||||
runtime_arg_refs[runtime_args_count++] = arg;
|
||||
}
|
||||
pi++;
|
||||
@@ -6027,6 +6030,60 @@ static AirInstRef semaAnalyzeCall(Sema* sema, SemaBlock* block, uint32_t inst,
|
||||
}
|
||||
}
|
||||
|
||||
// For generic functions, create a func_instance entry.
|
||||
// Ported from Sema.zig:7549 / InternPool.getFuncInstance.
|
||||
// The monomorphized function has its own func_type (runtime
|
||||
// params only) and a func_instance referencing the generic owner.
|
||||
if (is_generic && func_val_ip != IP_INDEX_NONE) {
|
||||
InternPoolIndex generic_owner_ip = func_val_ip;
|
||||
InternPoolIndex generic_owner_ty
|
||||
= sema->ip->items[generic_owner_ip].data.func_decl.ty;
|
||||
uint8_t owner_cc
|
||||
= sema->ip->items[generic_owner_ty].data.func_type.cc;
|
||||
|
||||
// Create monomorphized func_type with runtime params only.
|
||||
InternPoolKey mono_ft;
|
||||
memset(&mono_ft, 0, sizeof(mono_ft));
|
||||
mono_ft.tag = IP_KEY_FUNC_TYPE;
|
||||
mono_ft.data.func_type.return_type = ret_ty;
|
||||
mono_ft.data.func_type.param_count = runtime_args_count;
|
||||
mono_ft.data.func_type.cc = owner_cc;
|
||||
for (uint32_t ri = 0;
|
||||
ri < runtime_args_count && ri < FUNC_TYPE_MAX_PARAMS; ri++)
|
||||
mono_ft.data.func_type.param_types[ri]
|
||||
= runtime_param_types[ri];
|
||||
InternPoolIndex mono_ft_ip = (runtime_args_count > 0)
|
||||
? ipIntern(sema->ip, mono_ft)
|
||||
: ipForceIntern(sema->ip, mono_ft);
|
||||
|
||||
// Pre-compute the func_instance IP index (next slot).
|
||||
InternPoolIndex fi_ip = sema->ip->items_len;
|
||||
|
||||
// Create nav for the func_instance. Ported from
|
||||
// InternPool.finishFuncInstance.
|
||||
uint32_t owner_nav_idx
|
||||
= sema->ip->items[generic_owner_ip].data.func_decl.owner_nav;
|
||||
const Nav* owner_nav = ipGetNav(sema->ip, owner_nav_idx);
|
||||
const char* owner_name
|
||||
= (const char*)&sema->ip->string_bytes[owner_nav->name];
|
||||
char anon_name[256];
|
||||
snprintf(anon_name, sizeof(anon_name), "%s__anon_%u", owner_name,
|
||||
fi_ip);
|
||||
uint32_t anon_str = ipGetOrPutString(sema->ip, anon_name);
|
||||
uint32_t fi_nav = ipCreateDeclNav(sema->ip, anon_str, anon_str,
|
||||
owner_nav->zir_index, owner_nav->namespace_idx,
|
||||
owner_nav->is_pub, owner_nav->is_const);
|
||||
|
||||
// Intern the func_instance entry.
|
||||
InternPoolKey fi_key;
|
||||
memset(&fi_key, 0, sizeof(fi_key));
|
||||
fi_key.tag = IP_KEY_FUNC_INSTANCE;
|
||||
fi_key.data.func_instance.generic_owner = generic_owner_ip;
|
||||
fi_key.data.func_instance.ty = mono_ft_ip;
|
||||
fi_key.data.func_instance.owner_nav = fi_nav;
|
||||
func_val_ip = ipForceIntern(sema->ip, fi_key);
|
||||
}
|
||||
|
||||
// Emit CALL extra: {args_len, arg_refs[0..args_len]}.
|
||||
uint32_t call_extra = semaAddExtra(sema, runtime_args_count);
|
||||
for (uint32_t a = 0; a < runtime_args_count; a++)
|
||||
|
||||
@@ -98,6 +98,8 @@ static const char* ipKeyTagName(InternPoolKeyTag tag) {
|
||||
return "repeated";
|
||||
case IP_KEY_INT_U16:
|
||||
return "int_u16";
|
||||
case IP_KEY_FUNC_INSTANCE:
|
||||
return "func_instance";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
@@ -140,6 +142,11 @@ void verboseIpPrint(FILE* out, const InternPool* ip) {
|
||||
fprintf(out, " nav=%u ty=%u", key.data.func_decl.owner_nav,
|
||||
key.data.func_decl.ty);
|
||||
break;
|
||||
case IP_KEY_FUNC_INSTANCE:
|
||||
fprintf(out, " generic_owner=%u ty=%u nav=%u",
|
||||
key.data.func_instance.generic_owner,
|
||||
key.data.func_instance.ty, key.data.func_instance.owner_nav);
|
||||
break;
|
||||
case IP_KEY_ENUM_LITERAL:
|
||||
fprintf(out, " str_idx=%u", key.data.enum_literal);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user