sema: reuse callee func_decl for non-inline calls, bump 80→84

Fix non-inline function call to reuse the callee's existing func_decl
IP entry instead of creating a new one with func_inst as owner_nav.
Ported from upstream Sema.zig analyzeCall: func_val references the
resolved callee function, not a newly-created entry.

The callee is looked up by name in the file namespace. If the nav's
resolved_type already points to a func_decl (IP_KEY_FUNC), it's used
directly. Otherwise, the func_type from resolved_type is used to
construct and deduplicate the func_decl key.

Also fixes the coercion dedup fix from the previous commit: switched
semaCoerceIntRef from ipForceIntern to ipIntern now that skip_dedup
handles cross-shard separation.

Tests 80-83 now pass (call_inside_runtime_conditional, multi_func_call,
runtime_conditional_with_early_return, field_access_chain).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-03 07:41:10 +00:00
parent e6cda567d0
commit 2cfd4ac668
2 changed files with 49 additions and 16 deletions

View File

@@ -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 = 80;
pub const num_passing: usize = 84;
pub const files = [_][]const u8{
"stage0/sema_tests/empty.zig",

View File

@@ -6606,21 +6606,54 @@ static AirInstRef zirCall(
}
}
// Intern a function type with the resolved return type.
InternPoolKey ft_key;
memset(&ft_key, 0, sizeof(ft_key));
ft_key.tag = IP_KEY_FUNC_TYPE;
ft_key.data.func_type.return_type = ret_ty;
ft_key.data.func_type.param_count = runtime_args_count;
InternPoolIndex func_type_ip = ipIntern(sema->ip, ft_key);
// Intern a function value (unique per ZIR func inst).
InternPoolKey fv_key;
memset(&fv_key, 0, sizeof(fv_key));
fv_key.tag = IP_KEY_FUNC;
fv_key.data.func_decl.owner_nav = func_inst;
fv_key.data.func_decl.ty = func_type_ip;
InternPoolIndex func_val_ip = ipIntern(sema->ip, fv_key);
// Use the callee's existing func_decl. Ported from upstream
// Sema.zig analyzeCall: func_val is the resolved callee, not
// a newly-created func entry. Look up the callee's nav by name
// in the file namespace, then use its existing func_decl.
InternPoolIndex func_val_ip = IP_INDEX_NONE;
{
uint32_t callee_nav = UINT32_MAX;
if (callee_name_idx != 0
&& sema->zcu->root_file_idx != UINT32_MAX) {
const char* cname
= (const char*)&sema->code.string_bytes[callee_name_idx];
uint32_t rns
= sema->zcu->file_namespaces[sema->zcu->root_file_idx];
callee_nav = findNavInNamespace(sema, rns, cname);
}
if (callee_nav != UINT32_MAX) {
const Nav* cn = ipGetNav(sema->ip, callee_nav);
InternPoolIndex resolved = cn->resolved_type;
// If resolved points to a func_decl, use it directly.
// If it points to a func_type, construct the func_decl
// key and look it up.
if (resolved != IP_INDEX_NONE
&& sema->ip->items[resolved].tag == IP_KEY_FUNC) {
func_val_ip = resolved;
} else if (resolved != IP_INDEX_NONE) {
InternPoolKey fv_key;
memset(&fv_key, 0, sizeof(fv_key));
fv_key.tag = IP_KEY_FUNC;
fv_key.data.func_decl.owner_nav = callee_nav;
fv_key.data.func_decl.ty = resolved;
func_val_ip = ipIntern(sema->ip, fv_key);
}
} else {
// Fallback: create with func_inst as nav.
InternPoolKey ft_key;
memset(&ft_key, 0, sizeof(ft_key));
ft_key.tag = IP_KEY_FUNC_TYPE;
ft_key.data.func_type.return_type = ret_ty;
ft_key.data.func_type.param_count = runtime_args_count;
InternPoolIndex func_type_ip = ipForceIntern(sema->ip, ft_key);
InternPoolKey fv_key;
memset(&fv_key, 0, sizeof(fv_key));
fv_key.tag = IP_KEY_FUNC;
fv_key.data.func_decl.owner_nav = func_inst;
fv_key.data.func_decl.ty = func_type_ip;
func_val_ip = ipIntern(sema->ip, fv_key);
}
}
// Emit CALL extra: {args_len, arg_refs[0..args_len]}.
uint32_t call_extra = semaAddExtra(sema, runtime_args_count);