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
+139 -4

No files matched your search

+12
View File
@@ -3618,6 +3618,13 @@ def _translate_method(trans: HT.Translator | t.CPtr,
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct):按"对象即指针"引用传参。
# 若按 struct 值传参,self.Head = node 会取局部拷贝地址
# (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty = llvmlite.Ptr(pool, resolved)
case _:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
if pname is not None:
@@ -3683,6 +3690,11 @@ def _translate_method(trans: HT.Translator | t.CPtr,
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports, trans)
if resolved2 is not None:
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针)
match resolved2:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty2 = llvmlite.Ptr(pool, resolved2)
case _:
param_ty2 = resolved2
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
if alloca is not None:
+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 会被误判为模块名
+37
View File
@@ -401,6 +401,11 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty = llvmlite.Ptr(pool, resolved)
case _:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
if pname is not None:
@@ -523,6 +528,11 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg_e.annotation, imported_modules, from_imports, trans)
if resolved_e is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
match resolved_e:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty_e = llvmlite.Ptr(pool, resolved_e)
case _:
param_ty_e = resolved_e
pname_e: t.CChar | t.CPtr = pool.alloc(32)
if pname_e is not None:
@@ -605,6 +615,11 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg.annotation, imported_modules, from_imports, trans)
if resolved is not None:
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
match resolved:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty = llvmlite.Ptr(pool, resolved)
case _:
param_ty = resolved
pname: t.CChar | t.CPtr = pool.alloc(32)
if pname is not None:
@@ -632,6 +647,21 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
# 进入函数作用域(嵌套符号表)
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
# PEP 695 泛型函数: def f[T](...) — 设置泛型上下文,类型参数映射到 "int" 兜底。
# TPV 无泛型函数特化机制(类泛型走 _specialize_generic_class),泛型函数按普通
# 函数编译;设置上下文使参数注解 T / 方法体中的 T(x) 转换可解析为 int。
# (注意与类特化的 set_generic_context 一样是全局状态,需在退出作用域前清除。)
tp_names_fn: list[str] | t.CPtr = None
if fd.type_params is not None:
tp_names_fn = fd.type_params
tp_args_fn: list[str] | t.CPtr = list[str](pool, 8)
if tp_args_fn is not None:
tpn_fn: t.CSizeT = fd.type_params.__len__()
tpi_fn: t.CSizeT = 0
for tpi_fn in range(tpn_fn):
tp_args_fn.append("int")
HandlesType.set_generic_context(tp_names_fn, tp_args_fn)
# 为参数创建 alloca
if args_node is not None:
ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
@@ -650,6 +680,11 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, arg2.annotation, imported_modules, from_imports, trans)
if resolved2 is not None:
# 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针)
match resolved2:
case llvmlite.LLVMType.Struct(_, _, _):
param_ty2 = llvmlite.Ptr(pool, resolved2)
case _:
param_ty2 = resolved2
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
if alloca is not None:
@@ -765,6 +800,8 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
llvmlite.build_ret(func_builder, _zero_val)
# 恢复模块级作用域(退出函数作用域)
if tp_names_fn is not None:
HandlesType.clear_generic_context()
HandlesVar.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
+8
View File
@@ -1582,6 +1582,14 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
# class 名称: 查找已注册的 StructType,返回 StructType 本身(不包装 Ptr)
# 这样 build_alloca 会分配结构体大小的空间,alloca 返回 struct_ty*
# 命名空间隔离:严格模式下仅解析可见的结构体
# 跨模块同名类优先:当前模块自身定义了同名类时,用 find_struct_by_module
# 命中本模块的类(如 main.vp 的 G5Node 不再被 g5container.vp 预注册的
# G5Node 顶掉,避免 alloca 用本模块类型、load 用他模块类型的混用)。
# 本模块未定义时回退按裸名全局查找(import 来的类走此路径)。
if trans is not None and trans.ModuleSha1 is not None:
own_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_module(nm.id, trans.ModuleSha1)
if own_entry is not None and own_entry.Ty is not None:
return own_entry.Ty
if HandlesStruct.is_struct_visible(nm.id) != 0:
struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(nm.id)
if struct_ty is not None: