feat(compiler): __sizeof__ 支持实例接收者与泛型类引用(self/obj 实际类型 + Stack[T] 特化)

This commit is contained in:
TermiNexus committed 2026-08-08 12:26:44 +08:00
1 parent 51d0ef2c18
commit ba6beb439c
1 file changed
+56 -14
+56 -14
View File
@@ -4901,9 +4901,13 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
elif sz_vk == ast.ASTKind.Attribute:
sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value)
sz_cls_name = sz_inner_at.attr
# 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj)
sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None
sz_resolved_name: str = sz_cls_name
if sz_cls_name is not None:
# 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__()
sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name)
sz_resolved_name = sz_cls_name
# 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt")
# 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量
# "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA"
@@ -4952,22 +4956,60 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
# ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal
# 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值
return llvmlite.const_int64(pool, sz_builtin)
sz_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(
sz_cls_name)
if sz_struct_ty is not None:
sz_val: int = HandlesClassDef._get_type_size(sz_struct_ty)
if sz_val > 0:
return llvmlite.const_int64(pool, sz_val)
# 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止
HandlesType.fatal_error(
sz_at, f"类型 '{sz_cls_name}' 已注册但大小为 0(字段链表未填充),无法计算大小",
"TypeError")
# 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出)。
# 注意:__sizeof__ 的接收者若是变量名(如 self.__sizeof__()),sz_cls_name 是
# 字面变量名("self")而非类型名,此报错即由此类误用触发(见 G5/GenericTest2)。
sz_resolved_ty = HandlesStruct.get_struct_type(sz_cls_name)
# 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小
# (GenericTest2 Stack.type_size 依赖此路径)
if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript:
sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value)
if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name:
gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value)
if gen_nm_sz.id is not None:
gen_args_sz: list[str] | t.CPtr = _extract_type_args_from_slice(pool, sub_sz.slice)
if gen_args_sz is not None and gen_args_sz.__len__() > 0:
gargs_resolved: list[str] | t.CPtr = list[str](pool, 8)
if gargs_resolved is not None:
gai_sz: t.CSizeT = gen_args_sz.__len__()
gai2_sz: t.CSizeT = 0
for gai2_sz in range(gai_sz):
gres_sz: str = HandlesType.resolve_generic_type_name(
gen_args_sz.get(gai2_sz))
gargs_resolved.append(gres_sz)
spec_sz: str = HandlesClassDef._specialize_generic_class(
trans, gen_nm_sz.id, gargs_resolved)
if spec_sz is not None:
sz_resolved_name = spec_sz
sz_resolved_ty = HandlesStruct.get_struct_type(spec_sz)
# 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型
# (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int]))
if sz_resolved_ty is None:
inst_sz_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sz_at.value, None, 0, trans)
if inst_sz_val is not None and inst_sz_val.Ty is not None:
match inst_sz_val.Ty:
case llvmlite.LLVMType.Ptr(inst_inner_sz):
match inst_inner_sz:
case llvmlite.LLVMType.Struct(_, _, _):
sz_resolved_ty = inst_inner_sz
case _:
pass
case llvmlite.LLVMType.Struct(_, _, _):
sz_resolved_ty = inst_sz_val.Ty
case _:
pass
if sz_resolved_ty is not None:
sz_val: int = HandlesClassDef._get_type_size(sz_resolved_ty)
if sz_val > 0:
return llvmlite.const_int64(pool, sz_val)
# 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止
HandlesType.fatal_error(
sz_at, f"类型 '{sz_cls_name}' 未在结构体表中注册,无法计算大小",
sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小",
"TypeError")
# 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出)
if sz_resolved_name is None:
sz_resolved_name = "(unknown)"
HandlesType.fatal_error(
sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小",
"TypeError")
# 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8,i64)
# __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct