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 ast
import inspect
import os
import re
import hashlib
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName


class ImportHandle(BaseHandle):
    _struct_Load_cache = {}
    _pyi_cache = {}
    _pyi_cache_dir = None
    _project_root_cache = None
    # 类级 stub 索引：class_name -> list of (full_name, struct_body, file_sha1, from_output)
    # 一次扫描所有 .stub.ll 文件构建索引，避免 _TryLoadStructFromStub 每次调用都全量扫描
    # （原 609 次调用 × ~100 stub 文件 × ~50 行 = 5.5M 正则匹配 → 一次扫描 ~5000 匹配）
    _stub_index: dict[str, list[tuple[str, str, str, bool]]] = {}
    _stub_index_signature: tuple[int, int] | None = None  # (output_stub_count, temp_stub_count)

    def __init__(self, translator: "Translator") -> None:
        super().__init__(translator)
        # 实例级去重集合：每个 translator 独立跟踪已加载的 .pyi 和已发射的模块声明。
        # 若作为类变量共享，main.py 编译时加载的 __nodes.py 会阻止 __parser.py 编译时
        # 重新加载，导致函数未注册到 __parser.py 的 Gen.functions（NamedExpr bug 根因）。
        self._loaded_pyi_paths: set[str] = set()
        self._emitted_module_decls: set[tuple] = set()

    def _reset_file_cache(self) -> None:
        self._struct_Load_cache.clear()
        self._loaded_pyi_paths.clear()
        self._emitted_module_decls.clear()
        # stub 索引在文件间保留（同一 worker 进程内），但标记需检查是否过期
        # 不清除 _stub_index，通过 _stub_index_signature 在下次使用时校验新鲜度

    def _find_project_root(self) -> str:
        if self._project_root_cache is not None:
            return self._project_root_cache
        # 优先使用 translator 上显式设置的 _temp_dir（由 Phase2Translator._translate_file 传入），
        # 这样可以正确处理 include 文件——其源文件目录不在项目根目录下，
        # 从源文件目录向上搜索 temp/output 会失败并回退到错误的路径。
        temp_dir_attr = getattr(self.Trans, '_temp_dir', None)
        if temp_dir_attr and os.path.isdir(temp_dir_attr):
            project_root = os.path.dirname(os.path.abspath(temp_dir_attr))
            if os.path.isdir(os.path.join(project_root, 'temp')) and os.path.isdir(os.path.join(project_root, 'output')):
                self._project_root_cache = project_root
                return project_root
        current_file = getattr(self.Trans, 'CurrentFile', '') or ''
        if current_file:
            current_dir = os.path.dirname(os.path.abspath(current_file))
            search_dir = current_dir
            for _ in range(10):
                if os.path.isdir(os.path.join(search_dir, 'temp')) and os.path.isdir(os.path.join(search_dir, 'output')):
                    self._project_root_cache = search_dir
                    return search_dir
                parent = os.path.dirname(search_dir)
                if parent == search_dir:
                    break
                search_dir = parent
        # 回退到当前工作目录（编译运行时的项目根目录）
        cwd = os.getcwd()
        if os.path.isdir(os.path.join(cwd, 'temp')) and os.path.isdir(os.path.join(cwd, 'output')):
            self._project_root_cache = cwd
            return cwd
        if current_file:
            self._project_root_cache = current_dir
            return current_dir
        self._project_root_cache = cwd
        return cwd

    def _EmitImportDeclarationsLlvm(self, Node: ast.Import, Gen: LlvmGeneratorMixin) -> None:
        if not getattr(self.Trans, '_ImportedModules', None):
            self.Trans._ImportedModules = set()
        for alias in Node.names:
            name = alias.name
            if name in ('c', 't'):
                if alias.asname:
                    self.Trans.SymbolTable.import_aliases[alias.asname] = name
                    AliasInfo = CTypeInfo()
                    AliasInfo.IsModuleAlias = True
                    AliasInfo.ResolvedModule = name
                    self.Trans.SymbolTable.insert(alias.asname, AliasInfo)
                continue
            self.Trans._ImportedModules.add(name)
            if alias.asname:
                self.Trans.SymbolTable.import_aliases[alias.asname] = name
                # 同时在符号表中注册模块别名，以便 CTypeInfo.FromNode 能解析
                AliasInfo = CTypeInfo()
                AliasInfo.IsModuleAlias = True
                AliasInfo.ResolvedModule = name
                self.Trans.SymbolTable.insert(alias.asname, AliasInfo)
            current_module = self._get_current_module_name()
            self._EmitModuleDeclarationsLlvm(name, Gen, register_module_name=current_module)

    def _RegisterFromImportAliases(self, Node: ast.ImportFrom, Gen: LlvmGeneratorMixin, module: str) -> None:
        """Register 'from module import y as z' aliases after module declarations are Loaded"""
        if not Node.names:
            return
        for alias in Node.names:
            name = alias.name
            asname = alias.asname
            # For 'from X import Y' (no asname), register CDefine constants
            # into _define_constants so they can be found by _HandleNameLlvm
            if not asname or asname == name:
                define_constants = vars(Gen).setdefault('_define_constants', {})
                # Check if this name is a CDefine constant in SymbolTable
                sym_info = self.Trans.SymbolTable.lookup(name)
                if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
                    if name not in define_constants:
                        define_constants[name] = sym_info.DefineValue
                # Also check with module prefix
                for prefix_key in [f"{module}.{name}", name]:
                    sym_info2 = self.Trans.SymbolTable.lookup(prefix_key)
                    if sym_info2 and sym_info2.IsDefine and sym_info2.DefineValue is not None:
                        if name not in define_constants:
                            define_constants[name] = sym_info2.DefineValue
                        break
                # 治本修复：如果符号表中没有，回退查询 _all_define_constants
                # _all_define_constants 由 Phase2Translator 从所有 .pyi 文件预提取，
                # 包含跨模块导入的 CDefine 常量（如 FOREGROUND_GREEN、STD_OUTPUT_HANDLE）
                if name not in define_constants:
                    all_dc: dict = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
                    if name in all_dc:
                        define_constants[name] = all_dc[name]
                continue
            if not hasattr(self.Trans, '_t_c_imported_names'):
                self.Trans._t_c_imported_names = {}
            self.Trans._t_c_imported_names[asname] = (module, name)
            if name in Gen.functions:
                Gen.functions[asname] = Gen.functions[name]
            if name in Gen.structs:
                Gen.structs[asname] = Gen.structs[name]
            info = self.Trans.SymbolTable.lookup(name)
            if info:
                self.Trans.SymbolTable.insert(asname, info)
            if name in Gen.variables:
                Gen.variables[asname] = Gen.variables[name]
            if name in Gen.global_vars:
                Gen.global_vars[asname] = Gen.global_vars[name]
            for func_name in list(Gen.functions.keys()):
                if func_name.startswith(f'{name}.'):
                    method_suffix = func_name[len(name):]
                    Gen.functions[f'{asname}{method_suffix}'] = Gen.functions[func_name]
            for key in list(self.Trans.SymbolTable.keys()):
                if key.startswith(f'{name}.'):
                    suffix = key[len(name):]
                    self.Trans.SymbolTable.insert(f'{asname}{suffix}', self.Trans.SymbolTable[key])
            for meta_dict in (Gen.class_members, Gen.class_member_defaults,
                              Gen.class_member_signeds, Gen.class_member_bitfields,
                              Gen.class_member_byteorders, Gen.class_member_bitoffsets,
                              Gen.class_methods):
                if name in meta_dict:
                    meta_dict[asname] = meta_dict[name]
            if name in Gen.class_vtable:
                Gen.class_vtable.add(asname)
            if name in Gen.class_packed:
                Gen.class_packed.add(asname)
            struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
            if name in struct_sha1_map:
                struct_sha1_map[asname] = struct_sha1_map[name]

    def _EmitImportFromDeclarationsLlvm(self, Node: ast.ImportFrom, Gen: LlvmGeneratorMixin) -> None:
        module = Node.module if Node.module else ''
        if module in ('c', 't'):
            if not getattr(self.Trans, '_ImportedModules', None):
                self.Trans._ImportedModules = set()
            self.Trans._ImportedModules.add(module)
            if not hasattr(self.Trans, '_t_c_imported_names'):
                self.Trans._t_c_imported_names = {}
            # 注册 t/c 类型别名到 _t_type_symbols（CType 子类）
            t_type_syms = self.Trans.SymbolTable._t_type_symbols
            for alias in Node.names:
                name = alias.name
                asname = alias.asname or name
                self.Trans._t_c_imported_names[asname] = (module, name)
                # 仅注册 CType 子类（CEnum/CUnion/CStruct/REnum 等）
                if module == 't':
                    cls = getattr(t, name, None)
                    if isinstance(cls, type) and issubclass(cls, t.CType):
                        t_type_syms[asname] = cls
            return
        if not getattr(self.Trans, '_ImportedModules', None):
            self.Trans._ImportedModules = set()
        current_module = self._get_current_module_name()
        if Node.level and Node.level > 0:
            current_file = getattr(self.Trans, 'CurrentFile', '') or ''
            current_dir = os.path.dirname(os.path.abspath(current_file))
            parent_dir = current_dir
            for _ in range(Node.level - 1):
                parent_dir = os.path.dirname(parent_dir)
            if module:
                SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
                sub_path_base = os.path.join(parent_dir, module)
                for ext in SearchExtensions:
                    candidate = sub_path_base + ext
                    if os.path.isfile(candidate):
                        self.Trans._ImportedModules.add(module)
                        self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module, register_module_name=current_module)
                        self._RegisterFromImportAliases(Node, Gen, module)
                        return
                ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
                # 尝试完整模块名和短模块名
                full_mod_name = f"{current_module}.{module}" if current_module else module
                target_sha1 = ModuleSha1Map.get(full_mod_name) or ModuleSha1Map.get(module)
                if target_sha1:
                    temp_dir = getattr(Gen, '_temp_dir', None)
                    if temp_dir:
                        sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
                        if os.path.isfile(sha1_pyi):
                            self.Trans._ImportedModules.add(module)
                            self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module, register_module_name=current_module)
                            self._RegisterFromImportAliases(Node, Gen, module)
                            return
            else:
                mod_dir = parent_dir

            SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
            pkg_name = ''
            if not module:
                # When 'from . import name' is used, Load the package's __init__
                # to make package-level names (functions, classes, constants) available
                pkg_name = self._LoadPackageInitForRelativeImport(mod_dir, Gen, current_module)

                # Also try to Load each alias as a submodule
                for alias in Node.names:
                    found_sub = False
                    for ext in SearchExtensions:
                        sub_path = os.path.join(mod_dir, alias.name + ext)
                        if os.path.isfile(sub_path):
                            self.Trans._ImportedModules.add(alias.name)
                            self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=current_module)
                            if alias.asname:
                                self.Trans.SymbolTable.import_aliases[alias.asname] = alias.name
                            found_sub = True
                            break
                    if not found_sub:
                        # SHA1 map fallback for submodule
                        ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
                        sub_ModulePath = f"{pkg_name}.{alias.name}" if pkg_name else alias.name
                        target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name)
                        if target_sha1:
                            temp_dir = getattr(Gen, '_temp_dir', None)
                            if temp_dir:
                                sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
                                if os.path.isfile(sha1_pyi):
                                    self.Trans._ImportedModules.add(sub_ModulePath)
                                    self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=current_module)
                                    if alias.asname:
                                        self.Trans.SymbolTable.import_aliases[alias.asname] = alias.name
            self._RegisterFromImportAliases(Node, Gen, module or pkg_name)
            return
        self.Trans._ImportedModules.add(module)
        self._EmitModuleDeclarationsLlvm(module, Gen, register_module_name=current_module)
        self._RegisterFromImportAliases(Node, Gen, module)

    def _RegisterCrossModuleDocstrings(self, pyi_path: str, Gen: LlvmGeneratorMixin, module_prefix: str | None) -> None:
        """从 {sha1}.doc.json 加载跨模块 docstring 注册到 Gen._doc_strings。

        - 长名 {module_prefix}.{symbol} 总是注册
        - 短名 {symbol} 只在不存在时注册（避免覆盖本模块的）
        - slice_level != 0（优化开启）时注册为 None
        - 跨模块 docstring 在 _get_doc_ptr 访问时创建本地常量副本
        """
        if not module_prefix:
            return
        basename: str = os.path.basename(pyi_path)
        # 若传入 .vp/.py 文件，则从 _source_module_sig_files 查找对应的 {sha1}.vpi
        if basename.endswith('.vp') or basename.endswith('.py'):
            source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
            if source_sig_files:
                sig_path = source_sig_files.get(module_prefix)
                if sig_path and os.path.isfile(sig_path):
                    pyi_path = sig_path
                    basename = os.path.basename(pyi_path)
                else:
                    return
            else:
                return
        if not (basename.endswith('.vpi') or basename.endswith('.pyi')):
            return
        sha1: str = basename[:-4]  # 去掉 .vpi 或 .pyi 后缀（均为 4 字符）
        shared_doc_meta = getattr(self.Trans, '_shared_doc_meta', None)
        if not shared_doc_meta:
            return
        docs: dict[str, str] | None = shared_doc_meta.get(sha1)
        if not docs:
            return
        trans = getattr(Gen, '_Trans', None)
        slice_level: int = getattr(trans, 'SliceLevel', 3)
        optimized: bool = slice_level != 0
        for symbol, doc in docs.items():
            long_key: str = f"{module_prefix}.{symbol}"
            if optimized:
                Gen._doc_strings[long_key] = None
                if symbol not in Gen._doc_strings:
                    Gen._doc_strings[symbol] = None
            else:
                Gen._doc_strings[long_key] = doc
                if symbol not in Gen._doc_strings:
                    Gen._doc_strings[symbol] = doc

    def _LoadModuleDeclarationsFromFile(self, pyi_path: str, Gen: LlvmGeneratorMixin, module_name: str | None = None, register_module_name: str | None = None, actual_module_name: str | None = None, reexport_package: str | None = None) -> None:
        if not pyi_path or not os.path.isfile(pyi_path):
            return
        # 去重：同一 .pyi 文件只加载一次（菱形依赖下避免重复 read+parse）
        abs_pyi = os.path.abspath(pyi_path)
        if abs_pyi in self._loaded_pyi_paths:
            return
        self._loaded_pyi_paths.add(abs_pyi)
        # 注册跨模块 __doc__ docstring 到 Gen._doc_strings
        self._RegisterCrossModuleDocstrings(pyi_path, Gen, register_module_name or module_name)
        try:
            with open(pyi_path, 'r', encoding='utf-8') as f:
                ModuleCode = f.read()
            ModuleTree = ast.parse(ModuleCode)
        except Exception as _e:
            if _config_mode == "strict":
                self.Trans.LogWarning(f"异常被忽略: {_e}")
            return

        # 计算源模块名（从 .pyi 文件路径推导）。
        # 治本修复：module_name 参数可能来自 alias.name（如 `from stmts import Module`
        # 中的 'Module' 是类名而非模块名），直接传给 _EmitExternalClassDeclLlvm 会导致
        # ModuleSha1Map 查找失败 → _self_struct_sha1=None → 使用错误的同名 struct。
        # 使用文件名推导的模块名（如 'stmts'）作为 source_module_name 才是正确的。
        # 对于 sha1 命名的 .pyi 文件（如 e64295c03b564a53.pyi），文件名是 sha1 而非
        # 模块名，需回退到 actual_module_name 或 module_name。
        file_module_name = os.path.splitext(os.path.basename(pyi_path))[0]
        if len(file_module_name) == 16 and all(_c in '0123456789abcdef' for _c in file_module_name):
            file_module_name = actual_module_name or module_name or file_module_name

        for node in ModuleTree.body:
            try:
                if isinstance(node, ast.FunctionDef):
                    if node.name in ('va_start', 'va_arg', 'va_end'):
                        continue
                    effective_register = register_module_name or module_name
                    reexport_names = []
                    if module_name and module_name != file_module_name and module_name != effective_register:
                        reexport_names.append(module_name)
                    # When Loading a submodule for 'from .xxx import yyy' inside a package's __init__.py,
                    # re-export functions under the package name so 'pkg.func()' resolves correctly
                    if reexport_package and reexport_package != file_module_name and reexport_package not in reexport_names:
                        reexport_names.append(reexport_package)
                    self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=file_module_name, register_module_name=effective_register, reexport_module_names=reexport_names if reexport_names else None)
                elif isinstance(node, ast.AnnAssign):
                    self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=pyi_path)
                elif isinstance(node, ast.Assign):
                    self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=pyi_path)
                elif isinstance(node, ast.ClassDef):
                    if hasattr(node, 'type_params') and node.type_params:
                        if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'):
                            self.Trans.ClassHandler._generic_class_templates = {}
                        type_params = [tp.name for tp in node.type_params]
                        # 保留 prescan 阶段已注册的 sha1；若无则从 _ModuleSha1Map 查找，
                        # 避免覆盖带 sha1 的注册导致特化时 SHA1 前缀丢失
                        existing = self.Trans.ClassHandler._generic_class_templates.get(node.name)
                        template_sha1 = existing.get('sha1') if existing else None
                        if template_sha1 is None:
                            msm = getattr(self.Trans, '_ModuleSha1Map', None)
                            if msm:
                                for lookup_name in (file_module_name, module_name, actual_module_name):
                                    if lookup_name and lookup_name in msm:
                                        template_sha1 = msm[lookup_name]
                                        break
                        self.Trans.ClassHandler._generic_class_templates[node.name] = {
                            'node': node,
                            'type_params': type_params,
                            'sha1': template_sha1,
                        }
                    # 治本修复：使用 file_module_name（源模块名）而非 module_name（可能是别名/类名）。
                    # 这样 _EmitExternalClassDeclLlvm 内的 ModuleSha1Map 查找才能命中，
                    # _EmitExternalFuncDeclLlvm 才能拿到正确的 source_module_name → 正确的 struct sha1。
                    # 注意：actual_module_name 保持原值（可能为 None），不回退到 module_name（可能是别名）
                    self._EmitExternalClassDeclLlvm(node, Gen, module_name=file_module_name, actual_module_name=actual_module_name)
                elif isinstance(node, ast.ImportFrom):
                    if node.level > 0:
                        current_dir = os.path.dirname(os.path.abspath(pyi_path))
                        parent_dir = current_dir
                        for _ in range(node.level - 1):
                            parent_dir = os.path.dirname(parent_dir)
                        if node.module:
                            SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
                            sub_path_base = os.path.join(parent_dir, node.module)
                            found_sub = False
                            # 治本修复：用包目录名（如 'json'）而非 register_module_name（当前编译模块名，如 '_dict'）。
                            # 当 _dict.py 导入 json 包，递归处理 json/__init__.py 中的 `from .__parser import parse` 时，
                            # register_module_name='_dict' 会导致 actual_module='_dict.__parser'，
                            # 使 _mangle_func_name 查找失败回退到 self.module_sha1，生成错误的 mangled name。
                            # 包名推导优先级：
                            #   1. module_name（如果它在 ModuleSha1Map 中，说明是已注册的包名，如 'json'）
                            #      — 处理 sha1 命名的 .pyi 文件（parent_dir 是 temp 目录时）
                            #   2. os.path.basename(parent_dir)（原始路径推导，如 'json'）
                            if module_name and module_name in Gen.ModuleSha1Map:
                                pkg_basename = module_name
                            else:
                                pkg_basename = os.path.basename(parent_dir)
                            for ext in SearchExtensions:
                                candidate = sub_path_base + ext
                                if os.path.isfile(candidate):
                                    actual_module = f"{pkg_basename}.{node.module}" if pkg_basename else node.module
                                    self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen)
                                    if not getattr(self.Trans, '_ImportedModules', None):
                                        self.Trans._ImportedModules = set()
                                    self.Trans._ImportedModules.add(actual_module)
                                    for alias in node.names:
                                        if alias.name == '*':
                                            self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
                                        else:
                                            self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=reexport_package or module_name)
                                    found_sub = True
                                    break
                            # SHA1 map 回退
                            if not found_sub:
                                actual_module = f"{pkg_basename}.{node.module}" if pkg_basename else node.module
                                ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
                                target_sha1 = ModuleSha1Map.get(actual_module) or ModuleSha1Map.get(node.module)
                                if target_sha1:
                                    temp_dir = getattr(Gen, '_temp_dir', None)
                                    if temp_dir:
                                        sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
                                        if os.path.isfile(sha1_pyi):
                                            if not getattr(self.Trans, '_ImportedModules', None):
                                                self.Trans._ImportedModules = set()
                                            self.Trans._ImportedModules.add(actual_module)
                                            for alias in node.names:
                                                if alias.name == '*':
                                                    self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
                                                else:
                                                    self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=reexport_package or module_name)
                        else:
                            mod_dir = parent_dir
                            SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
                            # Load __init__.py to make package-level names available
                            self._LoadPackageInitForRelativeImport(mod_dir, Gen, register_module_name)
                            # 治本修复：用包目录名（如 'json'）而非 register_module_name（当前编译模块名，如 '_dict'）。
                            # 同 if node.module 分支的修复逻辑。
                            if module_name and module_name in Gen.ModuleSha1Map:
                                pkg_basename = module_name
                            else:
                                pkg_basename = os.path.basename(mod_dir)
                            for alias in node.names:
                                found_alias = False
                                for ext in SearchExtensions:
                                    sub_path = os.path.join(mod_dir, alias.name + ext)
                                    if os.path.isfile(sub_path):
                                        sub_ModulePath = f"{pkg_basename}.{alias.name}" if pkg_basename else alias.name
                                        if not getattr(self.Trans, '_ImportedModules', None):
                                            self.Trans._ImportedModules = set()
                                        self.Trans._ImportedModules.add(sub_ModulePath)
                                        if alias.name == '*':
                                            self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
                                        else:
                                            self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
                                        found_alias = True
                                        break
                                # SHA1 map 回退
                                if not found_alias:
                                    sub_ModulePath = f"{pkg_basename}.{alias.name}" if pkg_basename else alias.name
                                    ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
                                    target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name)
                                    if target_sha1:
                                        temp_dir = getattr(Gen, '_temp_dir', None)
                                        if temp_dir:
                                            sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
                                            if os.path.isfile(sha1_pyi):
                                                if not getattr(self.Trans, '_ImportedModules', None):
                                                    self.Trans._ImportedModules = set()
                                                self.Trans._ImportedModules.add(sub_ModulePath)
                                                if alias.name == '*':
                                                    self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
                                                else:
                                                    self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=reexport_package or module_name)
            except Exception as _e:
                _vlog().warning(
                    f"HandlesImports[_LoadModuleDeclarationsFromFile]: 忽略节点 "
                    f"{type(node).__name__} {getattr(node, 'name', '?')} 异常: {_e}",
                    exc_info=_e
                )
                continue

    def _get_current_module_name(self) -> str | None:
        current_file = getattr(self.Trans, 'CurrentFile', '') or ''
        if current_file:
            return os.path.splitext(os.path.basename(current_file))[0]
        return None

    def _RegisterSubModuleSha1(self, candidate_path: str, actual_module: str, short_module: str, Gen: LlvmGeneratorMixin) -> None:
        """Register a submodule's SHA1 in ModuleSha1Map so cross-module class references work"""
        try:
            with open(candidate_path, 'r', encoding='utf-8') as f:
                sub_content = f.read()
            sub_sha1 = hashlib.sha1(sub_content.encode('utf-8')).hexdigest()[:16]
            if hasattr(Gen, 'ModuleSha1Map'):
                Gen.ModuleSha1Map[actual_module] = sub_sha1
                if short_module and short_module not in Gen.ModuleSha1Map:
                    Gen.ModuleSha1Map[short_module] = sub_sha1
        except Exception as _e:
            if _config_mode == "strict":
                raise
            _vlog().warning(f"处理导入失败: {_e}", "Exception")

    def _LoadPackageInitForRelativeImport(self, mod_dir: str, Gen: LlvmGeneratorMixin, register_module_name: str | None) -> str:
        """Load __init__.py from the package directory for 'from . import name' resolution.
        This makes package-level names (functions, classes, constants) available.
        Returns the package name."""
        pkg_name = os.path.basename(mod_dir)
        init_Loaded = False

        # 跳过当前正在编译的文件，避免重复加载导致 class_members 重复
        current_sha1 = getattr(Gen, 'module_sha1', None)
        ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
        pkg_sha1 = ModuleSha1Map.get(pkg_name)
        if pkg_sha1 and pkg_sha1 == current_sha1:
            return pkg_name

        # Try SHA1 map first (correct mangled names from stub)
        if pkg_sha1:
            temp_dir = getattr(Gen, '_temp_dir', None)
            if temp_dir:
                sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.vpi")
                if os.path.isfile(sha1_pyi):
                    self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=pkg_name, register_module_name=register_module_name)
                    init_Loaded = True

        # Fallback: try Loading __init__.py directly from the package directory
        if not init_Loaded:
            for ext in ['.vpi', '.vp', '.pyi', '.py']:
                init_path = os.path.join(mod_dir, '__init__' + ext)
                if os.path.isfile(init_path):
                    self._LoadModuleDeclarationsFromFile(init_path, Gen, module_name=pkg_name, register_module_name=register_module_name)
                    init_Loaded = True
                    break

        return pkg_name

    def _EmitModuleDeclarationsLlvm(self, module_name: str, Gen: LlvmGeneratorMixin, register_module_name: str | None = None) -> None:
        # 去重：同一模块声明只发射一次（避免多个 import 同一模块时重复加载）
        decl_key = (module_name, register_module_name)
        if decl_key in self._emitted_module_decls:
            return
        self._emitted_module_decls.add(decl_key)
        if module_name in ('pyzlib',):
            source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
        ModulePathBase = module_name.replace('.', os.sep)
        PackageInitPathBase = module_name.replace('.', os.sep) + os.sep + '__init__'
        ProjectRoot = os.path.dirname(os.path.abspath(getattr(self.Trans, 'CurrentFile', '') or '')) or os.getcwd()

        HandlesFile = os.path.abspath(inspect.getfile(self.__class__))
        TransPyCRoot = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(HandlesFile))))

        FullModulePath = None
        SearchDirs = [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths)

        for LibPath in SearchDirs:
            SearchPath = os.path.join(ProjectRoot, LibPath) if not os.path.isabs(LibPath) else LibPath
            # 优先尝试 .vpi，回退 .pyi
            for stub_ext in ('.vpi', '.pyi'):
                CandidatePath = os.path.join(SearchPath, ModulePathBase + stub_ext)
                if os.path.isfile(CandidatePath):
                    FullModulePath = CandidatePath
                    break
                CandidatePath = os.path.join(SearchPath, PackageInitPathBase + stub_ext)
                if os.path.isfile(CandidatePath):
                    FullModulePath = CandidatePath
                    break
            if FullModulePath:
                break
            ModuleParts = ModulePathBase.split(os.sep)
            if len(ModuleParts) > 1:
                LibPathBasename = os.path.basename(LibPath.rstrip('/\\'))
                if LibPathBasename == ModuleParts[0]:
                    RemainingPath = os.sep.join(ModuleParts[1:])
                    for stub_ext in ('.vpi', '.pyi'):
                        CandidatePath = os.path.join(SearchPath, RemainingPath + stub_ext)
                        if os.path.isfile(CandidatePath):
                            FullModulePath = CandidatePath
                            break
                    if FullModulePath:
                        break
        if not FullModulePath:
            ModulePathPyBase = module_name.replace('.', os.sep)
            PackageInitPathPyBase = module_name.replace('.', os.sep) + os.sep + '__init__'
            SearchDirsForPy = [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths)
            for LibPath in SearchDirsForPy:
                SearchPath = os.path.join(ProjectRoot, LibPath) if not os.path.isabs(LibPath) else LibPath
                # 优先尝试 .vp，回退 .py
                for src_ext in ('.vp', '.py'):
                    CandidatePath = os.path.join(SearchPath, ModulePathPyBase + src_ext)
                    if os.path.isfile(CandidatePath):
                        FullModulePath = CandidatePath
                        break
                    CandidatePath = os.path.join(SearchPath, PackageInitPathPyBase + src_ext)
                    if os.path.isfile(CandidatePath):
                        FullModulePath = CandidatePath
                        break
                if FullModulePath:
                    break
        if not FullModulePath or not os.path.isfile(FullModulePath):
            source_sig_files = getattr(self.Trans, '_source_module_sig_files', None)
            if source_sig_files:
                sig_path = source_sig_files.get(module_name)
                if sig_path and os.path.isfile(sig_path):
                    FullModulePath = sig_path
                else:
                    for key, val in source_sig_files.items():
                        if key.endswith('.' + module_name) or key == module_name:
                            FullModulePath = val
                            break
            if not FullModulePath or not os.path.isfile(FullModulePath):
                if module_name in ('pyzlib', 'zdeflate', 'zinflate', 'zchecksum', 'zdef', 'zhuff'):
                    pass
                if not FullModulePath:
                    CurrentFile = getattr(self.Trans, 'CurrentFile', None) or ''
                    if CurrentFile:
                        CurrentFileDir = os.path.dirname(os.path.abspath(CurrentFile))
                        SearchFromDirs = [CurrentFileDir, os.getcwd()]
                    else:
                        SearchFromDirs = [os.getcwd()]
                    SearchDirsForSubmodule = SearchFromDirs + [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths)
                    for SearchPath in SearchDirsForSubmodule:
                        if os.path.isdir(SearchPath):
                            for root, dirs, files in os.walk(SearchPath):
                                if '__pycache__' in root:
                                    continue
                                for src_ext in ('.vp', '.py', '.vpi', '.pyi'):
                                    if module_name + src_ext in files:
                                        FullModulePath = os.path.join(root, module_name + src_ext)
                                        break
                                if FullModulePath:
                                    break
                            if FullModulePath:
                                break
        # 注册跨模块 __doc__ docstring（module_name 是被导入模块名）
        if FullModulePath:
            self._RegisterCrossModuleDocstrings(FullModulePath, Gen, module_name)
        self._LoadDeclarationsFromStubLlvm(module_name, Gen)
        if module_name == 'pyzlib':
            pass
        try:
            with open(FullModulePath, 'r', encoding='utf-8') as f:
                ModuleCode = f.read()
            ModuleTree = ast.parse(ModuleCode)
            if module_name == 'pyzlib':
                func_names = [n.name for n in ModuleTree.body if isinstance(n, ast.FunctionDef)]
            has_functions_or_classes = False
            for node in ModuleTree.body:
                if module_name == 'pyzlib':
                    node_type = type(node).__name__
                    name = getattr(node, 'name', getattr(node, 'attr', '?'))
                try:
                    if isinstance(node, ast.FunctionDef):
                        if node.name in ('va_start', 'va_arg', 'va_end'):
                            continue
                        effective_register = register_module_name or module_name
                        self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=module_name, register_module_name=effective_register)
                        has_functions_or_classes = True
                    elif isinstance(node, ast.AnnAssign):
                        self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=FullModulePath)
                        has_functions_or_classes = True
                    elif isinstance(node, ast.Assign):
                        self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, ModulePath=FullModulePath)
                        has_functions_or_classes = True
                    elif isinstance(node, ast.ClassDef):
                        if hasattr(node, 'type_params') and node.type_params:
                            if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'):
                                self.Trans.ClassHandler._generic_class_templates = {}
                            type_params = [tp.name for tp in node.type_params]
                            # 保留 prescan 阶段已注册的 sha1；若无则从 _ModuleSha1Map 查找，
                            # 避免覆盖带 sha1 的注册导致特化时 SHA1 前缀丢失
                            existing = self.Trans.ClassHandler._generic_class_templates.get(node.name)
                            template_sha1 = existing.get('sha1') if existing else None
                            if template_sha1 is None:
                                msm = getattr(self.Trans, '_ModuleSha1Map', None)
                                if msm and module_name in msm:
                                    template_sha1 = msm[module_name]
                            self.Trans.ClassHandler._generic_class_templates[node.name] = {
                                'node': node,
                                'type_params': type_params,
                                'sha1': template_sha1,
                            }
                        self._EmitExternalClassDeclLlvm(node, Gen, module_name=module_name)
                        has_functions_or_classes = True
                    elif isinstance(node, ast.ImportFrom):
                        if node.level > 0:
                            current_dir = os.path.dirname(os.path.abspath(FullModulePath))
                            parent_dir = current_dir
                            for _ in range(node.level - 1):
                                parent_dir = os.path.dirname(parent_dir)
                            if node.module:
                                SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
                                sub_path_base = os.path.join(parent_dir, node.module)
                                found_sub = False
                                for ext in SearchExtensions:
                                    candidate = sub_path_base + ext
                                    if os.path.isfile(candidate):
                                        actual_module = f"{module_name}.{node.module}" if module_name else node.module
                                        self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen)
                                        if not getattr(self.Trans, '_ImportedModules', None):
                                            self.Trans._ImportedModules = set()
                                        self.Trans._ImportedModules.add(actual_module)
                                        for alias in node.names:
                                            if alias.name == '*':
                                                self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
                                            else:
                                                self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=module_name)
                                            has_functions_or_classes = True
                                        found_sub = True
                                        break
                                # SHA1 map 回退：当文件查找失败时，从 SHA1 映射中查找子模块 stub
                                if not found_sub:
                                    actual_module = f"{module_name}.{node.module}" if module_name else node.module
                                    ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
                                    # 尝试完整模块名和短模块名
                                    target_sha1 = ModuleSha1Map.get(actual_module) or ModuleSha1Map.get(node.module)
                                    if target_sha1:
                                        temp_dir = getattr(Gen, '_temp_dir', None)
                                        if temp_dir:
                                            sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
                                            if os.path.isfile(sha1_pyi):
                                                if not getattr(self.Trans, '_ImportedModules', None):
                                                    self.Trans._ImportedModules = set()
                                                self.Trans._ImportedModules.add(actual_module)
                                                for alias in node.names:
                                                    if alias.name == '*':
                                                        self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
                                                    else:
                                                        self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=module_name)
                                                    has_functions_or_classes = True
                            else:
                                mod_dir = parent_dir
                                SearchExtensions = ['.vpi', '.vp', '.pyi', '.py']
                                # Load __init__.py to make package-level names available
                                self._LoadPackageInitForRelativeImport(mod_dir, Gen, register_module_name or module_name)
                                for alias in node.names:
                                    found_alias = False
                                    for ext in SearchExtensions:
                                        sub_path = os.path.join(mod_dir, alias.name + ext)
                                        if os.path.isfile(sub_path):
                                            sub_ModulePath = f"{module_name}.{alias.name}" if module_name else alias.name
                                            if not getattr(self.Trans, '_ImportedModules', None):
                                                self.Trans._ImportedModules = set()
                                            self.Trans._ImportedModules.add(sub_ModulePath)
                                            if alias.name == '*':
                                                self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
                                            else:
                                                self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=module_name)
                                            has_functions_or_classes = True
                                            found_alias = True
                                            break
                                    # SHA1 map 回退
                                    if not found_alias:
                                        sub_ModulePath = f"{module_name}.{alias.name}" if module_name else alias.name
                                        ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
                                        target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name)
                                        if target_sha1:
                                            temp_dir = getattr(Gen, '_temp_dir', None)
                                            if temp_dir:
                                                sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.vpi")
                                                if os.path.isfile(sha1_pyi):
                                                    if not getattr(self.Trans, '_ImportedModules', None):
                                                        self.Trans._ImportedModules = set()
                                                    self.Trans._ImportedModules.add(sub_ModulePath)
                                                    if alias.name == '*':
                                                        self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name)
                                                    else:
                                                        self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=module_name)
                                                    has_functions_or_classes = True
                except Exception as e:
                    if module_name == 'pyzlib':
                        node_type = type(node).__name__
                        name = getattr(node, 'name', getattr(node, 'attr', '?'))
                    _vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
                    continue
            if not has_functions_or_classes and module_name:
                self._LoadDeclarationsFromStubLlvm(module_name, Gen)
            elif 'includes' in FullModulePath and module_name:
                self._LoadDeclarationsFromStubLlvm(module_name, Gen)
        except Exception as e:
            if module_name:
                self._LoadDeclarationsFromStubLlvm(module_name, Gen)

    def _EmitExternalGlobalDeclLlvm(self, Node: ast.AnnAssign | ast.Assign, Gen: LlvmGeneratorMixin, module_name: str | None = None, ModulePath: str | None = None) -> None:
        """Emit external global variable declaration from imported module"""
        if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name):
            VarName = Node.target.id
            # 不再跳过 _ 开头的全局变量，跨模块引用需要声明它们
            var_type = ir.IntType(32)
            IsPtr = False
            is_string_val = False
            TypeInfo = None
            if VarName in Gen.module.globals:
                existing = Gen.module.globals[VarName]
                if isinstance(existing, ir.GlobalVariable):
                    return
            if Node.annotation:
                parse_result = ParseListAnnotation(Node.annotation)
                if parse_result and not parse_result.is_pointer:
                    # list[type, count] 数组声明
                    elem_type_node = parse_result.elem_type_node
                    count_node = parse_result.count_node
                    ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable)
                    if ElemTypeInfo:
                        elem_type = Gen._ctype_to_llvm(ElemTypeInfo)
                        if isinstance(elem_type, ir.VoidType):
                            elem_type = ir.IntType(8)
                        if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int):
                            var_type = ir.ArrayType(elem_type, count_node.value)
                        elif isinstance(count_node, ast.Constant) and count_node.value is None:
                            var_type = ir.ArrayType(elem_type, 0)
                        else:
                            var_type = Gen._ctype_to_llvm(ElemTypeInfo)
                    IsPtr = False
                else:
                    TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable)
                    if TypeInfo:
                        var_type = Gen._ctype_to_llvm(TypeInfo)
                        IsPtr = TypeInfo.IsPtr
                if isinstance(var_type, ir.IdentifiedStructType) and (var_type.elements is None or len(var_type.elements) == 0):
                    var_type = ir.IntType(32)
            if Node.value and ModulePath and IsPtr and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str):
                str_val = Node.value.value + '\x00'
                str_bytes = str_val.encode('utf-8')
                arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
                str_gv_name = VarName + '_str'
                if str_gv_name not in Gen.module.globals:
                    str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name)
                    str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
                    str_gv.linkage = 'internal'
                ptr_type = ir.PointerType(ir.IntType(8))
                if VarName not in Gen.module.globals:
                    ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName)
                    str_gv = Gen.module.globals[str_gv_name]
                    ptr_gv.initializer = ir.Constant.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)])
                    ptr_gv.linkage = 'internal'
                Gen.variables[VarName] = None
                return
            
            # 检查是否是 CDefine 常量或 CTypedef 类型别名
            IsCDefine = False
            IsCTypedef = False
            if Node.annotation:
                if isinstance(Node.annotation, ast.Attribute):
                    if getattr(Node.annotation.value, 'id', None) == 't' and Node.annotation.attr == 'CDefine':
                        IsCDefine = True
                    elif getattr(Node.annotation.value, 'id', None) == 't' and Node.annotation.attr == 'CTypedef':
                        IsCTypedef = True
                elif isinstance(Node.annotation, ast.Name):
                    if Node.annotation.id == 'CDefine':
                        IsCDefine = True
                    elif Node.annotation.id == 'CTypedef':
                        IsCTypedef = True

            if IsCTypedef:
                # 检查符号是否已存在且已正确解析（OriginalType 已设置），避免覆盖
                existing_sym = self.Trans.SymbolTable.lookup(VarName) if hasattr(self.Trans.SymbolTable, 'lookup') else None
                if existing_sym and isinstance(existing_sym, CTypeInfo) and existing_sym.IsTypedef and existing_sym.OriginalType:
                    return
                if Node.value:
                    ValueTypeInfo = None
                    if isinstance(Node.value, ast.BinOp) and isinstance(Node.value.op, ast.BitOr):
                        ValueTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.value)
                    else:
                        ValueTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.value)
                    if isinstance(ValueTypeInfo, CTypeInfo) and (ValueTypeInfo.BaseType or ValueTypeInfo.PtrCount > 0):
                        # GetCTypeInfo 对 t.CInt 等 Attribute 返回的 BaseType 可能是 CType 基类实例
                        # （而非具体子类如 CInt），导致 _resolve_typedef_int_width 无法解析位宽。
                        # 此时从 Node.value 提取类型名，设置 OriginalType 为字符串，
                        # 让 _resolve_typedef_int_width 通过 CTypeRegistry.GetClassByName 解析。
                        if ValueTypeInfo.BaseType and type(ValueTypeInfo.BaseType) is t.CType:
                            if isinstance(Node.value, ast.Attribute) and getattr(Node.value.value, 'id', None) == 't':
                                type_name: str = Node.value.attr
                                resolved_cls = CTypeRegistry.GetClassByName(type_name)
                                if resolved_cls is not None:
                                    ValueTypeInfo.OriginalType = type_name
                        ValueTypeInfo.IsTypedef = True
                        ValueTypeInfo.Name = VarName
                        # 设置 OriginalType，确保 _resolve_name 能解析（MergeTypes 不为 BinOp 结果设置 OriginalType）
                        if not ValueTypeInfo.OriginalType:
                            OriginalCopy: CTypeInfo = ValueTypeInfo.Copy()
                            OriginalCopy.IsTypedef = False
                            OriginalCopy.Name = ''
                            ValueTypeInfo.OriginalType = OriginalCopy
                        self.Trans.SymbolTable.insert(VarName, ValueTypeInfo)
                        if module_name:
                            FullName = f"{module_name}.{VarName}"
                            self.Trans.SymbolTable.insert(FullName, ValueTypeInfo)
                        return
                TTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation)
                if TTypeInfo:
                    TTypeInfo.IsTypedef = True
                    TTypeInfo.Name = VarName
                    self.Trans.SymbolTable.insert(VarName, TTypeInfo)
                    if module_name:
                        FullName = f"{module_name}.{VarName}"
                        self.Trans.SymbolTable.insert(FullName, TTypeInfo)
                return

            if IsCDefine:
                # CDefine 宏不生成 LLVM 全局变量，只注册到 SymbolTable
                # 引用时会直接替换为立即数
                DefineValue = None
                if Node.value:
                    DefineValue = self._ExtractConstValue(Node.value)
                # 注册不带前缀的键名（例如 Z_NO_COMPRESSION）
                # 但要先检查：如果符号已经存在且是 typedef，不覆盖它
                existing = self.Trans.SymbolTable.lookup(VarName)
                if not (existing and existing.IsTypedef and existing.OriginalType):
                    self._RegisterCDefineSymbol(VarName, DefineValue, Node.lineno, ModulePath or 'unknown')
                # 如果提供了模块名，也注册带模块前缀的键名
                if module_name:
                    FullName = f"{module_name}.{VarName}"
                    existing_full = self.Trans.SymbolTable.lookup(FullName)
                    if not (existing_full and existing_full.IsTypedef and existing_full.OriginalType):
                        self._RegisterCDefineSymbol(FullName, DefineValue, Node.lineno, ModulePath or 'unknown')
                return  # 不再继续生成 LLVM 全局变量

            # t.State 标记的全局变量：只声明不定义（external linkage），避免 DSO/non-DSO 重定义
            if TypeInfo and TypeInfo.IsState:
                if VarName not in Gen.module.globals:
                    gv = ir.GlobalVariable(Gen.module, var_type, name=VarName)
                    gv.linkage = 'external'
                Gen._export_funcs.add(VarName)
                return

            gv = ir.GlobalVariable(Gen.module, var_type, name=VarName)
            # 外部全局变量声明：只声明不定义（external linkage），避免多重定义
            gv.linkage = 'external'
        elif isinstance(node, ast.Assign) and Node.targets and isinstance(Node.targets[0], ast.Name):
            VarName = Node.targets[0].id
            if VarName.startswith('_'):
                return
            if VarName in Gen.module.globals:
                return
            gv = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName)
            gv.linkage = 'external'

    def _ExtractValue(self, value_node: ast.AST, target_type: ir.Type, var_name: str | None = None) -> ir.Constant | None:
        """Extract constant value from AST node for global variable initializer"""
        # 处理负号
        if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub):
            if isinstance(value_node.operand, ast.Constant) and isinstance(value_node.operand.value, int):
                neg_val = -value_node.operand.value
                if isinstance(target_type, ir.IntType):
                    return ir.Constant(target_type, neg_val)
                return ir.Constant(ir.IntType(32), neg_val)
        # 处理正号
        elif isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.UAdd):
            return self._ExtractValue(value_node.operand, target_type)
        
        if isinstance(value_node, ast.Constant):
            if isinstance(value_node.value, bool):
                if isinstance(target_type, ir.IntType):
                    return ir.Constant(target_type, 1 if value_node.value else 0)
                return ir.Constant(ir.IntType(32), 1 if value_node.value else 0)
            elif isinstance(value_node.value, int):
                if isinstance(target_type, ir.IntType):
                    return ir.Constant(target_type, value_node.value)
                return ir.Constant(ir.IntType(32), value_node.value)
            elif isinstance(value_node.value, str):
                str_val = value_node.value + '\x00'
                str_bytes = str_val.encode('utf-8')
                arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes))
                Gen = self.Trans.LlvmGen
                gv_name = var_name + '_str' if var_name else f"str_global_{id(value_node)}"
                if gv_name in Gen.module.globals:
                    gv = Gen.module.globals[gv_name]
                else:
                    gv = ir.GlobalVariable(Gen.module, arr_type, name=gv_name)
                    gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
                    gv.linkage = 'internal'
                ptr_type = ir.PointerType(ir.IntType(8))
                return ir.Constant(ptr_type, gv.reference)
            elif isinstance(value_node.value, bool):
                return ir.Constant(ir.IntType(32), 1 if value_node.value else 0)
            elif value_node.value is None:
                if isinstance(target_type, ir.BaseStructType):
                    return ir.Constant(target_type, None)
                if isinstance(target_type, ir.PointerType):
                    return ir.Constant(target_type, None)
                return ir.Constant(target_type, 0)
        elif isinstance(value_node, ast.Name):
            if value_node.id == 'None':
                if isinstance(target_type, ir.BaseStructType):
                    return ir.Constant(target_type, None)
                if isinstance(target_type, ir.PointerType):
                    return ir.Constant(target_type, None)
                return ir.Constant(target_type, 0)
        return None

    def _ExtractConstValue(self, value_node: ast.AST) -> object:
        """Extract constant value from AST node for SymbolTable registration
        支持常量、一元运算符、二元运算符和常量引用
        """
        if isinstance(value_node, ast.Constant):
            return value_node.value
        elif isinstance(value_node, ast.BinOp):
            left = self._ExtractConstValue(value_node.left)
            right = self._ExtractConstValue(value_node.right)
            if left is None or right is None:
                return None
            if isinstance(value_node.op, ast.Add):
                return left + right
            elif isinstance(value_node.op, ast.Sub):
                return left - right
            elif isinstance(value_node.op, ast.Mult):
                return left * right
            elif isinstance(value_node.op, ast.Div):
                return left // right if isinstance(left, int) and isinstance(right, int) else left / right
            elif isinstance(value_node.op, ast.FloorDiv):
                return left // right
            elif isinstance(value_node.op, ast.Mod):
                return left % right
            elif isinstance(value_node.op, ast.Pow):
                return left ** right
            elif isinstance(value_node.op, ast.LShift):
                return left << right
            elif isinstance(value_node.op, ast.RShift):
                return left >> right
            elif isinstance(value_node.op, ast.BitOr):
                return left | right
            elif isinstance(value_node.op, ast.BitXor):
                return left ^ right
            elif isinstance(value_node.op, ast.BitAnd):
                return left & right
        elif isinstance(value_node, ast.UnaryOp):
            operand = self._ExtractConstValue(value_node.operand)
            if operand is None:
                return None
            if isinstance(value_node.op, ast.USub):
                return -operand
            elif isinstance(value_node.op, ast.UAdd):
                return +operand
            elif isinstance(value_node.op, ast.Invert):
                return ~operand
        elif isinstance(value_node, ast.Name):
            if value_node.id in getattr(self.Trans, 'SymbolTable', {}):
                info = self.Trans.SymbolTable[value_node.id]
                if info.IsDefine and info.DefineValue is not None:
                    return info.DefineValue
        elif isinstance(value_node, ast.Call):
            if isinstance(value_node.func, ast.Attribute):
                if getattr(value_node.func.value, 'id', None) == 't':
                    if value_node.args:
                        return self._ExtractConstValue(value_node.args[0])
            elif isinstance(value_node.func, ast.Name):
                if value_node.args:
                    return self._ExtractConstValue(value_node.args[0])
        return None

    def _ExtractTypedefOriginalType(self, value_node: ast.AST) -> str | None:
        if isinstance(value_node, ast.Attribute):
            if getattr(value_node.value, 'id', None) == 't':
                llvm_str = CTypeRegistry.NameToLLVM(value_node.attr)
                if llvm_str:
                    return llvm_str
        elif isinstance(value_node, ast.Name):
            llvm_str = CTypeRegistry.NameToLLVM(value_node.id)
            if llvm_str:
                return llvm_str
        elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr):
            left = self._ExtractTypedefOriginalType(value_node.left)
            right = self._ExtractTypedefOriginalType(value_node.right)
            parts = []
            if left:
                parts.append(left)
            if right:
                parts.append(right)
            if parts:
                return '|'.join(parts)
        elif isinstance(value_node, ast.Call):
            if isinstance(value_node.func, ast.Attribute):
                if getattr(value_node.func.value, 'id', None) == 't':
                    llvm_str = CTypeRegistry.NameToLLVM(value_node.func.attr)
                    if llvm_str:
                        return llvm_str
            elif isinstance(value_node.func, ast.Name):
                llvm_str = CTypeRegistry.NameToLLVM(value_node.func.id)
                if llvm_str:
                    return llvm_str
        return None

    def _RegisterCDefineSymbol(self, FullName: str, DefineValue: object, lineno: int, FilePath: str) -> None:
        """Register CDefine constant to SymbolTable"""
        # 防御：新值为 None 但已存在非 None 值时保留旧值。
        # 翻译期间声明发射调用 _ExtractConstValue（不支持 ast.Attribute 形式如 t.CSizeT().Size），
        # 会返回 None 并覆盖共享符号表中已由 ConstEvaluator 正确求值的值（如 8）。
        # 共享符号表在 _build_shared_symbol_data 阶段已正确求值，此处不应覆盖。
        if DefineValue is None:
            existing: Any = self.Trans.SymbolTable.lookup(FullName)
            if existing and existing.IsDefine and existing.DefineValue is not None:
                return
        info = CTypeInfo()
        info.IsDefine = True
        info.DefineValue = DefineValue
        info.Lineno = lineno
        info.file = FilePath
        # 直接添加到 SymbolTable 字典
        self.Trans.SymbolTable.insert(FullName, info)

    def _check_annotation_for_state(self, annotation: ast.AST) -> bool:
        return (AnnotationContainsName(annotation, 'CExport') or
                AnnotationContainsName(annotation, 'CExtern') or
                AnnotationContainsName(annotation, 'State'))

    def _check_decorators_for_state(self, Node: ast.FunctionDef) -> bool:
        """检查装饰器列表中是否包含 @t.CExport / @t.CExtern / @t.State（t.CExport 既能作返回值注解也能作装饰器）"""
        if not Node.decorator_list:
            return False
        for decorator in Node.decorator_list:
            if (AnnotationContainsName(decorator, 'CExport') or
                    AnnotationContainsName(decorator, 'CExtern') or
                    AnnotationContainsName(decorator, 'State')):
                return True
        return False

    def _EmitExternalFuncDeclLlvm(self, Node: ast.FunctionDef, Gen: LlvmGeneratorMixin, is_class_method: bool = False, source_module_name: str | None = None, register_module_name: str | None = None, reexport_module_names: list[str] | None = None) -> None:
        FuncName = Node.name
        if (Node.returns and self._check_annotation_for_state(Node.returns)) or self._check_decorators_for_state(Node):
            Gen._export_funcs.add(FuncName)  # t.State 标记的外部 C 函数必须保持原始名称，以便链接器解析
            if source_module_name and source_module_name not in ('c', 't'):
                _src_sha1 = Gen.ModuleSha1Map.get(source_module_name)
                if not _src_sha1:
                    _init_name = f"{source_module_name}.__init__"
                    if _init_name in Gen.ModuleSha1Map:
                        _src_sha1 = Gen.ModuleSha1Map[_init_name]
                if _src_sha1:
                    Gen._export_extern_funcs[FuncName] = _src_sha1
        if FuncName in Gen.functions:
            return
        CReturnTypes = []
        if Node.decorator_list:
            for decorator in Node.decorator_list:
                if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute):
                    if decorator.func.attr == 'CReturn':
                        for arg in decorator.args:
                            CReturnTypes.append(arg)
        IsPtr = False
        ReturnTypeInfo = None
        if Node.returns:
            try:
                ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
                if ReturnTypeInfo and ReturnTypeInfo.IsStr:
                    ReturnTypeInfo = CTypeInfo()
                    ReturnTypeInfo.BaseType = t.CChar()
                    ReturnTypeInfo.PtrCount = 1
                if ReturnTypeInfo is None:
                    ReturnTypeInfo = CTypeInfo()
                    ReturnTypeInfo.BaseType = t.CInt()
                IsPtr = ReturnTypeInfo.IsPtr
            except Exception as e:  # 回退：返回类型解析失败时使用默认 CInt
                _vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
                ReturnTypeInfo = CTypeInfo()
                ReturnTypeInfo.BaseType = t.CInt()
        else:
            ReturnTypeInfo = CTypeInfo()
            ReturnTypeInfo.BaseType = t.CInt()
        ReturnType = Gen._ctype_to_llvm(ReturnTypeInfo)
        if (isinstance(ReturnType, ir.VoidType) or (isinstance(ReturnType, ir.PointerType) and isinstance(ReturnType.pointee, ir.VoidType))) and Node.returns:
            RetAnnName = None
            if isinstance(Node.returns, ast.Name):
                RetAnnName = Node.returns.id
            elif isinstance(Node.returns, ast.Attribute):
                RetAnnName = Node.returns.attr
            elif isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
                left = Node.returns.left
                if isinstance(left, ast.Name):
                    RetAnnName = left.id
                elif isinstance(left, ast.Attribute):
                    RetAnnName = left.attr
            if RetAnnName and RetAnnName in Gen.structs:
                ReturnType = ir.PointerType(Gen.structs[RetAnnName])
            elif IsPtr or RetAnnName:
                ReturnType = ir.PointerType(ir.IntType(8))
        # __new__ 方法应返回类指针类型（堆分配替换），与 _GetFunctionSignatureLlvm/_EmitFunctionLlvm 保持一致
        # .pyi 生成器对无返回类型注解的 __new__ 默认使用 t.CInt，这里修正为 ClassName*
        if '.__new__' in FuncName:
            _np = FuncName.split('.')
            if len(_np[0]) == 16 and all(_c in '0123456789abcdef' for _c in _np[0]):
                _new_class_name = _np[1]
            else:
                _new_class_name = _np[0]
            # 治本修复：优先用 source sha1 查找正确的 struct，避免同名类冲突时返回错误类型
            _new_struct = None
            _new_src_sha1: str | None = None
            if source_module_name and hasattr(Gen, 'ModuleSha1Map'):
                _new_src_sha1 = Gen.ModuleSha1Map.get(source_module_name)
                if not _new_src_sha1:
                    _init_name = f"{source_module_name}.__init__"
                    if _init_name in Gen.ModuleSha1Map:
                        _new_src_sha1 = Gen.ModuleSha1Map[_init_name]
            if _new_src_sha1 and _new_class_name:
                _new_struct = Gen.structs.get(f"{_new_src_sha1}.{_new_class_name}")
            if _new_struct is None:
                _new_struct = Gen.structs.get(_new_class_name)
            if _new_struct is None:
                _full_name = FuncName.split('.__new__')[0]
                _new_struct = Gen.structs.get(_full_name)
            if _new_struct:
                if isinstance(_new_struct, ir.PointerType):
                    ReturnType = _new_struct
                else:
                    ReturnType = ir.PointerType(_new_struct)
        ParamTypes = []
        is_method = is_class_method or '.__' in FuncName
        class_name_for_method = FuncName.split('.')[0] if '.' in FuncName else None
        class_is_cpython = class_name_for_method and self.Trans.SymbolTable.is_struct(class_name_for_method)
        # 治本修复：通过 source_module_name 获取源模块 sha1，查找正确的 struct。
        # 当存在同名类冲突（如 stmts.py:Module 和 __module.py:Module）时，
        # Gen.structs[short_name] 可能指向错误模块的 struct（set_body 已锁定错误布局）。
        # 优先查找以 sha1 为前缀的完整 key，避免使用错误的 struct 作为 self 参数类型。
        _self_struct_sha1: str | None = None
        if source_module_name and hasattr(Gen, 'ModuleSha1Map'):
            _self_struct_sha1 = Gen.ModuleSha1Map.get(source_module_name)
            if not _self_struct_sha1:
                _init_name = f"{source_module_name}.__init__"
                if _init_name in Gen.ModuleSha1Map:
                    _self_struct_sha1 = Gen.ModuleSha1Map[_init_name]
        for i, Arg in enumerate(Node.args.args):
            if i == 0 and is_method:
                # self parameter of a method should always be a pointer to the struct
                _self_struct = None
                if _self_struct_sha1 and class_name_for_method:
                    _full_key = f"{_self_struct_sha1}.{class_name_for_method}"
                    _self_struct = Gen.structs.get(_full_key)
                if _self_struct is None:
                    _self_struct = Gen.structs.get(class_name_for_method or FuncName.split('.')[0], ir.IntType(8))
                ParamType = ir.PointerType(_self_struct)
            elif Arg.annotation:
                try:
                    ParamTypeInfo = self.ResolveAnnotationType(Arg.annotation)
                    if ParamTypeInfo is None:
                        ParamTypeInfo = CTypeInfo()
                        ParamTypeInfo.BaseType = t.CInt()
                    ParamIsPtr = ParamTypeInfo.IsPtr
                    if i == 0 and is_method and Arg.arg == 'self' and class_is_cpython:
                        ParamIsPtr = True
                        ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
                    if ParamTypeInfo.IsStr:
                        ParamTypeInfo = CTypeInfo()
                        ParamTypeInfo.BaseType = t.CChar()
                        ParamTypeInfo.PtrCount = 1
                        ParamIsPtr = True
                    # C 语言中数组参数退化为指针：list[type, N] → type*
                    if ParamTypeInfo.ArrayDims:
                        ParamTypeInfo.ArrayDims = []
                        ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
                    ParamType = Gen._ctype_to_llvm(ParamTypeInfo)
                except Exception as e:  # 回退：参数类型解析失败时使用默认 i32
                    _vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
                    ParamType = ir.IntType(32)
                if isinstance(ParamType, ir.VoidType) or (isinstance(ParamType, ir.PointerType) and isinstance(ParamType.pointee, ir.VoidType)):
                    AnnName = None
                    if isinstance(Arg.annotation, ast.Name):
                        AnnName = Arg.annotation.id
                    elif isinstance(Arg.annotation, ast.Attribute):
                        AnnName = Arg.annotation.attr
                    elif isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr):
                        AnnName = ExtractTypeNameFromBinOp(Arg.annotation)
                    if AnnName and AnnName in Gen.structs:
                        ParamType = ir.PointerType(Gen.structs[AnnName])
                    else:
                        ParamType = ir.PointerType(ir.IntType(8))
            else:
                ParamType = ir.IntType(32)
            ParamTypes.append(ParamType)
        if CReturnTypes:
            for _ in CReturnTypes:
                ParamTypes.append(ir.PointerType(ir.IntType(8)))
        IsVariadic = Node.args.vararg is not None
        FuncType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic)
        _is_export = False
        if isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsState:
            _is_export = True
        if isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.Storage and isinstance(ReturnTypeInfo.Storage, t.CExport) and not ReturnTypeInfo.IsState:
            Gen._export_funcs.add(FuncName)
            _is_export = True
        if isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.Storage and isinstance(ReturnTypeInfo.Storage, t.CExtern):
            Gen._export_funcs.add(FuncName)
            _is_export = True
        if not _is_export:
            if Node.returns and self._check_annotation_for_state(Node.returns):
                _is_export = True
            elif self._check_decorators_for_state(Node):
                _is_export = True
        MangledName = Gen._mangle_func_name(FuncName, module_name=source_module_name)
        func = Gen._get_or_declare_function(MangledName, FuncType)
        Gen.functions[MangledName] = func
        Gen.functions[FuncName] = func
        func_meta = FuncMeta.NONE
        if Node.decorator_list:
            for d in Node.decorator_list:
                if isinstance(d, ast.Name):
                    if d.id == 'staticmethod':
                        func_meta |= FuncMeta.STATIC_METHOD
                    elif d.id == 'property':
                        func_meta |= FuncMeta.PROPERTY_GETTER
                    elif d.id == 'classmethod':
                        func_meta |= FuncMeta.CLASS_METHOD
                elif isinstance(d, ast.Attribute):
                    if isinstance(d.value, ast.Name):
                        # 支持 @property.setter 和 @propname.setter 两种形式
                        if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'):
                            if d.attr == 'setter':
                                func_meta |= FuncMeta.PROPERTY_SETTER
                            elif d.attr == 'getter':
                                func_meta |= FuncMeta.PROPERTY_GETTER
                            elif d.attr == 'deleter':
                                func_meta |= FuncMeta.PROPERTY_DELETER
        if not self.Trans.SymbolTable.has(FuncName):
            FuncInfo = CTypeInfo()
            FuncInfo.Name = FuncName
            FuncInfo.IsFunction = True
            FuncInfo.MetaList = func_meta
            self.Trans.SymbolTable.insert(FuncName, FuncInfo)
        else:
            existing = self.Trans.SymbolTable[FuncName]
            if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE:
                existing.MetaList = func_meta
        # 同时注册带模块前缀的符号，以便 module.func_name 查找能命中
        if source_module_name and source_module_name not in ('c', 't'):
            FullSymKey = f"{source_module_name}.{FuncName}"
            if not self.Trans.SymbolTable.has(FullSymKey):
                FullFuncInfo = CTypeInfo()
                FullFuncInfo.Name = FullSymKey
                FullFuncInfo.IsFunction = True
                FullFuncInfo.MetaList = func_meta
                self.Trans.SymbolTable.insert(FullSymKey, FullFuncInfo)
        # property setter/deleter: 在原始 PropKey（不带后缀）下注册 MetaList
        if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta:
            BasePropKey = FuncName.replace('$set', '').replace('$del', '')
            base_existing = self.Trans.SymbolTable.lookup(BasePropKey)
            if base_existing:
                if func_meta != FuncMeta.NONE:
                    base_existing.MetaList = base_existing.MetaList | func_meta
            else:
                PropInfo = CTypeInfo()
                PropInfo.Name = BasePropKey
                PropInfo.IsFunction = True
                PropInfo.MetaList = func_meta
                self.Trans.SymbolTable.insert(BasePropKey, PropInfo)
        if register_module_name and register_module_name != source_module_name:
            ReexportName = Gen._mangle_func_name(FuncName, module_name=register_module_name)
            Gen.functions[ReexportName] = func
        if reexport_module_names:
            for reexport_mod in reexport_module_names:
                if reexport_mod and reexport_mod != source_module_name:
                    ReexportName2 = Gen._mangle_func_name(FuncName, module_name=reexport_mod)
                    if ReexportName2 not in Gen.functions:
                        Gen.functions[ReexportName2] = func

    def _EmitExternalClassDeclLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin, module_name: str | None = None, actual_module_name: str | None = None, source_sha1: str | None = None) -> None:
        ClassName = Node.name
        # PEP 695 泛型类（如 GSListNode[T]）不再完全跳过：跨模块继承展平需要从泛型基类
        # 获取字段（如 Next），否则子类（如 Value(GSListNode[Value])）的 class_members
        # 会缺少继承字段，导致 struct body 字段数不正确 → GEP 索引错位 → 崩溃。
        # 但泛型类的方法声明必须跳过：方法参数类型 T 会被解析为 opaque struct，
        # LLVM 不允许 opaque struct 作为值参数（invalid type for function argument）。
        IsGenericClass: bool = hasattr(Node, 'type_params') and bool(Node.type_params)
        IsCenum = False
        IsRenum = False
        IsCpythonObject = False
        IsCVTable = False
        IsNoVTable = False
        if Node.bases:
            for base in Node.bases:
                if getattr(base, 'attr', None):
                    if base.attr == 'REnum':
                        IsRenum = True
                        break
                    elif base.attr == 'CEnum' or base.attr == 'Enum':
                        IsCenum = True
                        break
                elif getattr(base, 'id', None):
                    if base.id == 'REnum':
                        IsRenum = True
                        break
                    elif base.id == 'CEnum' or base.id == 'Enum':
                        IsCenum = True
                        break
        if not IsCenum and not IsRenum and getattr(Node, 'decorator_list', None):
            for decorator in Node.decorator_list:
                if isinstance(decorator, ast.Attribute):
                    if getattr(decorator.value, 'id', None) == 't':
                        if decorator.attr == 'Object':
                            IsCpythonObject = True
                        elif decorator.attr == 'CVTable':
                            IsCVTable = True
                        elif decorator.attr == 'NoVTable':
                            IsNoVTable = True
                        elif decorator.attr == 'REnum':
                            IsRenum = True
                        elif decorator.attr == 'CEnum' or decorator.attr == 'Enum':
                            IsCenum = True
                elif isinstance(decorator, ast.Call):
                    if isinstance(decorator.func, ast.Attribute):
                        if getattr(decorator.func.value, 'id', None) == 't':
                            if decorator.func.attr == 'Object':
                                IsCpythonObject = True
                            elif decorator.func.attr == 'CVTable':
                                IsCVTable = True
                            elif decorator.func.attr == 'NoVTable':
                                IsNoVTable = True
                    elif isinstance(decorator.func, ast.Name):
                        if decorator.func.id == 'Object':
                            IsCpythonObject = True
                        elif decorator.func.id == 'CVTable':
                            IsCVTable = True
                        elif decorator.func.id == 'NoVTable':
                            IsNoVTable = True
        if ClassName.startswith('__') and not IsCpythonObject and not IsCenum and not IsRenum:
            return
        IsPacked = False
        if getattr(Node, 'decorator_list', None):
            for decorator in Node.decorator_list:
                if isinstance(decorator, ast.Call):
                    if isinstance(decorator.func, ast.Attribute):
                        if getattr(decorator.func.value, 'id', None) == 'c' and decorator.func.attr == 'Attribute':
                            for arg in decorator.args:
                                if isinstance(arg, ast.Attribute):
                                    if isinstance(arg.value, ast.Attribute):
                                        if getattr(arg.value.value, 'id', None) == 't' and arg.value.attr == 'attr' and arg.attr == 'packed':
                                            IsPacked = True
        if IsPacked:
            Gen.class_packed.add(ClassName)
        if IsCpythonObject:
            CInfo = CTypeInfo()
            CInfo.Name = ClassName
            CInfo.IsCpythonObject = True
            CInfo.IsStruct = True
            if module_name:
                FullName = f"{module_name}.{ClassName}"
                self.Trans.SymbolTable.insert(FullName, CInfo)
            self.Trans.SymbolTable.insert(ClassName, CInfo)
        if IsCenum:
            EnumTypeNode = CTypeInfo()
            EnumTypeNode.Name = ClassName
            EnumTypeNode.BaseType = t.CEnum(ClassName)
            EnumTypeNode.IsEnum = True
            self.Trans.SymbolTable.insert(ClassName, EnumTypeNode)
            next_enum_value: int = 0
            for item in Node.body:
                VarName = None
                ItemValue = None
                if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
                    VarName = item.target.id
                    ItemValue = item.value
                elif isinstance(item, ast.Assign):
                    for target in item.targets:
                        if isinstance(target, ast.Name):
                            VarName = target.id
                            break
                    ItemValue = item.value
                if VarName is None:
                    continue
                # 提取枚举值：优先用显式赋值，否则自动编号
                if ItemValue is not None and isinstance(ItemValue, ast.Constant) and isinstance(ItemValue.value, int):
                    value = ItemValue.value
                    next_enum_value = ItemValue.value + 1
                else:
                    value = next_enum_value
                    next_enum_value += 1
                MemberNode = CTypeInfo()
                MemberNode.Name = VarName
                MemberNode.BaseType = t.CEnum(ClassName)
                MemberNode.value = value
                MemberNode.EnumName = ClassName
                MemberNode.Lineno = item.lineno
                MemberNode.IsEnumMember = True
                self.Trans.SymbolTable.insert(VarName, MemberNode)
                self.Trans.SymbolTable.insert(f"{ClassName}.{VarName}", MemberNode)
                self.Trans.SymbolTable.insert(f"{ClassName}_{VarName}", MemberNode)
            return
        if IsRenum:
            # REnum 跨模块导入：注册 REnum 类型 + 变体成员到 SymbolTable
            # 对齐同模块 _EmitREnumLlvm 的注册逻辑
            RenumTypeNode = CTypeInfo()
            RenumTypeNode.Name = ClassName
            RenumTypeNode.IsRenum = True
            RenumTypeNode.IsEnum = True  # 兼容 IsEnum 检查
            # REnum 在内存布局上是 struct，必须设置 IsStruct=True 才能让
            # HandlesTypeMerge 的 CPtr 吸收逻辑生效（REnumType | t.CPtr = REnumType*）
            RenumTypeNode.IsStruct = True
            if module_name:
                FullName = f"{module_name}.{ClassName}"
                self.Trans.SymbolTable.insert(FullName, RenumTypeNode)
            self.Trans.SymbolTable.insert(ClassName, RenumTypeNode)
            # 从 stub.ll 加载 REnum 结构体布局到 Gen.structs
            self._TryLoadStructFromStub(ClassName, Gen)
            # 记录 class_sha1_map（跨模块名修饰）
            source_sha1 = None
            if actual_module_name and hasattr(Gen, 'ModuleSha1Map') and actual_module_name in Gen.ModuleSha1Map:
                source_sha1 = Gen.ModuleSha1Map[actual_module_name]
            elif module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map:
                source_sha1 = Gen.ModuleSha1Map[module_name]
            if source_sha1:
                if not hasattr(Gen, 'class_sha1_map'):
                    Gen.class_sha1_map = {}
                Gen.class_sha1_map[ClassName] = source_sha1
            # 遍历嵌套 ClassDef 注册变体成员
            # REnum body 是嵌套 ClassDef（变体定义），不是 AnnAssign/Assign
            next_tag: int = 0
            variant_names: list[str] = []
            for item in Node.body:
                if isinstance(item, ast.ClassDef):
                    VariantName = item.name
                    MemberNode = CTypeInfo()
                    MemberNode.Name = VariantName
                    MemberNode.value = next_tag
                    MemberNode.EnumName = ClassName
                    MemberNode.Lineno = item.lineno
                    MemberNode.IsEnumMember = True
                    self.Trans.SymbolTable.insert(VariantName, MemberNode)
                    self.Trans.SymbolTable.insert(f"{ClassName}.{VariantName}", MemberNode)
                    self.Trans.SymbolTable.insert(f"{ClassName}_{VariantName}", MemberNode)
                    variant_names.append(VariantName)
                    next_tag += 1
                    # 加载嵌套变体结构体（如 LLVMType_Int）到 Gen.structs，
                    # 并注册 class_members 以支持 _HandleREnumConstructLlvm 的 payload 存储和
                    # _HandleRenumMatchLlvm 的 binding 提取。
                    NestedStructName: str = f"{ClassName}_{VariantName}"
                    self._TryLoadStructFromStub(NestedStructName, Gen)
                    if NestedStructName not in Gen.class_members:
                        Gen.class_members[NestedStructName] = []
                    if NestedStructName not in Gen.class_member_signeds:
                        Gen.class_member_signeds[NestedStructName] = {}
                    if Gen.class_members[NestedStructName]:
                        # 已有成员（_TryLoadStructFromStub 可能已加载），跳过
                        pass
                    else:
                        Gen.class_members[NestedStructName].append(('__tag', ir.IntType(32)))
                        Gen.class_member_signeds[NestedStructName]['__tag'] = None
                        for nested_item in item.body:
                            parsed = self.CollectAnnAssignMember(nested_item, Gen)
                            if parsed:
                                MName, MType, MTypeInfo = parsed
                                Gen.class_members[NestedStructName].append((MName, MType))
                                Gen.class_member_signeds[NestedStructName][MName] = None
                    # 当 stub 中没有嵌套变体结构体定义时（_TryLoadStructFromStub 失败），
                    # 使用主 REnum 结构体的 body (max_variant_struct) 创建嵌套变体结构体，
                    # 确保跨模块布局一致。否则 _generate_structs() Step 4 会从 class_members
                    # 设置最小布局 body，导致 GEP 偏移量与定义模块不匹配（offset 4 vs offset 8）。
                    NestedStructExisting = Gen.structs.get(NestedStructName)
                    NestedHasBody = (isinstance(NestedStructExisting, ir.IdentifiedStructType)
                                     and NestedStructExisting.elements is not None
                                     and len(NestedStructExisting.elements) > 0)
                    if not NestedHasBody:
                        MainRenumStruct = Gen.structs.get(ClassName)
                        if (isinstance(MainRenumStruct, ir.IdentifiedStructType)
                                and MainRenumStruct.elements is not None
                                and len(MainRenumStruct.elements) > 0):
                            NestedStruct = Gen._get_or_create_struct(NestedStructName, source_sha1=source_sha1)
                            if isinstance(NestedStruct, ir.IdentifiedStructType) and NestedStruct.is_opaque:
                                NestedStruct.set_body(*MainRenumStruct.elements)
                elif isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
                    # 显式值变体（无 payload）
                    VariantName = item.target.id
                    value = next_tag
                    if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
                        value = item.value.value
                    MemberNode = CTypeInfo()
                    MemberNode.Name = VariantName
                    MemberNode.value = value
                    MemberNode.EnumName = ClassName
                    MemberNode.Lineno = item.lineno
                    MemberNode.IsEnumMember = True
                    self.Trans.SymbolTable.insert(VariantName, MemberNode)
                    self.Trans.SymbolTable.insert(f"{ClassName}.{VariantName}", MemberNode)
                    self.Trans.SymbolTable.insert(f"{ClassName}_{VariantName}", MemberNode)
                    variant_names.append(VariantName)
                    next_tag = value + 1
            RenumTypeNode.RenumVariants = variant_names
            return
        # 先初始化 class_methods/class_members 等容器，确保 _TryLoadStructFromStub
        # 和 _get_or_create_struct 中的 IsEnum 守卫（clean_name not in class_methods）
        # 能正确识别 AST 节点类名（避免 ASTKind 枚举名冲突时把节点类当枚举返回 i32）
        if ClassName not in Gen.class_members:
            Gen.class_members[ClassName] = []
        if ClassName not in Gen.class_member_defaults:
            Gen.class_member_defaults[ClassName] = {}
        if ClassName not in Gen.class_member_signeds:
            Gen.class_member_signeds[ClassName] = {}
        if ClassName not in Gen.class_member_bitfields:
            Gen.class_member_bitfields[ClassName] = {}
        if ClassName not in Gen.class_member_byteorders:
            Gen.class_member_byteorders[ClassName] = {}
        if ClassName not in Gen.class_member_bitoffsets:
            Gen.class_member_bitoffsets[ClassName] = {}
        if ClassName not in Gen.class_methods:
            Gen.class_methods[ClassName] = []
        # 先计算 source_sha1，确保首次 _TryLoadStructFromStub 调用就能使用正确的 sha1
        # 优先使用传入的 source_sha1（来自 _TryLoadClassMembersFromPyi 的直接调用，
        # 当前模块未直接导入定义模块时 module_name 查找会失败，需依赖传入的 source_sha1）
        if not source_sha1:
            if actual_module_name and hasattr(Gen, 'ModuleSha1Map') and actual_module_name in Gen.ModuleSha1Map:
                source_sha1 = Gen.ModuleSha1Map[actual_module_name]
            elif module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map:
                source_sha1 = Gen.ModuleSha1Map[module_name]
        # 提前注册 struct：使用导入的 source_sha1 创建 opaque struct，
        # 避免后续 _TryLoadStructFromStub 触发嵌套编译时，StructGen 用本地 sha1
        # 创建缺少基类字段（如 GSListNode.Next）的本地类型定义。
        Gen._get_or_create_struct(ClassName, source_sha1=source_sha1, packed=IsPacked)
        # Track which module defines this class (for cross-module name mangling)
        if source_sha1:
            if not hasattr(Gen, 'class_sha1_map'):
                Gen.class_sha1_map = {}
            Gen.class_sha1_map[ClassName] = source_sha1
        # --- 预扫描预注册：修复编译时序问题 ---
        # _TryLoadStructFromStub → _parse_llvm_type → _specialize_generic_class
        # 可能触发 list[str].__new__ 编译（其中调用 pool.alloc(48)），
        # 此时 MemManager 尚未注册到虚表，导致直接调用返回 NULL → 段错误。
        # 修复：在 _TryLoadStructFromStub 之前预扫描方法列表并提前注册虚表。
        _has_methods_prescan = False
        # PEP 695 泛型类的方法声明必须跳过：方法参数类型 T（如 list[T].append(item: T)）
        # 会被解析为 opaque struct，LLVM 报 "invalid type for function argument"。
        # 字段（AnnAssign）仍正常加载，确保继承字段（如 GSListNode.Next）可被展平。
        if not IsGenericClass:
            for _item in Node.body:
                if isinstance(_item, ast.FunctionDef):
                    _has_methods_prescan = True
                    _MethodName = _item.name
                    # 构造函数（__new__/__init__/__before_init__）不放入 vtable，
                    # 避免子类与基类 vtable 大小不一致导致虚分派索引偏移
                    # （如 Module 有 __new__/__init__ 使 vtable=7，AST 无它们 vtable=5，
                    # 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4）。
                    if _MethodName in ('__new__', '__init__', '__before_init__'):
                        continue
                    _FuncFullName = f"{ClassName}.__init__" if _MethodName == "__init__" else f"{ClassName}.__call__" if _MethodName == "__call__" else f"{ClassName}.{_MethodName}"
                    if _FuncFullName not in Gen.class_methods[ClassName]:
                        Gen.class_methods[ClassName].append(_FuncFullName)
        if _has_methods_prescan and IsCVTable:
            Gen._cross_module_vtable_classes.add(ClassName)
            Gen.class_vtable.add(ClassName)
        # 首次加载就传入 source_sha1，避免从其他模块的 output stub 中加载到错误的结构体定义
        # （如 HandlesExprCall.py 的 output stub 中 43f27dda2e5b5923.Value 只有 5 字段，
        #   而正确的 aaf8ba449d1e64c1.Value 有 6 字段）
        self._TryLoadStructFromStub(ClassName, Gen, source_sha1=source_sha1)
        # 如果 _get_or_create_struct 因 sha1 冲突创建了新的 opaque struct，
        # 需用 source_sha1 重新加载正确的 stub body。
        if source_sha1:
            self._TryLoadStructFromStub(ClassName, Gen, source_sha1=source_sha1)
        has_methods = False
        # 解析 __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
        _existing_member_names = {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
            parsed = self.CollectAnnAssignMember(item, Gen)
            if parsed:
                VarName, MemberType, TypeInfo = parsed
                if TypeInfo is None:
                    if VarName not in _existing_member_names:
                        Gen.class_members[ClassName].append((VarName, MemberType))
                        _existing_member_names.add(VarName)
                    Gen.class_member_signeds[ClassName][VarName] = None
                    Gen.class_member_bitfields[ClassName][VarName] = 0
                else:
                    if TypeInfo.IsBitField:
                        Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth
                    else:
                        if VarName not in _existing_member_names:
                            Gen.class_members[ClassName].append((VarName, MemberType))
                            _existing_member_names.add(VarName)
                        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 = self._BuildScalarConstant(item.value, MemberType, Gen)
                        if const:
                            Gen.class_member_defaults[ClassName][VarName] = const
            elif isinstance(item, ast.FunctionDef) and not IsGenericClass:
                # PEP 695 泛型类跳过方法声明：T 参数会变成 opaque struct 触发
                # "invalid type for function argument"。字段已由上面的 AnnAssign
                # 分支加载，继承字段（如 GSListNode.Next）由后面的展平逻辑补充。
                has_methods = True
                MethodName = item.name
                FuncFullName = f"{ClassName}.__init__" if MethodName == "__init__" else f"{ClassName}.__call__" if MethodName == "__call__" else f"{ClassName}.{MethodName}"
                # 构造函数（__new__/__init__/__before_init__）不放入 vtable，
                # 避免子类与基类 vtable 大小不一致导致虚分派索引偏移。
                # register_method 内部也会过滤，此处仅跳过 class_methods.append。
                if MethodName not in ('__new__', '__init__', '__before_init__'):
                    if FuncFullName not in Gen.class_methods[ClassName]:
                        Gen.class_methods[ClassName].append(FuncFullName)
                Gen.register_method(ClassName, FuncFullName)
                is_item_static = any(isinstance(d, ast.Name) and d.id == 'staticmethod' for d in item.decorator_list)
                is_item_property = any(isinstance(d, ast.Name) and d.id == 'property' for d in item.decorator_list)
                is_item_classmethod = any(isinstance(d, ast.Name) and d.id == 'classmethod' for d in item.decorator_list)
                is_item_prop_setter = any(isinstance(d, ast.Attribute) and d.attr == 'setter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list)
                is_item_prop_getter = any(isinstance(d, ast.Attribute) and d.attr == 'getter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list)
                is_item_prop_deleter = any(isinstance(d, ast.Attribute) and d.attr == 'deleter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list)
                # setter/deleter 使用不同的函数名后缀
                DeclFuncName = FuncFullName
                if is_item_prop_setter:
                    DeclFuncName = FuncFullName + '$set'
                elif is_item_prop_deleter:
                    DeclFuncName = FuncFullName + '$del'
                if DeclFuncName not in Gen.functions:
                    FuncDeclNode = ast.FunctionDef(
                        name=DeclFuncName,
                        args=item.args,
                        body=item.body,
                        decorator_list=item.decorator_list,
                        returns=item.returns
                    )
                    try:
                        self._EmitExternalFuncDeclLlvm(FuncDeclNode, Gen, is_class_method=not is_item_static and not is_item_classmethod, source_module_name=module_name)
                    except Exception as e:
                        raise
                func_meta = FuncMeta.NONE
                if is_item_static:
                    func_meta |= FuncMeta.STATIC_METHOD
                if is_item_property:
                    func_meta |= FuncMeta.PROPERTY_GETTER
                if is_item_classmethod:
                    func_meta |= FuncMeta.CLASS_METHOD
                if is_item_prop_setter:
                    func_meta |= FuncMeta.PROPERTY_SETTER
                if is_item_prop_getter:
                    func_meta |= FuncMeta.PROPERTY_GETTER
                if is_item_prop_deleter:
                    func_meta |= FuncMeta.PROPERTY_DELETER
                # setter/deleter 的 SymKey 使用带后缀的函数名
                SymKey = DeclFuncName
                if not self.Trans.SymbolTable.has(SymKey):
                    FuncInfo = CTypeInfo()
                    FuncInfo.Name = SymKey
                    FuncInfo.IsFunction = True
                    FuncInfo.MetaList = func_meta
                    self.Trans.SymbolTable.insert(SymKey, FuncInfo)
                else:
                    existing = self.Trans.SymbolTable[SymKey]
                    if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE:
                        existing.MetaList = func_meta
                # setter/deleter: 同时在原始 PropKey（不带后缀）下注册 MetaList
                if is_item_prop_setter or is_item_prop_deleter:
                    base_existing = self.Trans.SymbolTable.lookup(FuncFullName)
                    if base_existing:
                        if func_meta != FuncMeta.NONE:
                            base_existing.MetaList = base_existing.MetaList | func_meta
                    else:
                        PropInfo = CTypeInfo()
                        PropInfo.Name = FuncFullName
                        PropInfo.IsFunction = True
                        PropInfo.MetaList = func_meta
                        self.Trans.SymbolTable.insert(FuncFullName, PropInfo)
        # --- 跨模块继承字段展平 ---
        # _EmitExternalClassDeclLlvm 只添加了类自身定义的字段（来自 .pyi），
        # 没有展平父类（如 GSListNode[T]）的继承字段，导致 class_members 缺少
        # 继承字段，_get_member_offset 返回错误偏移。
        # 修复：先尝试从已加载的父类获取真实字段名；若父类未加载，
        # 则用 struct body 元素数推断继承字段数并补充占位条目 __inherited_N。
        _ParentClass: str | None = None
        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
                elif isinstance(_base, ast.Subscript):
                    _spec_name: str | None = self.Trans.ExprCallHandle._ResolveGenericSlice(_base)
                    if _spec_name:
                        _base_name = _spec_name
                    else:
                        # _ResolveGenericSlice 失败（泛型基类未在当前模块注册为模板，
                        # 常见于跨模块导入：如 HandlesExprCall.py 导入 Value(GSListNode[Value])，
                        # 但 GSListNode 定义在 includes/linkedlist.py，尚未编译）。
                        # 直接从 AST 提取泛型基类名（如 GSListNode[Value] -> GSListNode），
                        # 后续继承字段展平逻辑会从 .pyi 加载该基类的字段。
                        if isinstance(_base.value, ast.Name):
                            _base_short_name: str = _base.value.id
                        elif isinstance(_base.value, ast.Attribute):
                            _base_short_name: str = _base.value.attr
                        else:
                            continue
                        # 尝试手动构造特化名并检查是否已有特化 class_members。
                        # 这解决了 _ResolveGenericSlice 失败但特化已通过其他路径
                        # （如 _parse_llvm_type）触发的情况。特化 class_members 中
                        # 的 T 已被正确替换为具体类型（如 BasicBlock），避免使用
                        # 未特化的 GSListNode 导致 T* 占位类型残留。
                        _slice_name: str | None = None
                        if isinstance(_base.slice, ast.Name):
                            _slice_name = _base.slice.id
                        elif isinstance(_base.slice, ast.Attribute):
                            _slice_name = _base.slice.attr
                        elif isinstance(_base.slice, ast.Subscript):
                            # 嵌套泛型（如 GSList[GSListNode[T]]），暂不处理
                            pass
                        _manual_spec_name: str | None = None
                        if _slice_name is not None:
                            _manual_spec_name = f"{_base_short_name}[{_slice_name}]"
                        if _manual_spec_name is not None and _manual_spec_name in Gen.class_members:
                            # 特化 class_members 已存在，直接使用（T 已被替换）
                            _base_name = _manual_spec_name
                        else:
                            _base_name = _base_short_name
                else:
                    continue
                if _base_name == ClassName:
                    continue
                if _base_name in ('CVTable', 'Object', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
                    continue
                # 总是记录父类名，即使父类 class_members 未加载。
                # _get_member_offset 会沿 class_parent 链回退查找继承字段。
                _ParentClass = _base_name
                if not hasattr(Gen, 'class_parent'):
                    Gen.class_parent = {}
                Gen.class_parent[ClassName] = _ParentClass
                break
        # 治本修复：在继承展开前，尝试从 stub/.pyi 加载父类的 class_members。
        # 确保子类 class_members 能正确展平父类真实字段名（而非 __inherited_N 占位符），
        # 避免 struct body 从不完整 class_members 生成导致 GEP 越界。
        # 同时处理父类 class_members 全为占位符的情况（清除后重新加载）。
        if _ParentClass:
            _parent_members_check: list = Gen.class_members.get(_ParentClass, [])
            _parent_all_placeholders: bool = bool(_parent_members_check) and all(
                n.startswith('__inherited_') for n, _ in _parent_members_check
            )
            if not _parent_members_check or _parent_all_placeholders:
                # 清除占位条目以便 _TryLoadClassMembersFromPyi 的 guard 通过
                _old_parent_members: list = _parent_members_check
                if _parent_all_placeholders:
                    Gen.class_members[_ParentClass] = []
                _sha1_map: dict[str, str] = getattr(Gen, 'ModuleSha1Map', {})
                _parent_loaded: bool = False
                for _mod_name, _mod_sha1 in _sha1_map.items():
                    _stub_name: str = f"{_mod_sha1}.stub.ll"
                    try:
                        self._TryLoadClassMembersFromPyi(_ParentClass, _stub_name, Gen)
                    except Exception:
                        pass
                    _parent_members_check = Gen.class_members.get(_ParentClass, [])
                    if _parent_members_check and not all(n.startswith('__inherited_') for n, _ in _parent_members_check):
                        _parent_loaded = True
                        break
                if not _parent_loaded and _old_parent_members:
                    # 加载失败，回滚到旧占位条目（有总比没有好）
                    Gen.class_members[_ParentClass] = _old_parent_members
        if _ParentClass and _ParentClass in Gen.class_members:
            _parent_members: list = list(Gen.class_members[_ParentClass])
            _parent_defaults: dict = dict(Gen.class_member_defaults.get(_ParentClass, {}))
            _existing_names: set = {m[0] for m in Gen.class_members[ClassName]}
            _inherited: list[tuple] = []
            for _pm_name, _pm_type in _parent_members:
                if _pm_name not in _existing_names:
                    _inherited.append((_pm_name, _pm_type))
                    if _pm_name in _parent_defaults:
                        Gen.class_member_defaults[ClassName][_pm_name] = _parent_defaults[_pm_name]
            Gen.class_members[ClassName] = _inherited + Gen.class_members[ClassName]
        else:
            # 父类未加载到 class_members（常见于泛型特化基类如 GSListNode[Value]，
            # 其特化不在 .pyi 中）。用 struct body 元素数推断继承字段数。
            _st = Gen.structs.get(ClassName)
            if isinstance(_st, ir.IdentifiedStructType) and _st.elements is not None:
                _num_elements = len(_st.elements)
                # 如果类有 vtable ptr（struct 首元素），需减去 1
                # 否则 vtable ptr 会被误当成 __inherited_0 占位条目，
                # 导致子类继承时多出一个字段（如 Name(AST) 从 9 字段变成 10）
                _has_vtable_ptr = IsCVTable or (has_methods and not IsNoVTable)
                if _has_vtable_ptr and _num_elements > 0:
                    _num_elements -= 1
                _num_members = len(Gen.class_members[ClassName])
                if _num_elements > _num_members:
                    _num_inherited = _num_elements - _num_members
                    _inherited_ph: list[tuple] = [(f'__inherited_{i}', _st.elements[i]) for i in range(_num_inherited)]
                    Gen.class_members[ClassName] = _inherited_ph + Gen.class_members[ClassName]
        if has_methods:
            if IsCVTable:
                Gen._cross_module_vtable_classes.add(ClassName)
                Gen.class_vtable.add(ClassName)
        if IsNoVTable:
            Gen._cross_module_novtable.add(ClassName)
        # __before_init__ 对所有跨模块结构体声明（定义侧无条件生成，导入侧也应无条件声明）
        NewFuncName = f'{ClassName}.__before_init__'
        if not Gen._has_function(NewFuncName):
            # 复用前面已查找的 source_sha1（优先 actual_module_name 再 module_name），
            # 通过 class_sha1_map 获取，避免此处只查 module_name 导致子模块（如 w32.win32file）查找失败
            source_sha1 = getattr(Gen, 'class_sha1_map', {}).get(ClassName)
            MangledName = Gen._mangle_name(NewFuncName) if not source_sha1 else f"{source_sha1}.{NewFuncName}"
            StructType = Gen.structs.get(ClassName)
            if StructType is not None:
                StructPtrType = ir.PointerType(StructType)
                NewFuncType = ir.FunctionType(ir.VoidType(), [StructPtrType])
                NewFunc = ir.Function(Gen.module, NewFuncType, name=MangledName)
                Gen.functions[NewFuncName] = NewFunc
        bitfields = Gen.class_member_bitfields.get(ClassName, {})
        if any(v > 0 for v in bitfields.values()):
            current_bit_offset = 0
            for name, _ in Gen.class_members.get(ClassName, []):
                bw = bitfields.get(name, 0)
                Gen.class_member_bitoffsets[ClassName][name] = current_bit_offset
                current_bit_offset += bw

    def _build_stub_index(self) -> None:
        """扫描所有 .stub.ll 文件构建 class_name → 条目列表索引

        一次扫描替代 _TryLoadStructFromStub 的 609 次全量扫描。
        通过文件数签名检测新增 stub，支持增量编译。
        """
        ProjectRoot = self._find_project_root()
        temp_dir = os.path.join(ProjectRoot, 'temp')
        output_dir = os.path.join(ProjectRoot, 'output')
        if not os.path.isdir(temp_dir) and not os.path.isdir(output_dir):
            return

        # 文件数签名：检测 stub 文件新增（增量编译时 output 逐步填充）
        output_count = sum(1 for f in os.listdir(output_dir) if f.endswith('.stub.ll')) if os.path.isdir(output_dir) else 0
        temp_count = sum(1 for f in os.listdir(temp_dir) if f.endswith('.stub.ll')) if os.path.isdir(temp_dir) else 0
        signature = (output_count, temp_count)
        if self._stub_index_signature == signature and self._stub_index:
            return  # 索引未过期

        # 重建索引
        self._stub_index.clear()
        for scan_dir, is_output in [(output_dir, True), (temp_dir, False)]:
            if not os.path.isdir(scan_dir):
                continue
            for filename in os.listdir(scan_dir):
                if not filename.endswith('.stub.ll'):
                    continue
                stub_path = os.path.join(scan_dir, filename)
                # 预检查文件存在性：os.listdir 与 open 之间文件可能被 --clean 或
                # 并发写入删除（独立 profile 脚本曾触发 FileNotFoundError）
                if not os.path.isfile(stub_path):
                    continue
                file_sha1 = filename.replace('.stub.ll', '')
                try:
                    with open(stub_path, 'r', encoding='utf-8') as f:
                        content = f.read()
                    for line in content.splitlines():
                        stripped = line.strip()
                        match = re.match(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)', stripped)
                        if match:
                            full_name = match.group(1)
                            short_name = match.group(2)
                            struct_body = match.group(3).strip()
                            # 索引键：short_name 和 full_name 都映射到同一条目
                            self._stub_index.setdefault(short_name, []).append((full_name, struct_body, file_sha1, is_output))
                            if full_name != short_name:
                                self._stub_index.setdefault(full_name, []).append((full_name, struct_body, file_sha1, is_output))
                except FileNotFoundError:
                    # 竞态：isfile 检查后文件被删除，跳过即可（不应触发 strict raise）
                    continue
                except Exception as _e:
                    if _config_mode == "strict":
                        raise
                    _vlog().warning(f"构建 stub 索引失败: {_e}", "Exception")
        self._stub_index_signature = signature

    def _TryLoadStructFromStub(self, class_name: str, Gen: LlvmGeneratorMixin, source_sha1: str | None = None) -> None:
        # 缓存键包含 Gen 实例标识，确保每个模块的 Gen 都能独立加载 struct 定义，
        # 同时仍能防止同一 Gen 内的递归重入。原先使用纯 class_name 作为键会导致
        # 跨模块 struct 类型对象无法分别 set_body（每个模块有独立的 self.structs）。
        # 治本修复：当 source_sha1 指定时（同名类冲突情况），使用 sha1 前缀全名作为
        # 缓存键，确保不同模块的同名类（如 stmts.py:Module 和 __module.py:Module）
        # 不会互相阻止 stub 加载。
        cache_key = (id(Gen), f"{source_sha1}.{class_name}" if source_sha1 else class_name)
        if cache_key in self._struct_Load_cache:
            return
        # 先设置缓存防止递归重入，但如果加载失败则清除缓存允许后续重试
        self._struct_Load_cache[cache_key] = True

        # 使用 stub 索引替代全量扫描（609 次 × 100 文件 → 1 次扫描 + O(1) 查询）
        self._build_stub_index()
        entries = self._stub_index.get(class_name, [])

        if not entries:
            del self._struct_Load_cache[cache_key]
            return

        # 选择最佳条目：
        # 优先级 0: 当 source_sha1 指定时，优先选择 type_sha1 匹配的条目（治本修复：
        #           同名类冲突时确保选择正确模块的 struct 定义）
        # 优先级 1: 类型定义模块自身的 stub（file_sha1 == full_name 中的 sha1 前缀）
        #           定义模块的 stub 包含完整的字段展平（含跨模块继承字段）
        # 优先级 2: output（Phase2 生成）优于 temp（Phase1 生成）
        # 优先级 3: 非 opaque（具体定义）优于 opaque
        def _entry_priority(e: tuple[str, str, str, bool]) -> tuple[int, int, int, int]:
            full_name, struct_body, file_sha1, from_output = e
            type_sha1 = file_sha1
            if '.' in full_name:
                parts = full_name.split('.', 1)
                if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]):
                    type_sha1 = parts[0]
            sha1_match = 0 if (source_sha1 and type_sha1 == source_sha1) else 1
            is_defining = 0 if type_sha1 == file_sha1 else 1
            is_temp = 0 if from_output else 1
            is_opaque = 0 if (struct_body and struct_body != 'opaque') else 1
            return (sha1_match, is_defining, is_temp, is_opaque)

        best_entry = min(entries, key=_entry_priority)
        full_name, struct_body, file_sha1, from_output = best_entry

        # Bug 1 修复：从 full_name 提取 sha1 前缀（类型定义模块的 sha1），
        # 而非使用 file_sha1（stub 文件所在模块的 sha1，可能只是导入方而非定义方）。
        # 例如 output/35ffd4b9fbd082d1.stub.ll (main.py) 中包含
        # %"5cde8c6813a2b6f3.Function" = type {...}，
        # 此时 file_sha1='35ffd4b9fbd082d1' (main.py) 但类型实际定义在
        # __function.py (sha1='5cde8c6813a2b6f3')，必须用后者作为 source_sha1。
        actual_sha1 = file_sha1
        if '.' in full_name:
            parts = full_name.split('.', 1)
            if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]):
                actual_sha1 = parts[0]

        is_packed = struct_body.startswith('<{') and struct_body.endswith('}>')
        if struct_body and struct_body != 'opaque':
            elem_types = []
            if is_packed:
                inner = struct_body[2:-1].strip()
            else:
                inner = struct_body.strip('{}').strip()
            if inner:
                for elem in inner.split(','):
                    elem = elem.strip()
                    if elem:
                        et = self._parse_llvm_type(elem, Gen, source_sha1=actual_sha1)
                        elem_types.append(et if et else ir.IntType(32))
            try:
                st = Gen._get_or_create_struct(class_name, source_sha1=actual_sha1, packed=is_packed)
                if isinstance(st, ir.IdentifiedStructType) and st.is_opaque:
                    st.set_body(*elem_types)
                    if is_packed:
                        Gen.class_packed.add(class_name)
                # 同步设置短名 struct 的 body：当存在 sha1 冲突时，_get_or_create_struct
                # 返回 full_key struct，但代码可能通过短名引用旧 struct（由 setup_from_symbol_table
                # 早期创建的 opaque 占位符，使用本地 sha1 前缀）。需要同步设置短名 struct
                # 的 body，确保 GEP 指令能正确访问字段（修复跨模块类型定义冲突导致的
                # 字段索引错位问题）。
                short_st = Gen.structs.get(class_name)
                if short_st is not None and short_st is not st and isinstance(short_st, ir.IdentifiedStructType) and short_st.is_opaque:
                    try:
                        short_st.set_body(*elem_types)
                    except Exception:
                        pass  # set_body 可能因已设置而失败，忽略
            except Exception as _e:
                if _config_mode == "strict":
                    raise
                _vlog().warning(f"处理导入失败: {_e}", "Exception")
        stub_filename = actual_sha1 + '.stub.ll'
        self._TryLoadClassMembersFromPyi(class_name, stub_filename, Gen)

    def _TryLoadClassMembersFromPyi(self, class_name: str, stub_filename: str, Gen: LlvmGeneratorMixin) -> None:
        ProjectRoot = self._find_project_root()
        temp_dir = os.path.join(ProjectRoot, 'temp')
        if class_name in Gen.class_members and len(Gen.class_members[class_name]) > 0:
            return
        pyi_basename = stub_filename.replace('.stub.ll', '.vpi')
        pyi_path = os.path.join(temp_dir, pyi_basename)
        if not os.path.isfile(pyi_path):
            # 回退读取旧缓存 .pyi
            pyi_basename = stub_filename.replace('.stub.ll', '.pyi')
            pyi_path = os.path.join(temp_dir, pyi_basename)
        
        if self._pyi_cache_dir != temp_dir:
            self._pyi_cache.clear()
            self._pyi_cache_dir = temp_dir
        
        if pyi_path not in self._pyi_cache:
            if not os.path.isfile(pyi_path):
                self._pyi_cache[pyi_path] = None
                return
            try:
                with open(pyi_path, 'r', encoding='utf-8') as f:
                    self._pyi_cache[pyi_path] = ast.parse(f.read())
            except Exception as e:
                _vlog().warning(f"HandlesImports: 忽略异常 {e}", exc_info=e)
                self._pyi_cache[pyi_path] = None
                return
        
        pyi_tree = self._pyi_cache[pyi_path]
        if pyi_tree is None:
            return
        source_sha1 = stub_filename.replace('.stub.ll', '')
        module_name = None
        if hasattr(Gen, 'ModuleSha1Map'):
            for mod_name, mod_sha1 in Gen.ModuleSha1Map.items():
                if mod_sha1 == source_sha1 and '.' not in mod_name:
                    module_name = mod_name
                    break
            if module_name is None:
                for mod_name, mod_sha1 in Gen.ModuleSha1Map.items():
                    if mod_sha1 == source_sha1:
                        module_name = mod_name
                        break
        if module_name is None and hasattr(Gen, 'module_sha1') and Gen.module_sha1 == source_sha1:
            module_name = '__self__'
        # module_name 反查失败时（当前模块未直接导入定义模块），
        # 仍需注册类成员和 vtable 信息。传 source_sha1 让 _EmitExternalClassDeclLlvm
        # 正确设置 class_sha1_map 和注册 vtable。
        found = False
        for node in pyi_tree.body:
            if isinstance(node, ast.ClassDef) and node.name == class_name:
                self._EmitExternalClassDeclLlvm(node, Gen, module_name=module_name, source_sha1=source_sha1)
                found = True
                break
        if not found:
            return
        if class_name in Gen.class_members and len(Gen.class_members[class_name]) > 0:
            return
        return

    def _BuildScalarConstant(self, value_node: ast.AST, target_type: ir.Type, Gen: LlvmGeneratorMixin) -> ir.Constant | None:
        """Build a scalar constant value from AST node, delegated to unified method."""
        return self.Trans._BuildScalarConstantUnified(value_node, target_type, Gen)

    def _LookupStubFuncType(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None:
        """从 stub.ll 文件中查找指定函数的 LLVM 类型

        扫描 output/ 和 temp/ 两个目录的 .stub.ll 文件。
        关键修复：output/（Phase 2 完整结果）必须覆盖 temp/（Phase 1 不完整结果），
        否则继承包装方法（在 Phase 2 的 _generate_inherited_method_wrappers 中生成）
        将无法被解析，导致跨模块调用使用默认 i32 返回类型 → 64 位指针截断。
        """

        if not getattr(self, '_stub_func_cache', None):
            self._stub_func_cache = {}

        ProjectRoot = self._find_project_root()
        temp_dir = os.path.join(ProjectRoot, 'temp')
        output_dir = os.path.join(ProjectRoot, 'output')

        # 文件数签名：检测 stub 新增（增量编译时 output 逐步填充完整签名）
        output_count = sum(1 for f in os.listdir(output_dir) if f.endswith('.stub.ll')) if os.path.isdir(output_dir) else 0
        temp_count = sum(1 for f in os.listdir(temp_dir) if f.endswith('.stub.ll')) if os.path.isdir(temp_dir) else 0
        signature = (output_count, temp_count)
        if getattr(self, '_stub_func_cache_signature', None) != signature or not self._stub_func_cache:
            # 签名变化或缓存为空，重建缓存
            self._stub_func_cache = {}
            self._stub_func_cache_signature = signature

        if not os.path.isdir(temp_dir) and not os.path.isdir(output_dir):
            return None

        if func_name not in self._stub_func_cache:
            # 先扫描 temp/（Phase 1，不完整签名），再扫描 output/（Phase 2，完整签名）覆盖之
            # 这样 output 中存在的继承包装方法会覆盖 temp 中的同名旧声明（若有），
            # 也填补 temp 中缺失的函数声明
            for scan_dir in [temp_dir, output_dir]:
                if not os.path.isdir(scan_dir):
                    continue
                for filename in os.listdir(scan_dir):
                    if not filename.endswith('.stub.ll'):
                        continue

                    stub_path = os.path.join(scan_dir, filename)
                    # 预检查文件存在性：os.listdir 与 open 之间文件可能被并发写入删除
                    if not os.path.isfile(stub_path):
                        continue
                    source_sha1 = filename.replace('.stub.ll', '')
                    try:
                        with open(stub_path, 'r', encoding='utf-8') as f:
                            content = f.read()

                        for line in content.splitlines():
                            stripped = line.strip()
                            if not stripped.startswith('declare '):
                                continue

                            name_match = stripped.split('@', 1)
                            if len(name_match) < 2:
                                continue

                            stub_func_name = name_match[1].split('(', 1)[0].strip().strip('"')

                            match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', stripped)
                            if match:
                                stub_ret = match.group(1).strip()
                                stub_params = match.group(3).strip()
                                self._stub_func_cache[stub_func_name] = (stub_ret, stub_params, '...' in stub_params, source_sha1)
                    except FileNotFoundError:
                        continue
                    except Exception as _e:
                        if _config_mode == "strict":
                            raise
                        _vlog().warning(f"处理导入失败: {_e}", "Exception")

        if func_name not in self._stub_func_cache:
            return None
        
        ret_str, params_str, is_variadic, source_sha1 = self._stub_func_cache[func_name]
        ret_type = self._parse_llvm_type(ret_str, Gen, source_sha1=source_sha1, create_structs=False)
        if ret_type is None:
            ret_type = ir.IntType(32)
        param_types = []
        if params_str and params_str != 'void':
            depth = 0
            current = ''
            for ch in params_str:
                if ch == ',' and depth == 0:
                    p = self._strip_llvm_param_name(current.strip())
                    if p and p != '...':
                        pt = self._parse_llvm_type(p, Gen, source_sha1=source_sha1, create_structs=False)
                        if pt is not None:
                            param_types.append(pt)
                        else:
                            param_types.append(ir.PointerType(ir.IntType(8)))
                    current = ''
                else:
                    if ch == '{':
                        depth += 1
                    elif ch == '}':
                        depth -= 1
                    current += ch
            p = self._strip_llvm_param_name(current.strip())
            if p and p != '...':
                pt = self._parse_llvm_type(p, Gen, source_sha1=source_sha1, create_structs=False)
                if pt is not None:
                    param_types.append(pt)
                else:
                    param_types.append(ir.PointerType(ir.IntType(8)))
        return ir.FunctionType(ret_type, param_types, var_arg=is_variadic)

    def _strip_llvm_param_name(self, param_str: str) -> str:
        """剥离 LLVM IR 参数字符串中的参数名，仅保留类型部分"""
        param_str = param_str.strip()
        # 支持 %name 和 %"quoted.name" 两种参数名形式
        result = re.sub(r'\s+%("[^"]*"|[\w.]+)\s*$', '', param_str)
        return result.strip()

    def _parse_simple_llvm_type(self, type_str: str) -> ir.Type | None:
        """解析简单的 LLVM 类型字符串（不创建结构体，避免副作用）"""

        type_str = type_str.strip()
        
        type_map = {
            'void': ir.VoidType(),
            'i1': ir.IntType(1),
            'i8': ir.IntType(8),
            'i16': ir.IntType(16),
            'i32': ir.IntType(32),
            'i64': ir.IntType(64),
            'float': ir.FloatType(),
            'double': ir.DoubleType(),
        }
        
        if type_str in type_map:
            return type_map[type_str]
        
        if type_str.endswith('*'):
            pointee = type_str[:-1].strip()
            pointee_type = self._parse_simple_llvm_type(pointee)
            if pointee_type:
                return ir.PointerType(pointee_type)
            return ir.PointerType(ir.IntType(8))
        
        if type_str.startswith('[') and ']' in type_str:
            arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str)
            if arr_match:
                size = int(arr_match.group(1))
                elem_type = self._parse_simple_llvm_type(arr_match.group(2).strip())
                if elem_type:
                    return ir.ArrayType(elem_type, size)
        
        if type_str.startswith('%'):
            return ir.PointerType(ir.IntType(8))
        
        return None

    def _LoadDeclarationsFromStubLlvm(self, module_name: str, Gen: LlvmGeneratorMixin) -> None:
        """从 stub.ll 文件加载函数声明和结构体定义到 Gen"""
        ProjectRoot = self._find_project_root()
        temp_dir = os.path.join(ProjectRoot, 'temp')

        if not os.path.isdir(temp_dir):
            return

        all_stub_files = [f for f in os.listdir(temp_dir) if f.endswith('.stub.ll')]

        source_sig_files = getattr(self.Trans, '_source_module_sig_files', {})
        target_sha1 = None
        if module_name:
            for key, val in source_sig_files.items():
                if key == module_name or key.endswith('.' + module_name):
                    target_sha1 = os.path.basename(val).replace('.vpi', '').replace('.pyi', '')
                    break
        if not target_sha1:
            ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
            target_sha1 = ModuleSha1Map.get(module_name)

        if target_sha1:
            target_stub = f"{target_sha1}.stub.ll"
            if target_stub in all_stub_files:
                stub_files = [target_stub]
            else:
                stub_files = []
        else:
            stub_files = []

        needed_sha1s = set()
        for filename in stub_files:
            stub_path = os.path.join(temp_dir, filename)
            try:
                with open(stub_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                for line in content.splitlines():
                    stripped = line.strip()
                    if stripped.startswith('%') and '=' in stripped and 'type' in stripped:
                        for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
                            needed_sha1s.add(m.group(1))
                    elif stripped.startswith('declare '):
                        for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
                            needed_sha1s.add(m.group(1))
            except Exception as _e:
                if _config_mode == "strict":
                    raise
                _vlog().warning(f"处理导入失败: {_e}", "Exception")

        preLoad_files = []
        for sha1 in needed_sha1s:
            dep_stub = f"{sha1}.stub.ll"
            if dep_stub in all_stub_files and dep_stub not in stub_files:
                preLoad_files.append(dep_stub)

        Load_order = preLoad_files + stub_files

        for filename in Load_order:
            stub_path = os.path.join(temp_dir, filename)
            source_sha1 = filename.replace('.stub.ll', '')
            is_preLoad = filename in preLoad_files
            try:
                with open(stub_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                
                for line in content.splitlines():
                    stripped = line.strip()
                    
                    if stripped.startswith('%') and '=' in stripped and 'type' in stripped:
                        struct_def_match = re.match(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)', stripped)
                        if struct_def_match:
                            raw_name = struct_def_match.group(1)
                            # 治本修复：从 raw_name 提取类型定义的实际 sha1 前缀，
                            # 而非使用 stub 文件的 sha1。同一 stub 文件可能包含多个模块的
                            # struct 定义（前向引用），必须用类型名中的 sha1 作为 source_sha1，
                            # 否则同名类冲突检测会失效（如 __module.py stub 中的
                            # e64295c03b564a53.Module 前向引用会被错误地用 6e3f70566907c6cf 作为 sha1）。
                            actual_type_sha1 = source_sha1
                            if '.' in raw_name:
                                _rn_parts = raw_name.split('.', 1)
                                if len(_rn_parts[0]) == 16 and all(_c in '0123456789abcdef' for _c in _rn_parts[0]):
                                    actual_type_sha1 = _rn_parts[0]
                                clean_name = _rn_parts[1]
                            else:
                                clean_name = raw_name
                            struct_body = struct_def_match.group(3).strip()
                            if struct_body and struct_body != 'opaque':
                                elem_types = []
                                is_packed = struct_body.startswith('<{') and struct_body.endswith('}>')
                                if is_packed:
                                    inner = struct_body[2:-1].strip()
                                else:
                                    inner = struct_body.strip('{}')
                                if inner:
                                    for elem in inner.split(','):
                                        elem = elem.strip()
                                        if elem:
                                            elem_type = self._parse_llvm_type(elem, Gen, source_sha1=actual_type_sha1)
                                            if elem_type is not None:
                                                elem_types.append(elem_type)
                                            else:
                                                elem_types.append(ir.IntType(32))
                                st = Gen._get_or_create_struct(clean_name, source_sha1=actual_type_sha1, packed=is_packed)
                                if isinstance(st, ir.IdentifiedStructType) and st.elements is None:
                                    try:
                                        st.set_body(*elem_types)
                                    except Exception as _e:
                                        if _config_mode == "strict":
                                            raise
                                        _vlog().warning(f"处理导入失败: {_e}", "Exception")
                        continue
                    
                    if not stripped.startswith('declare '):
                        continue
                    
                    if is_preLoad:
                        continue
                    
                    func_name_match = stripped.split('@', 1)
                    if len(func_name_match) < 2:
                        continue
                    
                    func_name = func_name_match[1].split('(', 1)[0].strip().strip('"')

                    if not module_name:
                        continue

                    # bare 名（无 16 位 hex SHA1 前缀）表示 CExport，调用点需用纯名
                    _Prefix: str = func_name.split('.', 1)[0]
                    if not (len(_Prefix) == 16 and all(_c in '0123456789abcdef' for _c in _Prefix)):
                        Gen._export_funcs.add(func_name)

                    try:
                        func_type = self._parse_llvm_declare(stripped, Gen)
                        if func_type is not None:
                            # __new__ 方法应返回类指针类型（堆分配替换），与 _GetFunctionSignatureLlvm/_EmitFunctionLlvm 保持一致
                            # .stub.ll 由 .pyi 生成，.pyi 生成器对无返回类型注解的 __new__ 默认使用 t.CInt，这里修正为 ClassName*
                            if '.__new__' in func_name:
                                _np = func_name.split('.')
                                if len(_np[0]) == 16 and all(_c in '0123456789abcdef' for _c in _np[0]):
                                    _new_class = _np[1]
                                else:
                                    _new_class = _np[0]
                                _new_struct = Gen.structs.get(_new_class)
                                if _new_struct is None:
                                    _full_name = func_name.split('.__new__')[0]
                                    _new_struct = Gen.structs.get(_full_name)
                                if _new_struct:
                                    _ret_type = _new_struct if isinstance(_new_struct, ir.PointerType) else ir.PointerType(_new_struct)
                                    func_type = ir.FunctionType(_ret_type, func_type.args, var_arg=func_type.var_arg)
                            if func_name in Gen.functions:
                                existing_func = Gen.functions[func_name]
                                existing_ftype = getattr(existing_func, 'ftype', None) or existing_func.type.pointee
                                if str(existing_ftype) != str(func_type):
                                    # 类型不一致：清理 module.globals + module.scope._useset 后重建，避免 DuplicatedNameError
                                    old_name = existing_func.name
                                    if old_name in Gen.module.globals:
                                        del Gen.module.globals[old_name]
                                    module_scope = getattr(Gen.module, 'scope', None)
                                    if getattr(module_scope, '_useset', None):
                                        module_scope._useset.discard(old_name)
                                    func = ir.Function(Gen.module, func_type, name=func_name)
                                    Gen.functions[func_name] = func
                                    if '.' in func_name:
                                        short_name = func_name.split('.', 1)[1]
                                        Gen.functions[short_name] = func
                            else:
                                func = Gen._get_or_declare_function(func_name, func_type)
                                Gen.functions[func_name] = func
                                if '.' in func_name:
                                    short_name = func_name.split('.', 1)[1]
                                    Gen.functions[short_name] = func
                    except Exception as _e:
                        if _config_mode == "strict":
                            raise
                        _vlog().warning(f"处理导入失败: {_e}", "Exception")
            except Exception as _e:
                if _config_mode == "strict":
                    raise
                _vlog().warning(f"处理导入失败: {_e}", "Exception")

    def _TryLoadFuncDeclsFromOutputStub(self, struct_name: str, Gen: LlvmGeneratorMixin) -> bool:
        """按需从 output 目录的 stub.ll 加载泛型特化方法声明。

        当 temp stub 不包含泛型特化（如 list[str].__iter__）时，
        从 output stub（由 _split_ll 从完整 IR 生成）中按需加载。

        struct_name: 结构体名，如 '9163064cf3eb88f4.list[str]' 或 'list[str]'
        返回 True 如果找到了并加载了新函数声明。
        """
        ProjectRoot = self._find_project_root()
        output_dir = os.path.join(ProjectRoot, 'output')
        if not os.path.isdir(output_dir):
            return False

        # 提取短名称和 SHA1 前缀
        sha1_prefix: str | None = None
        if '.' in struct_name:
            parts: list[str] = struct_name.split('.', 1)
            if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]):
                sha1_prefix = parts[0]
                short_name: str = parts[1]
            else:
                short_name = struct_name
        else:
            short_name = struct_name

        # 确定要搜索的 stub 文件列表
        stub_files_to_search: list[str] = []
        if sha1_prefix:
            target_stub = f'{sha1_prefix}.stub.ll'
            target_path = os.path.join(output_dir, target_stub)
            if os.path.isfile(target_path):
                stub_files_to_search.append(target_stub)
        else:
            # 没有SHA1前缀，搜索所有 output stub
            for fname in os.listdir(output_dir):
                if fname.endswith('.stub.ll'):
                    stub_files_to_search.append(fname)

        loaded_any: bool = False
        for fname in stub_files_to_search:
            stub_path = os.path.join(output_dir, fname)
            try:
                with open(stub_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                for line in content.splitlines():
                    stripped = line.strip()
                    if not stripped.startswith('declare '):
                        continue
                    # 检查是否是目标结构体的方法
                    if f'.{short_name}.' not in stripped:
                        continue
                    try:
                        func_type = self._parse_llvm_declare(stripped, Gen)
                        if func_type is None:
                            continue
                        # 提取函数名：最后一个 @ 到第一个 ( 之间的内容
                        paren_pos: int = stripped.index('(')
                        at_pos: int = stripped.rindex('@', 0, paren_pos)
                        func_name: str = stripped[at_pos + 1:paren_pos].strip().strip('"')
                        if func_name not in Gen.functions:
                            func = ir.Function(Gen.module, func_type, name=func_name)
                            Gen.functions[func_name] = func
                            if '.' in func_name:
                                short_fn = func_name.split('.', 1)[1]
                                Gen.functions[short_fn] = func
                            loaded_any = True
                    except Exception:
                        pass
            except Exception as _e:
                if _config_mode == "strict":
                    raise
                _vlog().warning(f"按需加载 output stub 失败: {_e}", "Exception")
        return loaded_any

    def _parse_llvm_declare(self, declare_line: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None:
        """解析 LLVM declare 语句"""
        match = re.match(r'declare\s+(.+?)\s+@("?[^()]+"?)\s*\((.*)\)$', declare_line)
        if not match:
            return None

        ret_type_str = match.group(1).strip()
        params_str = match.group(3).strip()

        ret_type = self._parse_llvm_type(ret_type_str, Gen)
        if ret_type is None:
            return None
        
        param_types = []
        if params_str and params_str != 'void':
            depth = 0
            current = ''
            for ch in params_str:
                if ch == ',' and depth == 0:
                    p = self._strip_llvm_param_name(current.strip())
                    if p and p != '...':
                        pt = self._parse_llvm_type(p, Gen)
                        if pt is not None:
                            param_types.append(pt)
                    current = ''
                else:
                    if ch == '{':
                        depth += 1
                    elif ch == '}':
                        depth -= 1
                    current += ch
            p = self._strip_llvm_param_name(current.strip())
            if p and p != '...':
                pt = self._parse_llvm_type(p, Gen)
                if pt is not None:
                    param_types.append(pt)
        
        is_variadic = '...' in params_str
        return ir.FunctionType(ret_type, param_types, var_arg=is_variadic)

    def _parse_llvm_type(self, type_str: str, Gen: LlvmGeneratorMixin, source_sha1: str | None = None, create_structs: bool = True) -> ir.Type | None:
        """解析 LLVM 类型字符串"""

        type_str = type_str.strip()

        type_map = {
            'void': ir.VoidType(),
            'i1': ir.IntType(1),
            'i8': ir.IntType(8),
            'i16': ir.IntType(16),
            'i32': ir.IntType(32),
            'i64': ir.IntType(64),
            'float': ir.FloatType(),
            'double': ir.DoubleType(),
        }

        if type_str in type_map:
            return type_map[type_str]

        if type_str.startswith('{') and type_str.endswith('}'):
            inner = type_str[1:-1].strip()
            field_types = []
            depth = 0
            current = ''
            for ch in inner:
                if ch == ',' and depth == 0:
                    field_types.append(current.strip())
                    current = ''
                else:
                    if ch == '{':
                        depth += 1
                    elif ch == '}':
                        depth -= 1
                    current += ch
            if current.strip():
                field_types.append(current.strip())
            llvm_fields = []
            for ft in field_types:
                parsed = self._parse_llvm_type(ft, Gen, source_sha1=source_sha1, create_structs=create_structs)
                if parsed is not None:
                    llvm_fields.append(parsed)
                else:
                    return None
            if llvm_fields:
                return ir.LiteralStructType(llvm_fields)
            return None

        if type_str.endswith('*'):
            pointee = type_str[:-1].strip()
            pointee_type = self._parse_llvm_type(pointee, Gen, source_sha1=source_sha1, create_structs=create_structs)
            if pointee_type is not None:
                return ir.PointerType(pointee_type)
            return ir.PointerType(ir.IntType(8))

        if type_str.startswith('[') and ']' in type_str:
            arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str)
            if arr_match:
                size = int(arr_match.group(1))
                elem_type = self._parse_llvm_type(arr_match.group(2).strip(), Gen, source_sha1=source_sha1, create_structs=create_structs)
                if elem_type is not None:
                    return ir.ArrayType(elem_type, size)

        typedef_names = {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}
        struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]]+)"?', type_str)
        if struct_match:
            raw_name = struct_match.group(1)
            actual_source_sha1 = source_sha1
            if '.' in raw_name:
                parts = raw_name.split('.', 1)
                if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]):
                    actual_source_sha1 = parts[0]
                struct_name = parts[1]
            else:
                struct_name = raw_name
            if struct_name not in typedef_names:
                # 泛型类特化（如 list[str]）：触发特化创建结构体和方法声明
                # 使用 declare_only=True 避免在引用模块中生成方法体（定义由定义模块提供）
                if '[' in struct_name and actual_source_sha1:
                    if struct_name in Gen.structs:
                        return Gen.structs[struct_name]
                    gc_base: str = struct_name.split('[')[0]
                    gc_args_raw: str = struct_name[len(gc_base):]
                    gc_type_args: list[str] = []
                    for gc_arg_part in gc_args_raw.split(']['):
                        gc_arg_part = gc_arg_part.strip('[]')
                        if gc_arg_part:
                            gc_type_args.append(gc_arg_part)
                    if (gc_type_args
                        and hasattr(self.Trans, 'ClassHandler')
                        and hasattr(self.Trans.ClassHandler, '_generic_class_templates')
                        and gc_base in self.Trans.ClassHandler._generic_class_templates):
                        gc_type_names: list[str] = []
                        for gc_ta in gc_type_args:
                            gc_tn: str = gc_ta
                            if gc_ta == 'int':
                                gc_tn = 'CInt'
                            elif gc_ta == 'double':
                                gc_tn = 'CDouble'
                            elif gc_ta == 'float':
                                gc_tn = 'CFloat'
                            elif gc_ta == 'char':
                                gc_tn = 'CChar'
                            elif gc_ta == 'bool':
                                gc_tn = 'CBool'
                            gc_type_names.append(gc_tn)
                        saved_module_sha1: str | None = getattr(Gen, 'module_sha1', None)
                        saved_trans_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
                        Gen.module_sha1 = actual_source_sha1
                        self.Trans._module_sha1 = actual_source_sha1
                        try:
                            gc_spec: str | None = self.Trans.ClassHandler._specialize_generic_class(
                                gc_base, gc_type_args, Gen, type_names=gc_type_names,
                                declare_only=True)
                        except Exception:
                            gc_spec = None
                        Gen.module_sha1 = saved_module_sha1
                        self.Trans._module_sha1 = saved_trans_sha1
                        if gc_spec and gc_spec in Gen.structs:
                            return Gen.structs[gc_spec]
                if create_structs:
                    return Gen._get_or_create_struct(struct_name, source_sha1=actual_source_sha1)
                else:
                    existing = Gen.structs.get(struct_name)
                    if existing is not None:
                        return existing
                    # 尝试用 source_sha1 前缀的全名查找
                    if actual_source_sha1:
                        full_key = f"{actual_source_sha1}.{struct_name}"
                        existing_full = Gen.structs.get(full_key)
                        if existing_full is not None:
                            return existing_full
                    return None
            return ir.IntType(32)

        return None

    def _strip_param_name(self, param_str: str) -> str:
        """从 LLVM 参数字符串中剥离参数名，只保留类型部分
        例如: '%"sha1.struct_name"* %param_name' -> '%"sha1.struct_name"*'
              'i8* %path' -> 'i8*'
              'i32' -> 'i32'
        """
        param_str = param_str.strip()
        stripped = re.sub(r'\s+%[\w.]+\s*$', '', param_str)
        return stripped.strip()
