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 os
import re
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 IsTModule, ExtractTypeNameFromBinOp


class ExprCallHandle(BaseHandle):
    def _append_eh_msg_out_arg(self, CallArgs: list[ir.Value], func: ir.Function | None, Gen: LlvmGeneratorMixin) -> None:
        if not func:
            return
        func_args: list[ir.Type] = func.function_type.args
        n_user_args: int = len(CallArgs)
        has_eh_msg: bool = False
        has_eh_code: bool = False
        if len(func_args) > n_user_args:
            last_type: ir.Type = func_args[-1]
            if (isinstance(last_type, ir.PointerType)
                and isinstance(last_type.pointee, ir.IntType)
                and last_type.pointee.width == 32):
                has_eh_code = True
        if len(func_args) > n_user_args + (1 if has_eh_code else 0):
            check_idx: int = len(func_args) - 1 - (1 if has_eh_code else 0)
            check_type: ir.Type = func_args[check_idx]
            if (isinstance(check_type, ir.PointerType)
                and isinstance(check_type.pointee, ir.PointerType)
                and isinstance(check_type.pointee.pointee, ir.IntType)
                and check_type.pointee.pointee.width == 8):
                has_eh_msg = True
        if not has_eh_msg:
            return
        eh_msg_ptr: ir.Value | None = None
        eh_code_ptr: ir.Value | None = None
        if Gen.eh_except_block_stack:
            _, _, exception_code, eh_message = Gen.eh_except_block_stack[-1]
            if eh_message is not None:
                eh_msg_ptr = eh_message
            if exception_code is not None:
                eh_code_ptr = exception_code
        if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0:
            for arg in Gen.func.args:
                if arg.name == '__eh_msg_out__' and eh_msg_ptr is None:
                    eh_msg_ptr = arg
                elif arg.name == '__eh_code_out__' and eh_code_ptr is None:
                    eh_code_ptr = arg
        if eh_msg_ptr is None:
            eh_msg_ptr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null")
        if eh_code_ptr is None:
            eh_code_ptr = Gen._allocaEntry(ir.IntType(32), name="eh_code_out_null")
        Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_msg_ptr)
        Gen._store(ir.Constant(ir.IntType(32), 0), eh_code_ptr)
        CallArgs.append(eh_msg_ptr)
        if has_eh_code:
            CallArgs.append(eh_code_ptr)

    def _check_eh_return(self, result: ir.Value, func_name: str, Gen: LlvmGeneratorMixin, called_func: ir.Function | None = None) -> ir.Value:
        has_eh_msg_out: bool = False
        has_eh_code_out: bool = False
        if called_func and hasattr(called_func, 'args') and len(called_func.args) > 0:
            for arg in called_func.args:
                if arg.name == '__eh_msg_out__':
                    has_eh_msg_out = True
                elif arg.name == '__eh_code_out__':
                    has_eh_code_out = True
        if not has_eh_msg_out:
            return result
        eh_msg_ptr: ir.Value | None = None
        eh_code_ptr: ir.Value | None = None
        if Gen.eh_except_block_stack:
            _, _, exception_code, eh_message = Gen.eh_except_block_stack[-1]
            if eh_message is not None:
                eh_msg_ptr = eh_message
            if exception_code is not None:
                eh_code_ptr = exception_code
        if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0:
            for arg in Gen.func.args:
                if arg.name == '__eh_msg_out__' and eh_msg_ptr is None:
                    eh_msg_ptr = arg
                elif arg.name == '__eh_code_out__' and eh_code_ptr is None:
                    eh_code_ptr = arg
        if eh_msg_ptr is not None:
            eh_msg_val: ir.Value = Gen._load(eh_msg_ptr, name=f"Load_eh_msg_{func_name}")
            null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None)
            is_error: ir.Value = Gen.builder.icmp_signed('!=', eh_msg_val, null_ptr, name=f"check_eh_msg_{func_name}")
            OkBB: ir.Block = Gen.func.append_basic_block(name=f"ok_after_{func_name}")
            ErrorBB: ir.Block = Gen.func.append_basic_block(name=f"error_after_{func_name}")
            Gen.builder.cbranch(is_error, ErrorBB, OkBB)
            Gen.builder.position_at_start(ErrorBB)
            ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None
            error_ret_val: ir.Constant | None = None
            if isinstance(ret_type, ir.IdentifiedStructType):
                if ret_type.elements:
                    error_ret_val = ir.Constant(ret_type, [
                        ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType))
                        else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType))
                        else ir.Constant(et, ir.Undefined) for et in ret_type.elements])
                else:
                    error_ret_val = ir.Constant(ret_type, None)
            elif isinstance(ret_type, ir.PointerType):
                error_ret_val = ir.Constant(ret_type, None)
            elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)):
                error_ret_val = ir.Constant(ret_type, 0.0)
            elif isinstance(ret_type, ir.IntType):
                error_ret_val = ir.Constant(ret_type, 1)
            elif isinstance(ret_type, ir.VoidType):
                pass
            else:
                error_ret_val = ir.Constant(ir.IntType(32), 1)
            if Gen.eh_except_block_stack:
                ExceptBB, _, exception_code, _ = Gen.eh_except_block_stack[-1]
                if ExceptBB is not None:
                    if has_eh_code_out and eh_code_ptr is not None:
                        eh_code_val = Gen._load(eh_code_ptr, name=f"Load_eh_code_{func_name}")
                        Gen._store(eh_code_val, exception_code)
                    else:
                        Gen._store(ir.Constant(ir.IntType(32), 1), exception_code)
                    Gen.builder.branch(ExceptBB)
                else:
                    if isinstance(ret_type, ir.VoidType):
                        Gen.builder.ret_void()
                    else:
                        Gen.builder.ret(error_ret_val)
            else:
                if isinstance(ret_type, ir.VoidType):
                    Gen.builder.ret_void()
                else:
                    Gen.builder.ret(error_ret_val)
            Gen.builder.position_at_start(OkBB)

    def _fill_default_args(self, CallArgs: list[ir.Value], func: ir.Function | None, func_name: str | None = None) -> None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        global_defaults: dict = self.Trans._global_function_default_args
        func_defaults: list | None = None
        if func_name:
            func_defaults = global_defaults.get(func_name)
        if not func_defaults and func:
            func_defaults = global_defaults.get(func.name)
        if not func_defaults and func_name:
            for gk, gv in global_defaults.items():
                if func_name in gk or gk.endswith(func_name) or gk.endswith('.' + func_name):
                    func_defaults = gv
                    break
        if func and len(CallArgs) < len(func.args):
            total_params: int = len(func.args)
            if func_defaults:
                num_defaults: int = len(func_defaults)
                default_start: int = total_params - num_defaults
            else:
                num_defaults = 0
                default_start = total_params
            while len(CallArgs) < total_params:
                arg_idx: int = len(CallArgs)
                arg = func.args[arg_idx]
                param_type: ir.Type = arg.type if hasattr(arg, 'type') else arg
                if func_defaults and arg_idx >= default_start:
                    def_idx: int = arg_idx - default_start
                    if def_idx < num_defaults and func_defaults[def_idx] is not None:
                        default_val = func_defaults[def_idx]
                        if isinstance(param_type, ir.IntType):
                            max_val: int = (1 << param_type.width) - 1
                            if isinstance(default_val, bool):
                                default_val = 1 if default_val else 0
                            if isinstance(default_val, int) and default_val > max_val:
                                default_val = default_val & max_val
                            if isinstance(default_val, int) and default_val < 0:
                                default_val = default_val & max_val
                            CallArgs.append(ir.Constant(param_type, default_val))
                        elif isinstance(param_type, ir.PointerType):
                            CallArgs.append(ir.Constant(param_type, None))
                        else:
                            try:
                                _zv = Gen._zero_value_for_type(param_type)
                                CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0))
                            except (AssertionError, TypeError):
                                CallArgs.append(ir.Constant(ir.IntType(32), 0))
                    else:
                        if isinstance(param_type, ir.PointerType):
                            CallArgs.append(ir.Constant(param_type, None))
                        elif isinstance(param_type, ir.IntType):
                            CallArgs.append(ir.Constant(param_type, 0))
                        else:
                            try:
                                _zv = Gen._zero_value_for_type(param_type)
                                CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0))
                            except (AssertionError, TypeError):
                                CallArgs.append(ir.Constant(ir.IntType(32), 0))
                else:
                    if isinstance(param_type, ir.PointerType):
                        CallArgs.append(ir.Constant(param_type, None))
                    elif isinstance(param_type, ir.IntType):
                        CallArgs.append(ir.Constant(param_type, 0))
                    else:
                        try:
                            _zv = Gen._zero_value_for_type(param_type)
                            CallArgs.append(_zv if _zv is not None else ir.Constant(ir.IntType(32), 0))
                        except (AssertionError, TypeError):
                            CallArgs.append(ir.Constant(ir.IntType(32), 0))

    def _ApplyKeywordArgs(self, Node: ast.Call, CallArgs: list[ir.Value], func: ir.Function | None, func_name: str | None, self_offset: int = 1) -> None:
        """在 _fill_default_args 之后调用：用 keyword args 按 param_names 覆盖 CallArgs 对应位置。
        self_offset=1 表示 CallArgs[0] 是 self，参数从 CallArgs[1] 开始（__init__/__new__/__call__/method）。
        self_offset=0 表示无 self，参数从 CallArgs[0] 开始（普通函数）。
        """
        if not Node.keywords:
            return
        global_param_names: dict = self.Trans._global_function_param_names
        param_names: list[str] | None = None
        if func_name:
            param_names = global_param_names.get(func_name)
        if not param_names and func is not None:
            param_names = global_param_names.get(func.name)
        if not param_names and func is not None and hasattr(func, 'args'):
            llvm_names: list[str] = [a.name for a in func.args] if func.args else []
            if llvm_names and not all(n.isdigit() for n in llvm_names):
                param_names = llvm_names
        if not param_names:
            # 无法获取参数名，回退：按顺序追加（保持旧行为，避免静默丢弃）
            for kw in Node.keywords:
                if kw.arg is None:
                    continue
                ArgVal = self.HandleExprLlvm(kw.value)
                if ArgVal:
                    CallArgs.append(ArgVal)
            return
        for kw in Node.keywords:
            if kw.arg is None:
                continue
            ArgVal = self.HandleExprLlvm(kw.value)
            if not ArgVal:
                continue
            if kw.arg in param_names:
                idx: int = param_names.index(kw.arg)
                target_idx: int = idx - self_offset
                if 0 <= target_idx < len(CallArgs) - self_offset:
                    CallArgs[self_offset + target_idx] = ArgVal

    def _HandleCallLlvm(self, Node: ast.Call) -> ir.Value:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        FuncAttr: str | None = None
        ModulePath: str | None = None
        if isinstance(Node.func, ast.Name):
            FuncName = Node.func.id
            if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates:
                return self._HandleGenericCallLlvm(Node, FuncName)
            result = self.Trans.ExprBuiltinHandle._HandleBuiltinCallLlvm(Node)
            if result is not None:
                return result
            if Gen._has_function(FuncName):
                return self._HandleClosureCallLlvm(Node, FuncName)
            SymInfo = self.Trans.SymbolTable.lookup(FuncName)
            if SymInfo:
                # 名字冲突处理：类名可能与 CEnum 成员名冲突（如 ASTKind.Name 枚举成员与 Name 类同名）
                # 若该名字同时是类（在 Gen.structs 中或存在 __before_init__），优先作为类构造函数处理
                IsAlsoClass: bool = (FuncName in Gen.structs) or Gen._has_function(f'{FuncName}.__before_init__')
                if SymInfo.IsEnum and not (IsAlsoClass and getattr(SymInfo, 'IsEnumMember', False)):
                    if Node.args:
                        arg_val = self.HandleExprLlvm(Node.args[0])
                        if arg_val:
                            if isinstance(arg_val.type, ir.IntType) and arg_val.type.width != 32:
                                if arg_val.type.width < 32:
                                    arg_val = Gen.builder.zext(arg_val, ir.IntType(32), name="zext_enum_arg")
                                else:
                                    arg_val = Gen.builder.trunc(arg_val, ir.IntType(32), name="trunc_enum_arg")
                            return arg_val
                    return ir.Constant(ir.IntType(32), 0)
                if SymInfo.IsTypedef:
                    return self._HandleTypedefCastLlvm(Node, FuncName)
            NewFuncName = f'{FuncName}.__before_init__'
            InitFuncName = f'{FuncName}.__init__'
            if Gen._has_function(NewFuncName):
                return self._HandleClassNewLlvm(Node, FuncName)
            if Gen._has_function(InitFuncName) and FuncName in Gen.structs:
                return self._HandleClassNewLlvm(Node, FuncName)
            if FuncName in Gen.structs:
                return self._HandleClassNewLlvm(Node, FuncName)
            if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncName in self.Trans.ClassHandler._generic_class_templates:
                return self._HandleClassNewLlvm(Node, FuncName)
            if self.Trans.FunctionDefCache.get(FuncName):
                return self._HandleClosureCallLlvm(Node, FuncName)
            if FuncName in self._C_LIB_FUNCS:
                return self._HandleClosureCallLlvm(Node, FuncName)
            ClassName = Gen.var_struct_class.get(FuncName)
            if ClassName and Gen._has_function(f'{ClassName}.__call__'):
                return self._HandleInstanceCallLlvm(Node, FuncName, ClassName)
            t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
            if FuncName in t_c_imported:
                src_module, src_name = t_c_imported[FuncName]
                virtual_node = self._make_virtual_attr_call(Node, src_module, src_name)
                return self._HandleCallLlvm(virtual_node)
            # 检查是否是全局变量中的函数指针（t.Callable 类型在模块级定义）
            if FuncName not in Gen.variables and FuncName in Gen.global_vars:
                Gen._Load_var(FuncName)
            if FuncName not in Gen.variables and FuncName in Gen.module.globals:
                GVar = Gen.module.globals[FuncName]
                if not isinstance(GVar, ir.Function):
                    StoredType = GVar.type.pointee if isinstance(GVar.type, ir.PointerType) else GVar.type
                    if isinstance(StoredType, ir.PointerType) and isinstance(StoredType.pointee, ir.FunctionType):
                        Gen.variables[FuncName] = GVar
            # 检查是否是闭包变量（lambda 赋值给变量后调用）
            if FuncName in Gen.variables and Gen.variables[FuncName] is not None:
                VarPtr = Gen.variables[FuncName]
                # 检查是否是函数指针变量（t.Callable 类型），直接加载并调用
                if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(VarPtr.type.pointee.pointee, ir.FunctionType):
                    fn_ptr = Gen._load(VarPtr, name=f"Load_fn_{FuncName}")
                    args = []
                    for arg in Node.args:
                        ArgVal = self.HandleExprLlvm(arg)
                        if ArgVal:
                            args.append(ArgVal)
                    return Gen.builder.call(fn_ptr, args, name=f"call_{FuncName}")
                closure_ptr = Gen._load(VarPtr, name=f"Load_closure_{FuncName}")
                if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.FunctionType):
                    fn_ptr = closure_ptr
                    args = []
                    for arg in Node.args:
                        ArgVal = self.HandleExprLlvm(arg)
                        if ArgVal:
                            args.append(ArgVal)
                    return Gen.builder.call(fn_ptr, args, name=f"call_{FuncName}")
                if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.LiteralStructType):
                    st = closure_ptr.type.pointee
                    if len(st.elements) == 2 and isinstance(st.elements[1], ir.PointerType) and isinstance(st.elements[1].pointee, ir.FunctionType):
                        fn_ptr_type = st.elements[1]
                        fn_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name=f"fn_ptr_{FuncName}")
                        fn_val = Gen._load(fn_ptr, name=f"fn_{FuncName}")
                        args = []
                        for arg in Node.args:
                            ArgVal = self.HandleExprLlvm(arg)
                            if ArgVal:
                                args.append(ArgVal)
                        env_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"env_ptr_{FuncName}")
                        env_val = Gen._load(env_ptr, name=f"env_{FuncName}")
                        call_args = [env_val] + args
                        expected_fn_type = fn_ptr_type.pointee
                        if len(call_args) < len(expected_fn_type.args):
                            while len(call_args) < len(expected_fn_type.args):
                                call_args.append(ir.Constant(expected_fn_type.args[len(call_args)], 0))
                        # 如果函数期望的 env 类型与闭包中存储的 i8* 不同，做 bitcast
                        if len(expected_fn_type.args) > 0 and call_args[0].type != expected_fn_type.args[0]:
                            call_args[0] = Gen.builder.bitcast(call_args[0], expected_fn_type.args[0], name=f"cast_env_{FuncName}")
                        return Gen.builder.call(fn_val, call_args, name=f"call_{FuncName}")
            raise Exception(f"Undefined function: '{FuncName}'")
        if isinstance(Node.func, ast.Subscript):
            # Handle list[int](mb) syntax — generic class constructor with explicit type args
            sub: ast.Subscript = Node.func
            if isinstance(sub.value, ast.Name):
                ClassName: str = sub.value.id
                if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates:
                    return self._HandleGenericClassNewLlvm(Node, ClassName, explicit_slice=sub.slice)
        if isinstance(Node.func, ast.Attribute):
            if Node.func.attr in ('update', 'final', 'transform'):
                pass
            if Node.func.attr == '__sizeof__':
                if isinstance(Node.func.value, ast.Subscript):
                    spec_name = self._ResolveGenericSlice(Node.func.value)
                    if spec_name:
                        return self._HandleSizeofLlvm(ast.Name(id=spec_name, ctx=ast.Load()))
                # 对于 BinOp/BitOr 联合类型（如 AST | t.CPtr），
                # sizeof 应返回指针大小 8，而非结构体大小
                # 必须在 HandleExprLlvm 之前检查，避免对类型名求值产生副作用
                if isinstance(Node.func.value, ast.BinOp) and isinstance(Node.func.value.op, ast.BitOr):
                    if self._AnnotationContainsCPtr(Node.func.value):
                        return ir.Constant(ir.IntType(64), 8)
                # 对于 ast.Attribute（如 ast.ClassDef.__sizeof__() / t.CInt.__sizeof__()），
                # 直接调用 _HandleSizeofLlvm，不走 HandleExprLlvm
                # 因为 ast.Attribute 在 sizeof 上下文中一定是类型名，不是变量
                if isinstance(Node.func.value, ast.Attribute):
                    type_name = Node.func.value.attr
                    SizeofNode = ast.Name(id=type_name, ctx=ast.Load())
                    _r = self._HandleSizeofLlvm(SizeofNode)
                    return _r
                # 对于 ast.Name，需要区分变量和类型名：
                # - 如果是已知变量（Gen.variables/_reg_values/_direct_values/self），
                #   走 HandleExprLlvm 路径（如 myvar.__sizeof__()）
                # - 否则视为类型名，直接调用 _HandleSizeofLlvm
                # 这避免了 HandleExprLlvm 对类型名求值产生副作用
                # （如修改 builder 状态、污染 variables 缓存等），
                # 这些副作用会导致泛型特化后 then 块为空
                if isinstance(Node.func.value, ast.Name):
                    nm: str = Node.func.value.id
                    is_variable: bool = (
                        nm == 'self'
                        or nm in Gen.variables
                        or nm in getattr(Gen, '_reg_values', {})
                        or nm in getattr(Gen, '_direct_values', {})
                    )
                    if not is_variable:
                        SizeofNode = ast.Name(id=nm, ctx=ast.Load())
                        _r = self._HandleSizeofLlvm(SizeofNode)
                        return _r
                # 变量/实例的 sizeof: 通过 HandleExprLlvm 获取值
                ObjVal = self.HandleExprLlvm(Node.func.value)
                if ObjVal and isinstance(ObjVal.type, ir.PointerType):
                    pointee = ObjVal.type.pointee
                    if isinstance(pointee, ir.ArrayType):
                        # Calculate element size in bytes
                        elem = pointee.element
                        if isinstance(elem, ir.IntType):
                            elem_size = elem.width // 8
                        elif isinstance(elem, ir.PointerType):
                            elem_size = 8  # 64-bit pointers
                        elif isinstance(elem, (ir.LiteralStructType, ir.IdentifiedStructType)):
                            # Approximate: sum of field sizes
                            elem_size = 0
                            for field in getattr(elem, 'elements', []):
                                if isinstance(field, ir.IntType):
                                    elem_size += field.width // 8
                                elif isinstance(field, ir.PointerType):
                                    elem_size += 8
                                elif isinstance(field, ir.ArrayType):
                                    if isinstance(field.element, ir.IntType):
                                        elem_size += field.count * (field.element.width // 8)
                                    else:
                                        elem_size += field.count * 8
                                else:
                                    elem_size += 8
                        elif isinstance(elem, ir.ArrayType):
                            if isinstance(elem.element, ir.IntType):
                                elem_size = elem.count * (elem.element.width // 8)
                            else:
                                elem_size = elem.count * 8
                        elif isinstance(elem, ir.FloatType):
                            elem_size = 4
                        elif isinstance(elem, ir.DoubleType):
                            elem_size = 8
                        else:
                            elem_size = 8  # fallback
                        return ir.Constant(ir.IntType(64), pointee.count * elem_size)
                    elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
                        # 结构体实例: 直接计算大小
                        self._resolve_opaque_struct_members(pointee, Gen)
                        size = Gen._get_struct_size(pointee)
                        if size > 0:
                            return ir.Constant(ir.IntType(64), size)
                # 回退: 尝试作为类型名处理
                if isinstance(Node.func.value, ast.Name):
                    type_name = Node.func.value.id
                    SizeofNode = ast.Name(id=type_name, ctx=ast.Load())
                    return self._HandleSizeofLlvm(SizeofNode)
            ModulePath = self._get_ModulePath(Node.func.value)
            if ModulePath:
                first_part = ModulePath.split('.')[0]
                resolved_first = self.Trans.SymbolTable.resolve_alias(first_part)
                if resolved_first != first_part:
                    ModulePath = resolved_first + ModulePath[len(first_part):]
            # 统一获取模块 SHA1，用于跨模块类型引用（确保用源模块的 SHA1 而非当前模块）
            # 放在 ModulePath 和 alias 解析之后，供所有 _HandleClassNewLlvm/_ensure_struct_declared 调用点使用
            _ctor_module_sha1: str | None = None
            if ModulePath and ModulePath not in {'t', 'c'}:
                _ctor_sha1_map: dict[str, str] = getattr(Gen, 'ModuleSha1Map', {})
                _ctor_module_sha1 = _ctor_sha1_map.get(ModulePath)
                if not _ctor_module_sha1 and '.' in ModulePath:
                    _ctor_module_sha1 = _ctor_sha1_map.get(ModulePath.split('.')[-1])
            if ModulePath:
                is_instance_var = isinstance(Node.func.value, ast.Name) and (
                    Node.func.value.id in Gen.var_struct_class
                    or Node.func.value.id in Gen.variables
                    or Node.func.value.id in Gen.global_vars
                ) and Node.func.value.id not in Gen.ModuleSha1Map
                is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or self.Trans.SymbolTable.is_struct(Node.func.value.id))
                # 链式方法调用：如 self.__mbuddy__.alloc() 或 trans.ImportsH.HandleImport(child)
                # Node.func.value 是 ast.Attribute，基础是实例变量（如 self/trans）
                _is_chained_instance: bool = False
                if isinstance(Node.func.value, ast.Attribute):
                    _base_node: ast.AST = Node.func.value
                    while isinstance(_base_node, ast.Attribute):
                        _base_node = _base_node.value
                    if isinstance(_base_node, ast.Name):
                        _base_name: str = _base_node.id
                        # 检查基名是否为已知变量（self、局部变量、全局变量、已知 struct 变量）
                        # 且不在 ModuleSha1Map 中（避免把模块名误判为变量）
                        if _base_name == 'self' or (
                            (_base_name in Gen.var_struct_class
                             or _base_name in Gen.variables
                             or _base_name in Gen.global_vars)
                            and _base_name not in Gen.ModuleSha1Map
                        ):
                            _is_chained_instance = True
                if (is_instance_var or _is_chained_instance) and not is_class_name:
                    return self._HandleMethodCallLlvm(Node)
                FuncAttr = Node.func.attr
                if FuncAttr in Gen.structs:
                    result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
                    if result is not None:
                        return result
                if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncAttr in self.Trans.ClassHandler._generic_class_templates:
                    return self._HandleGenericClassNewLlvm(Node, FuncAttr)
                # 跨模块 REnum 变体构造：ClassName.Variant(args)
                # 直接检查 Node.func.value 是否是 REnum 类名（不依赖变体短名注册）
                if isinstance(Node.func.value, ast.Name):
                    RenumClassName: str = Node.func.value.id
                    if self.Trans.SymbolTable.has(RenumClassName):
                        RenumInfo = self.Trans.SymbolTable[RenumClassName]
                        if RenumInfo.IsRenum and hasattr(RenumInfo, 'RenumVariants') and RenumInfo.RenumVariants:
                            if FuncAttr in RenumInfo.RenumVariants:
                                TagValue: int = RenumInfo.RenumVariants.index(FuncAttr)
                                result = self._HandleREnumConstructLlvm(Node, RenumClassName, FuncAttr, TagValue)
                                if result is not None:
                                    return result
                if self.Trans.SymbolTable.has(FuncAttr):
                    SymInfo = self.Trans.SymbolTable[FuncAttr]
                    if SymInfo.IsStruct:
                        if FuncAttr not in Gen.structs:
                            self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
                        if FuncAttr in Gen.structs:
                            result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
                            if result is not None:
                                return result
                    if SymInfo.IsEnumMember and SymInfo.EnumName:
                        # When called as module.func(args), check if module.func is a
                        # function/variable first. If so, skip REnum construction and
                        # let the function call path handle it. This fixes cases where
                        # a factory function shares a name with an REnum variant
                        # (e.g., llvmlite.Ptr vs LLVMType.Ptr).
                        _SkipRenum: bool = False
                        if ModulePath:
                            _FullKey = f"{ModulePath}.{FuncAttr}"
                            _FullSym = self.Trans.SymbolTable.lookup(_FullKey)
                            if _FullSym and (_FullSym.IsFunction or _FullSym.IsVariable):
                                _SkipRenum = True
                        if not _SkipRenum:
                            EnumName = SymInfo.EnumName
                            if self.Trans.SymbolTable.has(EnumName):
                                EnumInfo = self.Trans.SymbolTable[EnumName]
                                if EnumInfo.IsRenum:
                                    result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
                                    if result is not None:
                                        return result
                FullAttrKey = f"{ModulePath}.{FuncAttr}"
                if self.Trans.SymbolTable.has(FullAttrKey):
                    SymInfo = self.Trans.SymbolTable[FullAttrKey]
                    if SymInfo.IsStruct:
                        if FuncAttr not in Gen.structs:
                            self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
                        if FuncAttr in Gen.structs:
                            result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
                            if result is not None:
                                return result
                    # 跨模块 REnum 变体构造：FullName 查找（如 LLVMType.Int）
                    if SymInfo.IsEnumMember and SymInfo.EnumName:
                        EnumName = SymInfo.EnumName
                        if self.Trans.SymbolTable.has(EnumName):
                            EnumInfo = self.Trans.SymbolTable[EnumName]
                            if EnumInfo.IsRenum:
                                result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
                                if result is not None:
                                    return result
                if is_class_name:
                    ClassName = Node.func.value.id
                    result = self._HandleStaticMethodCallLlvm(Node, ClassName, FuncAttr)
                    if result is not None:
                        return result
                FullAttrKey = f"{ModulePath}.{FuncAttr}"
                if self.Trans.SymbolTable.has(FullAttrKey):
                    SymInfo = self.Trans.SymbolTable[FullAttrKey]
                    if SymInfo.IsTypedef:
                        return ir.Constant(ir.IntType(32), 0)
                    if SymInfo.IsStruct:
                        if FuncAttr not in Gen.structs:
                            self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
                        if FuncAttr in Gen.structs:
                            result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
                            if result is not None:
                                return result
                if FuncAttr in Gen.structs:
                    result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
                    if result is not None:
                        return result
                if ModulePath == 'c':
                    if FuncAttr == 'Asm':
                        return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
                    elif FuncAttr == 'Addr':
                        return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
                    elif FuncAttr == 'Set':
                        return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
                    elif FuncAttr == 'Load':
                        return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
                    elif FuncAttr == 'Deref':
                        return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
                    elif FuncAttr == 'DerefAs':
                        return self._HandleCDerefAsLlvm(Node)
                    elif FuncAttr == 'PtrToInt':
                        return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
                    elif FuncAttr in ('CIf', 'CElif'):
                        return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node)
                    elif FuncAttr == 'CError':
                        msg = "compile-time error"
                        if Node.args:
                            arg = Node.args[0]
                            if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
                                msg = arg.value
                        lineno = getattr(Node, 'lineno', 0)
                        raise Exception(f"#error: {msg} (line {lineno})")
                    elif FuncAttr in ('AsmInp', 'AsmOut'):
                        return ir.Constant(ir.IntType(32), 0)
                    elif FuncAttr == 'LLVMIR':
                        return self._HandleLLVMIRLlvm(Node)
                    elif FuncAttr in ('LInp', 'LOut'):
                        return ir.Constant(ir.IntType(32), 0)
                if ModulePath == 't':
                    MethodResult_t = self._HandleMethodCallLlvm(Node)
                    if MethodResult_t is not None:
                        return MethodResult_t
                    raise Exception(f"Undefined method: 't.{FuncAttr}'")
                if isinstance(Node.func.value, ast.Attribute):
                    inner_attr = Node.func.value.attr
                    if inner_attr in Gen.structs or self.Trans.SymbolTable.is_struct(inner_attr):
                        static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr)
                        if static_result is not None:
                            return static_result
                    MethodResult_attr = self._HandleMethodCallLlvm(Node)
                    is_zero_attr = isinstance(MethodResult_attr, ir.Constant) and isinstance(MethodResult_attr.type, ir.IntType) and MethodResult_attr.constant == 0
                    if MethodResult_attr is not None and not is_zero_attr:
                        return MethodResult_attr
                result = self._HandleExternalCallLlvm(Node, FuncAttr, ModulePath)
                if result is not None:
                    return result
            MethodResult = self._HandleMethodCallLlvm(Node)
            IsZeroResult = isinstance(MethodResult, ir.Constant) and isinstance(MethodResult.type, ir.IntType) and MethodResult.constant == 0
            if IsZeroResult and FuncAttr is not None:
                mangled_name = Gen._mangle_func_name(FuncAttr, ModulePath if ModulePath and ModulePath != 't' else None)
                if Gen._has_function(mangled_name):
                    CallArgs = []
                    for arg in Node.args:
                        ArgVal = self.HandleExprLlvm(arg)
                        if ArgVal:
                            CallArgs.append(ArgVal)
                    return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{FuncAttr}")
            if MethodResult is None or IsZeroResult:
                imported = getattr(self.Trans, '_ImportedModules', set())
                ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
                IsKnown = (ModulePath in imported or ModulePath in self.Trans.SymbolTable.import_aliases or
                            ModulePath in ModuleSha1Map)
                if not IsKnown and ModulePath and '.' in ModulePath:
                    LastPart = ModulePath.split('.')[-1]
                    IsKnown = (LastPart in imported or LastPart in self.Trans.SymbolTable.import_aliases or
                                LastPart in ModuleSha1Map)
                # 最后尝试: 用 FuncAttr 直接查找 Gen.functions（_find_function 会遍历 SHA1 前缀）
                if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}:
                    # _ctor_module_sha1 已在函数顶部统一获取，此处无需重复
                    # 先检查 FuncAttr 是否是函数/变量，如果是则跳过 struct 声明
                    _attr_sym = self.Trans.SymbolTable.lookup(FuncAttr)
                    _is_func_or_var = _attr_sym and (_attr_sym.IsFunction or _attr_sym.IsVariable)
                    if not _is_func_or_var and ModulePath:
                        _full_key = f"{ModulePath}.{FuncAttr}"
                        _full_sym = self.Trans.SymbolTable.lookup(_full_key)
                        if _full_sym and (_full_sym.IsFunction or _full_sym.IsVariable):
                            _is_func_or_var = True
                    # 优先检查 FuncAttr 是否为 struct/类构造器
                    if not _is_func_or_var and FuncAttr not in Gen.structs:
                        self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
                    if not _is_func_or_var and FuncAttr in Gen.structs:
                        result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
                        if result is not None:
                            return result
                    # 检查 FullAttrKey 是否为 struct（如 hashlib.md5）
                    if ModulePath:
                        FullAttrKey = f"{ModulePath}.{FuncAttr}"
                        if self.Trans.SymbolTable.has(FullAttrKey):
                            FullSymInfo = self.Trans.SymbolTable[FullAttrKey]
                            if FullSymInfo.IsStruct or FullSymInfo.IsCpythonObject:
                                if FuncAttr not in Gen.structs:
                                    self._ensure_struct_declared(FuncAttr, module_sha1=_ctor_module_sha1)
                                if FuncAttr in Gen.structs:
                                    result = self._HandleClassNewLlvm(Node, FuncAttr, module_sha1=_ctor_module_sha1)
                                    if result is not None:
                                        return result
                    fallback_func = Gen._find_function(FuncAttr)
                    if fallback_func is not None:
                        CallArgs = []
                        for arg in Node.args:
                            ArgVal = self.HandleExprLlvm(arg)
                            if ArgVal:
                                CallArgs.append(ArgVal)
                        self._append_eh_msg_out_arg(CallArgs, fallback_func, Gen)
                        result = Gen.builder.call(fallback_func, CallArgs, name=f"call_{FuncAttr}")
                        return self._check_eh_return(result, FuncAttr, Gen, called_func=fallback_func)
                    # 尝试从 stub 按需加载函数声明
                    if ModulePath in ModuleSha1Map:
                        sha1 = ModuleSha1Map[ModulePath]
                        stub_mangled = f"{sha1}.{FuncAttr}"
                        try:
                            stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(stub_mangled, Gen)
                        except Exception:
                            stub_func_type = None
                        if not stub_func_type:
                            try:
                                stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FuncAttr, Gen)
                            except Exception:
                                stub_func_type = None
                        if stub_func_type:
                            decl_name = stub_mangled if stub_mangled in getattr(self.Trans.ImportHandler, '_stub_func_cache', {}) else FuncAttr
                            func_decl = self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=FuncAttr)
                            CallArgs = []
                            for arg in Node.args:
                                ArgVal = self.HandleExprLlvm(arg)
                                if ArgVal:
                                    CallArgs.append(ArgVal)
                            self._append_eh_msg_out_arg(CallArgs, func_decl, Gen)
                            result = Gen.builder.call(func_decl, CallArgs, name=f"call_{FuncAttr}")
                            return self._check_eh_return(result, FuncAttr, Gen, called_func=func_decl)
                if ModulePath and IsKnown:
                    raise Exception(f"Undefined symbol: '{ModulePath}.{FuncAttr}'")
                if ModulePath and ModulePath not in {'t', 'c'} and not IsKnown:
                    raise Exception(f"Unknown module: '{ModulePath}' (undefined symbol: '{ModulePath}.{FuncAttr}')")
                if not ModulePath and FuncAttr:
                    raise Exception(f"Undefined method: '{FuncAttr}'")
            return MethodResult if MethodResult is not None else ir.Constant(ir.IntType(32), 0)
        if isinstance(Node.func, ast.BinOp) and isinstance(Node.func.op, ast.BitOr):
            return self._HandleTypeUnionCastLlvm(Node)
        raise Exception(f"Unsupported call expression")

    def _ensure_struct_declared(self, class_name: str, module_sha1: str | None = None) -> None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        # 如果名称是函数或变量，不应创建 struct
        SymInfo = self.Trans.SymbolTable.lookup(class_name)
        if SymInfo and (SymInfo.IsFunction or SymInfo.IsVariable):
            return
        # 跨模块类型引用：如果提供了 module_sha1，优先检查带 SHA1 前缀的完整名
        full_key: str | None = f"{module_sha1}.{class_name}" if module_sha1 else None
        if full_key and full_key in Gen.structs:
            existing = Gen.structs[full_key]
            if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0):
                self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
            return
        if class_name in Gen.structs:
            existing = Gen.structs[class_name]
            if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0):
                self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
                existing = Gen.structs.get(class_name, existing)
                if isinstance(existing, ir.IdentifiedStructType) and existing.elements is not None and len(existing.elements) > 0:
                    return
            else:
                # 短名已存在但 SHA1 可能不匹配：如果 module_sha1 与现有 struct 的 SHA1 不一致，
                # 需要用正确的 SHA1 创建独立 struct
                if module_sha1:
                    _existing_sha1: str = Gen._extract_struct_sha1(existing)
                    if _existing_sha1 and _existing_sha1 != module_sha1:
                        # SHA1 不匹配，用正确的 SHA1 创建
                        correct_st = Gen._get_or_create_struct(class_name, source_sha1=module_sha1)
                        self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
                return
        SymInfo = self.Trans.SymbolTable.lookup(class_name)
        if SymInfo and SymInfo.Members:
            member_types = []
            if isinstance(SymInfo.Members, dict):
                for member_name, member_info in SymInfo.Members.items():
                    if isinstance(member_info, CTypeInfo):
                        mt = member_info.ToLLVM(Gen)
                    elif isinstance(member_info, str):
                        mt = Gen._CType2LLVM(member_info, '*' in member_info)
                    else:
                        mt = Gen._CType2LLVM(str(member_info) if member_info else 'int', False)
                    if isinstance(mt, ir.VoidType):
                        mt = ir.IntType(8)
                    member_types.append(mt)
            else:
                for item in SymInfo.Members:
                    if isinstance(item, (list, tuple)) and len(item) == 2:
                        member_name, member_type_str = item
                        mt = Gen._CType2LLVM(member_type_str, '*' in member_type_str)
                        if isinstance(mt, ir.VoidType):
                            mt = ir.IntType(8)
                        member_types.append(mt)
            if member_types:
                st = Gen._get_or_create_struct(class_name, source_sha1=module_sha1)
                if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0):
                    st.set_body(*member_types)
            else:
                Gen._get_or_create_struct(class_name, source_sha1=module_sha1)
        else:
            if class_name not in Gen.structs and not (full_key and full_key in Gen.structs):
                self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen, source_sha1=module_sha1)
            Gen._get_or_create_struct(class_name, source_sha1=module_sha1)

    def _HandleStaticMethodCallLlvm(self, Node: ast.Call, ClassName: str, MethodName: str) -> ir.Value | None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
        class_sha1 = struct_sha1_map.get(ClassName)
        if class_sha1:
            MangledName = f'{class_sha1}.{ClassName}.{MethodName}'
        else:
            MangledName = f'{ClassName}.{MethodName}'
        func = Gen._find_function(MangledName)
        if not func:
            func = Gen._find_function(f'{MangledName}__')
        if not func:
            stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MangledName, Gen)
            if stub_func_type:
                func = self.GetOrCreateStubFuncDecl(MangledName, stub_func_type, Gen)
        if not func and class_sha1:
            plain_name = f'{ClassName}.{MethodName}'
            stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen)
            if stub_func_type:
                func = self.GetOrCreateStubFuncDecl(MangledName, stub_func_type, Gen)
        if not func:
            if ClassName not in Gen.structs:
                self._ensure_struct_declared(ClassName)
            SymInfo = self.LookupFunctionSymbol(MethodName, module_path=ClassName)
            if SymInfo and SymInfo.IsFunction:
                sig = self.BuildLLVMFuncTypeFromSig(SymInfo, Gen)
                if sig is not None:
                    ret_type, llvm_param_types, _ = sig
                    is_static = FuncMeta.STATIC_METHOD in SymInfo.MetaList
                    if ClassName in Gen.structs and not is_static:
                        llvm_param_types.insert(0, ir.PointerType(Gen.structs[ClassName]))
                    func_type = ir.FunctionType(ret_type, llvm_param_types)
                    func = ir.Function(Gen.module, func_type, name=MangledName)
                    Gen.functions[MangledName] = func
        if not func:
            p = Gen.class_parent.get(ClassName)
            while p:
                parent_mangled = Gen._mangle_name(f'{p}.{MethodName}')
                parent_func = Gen.functions.get(parent_mangled)
                if parent_func:
                    func = parent_func
                    break
                parent_func = Gen._find_function(f'{p}.{MethodName}')
                if parent_func:
                    func = parent_func
                    break
                p = Gen.class_parent.get(p)
        if not func:
            return None
        CallArgs = []
        SymInfo = self.LookupFunctionSymbol(MethodName, module_path=ClassName)
        is_static_call = SymInfo is not None and FuncMeta.STATIC_METHOD in SymInfo.MetaList
        is_classmethod_call = SymInfo is not None and FuncMeta.CLASS_METHOD in SymInfo.MetaList
        # @classmethod: 在参数列表前插入 cls（栈上分配的类实例指针）
        if is_classmethod_call and ClassName in Gen.structs:
            ClsPtr = Gen._alloca(Gen.structs[ClassName], name=f"cls_{ClassName}")
            CallArgs.append(ClsPtr)
        for arg in Node.args:
            ArgVal = self.HandleExprLlvm(arg)
            if ArgVal:
                CallArgs.append(ArgVal)
        if (ClassName not in Gen.class_vtable
                and ClassName not in Gen._cross_module_vtable_classes
                and class_sha1):
            self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)
        if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call:
            methods = Gen.class_methods[ClassName]
            if class_sha1:
                FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}'
            else:
                FullMethodName = f'{ClassName}.{MethodName}'
            method_idx = -1
            for mi, mn in enumerate(methods):
                if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'):
                    method_idx = mi
                    break
            if method_idx >= 0:
                ObjVal = CallArgs[0]
                if self._is_char_pointer(ObjVal):
                    if ClassName in Gen.structs:
                        ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_static")
                        CallArgs[0] = ObjVal
                VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}_static")
                VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_static")
                VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
                VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}_static")
                MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}_static")
                MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}_static")
                FuncPtrType = ir.PointerType(func.function_type)
                MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}_static")
                self._fill_default_args(CallArgs, func, FullMethodName)
                self._append_eh_msg_out_arg(CallArgs, func, Gen)
                adjusted = Gen._adjust_args(CallArgs, func)
                result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}")
                self._check_eh_return(result, FullMethodName, Gen, called_func=func)
                return result
        self._append_eh_msg_out_arg(CallArgs, func, Gen)
        CallArgs = Gen._apply_auto_addr(MangledName, CallArgs)
        adjusted = Gen._adjust_args(CallArgs, func)
        result = Gen.builder.call(func, adjusted, name=f"call_{MangledName}")
        self._check_eh_return(result, MangledName, Gen, called_func=func)
        return result

    def _HandleInstanceCallLlvm(self, Node: ast.Call, VarName: str, ClassName: str) -> ir.Value:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        ObjVal = self.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load()))
        if not ObjVal:
            raise Exception(f"Cannot evaluate object '{VarName}' for __call__")
        if self._is_char_pointer(ObjVal):
            if ClassName in Gen.structs:
                ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
        CallArgs = [ObjVal]
        for arg in Node.args:
            ArgVal = self.HandleExprLlvm(arg)
            if ArgVal:
                CallArgs.append(ArgVal)
        CallFuncName = f'{ClassName}.__call__'
        struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
        class_sha1 = struct_sha1_map.get(ClassName)
        if class_sha1:
            CallFuncName = f'{class_sha1}.{ClassName}.__call__'
        if not Gen._has_function(CallFuncName):
            raise Exception(f"Class '{ClassName}' has no __call__ method")
        func = Gen._get_function(CallFuncName)
        self._fill_default_args(CallArgs, func, CallFuncName)
        self._ApplyKeywordArgs(Node, CallArgs, func, CallFuncName, self_offset=1)
        self._append_eh_msg_out_arg(CallArgs, func, Gen)
        adjusted = Gen._adjust_args(CallArgs, func)
        result = Gen.builder.call(func, adjusted, name=f"call_{CallFuncName}")
        self._check_eh_return(result, CallFuncName, Gen, called_func=func)
        return result

    def _make_virtual_attr_call(self, Node: ast.Call, module_name: str, attr_name: str) -> ast.Call:
        virtual_func = ast.Attribute(
            value=ast.Name(id=module_name, ctx=ast.Load()),
            attr=attr_name,
            ctx=ast.Load()
        )
        new_node = ast.Call(
            func=virtual_func,
            args=Node.args,
            keywords=Node.keywords
        )
        ast.copy_location(new_node, Node)
        return new_node

    def _get_ModulePath(self, node: ast.AST) -> str | None:
        parts = []
        while isinstance(node, ast.Attribute):
            parts.append(node.attr)
            node = node.value
        if isinstance(node, ast.Name):
            parts.append(node.id)
        parts.reverse()
        return '.'.join(parts) if parts else None

    def _HandleLLVMIRLlvm(self, Node: ast.Call) -> ir.Value:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        if not Node.args:
            return ir.Constant(ir.IntType(32), 0)

        all_ops = []
        input_ops = []
        output_targets = []
        operand_seq = 0

        ret_type = ir.IntType(32)
        if len(Node.args) >= 2:
            ret_type_arg = Node.args[1]
            inferred = self.Trans.ExprAsmHandle._infer_expr_llvm_type(ret_type_arg)
            if inferred:
                ret_type = inferred

        ir_template = ""
        first_arg = Node.args[0]

        if isinstance(first_arg, ast.JoinedStr):
            parts = []
            for value in first_arg.values:
                if isinstance(value, ast.Constant) and isinstance(value.value, str):
                    parts.append(value.value)
                elif isinstance(value, ast.FormattedValue):
                    expr = value.value
                    if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute):
                        if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c':
                            if expr.func.attr == 'LInp':
                                if expr.args:
                                    val = self.HandleExprLlvm(expr.args[0])
                                    if val:
                                        input_ops.append(val)
                                        all_ops.append(('inp', len(input_ops) - 1))
                                        parts.append(f'%__OP{operand_seq}__')
                                        operand_seq += 1
                            elif expr.func.attr == 'LOut':
                                if expr.args:
                                    target_ptr = self.Trans.ExprAsmHandle._get_var_ptr_for_asm(expr.args[0])
                                    if target_ptr:
                                        val = target_ptr
                                    else:
                                        val = self.HandleExprLlvm(expr.args[0])
                                    if val:
                                        output_targets.append(val)
                                        all_ops.append(('out', len(output_targets) - 1))
                                        parts.append(f'%__OP{operand_seq}__')
                                        operand_seq += 1
                        else:
                            fallback = self.HandleExprLlvm(expr)
                            if fallback:
                                input_ops.append(fallback)
                                all_ops.append(('inp', len(input_ops) - 1))
                                parts.append(f'%__OP{operand_seq}__')
                                operand_seq += 1
                    else:
                        fallback = self.HandleExprLlvm(expr)
                        if fallback:
                            input_ops.append(fallback)
                            all_ops.append(('inp', len(input_ops) - 1))
                            parts.append(f'%__OP{operand_seq}__')
                            operand_seq += 1
            ir_template = ''.join(parts)
        elif isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
            ir_template = first_arg.value

        return self._EmitLLVMIRInstruction(Gen, ir_template, input_ops, output_targets, all_ops, ret_type)

    def _EmitLLVMIRInstruction(self, Gen: LlvmGeneratorMixin, ir_template: str, input_ops: list[ir.Value], output_targets: list[ir.Value], all_ops: list[tuple], ret_type: ir.Type) -> ir.Value:
        template = ir_template.strip()

        def resolve_op(idx):
            if idx < len(all_ops):
                kind, local_idx = all_ops[idx]
                if kind == 'inp' and local_idx < len(input_ops):
                    return input_ops[local_idx]
                elif kind == 'out' and local_idx < len(output_targets):
                    return output_targets[local_idx]
            return None

        assign_match = re.match(r'%__OP(\d+)__\s*=\s*(.+)', template)
        if assign_match:
            template = assign_match.group(2).strip()

        binop_map = {
            'add': 'add', 'fadd': 'fadd', 'sub': 'sub', 'fsub': 'fsub',
            'mul': 'mul', 'fmul': 'fmul', 'udiv': 'udiv', 'sdiv': 'sdiv',
            'fdiv': 'fdiv', 'urem': 'urem', 'srem': 'srem', 'frem': 'frem',
            'shl': 'shl', 'lshr': 'lshr', 'ashr': 'ashr',
            'and': 'and_', 'or': 'or_', 'xor': 'xor_',
        }

        icmp_match = re.match(r'icmp\s+(\w+)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template)
        if icmp_match:
            pred = icmp_match.group(1)
            op1 = resolve_op(int(icmp_match.group(3)))
            op2 = resolve_op(int(icmp_match.group(4)))
            if op1 and op2:
                result = Gen.builder.icmp_signed(pred, op1, op2, name="llvmir_result")
                return self._StoreLLVMIROutputs(Gen, result, output_targets)

        fcmp_match = re.match(r'fcmp\s+(\w+(?:\s+fast)?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template)
        if fcmp_match:
            pred = fcmp_match.group(1)
            op1 = resolve_op(int(fcmp_match.group(3)))
            op2 = resolve_op(int(fcmp_match.group(4)))
            if op1 and op2:
                result = Gen.builder.fcmp_ordered(pred, op1, op2, name="llvmir_result")
                return self._StoreLLVMIROutputs(Gen, result, output_targets)

        for op_name, method_name in binop_map.items():
            pattern = re.compile(
                rf'{op_name}\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__',
                re.IGNORECASE if op_name in ('and', 'or', 'xor') else 0
            )
            m = pattern.match(template)
            if m:
                op1 = resolve_op(int(m.group(2)))
                op2 = resolve_op(int(m.group(3)))
                if op1 and op2:
                    method = getattr(Gen.builder, method_name, None)
                    if method:
                        result = method(op1, op2, name="llvmir_result")
                        return self._StoreLLVMIROutputs(Gen, result, output_targets)

        select_match = re.match(r'select\s+i1\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template)
        if select_match:
            cond = resolve_op(int(select_match.group(1)))
            true_val = resolve_op(int(select_match.group(3)))
            false_val = resolve_op(int(select_match.group(5)))
            if cond and true_val and false_val:
                result = Gen.builder.select(cond, true_val, false_val, name="llvmir_result")
                return self._StoreLLVMIROutputs(Gen, result, output_targets)

        cast_map = {
            'zext': 'zext', 'sext': 'sext', 'trunc': 'trunc',
            'bitcast': 'bitcast', 'inttoptr': 'inttoptr', 'ptrtoint': 'ptrtoint',
            'uitofp': 'uitofp', 'sitofp': 'sitofp', 'fptoui': 'fptoui', 'fptosi': 'fptosi',
            'fpext': 'fpext', 'fptrunc': 'fptrunc',
        }
        for op_name, method_name in cast_map.items():
            pattern = re.compile(rf'{op_name}\s+(\w+)\s+%__OP(\d+)__\s+to\s+(\w+)')
            m = pattern.match(template)
            if m:
                src_val = resolve_op(int(m.group(2)))
                dest_type_str = m.group(3)
                dest_type = self._ParseLLVMType(Gen, dest_type_str)
                if src_val and dest_type:
                    method = getattr(Gen.builder, method_name, None)
                    if method:
                        result = method(src_val, dest_type, name="llvmir_result")
                        return self._StoreLLVMIROutputs(Gen, result, output_targets)

        Load_match = re.match(r'Load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template)
        if Load_match:
            ptr_val = resolve_op(int(Load_match.group(3)))
            if ptr_val:
                result = Gen.builder.load(ptr_val, name="llvmir_result")
                return self._StoreLLVMIROutputs(Gen, result, output_targets)

        store_match = re.match(r'store\s+(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template)
        if store_match:
            val = resolve_op(int(store_match.group(2)))
            ptr = resolve_op(int(store_match.group(4)))
            if val and ptr:
                Gen.builder.store(val, ptr)
                return ir.Constant(ir.IntType(32), 0)

        gep_match = re.match(r'getelementptr\s+(?:inbounds\s+)?(\w+),\s*(\w+)\s+%__OP(\d+)__,\s*(.+)', template)
        if gep_match:
            ptr_val = resolve_op(int(gep_match.group(3)))
            indices_str = gep_match.group(4)
            if ptr_val:
                indices = []
                for idx_part in re.split(r',\s*', indices_str):
                    idx_part = idx_part.strip()
                    idx_m = re.match(r'%__OP(\d+)__', idx_part)
                    if idx_m:
                        idx_op = resolve_op(int(idx_m.group(1)))
                        if idx_op:
                            indices.append(idx_op)
                    else:
                        try:
                            indices.append(ir.Constant(ir.IntType(32), int(idx_part)))
                        except ValueError:
                            break
                if indices:
                    result = Gen.builder.gep(ptr_val, indices, name="llvmir_result")
                    return self._StoreLLVMIROutputs(Gen, result, output_targets)

        neg_match = re.match(r'sub\s+(\w+)\s+(\d+),\s*%__OP(\d+)__', template)
        if neg_match:
            op = resolve_op(int(neg_match.group(3)))
            if op:
                zero = ir.Constant(op.type, int(neg_match.group(2)))
                result = Gen.builder.sub(zero, op, name="llvmir_result")
                return self._StoreLLVMIROutputs(Gen, result, output_targets)

        not_match = re.match(r'xor\s+(\w+)\s+(-1|\d+),\s*%__OP(\d+)__', template)
        if not_match:
            op = resolve_op(int(not_match.group(3)))
            if op:
                mask = ir.Constant(op.type, int(not_match.group(2)))
                result = Gen.builder.xor_(op, mask, name="llvmir_result")
                return self._StoreLLVMIROutputs(Gen, result, output_targets)

        call_match = re.match(r'call\s+(\w+)\s+@([\w.]+)\((.+)\)', template)
        if call_match:
            call_ret_str = call_match.group(1)
            func_name = call_match.group(2)
            args_str = call_match.group(3)
            call_args = []
            for arg_part in re.split(r',\s*', args_str):
                arg_part = arg_part.strip()
                typed_op = re.match(r'(\w+\*?)\s+%__OP(\d+)__', arg_part)
                if typed_op:
                    expected_type_str = typed_op.group(1)
                    op_idx = int(typed_op.group(2))
                    val = resolve_op(op_idx)
                    if val:
                        val = self._ConvertLLVMIRType(Gen, val, expected_type_str)
                        if val:
                            call_args.append(val)
                else:
                    const_m = re.match(r'(\w+)\s+(-?\d+)', arg_part)
                    if const_m:
                        const_type = self._ParseLLVMType(Gen, const_m.group(1))
                        if const_type:
                            call_args.append(ir.Constant(const_type, int(const_m.group(2))))
            if call_args:
                call_ret_type = self._ParseLLVMType(Gen, call_ret_str) or ir.VoidType()
                func_type = ir.FunctionType(call_ret_type, [a.type for a in call_args])
                if func_name.startswith('llvm.'):
                    existing = Gen.module.globals.get(func_name)
                    if existing:
                        func = existing
                    else:
                        try:
                            func = Gen.module.declare_intrinsic(func_name, [a.type for a in call_args])
                        except Exception:
                            func = ir.Function(Gen.module, func_type, name=func_name)
                else:
                    existing = Gen.module.globals.get(func_name)
                    if existing:
                        func = existing
                    else:
                        func = ir.Function(Gen.module, func_type, name=func_name)
                result = Gen.builder.call(func, call_args, name="llvmir_result")
                if output_targets:
                    return self._StoreLLVMIROutputs(Gen, result, output_targets)
                if isinstance(call_ret_type, ir.VoidType):
                    return ir.Constant(ir.IntType(32), 0)
                return result

        if output_targets:
            for i, target in enumerate(output_targets):
                if isinstance(target, ir.AllocaInstr):
                    Gen.builder.store(ir.Constant(target.type.pointee, 0), target)
            return ir.Constant(ir.IntType(32), 0)

        return ir.Constant(ret_type, 0)

    def _StoreLLVMIROutputs(self, Gen: LlvmGeneratorMixin, result: ir.Value, output_targets: list[ir.Value]) -> ir.Value:
        for target in output_targets:
            if isinstance(target, ir.AllocaInstr):
                if target.type.pointee == result.type:
                    Gen.builder.store(result, target)
                else:
                    i64t = ir.IntType(64)
                    if isinstance(result.type, ir.IntType) and result.type.width == 64 and isinstance(target.type.pointee, ir.PointerType):
                        ptr_val = Gen.builder.inttoptr(result, target.type.pointee)
                        Gen.builder.store(ptr_val, target)
                    elif isinstance(result.type, ir.PointerType) and isinstance(target.type.pointee, ir.IntType) and target.type.pointee.width == 64:
                        int_val = Gen.builder.ptrtoint(result, i64t)
                        Gen.builder.store(int_val, target)
                    else:
                        try:
                            cast_val = Gen.builder.bitcast(result, target.type.pointee)
                            Gen.builder.store(cast_val, target)
                        except Exception:
                            Gen.builder.store(result, target)
            elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr)):
                if isinstance(target.type, ir.PointerType):
                    if target.type.pointee == result.type:
                        Gen.builder.store(result, target)
                    else:
                        try:
                            cast_val = Gen.builder.bitcast(result, target.type.pointee)
                            Gen.builder.store(cast_val, target)
                        except Exception:
                            Gen.builder.store(result, target)
        return result

    def _ParseLLVMType(self, Gen: LlvmGeneratorMixin, type_str: str) -> ir.Type | None:
        type_map = {
            'i1': ir.IntType(1), 'i8': ir.IntType(8), 'i16': ir.IntType(16),
            'i32': ir.IntType(32), 'i64': ir.IntType(64), 'i128': ir.IntType(128),
            'float': ir.FloatType(), 'double': ir.DoubleType(),
            'void': ir.VoidType(),
        }
        if type_str in type_map:
            return type_map[type_str]
        if type_str.endswith('*'):
            pointee = self._ParseLLVMType(Gen, type_str[:-1])
            if pointee:
                return ir.PointerType(pointee)
        return None

    def _ConvertLLVMIRType(self, Gen: LlvmGeneratorMixin, val: ir.Value, expected_type_str: str) -> ir.Value | None:
        expected_type = self._ParseLLVMType(Gen, expected_type_str.rstrip('*'))
        if not expected_type:
            return val
        IsPtr = expected_type_str.endswith('*')
        if IsPtr:
            expected_ptr_type = ir.PointerType(expected_type)
            if isinstance(val.type, ir.PointerType) and val.type != expected_ptr_type:
                try:
                    return Gen.builder.bitcast(val, expected_ptr_type)
                except Exception:
                    return val
            elif isinstance(val.type, ir.IntType) and val.type.width == 64:
                try:
                    return Gen.builder.inttoptr(val, expected_ptr_type)
                except Exception:
                    return val
            return val
        if val.type == expected_type:
            return val
        if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.IntType):
            if expected_type.width < val.type.width:
                return Gen.builder.trunc(val, expected_type)
            else:
                return Gen.builder.zext(val, expected_type)
        if isinstance(val.type, ir.PointerType) and isinstance(expected_type, ir.IntType):
            if expected_type.width == 64:
                return Gen.builder.ptrtoint(val, expected_type)
        if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.PointerType):
            if val.type.width == 64:
                return Gen.builder.inttoptr(val, expected_type)
        return val

    def _HandleExternalCallLlvm(self, Node: ast.Call, func_name: str, ModulePath: str | None) -> ir.Value | None:
        Gen = self.Trans.LlvmGen

        # 解析 import 别名: 如 window -> vpsdk.window
        if ModulePath and ModulePath not in ('c', 't'):
            ModulePath = self.Trans.SymbolTable.resolve_alias(ModulePath)

        is_user_module = (ModulePath and ModulePath not in ('c', 't') and
                          (ModulePath in Gen.ModuleSha1Map or
                           ModulePath in getattr(self.Trans, '_ImportedModules', set()) or
                           ModulePath in self.Trans.SymbolTable.import_aliases))
        if ModulePath and ModulePath not in ('c', 't') and not is_user_module:
            is_user_module = (ModulePath in Gen.ModuleSha1Map or
                              ModulePath.split('.')[-1] in Gen.ModuleSha1Map or
                              ModulePath.split('.')[-1] in getattr(self.Trans, '_ImportedModules', set()))
            if is_user_module and ModulePath not in Gen.ModuleSha1Map and ModulePath not in getattr(self.Trans, '_ImportedModules', set()):
                ModulePath = ModulePath.split('.')[-1]

        if ModulePath and ModulePath not in ('c', 't') and not is_user_module:
            return None

        if is_user_module:
            mangled_name = Gen._mangle_func_name(func_name, ModulePath)
            sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath)
            is_inline = sym_info and (sym_info.IsInline or isinstance(sym_info.Storage, t.CInline))
            if is_inline and sym_info.InlineBody:
                self._HandleInlineExpandLlvm(Node, sym_info)
                return ir.Constant(ir.IntType(32), 1)
            sym_info_exact = self.Trans.SymbolTable.lookup(f'{ModulePath}.{func_name}')
            if sym_info_exact:
                exact_params = sym_info_exact.FuncPtrParams
                exact_param_names = [pn for pn, _ in exact_params]
                if exact_param_names:
                    provided = len(Node.args)
                    kw_provided = set()
                    for kw in Node.keywords:
                        if kw.arg and kw.arg in exact_param_names:
                            kw_provided.add(exact_param_names.index(kw.arg))
                    # 获取默认参数信息，计算必需参数数量（与 _fill_default_args 一致的查找逻辑）
                    global_defaults: dict = self.Trans._global_function_default_args
                    func_defaults: list | None = None
                    if mangled_name in global_defaults:
                        func_defaults = global_defaults[mangled_name]
                    elif func_name in global_defaults:
                        func_defaults = global_defaults[func_name]
                    else:
                        for gk, gv in global_defaults.items():
                            if func_name in gk or gk.endswith(func_name) or gk.endswith('.' + func_name):
                                func_defaults = gv
                                break
                    total_params: int = len(exact_param_names)
                    num_defaults: int = len(func_defaults) if func_defaults else 0
                    min_args: int = total_params - num_defaults
                    # 只检查必需参数（有默认值的参数允许缺失）
                    for i in range(min_args):
                        if i >= provided and i not in kw_provided:
                            raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数 '{exact_param_names[i]}'，该参数没有默认值")
            elif ModulePath in Gen.ModuleSha1Map and len(Node.args) == 0:
                func = Gen.functions.get(mangled_name)
                if func and len(func.function_type.args) > 0:
                    raise Exception(f"调用 {ModulePath}.{func_name}() 缺少必需参数，函数需要 {len(func.function_type.args)} 个参数但未传入任何参数")
            if Gen._has_function(mangled_name):
                return self._HandleClosureCallLlvm(Node, mangled_name)
            try:
                stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
            except Exception:
                stub_func_type = None
            if not stub_func_type and mangled_name != func_name:
                try:
                    stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen)
                except Exception:
                    stub_func_type = None
            if stub_func_type:
                if is_user_module:
                    decl_name = mangled_name
                else:
                    decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name
                self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=func_name)
                return self._HandleClosureCallLlvm(Node, decl_name)
            sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath)
            if sym_info:
                sig = self.BuildLLVMFuncTypeFromSig(sym_info, Gen, mangled_name=mangled_name, use_infer_fallback=True)
                if sig is not None:
                    ret_type, llvm_param_types, sym_is_variadic = sig
                    self.GetOrCreateFuncDecl(mangled_name, ret_type, llvm_param_types, Gen,
                                             is_variadic=sym_is_variadic, replace_name=func_name)
                    return self._HandleClosureCallLlvm(Node, mangled_name)
            # 回退: 直接用 func_name 查找（_find_function 会遍历 SHA1 前缀）
            fallback_func = Gen._find_function(func_name)
            if fallback_func is not None:
                return self._HandleClosureCallLlvm(Node, func_name)
            return None

        if ModulePath == 'c':
            if func_name == 'Asm':
                return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
            elif func_name == 'Addr':
                return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
            elif func_name == 'Set':
                return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
            elif func_name == 'Load':
                return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
            elif func_name == 'Deref':
                return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
            elif func_name == 'DerefAs':
                return self._HandleCDerefAsLlvm(Node)
            elif func_name == 'PtrToInt':
                return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
            elif func_name in ('CIf', 'CElif'):
                return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node)
            elif func_name == 'CError':
                msg = "compile-time error"
                if Node.args:
                    arg = Node.args[0]
                    if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
                        msg = arg.value
                lineno = getattr(Node, 'lineno', 0)
                raise Exception(f"#error: {msg} (line {lineno})")
            elif func_name in ('AsmInp', 'AsmOut'):
                return ir.Constant(ir.IntType(32), 0)
            elif func_name == 'LLVMIR':
                return self._HandleLLVMIRLlvm(Node)
            elif func_name in ('LInp', 'LOut'):
                return ir.Constant(ir.IntType(32), 0)

        win32_apis = {
            'SetConsoleOutputCP': (ir.IntType(32), [ir.IntType(32)]),
            'SetConsoleCP': (ir.IntType(32), [ir.IntType(32)]),
            'GetConsoleOutputCP': (ir.IntType(32), []),
            'GetConsoleCP': (ir.IntType(32), []),
        }
        if ModulePath and 'win32console' in ModulePath and func_name in win32_apis:
            ret_type, param_types = win32_apis[func_name]
            if func_name not in Gen.functions:
                func_type = ir.FunctionType(ret_type, param_types)
                func_decl = ir.Function(Gen.module, func_type, name=func_name)
                func_decl.linkage = 'external'
                Gen.functions[func_name] = func_decl
            call_args = []
            if Node.args:
                arg_val = self.HandleExprLlvm(Node.args[0])
                if arg_val:
                    target_type = param_types[0] if param_types else ir.IntType(32)
                    if isinstance(arg_val.type, ir.IntType) and arg_val.type.width < target_type.width:
                        arg_val = Gen.builder.zext(arg_val, target_type, name="zext_win32_arg")
                    elif isinstance(arg_val.type, ir.IntType) and arg_val.type.width > target_type.width:
                        arg_val = Gen.builder.trunc(arg_val, target_type, name="trunc_win32_arg")
                    call_args.append(arg_val)
            return Gen.builder.call(Gen.functions[func_name], call_args, name=f"call_{func_name}")

        if Gen._has_function(func_name):
            return self._HandleClosureCallLlvm(Node, func_name)

        if func_name in self.Trans.FunctionDefCache:
            return self._HandleClosureCallLlvm(Node, func_name)

        if func_name in self._C_LIB_FUNCS:
            return self._HandleClosureCallLlvm(Node, func_name)

        mangled_name = Gen._mangle_func_name(func_name, ModulePath)
        try:
            stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
        except Exception:
            stub_func_type = None
        if not stub_func_type and mangled_name != func_name:
            try:
                stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen)
            except Exception:
                stub_func_type = None
        if stub_func_type:
            decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name
            self.GetOrCreateStubFuncDecl(decl_name, stub_func_type, Gen, alias=func_name, check_existing=False)
            return self._HandleClosureCallLlvm(Node, decl_name)

        sym_info = self.LookupFunctionSymbol(func_name, module_path=ModulePath or None)
        if sym_info:
            sig = self.BuildLLVMFuncTypeFromSig(sym_info, Gen)
            if sig is not None:
                ret_type, llvm_param_types, sym_is_variadic = sig
                mangled_name = Gen._mangle_func_name(func_name, ModulePath)
                self.GetOrCreateFuncDecl(mangled_name, ret_type, llvm_param_types, Gen,
                                         is_variadic=sym_is_variadic, replace_name=func_name)
                return self._HandleClosureCallLlvm(Node, mangled_name)

        return None

    def _HandleTypeUnionCastLlvm(self, Node: ast.Call) -> ir.Value | None:
        Gen = self.Trans.LlvmGen
        if not Node.args:
            return None
        type_info = None
        try:
            type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func)
        except Exception as _e:
            if _config_mode == "strict":
                raise
            _vlog().warning(f"解析类型失败: {_e}", "Exception")
        if not isinstance(type_info, CTypeInfo):
            return None
        target_type_str = type_info.ToString()
        IsPtr = type_info.IsPtr
        if IsPtr and target_type_str and '*' not in target_type_str:
            target_type_str += ' *'
        if not target_type_str:
            return None
        if type_info.IsPtr and not IsPtr:
            IsPtr = True
            if '*' not in target_type_str:
                target_type_str += ' *'
        if isinstance(type_info.Storage, t.CExport) or isinstance(type_info.Storage, t.CExtern):
            pass
        if type_info.IsState:
            Gen._export_funcs.add('_type_union_cast')
        return self._HandleTypeCastLlvm(Node.args[0], target_type_str)

    def _HandleTypeCastLlvm(self, expr_node: ast.AST, target_type_str: str) -> ir.Value | None:
        Gen = self.Trans.LlvmGen
        val = self.HandleExprLlvm(expr_node)
        if val is None:
            return Gen.emit_constant(0, target_type_str)
        target_type = Gen._CType2LLVM(target_type_str)
        if not target_type:
            return val
        if val.type == target_type:
            if Gen._is_type_unsigned(target_type_str):
                Gen._unsigned_results[id(val)] = True
            return val
        src_is_float = isinstance(val.type, (ir.FloatType, ir.DoubleType))
        dst_is_float = isinstance(target_type, (ir.FloatType, ir.DoubleType))
        src_is_int = isinstance(val.type, ir.IntType)
        dst_is_int = isinstance(target_type, ir.IntType)
        src_IsPtr = isinstance(val.type, ir.PointerType)
        dst_IsPtr = isinstance(target_type, ir.PointerType)
        if src_is_int and dst_is_float:
            is_unsigned = Gen._check_node_unsigned(expr_node)
            if is_unsigned:
                return Gen.builder.uitofp(val, target_type, name="uint2float")
            return Gen.builder.sitofp(val, target_type, name="int2float")
        if src_is_float and dst_is_int:
            return Gen.builder.fptosi(val, target_type, name="float2int")
        if src_is_int and dst_is_int:
            is_dst_unsigned = Gen._is_type_unsigned(target_type_str)
            if val.type.width < target_type.width:
                if val.type.width == 1:
                    # i1 是布尔值（来自 icmp/fcmp/__contains__），无符号语义，必须 zext
                    result = Gen.builder.zext(val, target_type, name="zext_bool_cast")
                else:
                    is_unsigned = Gen._check_node_unsigned(expr_node)
                    if is_unsigned or is_dst_unsigned:
                        result = Gen.builder.zext(val, target_type, name="zext_cast")
                    else:
                        result = Gen.builder.sext(val, target_type, name="sext_cast")
                if is_dst_unsigned:
                    Gen._unsigned_results[id(result)] = True
                return result
            if val.type.width > target_type.width:
                result = Gen.builder.trunc(val, target_type, name="trunc_cast")
                if is_dst_unsigned:
                    Gen._unsigned_results[id(result)] = True
                return result
            if is_dst_unsigned:
                Gen._unsigned_results[id(val)] = True
            return val
        if src_is_float and dst_is_float:
            if isinstance(val.type, ir.FloatType) and isinstance(target_type, ir.DoubleType):
                return Gen.builder.fpext(val, target_type, name="fpext_cast")
            if isinstance(val.type, ir.DoubleType) and isinstance(target_type, ir.FloatType):
                return Gen.builder.fptrunc(val, target_type, name="fptrunc_cast")
            return val
        if src_IsPtr and dst_is_int:
            if target_type.width < 64:
                ptr_to_i64 = Gen.builder.ptrtoint(val, ir.IntType(64), name="ptr2i64")
                return Gen.builder.trunc(ptr_to_i64, target_type, name="ptr2int_cast")
            return Gen.builder.ptrtoint(val, target_type, name="ptr2int_cast")
        if src_is_int and dst_IsPtr:
            return Gen.builder.inttoptr(val, target_type, name="int2ptr_cast")
        if src_IsPtr and dst_IsPtr:
            if isinstance(val.type.pointee, ir.PointerType) and isinstance(target_type.pointee, ir.IntType):
                Loaded = Gen._load(val, name="load_ptr")
                return Loaded
            return Gen.builder.bitcast(val, target_type, name="ptrcast")
        try:
            return Gen.builder.bitcast(val, target_type, name="cast")
        except Exception:  # 回退：bitcast 失败时返回原值
            return val

    def _HandleREnumConstructLlvm(self, Node: ast.Call, RenumName: str, VariantName: str, TagValue: int) -> ir.Value | None:
        Gen = self.Trans.LlvmGen
        if RenumName not in Gen.structs:
            self.Trans.ImportHandler._TryLoadStructFromStub(RenumName, Gen)
        if RenumName not in Gen.structs:
            return None
        RenumType = Gen.structs[RenumName]
        result = Gen._allocaEntry(RenumType, name=f"{RenumName}_{VariantName}")
        tag_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="renum_tag_ptr")
        Gen._store(ir.Constant(ir.IntType(32), TagValue), tag_ptr)
        NestedStructName = f"{RenumName}_{VariantName}"
        if NestedStructName in Gen.structs and Node.args:
            NestedStructType = Gen.structs[NestedStructName]
            NestedStructPtrType = ir.PointerType(NestedStructType)
            variant_ptr = Gen.builder.bitcast(result, NestedStructPtrType, name=f"cast_{NestedStructName}")
            members = Gen.class_members.get(NestedStructName, [])
            payLoad_members = [(n, t) for n, t in members if n != '__tag']
            for i, arg in enumerate(Node.args):
                if i < len(payLoad_members):
                    member_name, member_type = payLoad_members[i]
                    ArgVal = self.HandleExprLlvm(arg)
                    if ArgVal:
                        Coerced = Gen._coerce_value(ArgVal, member_type)
                        if Coerced is not None:
                            ArgVal = Coerced
                        elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i + 1)], name=f"{VariantName}_{member_name}")
                        # REnum 嵌套结构体共享 max_variant_struct 布局，成员类型可能与
                        # 结构体字段类型不一致（如 Bits:i32 与 Ret:LLVMType* 重叠）。
                        # 需 bitcast elem_ptr 到成员类型，避免 _store 按 struct 字段类型做错误转换。
                        if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type:
                            elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"{VariantName}_{member_name}_cast")
                        Gen._store(ArgVal, elem_ptr)
        return result

    def _HandleTypedefCastLlvm(self, Node: ast.Call, TypedefName: str) -> ir.Value:
        Gen = self.Trans.LlvmGen
        SymInfo = self.Trans.SymbolTable.lookup(TypedefName)
        if not SymInfo or not SymInfo.IsTypedef:
            return ir.Constant(ir.IntType(32), 0)
        # 确保 Name 已设置，以便 _resolve_typedef_ctype 能正确解析
        if not SymInfo.Name:
            SymInfo.Name = TypedefName
        TargetType = Gen._ctype_to_llvm(SymInfo)
        if not Node.args:
            if isinstance(TargetType, ir.IntType):
                return ir.Constant(TargetType, 0)
            elif isinstance(TargetType, ir.PointerType):
                return ir.Constant(TargetType, None)
            return ir.Constant(ir.IntType(32), 0)
        ArgVal = self.HandleExprLlvm(Node.args[0])
        if not ArgVal:
            if isinstance(TargetType, ir.IntType):
                return ir.Constant(TargetType, 0)
            return ir.Constant(ir.IntType(32), 0)
        if ArgVal.type == TargetType:
            return ArgVal
        if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType):
            if ArgVal.type.width < TargetType.width:
                return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast")
            elif ArgVal.type.width > TargetType.width:
                return Gen.builder.trunc(ArgVal, TargetType, name=f"trunc_{TypedefName}_cast")
            return ArgVal
        if isinstance(TargetType, ir.PointerType):
            if isinstance(ArgVal.type, ir.PointerType):
                return Gen.builder.bitcast(ArgVal, TargetType, name=f"bitcast_{TypedefName}_cast")
            if isinstance(ArgVal.type, ir.IntType):
                return Gen.builder.inttoptr(ArgVal, TargetType, name=f"inttoptr_{TypedefName}_cast")
            # 如果参数是结构体值，需要 alloca 并返回指针
            if isinstance(ArgVal.type, ir.BaseStructType):
                alloca = Gen.builder.alloca(ArgVal.type, name=f"struct_alloca_{TypedefName}")
                Gen.builder.store(ArgVal, alloca, align=8)
                return Gen.builder.bitcast(alloca, TargetType, name=f"bitcast_struct_{TypedefName}")
        if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.PointerType):
            return Gen.builder.ptrtoint(ArgVal, TargetType, name=f"ptrtoint_{TypedefName}_cast")
        if isinstance(TargetType, (ir.FloatType, ir.DoubleType)) and isinstance(ArgVal.type, ir.IntType):
            return Gen.builder.sitofp(ArgVal, TargetType, name=f"sitofp_{TypedefName}_cast")
        if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, (ir.FloatType, ir.DoubleType)):
            return Gen.builder.fptosi(ArgVal, TargetType, name=f"fptosi_{TypedefName}_cast")
        return ArgVal

    def _HandleInlineExpandLlvm(self, Node: ast.Call, sym_info: CTypeInfo) -> None:
        Gen = self.Trans.LlvmGen
        inline_body = sym_info.InlineBody
        inline_params = sym_info.InlineParams or []
        call_args = []
        for arg in Node.args:
            call_args.append(self.Trans.ExprHandler.HandleExprLlvm(arg))
        saved_vars = {}
        for i, param_name in enumerate(inline_params):
            if i < len(call_args):
                saved_vars[param_name] = call_args[i]
        old_var_scopes = list(self.Trans.VarScopes)
        for param_name, val in saved_vars.items():
            if val is not None:
                alloca = Gen._allocaEntry(val.type, name=f"inline_arg_{param_name}")
                Gen._store(val, alloca)
                self.Trans.VarScopes.append((param_name, alloca))
        self.Trans.BodyHandler.HandleBodyLlvm(inline_body)
        for param_name, _ in saved_vars.items():
            if self.Trans.VarScopes and self.Trans.VarScopes[-1][0] == param_name:
                self.Trans.VarScopes.pop()
        self.Trans.VarScopes = old_var_scopes
        return None

    def _HandleClosureCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value:
        Gen = self.Trans.LlvmGen
        func = Gen.functions.get(FuncName)
        if not func:
            if FuncName in self.Trans.FunctionDefCache:
                FuncDef = self.Trans.FunctionDefCache[FuncName]
                self.Trans.FunctionHandler._EmitFunctionForwardDeclLlvm(FuncDef, Gen)
                func = Gen.functions.get(FuncName)
            if not func:
                func = self._try_declare_c_lib_func(FuncName, Gen)
            if not func:
                raise Exception(f"Undefined function: '{FuncName}'")

        FuncDef = self.Trans.FunctionDefCache.get(FuncName)
        param_names = []
        FuncDef_args = getattr(FuncDef, 'args', None) if FuncDef else None
        if FuncDef_args:
            param_names = [arg.arg for arg in FuncDef.args.args]
        # 回退到全局参数名表（支持跨模块 include 函数）
        if not param_names:
            global_param_names = getattr(self.Trans, '_global_function_param_names', {})
            param_names = global_param_names.get(FuncName) or []

        num_params = len(func.function_type.args)
        nonlocal_param_count = len(Gen.nonlocal_params.get(FuncName, []))
        eh_msg_out_count = 0
        if num_params > 0 and func.args:
            for arg in func.args:
                if arg.name in ('__eh_msg_out__', '__eh_code_out__'):
                    eh_msg_out_count += 1
        regular_param_count = num_params - nonlocal_param_count - eh_msg_out_count
        is_variadic = False
        func_ft = getattr(func, 'function_type', None)
        is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
        
        if not is_variadic and len(Node.args) > regular_param_count:
            raise Exception(f"调用 {FuncName}() 传入了 {len(Node.args)} 个参数，但函数只需要 {regular_param_count} 个参数")

        max_args = len(Node.args) if is_variadic else regular_param_count
        resolved = [None] * max_args

        for i, arg in enumerate(Node.args):
            if i < max_args:
                arg_var_type = None
                if i < num_params:
                    arg_var_type = func.function_type.args[i]
                ArgVal = self.HandleExprLlvm(arg, VarType=arg_var_type)
                if ArgVal:
                    resolved[i] = ArgVal

        for kw in Node.keywords:
            if kw.arg is None:
                if isinstance(kw.value, ast.Dict):
                    pass
                elif isinstance(kw.value, ast.Call):
                    pass
                continue
            ArgVal = self.HandleExprLlvm(kw.value)
            if not ArgVal:
                continue
            kw_name = kw.arg
            if kw_name in param_names:
                idx = param_names.index(kw_name)
                if idx < regular_param_count:
                    resolved[idx] = ArgVal

        FuncDef_args_defaults = getattr(getattr(FuncDef, 'args', None), 'defaults', []) if FuncDef else []
        if FuncDef_args_defaults:
            defaults = FuncDef.args.defaults
            num_defaults = len(defaults)
            if num_defaults > 0:
                min_args = regular_param_count - num_defaults
                for i in range(regular_param_count):
                    if resolved[i] is None and i >= min_args:
                        default_idx = i - min_args
                        if default_idx < len(defaults):
                            default_node = defaults[default_idx]
                            default_val = self.HandleExprLlvm(default_node)
                            if default_val:
                                param_type = func.function_type.args[i]
                                if default_val.type != param_type:
                                    if isinstance(param_type, ir.IntType) and isinstance(default_val.type, ir.IntType):
                                        if default_val.type.width < param_type.width:
                                            default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
                                        elif default_val.type.width > param_type.width:
                                            default_val = Gen.builder.trunc(default_val, param_type, name=f"trunc_default_{i}")
                                    elif isinstance(param_type, ir.PointerType) and isinstance(default_val.type, ir.IntType):
                                        default_val = Gen.builder.inttoptr(default_val, param_type, name=f"inttoptr_default_{i}")
                                resolved[i] = default_val

        if FuncDef and param_names:
            min_args = regular_param_count - num_defaults if FuncDef_args_defaults else regular_param_count
            provided = len(Node.args)
            kw_provided = set()
            for kw in Node.keywords:
                if kw.arg and kw.arg in param_names:
                    kw_provided.add(param_names.index(kw.arg))
            for i in range(min(min_args, len(param_names))):
                if i >= provided and i not in kw_provided:
                    raise Exception(f"调用 {FuncName}() 缺少必需参数 '{param_names[i]}'，该参数没有默认值")

        CallArgs = []
        for i in range(max_args):
            if resolved[i] is not None:
                CallArgs.append(resolved[i])
            elif i < regular_param_count:
                arg_type = func.function_type.args[i]
                if isinstance(arg_type, ir.PointerType):
                    CallArgs.append(ir.Constant(arg_type, None))
                elif isinstance(arg_type, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    zero_val = Gen._zero_value_for_type(arg_type)
                    if zero_val is not None:
                        CallArgs.append(zero_val)
                    else:
                        CallArgs.append(ir.Constant(ir.PointerType(arg_type), None))
                elif isinstance(arg_type, ir.ArrayType):
                    zero_val = Gen._zero_value_for_type(arg_type)
                    if zero_val is not None:
                        CallArgs.append(zero_val)
                    else:
                        CallArgs.append(ir.Constant(arg_type, 0))
                else:
                    CallArgs.append(ir.Constant(arg_type, 0))

        if FuncName in Gen.nonlocal_params:
            for var_name, ptr_type in Gen.nonlocal_params[FuncName]:
                if var_name in Gen.variables and Gen.variables[var_name] is not None:
                    CallArgs.append(Gen.variables[var_name])
                elif var_name in Gen._reg_values:
                    OldVal = Gen._reg_values[var_name]
                    var = Gen._allocaEntry(OldVal.type, name=var_name)
                    Gen._store(OldVal, var)
                    Gen.variables[var_name] = var
                    del Gen._reg_values[var_name]
                    CallArgs.append(var)

        self._append_eh_msg_out_arg(CallArgs, func, Gen)

        if is_variadic:
            # 对于可变参数函数，需要手动处理参数类型转换
            adjusted = []
            for i, arg in enumerate(CallArgs):
                if i < num_params:
                    # 固定参数：尝试类型转换
                    param_type = func.function_type.args[i]
                    if arg.type != param_type:
                        try:
                            if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType):
                                adjusted.append(self.builder.inttoptr(arg, param_type))
                            elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
                                adjusted.append(Gen.builder.ptrtoint(arg, param_type))
                            elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
                                adjusted.append(Gen.builder.zext(arg, param_type))
                            elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType):
                                adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}"))
                            else:
                                adjusted.append(arg)
                        except Exception:  # 回退：参数类型调整失败时使用原值
                            if isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType):
                                try:
                                    adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}"))
                                except Exception:
                                    adjusted.append(arg)
                            else:
                                adjusted.append(arg)
                    else:
                        adjusted.append(arg)
                else:
                    # 可变参数：应用默认参数提升（float -> double, i32 -> i64）
                    if isinstance(arg.type, ir.FloatType):
                        arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{FuncName}")
                    elif isinstance(arg.type, ir.IntType) and arg.type.width < 64:
                        # i1 是布尔值（来自 icmp/fcmp/__contains__），无符号语义，必须 zext
                        if arg.type.width == 1:
                            arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{FuncName}")
                        else:
                            # 有符号整数用 sext，无符号整数用 zext
                            is_signed = True
                            arg_node = Node.args[i] if i < len(Node.args) else None
                            if arg_node is not None:
                                is_u = Gen._check_node_unsigned(arg_node)
                                if is_u:
                                    is_signed = False
                            if is_signed:
                                arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{FuncName}")
                            else:
                                arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{FuncName}")
                    adjusted.append(arg)
            result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}")
        else:
            CallArgs = Gen._apply_auto_addr(FuncName, CallArgs)
            adjusted = Gen._adjust_args(CallArgs, func)
            # 兜底：确保所有指针类型参数与函数签名匹配（如 struct* -> i8*）
            for i, (arg, param) in enumerate(zip(adjusted, func.args)):
                if arg.type != param.type:
                    if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType):
                        adjusted[i] = Gen.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")
            result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}")
        self._check_eh_return(result, FuncName, Gen, called_func=func)
        return result

    @staticmethod
    def _has_cvtable_decorator(node: ast.ClassDef) -> bool:
        """检查 ClassDef 是否有 @t.CVTable 装饰器（或 @CVTable）"""
        for decorator in node.decorator_list:
            if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'CVTable':
                return True
            if isinstance(decorator, ast.Call):
                inner = decorator.func
                if isinstance(inner, ast.Attribute) and getattr(inner.value, 'id', None) == 't' and inner.attr == 'CVTable':
                    return True
                if isinstance(inner, ast.Name) and inner.id == 'CVTable':
                    return True
            if isinstance(decorator, ast.Name) and decorator.id == 'CVTable':
                return True
        return False

    @staticmethod
    def _has_novtable_decorator(node: ast.ClassDef) -> bool:
        """检查 ClassDef 是否有 @t.NoVTable 装饰器"""
        for decorator in node.decorator_list:
            if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'NoVTable':
                return True
            if isinstance(decorator, ast.Name) and decorator.id == 'NoVTable':
                return True
        return False

    def _try_register_vtable_ondemand(self, ClassName: str, class_sha1: str, Gen: "LlvmGeneratorMixin") -> None:
        """按需 vtable 注册：从 .pyi stub 检查 @t.CVTable 并注册到 vtable 集合。

        沿继承链递归收集方法，保证 vtable 布局与 prescan 的 _EmitClassLlvm 一致：
        - 基类方法在前（固定索引，保证多态分派正确）
        - 子类新增方法在后
        - 子类覆盖的方法放在父类的位置（用子类实现）

        与 prescan 的 _resolve_class_flags 逻辑一致：
        - 类自身有 @t.CVTable → 注册
        - 类自身有 @t.NoVTable → 不注册
        - 类继承 @t.CVTable 基类（且无 @t.NoVTable）→ 注册（自动启用 CVTable）
        """
        try:
            import_handler = self.Trans.ImportHandler
            project_root = import_handler._find_project_root()
            struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})

            # 缓存已读取的 .pyi 文件（sha1 -> class_map）
            pyi_cache: dict[str, dict[str, ast.ClassDef]] = {}

            def load_pyi(sha1: str) -> dict[str, ast.ClassDef] | None:
                if sha1 in pyi_cache:
                    return pyi_cache[sha1]
                pyi_path = os.path.join(project_root, 'temp', f'{sha1}.pyi')
                if not os.path.isfile(pyi_path):
                    return None
                with open(pyi_path, 'r', encoding='utf-8') as f:
                    pyi_code = f.read()
                tree = ast.parse(pyi_code)
                cmap: dict[str, ast.ClassDef] = {}
                for node in ast.iter_child_nodes(tree):
                    if isinstance(node, ast.ClassDef):
                        cmap[node.name] = node
                pyi_cache[sha1] = cmap
                return cmap

            def collect_class_methods(class_name: str, sha1: str, visited: set[str]) -> tuple[list[str], bool, bool, str | None]:
                """递归收集类的方法列表（基类方法在前，子类方法在后）。

                Returns:
                    (methods, is_cvtable, is_novtable, parent_name)
                """
                if class_name in visited:
                    return ([], False, False, None)
                visited.add(class_name)

                class_map = load_pyi(sha1)
                if class_map is None:
                    return ([], False, False, None)

                target_node = class_map.get(class_name)
                if target_node is None:
                    return ([], False, False, None)

                is_cvtable = self._has_cvtable_decorator(target_node)
                is_novtable = self._has_novtable_decorator(target_node)

                # 收集自身方法
                self_methods: list[str] = []
                for item in target_node.body:
                    if isinstance(item, ast.FunctionDef):
                        method_name = item.name
                        if method_name in ('__new__', '__init__', '__before_init__'):
                            continue
                        if method_name == '__call__':
                            self_methods.append(f"{class_name}.__call__")
                        else:
                            self_methods.append(f"{class_name}.{method_name}")

                # 收集基类方法
                parent_methods: list[str] = []
                parent_name: str | None = None
                for base in target_node.bases:
                    base_name: str | None = None
                    if hasattr(base, 'id'):
                        base_name = base.id
                    elif hasattr(base, 'attr'):
                        base_name = base.attr
                    if not base_name or base_name in ('Object', 'CVTable', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
                        continue
                    if parent_name is None:
                        parent_name = base_name

                    # 检查同文件内的基类
                    base_node = class_map.get(base_name)
                    if base_node is not None:
                        base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, sha1, visited)
                        if base_novtable:
                            pass  # 父类是 NoVTable，不继承 vtable
                        elif base_cvtable:
                            is_cvtable = True
                        parent_methods.extend(base_methods)
                    else:
                        # 跨模块基类 — 查找基类的 sha1
                        base_sha1 = struct_sha1_map.get(base_name)
                        if base_sha1:
                            base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, base_sha1, visited)
                            if base_novtable:
                                pass
                            elif base_cvtable:
                                is_cvtable = True
                            parent_methods.extend(base_methods)
                        else:
                            # 无法找到基类的 sha1
                            if base_name in Gen._cross_module_novtable:
                                pass  # 父类是 NoVTable，不继承 vtable

                # 合并方法列表：基类方法在前，子类方法在后
                # 子类覆盖的方法放在父类的位置
                child_method_map: dict[str, str] = {}
                for m in self_methods:
                    mn = m.split('.')[-1] if '.' in m else m
                    child_method_map[mn] = m

                merged: list[str] = []
                covered_names: set[str] = set()
                for pm in parent_methods:
                    mn = pm.split('.')[-1] if '.' in pm else pm
                    if mn in child_method_map:
                        merged.append(child_method_map[mn])
                        covered_names.add(mn)
                    else:
                        # 父类独有方法 — 用子类名（虚分派时函数查找会沿继承链回退）
                        merged.append(f"{class_name}.{mn}")

                for m in self_methods:
                    mn = m.split('.')[-1] if '.' in m else m
                    if mn not in covered_names:
                        merged.append(m)

                return (merged, is_cvtable, is_novtable, parent_name)

            methods, is_cvtable, is_novtable, parent_name = collect_class_methods(ClassName, class_sha1, set())

            if is_novtable:
                return
            if not is_cvtable:
                return

            # 注册到 vtable 集合（共享集合）
            Gen._cross_module_vtable_classes.add(ClassName)
            Gen.class_vtable.add(ClassName)
            # 设置方法列表（与 prescan 逻辑一致：基类方法在前）
            Gen.class_methods[ClassName] = methods
            # 设置 class_parent（用于虚分派时的函数查找回退）
            if parent_name and ClassName not in Gen.class_parent:
                Gen.class_parent[ClassName] = parent_name
        except Exception:
            pass

    def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value:
        Gen = self.Trans.LlvmGen
        MethodName = Node.func.attr
        # 检查是否为 @staticmethod 或 @classmethod，如果是则走特殊路径
        if isinstance(Node.func.value, ast.Name):
            VarName = Node.func.value.id
            ClassName = Gen.var_struct_class.get(VarName)
            if ClassName:
                SymKey = f'{ClassName}.{MethodName}'
                SymInfo = self.Trans.SymbolTable.lookup(SymKey)
                if SymInfo and SymInfo.MetaList:
                    if FuncMeta.STATIC_METHOD in SymInfo.MetaList:
                        return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName)
                    if FuncMeta.CLASS_METHOD in SymInfo.MetaList:
                        return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName)
        if isinstance(Node.func.value, ast.Name) and IsTModule(Node.func.value.id, self.Trans.SymbolTable):
            result = self.Trans.TSpecialCallHandle._HandleTSpecialCallLlvm(Node)
            if result is not None:
                return result
            ctype_cls = CTypeRegistry.GetClassByName(MethodName)
            if ctype_cls is not None:
                try:
                    ctype_inst = ctype_cls()
                except Exception:
                    ctype_inst = None
                target_bits = getattr(ctype_inst, 'Size', None) if ctype_inst else None
                if target_bits is None:
                    target_bits = 0
                is_float = getattr(ctype_inst, 'IsSigned', False) is None and target_bits > 0 if ctype_inst else False
                IsPtr_cast = len(Node.args) >= 2 and (
                    (isinstance(Node.args[1], ast.Attribute) and Node.args[1].attr == 'CPtr' and isinstance(Node.args[1].value, ast.Name) and IsTModule(Node.args[1].value.id, self.Trans.SymbolTable)) or
                    (isinstance(Node.args[1], ast.Name) and Node.args[1].id == 'CPtr')
                )
                if Node.args:
                    ArgNode = Node.args[0]
                    if isinstance(ArgNode, ast.Subscript):
                        SubscriptPtr = self._HandleSubscriptPtrLlvm(ArgNode)
                        if SubscriptPtr:
                            if MethodName == 'CPtr' or IsPtr_cast:
                                return SubscriptPtr
                            if isinstance(SubscriptPtr.type, ir.PointerType):
                                val = Gen._load(SubscriptPtr, name="Load_subscript_val")
                            else:
                                val = SubscriptPtr
                            if target_bits > 0 and isinstance(val.type, ir.IntType) and not is_float:
                                if val.type.width < target_bits:
                                    val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast")
                                elif val.type.width > target_bits:
                                    val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast")
                            return val
                    val = self.HandleExprLlvm(ArgNode)
                    if IsPtr_cast:
                        if target_bits > 0 and not is_float:
                            target_ptr_type = ir.PointerType(ir.IntType(target_bits))
                        elif is_float and target_bits == 32:
                            target_ptr_type = ir.PointerType(ir.FloatType())
                        elif is_float and target_bits == 64:
                            target_ptr_type = ir.PointerType(ir.DoubleType())
                        else:
                            target_ptr_type = ir.PointerType(ir.IntType(8))
                        if isinstance(val.type, ir.PointerType):
                            if val.type != target_ptr_type:
                                val = Gen.builder.bitcast(val, target_ptr_type, name="ptr_cast")
                        elif isinstance(val.type, ir.IntType):
                            if val.type.width < 64:
                                val = Gen.builder.zext(val, ir.IntType(64), name="zext_ptr_cast")
                            val = Gen.builder.inttoptr(val, target_ptr_type, name="int_to_ptr_cast")
                        return val
                    if val and target_bits > 0 and not is_float:
                        if isinstance(val.type, ir.IntType):
                            if val.type.width < target_bits:
                                val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast")
                            elif val.type.width > target_bits:
                                val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast")
                        elif isinstance(val.type, ir.PointerType):
                            val = Gen.builder.ptrtoint(val, ir.IntType(target_bits), name="ptrtoint_cast")
                    return val
                if is_float:
                    return ir.Constant(ir.FloatType() if target_bits == 32 else ir.DoubleType(), 0.0)
                return ir.Constant(ir.IntType(target_bits) if target_bits > 0 else ir.IntType(32), 0)
            if self.Trans.SymbolTable.has(MethodName):
                SymInfo = self.Trans.SymbolTable[MethodName]
                if SymInfo.IsTypedef:
                    return self._HandleTypedefCastLlvm(Node, MethodName)
        if isinstance(Node.func.value, ast.Name) and Node.func.value.id == 'c':
            if MethodName == 'Asm':
                return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node)
            if MethodName == 'Addr':
                return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node)
            elif MethodName == 'Set':
                return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node)
            elif MethodName == 'Load':
                return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node)
            elif MethodName == 'Deref':
                return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node)
            elif MethodName == 'DerefAs':
                return self._HandleCDerefAsLlvm(Node)
            elif MethodName == 'PtrToInt':
                return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node)
            elif MethodName in ('CIf', 'CElif'):
                if Node.args:
                    ArgVal = self.HandleExprLlvm(Node.args[0])
                    if ArgVal:
                        if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType):
                            return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0)
                        if isinstance(ArgVal.type, ir.IntType):
                            return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
                        if isinstance(ArgVal.type, ir.PointerType):
                            return Gen.builder.icmp_signed('!=', ArgVal, Gen._ZeroConst(ArgVal.type), name="cif_cond")
                return ir.Constant(ir.IntType(1), 0)
            elif MethodName in ('CIfdef', 'CIfndef'):
                return ir.Constant(ir.IntType(1), 1)
            elif MethodName == 'CError':
                msg = "compile-time error"
                if Node.args:
                    arg = Node.args[0]
                    if isinstance(arg, ast.Constant) and isinstance(arg.value, str):
                        msg = arg.value
                    else:
                        try:
                            val = self.HandleExprLlvm(arg)
                            if isinstance(val, str):
                                msg = val
                        except Exception as _e:
                            if _config_mode == "strict":
                                raise
                            _vlog().warning(f"处理函数调用失败: {_e}", "Exception")
                lineno = getattr(Node, 'lineno', 0)
                raise Exception(f"#error: {msg} (line {lineno})")
            elif MethodName in ('CElse', 'CEndif', 'CPragma', 'CUndef'):
                return ir.Constant(ir.IntType(1), 1)
            elif MethodName in ('LLVMIR', 'LInp', 'LOut'):
                return None
        ObjVal = self.HandleExprLlvm(Node.func.value)
        if not ObjVal:
            return None
        if isinstance(ObjVal.type, (ir.IdentifiedStructType, ir.LiteralStructType)):
            if isinstance(Node.func.value, ast.Name):
                var_name = Node.func.value.id
                if var_name in Gen.variables:
                    var_ptr = Gen.variables[var_name]
                    if isinstance(var_ptr.type, ir.PointerType) and isinstance(var_ptr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                        ObjVal = var_ptr
                    else:
                        tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
                        Gen._store(ObjVal, tmp)
                        ObjVal = tmp
                else:
                    tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
                    Gen._store(ObjVal, tmp)
                    ObjVal = tmp
            else:
                tmp = Gen._allocaEntry(ObjVal.type, name="chain_method_tmp")
                Gen._store(ObjVal, tmp)
                ObjVal = tmp
        if isinstance(Node.func.value, ast.Name):
            ModuleName = Node.func.value.id
            imported = getattr(self.Trans, '_ImportedModules', set())
            actual_module = self.Trans.SymbolTable.resolve_alias(ModuleName)
            if ModuleName in imported or actual_module in imported:
                mangled_name = Gen._mangle_func_name(MethodName, actual_module)
                if Gen._has_function(mangled_name):
                    CallArgs = []
                    for arg in Node.args:
                        ArgVal = self.HandleExprLlvm(arg)
                        if ArgVal:
                            CallArgs.append(ArgVal)
                    func = Gen._get_function(mangled_name)
                    self._fill_default_args(CallArgs, func, MethodName)
                    func_ft = getattr(func, 'function_type', None)
                    is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
                    num_fixed_params = len(func_ft.args) if func_ft else 0
                    if is_variadic:
                        adjusted = []
                        for i, arg in enumerate(CallArgs):
                            if i < num_fixed_params:
                                param_type = func_ft.args[i]
                                if arg.type != param_type:
                                    try:
                                        if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType):
                                            adjusted.append(self.builder.inttoptr(arg, param_type))
                                        elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
                                            adjusted.append(Gen.builder.ptrtoint(arg, param_type))
                                        elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
                                            adjusted.append(Gen.builder.zext(arg, param_type))
                                        else:
                                            adjusted.append(arg)
                                    except Exception:  # 回退：参数类型调整失败时使用原值
                                        adjusted.append(arg)
                                else:
                                    adjusted.append(arg)
                            else:
                                if isinstance(arg.type, ir.FloatType):
                                    arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}")
                                elif isinstance(arg.type, ir.IntType) and arg.type.width < 64:
                                    if arg.type.width == 1:
                                        arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{MethodName}")
                                    else:
                                        is_signed = True
                                        arg_node = Node.args[i] if i < len(Node.args) else None
                                        if arg_node is not None:
                                            is_u = Gen._check_node_unsigned(arg_node)
                                            if is_u:
                                                is_signed = False
                                        if is_signed:
                                            arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}")
                                        else:
                                            arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}")
                                adjusted.append(arg)
                        result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
                    else:
                        CallArgs = Gen._apply_auto_addr(MethodName, CallArgs)
                        adjusted = Gen._adjust_args(CallArgs, func)
                        result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
                    return result
                if Gen._has_function(MethodName):
                    _mf = Gen._get_function(MethodName)
                    if '.' not in _mf.name:
                        CallArgs = []
                        for arg in Node.args:
                            ArgVal = self.HandleExprLlvm(arg)
                            if ArgVal:
                                CallArgs.append(ArgVal)
                        func = _mf
                        self._fill_default_args(CallArgs, func, MethodName)
                        func_ft = getattr(func, 'function_type', None)
                        is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False
                        num_fixed_params = len(func_ft.args) if func_ft else 0
                        if is_variadic:
                            adjusted = []
                            for i, arg in enumerate(CallArgs):
                                if i < num_fixed_params:
                                    param_type = func_ft.args[i]
                                    if arg.type != param_type:
                                        try:
                                            if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType):
                                                adjusted.append(self.builder.inttoptr(arg, param_type))
                                            elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
                                                adjusted.append(Gen.builder.ptrtoint(arg, param_type))
                                            elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
                                                adjusted.append(Gen.builder.zext(arg, param_type))
                                            else:
                                                adjusted.append(arg)
                                        except Exception:  # 回退：参数类型调整失败时使用原值
                                            adjusted.append(arg)
                                    else:
                                        adjusted.append(arg)
                                else:
                                    if isinstance(arg.type, ir.FloatType):
                                        arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}")
                                    elif isinstance(arg.type, ir.IntType) and arg.type.width < 64:
                                        if arg.type.width == 1:
                                            arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_bool_vararg_{MethodName}")
                                        else:
                                            is_signed = True
                                            arg_node = Node.args[i] if i < len(Node.args) else None
                                            if arg_node is not None:
                                                is_u = Gen._check_node_unsigned(arg_node)
                                                if is_u:
                                                    is_signed = False
                                            if is_signed:
                                                arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}")
                                            else:
                                                arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}")
                                    adjusted.append(arg)
                            result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
                        else:
                            CallArgs = Gen._apply_auto_addr(MethodName, CallArgs)
                            adjusted = Gen._adjust_args(CallArgs, func)
                            result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
                        return result
                stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen)
                if not stub_func_type:
                    stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MethodName, Gen)
                if not stub_func_type and mangled_name != MethodName:
                    for sha1 in getattr(Gen, 'ModuleSha1Map', {}).values():
                        alt_name = f"{sha1}.{MethodName}"
                        stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(alt_name, Gen)
                        if stub_func_type:
                            mangled_name = alt_name
                            break
                if stub_func_type:
                    func = self.GetOrCreateStubFuncDecl(mangled_name, stub_func_type, Gen)
                    CallArgs = []
                    for arg in Node.args:
                        ArgVal = self.HandleExprLlvm(arg)
                        if ArgVal:
                            CallArgs.append(ArgVal)
                    self._fill_default_args(CallArgs, func, mangled_name)
                    self._append_eh_msg_out_arg(CallArgs, func, Gen)
                    CallArgs = Gen._apply_auto_addr(mangled_name, CallArgs)
                    adjusted = Gen._adjust_args(CallArgs, func)
                    result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}")
                    self._check_eh_return(result, mangled_name, Gen, called_func=func)
                    return result
                return ir.Constant(ir.IntType(32), 0)
        CallArgs = []
        for arg in Node.args:
            ArgVal = self.HandleExprLlvm(arg)
            if ArgVal:
                CallArgs.append(ArgVal)
        ClassName = None
        if isinstance(Node.func.value, ast.Name):
            ClassName = Gen.var_struct_class.get(Node.func.value.id)
        if not ClassName and isinstance(Node.func.value, ast.Attribute):
            # 链式属性访问（如 func.Params.append）：通过 _get_var_class 推导泛型特化类名
            ClassName = self.Trans.ExprHandler._get_var_class(Node.func.value, Gen)
        if not ClassName:
            for CN, ST in Gen.structs.items():
                if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == ST:
                    ClassName = CN
                    break
        if not ClassName and self._is_char_pointer(ObjVal):
            MethodName = Node.func.attr
            # FakeDuck: 检查是否有影子结构体 a__meta__ (per-instance 字段存储)
            meta_ptr: ir.Value | None = None
            if isinstance(Node.func.value, ast.Name):
                meta_name = f"{Node.func.value.id}__meta__"
                if meta_name in Gen.variables:
                    meta_ptr = Gen.variables[meta_name]
            for CN, ST in Gen.structs.items():
                method_key = f'{CN}.{MethodName}'
                if not Gen._has_function(method_key):
                    continue
                # FakeDuck: 不跳过空结构体 (扩展类可能没有数据成员只有方法)
                try:
                    # 如果有影子结构体且该类有字段, 使用影子结构体作为 self (而非 bitcast char*)
                    if meta_ptr is not None and hasattr(ST, 'elements') and len(ST.elements) > 0:
                        ObjVal = meta_ptr
                    elif CN == '_str' and hasattr(ST, 'elements') and len(ST.elements) > 0:
                        # FakeDuck: 字符串字面量/匿名 str 表达式调用 _str 方法时，
                        # 创建临时影子结构体 (栈上), 设置 __data__ 和 __mbuddy__ 字段。
                        # bitcast i8* → _str* 会导致读取垃圾指针 → ACCESS_VIOLATION
                        tmp_meta: ir.AllocaInstr = Gen._allocaEntry(ST, name="tmp_str_meta")
                        _data_off = Gen._get_member_offset('__data__', '_str')
                        if _data_off is not None:
                            _data_ptr = Gen.builder.gep(tmp_meta, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _data_off)], name="tmp_str_data")
                            Gen._store(ObjVal, _data_ptr)
                        _mpool_off = Gen._get_member_offset('__mbuddy__', '_str')
                        if _mpool_off is not None:
                            _mpool_ptr = Gen.builder.gep(tmp_meta, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _mpool_off)], name="tmp_str_mbuddy")
                            Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), _mpool_ptr)
                        # 从 with 上下文自动注入 requires 字段 (如 __mbuddy__)
                        self._InjectRequiresFields(tmp_meta, '_str', Gen)
                        ObjVal = tmp_meta
                    else:
                        casted = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}")
                        ObjVal = casted
                    ClassName = CN
                    break
                except Exception:  # 回退：bitcast 失败时尝试下一个类
                    continue
        if not ClassName and isinstance(Node.func.value, ast.Call):
            if isinstance(Node.func.value.func, ast.Attribute):
                InnerAttrName = Node.func.value.func.attr
                for CN in Gen.structs:
                    if CN.endswith(f'__{InnerAttrName}') or f'__{InnerAttrName}' in CN:
                        continue
                    method_name = f'{CN}__{InnerAttrName}'
                    if Gen._has_function(method_name):
                        func = Gen._get_function(method_name)
                        ret_type = func.fnty.return_type
                        if isinstance(ret_type, ir.PointerType):
                            for CN2, ST in Gen.structs.items():
                                if ret_type.pointee == ST:
                                    ClassName = CN2
                                    break
                        elif isinstance(ret_type, ir.IdentifiedStructType):
                            for CN2, ST in Gen.structs.items():
                                if ret_type == ST:
                                    ClassName = CN2
                                    break
                        if ClassName:
                            break
        if not ClassName:
            return ir.Constant(ir.IntType(32), 0)
        struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
        class_sha1 = struct_sha1_map.get(ClassName)
        if class_sha1:
            FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}'
        else:
            FullMethodName = f'{ClassName}.{MethodName}'

        # 提前查找函数以获取参数信息
        func_for_kw = Gen._find_function(FullMethodName)
        if not func_for_kw:
            func_for_kw = Gen._find_function(f'{FullMethodName}__')
        if not func_for_kw and class_sha1:
            func_for_kw = Gen._find_function(f'{ClassName}.{MethodName}')

        # 处理关键字参数: 先用 _fill_default_args 填充默认值，再用 keyword args 覆盖
        if Node.keywords and func_for_kw:
            # 优先从全局参数名表获取 Python 参数名（支持跨模块 include 函数）
            global_param_names = getattr(self.Trans, '_global_function_param_names', {})
            param_names = global_param_names.get(FullMethodName)
            if not param_names:
                param_names = global_param_names.get(f'{ClassName}.{MethodName}')
            if not param_names:
                # 回退到 LLVM 函数参数名（仅当参数名不是自动生成的数字名时有效）
                llvm_names = [arg.name for arg in func_for_kw.args] if func_for_kw.args else []
                # 检测是否为 LLVM 自动生成的数字名（如 "0", "1", "2"）
                if llvm_names and not all(n.isdigit() for n in llvm_names):
                    param_names = llvm_names
            if param_names:
                # 构造临时 call_args (含 self) 调用 _fill_default_args 填充默认值
                temp_call_args = [ObjVal] + list(CallArgs)
                self._fill_default_args(temp_call_args, func_for_kw, FullMethodName)
                # 提取回非 self 参数 (现在已填充默认值)
                CallArgs.clear()
                CallArgs.extend(temp_call_args[1:])
                # 用 keyword args 覆盖对应位置
                for kw in Node.keywords:
                    if kw.arg is None:
                        continue
                    ArgVal = self.HandleExprLlvm(kw.value)
                    if not ArgVal:
                        continue
                    kw_name = kw.arg
                    if kw_name in param_names:
                        idx = param_names.index(kw_name)
                        # idx 0 是 self, 所以 CallArgs 中的偏移是 idx-1
                        target_idx = idx - 1
                        if 0 <= target_idx < len(CallArgs):
                            CallArgs[target_idx] = ArgVal

        # 按需 vtable 注册：当 ClassName 不在 vtable 集合中但有 class_sha1 时，
        # 从 .pyi stub 检查 @t.CVTable 装饰器并注册。
        # 修复场景：list[str].__new__ 中 pool.alloc(48) 编译时，
        # MemManager 可能因导入时序问题未注册到当前 Gen 的 vtable 集合，
        # 导致生成 call_（直接调用）而非 vcall_（虚分派），运行时段错误。
        if (ClassName not in Gen.class_vtable
                and ClassName not in Gen._cross_module_vtable_classes
                and class_sha1):
            self._try_register_vtable_ondemand(ClassName, class_sha1, Gen)

        if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods:
            methods = Gen.class_methods[ClassName]
            method_idx = -1
            for mi, mn in enumerate(methods):
                if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'):
                    method_idx = mi
                    break
            if method_idx >= 0:
                func = Gen._find_function(FullMethodName)
                if not func:
                    func = Gen._find_function(f'{FullMethodName}__')
                if not func:
                    p = Gen.class_parent.get(ClassName)
                    while p:
                        parent_full = f'{p}.{MethodName}'
                        func = Gen._find_function(parent_full)
                        if not func:
                            func = Gen._find_function(f'{parent_full}__')
                        if func:
                            break
                        p = Gen.class_parent.get(p)
                if func:
                    VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
                    VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
                    VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
                    VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}")
                    MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}")
                    MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}")
                    FuncPtrType = ir.PointerType(func.function_type)
                    MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}")
                    call_args = [ObjVal] + CallArgs
                    self._fill_default_args(call_args, func, FullMethodName)
                    self._append_eh_msg_out_arg(call_args, func, Gen)
                    adjusted = Gen._adjust_args(call_args, func)
                    result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}")
                    self._check_eh_return(result, FullMethodName, Gen, called_func=func)
                    return result
        func = Gen._find_function(FullMethodName)
        if not func:
            func = Gen._find_function(f'{FullMethodName}__')
        if not func and class_sha1:
            stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FullMethodName, Gen)
            if stub_func_type:
                func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
        if not func and class_sha1:
            plain_name = f'{ClassName}.{MethodName}'
            stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen)
            if stub_func_type:
                func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
        # 最终回退：尝试无 sha1 前缀的函数名（与 func_for_kw 的双路径回退一致）
        if not func:
            plain_name = f'{ClassName}.{MethodName}'
            func = Gen._find_function(plain_name)
        if func:
            call_args = [ObjVal] + CallArgs
            self._fill_default_args(call_args, func, FullMethodName)
            self._append_eh_msg_out_arg(call_args, func, Gen)
            call_args = Gen._apply_auto_addr(FullMethodName, call_args)
            adjusted = Gen._adjust_args(call_args, func)
            result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}")
            self._check_eh_return(result, FullMethodName, Gen, called_func=func)
            return result
        i8ptr = ir.PointerType(ir.IntType(8))
        member_idx = -1
        if ClassName in Gen.class_members:
            for mi, (mn, mt) in enumerate(Gen.class_members[ClassName]):
                if mn == MethodName:
                    member_idx = mi
                    break
        if member_idx >= 0 and isinstance(ObjVal.type, ir.PointerType):
            has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes
            base = 1 if has_vtable else 0
            member_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + member_idx)], name=f"funcptr_{MethodName}_ptr")
            raw_ptr = Gen._load(member_ptr, name=f"funcptr_{MethodName}_raw")
            func_ptr_type = ir.PointerType(ir.FunctionType(ir.IntType(32), [i8ptr] + [a.type for a in CallArgs]))
            typed_ptr = Gen.builder.bitcast(raw_ptr, func_ptr_type, name=f"funcptr_{MethodName}_typed")
            obj_as_i8 = Gen.builder.bitcast(ObjVal, i8ptr, name=f"funcptr_self_{ClassName}")
            call_args = [obj_as_i8] + CallArgs
            result = Gen.builder.call(typed_ptr, call_args, name=f"call_funcptr_{ClassName}.{MethodName}")
            return result
        if class_sha1 and ClassName in Gen.structs:
            struct_type = Gen.structs[ClassName]
            self_ptr_type = ir.PointerType(struct_type)
            param_types = [self_ptr_type] + [a.type for a in CallArgs]
            func_type = ir.FunctionType(ir.IntType(32), param_types)
            func = ir.Function(Gen.module, func_type, name=FullMethodName)
            Gen.functions[FullMethodName] = func
            if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == struct_type:
                call_self = ObjVal
            else:
                call_self = Gen.builder.bitcast(ObjVal, self_ptr_type, name=f"method_self_{ClassName}")
            adjusted = Gen._adjust_args([call_self] + CallArgs, func)
            result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}")
            return result
        raise Exception(f"Undefined method '{MethodName}' in class '{ClassName}' (no function declaration found for '{FullMethodName}')")

    _C_LIB_FUNCS = {
        'malloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64)]),
        'calloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)]),
        'realloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
        'free': lambda: (ir.VoidType(), [ir.PointerType(ir.IntType(8))]),
        'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
        'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
        'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]),
        'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
        'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
        'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
        'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
        'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
        'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
        'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]),
        'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]),
        'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
        'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
        'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
        'abs': lambda: (ir.IntType(32), [ir.IntType(32)]),
        'labs': lambda: (ir.IntType(64), [ir.IntType(64)]),
        'system': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]),
    }

    def _try_declare_c_lib_func(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.Function | None:
        if func_name not in self._C_LIB_FUNCS:
            return None
        ret_type, param_types = self._C_LIB_FUNCS[func_name]()
        func_type = ir.FunctionType(ret_type, param_types)
        func = ir.Function(Gen.module, func_type, name=func_name)
        Gen.functions[func_name] = func
        return func

    def _HandleLenLlvm(self, arg_node: ast.AST) -> ir.Value | None:
        Gen = self.Trans.LlvmGen
        if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self':
            attr_name = arg_node.attr
            len_member = f'{attr_name}__len'
            current_class = self.Trans._CurrentCpythonObjectClass
            if current_class and current_class in Gen.class_members:
                for m_name, m_type in Gen.class_members[current_class]:
                    if m_name == len_member:
                        self_val = Gen._get_var_ptr('self')
                        if self_val:
                            self_ptr = Gen._load(self_val, name="self_for_len")
                            offset = Gen._get_member_offset(len_member, current_class)
                            len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr")
                            return Gen._load(len_ptr, name=f"self_{len_member}")
        val = self.HandleExprLlvm(arg_node)
        if not val:
            return None
        if isinstance(val.type, ir.PointerType):
            pointee = val.type.pointee
            if isinstance(pointee, ir.PointerType):
                val = Gen._load(val, name="len_deref")
                pointee = val.type.pointee
            if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                for CN, ST in Gen.structs.items():
                    if pointee == ST:
                        result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__len__', val, Gen)
                        if result is not None:
                            return result
                        break
            if isinstance(pointee, ir.ArrayType):
                return ir.Constant(ir.IntType(64), pointee.count)
            if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8:
                return ir.Constant(ir.IntType(64), 0)
            if val.type != ir.PointerType(ir.IntType(8)):
                val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast")
            correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))])
            strlen_func = None
            if 'strlen' in Gen.functions:
                existing = Gen.functions['strlen']
                if existing.ftype == correct_strlen_type:
                    strlen_func = existing
            if not strlen_func:
                try:
                    strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen')
                    Gen.functions['strlen'] = strlen_func
                except Exception as _e:
                    if _config_mode == "strict":
                        self.Trans.LogWarning(f"异常被忽略: {_e}")
            if strlen_func:
                result = Gen.builder.call(strlen_func, [val], name="strlen_call")
                return result
        elif isinstance(val.type, ir.ArrayType):
            return ir.Constant(ir.IntType(64), val.type.count)
        return ir.Constant(ir.IntType(64), 0)

    def _resolve_opaque_struct_members(self, struct_type: ir.Type, Gen: LlvmGeneratorMixin, _visited: set | None = None) -> None:
        """Recursively resolve opaque struct members by loading from stub files."""
        if _visited is None:
            _visited = set()
        if not isinstance(struct_type, ir.IdentifiedStructType):
            return
        # 防止循环引用导致无限递归
        try:
            st_id = id(struct_type)
        except Exception:
            st_id = struct_type
        if st_id in _visited:
            return
        _visited.add(st_id)
        if struct_type.elements is None or len(struct_type.elements) == 0:
            # Find the class name for this opaque struct and try to resolve
            for cn, st in Gen.structs.items():
                try:
                    if st == struct_type or (hasattr(st, 'name') and hasattr(struct_type, 'name') and st.name == struct_type.name):
                        self.Trans.ImportHandler._TryLoadStructFromStub(cn, Gen)
                        break
                except (AssertionError, RuntimeError):
                    pass
        # Re-get the struct in case it was resolved
        if struct_type.elements:
            for elem in struct_type.elements:
                if isinstance(elem, ir.IdentifiedStructType):
                    self._resolve_opaque_struct_members(elem, Gen, _visited)
                elif isinstance(elem, ir.PointerType):
                    pointee = elem.pointee
                    if isinstance(pointee, ir.IdentifiedStructType):
                        self._resolve_opaque_struct_members(pointee, Gen, _visited)

    def _resolve_type_arg_str(self, node: ast.AST) -> str:
        """将类型参数 AST 节点解析为规范化的类型字符串（用于泛型特化的 mangling）。

        走和普通类型签名同样的规范化路径（不单独创建规则）：
        - ast.Name: 若为已注册结构体，加 SHA1 前缀（如 'AST' → '9ada227b160c07a1.AST'），
          与 DeclarationGenerator._get_type_str 对 ast.Name 的处理一致
        - ast.Attribute: t.CPtr → 'ptr'（指针标记，等价于普通签名中 t.CPtr → i8* 的指针语义；
          用 'ptr' 而非 '*' 是因为 _get_or_create_struct 的 clean_name 会移除 '*'，
          导致 Phase2 直接编译与 .stub.ll 加载路径的 mangled 名不一致）；
          其他 t 模块类型按 CTypeRegistry.NameToLLVM 解析
        - ast.BinOp: 递归处理左右操作数并直接拼接（如 AST | t.CPtr → 'sha1.ASTptr'），
          避免空格/管道符导致 _get_or_create_struct 的 clean_name 清洗不一致
        """
        if isinstance(node, ast.Name):
            tn: str = node.id
            t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
            if tn in t_c_imported:
                src_module, src_name = t_c_imported[tn]
                return f'{src_module}.{src_name}'
            # 若为已注册结构体，加 SHA1 前缀（和普通签名路径一致）
            Gen = self.Trans.LlvmGen
            struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {}
            if tn in struct_sha1_map:
                return f'{struct_sha1_map[tn]}.{tn}'
            return tn
        if isinstance(node, ast.Attribute):
            if isinstance(node.value, ast.Name):
                full_name: str = f'{node.value.id}.{node.attr}'
                # t.CPtr → 'ptr'（指针标记，和普通签名中 t.CPtr 被解析为指针类型 i8* 语义一致）
                if full_name == 't.CPtr':
                    return 'ptr'
                # 其他 t 模块类型按 CTypeRegistry 解析（和普通签名路径一致）
                llvm_str: str | None = CTypeRegistry.NameToLLVM(node.attr)
                if llvm_str is not None:
                    return llvm_str
                return full_name
            return ast.unparse(node)
        if isinstance(node, ast.BinOp):
            left_str: str = self._resolve_type_arg_str(node.left)
            right_str: str = self._resolve_type_arg_str(node.right)
            # 直接拼接（如 'sha1.AST' + 'ptr' = 'sha1.ASTptr'），避免空格导致清洗不一致
            return f'{left_str}{right_str}'
        return ast.unparse(node)

    def _get_raw_type_name(self, node: ast.AST) -> str:
        """获取类型节点的原始名称（不带模块前缀），用于泛型 T 替换。

        ast.Name → sn.id (如 'AST', 'CInt')
        ast.Attribute → sn.attr (如 t.CInt → 'CInt')
        ast.BinOp → 左侧的原始名称 (如 AST | CPtr → 'AST')
        """
        if isinstance(node, ast.Name):
            return node.id
        if isinstance(node, ast.Attribute):
            return node.attr
        if isinstance(node, ast.BinOp):
            return self._get_raw_type_name(node.left)
        return ast.unparse(node)

    def _resolve_generic_slice_type(self, sn: ast.AST) -> tuple[str, str] | None:
        """解析泛型 slice 中的单个类型参数节点，返回 (type_arg, type_name) 或 None。

        type_arg: 用于 mangling，走和普通签名同样的规范化路径
                  （如 'AST | t.CPtr' → '9ada227b160c07a1.ASTptr'，AST 加 SHA1 前缀，t.CPtr 处理为 ptr）
        type_name: 用于替换泛型类型参数 T（如 'AST' 或 'CInt'，_specialize_generic_class 会自动加 | t.CPtr 给类名）
        """
        if isinstance(sn, ast.Name):
            tn: str = sn.id
            ts: str = 'int'
            if tn == 'int':
                ts, tn = 'int', 'CInt'
            elif tn == 'double':
                ts, tn = 'double', 'CDouble'
            elif tn == 'float':
                ts, tn = 'float', 'CFloat'
            elif tn == 'char':
                ts, tn = 'i8', 'CChar'
            elif tn == 'bool':
                ts, tn = 'i8', 'CBool'
            elif tn in ('CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'):
                ts = 'int'
            elif tn in ('CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'):
                ts = 'double'
            else:
                ts = tn
            return (ts, tn)
        # BinOp (如 AST | CPtr) 或 Attribute (如 t.CPtr / t.CInt)
        type_str: str = self._resolve_type_arg_str(sn)
        # type_name 取原始名称（不带模块前缀），用于 T 替换
        raw_name: str = self._get_raw_type_name(sn)
        return (type_str, raw_name)

    def _ResolveGenericSlice(self, Sub: ast.Subscript) -> str | None:
        """从泛型 Subscript (如 Stack[int]) 解析特化名，确保特化类型已生成。"""
        if not isinstance(Sub.value, ast.Name):
            return None
        ClassName: str = Sub.value.id
        if not (hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates):
            return None
        Gen = self.Trans.LlvmGen
        # 共享符号表构建阶段（_build_shared_symbol_data / ParsePythonFile）LlvmGen 为 None，
        # 此时不应发射特化 IR；调用方（GetCTypeInfo）已用 mangled 名设置符号表信息
        if Gen is None:
            return None
        template: dict = self.Trans.ClassHandler._generic_class_templates[ClassName]
        type_param_names: list[str] = template['type_params']
        type_args: list[str] = []
        type_names: list[str] = []
        slice_nodes: list[ast.AST] = []
        if isinstance(Sub.slice, ast.Tuple):
            slice_nodes = list(Sub.slice.elts)
        else:
            slice_nodes = [Sub.slice]
        for sn in slice_nodes:
            result = self._resolve_generic_slice_type(sn)
            if result is not None:
                type_args.append(result[0])
                type_names.append(result[1])
        while len(type_args) < len(type_param_names):
            type_args.append('int')
            type_names.append('CInt')
        return self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)

    @staticmethod
    def _AnnotationContainsCPtr(Node: ast.AST) -> bool:
        """检查类型注解 AST 是否包含 t.CPtr（即是否为指针类型）"""
        if isinstance(Node, ast.Attribute):
            if Node.attr == 'CPtr':
                return True
        if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
            return (ExprCallHandle._AnnotationContainsCPtr(Node.left)
                    or ExprCallHandle._AnnotationContainsCPtr(Node.right))
        return False

    @staticmethod
    def _is_sizeof_type_name(name: str, Gen: "LlvmGeneratorMixin") -> bool:
        """检查名称是否是已知的类型名（用于 __sizeof__ 上下文）。
        检查顺序: Gen.structs → SHA1 前缀 → 内建类型 → CTypeRegistry
        """
        if not name:
            return False
        # 1. 直接在 Gen.structs 中查找
        if name in Gen.structs:
            return True
        # 2. 带 SHA1 前缀查找（如 ClassDef → 657e182b27c2a022.ClassDef）
        struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
        if name in struct_sha1_map:
            return True
        # 遍历所有 SHA1 前缀
        for sha1 in struct_sha1_map.values():
            prefixed = f"{sha1}.{name}"
            if prefixed in Gen.structs:
                return True
        # 3. 内建类型名
        if name in ('str', 'bytes', 'int', 'double', 'float', 'char', 'bool',
                     'void', 'i8', 'i16', 'i32', 'i64', 'half', 'fp128'):
            return True
        # 4. CTypeRegistry 中的类型
        if CTypeRegistry.GetClassByName(name) is not None:
            return True
        if CTypeRegistry.ResolveName(name):
            return True
        return False

    def _HandleSizeofLlvm(self, Node: ast.AST) -> ir.Constant:
        Gen = self.Trans.LlvmGen
        if isinstance(Node, ast.Name):
            type_name = Node.id
        elif isinstance(Node, ast.Attribute):
            type_name = Node.attr
        else:
            return ir.Constant(ir.IntType(64), 0)

        if type_name not in Gen.structs:
            # SHA1 前缀查找：如 ClassDef → 657e182b27c2a022.ClassDef
            struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
            resolved_name: str | None = None
            if type_name in struct_sha1_map:
                resolved_name = f"{struct_sha1_map[type_name]}.{type_name}"
            else:
                for sha1 in struct_sha1_map.values():
                    prefixed = f"{sha1}.{type_name}"
                    if prefixed in Gen.structs:
                        resolved_name = prefixed
                        break
            if resolved_name is not None and resolved_name in Gen.structs:
                type_name = resolved_name
        if type_name not in Gen.structs:
            # str/bytes 是指针类型 (char*/void*)，sizeof = 指针大小
            if type_name in ('str', 'bytes'):
                return ir.Constant(ir.IntType(64), 8)
            ctype_cls = CTypeRegistry.GetClassByName(type_name)
            if ctype_cls is not None:
                try:
                    ctype_inst = ctype_cls()
                    size_bits = getattr(ctype_inst, 'Size', 0) or 0
                    size_bytes = size_bits // 8
                    return ir.Constant(ir.IntType(64), size_bytes)
                except Exception as _e:
                    if _config_mode == "strict":
                        raise
                    _vlog().warning(f"解析类型失败: {_e}", "Exception")
            resolved = CTypeRegistry.ResolveName(type_name)
            if resolved:
                ctype_cls, ptr_level = resolved
                try:
                    ctype_inst = ctype_cls()
                    size_bits = getattr(ctype_inst, 'Size', 0) or 0
                    size_bytes = size_bits // 8
                    if ptr_level > 0:
                        size_bytes = 8
                    return ir.Constant(ir.IntType(64), size_bytes)
                except Exception as _e:
                    if _config_mode == "strict":
                        raise
                    _vlog().warning(f"解析类型失败: {_e}", "Exception")
            # 所有查找策略均失败（不在 Gen.structs、SHA1 前缀查找失败、CTypeRegistry 也找不到）：
            # 报错终止，拒绝静默返回 0（会导致 malloc(0)/alloc(0) 堆溢出）
            raise ValueError(
                f"[FATAL][__sizeof__] 类型 '{type_name}' 无法解析"
                f"（不在 Gen.structs、SHA1 前缀查找失败、CTypeRegistry 也找不到），"
                f"拒绝静默返回 0"
            )

        struct_type = Gen.structs[type_name]
        if isinstance(struct_type, ir.PointerType):
            struct_type = struct_type.pointee
        # 保存 builder 状态：_TryLoadStructFromStub / _resolve_opaque_struct_members
        # 可能触发重入编译（编译其他模块的函数），这会改变 Gen.func/Gen.builder，
        # 导致当前函数的指令被写到错误函数的 block 中（then 块为空的根因）
        _saved_func = Gen.func
        _saved_builder = Gen.builder
        _saved_block = Gen.builder.block if (Gen.builder and Gen.builder.block) else None
        _saved_variables = dict(Gen.variables) if Gen.variables else {}
        _saved_reg_values = dict(getattr(Gen, '_reg_values', {}))
        _saved_direct_values = dict(getattr(Gen, '_direct_values', {}))
        _saved_var_type_info = dict(getattr(Gen, 'var_type_info', {}))
        _saved_var_signedness = dict(getattr(Gen, 'var_signedness', {}))
        _saved_global_vars = set(getattr(Gen, 'global_vars', set()))
        _saved_var_scopes = [dict(s) for s in getattr(self.Trans, 'VarScopes', [])]
        try:
            if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0):
                self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen)
                struct_type = Gen.structs.get(type_name, struct_type)
            # Recursively resolve opaque struct members
            self._resolve_opaque_struct_members(struct_type, Gen)
        finally:
            Gen.func = _saved_func
            Gen.builder = _saved_builder
            if _saved_block is not None and Gen.builder is not None:
                Gen.builder.position_at_end(_saved_block)
            Gen.variables = _saved_variables
            Gen._reg_values = _saved_reg_values
            Gen._direct_values = _saved_direct_values
            Gen.var_type_info = _saved_var_type_info
            Gen.var_signedness = _saved_var_signedness
            Gen.global_vars = _saved_global_vars
            self.Trans.VarScopes = _saved_var_scopes
        size = Gen._get_struct_size(struct_type)
        if size > 0:
            return ir.Constant(ir.IntType(64), size)
        return ir.Constant(ir.IntType(64), 0)

    def _HandleAbsLlvm(self, arg_node: ast.AST) -> ir.Value | None:
        Gen = self.Trans.LlvmGen
        val = self.HandleExprLlvm(arg_node)
        if not val:
            return None
        if isinstance(val.type, ir.PointerType):
            pointee = val.type.pointee
            if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                for CN, ST in Gen.structs.items():
                    if pointee == ST:
                        result = self.Trans.ExprUtils._try_operator_overLoad(CN, '__abs__', val, Gen)
                        if result is not None:
                            return result
                        break
        if isinstance(val.type, ir.IntType):
            neg_val = Gen.builder.neg(val, name="abs_neg")
            is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg")
            return Gen.builder.select(is_neg, neg_val, val, name="abs_result")
        elif isinstance(val.type, (ir.FloatType, ir.DoubleType)):
            zero = ir.Constant(val.type, 0.0)
            neg_val = Gen.builder.fneg(val, name="fabs_neg")
            is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg")
            return Gen.builder.select(is_neg, neg_val, val, name="fabs_result")
        return None

    def _HandleDirLlvm(self, Node: ast.Call) -> ir.Constant:
        Gen = self.Trans.LlvmGen
        return ir.Constant(ir.IntType(8).as_pointer(), None)

    def _HandleTypeLlvm(self, Node: ast.Call) -> ir.Value:
        Gen = self.Trans.LlvmGen
        if not Node.args:
            type_str = "<class 'unknown' size=0 signed=false, ptr=false>"
        else:
            arg = Node.args[0]
            enum_type_name = None

            def _get_attr_path(node):
                if isinstance(node, ast.Name):
                    return node.id
                elif isinstance(node, ast.Attribute):
                    return f"{_get_attr_path(node.value)}.{node.attr}"
                return None

            if isinstance(arg, ast.Name):
                arg_name = arg.id
                Gen = self.Trans.LlvmGen
                if arg_name in Gen.var_type_info:
                    type_info = Gen.var_type_info[arg_name]
                    if isinstance(type_info, dict) and type_info.get('type') == 'enum':
                        enum_type_name = type_info.get('name')
                if not enum_type_name:
                    TypeInfo = self.Trans.SymbolTable.lookup(arg_name)
                    if TypeInfo and TypeInfo.IsEnum:
                        enum_type_name = arg_name
            elif isinstance(arg, ast.Attribute):
                LastPart = None
                enum_class_name = None
                if isinstance(arg.value, ast.Name):
                    LastPart = arg.attr
                    AttrInfo = self.Trans.SymbolTable.lookup(LastPart)
                    if AttrInfo and AttrInfo.IsEnumMember and AttrInfo.EnumName:
                        enum_type_name = AttrInfo.EnumName
                elif isinstance(arg.value, ast.Attribute):
                    attr_path = _get_attr_path(arg)
                    if attr_path:
                        parts = attr_path.split('.')
                        if len(parts) >= 2:
                            enum_class_name = parts[-2]
                            LastPart = parts[-1]
                            qualified_name_dot = f"{enum_class_name}.{LastPart}"
                            qualified_name_under = f"{enum_class_name}_{LastPart}"
                            enum_member_found = None
                            for qname in (qualified_name_dot, qualified_name_under):
                                info = self.Trans.SymbolTable.lookup(qname)
                                if info and info.IsEnumMember and info.EnumName == enum_class_name:
                                    enum_member_found = info
                                    break
                            if not enum_member_found:
                                for key in self.Trans.SymbolTable:
                                    if key == LastPart:
                                        info = self.Trans.SymbolTable[key]
                                        if info.IsEnumMember and info.EnumName == enum_class_name:
                                            enum_member_found = info
                                            break
                            if enum_member_found:
                                enum_type_name = enum_class_name
            if enum_type_name:
                type_str = f"<enum '{enum_type_name}' size=4 signed=true, ptr=false>"
            else:
                llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg)
                if isinstance(llvm_type, ir.PointerType):
                    pointee = llvm_type.pointee
                    if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                        llvm_type = pointee
                type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type)
                type_str = f"<class '{type_info['name']}' size={type_info['size']} signed={str(type_info['signed']).lower()}, ptr={str(type_info['ptr']).lower()}>"
        return Gen.emit_constant(type_str, 'string')

    def _HandleInputLlvm(self, Node: ast.Call) -> ir.Value:
        Gen = self.Trans.LlvmGen
        if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str):
            prompt = Node.args[0].value
            prompt_ptr = Gen.emit_constant(prompt, 'string')
            printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
            Gen.builder.call(printf_func, [prompt_ptr])
        scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True))
        input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer")
        result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer])
        return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result")

    def _HandleAtoiLlvm(self, str_ptr: ir.Value) -> ir.Value:
        Gen = self.Trans.LlvmGen
        atoi_func = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))]))
        return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result")

    def _HandleOrdLlvm(self, expr_node: ast.AST) -> ir.Value:
        Gen = self.Trans.LlvmGen
        val = self.HandleExprLlvm(expr_node)
        if val and self._is_char_pointer(val):
            return Gen._load(val, name="ord_result")
        return ir.Constant(ir.IntType(32), 0)

    def _HandleChrLlvm(self, expr_node: ast.AST) -> ir.Value:
        Gen = self.Trans.LlvmGen
        val = self.HandleExprLlvm(expr_node)
        if val:
            char_ptr = Gen._alloca(ir.IntType(8), name="chr_char")
            Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr)
            return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result")
        return ir.Constant(ir.IntType(8).as_pointer(), None)

    def _EmitStringFromValue(self, val: ir.Value) -> ir.Value:
        Gen = self.Trans.LlvmGen
        if isinstance(val.type, ir.IntType):
            buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32))
            snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [
                ir.PointerType(ir.IntType(8)),
                ir.IntType(32),
                ir.PointerType(ir.IntType(8))
            ]))
            fmt_ptr = Gen.emit_constant("%d", 'string')
            Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(32), 32), fmt_ptr, val])
            return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
        return ir.Constant(ir.IntType(8).as_pointer(), None)

    def _HandleMallocLlvm(self, args: list[ast.AST]) -> ir.Value:
        Gen = self.Trans.LlvmGen
        malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
        malloc_func = Gen._get_or_declare_func('malloc', malloc_type)
        param_type = malloc_func.type.pointee.args[0]
        size_val = None
        if args:
            size_val = self.HandleExprLlvm(args[0])
            if size_val and isinstance(size_val.type, ir.IntType):
                if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width:
                    if size_val.type.width < param_type.width:
                        size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size")
                    else:
                        size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size")
        if not size_val:
            size_val = ir.Constant(param_type, 1)
        result = Gen.builder.call(malloc_func, [size_val], name="malloc_result")
        return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast")

    def _HandleReallocLlvm(self, args: list[ast.AST]) -> ir.Value:
        Gen = self.Trans.LlvmGen
        realloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)])
        realloc_func = Gen._get_or_declare_func('realloc', realloc_type)
        size_param_type = realloc_func.type.pointee.args[1]
        ptr_val = None
        size_val = None
        if len(args) >= 2:
            ptr_val = self.HandleExprLlvm(args[0])
            size_val = self.HandleExprLlvm(args[1])
        elif len(args) == 1:
            size_val = self.HandleExprLlvm(args[0])
        if not ptr_val:
            ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None)
        if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val):
            ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr")
        if size_val and isinstance(size_val.type, ir.IntType):
            if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width:
                if size_val.type.width < size_param_type.width:
                    size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size")
                else:
                    size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size")
        if not size_val:
            size_val = ir.Constant(size_param_type, 0)
        result = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result")
        return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast")

    def _HandleFreeLlvm(self, args: list[ast.AST]) -> ir.Constant:
        Gen = self.Trans.LlvmGen
        free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])
        free_func = Gen._get_or_declare_func('free', free_type)
        if args:
            var_name = None
            if isinstance(args[0], ast.Name):
                var_name = args[0].id
            ptr_val = self.HandleExprLlvm(args[0])
            if ptr_val:
                if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr:
                    registered_val = Gen._var_to_heap_ptr[var_name]
                    Gen._unregister_local_heap_ptr(registered_val)
                    del Gen._var_to_heap_ptr[var_name]
                if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val):
                    ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr")
                Gen.builder.call(free_func, [ptr_val], name="free_call")
        return ir.Constant(ir.IntType(32), 0)

    def _HandleMemcpyLlvm(self, args: list[ast.AST]) -> None:
        Gen = self.Trans.LlvmGen
        if 'llvm.memcpy' not in Gen.functions:
            memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)])
            Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy')
        if len(args) >= 3:
            dst = self.HandleExprLlvm(args[0])
            src = self.HandleExprLlvm(args[1])
            size = self.HandleExprLlvm(args[2])
            if dst and src and size:
                i8ptr = ir.PointerType(ir.IntType(8))
                if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr:
                    dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast")
                elif isinstance(dst.type, ir.IntType):
                    if dst.type.width < 64:
                        dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr")
                    dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr")
                if isinstance(src.type, ir.PointerType) and src.type != i8ptr:
                    src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast")
                elif isinstance(src.type, ir.IntType):
                    if src.type.width < 64:
                        src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr")
                    src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr")
                if isinstance(size.type, ir.IntType) and size.type.width < 64:
                    size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size")
                isvolatile = ir.Constant(ir.IntType(1), 0)
                Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call")
        return None

    def _HandleMemsetLlvm(self, args: list[ast.AST]) -> None:
        Gen = self.Trans.LlvmGen
        memset_func = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]))
        if len(args) >= 3:
            dst = self.HandleExprLlvm(args[0])
            val = self.HandleExprLlvm(args[1])
            size = self.HandleExprLlvm(args[2])
            if dst and val is not None and size:
                if isinstance(dst.type, ir.PointerType) and not self._is_char_pointer(dst):
                    dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast")
                if isinstance(val.type, ir.IntType) and val.type.width != 32:
                    if val.type.width < 32:
                        val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val")
                    else:
                        val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val")
                if isinstance(size.type, ir.IntType) and size.type.width < 64:
                    size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size")
                elif isinstance(size.type, ir.IntType) and size.type.width > 64:
                    size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size")
                Gen.builder.call(memset_func, [dst, val, size], name="memset_call")
        return None

    def _HandleVaStartLlvm(self, args: list[ast.AST]) -> None:
        Gen = self.Trans.LlvmGen
        return None

    def _HandleVaEndLlvm(self, args: list[ast.AST]) -> None:
        Gen = self.Trans.LlvmGen
        return None

    def _HandleArgLlvm(self, args: list[ast.AST], CallNode: ast.Call | None = None) -> ir.Value | None:
        Gen = self.Trans.LlvmGen
        va_list_ptr = None
        variadic_info = getattr(Gen, '_va_arg_info', None)
        if not variadic_info:
            variadic_info = getattr(Gen, '_variadic_info', None)
        if variadic_info:
            va_list_ptr = variadic_info.get('va_list_ptr')
        if not va_list_ptr:
            vararg_name = variadic_info.get('vararg_name', 'args') if variadic_info else 'args'
            if vararg_name in Gen._direct_values:
                va_list_ptr = Gen._direct_values[vararg_name]
            elif vararg_name in Gen.variables:
                va_list_ptr = Gen.variables[vararg_name]
        if not va_list_ptr:
            return ir.Constant(ir.IntType(32), 0)
        target_type = ir.IntType(32)
        if args:
            type_arg = args[0]
            if isinstance(type_arg, ast.Name):
                type_name = type_arg.id
                if type_name in ('str', 'bytes'):
                    target_type = ir.PointerType(ir.IntType(8))
                elif type_name == 'CPtr':
                    target_type = ir.PointerType(ir.IntType(8))
                elif type_name in Gen.structs:
                    target_type = ir.PointerType(Gen.structs[type_name])
                else:
                    ctype_cls = CTypeRegistry.GetClassByName(type_name)
                    if ctype_cls is not None:
                        llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
                        resolved = Gen._type_str_to_llvm(llvm_str)
                        if resolved:
                            target_type = resolved
                    else:
                        resolved = CTypeRegistry.ResolveName(type_name)
                        if resolved is not None:
                            ctype_cls, ptr_level = resolved
                            llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
                            if llvm_str:
                                base = Gen._type_str_to_llvm(llvm_str)
                                if base is not None:
                                    for _ in range(ptr_level):
                                        if isinstance(base, ir.VoidType):
                                            base = ir.IntType(8).as_pointer()
                                        else:
                                            base = ir.PointerType(base)
                                    target_type = base
            elif isinstance(type_arg, ast.Attribute):
                if isinstance(type_arg.value, ast.Name) and IsTModule(type_arg.value.id, self.Trans.SymbolTable):
                    attr_name = type_arg.attr
                    ctype_cls = CTypeRegistry.GetClassByName(attr_name)
                    if ctype_cls is not None:
                        llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
                        resolved = Gen._type_str_to_llvm(llvm_str)
                        if resolved:
                            target_type = resolved
        else:
            assign_node = getattr(self.Trans, '_current_assign_node', None)
            if assign_node:
                ann = getattr(assign_node, 'annotation', None)
                if ann:
                    ann_name = None
                    if isinstance(ann, ast.Name):
                        ann_name = ann.id
                    elif isinstance(ann, ast.Attribute):
                        ann_name = ann.attr
                    elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
                        ann_name = ExtractTypeNameFromBinOp(ann)
                    if ann_name:
                        ctype_cls = CTypeRegistry.GetClassByName(ann_name)
                        if ctype_cls is not None:
                            llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls)
                            resolved = Gen._type_str_to_llvm(llvm_str)
                            if resolved:
                                target_type = resolved
                        elif ann_name in Gen.structs:
                            target_type = ir.PointerType(Gen.structs[ann_name])
        va_arg_counter = getattr(Gen, '_va_arg_counter', 0)
        Gen._va_arg_counter = va_arg_counter + 1
        result = Gen.emit_va_arg(va_list_ptr, target_type)
        if result is not None and getattr(result, 'name', ''):
            result.name = f"va_arg_result_{Gen._va_arg_counter}"
        return result

    def _HandleVaArgLlvm(self, args: list[ast.AST]) -> ir.Constant:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        return ir.Constant(ir.IntType(32), 0)

    def _HandleCDerefAsLlvm(self, Node: ast.Call) -> ir.Constant:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        if len(Node.args) < 2:
            return ir.Constant(ir.IntType(32), 0)
        ptr_val: ir.Value | None = self.HandleExprLlvm(Node.args[0])
        val_val: ir.Value | None = self.HandleExprLlvm(Node.args[1])
        if ptr_val is None or val_val is None:
            return ir.Constant(ir.IntType(32), 0)
        if isinstance(ptr_val.type, ir.PointerType):
            store_val: ir.Value = val_val
            # 两端均为指向同一结构体类型的指针时执行结构体拷贝（*ptr = *val），
            # 而非存储指针值。这对 REnum 变体构造（c.DerefAs(ptr, LLVMType.Int(32))) 至关重要。
            if (isinstance(val_val.type, ir.PointerType) and
                    isinstance(ptr_val.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)) and
                    ptr_val.type.pointee == val_val.type.pointee):
                loaded: ir.Value = Gen._load(val_val, name="deref_as_struct_load")
                Gen._store(loaded, ptr_val)
                return ir.Constant(ir.IntType(32), 0)
            if isinstance(val_val.type, ir.PointerType):
                void_pp: ir.PointerType = ir.PointerType(ir.PointerType(ir.IntType(8)))
                if ptr_val.type != void_pp:
                    ptr_val = Gen.builder.bitcast(ptr_val, void_pp, name="deref_as_pp")
                if val_val.type.pointee != ir.IntType(8):
                    store_val = Gen.builder.bitcast(val_val, ir.PointerType(ir.IntType(8)), name="deref_as_vp")
            elif isinstance(val_val.type, ir.IntType) and isinstance(ptr_val.type.pointee, ir.IntType):
                if val_val.type.width != ptr_val.type.pointee.width:
                    if ptr_val.type.pointee.width == 8 and val_val.type.width > 8:
                        target_ptr_type = ir.PointerType(val_val.type)
                        ptr_val = Gen.builder.bitcast(ptr_val, target_ptr_type, name="deref_as_cast")
                    elif val_val.type.width < ptr_val.type.pointee.width:
                        store_val = Gen.builder.zext(val_val, ptr_val.type.pointee, name="deref_as_zext")
                    else:
                        store_val = Gen.builder.trunc(val_val, ptr_val.type.pointee, name="deref_as_trunc")
            elif isinstance(val_val.type, ir.IntType) and isinstance(ptr_val.type.pointee, ir.PointerType):
                if val_val.type.width == 64:
                    store_val = Gen.builder.inttoptr(val_val, ptr_val.type.pointee, name="deref_as_inttoptr")
                else:
                    ext = Gen.builder.zext(val_val, ir.IntType(64), name="deref_as_zext")
                    store_val = Gen.builder.inttoptr(ext, ptr_val.type.pointee, name="deref_as_inttoptr")
            elif val_val.type != ptr_val.type.pointee:
                target_ptr_type = ir.PointerType(val_val.type)
                ptr_val = Gen.builder.bitcast(ptr_val, target_ptr_type, name="deref_as_cast")
            Gen.builder.store(store_val, ptr_val)
        return ir.Constant(ir.IntType(32), 0)

    def _InjectRequiresFields(self, result: ir.Value, ClassName: str, Gen: LlvmGeneratorMixin) -> None:
        """在 __new__ 后、__init__ 前自动注入 __requires__/__require_must__ 字段。

        - 编译期：对 __require_must__ 做纯静态可达性检查（遍历 _with_provides_stack）
        - 运行时：对每个 requires 字段调用 _find_provider，非 NULL 则 bitcast 写入
        """
        requires_all: list[str] = []
        requires_all.extend(Gen.class_requires.get(ClassName, []))
        requires_all.extend(Gen.class_require_must.get(ClassName, []))
        if not requires_all:
            return
        # 编译期 __require_must__ 静态检查
        must_fields: list[str] = Gen.class_require_must.get(ClassName, [])
        if must_fields:
            # 跳过类自身方法内的检查（类的实现内部不需要 with 上下文）
            current_class = getattr(Gen, '_current_class_name', None)
            if current_class != ClassName:
                available: set[str] = set()
                for provides_list in Gen._with_provides_stack:
                    available.update(provides_list)
                for field in must_fields:
                    if field not in available:
                        raise SyntaxError(
                            f"[TransPyC] Class '{ClassName}' __require_must__ field '{field}' "
                            f"not provided by any enclosing 'with' context"
                        )
        # 运行时注入
        find_func = Gen.functions.get('_find_provider')
        if not find_func:
            return
        members = Gen.class_members.get(ClassName, [])
        has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes
        base = 1 if has_vtable else 0
        field_map: dict[str, tuple[int, ir.Type]] = {}
        for i, (mname, mtype) in enumerate(members):
            if mname in requires_all:
                field_map[mname] = (base + i, mtype)
        for field_name in requires_all:
            if field_name not in field_map:
                continue
            field_idx, field_type = field_map[field_name]
            field_str = Gen._create_string_global(field_name)
            ptr_val = Gen.builder.call(find_func, [field_str], name=f"find_{field_name}")
            null_ptr = ir.Constant(ptr_val.type, None)
            is_null = Gen.builder.icmp_unsigned('==', ptr_val, null_ptr, name=f"is_null_{field_name}")
            skip_bb = Gen.func.append_basic_block(f"skip_inject_{field_name}")
            inject_bb = Gen.func.append_basic_block(f"inject_{field_name}")
            Gen.builder.cbranch(is_null, skip_bb, inject_bb)
            Gen.builder.position_at_end(inject_bb)
            if isinstance(field_type, ir.PointerType):
                casted = Gen.builder.bitcast(ptr_val, field_type, name=f"cast_{field_name}")
            elif isinstance(field_type, ir.IntType):
                casted = Gen.builder.ptrtoint(ptr_val, field_type, name=f"cast_{field_name}")
            else:
                casted = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name=f"cast_{field_name}")
            elem_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), field_idx)], name=f"field_{field_name}_ptr")
            Gen._store(casted, elem_ptr)
            Gen.builder.branch(skip_bb)
            Gen.builder.position_at_end(skip_bb)

    def _HandleClassNewLlvm(self, Node: ast.Call, ClassName: str, module_sha1: str | None = None) -> ir.Value:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        # 跨模块类型引用：优先用 {module_sha1}.{ClassName} 查找 struct
        _struct_full_key: str | None = f"{module_sha1}.{ClassName}" if module_sha1 else None

        def _get_struct_type(name: str) -> ir.Type | None:
            """优先用 SHA1 前缀完整名查找，回退到短名"""
            if _struct_full_key and _struct_full_key in Gen.structs:
                return Gen.structs[_struct_full_key]
            return Gen.structs.get(name)

        if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates:
            return self._HandleGenericClassNewLlvm(Node, ClassName)
        NewFuncName = f'{ClassName}.__before_init__'
        InitFuncName = f'{ClassName}.__init__'
        NewMethodFuncName = f'{ClassName}.__new__'
        has_new_method = Gen._find_function(NewMethodFuncName) is not None
        if Gen._has_function(NewFuncName):
            NewFunc = Gen._get_function(NewFuncName)
            StructType = _get_struct_type(ClassName)
            if StructType:
                result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca")
            else:
                return ir.Constant(ir.IntType(32), 0)
            Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}")
            if has_new_method:
                NewMethodFunc = Gen._find_function(NewMethodFuncName)
                if NewMethodFunc:
                    NewMethodArgs = [result]
                    for arg in Node.args:
                        ArgVal = self.HandleExprLlvm(arg)
                        if ArgVal:
                            NewMethodArgs.append(ArgVal)
                    self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName)
                    self._ApplyKeywordArgs(Node, NewMethodArgs, NewMethodFunc, NewMethodFuncName, self_offset=1)
                    NewMethodArgs = Gen._apply_auto_addr(NewMethodFuncName, NewMethodArgs)
                    adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc)
                    heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}")
                    if heap_ptr:
                        target_ptr_type = ir.PointerType(StructType) if StructType else None
                        if isinstance(heap_ptr.type, ir.PointerType):
                            # Bitcast the returned pointer to the struct pointer type if needed
                            if target_ptr_type and heap_ptr.type != target_ptr_type:
                                result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast")
                            else:
                                result = heap_ptr
                        elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type:
                            # __new__ returned an integer (pointer as int), convert back to pointer
                            if heap_ptr.type.width < 64:
                                i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64")
                                result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr")
                            else:
                                result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr")
            # __new__ 后：对堆指针重新调用 __before_init__ 初始化默认值（alloca 的默认值已随 alloca 丢弃）
            if has_new_method:
                Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}_heap")
            # __new__ 后、__init__ 前：自动注入 requires 字段
            self._InjectRequiresFields(result, ClassName, Gen)
            if Gen._has_function(InitFuncName):
                InitFunc = Gen._get_function(InitFuncName)
                InitArgs = [result]
                for arg in Node.args:
                    ArgVal = self.HandleExprLlvm(arg)
                    if ArgVal:
                        InitArgs.append(ArgVal)
                self._fill_default_args(InitArgs, InitFunc, InitFuncName)
                self._ApplyKeywordArgs(Node, InitArgs, InitFunc, InitFuncName, self_offset=1)
                self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen)
                InitArgs = Gen._apply_auto_addr(InitFuncName, InitArgs)
                adjusted_init = Gen._adjust_args(InitArgs, InitFunc)
                Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}")
            return result
        if _struct_full_key and _struct_full_key in Gen.structs:
            StructType = Gen.structs[_struct_full_key]
            if isinstance(StructType, ir.PointerType):
                StructType = StructType.pointee
            is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0)
            if is_opaque:
                self._ensure_struct_declared(ClassName, module_sha1=module_sha1)
                StructType = Gen.structs.get(_struct_full_key, Gen.structs.get(ClassName, StructType))
                if isinstance(StructType, ir.PointerType):
                    StructType = StructType.pointee
                is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0)
            if is_opaque:
                return None
        elif ClassName in Gen.structs:
            StructType = Gen.structs[ClassName]
            if isinstance(StructType, ir.PointerType):
                StructType = StructType.pointee
            is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0)
            if is_opaque:
                self._ensure_struct_declared(ClassName, module_sha1=module_sha1)
                StructType = Gen.structs.get(ClassName, StructType)
                if isinstance(StructType, ir.PointerType):
                    StructType = StructType.pointee
                is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0)
            if is_opaque:
                return None
            result = Gen._allocaEntry(StructType, name=f"{ClassName}_alloca")
            # Call __new__ method if it exists (may replace self with heap pointer)
            if has_new_method:
                NewMethodFunc = Gen._find_function(NewMethodFuncName)
                if NewMethodFunc:
                    NewMethodArgs = [result]
                    for arg in Node.args:
                        ArgVal = self.HandleExprLlvm(arg)
                        if ArgVal:
                            NewMethodArgs.append(ArgVal)
                    self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName)
                    self._ApplyKeywordArgs(Node, NewMethodArgs, NewMethodFunc, NewMethodFuncName, self_offset=1)
                    NewMethodArgs = Gen._apply_auto_addr(NewMethodFuncName, NewMethodArgs)
                    adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc)
                    heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}")
                    if heap_ptr:
                        target_ptr_type = ir.PointerType(StructType) if StructType else None
                        if isinstance(heap_ptr.type, ir.PointerType):
                            # Bitcast the returned pointer to the struct pointer type if needed
                            if target_ptr_type and heap_ptr.type != target_ptr_type:
                                result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast")
                            else:
                                result = heap_ptr
                        elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type:
                            # __new__ returned an integer (pointer as int), convert back to pointer
                            if heap_ptr.type.width < 64:
                                i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64")
                                result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr")
                            else:
                                result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr")
            # __new__ 后：对堆指针调用 __before_init__ 初始化默认值
            if has_new_method and Gen._has_function(NewFuncName):
                NewFunc = Gen._get_function(NewFuncName)
                Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}_heap")
            # __new__ 后、__init__ 前：自动注入 requires 字段
            self._InjectRequiresFields(result, ClassName, Gen)
            InitFunc = Gen.functions.get(InitFuncName)
            if not InitFunc:
                g = Gen.module.globals.get(InitFuncName)
                if g and isinstance(g, ir.Function):
                    Gen.functions[InitFuncName] = g
                    InitFunc = g
            if InitFunc:
                InitArgs = [result]
                init_param_types = InitFunc.function_type.args if hasattr(InitFunc, 'function_type') else []
                for i, arg in enumerate(Node.args):
                    arg_var_type = init_param_types[i + 1] if i + 1 < len(init_param_types) else None
                    ArgVal = self.HandleExprLlvm(arg, VarType=arg_var_type)
                    if ArgVal:
                        InitArgs.append(ArgVal)
                self._fill_default_args(InitArgs, InitFunc, InitFuncName)
                self._ApplyKeywordArgs(Node, InitArgs, InitFunc, InitFuncName, self_offset=1)
                self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen)
                InitArgs = Gen._apply_auto_addr(InitFuncName, InitArgs)
                adjusted_init = Gen._adjust_args(InitArgs, InitFunc)
                Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}")
            elif Node.args or Node.keywords:
                self._InitStructDefaults(result, ClassName, StructType)
                self._InitStructFromArgs(result, Node, ClassName, StructType)
            else:
                self._InitStructDefaults(result, ClassName, StructType)
            return result
        return ir.Constant(ir.IntType(32), 0)

    def _ZeroInitStruct(self, struct_ptr: ir.Value, StructType: ir.Type) -> None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        if isinstance(StructType, ir.IdentifiedStructType) and StructType.elements:
            for i, elem_type in enumerate(StructType.elements):
                elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"zero_elem_{i}")
                zero_val = self._GetZeroValue(elem_type)
                if zero_val is not None:
                    Gen._store(zero_val, elem_ptr)
        elif isinstance(StructType, ir.IntType):
            Gen._store(ir.Constant(StructType, 0), struct_ptr)
        elif isinstance(StructType, ir.ArrayType) and isinstance(StructType.pointee, ir.IntType):
            zero_arr = ir.Constant(StructType, None)
            Gen._store(zero_arr, struct_ptr)

    def _GetZeroValue(self, typ: ir.Type) -> ir.Constant | None:
        if isinstance(typ, ir.IntType):
            return ir.Constant(typ, 0)
        elif isinstance(typ, ir.PointerType):
            return ir.Constant(typ, None)
        elif isinstance(typ, (ir.FloatType, ir.DoubleType)):
            return ir.Constant(typ, 0.0)
        elif isinstance(typ, ir.ArrayType):
            return ir.Constant(typ, None)
        return None

    def _InitStructDefaults(self, struct_ptr: ir.Value, ClassName: str, StructType: ir.Type) -> None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        defaults: dict = Gen.class_member_defaults.get(ClassName, {})
        members: list[tuple] = Gen.class_members.get(ClassName, [])
        if not defaults or not members:
            return
        if not isinstance(StructType, ir.IdentifiedStructType):
            return
        has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes
        base = 1 if has_vtable else 0
        for i, (member_name, member_type) in enumerate(members):
            if member_name in defaults:
                default_val = defaults[member_name]
                if isinstance(default_val, ir.Constant):
                    elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"default_{ClassName}_{member_name}")
                    Gen._store(default_val, elem_ptr)

    def _InitStructFromArgs(self, struct_ptr: ir.Value, Node: ast.Call, ClassName: str, StructType: ir.Type) -> None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        if not isinstance(StructType, ir.IdentifiedStructType):
            return
        members = Gen.class_members.get(ClassName, [])
        has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes
        base = 1 if has_vtable else 0
        for i, arg in enumerate(Node.args):
            if i >= len(members):
                break
            val = self.HandleExprLlvm(arg)
            if not val:
                continue
            member_name, member_type = members[i]
            elem_idx = base + i
            if StructType.elements is None or elem_idx >= len(StructType.elements):
                break
            elem_type = StructType.elements[elem_idx]
            if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType):
                if val.type.width < elem_type.width:
                    val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{i}")
                elif val.type.width > elem_type.width:
                    val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{i}")
            elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType):
                if val.type.pointee != elem_type.pointee:
                    val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{i}")
            elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{member_name}")
            Gen._store(val, elem_ptr)
        if Node.keywords:
            member_map = {name: (base + i) for i, (name, _) in enumerate(members)}
            for kw in Node.keywords:
                if kw.arg in member_map:
                    val = self.HandleExprLlvm(kw.value)
                    if not val:
                        continue
                    elem_idx = member_map[kw.arg]
                    if StructType.elements is None or elem_idx >= len(StructType.elements):
                        continue
                    elem_type = StructType.elements[elem_idx]
                    if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType):
                        if val.type.width < elem_type.width:
                            val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{kw.arg}")
                        elif val.type.width > elem_type.width:
                            val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{kw.arg}")
                    elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType):
                        if val.type.pointee != elem_type.pointee:
                            val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{kw.arg}")
                    elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{kw.arg}")
                    Gen._store(val, elem_ptr)

    def _HandleSubscriptPtrLlvm(self, Node: ast.Subscript) -> ir.Value | None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.value, Gen)
        if ClassName and ClassName in Gen.structs and Gen._has_function(f'{ClassName}.__getitem__'):
            obj_val = self.HandleExprLlvm(Node.value)
            idx_val = self.HandleExprLlvm(Node.slice)
            if obj_val and idx_val:
                # 处理 obj_val 为 i8（整数）的情况：联合类型 | t.CPtr 降级后可能被 load 为 i8
                if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
                    obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
                if self._is_char_pointer(obj_val):
                    obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
                if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64:
                    idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx")
                result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__")
                return result
        ValueVal = self.HandleExprLlvm(Node.value)
        if not ValueVal:
            return None
        IndexVal = self.HandleExprLlvm(Node.slice)
        if not IndexVal:
            return None
        if isinstance(ValueVal.type, ir.IntType):
            var_ptr = self._get_int_ptr(Node.value)
            if var_ptr:
                i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr")
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                    IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index")
                ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr")
                return ptr
            return None
        if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType):
            LoadedValueVal = Gen._load(ValueVal, name="Load_subscript")
            if isinstance(LoadedValueVal.type, ir.PointerType):
                ElemPtr = Gen.builder.gep(LoadedValueVal, [IndexVal], name="subscript")
                return ElemPtr
        if isinstance(ValueVal.type, ir.PointerType):
            pointee = ValueVal.type.pointee
            if isinstance(pointee, ir.ArrayType):
                zero = ir.Constant(ir.IntType(32), 0)
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                    if IndexVal.type.width < 32:
                        IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                    else:
                        IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript")
                return Gen._load(ElemPtr, name="arr_subscript_val")
            else:
                if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
                    IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index")
                ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript")
                if isinstance(pointee, ir.IntType):
                    return Gen._load(ElemPtr, name="subscript_val")
                return ElemPtr
        elif isinstance(ValueVal.type, ir.ArrayType):
            zero = ir.Constant(ir.IntType(32), 0)
            if isinstance(Node.value, ast.Name):
                VarName = Node.value.id
                if VarName in Gen.variables and Gen.variables[VarName] is not None:
                    VarPtr = Gen.variables[VarName]
                    if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType):
                        if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32:
                            if IndexVal.type.width < 32:
                                IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index")
                            else:
                                IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index")
                        ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript")
                        return ElemPtr
            arr_alloc = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp")
            Gen._store(ValueVal, arr_alloc)
            ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript")
            return ElemPtr
        return None

    def _HandleGenericCallLlvm(self, Node: ast.Call, FuncName: str) -> ir.Value | None:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        template: dict = self.Trans.FunctionHandler._generic_templates[FuncName]
        type_param_names: list[str] = template['type_params']
        type_args: list[str] = []
        CallArgs: list[ir.Value] = []
        for i, arg_node in enumerate(Node.args):
            arg_val = self.HandleExprLlvm(arg_node)
            if arg_val:
                CallArgs.append(arg_val)
                type_str = self.Trans.FunctionHandler._infer_type_arg_from_value(arg_val, Gen)
                type_args.append(type_str)
            else:
                type_args.append('int')
        while len(type_args) < len(type_param_names):
            type_args.append('int')
        type_args = type_args[:len(type_param_names)]
        spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen)
        if spec_name is None:
            return None
        mangled_spec = Gen._mangle_func_name(spec_name)
        func = None
        if mangled_spec in Gen.functions:
            func = Gen.functions[mangled_spec]
        elif spec_name in Gen.functions:
            func = Gen.functions[spec_name]
        else:
            for fname, fobj in Gen.functions.items():
                if spec_name in fname or fname.endswith(spec_name):
                    func = fobj
                    break
        if func is None:
            return None
        if not CallArgs:
            CallArgs = [ir.Constant(ir.IntType(32), 0) for _ in func.args]
        CallArgs = Gen._apply_auto_addr(spec_name, CallArgs)
        adjusted = Gen._adjust_args(CallArgs, func)
        return Gen.builder.call(func, adjusted, name=f"call_{spec_name}")

    def _HandleGenericClassNewLlvm(self, Node: ast.Call, ClassName: str, explicit_slice: ast.AST | None = None) -> ir.Value:
        Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
        template: dict = self.Trans.ClassHandler._generic_class_templates[ClassName]
        type_param_names: list[str] = template['type_params']
        type_args: list[str] = []
        type_names: list[str] = []
        # 如果有显式类型参数 (如 list[int](mb))，直接从 slice 提取
        if explicit_slice is not None:
            slice_nodes: list[ast.AST] = []
            if isinstance(explicit_slice, ast.Tuple):
                slice_nodes = list(explicit_slice.elts)
            else:
                slice_nodes = [explicit_slice]
            for sn in slice_nodes:
                result = self._resolve_generic_slice_type(sn)
                if result is not None:
                    type_args.append(result[0])
                    type_names.append(result[1])
            # 补齐缺少的类型参数
            while len(type_args) < len(type_param_names):
                type_args.append('int')
                type_names.append('CInt')
            spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)
            if spec_name is None:
                return ir.Constant(ir.IntType(32), 0)
            return self._HandleClassNewLlvm(Node, spec_name)
        all_inferred: list[tuple[str, str]] = []
        for i, arg_node in enumerate(Node.args):
            type_str = 'int'
            type_name = 'CInt'
            if isinstance(arg_node, ast.Constant):
                if isinstance(arg_node.value, float):
                    type_str = 'double'
                    type_name = 'CDouble'
                elif isinstance(arg_node.value, int):
                    type_str = 'int'
                    type_name = 'CInt'
                elif isinstance(arg_node.value, bool):
                    type_str = 'i8'
                    type_name = 'CBool'
            elif isinstance(arg_node, ast.Call):
                if isinstance(arg_node.func, ast.Name):
                    func_id = arg_node.func.id
                    if func_id == 'float':
                        type_str = 'double'
                        type_name = 'CDouble'
                    elif func_id == 'int':
                        type_str = 'int'
                        type_name = 'CInt'
                    else:
                        float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'}
                        int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'}
                        if func_id in float_types:
                            type_str = 'double'
                            type_name = func_id
                        elif func_id in int_types:
                            type_str = 'int'
                            type_name = func_id
                elif isinstance(arg_node.func, ast.Attribute):
                    attr_name = arg_node.func.attr
                    float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'}
                    int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'}
                    if attr_name in float_types:
                        type_str = 'double'
                        type_name = attr_name
                    elif attr_name in int_types:
                        type_str = 'int'
                        type_name = attr_name
            elif isinstance(arg_node, ast.Name):
                var_info = self.Trans.SymbolTable.lookup(arg_node.id)
                if var_info and isinstance(var_info, dict):
                    var_type = var_info.get('type', '')
                    if var_type in ('double', 'float'):
                        type_str = 'double'
                        type_name = 'CDouble'
            all_inferred.append((type_str, type_name))
        hint_types = [(ts, tn) for ts, tn in all_inferred if tn != 'CInt' or ts != 'int']
        for i in range(len(type_param_names)):
            if i < len(hint_types):
                type_args.append(hint_types[i][0])
                type_names.append(hint_types[i][1])
            elif i < len(all_inferred):
                type_args.append(all_inferred[i][0])
                type_names.append(all_inferred[i][1])
            else:
                type_args.append('int')
                type_names.append('CInt')
        spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)
        if spec_name is None:
            return ir.Constant(ir.IntType(32), 0)
        return self._HandleClassNewLlvm(Node, spec_name)

