审计并修复 23 个文件:类型注解中的 T1 | T2 一律 fail-fast;typedef/define/export/extern/static/const/volatile/attribute 优先读取 Markers/Attributes/ByteOrder/BitWidth;指针统一 CPtr/rawptr/CRef/CTempRef/CArrayPtr/CAutoPtr Subscript;stub 输出统一新语法。
2037 lines
122 KiB
Python
2037 lines
122 KiB
Python
from __future__ import annotations
|
||
from typing import TYPE_CHECKING
|
||
if TYPE_CHECKING:
|
||
from lib.core.translator import Translator
|
||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||
import vast as ast
|
||
import copy
|
||
import sys
|
||
import llvmlite.ir as ir
|
||
from lib.core.Exportable import EnumMember as ExportEnumMember
|
||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||
from lib.core.SymbolUtils import (
|
||
MangleTypeArgByRegistry,
|
||
EnumClassIntWidth,
|
||
EnumBodyMemberNames, EnumMemberCountMismatchError,
|
||
ClassHasFuncLevelCVTable, IsVtableSlotMethod)
|
||
from lib.core.VLogger import get_logger as _vlog
|
||
from lib.constants.config import mode as _config_mode
|
||
from lib.core import TypeSystem
|
||
from lib.core.TypeSystem import CTypeRegistry
|
||
|
||
# 枚举成员不允许的指针形态名:CPtr 家族(CPtr/CAutoPtr,后者继承
|
||
# CPtr)、值引用标记(CRef/CTempRef,`&T`/`&temp T`)、内建 rawptr(= CPtr)、
|
||
# str/bytes(= i8*)。枚举值是整数常量,指针成员语义不成立,命中即明确报错
|
||
# (不静默当 int)。
|
||
_ENUM_PTR_ANNOTATION_NAMES: frozenset[str] = frozenset({
|
||
'CPtr', 'CAutoPtr', 'CRef', 'CTempRef', 'rawptr', 'str', 'bytes',
|
||
})
|
||
|
||
# 指针/引用下标包装名(`CPtr[T]` / `rawptr[T]` / `CRef[T]` ...):
|
||
# 新 AST 表示下指针是 Subscript,不再是 `T | CPtr` 联合的一翼。
|
||
_PTR_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||
})
|
||
|
||
|
||
class ClassHandle(BaseHandle):
|
||
def _is_exception_class(self, Node: ast.ClassDef) -> bool:
|
||
if not Node.bases:
|
||
return False
|
||
for base in Node.bases:
|
||
if hasattr(base, 'id'):
|
||
if base.id == 'Exception':
|
||
return True
|
||
if base.id in self.Trans.exception_registry:
|
||
return True
|
||
elif hasattr(base, 'attr'):
|
||
if base.attr == 'Exception':
|
||
return True
|
||
if base.attr in self.Trans.exception_registry:
|
||
return True
|
||
return False
|
||
|
||
def _get_exception_parent(self, Node: ast.ClassDef) -> str | None:
|
||
if not Node.bases:
|
||
return None
|
||
for base in Node.bases:
|
||
if hasattr(base, 'id'):
|
||
if base.id != 'Exception' and base.id in self.Trans.exception_registry:
|
||
return base.id
|
||
elif hasattr(base, 'attr'):
|
||
if base.attr != 'Exception' and base.attr in self.Trans.exception_registry:
|
||
return base.attr
|
||
return None
|
||
|
||
def _RegisterExceptionClass(self, Node: ast.ClassDef) -> None:
|
||
ClassName: str = Node.name
|
||
if ClassName in self.Trans.exception_registry:
|
||
return
|
||
code: int = self.Trans._next_exception_code
|
||
self.Trans._next_exception_code += 1
|
||
self.Trans.exception_registry[ClassName] = code
|
||
parent: str | None = self._get_exception_parent(Node)
|
||
if parent:
|
||
self.Trans.exception_parents[ClassName] = parent
|
||
ExcTypeInfo: CTypeInfo = CTypeInfo()
|
||
ExcTypeInfo.Name = ClassName
|
||
ExcTypeInfo.IsExceptionClass = True
|
||
ExcTypeInfo.value = code
|
||
self.Trans.SymbolTable.insert(ClassName, ExcTypeInfo)
|
||
|
||
def _is_generic_class(self, Node: ast.ClassDef) -> bool:
|
||
if hasattr(Node, 'type_params') and Node.type_params:
|
||
return True
|
||
return False
|
||
|
||
def _mangle_generic_class_name(self, class_name: str, type_args: list[str]) -> str:
|
||
"""泛型类特化名:class_name + '[arg1][arg2]'。
|
||
|
||
单项 mangling 走 SymbolUtils.MangleTypeArgByRegistry(声明端
|
||
DeclarationGenerator 的泛型分支以 ResolveGenericTypeArgStr 调用同一函数,
|
||
两侧拼名规则唯一),'][' 分隔与 HandlesTypeMerge / DeclarationGenerator 一致。
|
||
"""
|
||
mangled_args: list[str] = [MangleTypeArgByRegistry(ta) for ta in type_args]
|
||
return class_name + '[' + ']['.join(mangled_args) + ']'
|
||
|
||
def _HasClassDefinition(self, Name: str, Gen: LlvmGeneratorMixin) -> bool:
|
||
"""类型名是否有类定义——泛型"类类型参数"的唯一判据。
|
||
|
||
数据来源就是"是否存在类定义"这一事实本身:Gen._struct_sha1_map
|
||
(类名 → 定义模块 SHA1,Phase2 从各 .vpi 扫描构建)与 Gen.structs
|
||
(本模块已发射的 struct 名,键形如 '{sha1}.{名}')。
|
||
因此内建值类型(int/CInt/…,LLVM 映射 i32 等)与语言内建 `str`
|
||
(LLVM 映射 i8*)都不在两张表里 → 自然判为值类型,不需要任何
|
||
内建名白名单/黑名单参与判定。
|
||
"""
|
||
if not Name:
|
||
return False
|
||
if Name in Gen._struct_sha1_map or Name in Gen.structs:
|
||
return True
|
||
for Sha1 in Gen._struct_sha1_map.values():
|
||
if f'{Sha1}.{Name}' in Gen.structs:
|
||
return True
|
||
return False
|
||
|
||
@staticmethod
|
||
def _BareClassAnnotationName(Node: ast.AST) -> str | None:
|
||
"""取注解节点的裸类名(供 class_type_names 判定),非类名形态返回 None。
|
||
|
||
T 替换后的两种形态都要认:
|
||
- ast.Name:'AST'(未注册类)或 'sha1.AST'(旧式点号名)→ 去前缀;
|
||
- ast.Attribute:'sha1.AST' 经 _make_replacement_node/_make_name_node
|
||
产出的 Attribute 链(Name('sha1').AST)→ attr 名。
|
||
其余(Union `X | CPtr`、Subscript `list[T]`、内建)→ None,不追加
|
||
指针层(已显式写了 `| CPtr` 的注解不再重复加层)。
|
||
"""
|
||
if isinstance(Node, ast.Name):
|
||
Name: str = Node.id
|
||
return Name.split('.')[-1] if '.' in Name else Name
|
||
if isinstance(Node, ast.Attribute):
|
||
return Node.attr
|
||
return None
|
||
|
||
def _specialize_generic_class(self, ClassName: str, type_args: list[str], Gen: LlvmGeneratorMixin, type_names: list[str] | None = None, declare_only: bool = False) -> str | None:
|
||
if not hasattr(self, '_generic_class_templates') or ClassName not in self._generic_class_templates:
|
||
return None
|
||
# 防御:共享符号表构建阶段 Gen 可能为 None,此时无法发射特化 IR
|
||
if Gen is None:
|
||
return None
|
||
template: dict = self._generic_class_templates[ClassName]
|
||
Node: ast.ClassDef = template['node']
|
||
type_param_names: list[str] = template['type_params']
|
||
if len(type_args) != len(type_param_names):
|
||
return None
|
||
spec_key: str = ClassName + '<' + ','.join(type_args) + '>'
|
||
# 缓存必须在 Gen 上(每个模块独立),不能在 ClassHandler 上跨模块共享,
|
||
# 否则临时 Gen(如共享符号表构建阶段)的特化会污染正式翻译阶段的缓存
|
||
if not hasattr(Gen, '_generic_class_specializations'):
|
||
Gen._generic_class_specializations = {}
|
||
if spec_key in Gen._generic_class_specializations:
|
||
cached: object = Gen._generic_class_specializations[spec_key]
|
||
# 缓存格式: (spec_name, was_declare_only)
|
||
if isinstance(cached, tuple):
|
||
cached_name: str = cached[0]
|
||
cached_declare_only: bool = cached[1]
|
||
# 完整特化请求但缓存只有 declare_only 版本 → 需要补发方法体
|
||
if not declare_only and cached_declare_only:
|
||
spec_name = cached_name
|
||
# 标记为正在完整特化,防止递归
|
||
Gen._generic_class_specializations[spec_key] = (spec_name, False)
|
||
else:
|
||
return cached_name
|
||
else:
|
||
# 旧格式(纯字符串):直接返回
|
||
return cached
|
||
else:
|
||
spec_name: str = self._mangle_generic_class_name(ClassName, type_args)
|
||
# 预注册到缓存,防止特化过程中方法体引用自身类型导致无限递归
|
||
Gen._generic_class_specializations[spec_key] = (spec_name, declare_only)
|
||
# 内建类型名集合(必须在 type_map/cptr_params 检测之前定义)
|
||
_BUILTIN_TYPE_NAMES: set = {
|
||
'CInt', 'CUInt', 'CInt8T', 'CUInt8T', 'CInt16T', 'CUInt16T',
|
||
'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CChar', 'CShort',
|
||
'CLong', 'CDouble', 'CFloat', 'CFloat32T', 'CFloat64T', 'CBool',
|
||
'CVoid', 'CSizeT', 'CSSizeT', 'CPtr', 'CArray', 'CEnum', 'CUnion',
|
||
'CStruct', 'CDefine',
|
||
'int', 'double', 'float', 'i8', 'i16', 'i32', 'i64', 'void',
|
||
'half', 'fp128', 'char', 'bool',
|
||
}
|
||
# 值类型/类类型不再用"内建名白名单"判定:见下方 class_type_names,
|
||
# 唯一判据是"是否有类定义"(_HasClassDefinition:Gen._struct_sha1_map
|
||
# / Gen.structs)。内建(int/CInt/…)与语言内建 `str`(LLVM 映射 i8*)
|
||
# 都不在类表里 → 天然判为值类型,无需名表。
|
||
# 历史教训(名表判据的代价,保留以便回归时理解):`str` 曾漏在
|
||
# "非类类型名"集合外 → `list[str]` 的类型参数被误判为类类型,特化后
|
||
# 方法签名被额外包一层 `CPtr[...]`(append/set 形参 i8**、get/pop 返回
|
||
# i8**)→ 调用点多解一层 load(读字符串首 8 字节)→ ASan 崩溃。
|
||
# 注意 _BUILTIN_TYPE_NAMES 本身仍保留:它用于 type_map 替换
|
||
# 与 _from_import_aliases 注册,不能把 'str' 并进去
|
||
# (否则 HandlesTypeMerge 会把注解 `str` 当内建类型名参与替换)。
|
||
type_map: dict[str, str] = {}
|
||
for i, tp_name in enumerate(type_param_names):
|
||
if type_names and i < len(type_names):
|
||
tn: str = type_names[i]
|
||
# 判断是否为内建类型名(如 'CInt'):
|
||
# 内建类型必须用源码名(type_name)替换 T(CInt → i32),否则
|
||
# 用 mangled type_arg(如 'i32')替换会产生 'i32.__sizeof__' 这类
|
||
# 源码中不存在的名称([FATAL][__sizeof__] 类型 'i32' 无法解析)。
|
||
# 真正的类类型参数(如 'AST'/'ast.AST')才用 mangled type_arg
|
||
# (带 sha1 前缀 + ptr 后缀),避免模板内部嵌套注解被替换成裸短名
|
||
# 后重新特化出只有 declare、无方法体的错误特化(list[AST].__len__
|
||
# undefined symbol 根因)。_make_replacement_node 会把 mangled 名
|
||
# 还原为 'CPtr[sha1.AST]',重新解析时拼回一致的 mangled 名。
|
||
tn_bare: str = tn.split('.')[-1] if '.' in tn else tn
|
||
if tn_bare in _BUILTIN_TYPE_NAMES:
|
||
type_map[tp_name] = tn
|
||
elif i < len(type_args):
|
||
type_map[tp_name] = type_args[i]
|
||
else:
|
||
type_map[tp_name] = tn
|
||
else:
|
||
type_map[tp_name] = type_args[i]
|
||
# 检测哪些类型参数在原始类型实参中带有指针语义(CPtr[T] / rawptr[T] 等)
|
||
# 当 type_arg 以 '*' 结尾(mangling 把每个 CPtr 层渲染为一层 '*')且对应的
|
||
# type_name(去模块前缀后)不是内建类型名时,说明调用方写了
|
||
# list[CPtr[AST]] / list[rawptr[AST]]。注意用 tn_bare 判断:
|
||
# 'CPtr' 去前缀后是 'CPtr'(内建),不算类类型参数。
|
||
cptr_params: set[str] = set()
|
||
for i, tp_name in enumerate(type_param_names):
|
||
type_arg: str = type_args[i]
|
||
if type_arg.endswith('*'):
|
||
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
||
tn_bare_c: str = tn.split('.')[-1] if '.' in tn else tn
|
||
if tn_bare_c not in _BUILTIN_TYPE_NAMES:
|
||
cptr_params.add(tp_name)
|
||
# Bug 2 修复:识别特化为 class 类型的类型参数
|
||
# 这类参数在方法签名中是裸 T,特化后为裸 ClassName(值类型)
|
||
# 需要加 CPtr[...] 使其成为指针类型(class 实例应按指针传递)
|
||
# 判据 = "是否有类定义"(_HasClassDefinition),存**裸名**:注解侧的
|
||
# 比较也用裸名(T 替换后的 'sha1.Param' 去前缀)——此前存带模块前缀的
|
||
# tn(如 'ast.AST')而比较用裸名 'AST',前缀形态永不命中。
|
||
class_type_names: set[str] = set()
|
||
for i, tp_name in enumerate(type_param_names):
|
||
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
||
tn_bare_cls: str = tn.split('.')[-1] if '.' in tn else tn
|
||
if self._HasClassDefinition(tn_bare_cls, Gen):
|
||
class_type_names.add(tn_bare_cls)
|
||
def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None:
|
||
"""解析基类名称的类型种类
|
||
|
||
查询顺序:
|
||
1. _builtin_type_symbols(内建类型符号)
|
||
2. TypeSystem 内建类型属性(CEnum / CUnion / CStruct / REnum)
|
||
3. 返回 None 表示不是已知标记基类
|
||
|
||
Returns:
|
||
'enum' | 'union' | 'renum' | 'struct' | None
|
||
"""
|
||
# 1) 查 _builtin_type_symbols(别名导入)
|
||
symtab: object = self.Trans.SymbolTable
|
||
cls: type | None = symtab._builtin_type_symbols.get(base_name)
|
||
if cls is not None:
|
||
if issubclass(cls, (TypeSystem.CEnum, TypeSystem.REnum)):
|
||
return 'renum' if issubclass(cls, TypeSystem.REnum) else 'enum'
|
||
if issubclass(cls, TypeSystem.CUnion):
|
||
return 'union'
|
||
if issubclass(cls, TypeSystem.CStruct):
|
||
return 'struct'
|
||
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
|
||
# 不应被编译为真实结构体。
|
||
if issubclass(cls, TypeSystem.CType):
|
||
return 'ctype_marker'
|
||
|
||
# 2) 查 TypeSystem 内建类型属性(直接引用 CEnum 等)
|
||
t_cls: type | None = getattr(TypeSystem, base_name, None)
|
||
if isinstance(t_cls, type) and issubclass(t_cls, TypeSystem.CType):
|
||
if issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum)):
|
||
return 'renum' if issubclass(t_cls, TypeSystem.REnum) else 'enum'
|
||
if issubclass(t_cls, TypeSystem.CUnion):
|
||
return 'union'
|
||
if issubclass(t_cls, TypeSystem.CStruct):
|
||
return 'struct'
|
||
# CType 及其子类是"类型强转"标记,不编译为结构体。
|
||
return 'ctype_marker'
|
||
|
||
return None
|
||
|
||
@staticmethod
|
||
def _is_classname_ctype_marker(class_name: str) -> bool:
|
||
"""检查类名是否是 CType 的"类型强转"标记子类。
|
||
|
||
只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/
|
||
CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等)
|
||
才应跳过编译。有 BASE position 的基本类型(CInt/CChar/CSizeT/CLong 等)
|
||
有具体大小,应被正常编译。CType 基类本身无 bases,base 检测无法触发,
|
||
需要直接按类名检查。
|
||
|
||
注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault,
|
||
所以这里直接用 getattr(TypeSystem, name) 检查内建类型属性。
|
||
|
||
Returns:
|
||
True 如果 class_name 是 CType 标记子类名(应跳过编译)
|
||
"""
|
||
if not class_name:
|
||
return False
|
||
# 直接查 TypeSystem 内建类型属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian)
|
||
t_cls: type | None = getattr(TypeSystem, class_name, None)
|
||
if not isinstance(t_cls, type) or not issubclass(t_cls, TypeSystem.CType):
|
||
return False
|
||
if issubclass(t_cls, (TypeSystem.CStruct, TypeSystem.CEnum, TypeSystem.REnum, TypeSystem.CUnion)):
|
||
return False
|
||
# 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过
|
||
# CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过
|
||
if TypeSystem.CType.BASE in t_cls.position:
|
||
try:
|
||
inst = t_cls()
|
||
size_val = getattr(inst, 'Size', None)
|
||
if size_val is not None and size_val > 0:
|
||
return False
|
||
except Exception:
|
||
pass
|
||
return True
|
||
|
||
def _resolve_decorator_kind(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> str | None:
|
||
"""从装饰器列表中解析结构体类型种类
|
||
|
||
支持 @CStruct, @CUnion, @CEnum, @REnum(内建标记按裸名书写)
|
||
|
||
Returns:
|
||
'enum' | 'union' | 'renum' | 'struct' | None
|
||
"""
|
||
if not hasattr(Node, 'decorator_list') or not Node.decorator_list:
|
||
return None
|
||
symtab: object = self.Trans.SymbolTable
|
||
for decorator in Node.decorator_list:
|
||
attr_name: str | None = None
|
||
# 内建标记按裸名书写(@CStruct / @CUnion / ...)
|
||
if isinstance(decorator, ast.Name):
|
||
cls: type | None = getattr(TypeSystem, decorator.id, None)
|
||
if cls is None and hasattr(symtab, '_builtin_type_symbols'):
|
||
cls = symtab._builtin_type_symbols.get(decorator.id)
|
||
if cls is not None and isinstance(cls, type) and issubclass(cls, TypeSystem.CType):
|
||
attr_name = cls.__name__
|
||
if attr_name:
|
||
# 查 _builtin_type_symbols 和 TypeSystem 内建类型属性以确定种类
|
||
resolved_cls: type | None = None
|
||
if hasattr(symtab, '_builtin_type_symbols'):
|
||
resolved_cls = symtab._builtin_type_symbols.get(attr_name)
|
||
if resolved_cls is None:
|
||
resolved_cls = getattr(TypeSystem, attr_name, None)
|
||
if resolved_cls is not None and isinstance(resolved_cls, type):
|
||
if issubclass(resolved_cls, TypeSystem.REnum):
|
||
return 'renum'
|
||
if issubclass(resolved_cls, TypeSystem.CEnum):
|
||
return 'enum'
|
||
if issubclass(resolved_cls, TypeSystem.CUnion):
|
||
return 'union'
|
||
if issubclass(resolved_cls, TypeSystem.CStruct):
|
||
return 'struct'
|
||
return None
|
||
|
||
def _resolve_class_flags(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> tuple[bool, bool, str | None, bool, bool]:
|
||
"""解析类的 Object/CVTable 标志和父类信息
|
||
|
||
Returns:
|
||
tuple: (IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable,
|
||
VtableByClassLevel)
|
||
VtableByClassLevel:**忽略方法级 CVTable 标记**算出的 vtable 状态(= 类级
|
||
CVTable / 继承链判定),供 vtable 槽筛选(SymbolUtils.IsVtableSlotMethod)
|
||
使用——与 VPC _should_method_be_virtual 第 3/4 条的判据一致。
|
||
"""
|
||
ClassName: str = Node.name
|
||
IsCpythonObject: bool = False
|
||
IsCVTable: bool = False
|
||
IsNoVTable: bool = False
|
||
if hasattr(Node, 'decorator_list') and Node.decorator_list:
|
||
for decorator in Node.decorator_list:
|
||
if isinstance(decorator, ast.Name):
|
||
if decorator.id == 'Object':
|
||
IsCpythonObject = True
|
||
elif decorator.id == 'CVTable':
|
||
IsCVTable = True
|
||
elif decorator.id == 'NoVTable':
|
||
IsNoVTable = True
|
||
elif isinstance(decorator, ast.Call):
|
||
# 检测 @Attribute(attr.packed)
|
||
if isinstance(decorator.func, ast.Name) and decorator.func.id == 'Attribute':
|
||
for arg in decorator.args:
|
||
if (isinstance(arg, ast.Attribute)
|
||
and isinstance(arg.value, ast.Name)
|
||
and arg.value.id == 'attr'
|
||
and arg.attr == 'packed'):
|
||
Gen.class_packed.add(ClassName)
|
||
class_graph: dict = Gen._class_graph
|
||
if class_graph.get(ClassName, {}).get('has_methods', False) and not IsNoVTable:
|
||
if not IsCpythonObject:
|
||
IsCpythonObject = True
|
||
# 多继承支持(与 VPC _detect_vtable_status 对齐):不再因"作为其他类的基类"
|
||
# 自动启用 vtable。vtable 状态统一由继承链决定(见下方 HasParentClass 判定):
|
||
# 类自身无 @CVTable 时,父类有 vtable → 子类有;父类无 vtable → 子类静态。
|
||
# 否则基类(如 C(A,B) 中的 A/B)被自动加 vptr 后,其字段区在子类中的偏移
|
||
# 与自身布局不一致,继承方法按自身布局读 self 会字段错位。
|
||
HasParentClass: bool = False
|
||
ParentClassName: str | None = None
|
||
ParentClasses: list[str] = []
|
||
ParentIsNoVTable: bool = False
|
||
if Node.bases:
|
||
for base in Node.bases:
|
||
base_name: str | None = None
|
||
if hasattr(base, 'id'):
|
||
base_name = base.id
|
||
elif hasattr(base, 'attr'):
|
||
base_name = base.attr
|
||
if base_name:
|
||
kind: str | None = self._resolve_base_kind(base_name, Gen)
|
||
if kind is not None or base_name in TypeSystem._MARKER_BASES:
|
||
continue # 标记基类,跳过
|
||
# 多继承:收集所有真实父类(声明顺序),不再 break
|
||
ParentClasses.append(base_name)
|
||
if ParentClassName is None:
|
||
ParentClassName = base_name
|
||
if base_name in class_graph or base_name in Gen.class_members or base_name in Gen.structs:
|
||
HasParentClass = True
|
||
# 检测父类是否有 @NoVTable 标记(非多态继承)
|
||
if class_graph.get(base_name, {}).get('has_novtable', False):
|
||
ParentIsNoVTable = True
|
||
# 跨模块父类:检查 _cross_module_novtable 集合
|
||
if base_name in Gen._cross_module_novtable:
|
||
ParentIsNoVTable = True
|
||
if HasParentClass and not IsCVTable and not IsNoVTable and not ParentIsNoVTable:
|
||
# 继承链统一 vtable(与 VPC _detect_vtable_status 一致):
|
||
# 父类有 vtable → 子类启用;父类无 vtable → 子类不启用(静态);
|
||
# 父类 vtable 状态未知(跨模块/未注册)→ 保守启用。
|
||
# 沿继承链追溯父类的 vtable 状态(支持空中间基类 Stmt/ExprNode):
|
||
# Stmt/ExprNode 无方法但 @CVTable,跨模块加载时 _has_methods_prescan=False
|
||
# 未注册 class_vtable,若只查直接父类会误判子类为静态类 →
|
||
# __before_init__ base=0 不写 vtable → 实例 vtable 为 null → 虚调用段错误。
|
||
# 修复:沿 class_parent 链向上查,任一祖先有 vtable 即判定子类有 vtable。
|
||
_parent_has_vtable: bool = False
|
||
_p_chain: str | None = ParentClassName
|
||
_p_visited_chain: set[str] = {ClassName}
|
||
_class_parent_map: dict = getattr(Gen, 'class_parent', {})
|
||
while _p_chain and _p_chain not in _p_visited_chain:
|
||
_p_visited_chain.add(_p_chain)
|
||
if (_p_chain in Gen.class_vtable
|
||
or _p_chain in Gen._cross_module_vtable_classes):
|
||
_parent_has_vtable = True
|
||
break
|
||
_p_chain = _class_parent_map.get(_p_chain)
|
||
parent_has_vtable: bool = _parent_has_vtable
|
||
parent_known: bool = (ParentClassName in class_graph
|
||
or ParentClassName in Gen.class_members
|
||
or ParentClassName in Gen.structs)
|
||
if parent_has_vtable or not parent_known:
|
||
IsCVTable = True
|
||
# 方法级 virtual(`virtual def m(...)` ⇒ 方法装饰器 @CVTable)触发类级 vtable:
|
||
# 与 VPC ClassGenBase._detect_vtable_status 的三条 `_has_any_func_cvtable`
|
||
# 分支逐条对齐(类级 NoVTable / 父类 NoVTable / 无真实父类)。
|
||
# 注意"父类已知且无 vtable" **不**触发(VPC 同分支返回 0)——
|
||
# 父类按无 vptr 布局而子类插 vptr 会让继承方法字段错位。
|
||
VtableByClassLevel: bool = IsCVTable
|
||
if (not VtableByClassLevel and ClassHasFuncLevelCVTable(Node)
|
||
and (IsNoVTable or ParentIsNoVTable or not HasParentClass)):
|
||
IsCVTable = True
|
||
if IsCVTable:
|
||
Gen.class_vtable.add(ClassName)
|
||
# 沿继承链向上传播,将所有祖先类加入 vtable
|
||
visited: set[str] = {ClassName}
|
||
ancestor: str | None = ParentClassName
|
||
while ancestor and ancestor not in visited:
|
||
visited.add(ancestor)
|
||
Gen.class_vtable.add(ancestor)
|
||
# 查询祖先类的父类
|
||
ancestor_info: dict | None = class_graph.get(ancestor)
|
||
if ancestor_info:
|
||
ancestor_bases: list = ancestor_info.get('bases', [])
|
||
next_ancestor: str | None = None
|
||
for ab in ancestor_bases:
|
||
if ab not in TypeSystem._MARKER_BASES and ab not in visited:
|
||
next_ancestor = ab
|
||
break
|
||
ancestor = next_ancestor
|
||
else:
|
||
# 类图中没有,尝试从 class_parent 查询
|
||
ancestor = Gen.class_parent.get(ancestor)
|
||
return IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable, VtableByClassLevel
|
||
|
||
def _RegisterGenericClassTemplate(self, Node: ast.ClassDef) -> None:
|
||
"""注册泛型类模板到 `_generic_class_templates`(判据唯一:`_is_generic_class`)。
|
||
|
||
调用点两处:类处理阶段(_EmitClassLlvm)与前置声明之前的本模块预扫描
|
||
(PrescanModuleGenericClassTemplates)。注册内容唯一(node/type_params/
|
||
定义模块 SHA1),两个调用点不得各写一份。
|
||
"""
|
||
if not hasattr(self, '_generic_class_templates'):
|
||
self._generic_class_templates = {}
|
||
self._generic_class_templates[Node.name] = {
|
||
'node': Node,
|
||
'type_params': [tp.name for tp in Node.type_params],
|
||
# 记录泛型模板定义模块的 SHA1,用于特化时统一命名空间
|
||
'sha1': getattr(self.Trans, '_module_sha1', None),
|
||
}
|
||
|
||
def PrescanModuleGenericClassTemplates(self, ModuleBody: object) -> None:
|
||
"""前置声明之前预注册**本模块**泛型类模板。
|
||
|
||
判据与 includes 侧对泛型类的注册(HandlesImports._LoadModuleDeclarationsFromFile/
|
||
_EmitImportFromDeclarations 的 `node.type_params` 非空)**同源**,即
|
||
_is_generic_class,不看类名白名单。
|
||
|
||
类处理阶段(下方 _EmitClassLlvm)才注册本模块模板,而顶层函数前置声明
|
||
(GenerateLlvmDirect 的 _EmitFunctionForwardDeclLlvm)已需要它:模块级函数
|
||
参数/返回注解写自身泛型类(`def f(b: Box[Node])`)时
|
||
_SubscriptHitsGenericTemplate 判为不命中 → TypeAnnotationResolver 解析为空 →
|
||
VoidType → 抛"无法识别的参数类型注解";而同模块方法参数(类处理阶段之后)
|
||
却可用,二者分裂。预注册后两处走同一 _generic_class_templates。
|
||
"""
|
||
for Node in ModuleBody:
|
||
if isinstance(Node, ast.ClassDef) and self._is_generic_class(Node):
|
||
self._RegisterGenericClassTemplate(Node)
|
||
|
||
# ==================================================================
|
||
# _EmitNestedClassDefs - 递归发射类体内的嵌套 class / struct
|
||
#
|
||
# 命名与引用口径(用户 2026-10-01 定,与 union/renum 嵌套命名同源):
|
||
# · 内层结构体名 = `{外类}_{内类}`(Gen.structs / class_members 等同键);
|
||
# · 引用:限定名 `外类.内类`(TypeAnnotationResolver._from_node_attribute 的
|
||
# 扁平名回退)与扁平名 `外类_内类`(裸名直查 SymbolTable)都可用;
|
||
# · 多层嵌套自然递归为 A_B_C(deepcopy 后改名再递归)。
|
||
# 用 deepcopy 而不是临时改原名:源码 AST 节点还会被 _CollectOwnMemberTypes /
|
||
# SymbolExtractor / vpi 写出等路径读到,不得留下改名的副作用。
|
||
# ==================================================================
|
||
def _EmitNestedClassDefs(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
|
||
"""把类体内的嵌套 ClassDef 逐个以 `{外类}_{内类}` 递归发射(见上方注释)"""
|
||
if Node is None:
|
||
return
|
||
Body: list | None = getattr(Node, 'body', None)
|
||
ClassName: str | None = getattr(Node, 'name', None)
|
||
if not Body or not ClassName:
|
||
return
|
||
for Item in list(Body):
|
||
if not isinstance(Item, ast.ClassDef):
|
||
continue
|
||
InnerName: str | None = getattr(Item, 'name', None)
|
||
if not InnerName:
|
||
continue
|
||
NestedName: str = f'{ClassName}_{InnerName}'
|
||
# 已发射过(多遍/重复调用)只补名字登记,不重复发射
|
||
if NestedName in Gen.structs and NestedName in Gen.class_members:
|
||
self._RegisterNestedClassName(ClassName, InnerName, NestedName)
|
||
continue
|
||
NestedNode: ast.ClassDef = copy.deepcopy(Item)
|
||
NestedNode.name = NestedName
|
||
self._EmitClassLlvm(NestedNode, Gen)
|
||
self._RegisterNestedClassName(ClassName, InnerName, NestedName)
|
||
|
||
def _RegisterNestedClassName(self, ClassName: str, InnerName: str, NestedName: str) -> None:
|
||
"""登记嵌套类名的三种写法(裸名 / `外类.内类` / 扁平名)
|
||
|
||
与 _EmitREnumLlvm 的变体三键登记同口径(见本文件 REnum 变体注册处),
|
||
供"限定名扁平回退"与"裸名直查"两条解析路径命中。
|
||
"""
|
||
MemberNode: CTypeInfo = CTypeInfo()
|
||
MemberNode.Name = NestedName
|
||
MemberNode.BaseType = TypeSystem.CStruct(name=NestedName)
|
||
MemberNode.IsStruct = True
|
||
self.Trans.SymbolTable.insert(NestedName, MemberNode)
|
||
self.Trans.SymbolTable.insert(f'{ClassName}.{InnerName}', MemberNode)
|
||
|
||
def _EmitClassLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin, declare_only: bool = False) -> None:
|
||
ClassName: str = Node.name
|
||
# CType 及其子类(CChar/CInt/CVoid/CPtr/CTypeDefault 等)是"类型强转"标记,
|
||
# 不应被编译为真实结构体。CType 基类本身无 bases,base 检测无法触发,
|
||
# 此处在方法入口直接按类名跳过。
|
||
if self._is_classname_ctype_marker(ClassName):
|
||
return
|
||
if self._is_generic_class(Node):
|
||
self._RegisterGenericClassTemplate(Node)
|
||
return
|
||
if self._is_exception_class(Node):
|
||
self._RegisterExceptionClass(Node)
|
||
return
|
||
IsCenum: bool = False
|
||
IsCunion: bool = False
|
||
IsRenum: bool = False
|
||
# 先检查装饰器形式(@CStruct / @CEnum / @CUnion / @REnum)
|
||
deco_kind: str | None = self._resolve_decorator_kind(Node, Gen)
|
||
if deco_kind == 'enum':
|
||
IsCenum = True
|
||
elif deco_kind == 'union':
|
||
IsCunion = True
|
||
elif deco_kind == 'renum':
|
||
IsRenum = True
|
||
# 再检查基类继承形式(class X(CStruct):),与装饰器合并
|
||
if not IsCenum and not IsCunion and not IsRenum and Node.bases:
|
||
for base in Node.bases:
|
||
base_name: str | None = None
|
||
if hasattr(base, 'attr'):
|
||
base_name = base.attr
|
||
elif hasattr(base, 'id'):
|
||
base_name = base.id
|
||
if base_name:
|
||
kind: str | None = self._resolve_base_kind(base_name, Gen)
|
||
if kind == 'enum':
|
||
IsCenum = True
|
||
break
|
||
elif kind == 'union':
|
||
IsCunion = True
|
||
elif kind == 'renum':
|
||
IsRenum = True
|
||
elif kind == 'ctype_marker':
|
||
# CType 及其子类(CChar/CInt/CVoid/CPtr/CTypeDefault 等)是
|
||
# "类型强转"标记,不应被编译为真实结构体。直接 return 跳过编译。
|
||
return
|
||
if IsCenum:
|
||
self._RegisterEnumMembers(Node)
|
||
return
|
||
if IsCunion:
|
||
self._EmitUnionLlvm(Node, Gen)
|
||
return
|
||
if IsRenum:
|
||
self._EmitREnumLlvm(Node, Gen)
|
||
return
|
||
IsCpythonObject: bool
|
||
IsCVTable: bool
|
||
ParentClassName: str | None
|
||
IsNoVTable: bool
|
||
VtableByClassLevel: bool
|
||
IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable, VtableByClassLevel = self._resolve_class_flags(Node, Gen)
|
||
# 嵌套类 / 嵌套 struct:类体里再写 class / struct 此前被**静默忽略**(本函数的
|
||
# 字段/方法遍历只认 AnnAssign / FunctionDef,CollectAnnAssignMember 对其它节点
|
||
# 直接返回 None)。现按既有扁平命名先例发射为独立结构体 `{外类}_{内类}`
|
||
# (与 _EmitUnionLlvm:1569 / _EmitREnumLlvm:1715 的 `f"{ClassName}_{Nested}"`
|
||
# 同源),并登记 SymbolTable 三键,使 `外类.内类` 与扁平名 `外类_内类` 都能解析。
|
||
# 时机:在 flags 解析之后、class_members 初始化之前 —— 让嵌套结构体先就绪,
|
||
# 外层字段注解引用 `外类.内类` 时即可命中(_resolve_class_flags 内的名字键
|
||
# 均已按 ClassName 建立,递归改名不影响外层)。
|
||
self._EmitNestedClassDefs(Node, Gen)
|
||
# 跟踪正在发射的类,防止递归特化时 _generate_structs 过早为空成员类设置 body
|
||
Gen._classes_in_progress.add(ClassName)
|
||
# 标记正在收集字段,阻止继承处理(_ResolveGenericSlice → _specialize_generic_class)
|
||
# 和 CollectAnnAssignMember 触发的嵌套 _generate_structs 用不完整 class_members 调用 set_body
|
||
Gen._collecting_members_set.add(ClassName)
|
||
if ClassName not in Gen.class_methods:
|
||
Gen.class_methods[ClassName] = []
|
||
else:
|
||
# 防御性清除:移除导入阶段可能添加的构造函数(__new__/__init__/__before_init__)。
|
||
# 构造函数不参与虚分派,放入 vtable 会导致子类与基类 vtable 大小不一致,
|
||
# 索引偏移破坏多态分派(如 Module 有 __new__/__init__ 使 vtable=7,而 AST 无它们 vtable=5,
|
||
# 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。
|
||
Gen.class_methods[ClassName] = [
|
||
m for m in Gen.class_methods[ClassName]
|
||
if m.split('.')[-1] not in ('__new__', '__init__', '__before_init__')
|
||
]
|
||
# 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明。
|
||
# 关键:如果本地类是 @NoVTable 但同名导入类有 vtable(名称冲突),
|
||
# 必须清除 vtable 状态,否则 _generate_structs 会错误添加 vtable 指针。
|
||
if IsNoVTable:
|
||
Gen.class_vtable.discard(ClassName)
|
||
Gen._cross_module_vtable_classes.discard(ClassName)
|
||
Gen._cross_module_novtable.add(ClassName)
|
||
# 清除可能从导入 stub 加载的旧 struct body(含错误 vtable 指针),
|
||
# 让 _generate_structs 用本地 class_members 重新生成。
|
||
# 字段名必须是 llvmlite 的**公开属性 `elements`**(is_opaque = elements is None;
|
||
# set_body 仅在 elements is not None 时拒绝)——写 `_elements` 在本版本是空操作,
|
||
# 会让"权威重建点"永远无法刷新已冻结的错误布局。
|
||
_old_st = Gen.structs.get(ClassName)
|
||
if isinstance(_old_st, ir.IdentifiedStructType) and _old_st.elements is not None:
|
||
_old_st.elements = None
|
||
_ih = getattr(Gen, '_import_handler_ref', None)
|
||
if _ih is not None:
|
||
_ck = (id(Gen), ClassName)
|
||
if _ck in _ih._struct_Load_cache:
|
||
del _ih._struct_Load_cache[_ck]
|
||
Gen.class_members[ClassName] = []
|
||
# 本地定义是权威重建点:先撤销"已展平"登记,重建完成(且父类齐全)后再登记。
|
||
Gen._members_flattened.discard(ClassName)
|
||
Gen.class_member_defaults[ClassName] = {}
|
||
Gen.class_member_signeds[ClassName] = {}
|
||
Gen.class_member_bitfields[ClassName] = {}
|
||
Gen.class_member_byteorders[ClassName] = {}
|
||
Gen.class_member_bitoffsets[ClassName] = {}
|
||
ParentClass: str | None = None
|
||
ParentClasses: list[str] = []
|
||
# 本类展平是否完整(父类若在此刻尚未就绪会被跳过 ⇒ 不登记已展平,
|
||
# 留待查询侧 HandlesImports.EnsureClassMembersFlattened 补齐,顺序无关)。
|
||
_local_flat_complete: bool = True
|
||
if Node.bases:
|
||
class_graph: dict = Gen._class_graph
|
||
for base in Node.bases:
|
||
if hasattr(base, 'id'):
|
||
base_name = base.id
|
||
elif hasattr(base, 'attr'):
|
||
base_name = base.attr
|
||
elif isinstance(base, ast.Subscript):
|
||
# 泛型特化基类:GSListNode[GNode]
|
||
# 特化泛型类,用特化名作为父类名
|
||
spec_name: str | None = self.Trans.ExprCallHandle._ResolveGenericSlice(base)
|
||
if spec_name:
|
||
base_name = spec_name
|
||
else:
|
||
continue
|
||
else:
|
||
continue
|
||
if base_name == ClassName:
|
||
continue
|
||
if base_name in ('Object', 'CVTable', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
|
||
continue
|
||
# 多继承:收集所有真实父类(声明顺序),不再 break。
|
||
# 总是记录父类名,即使父类 class_members 未加载。
|
||
# _get_member_offset 会沿 class_parent 链回退查找继承字段。
|
||
if ParentClass is None:
|
||
ParentClass = base_name
|
||
Gen.class_parent[ClassName] = ParentClass
|
||
ParentClasses.append(base_name)
|
||
if ParentClasses:
|
||
Gen.class_parents[ClassName] = ParentClasses
|
||
if ParentClasses:
|
||
# ============================================================
|
||
# 多继承字段展平:遍历所有父类(声明顺序),字段名**不去重**,
|
||
# __vtable__ 跳过(vtable 指针由 _generate_structs 按 class_vtable 统一添加)。
|
||
# 布局: [父类1字段..., 父类2字段..., 子类字段...](MRO 正序,与
|
||
# DeclarationGenerator stub / VPC 参考实现一致)。
|
||
#
|
||
# 关键修复(2026-08-10):原实现用 `inherited + class_members`(prepend)
|
||
# 产出 MRO 反序布局,且按字段名去重(如多个 Mixin 各自声明的 TempDir
|
||
# 被剔除)——导致定义模块 struct 与跨模块 stub 布局不一致,所有多继承
|
||
# 类字段运行时错位(ASan 下读到 0xbe 填充崩溃)。Mixin 方法体以自身
|
||
# 局部索引独立编译,调用侧 this_adjust + 块内索引依赖"展平块与 Mixin
|
||
# 自身逐字段一致",因此跨父类不能去重。菱形继承(A→D, B→D)会让 D
|
||
# 字段重复——当前项目 Mixin 为兄弟无共享祖先;若未来出现真菱形需改为
|
||
# "按继承源去重"而非"按字段名去重"。
|
||
# ============================================================
|
||
# 按继承源去重(2026-08-18):菱形继承(子类同时继承 A、B、D 且
|
||
# A/B 也继承 D)会让 D 的字段被重复展平。典型:Generator 同时继承
|
||
# ClassGenMixin/ClassGenEnum/ClassGenGeneric/ClassGenVTable/ClassGenDef/
|
||
# ClassGenBase,而前 5 个都继承 ClassGenBase → ClassGenBase 41 字段
|
||
# 被展平 6 次,struct 膨胀且 this_adjust/字段 GEP 全部错位。
|
||
# 修复:递归展平整个继承树,每个类只处理一次;每类只贡献
|
||
# "非祖先字段"(class_members[类] 是含祖先的展平结果,需剔除祖先
|
||
# 部分)。同名字段(如 TempDir 在 CallGenBase/TypeGenBase 各自声明)
|
||
# 因非继承关系,两个类都贡献,各自保留——符合下方 L654 注释的
|
||
# "按继承源去重"而非"按字段名去重"。
|
||
def _FlattenInherited(cls_name: str, _seen_cls: set,
|
||
_out: list, _gen) -> None:
|
||
if cls_name in _seen_cls:
|
||
return
|
||
_seen_cls.add(cls_name)
|
||
for _gp in _gen.class_parents.get(cls_name, []) or []:
|
||
_FlattenInherited(_gp, _seen_cls, _out, _gen)
|
||
# 收集该类的全部祖先字段名(含间接),剔除自身已展平结果中
|
||
# 属于祖先的部分(避免 class_members[类] 里混合的祖先字段重复)
|
||
_anc_names: set[str] = set()
|
||
_stack: list[str] = [cls_name]
|
||
_vis: set[str] = set()
|
||
while _stack:
|
||
_c = _stack.pop()
|
||
for _gp in _gen.class_parents.get(_c, []) or []:
|
||
if _gp in _vis:
|
||
continue
|
||
_vis.add(_gp)
|
||
_stack.append(_gp)
|
||
for _mn, _mt in _gen.class_members.get(_gp, []) or []:
|
||
_anc_names.add(_mn)
|
||
for _mn, _mt in _gen.class_members.get(cls_name, []) or []:
|
||
if _mn == '__vtable__':
|
||
continue
|
||
if _mn in _anc_names:
|
||
continue
|
||
_out.append((_mn, _mt))
|
||
_pd: dict = dict(_gen.class_member_defaults.get(cls_name, {}))
|
||
if _mn in _pd:
|
||
_gen.class_member_defaults[ClassName][_mn] = _pd[_mn]
|
||
|
||
_seen_cls: set[str] = set()
|
||
_flat: list[tuple] = []
|
||
for ParentClass in ParentClasses:
|
||
if ParentClass not in class_graph and ParentClass not in Gen.class_members:
|
||
# 父类尚未就绪(跨模块父类在此刻未加载 / 特化表未生成)⇒
|
||
# 本类展平不完整,不登记 _members_flattened。
|
||
_local_flat_complete = False
|
||
continue
|
||
_FlattenInherited(ParentClass, _seen_cls, _flat, Gen)
|
||
if _flat:
|
||
# 【幂等(2026-09-30)】该祖先块已作为**连续整段**存在于本表时不再追加:
|
||
# 本处是**追加**(`class_members + _flat`),与导入侧的
|
||
# `PrependInheritedBlock`(前置,自带表头判据)判据不对称,"块已在表中段/
|
||
# 尾部"的情形谁都不判 ⇒ 整块再插一次,表里多出 len(_flat) 条重复条目,
|
||
# body 随之多出同名槽(现场:output/<sha1>.stub.ll 的 TypeGenCType 73 槽
|
||
# = temp 声明 41 槽 + 其 [9:41] 的原样副本;同族 7 个类,
|
||
# 下游即 Repl.vp:802 的"基座 pointee 未匹配任何 struct")。
|
||
# 判据(名字 + IR 类型逐项连续匹配)与成因见
|
||
# HandlesImports.InheritedBlockAlreadyPresent;只跳过重复、不改其余布局。
|
||
from lib.core.Handles.HandlesImports import NormalizeAncestralCopies as _NormAnc
|
||
# 【规范化(2026-09-30)】_NormAnc 同时完成两件事:
|
||
# ① "块已整段在头/尾 ⇒ 不再追加"(等价于原 InheritedBlockAlreadyPresent);
|
||
# ② 剥掉两端挂着的"祖先块前缀的**陈旧半截副本**"——此前某次展平写入的是
|
||
# 半截祖先块(父类表当时只收到前 k 项),本次整块追加就让那 k 条留在表里
|
||
# 成重复(现场:ClassGenDef 表 50 / 去重 42 / body 42 ⇒ 8 条陈旧副本)。
|
||
# 判据与成因见 HandlesImports.NormalizeAncestralCopies。
|
||
_Trimmed: list
|
||
_HasFull: bool
|
||
_Trimmed, _HasFull = _NormAnc(list(Gen.class_members[ClassName]), _flat, InsertAtHead=False)
|
||
_Dropped: int = len(Gen.class_members[ClassName]) - len(_Trimmed)
|
||
if _Dropped > 0:
|
||
_vlog().warning(
|
||
f"[成员展平] 类 '{ClassName}' 追加祖先块({len(_flat)} 项)前剥掉 "
|
||
f"{_Dropped} 条**陈旧半截副本**(重名条目不占布局槽位,却会让 "
|
||
f"base/下标回退失准):表 {len(Gen.class_members[ClassName])} → "
|
||
f"{len(_Trimmed)} 项",
|
||
"成员展平")
|
||
Gen.class_members[ClassName] = _Trimmed
|
||
if _HasFull:
|
||
_vlog().warning(
|
||
f"[成员展平] 类 '{ClassName}' 的祖先块({len(_flat)} 项)已存在于成员表"
|
||
f"(表 {len(Gen.class_members[ClassName])} 项)⇒ 跳过重复追加"
|
||
f"(重复会让 body 多出同名槽、与 Phase 1 声明布局分叉)",
|
||
"成员展平")
|
||
else:
|
||
Gen.class_members[ClassName] = _Trimmed + _flat
|
||
# ============================================================
|
||
# 多继承方法合并:遍历所有父类(声明顺序)收集方法(短名去重,先声明父类优先),
|
||
# vtable 槽/方法名用"实际定义类.方法"(如 B.get_b,与 VPC 一致),
|
||
# 不再生成子类包装器 "ClassName.method"(旧逻辑注册了包装器但未生成函数体,
|
||
# 导致链接 undefined reference,如 C.get_b / ColoredCircle.color_code / Vec2Both.extra_val)。
|
||
# ============================================================
|
||
all_parent_methods: list[str] = []
|
||
parent_method_names_seen: set[str] = set()
|
||
for ParentClass in ParentClasses:
|
||
for pm in list(Gen.class_methods.get(ParentClass, [])):
|
||
method_name: str = pm.split('.')[-1] if '.' in pm else pm
|
||
if method_name in ('__new__', '__init__', '__before_init__'):
|
||
continue
|
||
if method_name in parent_method_names_seen:
|
||
continue # 先声明父类优先,菱形去重
|
||
parent_method_names_seen.add(method_name)
|
||
all_parent_methods.append(pm)
|
||
if all_parent_methods:
|
||
# 构建子类已有方法映射(方法短名 -> 方法全名)。
|
||
# 子类覆盖判定:既查 class_methods(prescan/导入阶段已注册),
|
||
# 也直接扫描 ClassDef 自身的方法(与 VPC _collect_vtable_methods 一致)。
|
||
child_method_map: dict[str, str] = {}
|
||
for m in Gen.class_methods[ClassName]:
|
||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||
child_method_map[method_name] = m
|
||
for _item_self in Node.body:
|
||
if isinstance(_item_self, ast.FunctionDef):
|
||
_mn_self: str = _item_self.name
|
||
if _mn_self in ('__new__', '__init__', '__before_init__'):
|
||
continue
|
||
child_method_map[_mn_self] = f"{ClassName}.{_mn_self}"
|
||
# 父类方法在前(保证 vtable 布局一致性,子类多态分派索引正确),
|
||
# 子类新增方法在后。子类覆盖的方法放在父类方法的位置(用子类实现)。
|
||
new_methods: list = []
|
||
covered_names: set[str] = set()
|
||
for pm in all_parent_methods:
|
||
method_name: str = pm.split('.')[-1] if '.' in pm else pm
|
||
if method_name in child_method_map:
|
||
# 子类覆盖了父类方法 — 用子类的实现,放在父类的位置
|
||
new_methods.append(child_method_map[method_name])
|
||
covered_names.add(method_name)
|
||
else:
|
||
# 父类独有方法 — 直接用父类方法原名(定义类名,如 B.get_b)
|
||
new_methods.append(pm)
|
||
covered_names.add(method_name)
|
||
# 添加子类新增方法(不在父类中的)
|
||
for m in list(Gen.class_methods[ClassName]):
|
||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||
if method_name not in covered_names:
|
||
new_methods.append(m)
|
||
Gen.class_methods[ClassName] = new_methods
|
||
# 提取首个裸字符串字面量作为结构体 __doc__ docstring
|
||
if (Node.body and isinstance(Node.body[0], ast.Expr)
|
||
and isinstance(Node.body[0].value, ast.Constant)
|
||
and isinstance(Node.body[0].value.value, str)):
|
||
Gen._create_doc_global(ClassName, Node.body[0].value.value)
|
||
else:
|
||
Gen._create_doc_global(ClassName, None)
|
||
# 解析 __provides__/__requires__/__require_must__ 编译期元数据
|
||
for item in Node.body:
|
||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||
field_name: str = item.target.id
|
||
if field_name in ('__provides__', '__requires__', '__require_must__') and item.value:
|
||
values: list[str] = []
|
||
if isinstance(item.value, ast.List):
|
||
for elt in item.value.elts:
|
||
if isinstance(elt, ast.Constant) and isinstance(elt.value, str):
|
||
values.append(elt.value)
|
||
if field_name == '__provides__':
|
||
Gen.class_provides[ClassName] = values
|
||
elif field_name == '__requires__':
|
||
Gen.class_requires[ClassName] = values
|
||
elif field_name == '__require_must__':
|
||
Gen.class_require_must[ClassName] = values
|
||
# 自有字段追加段的起点(供下方"字段名遮蔽"检查切分自有/继承两段;
|
||
# 此时 class_members[ClassName] 只含继承前缀,见 :825)。
|
||
_OwnFieldStart: int = len(Gen.class_members[ClassName])
|
||
# 【嵌套重入防重(2026-09-30)】本循环**每轮都可能重入**同一张表:
|
||
# CollectAnnAssignMember → ResolveAnnotationType → 泛型特化(list[X] 等)
|
||
# → _generate_structs / _TryLoadClassMembersFromPyi → _EmitExternalClassDeclLlvm
|
||
# → 可按 .vpi **清空并重填**本类成员表(HandlesImports.py:3408 的 force 分支,
|
||
# 由 HandlesImports.py:2647/2654 与 FuncGen.py:1057 触发;该分支不受
|
||
# "字段收集中"保护,见 HandlesImports.py:3299 的 `not force` 豁免)。
|
||
# 此时本循环后面的 `append` 会把**嵌套帧已经登记过的同一字段**再写一条 ——
|
||
# 现场:AST 的最后一个字段 `children: CPtr[list[rawptr[AST]]]` 是全类唯一
|
||
# 触发泛型特化的注解,处理它时嵌套帧重填了 AST 表(7 项),本循环恢复后
|
||
# 又追加一次 `children` ⇒ 表 8 项 / 去重 7 项,重名条目 `children@7`;
|
||
# 该表又被祖先块展平**原样拷贝**给 AST 的每个子类(_FlattenInherited 只按
|
||
# 祖先名过滤、不按名去重)⇒ StructGen 的"[结构体布局] 成员表含重名条目"
|
||
# 在大量 AST 子类上齐发(AST/Stmt/ExprNode/MatchCase/ExceptHandler…)。
|
||
# 判据刻意收窄:**只跳过"本轮循环开始之后才出现"的同名条目**(嵌套帧刚登记
|
||
# 的那条)。循环前已在表里的同名(继承前缀/同名字段)照旧追加 ⇒ 上方
|
||
# "字段名遮蔽"fail-fast 的判据(自有段切分)与既有布局语义逐字不变。
|
||
_StartNames: set[str] = {m[0] for m in Gen.class_members[ClassName]}
|
||
for item in Node.body:
|
||
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
|
||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||
if item.target.id in ('__provides__', '__requires__', '__require_must__'):
|
||
continue
|
||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||
Line: int = getattr(item.annotation, 'lineno', 0) or 0
|
||
raise TypeError(
|
||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||
if parsed:
|
||
VarName, MemberType, TypeInfo = parsed
|
||
if VarName not in _StartNames \
|
||
and VarName in {m[0] for m in Gen.class_members[ClassName]}:
|
||
continue
|
||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||
# const / volatile 类字段登记(统一登记入口,见 BaseGen)。
|
||
# 键 `类名.字段名` + 裸字段名;与 ViperC 侧 ClassGenDef 的
|
||
# FieldEntry.IsConst/IsVolatile/PointeeVolatile 同口径。
|
||
Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation)
|
||
if TypeInfo:
|
||
# Subscript 容器/指针字段(list[X] / CPtr[list[X]] /
|
||
# rawptr[GSList[X]]):记录容器/特化名,供字段方法分派与
|
||
# 泛型特化结构体指针字段解析使用;身份丢失会导致
|
||
# "Undefined method 'get' in class 'rawptr'"(Converter.vp L190)。
|
||
# 旧联合写法(如 `GSList[BasicBlock] | CPtr`)已由循环入口
|
||
# fail-fast 拦截,不再走合并路径。与 HandlesImports 对称,
|
||
# 用与特化生成端同源的 _resolve_type_arg_str 记录 element_class。
|
||
if isinstance(item.annotation, ast.Subscript):
|
||
_ann_sub_c: ast.Subscript = item.annotation
|
||
_subv_c: ast.AST = _ann_sub_c.value
|
||
_subname_c: str = getattr(_subv_c, 'id', None) or getattr(_subv_c, 'attr', '')
|
||
_elem_slice_c: ast.AST | None = None
|
||
if _subname_c == 'list':
|
||
_elem_slice_c = _ann_sub_c.slice
|
||
elif _subname_c in _PTR_SUBSCRIPT_NAMES:
|
||
_slice_c: ast.AST = _ann_sub_c.slice
|
||
if isinstance(_slice_c, ast.Subscript):
|
||
# rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]):
|
||
# 容器身份 = 泛型特化名。list 继续走 _elem_slice_c 统一登记;
|
||
# 其余泛型容器直接登记 element_class(阻塞 B 根因链一环:
|
||
# 原实现只认内层 list,rawptr[GSList[Param]] 在此空转并跳过
|
||
# 裸结构分支 → element_class 缺失 → 字段/局部变量方法分派
|
||
# 丢失容器身份,FakeDuck 错绑 LinkedNode.append 写穿)。
|
||
_inner_sub_c: ast.Subscript = _slice_c
|
||
_iname_c: str = getattr(_inner_sub_c.value, 'id', None) or getattr(_inner_sub_c.value, 'attr', '')
|
||
if _iname_c == 'list':
|
||
_elem_slice_c = _inner_sub_c.slice
|
||
else:
|
||
_ec_gc: str | None = None
|
||
if _iname_c:
|
||
try:
|
||
_ec_gc = f'{_iname_c}[{self.Trans.ExprCallHandle._resolve_type_arg_str(_inner_sub_c.slice)}]'
|
||
except Exception:
|
||
_ec_gc = None
|
||
if _ec_gc:
|
||
if ClassName not in Gen.class_member_element_class:
|
||
Gen.class_member_element_class[ClassName] = {}
|
||
Gen.class_member_element_class[ClassName][VarName] = _ec_gc
|
||
else:
|
||
# rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内
|
||
# 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复
|
||
# struct 身份走 char*→struct cast。指针统一为 Subscript
|
||
# (`rawptr[Token]` / `CPtr[Token]`),由本分支登记。
|
||
# 与 HandlesImports 的 rawptr 分支对称。
|
||
_slc_name_c: str | None = None
|
||
if isinstance(_slice_c, ast.Name):
|
||
_slc_name_c = _slice_c.id
|
||
elif isinstance(_slice_c, ast.Attribute):
|
||
_slc_name_c = _slice_c.attr
|
||
_ec_target_c: str | None = None
|
||
if _slc_name_c:
|
||
if _slc_name_c in Gen.structs:
|
||
_ec_target_c = _slc_name_c
|
||
else:
|
||
_st_sha1_c: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(_slc_name_c)
|
||
if _st_sha1_c and f'{_st_sha1_c}.{_slc_name_c}' in Gen.structs:
|
||
_ec_target_c = f'{_st_sha1_c}.{_slc_name_c}'
|
||
else:
|
||
# 短名模糊扫描(对齐 HandlesAnnAssign 变量侧
|
||
# 补偿 L597-602):跨模块 `mod.Class` 形态的
|
||
# rawptr[Class] 字段在 class_sha1_map 尚无该短名
|
||
# 时上面两路全 miss → element_class 静默缺失 →
|
||
# 字段方法调用(factory.PermPool.alloc)链尾类名
|
||
# 丢失 → TPC 调用分派返回 i32 0 哨兵 → 误报
|
||
# "Unknown module: ...PermPool"。
|
||
for _ec_k_c in Gen.structs:
|
||
_ec_short_c: str = _ec_k_c.split('.')[-1] if '.' in _ec_k_c else _ec_k_c
|
||
if _ec_short_c == _slc_name_c:
|
||
_ec_target_c = _ec_k_c
|
||
break
|
||
if _ec_target_c:
|
||
if ClassName not in Gen.class_member_element_class:
|
||
Gen.class_member_element_class[ClassName] = {}
|
||
Gen.class_member_element_class[ClassName][VarName] = _ec_target_c
|
||
if _elem_slice_c is not None:
|
||
_ec_c: str | None = None
|
||
try:
|
||
_ec_c = f'list[{self.Trans.ExprCallHandle._resolve_type_arg_str(_elem_slice_c)}]'
|
||
except Exception:
|
||
_ec_c = None
|
||
if _ec_c:
|
||
if ClassName not in Gen.class_member_element_class:
|
||
Gen.class_member_element_class[ClassName] = {}
|
||
Gen.class_member_element_class[ClassName][VarName] = _ec_c
|
||
if hasattr(TypeInfo.BaseType, 'IsSigned'):
|
||
Gen.class_member_signeds[ClassName][VarName] = TypeInfo.BaseType.IsSigned
|
||
else:
|
||
Gen.class_member_signeds[ClassName][VarName] = None
|
||
if TypeInfo.IsBitField:
|
||
Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth
|
||
else:
|
||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||
if TypeInfo.ByteOrder:
|
||
Gen.class_member_byteorders[ClassName][VarName] = TypeInfo.ByteOrder
|
||
else:
|
||
Gen.class_member_byteorders[ClassName][VarName] = ""
|
||
if item.value:
|
||
const: ir.Constant | None = self._BuildScalarConstant(item.value, MemberType, Gen)
|
||
if const:
|
||
Gen.class_member_defaults[ClassName][VarName] = const
|
||
else:
|
||
Gen.class_member_signeds[ClassName][VarName] = None
|
||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||
# ============================================================
|
||
# 【字段名遮蔽 fail-fast】类体声明的字段名与**任一祖先声明的字段名**重名 ⇒ 终止编译
|
||
#
|
||
# 这不是风格问题:本仓两条既有机制决定了"同名"必然产出**写错槽**,且是静默的。
|
||
# ① 子类同名声明会成为**自有字段**,与**同名继承项**在 class_members 里并存;
|
||
# 跨模块侧的前置过滤器(HandlesImports._FlattenExt 前置段 :2516-2521)按
|
||
# "名字已在表内"过滤——它本意只是防同一函数重入时重复前置,却会把**同名继承项
|
||
# 整条丢掉** ⇒ 继承段与 struct body 的继承前缀失去一一对应:被丢项**之后**的
|
||
# 继承字段表内下标整体前移 k(k = 被丢项数),而查询侧回退路径用的是
|
||
# `base + 表内下标`(FuncGen._get_member_offset)⇒ 落到**类型完全不同的槽**。
|
||
# 现场:TypeGenCType 重复声明 5 个父类已有字段后,继承字段
|
||
# LastBuiltinsTypedefResult(下标 32)前移为 27 = CTypedefNameIdxBuilt(i32)
|
||
# ⇒ `self.Gen.TypeGenCType.LastBuiltinsTypedefResult = "CPtr"` 报
|
||
# "指针隐式转整数已禁止:不能把指针类型 i8* 赋给整数类型 i32"。
|
||
# ② 父类方法按**父类布局**访问该名字的槽、子类方法按**自有槽**访问 ⇒ 同名两槽
|
||
# split-brain(一侧写、另一侧读),运行期静默错值。
|
||
# 唯一合法写法:字段只在其**归属类**声明一次;子类要新字段就换名字。
|
||
# 合法例外(不在本检查范围):两个**互不为祖先**的类各自声明同名字段
|
||
# (如 CallGenBase / TypeGenBase 的 TempDir)——那不属于遮蔽。
|
||
# 判据来源:自有 = 本类类体追加段(:903 快照起);祖先 = 沿 class_parents 传递收集
|
||
# 各祖先 class_members 的声明名(含仅从 .vpi 加载的祖先;祖先未就绪则该项不成判据,
|
||
# 不产生误报)。
|
||
# ============================================================
|
||
_AncestorFieldNames: dict[str, str] = {}
|
||
_AncSeen: set[str] = set()
|
||
# class_parents 可能尚未建立(HandlesImports 同族代码也用 hasattr 兜底),
|
||
# 缺失时视为"无祖先"——只可能少报、不可能误报。
|
||
_ParentsMap: dict = getattr(Gen, 'class_parents', None) or {}
|
||
_AncStack: list[str] = list(_ParentsMap.get(ClassName) or [])
|
||
while _AncStack:
|
||
_Anc: str = _AncStack.pop()
|
||
if not _Anc or _Anc in _AncSeen:
|
||
continue
|
||
_AncSeen.add(_Anc)
|
||
for _An, _ in Gen.class_members.get(_Anc) or []:
|
||
if _An != '__vtable__':
|
||
_AncestorFieldNames.setdefault(_An, _Anc)
|
||
_AncStack.extend(_ParentsMap.get(_Anc) or [])
|
||
_OwnFieldNames: list[str] = [n for n, _ in Gen.class_members[ClassName][_OwnFieldStart:]]
|
||
_Shadowed: list[str] = sorted({_n for _n in _OwnFieldNames if _n in _AncestorFieldNames})
|
||
if _Shadowed:
|
||
_Decl: ast.AST | None = None
|
||
for _it in Node.body:
|
||
if (isinstance(_it, ast.AnnAssign) and isinstance(_it.target, ast.Name)
|
||
and _it.target.id in _Shadowed):
|
||
_Decl = _it
|
||
break
|
||
_src: str = getattr(Gen, '_current_source_file', '') or ''
|
||
_ln: int = (getattr(_Decl, 'lineno', 0) or getattr(Node, 'lineno', 0) or 0)
|
||
_col: int = getattr(_Decl, 'col_offset', -1) if _Decl is not None else -1
|
||
# 行号还原:AST 行号含 _inject_auto_imports 注入的 N 行(同
|
||
# HandlesBase._FailFastFixedArrayKeyword / _ErrorStack 各站点)。
|
||
_off: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _off > 0 and _ln > _off:
|
||
_ln -= _off
|
||
_code: str = ''
|
||
try:
|
||
_code = (Gen._get_source_line(_ln) or '').strip()
|
||
except Exception:
|
||
_code = ''
|
||
_Pairs: str = '、'.join(f"'{_n}'(祖先 '{_AncestorFieldNames[_n]}' 已声明)"
|
||
for _n in _Shadowed)
|
||
_msg: str = (
|
||
f"类 '{ClassName}' 的类体字段与祖先类声明的字段**重名**:{_Pairs}。"
|
||
f"字段只能在其归属类声明一次(子类要新字段请改名;若确实要复用父类字段,"
|
||
f"删掉子类的这条声明即可)——重名会让该名字在 class_members 里变成"
|
||
f"「自有字段 + 同名继承项」两份,跨模块展平的按名过滤会丢掉继承项,"
|
||
f"使其后所有继承字段的表内下标整体前移、写入落到类型不同的槽"
|
||
f"(典型:指针值写进 i32 槽 → 「指针隐式转整数已禁止」);"
|
||
f"父类方法与子类方法还会各自访问不同槽(同一变量 split-brain)。"
|
||
f"位置 {_src}:{_ln}:{_col}")
|
||
_vlog().compile_error(_msg, _src, _ln, _code)
|
||
sys.exit(1)
|
||
# 字段收集完成,清除标志,允许后续 _generate_structs 正常设置 body
|
||
Gen._collecting_members_set.discard(ClassName)
|
||
existing_members: set[str] = {m[0] for m in Gen.class_members[ClassName]}
|
||
for item in Node.body:
|
||
if isinstance(item, ast.FunctionDef):
|
||
self._current_method_args = {}
|
||
for arg in item.args.args:
|
||
if arg.arg != 'self' and arg.annotation:
|
||
self._current_method_args[arg.arg] = arg.annotation
|
||
self._scan_method_body_for_self_members(item.body, ClassName, existing_members, Gen)
|
||
self._current_method_args = {}
|
||
for item in Node.body:
|
||
if isinstance(item, ast.FunctionDef):
|
||
MethodName: str = item.name
|
||
FullMethodName: str = f"{ClassName}.{MethodName}"
|
||
# property setter/deleter 使用不同的函数名后缀
|
||
item_meta: FuncMeta = self.Trans.FunctionHandler._ExtractFuncMeta(item.decorator_list)
|
||
if FuncMeta.PROPERTY_SETTER in item_meta:
|
||
FullMethodName = FullMethodName + '$set'
|
||
elif FuncMeta.PROPERTY_DELETER in item_meta:
|
||
FullMethodName = FullMethodName + '$del'
|
||
# 构造函数(__new__/__init__)不放入 vtable,避免子类与基类
|
||
# vtable 大小不一致导致虚分派索引偏移。__before_init__ 由 TPC
|
||
# 自动生成,不会出现在 FunctionDef 中,此处一并防御。
|
||
#
|
||
# 方法级修饰符(`novirtual def m(...)` ⇒ @NoVTable /
|
||
# `virtual def m(...)` ⇒ @CVTable):是否占槽按
|
||
# SymbolUtils.IsVtableSlotMethod 判定——与 VPC
|
||
# ClassGenBase._should_method_be_virtual 同判据(**唯一规则源**),
|
||
# 故 TPC/VPC 的虚表槽位顺序与数量逐槽一致(含"类级 NoVTable +
|
||
# 方法级 CVTable ⇒ 仍生成虚表且只有该方法进槽"这一组合形态)。
|
||
# 仅在本类确有 vtable(IsCVTable)时筛选:无 vtable 的类不进
|
||
# Vtables,class_methods 仍保留全部方法供静态解析/继承包装使用。
|
||
if MethodName not in ('__new__', '__init__', '__before_init__'):
|
||
_IsSlot: bool = (not IsCVTable) or IsVtableSlotMethod(item, VtableByClassLevel)
|
||
if _IsSlot and FullMethodName not in Gen.class_methods[ClassName]:
|
||
Gen.class_methods[ClassName].append(FullMethodName)
|
||
Gen.register_method(ClassName, FullMethodName, _IsSlot)
|
||
else:
|
||
Gen.register_method(ClassName, FullMethodName)
|
||
if IsCVTable:
|
||
Gen.class_vtable.add(ClassName)
|
||
Gen._generate_structs()
|
||
Gen._create_Vtable_globals()
|
||
if _local_flat_complete:
|
||
# 登记"该表已按父类展平":供 _TryLoadClassMembersFromPyi 的 guard 与
|
||
# FuncGen._member_base 的查询前补齐使用(与跨模块路径同一口径)。
|
||
Gen._members_flattened.add(ClassName)
|
||
# _create_Vtable_globals 会跳过正在发射中的类(方法列表可能不完整),
|
||
# 当前类的方法已全部注册(L559-571),此处显式创建其 vtable
|
||
if IsCVTable:
|
||
Gen._create_vtable_for_class(ClassName)
|
||
if ClassName in Gen.structs:
|
||
self._EmitNewFunctionLlvm(ClassName, Gen, IsCVTable=IsCVTable, IsCpythonObject=IsCpythonObject)
|
||
for item in Node.body:
|
||
if isinstance(item, ast.FunctionDef):
|
||
self.Trans.FunctionHandler._EmitFunctionForwardDeclLlvm(item, Gen, ClassName=ClassName)
|
||
if not declare_only:
|
||
for item in Node.body:
|
||
if isinstance(item, ast.FunctionDef):
|
||
self.Trans.FunctionHandler._EmitFunctionLlvm(item, Gen, ClassName=ClassName)
|
||
if IsCVTable and ClassName in Gen.Vtables:
|
||
self._fill_vtable_with_methods(ClassName, Gen)
|
||
# 多继承支持:不再生成子类包装器(_generate_inherited_method_wrappers)。
|
||
# 包装器只对 self 做 bitcast 基址转换,不调整字段偏移——对多继承中
|
||
# 第二个及之后的父类(字段区偏移 > 0)会错位。继承方法统一走
|
||
# MRO 祖先链查找 + this 调整(见 HandlesExprCall._adjust_this_for_inherited_method),
|
||
# 与 VPC 一致。
|
||
Gen._classes_in_progress.discard(ClassName)
|
||
|
||
def _generate_inherited_method_wrappers(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
|
||
"""为子类继承但未覆写的方法生成包装函数,使跨模块调用能正确链接。
|
||
|
||
例如 Label 继承 Widget.place,生成 Label.place 函数,
|
||
内部将 self 从 Label* bitcast 为 Widget*,然后调用 Widget.place。
|
||
"""
|
||
# 收集本类方法 + 沿 MRO 继承链收集父类方法名
|
||
# 原代码只遍历 class_methods[ClassName],遗漏父类独有方法(如 __enter__),
|
||
# 导致子类调用继承的方法时链接失败(undefined reference)
|
||
methods: list = list(Gen.class_methods.get(ClassName, []))
|
||
seen_shorts: set[str] = {m.split('.')[-1] if '.' in m else m for m in methods}
|
||
mro_list: list[str] = Gen._get_mro_chain(ClassName)
|
||
for anc in mro_list[1:]: # 跳过自身,先声明父类优先(MRO 已去重)
|
||
parent_methods: list = Gen.class_methods.get(anc, [])
|
||
for pm in parent_methods:
|
||
pm_short: str = pm.split('.')[-1] if '.' in pm else pm
|
||
# 避免重复:如果子类已覆写同名方法,不添加
|
||
if pm_short not in seen_shorts:
|
||
seen_shorts.add(pm_short)
|
||
methods.append(pm)
|
||
if not methods:
|
||
return
|
||
if ClassName not in Gen.structs:
|
||
return
|
||
|
||
for method_name in methods:
|
||
method_short: str = method_name.split('.')[-1] if '.' in method_name else method_name
|
||
child_full: str = f"{ClassName}.{method_short}"
|
||
|
||
# 如果子类已经有该方法的实现,跳过
|
||
if Gen._find_function(child_full):
|
||
continue
|
||
|
||
# 沿 MRO 继承链查找父类实现(先声明父类优先)
|
||
parent_func: ir.Function | None = None
|
||
parent_class: str | None = None
|
||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||
parent_full: str = f"{anc}.{method_short}"
|
||
parent_func = Gen._find_function(parent_full)
|
||
if parent_func:
|
||
parent_class = anc
|
||
break
|
||
|
||
if not parent_func or not parent_class:
|
||
continue
|
||
|
||
# 父类和子类都需要有 struct 定义
|
||
if parent_class not in Gen.structs:
|
||
continue
|
||
|
||
# 构造子类包装函数签名:与父类函数相同,但 self 参数类型为子类指针
|
||
parent_ftype: ir.FunctionType = parent_func.function_type
|
||
parent_ret_type: ir.Type = parent_ftype.return_type
|
||
parent_param_types: list[ir.Type] = list(parent_ftype.args)
|
||
is_vararg: bool = parent_ftype.var_arg
|
||
|
||
# 判断父类方法是否是静态方法:
|
||
# 如果第一个参数类型是父类指针,说明是实例方法;否则是静态方法
|
||
parent_struct_ptr_type: ir.PointerType | None = ir.PointerType(Gen.structs[parent_class]) if parent_class in Gen.structs else None
|
||
is_static: bool = True
|
||
if parent_param_types and parent_struct_ptr_type:
|
||
first_param: ir.Type = parent_param_types[0]
|
||
# 检查第一个参数是否是父类指针(或可以 bitcast 为父类指针的指针类型)
|
||
if isinstance(first_param, ir.PointerType):
|
||
if isinstance(first_param.pointee, ir.IdentifiedStructType):
|
||
if first_param.pointee.name == Gen.structs[parent_class].name:
|
||
is_static = False
|
||
elif first_param == ir.IntType(8):
|
||
# i8* 可能是前向声明时的 self 类型,视为实例方法
|
||
is_static = False
|
||
|
||
if is_static:
|
||
# 静态方法:签名与父类完全一致,不需要 self 参数
|
||
child_param_types: list[ir.Type] = list(parent_param_types)
|
||
child_struct_ptr: ir.PointerType | None = None
|
||
else:
|
||
# 实例方法:替换第一个参数(self)的类型为子类指针
|
||
child_struct_ptr = ir.PointerType(Gen.structs[ClassName])
|
||
if parent_param_types:
|
||
child_param_types = [child_struct_ptr] + parent_param_types[1:]
|
||
else:
|
||
child_param_types = [child_struct_ptr]
|
||
|
||
child_func_type: ir.FunctionType = ir.FunctionType(parent_ret_type, child_param_types, var_arg=is_vararg)
|
||
child_mangled: str = Gen._mangle_func_name(child_full)
|
||
child_func: ir.Function = Gen._get_or_declare_function(child_mangled, child_func_type)
|
||
Gen.functions[child_full] = child_func
|
||
|
||
# 生成函数体
|
||
entry_block: ir.Block = child_func.append_basic_block(name="entry")
|
||
saved_builder: ir.IRBuilder = Gen.builder
|
||
saved_func: ir.Function = Gen.func
|
||
Gen.builder = Gen._NewIrBuilder(entry_block)
|
||
Gen.func = child_func
|
||
|
||
# 准备参数
|
||
call_args: list[ir.Value] = []
|
||
if is_static:
|
||
# 静态方法:参数直接传递,不做 bitcast
|
||
for arg in child_func.args:
|
||
call_args.append(arg)
|
||
else:
|
||
# 实例方法:bitcast self,其余参数直接传递
|
||
for i, arg in enumerate(child_func.args):
|
||
if i == 0 and parent_param_types:
|
||
actual_self_type: ir.Type = parent_param_types[0]
|
||
casted_self: ir.Value = Gen.builder.bitcast(arg, actual_self_type, name="self_cast")
|
||
call_args.append(casted_self)
|
||
else:
|
||
call_args.append(arg)
|
||
|
||
result: ir.Value = Gen.builder.call(parent_func, call_args, name="inherited_call")
|
||
|
||
if isinstance(parent_ret_type, ir.VoidType):
|
||
Gen.builder.ret_void()
|
||
else:
|
||
Gen.builder.ret(result)
|
||
|
||
Gen.builder = saved_builder
|
||
Gen.func = saved_func
|
||
|
||
def _fill_vtable_with_methods(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
|
||
methods: list = Gen.class_methods.get(ClassName, [])
|
||
if not methods or ClassName not in Gen.Vtables:
|
||
return
|
||
Vtable: ir.GlobalVariable = Gen.Vtables[ClassName]
|
||
VtableType: ir.Type = Vtable.type.pointee
|
||
null_i8ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||
initializers: list[ir.Constant] = []
|
||
for mi, method_name in enumerate(methods):
|
||
# 多继承:vtable 槽直接用完整方法名(实际定义类.方法,如 B.get_b),
|
||
# 与 VPC 一致,避免"子类名.方法"包装器导致链接 undefined reference。
|
||
func: ir.Function | None = Gen._find_function(method_name)
|
||
if not func:
|
||
func = Gen._find_function(f"{method_name}__")
|
||
if not func:
|
||
method_short: str = method_name.split('.')[-1] if '.' in method_name else method_name
|
||
func = Gen._find_function(f"{ClassName}.{method_short}")
|
||
if not func:
|
||
func = Gen._find_function(f"{ClassName}.{method_short}__")
|
||
if not func:
|
||
# 沿 MRO 祖先链查找定义类(先声明父类优先)
|
||
for anc in Gen._get_mro_chain(ClassName)[1:]:
|
||
func = Gen._find_function(f"{anc}.{method_short}")
|
||
if not func:
|
||
func = Gen._find_function(f"{anc}.{method_short}__")
|
||
if func:
|
||
break
|
||
if func:
|
||
initializers.append(func.bitcast(ir.PointerType(ir.IntType(8))))
|
||
else:
|
||
initializers.append(null_i8ptr)
|
||
if initializers:
|
||
Vtable.initializer = ir.Constant(VtableType, initializers)
|
||
|
||
def _scan_method_body_for_self_members(self, body: list[ast.AST], ClassName: str, existing_members: set[str], Gen: LlvmGeneratorMixin) -> None:
|
||
for stmt in body:
|
||
self._scan_node_for_self_assign(stmt, ClassName, existing_members, Gen)
|
||
|
||
def _scan_node_for_self_assign(self, node: ast.AST, ClassName: str, existing_members: set[str], Gen: LlvmGeneratorMixin) -> None:
|
||
if isinstance(node, ast.AnnAssign):
|
||
if (isinstance(node.target, ast.Attribute)
|
||
and isinstance(node.target.value, ast.Name)
|
||
and node.target.value.id == 'self'):
|
||
VarName: str = node.target.attr
|
||
if VarName not in existing_members:
|
||
# fail-fast(项目约定:类型信息缺失立即终止,不兜底)。
|
||
# 此前三处静默 i32 兜底(FromNode 返回 None / _ctype_to_llvm 得 void /
|
||
# 解析抛异常)会把"声明没解析出来"伪装成"该成员是 i32",下游赋值/取址
|
||
# 检查于是报出与真因无关的错——实测:`free_lists: uint64*` 被当成 i32,
|
||
# `self.free_lists = base`(i8*) 因此误报"指针隐式转整数已禁止"。
|
||
AnnotationText: str = ast.unparse(node.annotation)
|
||
try:
|
||
TypeInfo: CTypeInfo | None = CTypeInfo.FromNode(node.annotation, self.Trans.SymbolTable)
|
||
if TypeInfo is None:
|
||
raise ValueError(
|
||
f"[FATAL] 类 '{ClassName}' 成员 '{VarName}' 的注解 "
|
||
f"'{AnnotationText}' 解析不出类型(CTypeInfo.FromNode 返回 None)"
|
||
f"—— 拒绝静默当作 i32"
|
||
)
|
||
MemberType: ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||
if isinstance(MemberType, ir.VoidType):
|
||
raise ValueError(
|
||
f"[FATAL] 类 '{ClassName}' 成员 '{VarName}' 的注解 "
|
||
f"'{AnnotationText}' 解析为 void(BaseType="
|
||
f"{getattr(TypeInfo, 'BaseType', None)} PtrCount="
|
||
f"{getattr(TypeInfo, 'PtrCount', None)} IsTypedef="
|
||
f"{getattr(TypeInfo, 'IsTypedef', None)} Name="
|
||
f"{getattr(TypeInfo, 'Name', None)})—— 拒绝静默当作 i32"
|
||
)
|
||
except Exception as e: # 成员类型解析失败:带注解原文与类/成员名终止
|
||
if isinstance(e, ValueError) and str(e).startswith('[FATAL]'):
|
||
raise
|
||
raise ValueError(
|
||
f"[FATAL] 类 '{ClassName}' 成员 '{VarName}' 的注解 "
|
||
f"'{AnnotationText}' 解析失败:{type(e).__name__}: {e}"
|
||
) from e
|
||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||
Gen.class_member_signeds[ClassName][VarName] = None
|
||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||
Gen.class_member_byteorders[ClassName][VarName] = ""
|
||
Gen.class_member_bitoffsets[ClassName][VarName] = 0
|
||
existing_members.add(VarName)
|
||
len_name = f'{VarName}__len'
|
||
if isinstance(MemberType, ir.PointerType) and node.value and isinstance(node.value, ast.List):
|
||
if len_name not in existing_members:
|
||
Gen.class_members[ClassName].append((len_name, ir.IntType(64)))
|
||
Gen.class_member_signeds[ClassName][len_name] = None
|
||
Gen.class_member_bitfields[ClassName][len_name] = 0
|
||
Gen.class_member_byteorders[ClassName][len_name] = ""
|
||
Gen.class_member_bitoffsets[ClassName][len_name] = 0
|
||
Gen.class_member_defaults[ClassName][len_name] = ir.Constant(ir.IntType(64), len(node.value.elts))
|
||
existing_members.add(len_name)
|
||
elif isinstance(node, ast.Assign):
|
||
for target in node.targets:
|
||
if (isinstance(target, ast.Attribute)
|
||
and isinstance(target.value, ast.Name)
|
||
and target.value.id == 'self'):
|
||
VarName = target.attr
|
||
if VarName not in existing_members:
|
||
# 类型判定:只接受**能唯一确定**的取值形态(下表);推不出即
|
||
# fail-fast,绝不静默产出 i32 槽(项目约定:类型信息缺失立即
|
||
# 终止;与同函数 `self.X: T` 分支 :1356-1386 同口径)。
|
||
# 同族现场:`free_lists: uint64*` 被当成 i32 后,
|
||
# `self.free_lists = base`(i8*) 误报"指针隐式转整数已禁止"。
|
||
# 【必须与 DeclarationGenerator._CollectOwnMemberTypes 的
|
||
# 同名规则逐条一致】否则 stub 与定义端 struct 布局分叉
|
||
# (stub 少/多一个槽 ⇒ 跨模块字段偏移整体错位):
|
||
# 整型字面量 → i32;布尔字面量 → i32(Python 中 bool 是 int
|
||
# 子类,维持既有 int 分支语义);浮点字面量 → double;
|
||
# 字符串字面量 → i8*;值为**本方法带注解的形参** → 该形参类型;
|
||
# 白名单调用 float()/double() → double、char() → i8、
|
||
# int()/long()/short() → i32、`x.len()` → i32。
|
||
# 其余(None 字面量、BinOp、任意调用/属性链…)→ fail-fast:
|
||
# 这些形态推不出成员类型,静默 i32 只会把错误推到下游
|
||
# (写指针值 → "指针隐式转整数已禁止")。
|
||
MemberType: ir.Type | None = None
|
||
if node.value is not None:
|
||
try:
|
||
if isinstance(node.value, ast.Constant):
|
||
if isinstance(node.value.value, bool):
|
||
MemberType = ir.IntType(32)
|
||
elif isinstance(node.value.value, int):
|
||
MemberType = ir.IntType(32)
|
||
elif isinstance(node.value.value, float):
|
||
MemberType = ir.DoubleType()
|
||
elif isinstance(node.value.value, str):
|
||
MemberType = ir.PointerType(ir.IntType(8))
|
||
elif isinstance(node.value, ast.Name):
|
||
if hasattr(self, '_current_method_args'):
|
||
arg_info = self._current_method_args.get(node.value.id)
|
||
if arg_info:
|
||
TypeInfo = CTypeInfo.FromNode(arg_info, self.Trans.SymbolTable)
|
||
if TypeInfo:
|
||
InferredType = Gen._ctype_to_llvm(TypeInfo)
|
||
if not isinstance(InferredType, ir.VoidType):
|
||
MemberType = InferredType
|
||
elif isinstance(node.value, ast.Call):
|
||
if isinstance(node.value.func, ast.Name):
|
||
if node.value.func.id in ('float', 'double'):
|
||
MemberType = ir.DoubleType()
|
||
elif node.value.func.id == 'char':
|
||
# char() 是内建 i8 强转(与 float()/double() 并列)
|
||
MemberType = ir.IntType(8)
|
||
elif node.value.func.id in ('int', 'long', 'short'):
|
||
MemberType = ir.IntType(32)
|
||
elif isinstance(node.value.func, ast.Attribute):
|
||
if node.value.func.attr == 'len':
|
||
MemberType = ir.IntType(32)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
if MemberType is None:
|
||
_src_f: str = getattr(Gen, '_current_source_file', '') or ''
|
||
_ln_f: int = getattr(node, 'lineno', 0) or 0
|
||
_col_f: int = getattr(node, 'col_offset', -1)
|
||
# 行号还原:AST 行号含 _inject_auto_imports 注入的 N 行
|
||
_off_f: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _off_f > 0 and _ln_f > _off_f:
|
||
_ln_f -= _off_f
|
||
_code_f: str = ''
|
||
try:
|
||
_code_f = (Gen._get_source_line(_ln_f) or '').strip()
|
||
except Exception:
|
||
_code_f = ''
|
||
_val_txt: str = ''
|
||
try:
|
||
_val_txt = ast.unparse(node.value) if node.value is not None else '<无值>'
|
||
except Exception:
|
||
_val_txt = '<无法反解析>'
|
||
_msg_f: str = (
|
||
f"类 '{ClassName}' 的字段 '{VarName}' 没有声明类型"
|
||
f"(既不在类体注解、也不在祖先中),且首次赋值 "
|
||
f"`self.{VarName} = {_val_txt}` 的取值形态推不出成员类型"
|
||
f"——拒绝静默当成 i32(那会把错误推到下游:写指针值时报"
|
||
f"「指针隐式转整数已禁止」)。请在类体声明该字段并给注解"
|
||
f"(如 `{VarName}: CInt32T` / `{VarName}: CPtr`),"
|
||
f"或在赋值处给出可定型的取值。"
|
||
f"位置 {_src_f}:{_ln_f}:{_col_f}")
|
||
_vlog().compile_error(_msg_f, _src_f, _ln_f, _code_f)
|
||
sys.exit(1)
|
||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||
Gen.class_member_signeds[ClassName][VarName] = None
|
||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||
Gen.class_member_byteorders[ClassName][VarName] = ""
|
||
Gen.class_member_bitoffsets[ClassName][VarName] = 0
|
||
existing_members.add(VarName)
|
||
for child in ast.iter_child_nodes(node):
|
||
if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
||
continue
|
||
self._scan_node_for_self_assign(child, ClassName, existing_members, Gen)
|
||
|
||
def _EmitUnionLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
|
||
ClassName: str = Node.name
|
||
union_member_types: list[ir.Type] = []
|
||
for item in Node.body:
|
||
if isinstance(item, ast.ClassDef):
|
||
nested_class_name: str = item.name
|
||
nested_member_types: list[ir.Type] = []
|
||
for nested_item in item.body:
|
||
parsed = self.CollectAnnAssignMember(nested_item, Gen)
|
||
if parsed:
|
||
nested_member_types.append(parsed[1])
|
||
if nested_member_types:
|
||
nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}")
|
||
nested_struct_type.set_body(*nested_member_types)
|
||
Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type
|
||
union_member_types.append(nested_struct_type)
|
||
nested_class_full_name: str = f"{ClassName}_{nested_class_name}"
|
||
if nested_class_full_name not in Gen.class_members:
|
||
Gen.class_members[nested_class_full_name] = []
|
||
if nested_class_full_name not in Gen.class_member_signeds:
|
||
Gen.class_member_signeds[nested_class_full_name] = {}
|
||
for nested_item in item.body:
|
||
parsed = self.CollectAnnAssignMember(nested_item, Gen)
|
||
if parsed:
|
||
VarName, MemberType, TypeInfo = parsed
|
||
Gen.class_members[nested_class_full_name].append((VarName, MemberType))
|
||
if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'):
|
||
Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned
|
||
else:
|
||
Gen.class_member_signeds[nested_class_full_name][VarName] = None
|
||
if union_member_types:
|
||
max_size: int = 0
|
||
for member_type in union_member_types:
|
||
# 统一走 Gen._get_struct_size(与 __sizeof__ / memhub alloc 同源)。
|
||
# llvmlite 并无 ir.DataLayout 类,原先那行必然抛 AttributeError,
|
||
# 再被 except 吞成 size=8 —— 静默少算,union 载荷区被开得过小。
|
||
size: int = Gen._get_struct_size(member_type)
|
||
max_size = max(max_size, size)
|
||
union_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, ClassName)
|
||
union_type.set_body(ir.ArrayType(ir.IntType(8), max_size))
|
||
Gen.structs[ClassName] = union_type
|
||
UnionNode: CTypeInfo = CTypeInfo()
|
||
UnionNode.Name = ClassName
|
||
UnionNode.IsUnion = True
|
||
self.Trans.SymbolTable.insert(ClassName, UnionNode)
|
||
|
||
def _EmitREnumLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
|
||
ClassName: str = Node.name
|
||
variant_info: list[tuple] = []
|
||
variant_names: list[str] = []
|
||
|
||
# 预注册 REnum opaque 结构体到 Gen.structs 和 SymbolTable,
|
||
# 使自引用成员(如 CPtr[LLVMType] / rawptr[LLVMType])在收集成员时能正确解析为 %LLVMType*。
|
||
# 若不预注册,GetCTypeInfo 找不到 LLVMType → 回退到 IsEnum → i32 → 再加一层指针 → i32*(错误)。
|
||
PreRenumType: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, ClassName)
|
||
Gen.structs[ClassName] = PreRenumType
|
||
PreTypeInfo: CTypeInfo = CTypeInfo()
|
||
PreTypeInfo.Name = ClassName
|
||
PreTypeInfo.BaseType = TypeSystem.REnum(ClassName)
|
||
PreTypeInfo.IsRenum = True
|
||
PreTypeInfo.IsEnum = True
|
||
# REnum 在内存布局上是 struct({ i32 __tag, <max_payload> }),
|
||
# 必须设置 IsStruct=True 才能让 HandlesTypeMerge 的 CPtr 吸收逻辑生效:
|
||
# `CPtr[REnumType]` 应得到 REnumType*(PtrCount=1)而非 REnumType**(PtrCount=2)。
|
||
# 否则 include-imported 函数返回类型会出现双指针,与声明单指针不匹配 → 运行时崩溃。
|
||
PreTypeInfo.IsStruct = True
|
||
PreTypeInfo.RenumVariants = []
|
||
self.Trans.SymbolTable.insert(ClassName, PreTypeInfo)
|
||
|
||
# 第一遍:收集显式赋值的 tag 值,确定起始索引
|
||
explicit_values: dict[str, int] = {}
|
||
for item in Node.body:
|
||
if isinstance(item, ast.Assign):
|
||
for target in item.targets:
|
||
if isinstance(target, ast.Name):
|
||
if item.value and isinstance(item.value, ast.Constant):
|
||
explicit_values[target.id] = item.value.value
|
||
# 类变体从 max(explicit_values, default=-1) + 1 开始
|
||
next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0
|
||
variant_index: int = 0
|
||
|
||
for item in Node.body:
|
||
if isinstance(item, ast.ClassDef):
|
||
VariantName: str = item.name
|
||
variant_names.append(VariantName)
|
||
member_types: list[ir.Type] = []
|
||
member_names: list[str] = []
|
||
member_annotations: list[ast.AST | None] = []
|
||
for nested_item in item.body:
|
||
parsed = self.CollectAnnAssignMember(nested_item, Gen)
|
||
if parsed:
|
||
VarName, MemberType, TypeInfo = parsed
|
||
member_types.append(MemberType)
|
||
member_names.append(VarName)
|
||
member_annotations.append(nested_item.annotation if TypeInfo else None)
|
||
# 类变体使用专用计数器,避免与显式值冲突
|
||
tag: int = next_class_tag
|
||
next_class_tag += 1
|
||
variant_info.append((VariantName, member_types, member_names, member_annotations, item.lineno, tag))
|
||
elif isinstance(item, ast.Assign):
|
||
for target in item.targets:
|
||
if isinstance(target, ast.Name):
|
||
VarName = target.id
|
||
variant_names.append(VarName)
|
||
value: int | None = None
|
||
if item.value and isinstance(item.value, ast.Constant):
|
||
value = item.value.value
|
||
else:
|
||
value = variant_index
|
||
variant_index += 1
|
||
variant_info.append((VarName, [], [], [], item.lineno, value))
|
||
# REnum 布局是所有变体的联合体。每个字段位置必须能容纳任何变体在该位置的字段。
|
||
# Bug 修复:原来只选总尺寸最大的变体,但不同变体在同一位置可能有不同尺寸的字段。
|
||
# 例如 MetaType: Concrete 位置3是 i32(4字节),但 Var 位置3是 MetaType*(8字节)。
|
||
# 用 Concrete 的布局会导致 Var.Instance 指针被截断为4字节 → 运行时崩溃。
|
||
# 修复:按每个位置的 max 字段尺寸构建布局。
|
||
def _ir_type_size(t: ir.Type) -> int:
|
||
if isinstance(t, ir.IntType):
|
||
return max(4, t.width // 8)
|
||
elif isinstance(t, ir.PointerType):
|
||
return 8
|
||
elif isinstance(t, ir.FloatType):
|
||
return 4
|
||
elif isinstance(t, ir.DoubleType):
|
||
return 8
|
||
elif isinstance(t, ir.ArrayType):
|
||
if isinstance(t.element, ir.IntType):
|
||
return t.element.width // 8 * t.count
|
||
return 8 * t.count
|
||
else:
|
||
return 8
|
||
|
||
all_variant_types: list[list[ir.Type]] = []
|
||
max_field_count: int = 0
|
||
for _, member_types, _, _, _, _ in variant_info:
|
||
if member_types:
|
||
full_types: list[ir.Type] = [ir.IntType(32)] + member_types
|
||
all_variant_types.append(full_types)
|
||
if len(full_types) > max_field_count:
|
||
max_field_count = len(full_types)
|
||
max_variant_struct: list[ir.Type] = []
|
||
for pos in range(max_field_count):
|
||
pos_max_size: int = 0
|
||
for vt in all_variant_types:
|
||
if pos < len(vt):
|
||
sz: int = _ir_type_size(vt[pos])
|
||
if sz > pos_max_size:
|
||
pos_max_size = sz
|
||
# 按最大尺寸选择 LLVM 类型:<=4 用 i32,>4 用 i64(8字节,可容纳指针)
|
||
if pos_max_size <= 4:
|
||
max_variant_struct.append(ir.IntType(32))
|
||
else:
|
||
max_variant_struct.append(ir.IntType(64))
|
||
if not max_variant_struct:
|
||
max_variant_struct = [ir.IntType(32), ir.IntType(32)]
|
||
# 复用预注册的 opaque 结构体,设置 body 使其完整
|
||
PreRenumType.set_body(*max_variant_struct)
|
||
for VariantName, member_types, member_names, member_annotations, lineno, tag_value in variant_info:
|
||
NestedStructName: str = f"{ClassName}_{VariantName}"
|
||
if member_types:
|
||
padded_member_types: list[ir.Type] = list(max_variant_struct)
|
||
nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, NestedStructName)
|
||
nested_struct_type.set_body(*padded_member_types)
|
||
Gen.structs[NestedStructName] = nested_struct_type
|
||
if NestedStructName not in Gen.class_members:
|
||
Gen.class_members[NestedStructName] = []
|
||
if NestedStructName not in Gen.class_member_signeds:
|
||
Gen.class_member_signeds[NestedStructName] = {}
|
||
Gen.class_members[NestedStructName].append(('__tag', ir.IntType(32)))
|
||
Gen.class_member_signeds[NestedStructName]['__tag'] = None
|
||
for i, (mname, mtype) in enumerate(zip(member_names, member_types)):
|
||
Gen.class_members[NestedStructName].append((mname, mtype))
|
||
try:
|
||
ti: CTypeInfo | None = CTypeInfo.FromNode(member_annotations[i], self.Trans.SymbolTable)
|
||
if ti and hasattr(ti.BaseType, 'IsSigned'):
|
||
Gen.class_member_signeds[NestedStructName][mname] = ti.BaseType.IsSigned
|
||
else:
|
||
Gen.class_member_signeds[NestedStructName][mname] = None
|
||
except Exception as e: # 回退:签名信息解析失败时设为 None
|
||
_vlog().warning(f"HandlesClassDef: 忽略异常 {e}", exc_info=e)
|
||
Gen.class_member_signeds[NestedStructName][mname] = None
|
||
MemberNode: CTypeInfo = CTypeInfo()
|
||
MemberNode.Name = VariantName
|
||
MemberNode.BaseType = TypeSystem.CEnum(ClassName)
|
||
MemberNode.value = tag_value
|
||
MemberNode.EnumName = ClassName
|
||
MemberNode.Lineno = lineno
|
||
MemberNode.IsEnumMember = True
|
||
self.Trans.SymbolTable.insert(VariantName, MemberNode)
|
||
# 同模块 REnum 变体也注册限定名和下划线名,
|
||
# 对齐跨模块导入(HandlesImports.py)的注册逻辑。
|
||
# 避免裸名被同名的工厂函数覆盖后,路径 2 的限定名查找失败。
|
||
self.Trans.SymbolTable.insert(f"{ClassName}.{VariantName}", MemberNode)
|
||
self.Trans.SymbolTable.insert(f"{ClassName}_{VariantName}", MemberNode)
|
||
# 更新预注册的 REnum 类型信息(填充变体列表)
|
||
PreTypeInfo.RenumVariants = variant_names
|
||
|
||
def _EnumMemberAnnotationIsPtr(self, annotation: ast.AST | None) -> bool:
|
||
"""枚举成员注解是否含指针形态(逐层下标),True=含指针
|
||
|
||
与 VPC 侧 ClassGenEnum._enum_member_annotation_is_ptr 同口径。枚举值是
|
||
整数常量,指针成员语义不成立,必须明确报错(fail-fast)而非静默接受:
|
||
`Name: CPtr` 不能被当成普通 i32 成员放行。
|
||
指针标记既按名字匹配(含 str/bytes = i8*、rawptr = CPtr),也按
|
||
_builtin_type_symbols 中的内建类型符号判定。
|
||
"""
|
||
if annotation is None:
|
||
return False
|
||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||
raise TypeError(
|
||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||
if isinstance(annotation, ast.Subscript):
|
||
return self._EnumMemberAnnotationIsPtr(annotation.value)
|
||
name: str | None = None
|
||
if isinstance(annotation, ast.Attribute):
|
||
name = annotation.attr
|
||
elif isinstance(annotation, ast.Name):
|
||
name = annotation.id
|
||
if name is None:
|
||
return False
|
||
if name in _ENUM_PTR_ANNOTATION_NAMES:
|
||
return True
|
||
symtab: object = self.Trans.SymbolTable
|
||
resolved: type | None = None
|
||
if hasattr(symtab, '_builtin_type_symbols'):
|
||
resolved = symtab._builtin_type_symbols.get(name)
|
||
if resolved is None:
|
||
resolved = getattr(TypeSystem, name, None)
|
||
if isinstance(resolved, type) and issubclass(resolved, TypeSystem.CPtr):
|
||
return True
|
||
return False
|
||
|
||
def _EnumClassIntWidth(self, Node: ast.ClassDef) -> int:
|
||
"""按"最宽成员类型"推导枚举存储宽度(bit)。
|
||
|
||
规则本体唯一:SymbolUtils.EnumClassIntWidth(定义端 / 跨模块 `.vpi` 读取端 /
|
||
符号表提取端 / 声明端共用同一函数),此处只注入本端 SymbolTable
|
||
(覆盖库内自定义 typedef 与 builtins 表)。无任何可解析为整数的成员
|
||
→ 默认 32——既有枚举全部落在此支,与改前的恒 i32 逐字一致(零行为变化)。
|
||
"""
|
||
return EnumClassIntWidth(Node.body, self.Trans.SymbolTable)
|
||
|
||
def _EnumSiteLoc(self, Node: ast.AST) -> str:
|
||
"""枚举 fail-fast 站点:`文件:行[:列]`(行号经 `_line_offset` 还原)+ 源码片段。
|
||
|
||
口径与 `_FailFastFixedArrayKeyword` / `SymbolUtils._DefineSiteInfo` 一致。
|
||
"""
|
||
Gen: object = getattr(self.Trans, 'LlvmGen', None)
|
||
lineno: int = int(getattr(Node, 'lineno', 0) or 0)
|
||
Offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if Offset > 0 and lineno > Offset:
|
||
lineno -= Offset
|
||
col: int = int(getattr(Node, 'col_offset', -1))
|
||
Loc: str = getattr(Gen, '_current_source_file', '') or ''
|
||
Loc += f":{lineno}"
|
||
if col >= 0:
|
||
Loc += f":{col}"
|
||
Source: str = ''
|
||
if lineno > 0 and Gen is not None and hasattr(Gen, '_get_source_line'):
|
||
try:
|
||
Source = (Gen._get_source_line(lineno) or '').strip()
|
||
except Exception:
|
||
Source = ''
|
||
return Loc + (f",源码: {Source}" if Source else '')
|
||
|
||
def _RegisterEnumMembers(self, Node: ast.ClassDef) -> None:
|
||
ClassName: str = Node.name
|
||
# 枚举存储宽度 = 最宽成员类型(先推导再登记;成员注册顺序无关)。
|
||
# 登记到枚举条目与每个成员条目上,供常量发射点与类型解析点同点读取
|
||
# (两侧 ABI:常量宽度必须与枚举类型宽度一致)。
|
||
EnumWidth: int = self._EnumClassIntWidth(Node)
|
||
EnumTypeInfo: CTypeInfo = CTypeInfo()
|
||
EnumTypeInfo.Name = ClassName
|
||
EnumTypeInfo.BaseType = TypeSystem.CEnum(ClassName)
|
||
EnumTypeInfo.IsEnum = True
|
||
EnumTypeInfo.set('enum_width', EnumWidth)
|
||
self.Trans.SymbolTable.insert(ClassName, EnumTypeInfo)
|
||
enum_export = self.Trans.Exportable.add_enum(
|
||
name=ClassName,
|
||
lineno=Node.lineno,
|
||
is_public=True
|
||
)
|
||
next_enum_value: int = 0
|
||
# 已登记成员名(用于"可见名数 vs 登记数"兜底判据,见 SymbolUtils.EnumBodyMemberNames)
|
||
RegisteredNames: list[str] = []
|
||
for item in Node.body:
|
||
if isinstance(item, ast.Assign):
|
||
for target in item.targets:
|
||
if isinstance(target, ast.Name):
|
||
VarName: str = target.id
|
||
value: int | str | None = None
|
||
if item.value:
|
||
if isinstance(item.value, ast.Constant):
|
||
value = item.value.value
|
||
next_enum_value = value + 1
|
||
elif isinstance(item.value, ast.UnaryOp) and isinstance(item.value.op, ast.USub):
|
||
if isinstance(item.value.operand, ast.Constant):
|
||
value = -item.value.operand.value
|
||
next_enum_value = value + 1
|
||
elif isinstance(item.value, ast.Name):
|
||
value = item.value.id
|
||
ref_info: CTypeInfo | None = self.Trans.SymbolTable.lookup(value)
|
||
if ref_info:
|
||
if ref_info.value is not None and isinstance(ref_info.value, int):
|
||
next_enum_value = ref_info.value + 1
|
||
else:
|
||
value = next_enum_value
|
||
next_enum_value += 1
|
||
MemberNode: CTypeInfo = CTypeInfo()
|
||
MemberNode.Name = VarName
|
||
MemberNode.BaseType = TypeSystem.CEnum(ClassName)
|
||
MemberNode.value = value
|
||
MemberNode.EnumName = ClassName
|
||
MemberNode.Lineno = item.lineno
|
||
MemberNode.IsEnumMember = True
|
||
MemberNode.set('enum_width', EnumWidth)
|
||
self.Trans.SymbolTable.insert(VarName, MemberNode)
|
||
RegisteredNames.append(VarName)
|
||
enum_export.members.append(ExportEnumMember(
|
||
name=VarName,
|
||
value=value,
|
||
lineno=item.lineno
|
||
))
|
||
elif isinstance(item, ast.AnnAssign):
|
||
if isinstance(item.target, ast.Name):
|
||
VarName = item.target.id
|
||
# [枚举规格 fail-fast] 成员不允许指针类型(CPtr 家族 /
|
||
# rawptr[...] / str / bytes / 联合里夹带指针)——此前成员注解
|
||
# 被整体忽略,指针成员被静默当 i32 放行。
|
||
if self._EnumMemberAnnotationIsPtr(item.annotation):
|
||
# 注入行偏移还原:AST 行号含 _inject_auto_imports 注入的 N 行
|
||
_lineno: int = int(getattr(item, 'lineno', 0) or 0)
|
||
_line_offset: int = int(getattr(self.Trans, '_line_offset', 0) or 0)
|
||
if _line_offset > 0 and _lineno > _line_offset:
|
||
_lineno -= _line_offset
|
||
raise TypeError(
|
||
f"[fast-fail] 枚举 '{ClassName}' 成员 '{VarName}' 不能是指针类型"
|
||
f"(枚举值只支持整数成员类型),line {_lineno}"
|
||
)
|
||
value = None
|
||
if item.value:
|
||
if isinstance(item.value, ast.Constant):
|
||
value = item.value.value
|
||
next_enum_value = value + 1
|
||
elif isinstance(item.value, ast.UnaryOp) and isinstance(item.value.op, ast.USub):
|
||
if isinstance(item.value.operand, ast.Constant):
|
||
value = -item.value.operand.value
|
||
next_enum_value = value + 1
|
||
elif isinstance(item.value, ast.Name):
|
||
value = item.value.id
|
||
ref_info: CTypeInfo | None = self.Trans.SymbolTable.lookup(value)
|
||
if ref_info:
|
||
if ref_info.value is not None and isinstance(ref_info.value, int):
|
||
next_enum_value = ref_info.value + 1
|
||
else:
|
||
value = next_enum_value
|
||
next_enum_value += 1
|
||
MemberNode: CTypeInfo = CTypeInfo()
|
||
MemberNode.Name = VarName
|
||
MemberNode.BaseType = TypeSystem.CEnum(ClassName)
|
||
MemberNode.value = value
|
||
MemberNode.EnumName = ClassName
|
||
MemberNode.Lineno = item.lineno
|
||
MemberNode.IsEnumMember = True
|
||
MemberNode.set('enum_width', EnumWidth)
|
||
self.Trans.SymbolTable.insert(VarName, MemberNode)
|
||
RegisteredNames.append(VarName)
|
||
enum_export.members.append(ExportEnumMember(
|
||
name=VarName,
|
||
value=value,
|
||
lineno=item.lineno
|
||
))
|
||
# [兜底判据 fail-fast] "源码里可见的成员名字数" vs "实际登记成员数"。
|
||
# 任何注册器不认的成员写法(逗号组带值 `A, B = 1`、逗号组带注解
|
||
# `A, B: T`、单名尾随逗号 `A,`,以及未来出现的新形态)都会让可见名数 >
|
||
# 登记数——此前是**静默丢成员**(ASTKind 71→3、OpKind 32→2;与
|
||
# Debugger/enum-semantics.md §15、rawptr-migration-and-fastfail.md §27
|
||
# 同族,这是第三次复发),此处一律 fail-fast,不再静默跳过。
|
||
# 判据口径与 VPC ClassGenEnum._translate_enum_def 完全一致(同一规则源)。
|
||
Visible: list[tuple[str, object]] = EnumBodyMemberNames(Node.body)
|
||
if len(Visible) != len(RegisteredNames):
|
||
Rest: list[str] = list(RegisteredNames)
|
||
BadNode: object = Node
|
||
for Nm, Nd in Visible:
|
||
if Nm in Rest:
|
||
Rest.remove(Nm)
|
||
elif BadNode is Node:
|
||
BadNode = Nd
|
||
raise TypeError(EnumMemberCountMismatchError(
|
||
ClassName, Visible, RegisteredNames, self._EnumSiteLoc(BadNode),
|
||
int(getattr(self.Trans, '_line_offset', 0) or 0)))
|
||
|
||
def _EmitNewFunctionLlvm(self, ClassName: str, Gen: LlvmGeneratorMixin, IsCVTable: bool = False, IsCpythonObject: bool = False) -> None:
|
||
NewFuncName: str = f'{ClassName}.__before_init__'
|
||
existing_func: ir.Function | None = Gen.functions.get(NewFuncName)
|
||
if existing_func and len(existing_func.blocks) > 0:
|
||
return
|
||
MangledName: str = Gen._mangle_name(NewFuncName)
|
||
StructType: ir.Type = Gen.structs[ClassName]
|
||
if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0):
|
||
self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen)
|
||
StructType = Gen.structs.get(ClassName, StructType)
|
||
StructPtrType: ir.PointerType = ir.PointerType(StructType)
|
||
FuncType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [StructPtrType])
|
||
if existing_func:
|
||
func: ir.Function = existing_func
|
||
else:
|
||
func = Gen._get_or_declare_function(MangledName, FuncType)
|
||
# 泛型特化类(ClassName 含 '[',如 GSList[NameEntry])的 __before_init__
|
||
# 在多模块各自特化生成同名定义(external linkage)→ ld.lld duplicate
|
||
# symbol warning。__before_init__ 由相同模板+类型参数合成,定义相同,
|
||
# 设 linkonce_odr 让链接器合并重复定义。
|
||
if '[' in ClassName:
|
||
func.linkage = 'linkonce_odr'
|
||
Gen.functions[NewFuncName] = func
|
||
EntryBlock: ir.Block = func.append_basic_block(name="entry")
|
||
saved_builder: ir.IRBuilder = Gen.builder
|
||
saved_func: ir.Function = Gen.func
|
||
Gen.builder = Gen._NewIrBuilder(EntryBlock)
|
||
Gen.func = func
|
||
StructPtr: ir.Argument = func.args[0]
|
||
base: int = 1 if IsCVTable else 0
|
||
if IsCVTable and ClassName in Gen.Vtables:
|
||
VtablePtr: ir.Value = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="vtable_slot")
|
||
VtableAddr: ir.Value = Gen.builder.bitcast(Gen.Vtables[ClassName], ir.PointerType(ir.IntType(8)), name="vtable_addr")
|
||
Gen.builder.store(VtableAddr, VtablePtr)
|
||
members: list[tuple] = Gen.class_members.get(ClassName, [])
|
||
defaults: dict = Gen.class_member_defaults.get(ClassName, {})
|
||
struct_elems: tuple = StructType.elements if hasattr(StructType, 'elements') and StructType.elements is not None else ()
|
||
for i, (member_name, member_type) in enumerate(members):
|
||
elem_idx: int = base + i
|
||
if len(struct_elems) > 0 and elem_idx >= len(struct_elems):
|
||
break
|
||
ElemPtr: ir.Value = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"{ClassName}_{member_name}")
|
||
if member_name in defaults:
|
||
try:
|
||
val: ir.Constant = defaults[member_name]
|
||
if not isinstance(val, ir.Constant):
|
||
val = ir.Constant(ElemPtr.type.pointee, val)
|
||
Gen.builder.store(val, ElemPtr)
|
||
except Exception as _e:
|
||
if _config_mode == "strict":
|
||
self.Trans.LogWarning(f"异常被忽略: {_e}")
|
||
else:
|
||
try:
|
||
ZeroVal: ir.Constant = ir.Constant(ElemPtr.type.pointee, None)
|
||
Gen.builder.store(ZeroVal, ElemPtr)
|
||
except Exception:
|
||
pass
|
||
Gen.builder.ret_void()
|
||
Gen.builder = saved_builder
|
||
Gen.func = saved_func
|
||
|
||
def _PreRegisterClassMembers(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
|
||
"""兜底:把一个类的**自有字段**从 ClassDef 体收集进 `Gen.class_members[类名]`。
|
||
|
||
调用点:[FuncGen._get_member_offset] 的"struct body 已存在、而
|
||
`class_members[类名]` 为空"分支——该类的成员表在本次翻译里从未被收集
|
||
(时序/跨模块窗口),而按名定位字段槽位必须有表。
|
||
此前本方法**全仓无定义**(调用点却存在)⇒ 一旦进入即
|
||
`AttributeError: 'ClassHandle' object has no attribute '_PreRegisterClassMembers'`
|
||
(现场:翻译 ViperC/App/lib/core/Gen/Call/CallGenLeafKit.vp 终止编译)。
|
||
|
||
判据与实现刻意与既有两处成员收集段同源:
|
||
- `_EmitClassLlvm` 的自有字段段(`CollectAnnAssignMember` → 追加 `(名, 类型)`);
|
||
- `HandlesImports._EmitExternalClassDeclLlvm` 的同名段。
|
||
但**只做收集**:
|
||
- 不展平继承前缀——调用方随后经 `_member_base` →
|
||
`EnsureClassMembersFlattened` 按父类补齐(表空且有父类时会被前置);
|
||
- 不调用 `_generate_structs()`:body 已存在,重入 `set_body` 会把残缺布局
|
||
永久固化(llvmlite 的 `set_body` 只能设一次,见
|
||
HandlesImports._EmitExternalClassDeclLlvm 的 `_collecting_members_set` 说明);
|
||
- 只追加**尚无同名**的条目(幂等:重复命中不会把表撑长,也就不会让
|
||
`base + 表内下标` 整体后移)。
|
||
"""
|
||
if Node is None or Gen is None:
|
||
return
|
||
ClassName: str = getattr(Node, 'name', None)
|
||
if not ClassName:
|
||
return
|
||
if ClassName not in Gen.class_members:
|
||
Gen.class_members[ClassName] = []
|
||
# 【防重 · 实时判据(2026-09-30)】原实现循环前快照一次名字集合,循环内只更新
|
||
# 自己追加的项;而 CollectAnnAssignMember 每轮都可能重入并**清空重填**本类表
|
||
# (泛型特化 → _generate_structs → _TryLoadClassMembersFromPyi(force=True) →
|
||
# HandlesImports.py:3415)⇒ 快照失效后会重复追加同一字段。改为每轮实时读表,
|
||
# 判据语义("名字已在表里就不追加")与改前逐字相同。
|
||
Gen._collecting_members_set.add(ClassName)
|
||
try:
|
||
for item in Node.body:
|
||
# 编译期元数据字段(__provides__/__requires__/__require_must__)不是布局槽位
|
||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||
if item.target.id in ('__provides__', '__requires__', '__require_must__'):
|
||
continue
|
||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||
if not parsed:
|
||
continue
|
||
VarName, MemberType, TypeInfo = parsed
|
||
if VarName in {n for n, _ in Gen.class_members[ClassName]}:
|
||
continue
|
||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||
Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation)
|
||
_Signeds: dict = getattr(Gen, 'class_member_signeds', {}).get(ClassName)
|
||
if isinstance(_Signeds, dict):
|
||
_Signeds[VarName] = None
|
||
_BitFields: dict = getattr(Gen, 'class_member_bitfields', {}).get(ClassName)
|
||
if isinstance(_BitFields, dict):
|
||
_BitFields[VarName] = 0
|
||
finally:
|
||
Gen._collecting_members_set.discard(ClassName)
|
||
|
||
def _BuildScalarConstant(self, node: ast.AST, llvm_type: ir.Type, Gen: LlvmGeneratorMixin | None = None) -> ir.Constant | None:
|
||
"""构建标量常量,委托给统一的 _BuildScalarConstantUnified 方法。"""
|
||
if Gen is None:
|
||
Gen = self.Trans.LlvmGen
|
||
return self.Trans._BuildScalarConstantUnified(node, llvm_type, Gen)
|
||
|
||
def _BuildStructConstant(self, call_node: ast.Call, StructName: str, Gen: LlvmGeneratorMixin) -> ir.Constant | None:
|
||
struct_type: ir.Type = Gen.structs[StructName]
|
||
members: list[tuple] = Gen.class_members.get(StructName, [])
|
||
defaults: dict = Gen.class_member_defaults.get(StructName, {})
|
||
member_values: list[ir.Constant] = []
|
||
for member_name, member_type in members:
|
||
if member_name in defaults:
|
||
val: ir.Constant = defaults[member_name]
|
||
if not isinstance(val, ir.Constant):
|
||
try:
|
||
val = ir.Constant(member_type, val)
|
||
except Exception: # 回退:常量转换失败时使用零值
|
||
val = ir.Constant(member_type, 0)
|
||
member_values.append(val)
|
||
else:
|
||
try:
|
||
if isinstance(member_type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.PointerType, ir.ArrayType)):
|
||
member_values.append(ir.Constant(member_type, None))
|
||
else:
|
||
member_values.append(ir.Constant(member_type, ir.Undefined))
|
||
except Exception: # 回退:常量创建失败时使用零值
|
||
member_values.append(ir.Constant(member_type, 0))
|
||
if call_node.args:
|
||
for i, arg in enumerate(call_node.args):
|
||
if i < len(members):
|
||
_, member_type = members[i]
|
||
const: ir.Constant | None = self._BuildScalarConstant(arg, member_type, Gen)
|
||
if const is not None:
|
||
member_values[i] = const
|
||
try:
|
||
return ir.Constant(struct_type, member_values)
|
||
except Exception: # 回退:结构体常量创建失败
|
||
return None
|