From 19f48eea028f14c5ee83106c9a808b32d46f04ea Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 13 Aug 2026 08:30:44 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen):=20struct=20=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=A7=A3=E6=9E=90=20+=20=E5=8F=98=E5=8F=82?= =?UTF-8?q?=E6=8F=90=E5=8D=87=20+=20=E6=B3=9B=E5=9E=8B=E9=9A=90=E5=BC=8F?= =?UTF-8?q?=E6=8E=A8=E6=96=AD=E4=B8=89=E7=BB=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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。 --- App/lib/core/Gen/CallGenMixin.vp | 79 ++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 98623a2..92d8ae8 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -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: