fix(tpc): 方法调用/属性调用路径的实参不再静默丢弃(收口"整体错位一格")

类别:a(编译器缺陷)—— 实参求值为空被静默丢弃 ⇒ 后续实参整体前移一格 ⇒ 报出与
真因无关的类型不匹配。

现场(TransPyV/App/lib/core/Gen/Func/FuncGenMixin.vp:1429):
  `return self._lambda_scan_body(trans, ie.orelse, param_names, param_count,
                                 cap_names, cap_allocas, cap_tys, cc6)`
  → `_adjust_args` 报"指针类型 i8* 不能隐式转换为整数参数 i32"。

判据(把报文的"逐项"列表与两种假设逐位对照):
  形参表(stub declare,与该行源码一致):
    self, trans, node=%AST*, param_names=i8*, param_count=i32,
    cap_names=i8*, cap_allocas=i8*, cap_tys=i8*, cap_count=i32
  实测实参:i8*, i32, i8*, i8*, i8*, i32, i32(9 项)
  假设"第 3 个实参(param_names,i8*)被丢弃、末尾由 _fill_default_args 补
  cap_count 的零值 i32"⇒ 预测 arg[2..8]=orelse(i8*), param_count(i32),
  cap_names(i8*), cap_allocas(i8*), cap_tys(i8*), cc6(i32), 补零(i32)
  ⇒ **与实测逐位完全一致**。反证:若丢的是末尾的 cc6,预测序列与实测不符。
  (`_fill_default_args` 只从**末尾**按形参类型补零:HandlesExprCall.py:202-248)

修复:方法调用路径(_HandleMethodCallLlvm)与属性调用回退路径(_HandleCallLlvm)
共 7 处仍写作 `ArgVal = HandleExprLlvm(arg); if ArgVal: append(ArgVal)` —— 正是
`_RequireArgValue` 文档里点名要收口的旧写法(此前只收口了 4 处类构造)。现全部
改为 `_RequireArgValue(...)`:实参求值为空当场 fail-fast,报文含被调者、实参序号与
源表达式,**不丢弃该实参**。

同族未收口(本次不动,逐条记录):`_ApplyKeywordArgs` 的关键字实参(:337)、
`:595` 的 UserCallArgs、`:1262`、`:1336` 共 4 处仍是旧写法。

