fix(call): 缺参 fail-fast 误杀参数匹配的构造调用 + 行号修复

- _call_method_on_ptr 的 elif found_func 分支原无条件 fatal,即使实参与形参匹配(如 JsonValue(pool) 构造 __new__(self, pool))也误报;改为数 found_func 形参数量,仅 total_count < fp_count 时缺参报错。
- 构造路径(_translate_struct_ctor/_translate_struct_ctor_kw)的 _call_method_on_ptr 调用补传诊断节点(取首个实参 AST),fatal_error 不再显示 line 0。
This commit is contained in:
TermiNexus committed 2026-08-13 02:41:52 +08:00
1 parent e796e7fc2b
commit 0c94f52f21
1 file changed
+28 -8
+28 -8
View File
@@ -2023,6 +2023,11 @@ class CallGenMixin:
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return llvmlite.ConstZero(pool, struct_ty)
# 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的
# fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点)
diag_node_ct: ast.AST | t.CPtr = None
if cargs is not None and len(cargs) > 0:
diag_node_ct = cargs.get(0)
# 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错)
ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
@@ -2081,7 +2086,7 @@ class CallGenMixin:
new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr(
pool, builder, mod, class_name,
"__new__", tmp, new_arg_vals, new_arg_count, trans)
"__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
@@ -2099,7 +2104,7 @@ class CallGenMixin:
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
self._call_method_on_ptr(pool, builder, mod, class_name,
"__before_init__", storage_ptr, None, 0, trans)
"__before_init__", storage_ptr, None, 0, trans, diag_node_ct)
# 如果有 __init__,调用 __init__(ptr, args...)
# 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断
@@ -2125,7 +2130,7 @@ class CallGenMixin:
real_arg_count += 1
self._call_method_on_ptr(pool, builder, mod, class_name,
"__init__", storage_ptr, arg_vals, real_arg_count, trans)
"__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct)
elif has_new_flag == 0:
# 无 __init__ 且无 __new__:逐字段 store 参数值
# (有 __new__ 时参数已由 __new__ 消费,不应存入字段)
@@ -2709,9 +2714,19 @@ class CallGenMixin:
node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
mdf_pi += 1
elif found_func is not None:
# 无默认参数信息但有 found_func:剩余形参即调用缺参(无默认值),fail-fast
HandlesType.fatal_error(
node, f"调用 '{lookup_name}' 缺少参数(无默认值)", "TypeError")
# 无函数表默认参数信息但有 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 的形参类型 coerce 每个实参(跳过 self/cls 参数 0)
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
@@ -4268,6 +4283,11 @@ class CallGenMixin:
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return llvmlite.ConstZero(pool, struct_ty)
# 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的
# fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点)
diag_node_ct: ast.AST | t.CPtr = None
if cargs is not None and len(cargs) > 0:
diag_node_ct = cargs.get(0)
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
# 用 find_struct_by_type 规避跨模块同名 find_struct 找错
@@ -4356,7 +4376,7 @@ class CallGenMixin:
new_arg_count += 1
new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr(
pool, builder, mod, class_name,
"__new__", tmp, new_arg_vals, new_arg_count, trans)
"__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
@@ -4402,7 +4422,7 @@ class CallGenMixin:
# 调用 __init__(storage_ptr, *args)
self._call_method_on_ptr(pool, builder, mod, class_name,
"__init__", storage_ptr, init_arg_vals, init_arg_count, trans)
"__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct)
# 返回指针
return storage_ptr