fix(gen): lambda 捕获 str 指针偏移 + 表达式接收者等五组回归修复

- lambda 捕获 cap_slot 改 cap_names + ci*64:TPV 将 (str)(整数) 编译为 itoa,define_var 键名变数字串,lambda body lookup 穿透父函数作用域产生跨函数误读
- StructGenMixin 递归解 Ptr 到 Struct / CallGenMixin self coerce + 表达式接收者方法调用:修 sub Vec3**、ld.lld undefined dot/cross
- TranslatorGenMixin/HandlesAnnAssign 跳过 CTypedef 全局符号:修 duplicate float64_t
- ClassGenMixin 枚举/联合/REnum 基类别名经 lookup_from_import_original 解析:修 Color.Green NameError
- 重载路径 1 对 Ptr(Ptr(Struct)) 先 load 对象指针:修 MultiInheritTest self 误读
- TypeGenMixin 泛型 T 先 resolve_generic_type_name:修 NoVTableTest T 未注册
This commit is contained in:
TermiNexus committed 2026-08-13 19:10:50 +08:00
1 parent a0edc3d961
commit c27a1ba347
8 files changed
+362 -52

No files matched your search

+32 -14
View File
@@ -2746,19 +2746,18 @@ class CallGenMixin:
total_count += 1
param_node = llvmlite.param_get_next(param_node)
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0)
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(含 self)。
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
# 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾,
# 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。
# self 在运算符重载路径 2(lhs 为 X|t.CPtr 联合简化的 Vec3** 对象指针)时
# 与形参 Vec3* 不匹配,需 bitcast(coerce 指针→指针生成 bitcast),
# 否则 call 参数类型与声明不一致 llc 报错。
if found_func is not None and head is not None:
pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
# 跳过 self 参数(索引 0)
if pc_param is not None:
pc_param = llvmlite.param_get_next(pc_param)
pc_node: llvmlite.Value | t.CPtr = head.Next
new_tail: llvmlite.Value | t.CPtr = head
if head is not None:
head.Next = None
pc_node: llvmlite.Value | t.CPtr = head
new_head_pc: llvmlite.Value | t.CPtr = head
prev_pc: llvmlite.Value | t.CPtr = None
while pc_node is not None:
pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next
coerced_pc: llvmlite.Value | t.CPtr = pc_node
@@ -2771,9 +2770,13 @@ class CallGenMixin:
coerced_pc = c_pc
pc_param = llvmlite.param_get_next(pc_param)
coerced_pc.Next = None
new_tail.Next = coerced_pc
new_tail = coerced_pc
if prev_pc is None:
new_head_pc = coerced_pc
else:
prev_pc.Next = coerced_pc
prev_pc = coerced_pc
pc_node = pc_next_save
head = new_head_pc
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
# 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错)
@@ -5749,10 +5752,25 @@ class CallGenMixin:
builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans)
if expr_obj is not None and expr_obj.Ty is not None:
expr_cls_nm: str = None
match expr_obj.Ty:
case llvmlite.LLVMType.Ptr(expr_struct_ty):
expr_cls_nm = HandlesStruct.get_class_name_by_type(
pool, expr_struct_ty)
# 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct))
# (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法
# 调用被当裸函数 @dot 解析 → 链接 undefined symbol
expr_struct_ty: llvmlite.LLVMType | t.CPtr = \
HandlesStruct.get_struct_type_from_value(expr_obj)
if expr_struct_ty is not None:
expr_cls_nm = HandlesStruct.get_class_name_by_type(
pool, expr_struct_ty)
# 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时,
# 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...)
# 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解)
# 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例
if expr_cls_nm is None:
import lib.core.Gen.Generator as Generator
g3: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g3 is not None:
expr_cls_nm = g3.infer_expr_class(
pool, mod, expr_method_at.value, trans)
if expr_cls_nm is not None:
return self._translate_method_call(
pool, builder, mod, expr_cls_nm, func_name,
+59 -15
View File
@@ -14,6 +14,7 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.StubMerger as StubMerger
@@ -136,7 +137,8 @@ class ClassGenMixin:
# 本模块函数调用改 self.,外部模块调用保留模块前缀)
# ============================================================
def _is_cenum_base(self, base_node: ast.AST | t.CPtr) -> int:
def _is_cenum_base(self, base_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否"""
if base_node is None:
return 0
@@ -144,8 +146,21 @@ class ClassGenMixin:
# Name('CEnum') 形式(from t import CEnum)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
if nm.id is not None and string.strcmp(nm.id, "CEnum") == 0:
if nm.id is None:
return 0
if string.strcmp(nm.id, "CEnum") == 0:
return 1
# 别名形式: from t import CEnum as en; class Color(en)
# 解析别名原始名(en → CEnum)再比较
if trans is not None and trans._from_imports is not None:
alias_orig: str = HandlesImports.lookup_from_import_original(
trans._from_imports, nm.id)
if alias_orig is not None:
og_len_ce: t.CSizeT = 0
while alias_orig[og_len_ce] != ' ' and alias_orig[og_len_ce] != '\0':
og_len_ce += 1
if og_len_ce == 5 and string.strncmp(alias_orig, "CEnum", 5) == 0:
return 1
return 0
# Attribute(t.CEnum) 形式
if k == ast.ASTKind.Attribute:
@@ -155,7 +170,8 @@ class ClassGenMixin:
return 0
return 0
def _is_enum_class(self, cd: ast.ClassDef | t.CPtr) -> int:
def _is_enum_class(self, cd: ast.ClassDef | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 ClassDef 是否为 CEnum:继承自 t.CEnum 或 @t.CEnum 装饰器形式"""
if cd is None:
return 0
@@ -173,11 +189,12 @@ class ClassGenMixin:
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
if self._is_cenum_base(base_node) == 1:
if self._is_cenum_base(base_node, trans) == 1:
return 1
return 0
def _is_cunion_base(self, base_node: ast.AST | t.CPtr) -> int:
def _is_cunion_base(self, base_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否"""
if base_node is None:
return 0
@@ -185,8 +202,20 @@ class ClassGenMixin:
# Name('CUnion') 形式(from t import CUnion)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
if nm.id is not None and string.strcmp(nm.id, "CUnion") == 0:
if nm.id is None:
return 0
if string.strcmp(nm.id, "CUnion") == 0:
return 1
# 别名形式: from t import CUnion as un; class Data(un)
if trans is not None and trans._from_imports is not None:
alias_orig: str = HandlesImports.lookup_from_import_original(
trans._from_imports, nm.id)
if alias_orig is not None:
og_len_cu: t.CSizeT = 0
while alias_orig[og_len_cu] != ' ' and alias_orig[og_len_cu] != '\0':
og_len_cu += 1
if og_len_cu == 6 and string.strncmp(alias_orig, "CUnion", 6) == 0:
return 1
return 0
# Attribute(t.CUnion) 形式
if k == ast.ASTKind.Attribute:
@@ -196,7 +225,8 @@ class ClassGenMixin:
return 0
return 0
def _is_union_class(self, cd: ast.ClassDef | t.CPtr) -> int:
def _is_union_class(self, cd: ast.ClassDef | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 ClassDef 是否为 CUnion:继承自 t.CUnion 或 @t.CUnion 装饰器形式"""
if cd is None:
return 0
@@ -214,11 +244,12 @@ class ClassGenMixin:
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
if self._is_cunion_base(base_node) == 1:
if self._is_cunion_base(base_node, trans) == 1:
return 1
return 0
def _is_crenum_base(self, base_node: ast.AST | t.CPtr) -> int:
def _is_crenum_base(self, base_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 base 节点是否为 t.REnum,返回 1=是 / 0=否"""
if base_node is None:
return 0
@@ -226,8 +257,20 @@ class ClassGenMixin:
# Name('REnum') 形式(from t import REnum)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
if nm.id is not None and string.strcmp(nm.id, "REnum") == 0:
if nm.id is None:
return 0
if string.strcmp(nm.id, "REnum") == 0:
return 1
# 别名形式: from t import REnum as ren; class Opt(ren)
if trans is not None and trans._from_imports is not None:
alias_orig: str = HandlesImports.lookup_from_import_original(
trans._from_imports, nm.id)
if alias_orig is not None:
og_len_cr: t.CSizeT = 0
while alias_orig[og_len_cr] != ' ' and alias_orig[og_len_cr] != '\0':
og_len_cr += 1
if og_len_cr == 5 and string.strncmp(alias_orig, "REnum", 5) == 0:
return 1
return 0
# Attribute(t.REnum) 形式
if k == ast.ASTKind.Attribute:
@@ -237,7 +280,8 @@ class ClassGenMixin:
return 0
return 0
def _is_renum_class(self, cd: ast.ClassDef | t.CPtr) -> int:
def _is_renum_class(self, cd: ast.ClassDef | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> int:
"""检查 ClassDef 是否为 REnum:继承自 t.REnum 或 @t.REnum 装饰器形式"""
if cd is None:
return 0
@@ -255,7 +299,7 @@ class ClassGenMixin:
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
if self._is_crenum_base(base_node) == 1:
if self._is_crenum_base(base_node, trans) == 1:
return 1
return 0
@@ -2392,15 +2436,15 @@ class ClassGenMixin:
HandlesStruct.add_visible_struct(pool, class_name)
# 枚举类:交给 HandlesEnum 处理
if self._is_enum_class(cd) == 1:
if self._is_enum_class(cd, trans) == 1:
return self._translate_enum_def(trans, cd)
# 联合体类:交给联合体处理
if self._is_union_class(cd) == 1:
if self._is_union_class(cd, trans) == 1:
return self._translate_union_def(trans, cd)
# REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局)
if self._is_renum_class(cd) == 1:
if self._is_renum_class(cd, trans) == 1:
return self._translate_renum_def(trans, cd)
# 泛型类:存储为模板,不发射 IR(等实例化时特化)
+213 -2
View File
@@ -1776,8 +1776,17 @@ class ExprGenMixin:
trans.SymTab, nm.id)
if lhs_alloca is not None:
if cmp_zero == 0 or self.get_ptr_level(lhs_alloca.Ty) == 0:
ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca
# Ptr(Ptr(Struct)) 对象存储槽:load 出对象指针作 self
# (与 translate_binop 路径 1 一致,避免槽地址当对象地址)
if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \
and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0:
load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, lhs_alloca.Ty.Pointee, lhs_alloca)
if load_self1 is not None:
ovl_self1 = load_self1
ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload(
pool, builder, mod, lhs_alloca, rhs, op, trans, 1)
pool, builder, mod, ovl_self1, rhs, op, trans, 1)
if ovl_result is not None:
return ovl_result
@@ -4947,6 +4956,196 @@ class ExprGenMixin:
# P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算)
# ============================================================
# ============================================================
# infer_expr_class - 从表达式推断结构体类名(共享推断)
#
# 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用:
# 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断:
# Call → 类实例化(func 为已注册结构体名);func 为 Attribute
# 时是方法调用,经 vpi 返回注解缓存解析返回类名
# Name → 源变量的 AnnotClassName
# BinOp/UnaryOp → lhs 类名 + 存在对应 dunder 方法(返回同类对象)
# Attribute → 字段注解类名(_resolve_attr_field_class)
# 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。
# ============================================================
def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr) -> str:
"""从表达式推断结构体类名,无法推断返回 None"""
if node is None or trans is None:
return None
k: int = node.kind()
# Call: 类实例化 / 方法调用
if k == ast.ASTKind.Call:
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
if cl is None or cl.func is None:
return None
if cl.func.kind() == ast.ASTKind.Name:
cand: str = ((ast.Name | t.CPtr)(cl.func)).id
if cand is None:
return None
if HandlesStruct.find_struct(cand) is not None:
return cand
return None
if cl.func.kind() == ast.ASTKind.Attribute:
# 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名
# (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if ca is None or ca.attr is None or ca.value is None:
return None
obj_cls: str = self.infer_expr_class(pool, mod, ca.value, trans)
if obj_cls is None:
return None
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
return None
cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls)
if cls_sha1 is None and trans.ModuleSha1 is not None:
cls_sha1 = trans.ModuleSha1
ret_cls: str = None
if cls_sha1 is not None:
import lib.StubGen.VpiReader as VpiReader
temp_dir: str = None
# 跨 Mixin 不能 self 访问 Generator 的 TempDir 字段(字段按
# 声明类隔离),经全局单例获取(同 HandlesAssign 模式)
import lib.core.Gen.Generator as Generator
g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g2 is not None and g2.TempDir is not None:
temp_dir = g2.TempDir
if temp_dir is not None:
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir)
annot_ret: str = VpiReader._lookup_vpi_ret_annot(
cls_sha1, obj_cls, ca.attr)
if annot_ret is not None:
ret_cls = self._extract_annot_class_name(pool, annot_ret)
return ret_cls
return None
# Name: 源变量注解
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm is None or nm.id is None:
return None
ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm.id)
if ve is None:
return None
return ve.AnnotClassName
# BinOp/UnaryOp: 运算符重载返回同类对象
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
if bop is None or bop.left is None:
return None
dunder: str = self._binop_to_dunder(bop.op)
if dunder is None:
return None
lhs_cls: str = self.infer_expr_class(pool, mod, bop.left, trans)
if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0:
return None
return lhs_cls
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
if uop is None or uop.operand is None:
return None
dunder: str = self._unaryop_to_dunder(uop.op)
if dunder is None:
return None
opr_cls: str = self.infer_expr_class(pool, mod, uop.operand, trans)
if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0:
return None
return opr_cls
# Attribute: 字段注解类名(属性链递归,如 p = r.origin)
if k == ast.ASTKind.Attribute:
return self._resolve_attr_field_class(pool, trans, node)
return None
# ============================================================
# _cls_has_dunder - 检查类(含继承链)是否存在 dunder/方法
#
# 与 try_operator_overload 的查找一致:当前模块内定义或跨模块类有
# SHA1(stub 中声明)即视为存在。仅在确实存在时采用推断类名,
# 避免把原生运算误标为类类型。
# ============================================================
def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str, dunder: str) -> int:
"""类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1"""
if class_name is None or dunder is None or mod is None:
return 0
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return 0
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
if HandlesExprCall.find_func_in_module(mod, lookup_name) is not None:
return 1
# 继承链祖先查找
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mi: int = 1
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
anc_lookup: str = pool.alloc(128)
if anc_lookup is not None:
viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder)
if HandlesExprCall.find_func_in_module(mod, anc_lookup) is not None:
return 1
mi += 1
# 跨模块:类有 SHA1(stub 中声明该方法)视为存在
if HandlesStruct.get_struct_sha1(class_name) is not None:
return 1
return 0
# ============================================================
# _extract_annot_class_name - 从返回注解文本提取结构体类名
#
# vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除
# 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/
# CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合
# 多候选时取首个命中段。
# ============================================================
def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr,
annot: str) -> str:
"""从返回注解文本提取已注册结构体类名,无命中返回 None"""
if pool is None or annot is None:
return None
alen: t.CSizeT = string.strlen(annot)
if alen == 0:
return None
seg: str = pool.alloc(256)
if seg is None:
return None
start: t.CSizeT = 0
i: t.CSizeT
for i in range(alen):
if annot[i] == '|':
s: t.CSizeT = start
e: t.CSizeT = i
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
e -= 1
seglen: t.CSizeT = e - s
if seglen > 0 and seglen < 256:
string.strncpy(seg, annot + s, seglen)
seg[seglen] = '\0'
if HandlesStruct.find_struct(seg) is not None:
return seg
start = i + 1
# 最后一段(无 '|' 后缀)
s: t.CSizeT = start
e: t.CSizeT = alen
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
e -= 1
seglen: t.CSizeT = e - s
if seglen > 0 and seglen < 256:
string.strncpy(seg, annot + s, seglen)
seg[seglen] = '\0'
if HandlesStruct.find_struct(seg) is not None:
return seg
return None
# ============================================================
# BinOp 运算符 → dunder 方法名
# ============================================================
@@ -5221,8 +5420,20 @@ class ExprGenMixin:
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, nm.id)
if lhs_alloca is not None:
ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca
# alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时,
# load 出对象指针作为 self——若把槽地址当 self,dunder 内
# load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest
# Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value
# 递归解指针后路径 1 能识别 alloca,需同步修正 self 语义)
if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \
and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0:
load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, lhs_alloca.Ty.Pointee, lhs_alloca)
if load_self1 is not None:
ovl_self1 = load_self1
ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload(
pool, builder, mod, lhs_alloca, rhs, op, trans, 0)
pool, builder, mod, ovl_self1, rhs, op, trans, 0)
if ovl_result is not None:
return ovl_result
+6 -4
View File
@@ -1709,8 +1709,10 @@ class FuncGenMixin:
# 9. 捕获变量:从 env 堆槽加载值到局部 alloca
for ci in range(cap_count):
cap_addr: t.CUInt64T = t.CUInt64T(cap_names) + ci * 64
cap_slot: str = (str)(cap_addr)
# 直接 str 指针偏移取捕获名(与 param_names + pi*32 一致)。
# 注意:不能用 (str)(cap_addr) 整数转换——TPV 将其编译为 itoa(整数转字符串),
# 会把 cap_slot 变成数字串,define_var 键名错乱,lambda body lookup 无法命中。
cap_slot: str = cap_names + ci * 64
if cap_slot[0] == '\0':
continue
ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8
@@ -1798,8 +1800,8 @@ class FuncGenMixin:
builder, "malloc", env_size_val, 1, i8_ptr_ty, 0)
if env_ptr is not None:
for ci3 in range(cap_count):
cap_addr3: t.CUInt64T = t.CUInt64T(cap_names) + ci3 * 64
cap_slot3: str = (str)(cap_addr3)
# 与步骤 9 一致:str 指针偏移判空,避免整数转换 itoa 语义
cap_slot3: str = cap_names + ci3 * 64
if cap_slot3[0] == '\0':
continue
al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8
+17 -11
View File
@@ -660,19 +660,25 @@ class StructGenMixin:
return 0
def get_struct_type_from_value(self, val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""从 Value 的类型推断结构体类型"""
"""从 Value 的类型推断结构体类型
递归解 Ptr:支持 X|t.CPtr 联合简化产生的 Ptr(Ptr(Struct)) 对象指针
(如运算符重载中间结果 a*2.0 的 Vec3**),否则 try_operator_overload
重载识别失败回退原生运算,对指针生成非法 sub 指令(llc: invalid
operand type for instruction)。
"""
if val is None or val.Ty is None:
return None
# 嵌套 match:先匹配 Ptr,再在 case 块内匹配 pointee 是否为 Struct
match val.Ty:
case llvmlite.LLVMType.Ptr(pointee):
match pointee:
case llvmlite.LLVMType.Struct(fields, fcount, name):
return pointee
case _:
return None
case _:
return None
ty: llvmlite.LLVMType | t.CPtr = val.Ty
while ty is not None:
match ty:
case llvmlite.LLVMType.Ptr(pointee):
ty = pointee
case llvmlite.LLVMType.Struct(fields, fcount, name):
return ty
case _:
return None
return None
def mark_as_union(self, name: str) -> int:
"""标记已注册的结构体为联合体,返回 1=成功 / 0=失败"""
+7
View File
@@ -346,6 +346,13 @@ class TranslatorGenMixin:
HandlesAnnAssign._register_cdefine_from_value(
pool, nm_cd.id, aa_cd.value)
return 0
# CTypedef 注解(如 stdint.vp float64_t: t.CTypedef = t.CFloat64T):
# 类型别名已由 ScanCTypedefDeclarations 注册到 CTypedef 表,
# 不创建全局变量——否则每个包含 stdint 的模块生成
# @float64_t 全局 → 链接 duplicate symbol warning
# (跨 Mixin 经 HandlesAnnAssign 模块委托调用)
if HandlesAnnAssign.is_ctypedef_annotation(aa_cd.annotation) != 0:
return 0
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
+13 -6
View File
@@ -1505,18 +1505,25 @@ class TypeGenMixin:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is None:
return None
# 泛型特化上下文:T → 具体类型(特化方法体内局部变量注解
# 如 `cur: T | t.CPtr` 未被 _clone_classdef_for_spec 克隆替换,
# 依赖此处在翻译时经上下文解析;否则 cur.annot="T",
# 属性访问 cur.Next → lookup_field_by_class("T") 未注册报错)
resolved_id: str = self.resolve_generic_type_name(nm.id)
if resolved_id is None:
return None
# 跳过内置类型名
if string.strcmp(nm.id, "str") == 0:
if string.strcmp(resolved_id, "str") == 0:
return None
if string.strcmp(nm.id, "bytes") == 0:
if string.strcmp(resolved_id, "bytes") == 0:
return None
if string.strcmp(nm.id, "bool") == 0:
if string.strcmp(resolved_id, "bool") == 0:
return None
if string.strcmp(nm.id, "float") == 0:
if string.strcmp(resolved_id, "float") == 0:
return None
if string.strcmp(nm.id, "double") == 0:
if string.strcmp(resolved_id, "double") == 0:
return None
return nm.id
return resolved_id
# Attribute 节点: memhub.MemBuddy → "memhub.MemBuddy"(模块限定名)
if k == ast.ASTKind.Attribute:
+15
View File
@@ -59,6 +59,15 @@ def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int:
return 0
def is_ctypedef_annotation(annot: ast.AST | t.CPtr) -> int:
"""检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否(委托到 gen._is_ctypedef_annotation)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_ctypedef_annotation(annot)
return 0
# ============================================================
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
#
@@ -310,6 +319,12 @@ class AnnAssignHandle(HandlesBase.Mixin):
_register_cdefine_from_value(pool_ps, nm.id, aa.value)
return 0
# CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表),
# 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T
# 等生成 @float64_t 符号,链接 duplicate symbol warning
if is_ctypedef_annotation(aa.annotation) != 0:
return 0
# global/nonlocal 变量不需要局部 alloca
if HT.is_global_name(self.Trans, nm.id) != 0:
return 0