验证:GetDiagnostics 干净;未跑编译器。
This commit is contained in:
TermiNexus committed 2026-09-29 17:01:14 +08:00
1 parent 62cab0f6c1
commit 783aba1e49
1 file changed
+34 -28
+34 -28
View File
@@ -1036,10 +1036,11 @@ class ExprCallHandle(BaseHandle):
mangled_name = Gen._mangle_func_name(FuncAttr, ModulePath if ModulePath and ModulePath != 't' else None)
if Gen._has_function(mangled_name):
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
for ArgIdx, arg in enumerate(Node.args, start=1):
# 禁止静默丢弃求值为空的实参(会导致后续整体前移一格,
# 报出与真因无关的类型不匹配,见 _RequireArgValue 说明)
CallArgs.append(self._RequireArgValue(
self.HandleExprLlvm(arg), FuncAttr, ArgIdx, arg, Node))
return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{FuncAttr}")
if MethodResult is None or IsZeroResult:
imported = getattr(self.Trans, '_ImportedModules', set())
@@ -1083,10 +1084,10 @@ class ExprCallHandle(BaseHandle):
fallback_func = Gen._find_function(FuncAttr)
if fallback_func is not None:
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
for ArgIdx, arg in enumerate(Node.args, start=1):
# 同 1039:禁止静默丢弃(会导致后续前移一格)
CallArgs.append(self._RequireArgValue(
self.HandleExprLlvm(arg), FuncAttr, ArgIdx, arg, Node))
self._append_eh_msg_out_arg(CallArgs, fallback_func, Gen)
result = Gen.builder.call(fallback_func, CallArgs, name=f"call_{FuncAttr}")
return self._check_eh_return(result, FuncAttr, Gen, called_func=fallback_func)
@@ -1107,10 +1108,10 @@ class ExprCallHandle(BaseHandle):
decl_name = stub_mangled if stub_mangled in getattr(self.Trans.ImportHandler, '_stub_func_cache', {}) else FuncAttr
func_decl = self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=FuncAttr)
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
for ArgIdx, arg in enumerate(Node.args, start=1):
# 同 1039:禁止静默丢弃(会导致后续前移一格)
CallArgs.append(self._RequireArgValue(
self.HandleExprLlvm(arg), FuncAttr, ArgIdx, arg, Node))
self._append_eh_msg_out_arg(CallArgs, func_decl, Gen)
result = Gen.builder.call(func_decl, CallArgs, name=f"call_{FuncAttr}")
return self._check_eh_return(result, FuncAttr, Gen, called_func=func_decl)
@@ -3356,10 +3357,13 @@ class ExprCallHandle(BaseHandle):
_ptypes: list[ir.Type] = func.function_type.args if func is not None else []
for _ai, arg in enumerate(Node.args):
_pt: ir.Type | None = _ptypes[_ai] if _ai < len(_ptypes) else None
ArgVal = self.HandleExprLlvm(
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt))
if ArgVal:
CallArgs.append(ArgVal)
# 不再 `if ArgVal: append`(实参求值为空会被静默丢弃 ⇒ 后续整体
# 前移一格 ⇒ 由 _adjust_args 报出与真因无关的类型不匹配,见
# _RequireArgValue 的说明)。
CallArgs.append(self._RequireArgValue(
self.HandleExprLlvm(
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt)),
mangled_name, _ai + 1, arg, Node))
self._fill_default_args(CallArgs, func, MethodName)
func_ft = getattr(func, 'function_type', None)
is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
@@ -3415,10 +3419,11 @@ class ExprCallHandle(BaseHandle):
_ptypes: list[ir.Type] = _mf.function_type.args
for _ai, arg in enumerate(Node.args):
_pt: ir.Type | None = _ptypes[_ai] if _ai < len(_ptypes) else None
ArgVal = self.HandleExprLlvm(
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt))
if ArgVal:
CallArgs.append(ArgVal)
# 同 3357:禁止静默丢弃求值为空的实参(会导致后续前移一格)
CallArgs.append(self._RequireArgValue(
self.HandleExprLlvm(
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt)),
MethodName, _ai + 1, arg, Node))
func = _mf
self._fill_default_args(CallArgs, func, MethodName)
func_ft = getattr(func, 'function_type', None)
@@ -3484,10 +3489,11 @@ class ExprCallHandle(BaseHandle):
_ptypes: list[ir.Type] = func.function_type.args if func is not None else []
for _ai, arg in enumerate(Node.args):
_pt: ir.Type | None = _ptypes[_ai] if _ai < len(_ptypes) else None
ArgVal = self.HandleExprLlvm(
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt))
if ArgVal:
CallArgs.append(ArgVal)
# 同 3357:禁止静默丢弃求值为空的实参(会导致后续前移一格)
CallArgs.append(self._RequireArgValue(
self.HandleExprLlvm(
arg, ConstWidthHint=DefineUseWidthFromLLVMType(_pt)),
mangled_name, _ai + 1, arg, Node))
self._fill_default_args(CallArgs, func, mangled_name)
self._append_eh_msg_out_arg(CallArgs, func, Gen)
CallArgs = Gen._apply_auto_addr(mangled_name, CallArgs)
@@ -3497,10 +3503,10 @@ class ExprCallHandle(BaseHandle):
return result
return ir.Constant(ir.IntType(32), 0)
CallArgs = []
for arg in Node.args:
ArgVal = self.HandleExprLlvm(arg)
if ArgVal:
CallArgs.append(ArgVal)
for _ai, arg in enumerate(Node.args):
# 同 3357:禁止静默丢弃求值为空的实参(会导致后续整体前移一格)
CallArgs.append(self._RequireArgValue(
self.HandleExprLlvm(arg), self._ExprText(Node.func), _ai + 1, arg, Node))
ClassName = None
if isinstance(Node.func.value, ast.Name):
ClassName = Gen.var_struct_class.get(Node.func.value.id)