fix(call): 恢复缺参零值兜底,消除默认参数表查不到时的误杀

默认参数表按裸名注册(如 __init__),跨模块 'ClassName.method' 查找常查不到——查不到不等于无默认值(如 Buf.__init__(data, capacity) 缺的 length=0/owned=False 恰为零值)。恢复三处零值兜底(_call_method_on_ptr if/elif、_translate_method_call if、kw 分支),保留快照缺失 fail-fast。
This commit is contained in:
TermiNexus committed 2026-08-13 02:46:52 +08:00
1 parent 0c94f52f21
commit 8b8b716523
1 file changed
+58 -21
+58 -21
View File
@@ -2709,24 +2709,42 @@ class CallGenMixin:
total_count += 1
mdf_pi += 1
continue
# 无默认值即必传参数缺失:fail-fast,绝不零值兜底
HandlesType.fatal_error(
node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
# 无默认值时用零值兜底(需要 found_func 获取参数类型)。
# 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method"
# 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity)
# 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。
if found_func is not None:
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_z: int = 0
while skip_z <= mdf_pi and param_node_z is not None:
param_node_z = llvmlite.param_get_next(param_node_z)
skip_z += 1
if param_node_z is not None:
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
if zero_val is not None:
llvmlite.value_set_next(zero_val, None)
llvmlite.value_set_next(tail, zero_val)
tail = zero_val
total_count += 1
mdf_pi += 1
elif found_func is not None:
# 无函数表默认参数信息但有 found_func:数形参数量判断是否真的缺参。
# 注意:不能无条件 fail-fast——mdf 缺失时 extra_count 可能正好等于
# 形参数量(如 JsonValue(pool) 构造 __new__(self, pool)),
# 参数匹配是合法调用,误报会阻断正常构造。
fp_count: int = 0
fpn_c: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
while fpn_c is not None:
fp_count += 1
fpn_c = llvmlite.param_get_next(fpn_c)
if total_count < fp_count:
# 调用实参(含 self)少于形参(含 self)且无默认值:缺参错误
HandlesType.fatal_error(
node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
# 无默认参数信息但有 found_func:用零值兜底填充缺失参数
# (原逻辑;禁止 fail-fast 误杀——同上,查不到默认参数表 ≠ 无默认值)
param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_idx: int = 0
while skip_idx < total_count and param_node is not None:
param_node = llvmlite.param_get_next(param_node)
skip_idx += 1
while param_node is not None:
missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node)
zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty)
if zero_val2 is not None:
llvmlite.value_set_next(zero_val2, None)
llvmlite.value_set_next(tail, zero_val2)
tail = zero_val2
total_count += 1
param_node = llvmlite.param_get_next(param_node)
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0)
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
@@ -3825,8 +3843,12 @@ class CallGenMixin:
arg_val_k = HandlesExpr.translate_value(
builder, pool, mod, arg_node_k, None, 0, trans)
if arg_val_k is None:
# 缺失参数且无默认值必传:fail-fast,绝不零值兜底(会静默吞掉调用错误)
HandlesType.fatal_error(cl, f"方法 '{lookup_name}' 缺少必传参数", "TypeError")
# 缺失参数:零值兜底(保持参数数量匹配)。
# kw 省略的形参可能有默认值(查不到默认表 ≠ 无默认值),
# 零值兜底与原逻辑一致,禁止 fail-fast 误杀。
pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
if pty_k is not None:
arg_val_k = llvmlite.ConstZero(pool, pty_k)
if arg_val_k is not None:
pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
if pty_k2 is not None:
@@ -3939,9 +3961,24 @@ class CallGenMixin:
total_count += 1
mdf_pi += 1
continue
# 无默认值即必传参数缺失:fail-fast,绝不零值兜底
HandlesType.fatal_error(
cl, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
# 无默认值时用零值兜底(需要 found_func 获取参数类型)。
# 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method"
# 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity)
# 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。
if found_func is not None:
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_z: int = 0
while skip_z <= mdf_pi and param_node_z is not None:
param_node_z = llvmlite.param_get_next(param_node_z)
skip_z += 1
if param_node_z is not None:
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
if zero_val is not None:
llvmlite.value_set_next(zero_val, None)
llvmlite.value_set_next(tail, zero_val)
tail = zero_val
total_count += 1
mdf_pi += 1
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用