feat(TPC): 拓展 isinstance 跨模块支持
vtable linkage 改默认外部强定义(含 initializer 自动归一为空),跨模块可引用 sha1.Class_Vtable;外部引用声明为 i8* 避免 array 类型不匹配;_ResolveVtableAddr 增加 CVTable 状态检查,NoVTable 类回退编译时静态判断避免坏引用。新增 geom_lib.vp 跨模块测试库,main.vp 增加跨模块继承/运行时多态/NoVTable 场景。
This commit is contained in:
1 parent
8783340385
commit
1b89225130
4 files changed
+90
-6
No files matched your search
@@ -0,0 +1,43 @@
|
||||
import t
|
||||
from t import CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 跨模块 isinstance 测试库
|
||||
#
|
||||
# 供 main.vp import 使用:验证 isinstance 对"定义在其他模块
|
||||
# 的类"也能正确比较(对象 vtable 指针跨 obj 链接解析)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Shape:
|
||||
def area(self) -> CInt:
|
||||
return 0
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Circle(Shape):
|
||||
r: CInt
|
||||
|
||||
def __init__(self, r: CInt):
|
||||
self.r = r
|
||||
|
||||
def area(self) -> CInt:
|
||||
return self.r
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Square(Shape):
|
||||
s: CInt
|
||||
|
||||
def __init__(self, s: CInt):
|
||||
self.s = s
|
||||
|
||||
def area(self) -> CInt:
|
||||
return self.s
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class PlainShape:
|
||||
tag: CInt
|
||||
@@ -1,6 +1,7 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import testcheck
|
||||
import geom_lib
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -123,5 +124,29 @@ def main() -> CInt | CExport:
|
||||
"isinstance NoVTable FAILED")
|
||||
testcheck.check(p.v == 42, "NoVTable 字段正常 OK", "NoVTable 字段 FAILED")
|
||||
|
||||
# --- 6. 跨模块 isinstance(vtable 跨 obj 链接解析) ---
|
||||
cc: geom_lib.Circle | CPtr = geom_lib.Circle(5)
|
||||
testcheck.check(isinstance(cc, geom_lib.Circle) == 1,
|
||||
"跨模块 isinstance 自身 OK", "跨模块 isinstance 自身 FAILED")
|
||||
testcheck.check(isinstance(cc, geom_lib.Shape) == 1,
|
||||
"跨模块 isinstance 子类→基类 OK", "跨模块 isinstance 子类→基类 FAILED")
|
||||
testcheck.check(isinstance(cc, geom_lib.Square) == 0,
|
||||
"跨模块 isinstance 不匹配 OK", "跨模块 isinstance 不匹配 FAILED")
|
||||
sq: geom_lib.Square | CPtr = geom_lib.Square(3)
|
||||
testcheck.check(isinstance(sq, geom_lib.Shape) == 1,
|
||||
"跨模块 Square→Shape OK", "跨模块 Square→Shape FAILED")
|
||||
testcheck.check(isinstance(sq, geom_lib.Circle) == 0,
|
||||
"跨模块 Square vs Circle OK", "跨模块 Square vs Circle FAILED")
|
||||
shp: geom_lib.Shape | CPtr = (geom_lib.Shape | CPtr)(cc)
|
||||
testcheck.check(isinstance(shp, geom_lib.Circle) == 1,
|
||||
"跨模块运行时多态 OK", "跨模块运行时多态 FAILED")
|
||||
testcheck.check(shp.area() == 5, "跨模块虚方法分派 OK", "跨模块虚方法分派 FAILED")
|
||||
testcheck.check(cc.area() == 5, "跨模块 Circle.area OK", "跨模块 Circle.area FAILED")
|
||||
|
||||
# --- 7. NoVTable 跨模块静态判断 ---
|
||||
ps: geom_lib.PlainShape | CPtr = geom_lib.PlainShape()
|
||||
testcheck.check(isinstance(ps, geom_lib.PlainShape) == 1,
|
||||
"跨模块 NoVTable 静态 OK", "跨模块 NoVTable 静态 FAILED")
|
||||
|
||||
testcheck.ok("isinstance 全部测试完成")
|
||||
return testcheck.end()
|
||||
@@ -289,9 +289,17 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
return addrs
|
||||
|
||||
def _ResolveVtableAddr(self, Gen, ClassName: str):
|
||||
"""解析类 ClassName 的 vtable 全局地址(本地 Vtables / 跨模块外部引用),
|
||||
无 vtable(NoVTable / 未注册)返回 None。
|
||||
"""解析类 ClassName 的 vtable 全局地址(本地 Vtables / 跨模块外部引用)。
|
||||
|
||||
仅对 CVTable 类返回地址;NoVTable 类(class_vtable 与
|
||||
_cross_module_vtable_classes 均不含)没有 vtable 全局变量,
|
||||
返回 None 让调用方回退编译时静态判断(避免生成对不存在的
|
||||
sha1.Class_Vtable 符号的引用导致链接失败)。
|
||||
"""
|
||||
has_vtable: bool = (ClassName in Gen.class_vtable
|
||||
or ClassName in Gen._cross_module_vtable_classes)
|
||||
if not has_vtable:
|
||||
return None
|
||||
vt = Gen.Vtables.get(ClassName) if hasattr(Gen, 'Vtables') else None
|
||||
if vt is not None:
|
||||
return vt
|
||||
@@ -303,7 +311,9 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
if vname in Gen.module.globals:
|
||||
return Gen.module.globals[vname]
|
||||
try:
|
||||
ext = ir.GlobalVariable(Gen.module, ir.ArrayType(ir.PointerType(ir.IntType(8)), 1), name=vname)
|
||||
# 外部引用声明为 i8*(而非 [N x i8*]),避免与定义模块
|
||||
# 不同长度的 array 类型在链接时 type mismatch
|
||||
ext = ir.GlobalVariable(Gen.module, ir.PointerType(ir.IntType(8)), name=vname)
|
||||
ext.linkage = 'external'
|
||||
return ext
|
||||
except Exception:
|
||||
@@ -321,7 +331,10 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
VtPtr: ir.Value = Gen._load(ObjAsVt, name="isinstance_vt")
|
||||
Res: ir.Value | None = None
|
||||
for addr in VtableAddrs:
|
||||
AddrI8: ir.Value = Gen.builder.bitcast(addr, ir.PointerType(ir.IntType(8)), name="vt_addr")
|
||||
if addr.type == ir.PointerType(ir.IntType(8)):
|
||||
AddrI8: ir.Value = addr
|
||||
else:
|
||||
AddrI8 = Gen.builder.bitcast(addr, ir.PointerType(ir.IntType(8)), name="vt_addr")
|
||||
Cmp: ir.Value = Gen.builder.icmp_unsigned('==', VtPtr, AddrI8, name="isinstance_cmp")
|
||||
if Res is None:
|
||||
Res = Cmp
|
||||
|
||||
@@ -560,7 +560,10 @@ class StructGenMixin:
|
||||
VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||||
Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable"))
|
||||
Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods))
|
||||
Vtable.linkage = 'internal'
|
||||
# 保持默认 linkage(空字符串,带 initializer 自动打印为外部强定义
|
||||
# global,llvmlite descr 规则:initializer 非空时 linkage 归一为空)。
|
||||
# 2026-08-10:跨模块 isinstance 需引用 sha1.Class_Vtable 符号,
|
||||
# vtable 名含模块 sha1 前缀全局唯一,外部可见不会冲突。
|
||||
self.Vtables[ClassName] = Vtable
|
||||
|
||||
def _create_vtable_for_class(self, ClassName: str) -> None:
|
||||
@@ -589,7 +592,7 @@ class StructGenMixin:
|
||||
VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
|
||||
Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=_vtable_name)
|
||||
Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods))
|
||||
Vtable.linkage = 'internal'
|
||||
# 默认 linkage(外部强定义),跨模块 isinstance 引用(与 _create_Vtable_globals 一致)
|
||||
self.Vtables[ClassName] = Vtable
|
||||
|
||||
def _fix_global_var_init(self) -> None:
|
||||
|
||||
Reference in new issue
Block a user