fix(generic): 恢复泛型特化发射主路径

补回 _specialize_generic_class 的 deepcopy/改名/字段与方法 T 替换/_EmitClassLlvm 发射逻辑,list[...].__len__ 与 get 正常生成;源码不再支持 CPtr[...],统一写 T*;编译错误只由主进程输出一次。
This commit is contained in:
TermiNexus committed 2026-10-18 19:50:32 +08:00
1 parent 09553401e7
commit 369afb5011
13 files changed
+413 -95

No files matched your search

+104
View File
@@ -235,6 +235,110 @@ class ClassHandle(BaseHandle):
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)
# 特化 AST:复制模板 → 清空 type_params → 改名为特化名,再整体替换
# T(注解 + 方法体)。之后走与普通类完全相同的 _EmitClassLlvm 发射
# (declare_only=False 时逐方法 _EmitFunctionLlvm 生成方法体)。
SpecNode: ast.ClassDef = copy.deepcopy(Node)
SpecNode.type_params = []
SpecNode.name = spec_name
for item in SpecNode.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
if item.annotation:
item.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(item.annotation, type_map, cptr_params)
elif isinstance(item, ast.FunctionDef):
for arg in item.args.args:
if arg.annotation:
arg.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(arg.annotation, type_map, cptr_params)
# class 类型参数加指针语义。T 替换后的真实形态可能是
# Attribute 链('<sha1>.GNode' → Name('<sha1>').GNode,
# 见 _make_replacement_node/_make_name_node),不是 ast.Name,
# 故按裸名判据(_BareClassAnnotationName)判定;已经是指针
# 下标(CPtr[T] / rawptr[T])的注解返回 None,不重复加层。
raw_name: str | None = self._BareClassAnnotationName(arg.annotation)
if raw_name is not None and raw_name in class_type_names:
arg.annotation = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=arg.annotation,
ctx=ast.Load(),
)
if item.returns:
item.returns = self.Trans.FunctionHandler._replace_type_in_annotation(item.returns, type_map, cptr_params)
# 返回类型也加指针语义(同一裸名判据,形态同上)
raw_name: str | None = self._BareClassAnnotationName(item.returns)
if raw_name is not None and raw_name in class_type_names:
item.returns = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=item.returns,
ctx=ast.Load(),
)
self.Trans.FunctionHandler._apply_type_map_to_body(item.body, type_map, cptr_params)
saved_builder: ir.IRBuilder = Gen.builder
saved_func: ir.Function = Gen.func
saved_variables: dict = dict(Gen.variables) if Gen.variables else {}
saved_direct_values: dict = dict(Gen._direct_values) if Gen._direct_values else {}
saved_var_type_info: dict = dict(Gen.var_type_info) if Gen.var_type_info else {}
saved_var_signedness: dict = dict(Gen.var_signedness) if Gen.var_signedness else {}
saved_global_vars: set = set(Gen.global_vars) if Gen.global_vars else set()
saved_var_scopes: list = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else []
saved_block: ir.Block | None = None
if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated:
saved_block = Gen.builder.block
# 切换 module_sha1 为泛型模板定义模块的 SHA1,
# 使结构体类型名和方法定义名都用定义模块的 SHA1 前缀,
# 与调用端 _struct_sha1_map 查到的 SHA1 一致。
template_sha1: str | None = template.get('sha1')
if not template_sha1:
# 模板注册表缺 sha1 时回退到"模板类定义模块"(_struct_sha1_map 即
# 类名 → 定义模块表,Phase2 从各 .vpi 扫描构建):与声明端
# DeclarationGenerator._get_type_str 的泛型前缀、调用点
# Gen._struct_sha1_map[spec_name] 同一条规则源;否则 declare/define
# 两侧前缀分裂(使用方模块 vs 模板模块)→ 跨模块 undefined symbol。
template_sha1 = Gen._struct_sha1_map.get(ClassName)
saved_gen_sha1: str | None = getattr(Gen, 'module_sha1', None)
saved_trans_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
if template_sha1:
Gen.module_sha1 = template_sha1
self.Trans._module_sha1 = template_sha1
try:
self._EmitClassLlvm(SpecNode, Gen, declare_only=declare_only)
except BaseException:
# 失败时撤销预注册缓存:否则后续调用会把「特化到一半」当成已完成
# (declare_only=False),方法体永远不会再补发,错误被伪装成
# "没有 __len__ 方法 / Undefined method"。异常本身不吞,继续上抛。
Gen._generic_class_specializations.pop(spec_key, None)
raise
finally:
# 确保 Gen 状态恢复,即使 _EmitClassLlvm 抛出异常(异常本身不吞,
# 由调用方记录到 Gen._generic_spec_error 或直接上抛)。
Gen.builder = saved_builder
if saved_block is not None and Gen.builder is not None:
Gen.builder.position_at_end(saved_block)
Gen.func = saved_func
Gen.variables = saved_variables
Gen._direct_values = saved_direct_values
Gen.var_type_info = saved_var_type_info
Gen.var_signedness = saved_var_signedness
Gen.global_vars = saved_global_vars
self.Trans.VarScopes = saved_var_scopes
# 恢复原始 module_sha1
Gen.module_sha1 = saved_gen_sha1
self.Trans._module_sha1 = saved_trans_sha1
Gen._generic_class_specializations[spec_key] = (spec_name, declare_only)
# 缓存 type_args/type_names,供后续 declare_only=False 完整特化补发方法体使用
# (如 _HandleMethodCallLlvm 中发现方法未定义时触发)
if not hasattr(Gen, '_generic_class_spec_type_info'):
Gen._generic_class_spec_type_info = {}
Gen._generic_class_spec_type_info[spec_key] = (list(type_args), list(type_names) if type_names else None)
if not hasattr(self.Trans, '_generic_class_specializations'):
self.Trans._generic_class_specializations = {}
self.Trans._generic_class_specializations[spec_key] = spec_name
# 用模板定义模块的 SHA1 注册到 _struct_sha1_map,与方法定义端一致
if template_sha1:
Gen._struct_sha1_map[spec_name] = template_sha1
elif hasattr(self.Trans, '_module_sha1') and self.Trans._module_sha1:
Gen._struct_sha1_map[spec_name] = self.Trans._module_sha1
return spec_name
def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None:
"""解析基类名称的类型种类