fix(gen): struct 返回类型解析 + 变参提升 + 泛型隐式推断三组修复

1. _ParseLLVMRetTyStr 支持 struct 字面量 {T1,T2,...}:"{i8*,i16}" 内含 * 被
   误判为 i8*,b2a_hqx tuple[str,u16] 调用侧返回类型退化 → HandlesAssign
   tuple 解包静默跳过 → 目标未初始化 → free 垃圾指针崩溃(HashLibTest hqx);
2. 变参提升 is_u_va 失败时 i8 默认 zext:printf("%02x", uint8) 不再 sext 成
   0xFFFFFFF3 输出 ffffffXX(对齐 should_zext_widen 无符号字节策略);
3. _infer_generic_ctor_type_arg:Name("CInt")/("CFloat64T") 裸名类型转换补
   strstr 匹配(from t import 后 func 是 Name);非类型转换实参(pool 等非
   T 参数)返回默认 int 被"过滤纯 int"排除,不再 fail-fast(VectorGenericTest
   隐式泛型推断),仅 Call 类型转换识别失败才 fail-fast。
This commit is contained in:
TermiNexus committed 2026-08-13 08:30:44 +08:00
1 parent 9bb6dd7612
commit 19f48eea02
1 file changed
+71 -8
+71 -8
View File
@@ -3018,6 +3018,49 @@ class CallGenMixin:
if ty_len == 0:
return None
# struct 字面量 {T1, T2, ...}(tuple 打包返回类型,如 b2a_hqx ->
# tuple[str, t.CUnsignedShort] 编译为 {i8*, i16})。必须在 * 检查
# 之前——否则 "{i8*, i16}" 内含 * 会被误判为 i8*(b2a_hqx 调用侧
# 返回类型退化 i8* → HandlesAssign tuple 解包静默跳过 → free 未初始化
# 指针崩溃,HashLibTest hqx 段)。
if s < e and buf[s] == '{':
th_st: llvmlite.ParamNode | t.CPtr = None
tt_st: llvmlite.ParamNode | t.CPtr = None
tc_st: int = 0
ps_st: t.CSizeT = s + 1
while ps_st < e and buf[ps_st] != '}':
while ps_st < e and (buf[ps_st] == ' ' or buf[ps_st] == ','):
ps_st += 1
if ps_st >= e or buf[ps_st] == '}':
break
es_st: t.CSizeT = ps_st
while ps_st < e and buf[ps_st] != ',' and buf[ps_st] != '}':
ps_st += 1
ee_st: t.CSizeT = ps_st
if ee_st > es_st:
et_st: llvmlite.LLVMType | t.CPtr = self._ParseLLVMRetTyStr(
pool, buf, es_st, ee_st)
if et_st is None:
return None
en_st: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(
pool, et_st)
if en_st is None:
return None
if th_st is None:
th_st = en_st
else:
llvmlite.paramnode_set_next(tt_st, en_st)
tt_st = en_st
tc_st += 1
if th_st is None or tc_st == 0:
return None
st_ty_st: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, th_st, tc_st, None)
# 指针到 struct({i32, i8}*):返回 Ptr(Struct);纯 tuple 打包
# ({i8*, i16})无尾部 *,返回 Struct 本身。
if ps_st < e and buf[ps_st] == '*':
return llvmlite.Ptr(pool, st_ty_st)
return st_ty_st
# 检查是否含 * (指针类型) → 返回 i8* (通用指针)
# 包括 i8*, i32*, %"name"*, { i32, i8 }* 等
ci: t.CSizeT = s
@@ -4793,9 +4836,16 @@ class CallGenMixin:
if cl_f.func.kind() == ast.ASTKind.Name:
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func)
if fn_nm.id is not None:
if string.strcmp(fn_nm.id, "float") == 0:
# 与下方 Attribute 分支的 strstr 匹配一致:from t import CInt
# 后 `CInt(0)` 的 func 是 Name("CInt"),仅精确匹配 int/float
# 会漏判 → fail-fast 误杀(VectorGenericTest 隐式泛型推断)。
if string.strcmp(fn_nm.id, "float") == 0 or string.strcmp(fn_nm.id, "double") == 0 \
or string.strstr(fn_nm.id, "Float") is not None or string.strstr(fn_nm.id, "Double") is not None:
return "double"
if string.strcmp(fn_nm.id, "int") == 0:
if string.strcmp(fn_nm.id, "int") == 0 \
or string.strstr(fn_nm.id, "Int") is not None or string.strstr(fn_nm.id, "UInt") is not None \
or string.strstr(fn_nm.id, "Char") is not None or string.strstr(fn_nm.id, "Short") is not None \
or string.strstr(fn_nm.id, "Long") is not None:
return "int"
elif cl_f.func.kind() == ast.ASTKind.Attribute:
fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func)
@@ -4804,11 +4854,16 @@ class CallGenMixin:
return "double"
if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None:
return "int"
# 无法从 AST 静态推断:fail-fast,绝不静默默认 "int"(会特化出错误类型)
HandlesType.fatal_error(
arg_node,
f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)",
"TypeError")
# 类型转换调用(Call)但函数名无法识别:明确的类型意图却无法解析,
# fail-fast(区别于普通变量 Name——那是非 T 参数,默认 int 被过滤)。
HandlesType.fatal_error(
arg_node,
f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)",
"TypeError")
return "int"
# 非类型转换节点(普通变量 Name/Attribute 等,如 Vector(pool, 8, ...)
# 的 pool 参数):不是 T 类型提示,返回默认 "int"(调用方"过滤纯 int"
# 逻辑将其排除,只保留 float/str 等区分性提示)。
return "int"
def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr,
@@ -7619,7 +7674,15 @@ class CallGenMixin:
if is_u_va != 0:
promoted = llvmlite.build_zext(builder, cur, i32_ty_promote)
else:
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
# is_u_va 判断失败(arg_nodes/trans 缺失或变量注解查不到)时,
# i8 按系统编程惯例默认 zext(对齐 should_zext_widen 的
# "i8 → zext(系统编程中 i8 几乎总是无符号字节)"策略),
# 否则 printf("%02x", buf[i]) 中 uint8 字节被 sext 成
# 0xFFFFFFF3,哈希摘要输出 ffffffXX 垃圾。
if HandlesExpr.get_llvm_type_bits(cur.Ty) == 8:
promoted = llvmlite.build_zext(builder, cur, i32_ty_promote)
else:
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
if promoted is not None:
promoted.Next = next_node
if prev is not None: