fix(compiler): 裸类形参按引用传参 + 同名类优先本模块 + 裸名泛型构造/类型参数转换

- 裸类形参(方法+函数)解析为 Ptr(struct),修复 GSList[T].append 按值传参悬垂(G5 Test4 head.Value 读到垃圾)

- resolve_annotation_type 裸类名优先 find_struct_by_module 命中本模块,避免跨模块同名类(main.vp G5Node vs g5container.vp)类型混用

- translate_call 新增裸名泛型类模板构造:Box(42)→从实参推断→特化→构造(GenericTest Test4/5/10、GenericTest2 Stack/Range 等)

- 类型转换路径先 resolve_generic_type_name:类特化/泛型函数中的 T(x) 解析为 int/str/bool/double 转换

- 泛型函数翻译时设泛型上下文 T→int(TPV 泛型函数按普通 i32 函数编译,退出作用域前清除)
This commit is contained in:
TermiNexus committed 2026-08-08 11:54:32 +08:00
1 parent 60493d6ae5
commit e0303c46f6
4 files changed
+145 -10

No files matched your search

+82 -4
View File
@@ -4532,6 +4532,46 @@ def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr,
# 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1
# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。
# ============================================================
def _infer_generic_ctor_type_arg(pool: memhub.MemBuddy | t.CPtr,
arg_node: ast.AST | t.CPtr) -> str:
"""从构造实参 AST 推断泛型类型实参名;无法推断时默认 "int"(与 TPC 一致)
裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。
对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。
注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。
"""
if pool is None or arg_node is None:
return "int"
k: int = arg_node.kind()
# 常量: 42→int, 3.14→double, "abc"→str
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node)
if cn.const_kind == ast.CONST_FLOAT:
return "double"
if cn.const_kind == ast.CONST_STR:
return "str"
return "int"
# 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...)
if k == ast.ASTKind.Call:
cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node)
if cl_f.func is not None:
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:
return "double"
if string.strcmp(fn_nm.id, "int") == 0:
return "int"
elif cl_f.func.kind() == ast.ASTKind.Attribute:
fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func)
if fn_at.attr is not None:
if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None:
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"
return "int"
def _translate_generic_ctor_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
@@ -4731,8 +4771,12 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
# 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x)
# 单参数:str(val) → bitcast val to i8*
# int(val) → trunc/sext val to i32
# 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名
# (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、
# combine[T1,T2] 的 T1(b) 依赖此路径)
if func_name is not None and can == 1:
if string.strcmp(func_name, "str") == 0 or string.strcmp(func_name, "bytes") == 0:
cast_fn_name: str = HandlesType.resolve_generic_type_name(func_name)
if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0:
# str(x) / bytes(x) → i8* (bitcast)
cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
@@ -4740,7 +4784,7 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
return _translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin)
return None
elif string.strcmp(func_name, "int") == 0:
elif string.strcmp(cast_fn_name, "int") == 0:
# int(x) → i32
cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
@@ -4748,7 +4792,7 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
return _translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin)
return None
elif string.strcmp(func_name, "bool") == 0:
elif string.strcmp(cast_fn_name, "bool") == 0:
# bool(x) → i1(严格 != 0 归一化)
# 整数: icmp ne x, 0 → i1
# 浮点: fcmp one x, 0.0 → i1
@@ -4823,8 +4867,17 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
# 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等
# 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换
# map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等)
# 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体
# 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、
# combine[T1,T2] 的 T1(b) 依赖此路径)
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
bare_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name)
bare_fn_name: str = HandlesType.resolve_generic_type_name(func_name)
bare_ty: llvmlite.LLVMType | t.CPtr = None
# 泛型上下文解析出的内建名(如 T→"double"):map_t_type 只认 t.CDouble
if string.strcmp(bare_fn_name, "double") == 0 or string.strcmp(bare_fn_name, "float") == 0:
bare_ty = llvmlite.Double(pool)
else:
bare_ty = HandlesType.map_t_type(pool, bare_fn_name)
if bare_ty is not None and can == 1:
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
if bare_arg_node is not None:
@@ -5403,6 +5456,31 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
return _translate_struct_ctor(
pool, builder, mod, struct_ty, func_name, cargs, can, trans)
# 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造
# (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5
# Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb)
# 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。)
if struct_ty is None and gen_ctor_entry is None and trans is not None:
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
template_cd_bare: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(func_name)
if template_cd_bare is not None and template_cd_bare.type_params is not None:
tp_bare: list[str] | t.CPtr = template_cd_bare.type_params
tp_count_bare: t.CSizeT = tp_bare.__len__()
if tp_count_bare > 0:
inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8)
if inferred_args_bare is not None:
tpi_bare: t.CSizeT = 0
for tpi_bare in range(tp_count_bare):
ta_bare: str = "int"
if tpi_bare < can:
ta_bare = _infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare))
inferred_args_bare.append(ta_bare)
spec_name_bare: str = HandlesClassDef._specialize_generic_class(
trans, func_name, inferred_args_bare)
if spec_name_bare is not None:
return _translate_generic_ctor_call(
pool, builder, mod, spec_name_bare, cl, trans)
# REnum 变体构造检测: ClassName.VariantName(args...)
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体
# 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名