fix(gen): 泛型特化类记录触发文件,作废重译正确重置 MethodsEmitted

ld.lld undefined symbol list[ast.ClassDef|t.CPtr].* 根因:Phase A _deps_pending
作废重译时 reset_module_methods_emitted 按当前文件 sha1 精确匹配,特化类
ModuleSha1=模板 sha1(方法名带模板前缀)匹配不到,MethodsEmitted 残留 1
→ 下遍 _specialize_generic_class 补译分支(==0 才补译)跳过 → text.ll 只有
call 无 define → 链接失败。

修复:StructEntry 新增 SpecTriggerSha1(特化类触发文件 sha1),
_specialize_generic_class 全部返回路径经 _record_spec_trigger 记录,
reset_module_methods_emitted 按 ModuleSha1 或 SpecTriggerSha1 匹配重置。
This commit is contained in:
TermiNexus committed 2026-08-20 04:04:40 +08:00
1 parent b68ae16639
commit cf6c917e83
3 files changed
+49 -4

No files matched your search

+30
View File
@@ -473,6 +473,29 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
merged[cur_len] = ' '
string.strcpy(merged + cur_len + 1, tdeps)
trans._imported_modules = merged
def _record_spec_trigger(self, pool: memhub.MemBuddy | t.CPtr,
spec_name: str, trigger_sha1: str) -> int:
"""记录泛型特化类的触发文件 sha1(StructEntry.SpecTriggerSha1)
特化类 ModuleSha1=模板 sha1(方法名带模板前缀),Phase A _deps_pending
作废重译时 reset_module_methods_emitted 按当前文件 sha1 匹配不到 →
特化方法体 MethodsEmitted 残留 1 → 下遍不补译 → 链接 undefined symbol。
记录触发文件 sha1 后按此精确重置(见 StructGenMixin.reset_module_methods_emitted)。
"""
if spec_name is None or trigger_sha1 is None:
return 0
entry_rt: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if entry_rt is None:
return 0
if string.strcmp(entry_rt.Name, spec_name) != 0:
return 0
ts_len_r: t.CSizeT = string.strlen(trigger_sha1)
ts_buf_r: str = CompilerFactory.get_perm_pool().alloc(ts_len_r + 1)
if ts_buf_r is None:
return 0
string.strcpy(ts_buf_r, trigger_sha1)
entry_rt.SpecTriggerSha1 = ts_buf_r
return 1
def _specialize_generic_class(self, trans: HT.Translator | t.CPtr,
class_name: str,
type_args: list[str] | t.CPtr) -> str:
@@ -491,6 +514,10 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
# 泛型循环套用防护:递归深度 +1,超过上限立即报错终止(防 F-bounded
# 等循环特化把编译变死循环)。所有返回路径都必须 -1(见各 return 前)。
self.GenericSpecDepth += 1
# 特化触发文件 sha1:进入函数时 trans.ModuleSha1 是触发方文件,
# 翻译特化类时会被切换为模板 sha1(见下方),作废重译时按此重置
# 特化类 MethodsEmitted(见 _record_spec_trigger / reset_module_methods_emitted)
spec_trigger_sha1: str = trans.ModuleSha1
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
err_spec: str = trans.Pool.alloc(256)
if err_spec is not None:
@@ -603,6 +630,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
string.strcat(spec_key, ">")
cached: str = self._find_cached_spec(spec_key)
if cached is not None:
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
self.GenericSpecDepth -= 1
return cached
@@ -610,6 +638,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if existing is not None:
self._cache_spec(pool, spec_key, spec_name)
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
self.GenericSpecDepth -= 1
return spec_name
@@ -681,5 +710,6 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
VLogger.error("SPEC 字段名缺失(字段表损坏)", "SPEC")
HandlesType.fatal_error(None, "SPEC 字段名缺失(字段表损坏)", "TypeError")
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
self.GenericSpecDepth -= 1
return spec_name
+15 -4
View File
@@ -523,10 +523,21 @@ class StructGenMixin:
reset_count: int = 0
for i in range(self.StructCount):
entry: HandlesStruct.StructEntry | t.CPtr = self._get_struct_entry(i)
if entry is not None and entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
entry.MethodsEmitted = 0
reset_count += 1
if entry is not None:
# 普通类按 ModuleSha1 匹配
if entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
entry.MethodsEmitted = 0
reset_count += 1
continue
# 泛型特化类按触发文件 sha1 匹配:特化类 ModuleSha1 是模板 sha1
# (方法名带模板前缀),无法匹配当前作废文件。不重置则特化方法体
# 残留 MethodsEmitted=1,下遍不补译 → text.ll 只有 call 无 define
# → ld.lld undefined symbol(list[ast.ClassDef|t.CPtr].* 根因)
if entry.SpecTriggerSha1 is not None:
if string.strcmp(entry.SpecTriggerSha1, sha1) == 0:
entry.MethodsEmitted = 0
reset_count += 1
return reset_count
def find_struct_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> HandlesStruct.StructEntry | t.CPtr:
+4
View File
@@ -74,6 +74,10 @@ class StructEntry:
VTableMethods: str # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
ModuleSha1: str # 定义该类的模块 SHA1(None=无 SHA1)
MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译)
SpecTriggerSha1: str # 泛型特化类的触发文件 SHA1(None=非特化类)。特化类 ModuleSha1=模板
# sha1(方法名带模板前缀),作废重译时 reset_module_methods_emitted
# 按触发文件 sha1 精确重置 MethodsEmitted,防特化方法体残留 1 不补译
# → 链接 undefined symbol(list[ast.ClassDef|t.CPtr].* 根因)
# ============================================================