feat(dunder): 补齐 dunder 协议(__bool__/__call__/__str__/__abs__/__del__/**/增量/反向)
- __bool__:ExprGenOps.coerce_cond_to_bool 统一 if/while/and/or/not/三元/协程条件的真值归一,优先调度 __bool__ - __call__:obj(args) 分发到 obj.__call__(CallGenMixin 裸名分支) - __str__:str()/print/f-string 调度(CallGenDispatch/CallGenLeafKit/ExprGenFstr) - __abs__:abs(obj) 调度(CallGenMixin) - __del__/__delete__:del obj → __delete__;del obj.attr 无 property deleter 时回退对象 __del__ - ** / __pow__:新增 llvm.pow 内联(整数按常量指数回写),_binop_to_dunder 补 Pow - 增量赋值:__iX__ 优先、缺失回退 __X__(新增 _aug_op_to_dunder) - 反向运算符:新增 _rbinop_to_dunder,lhs 无 dunder 时调度 rhs.__rX__
This commit is contained in:
1 parent
a3bb62f2c3
commit
4eec3f0908
9 files changed
+375
-110
No files matched your search
@@ -1269,6 +1269,11 @@ novirtual class AssignGenMixin:
|
||||
trans: HT.Translator* = None,
|
||||
lhs_node: ast.AST* = None) -> llvmlite.Value*:
|
||||
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)"""
|
||||
# `**=` 幂运算:基础类型 → llvm.pow(与 BinOp 共用 ExprGenOps.emit_pow)
|
||||
if op == ast.OpKind.Pow:
|
||||
if trans is None:
|
||||
return None
|
||||
return self.Gen.ExprGenOps.emit_pow(pool, builder, trans.Module, lhs, rhs, node, trans)
|
||||
lhs_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty)
|
||||
rhs_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty)
|
||||
lhs_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(lhs.Ty)
|
||||
@@ -1650,8 +1655,50 @@ novirtual class AssignGenMixin:
|
||||
# fail-fast: RHS 翻译失败
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||||
|
||||
# 3b. 运算符重载:对象变量 += → __iadd__;该类无 __iadd__ 时回退 __add__
|
||||
# (对齐 TPC HandlesAugAssign._AUGOP_MAP/_AUGOP_FALLBACK)。
|
||||
# 仅局部变量(与 TPC 同范围:全局/nonlocal 不调度增量 dunder)。
|
||||
if scope_type == 0 and target_alloca is not None:
|
||||
aug_dup: str = self._aug_op_to_dunder(aug.op)
|
||||
if aug_dup is not None:
|
||||
ovl_self_aug: llvmlite.Value* = target_alloca
|
||||
# 指针存储槽(Ptr(Ptr(Struct))):load 出对象指针作为 self
|
||||
if target_alloca.Ty is not None and target_alloca.Ty.Pointee != 0 \
|
||||
and self.Gen.ExprGenBase.is_ptr_type(target_alloca.Ty.Pointee) != 0:
|
||||
load_self_aug: llvmlite.Value* = llvmlite.build_load(builder, target_alloca.Ty.Pointee, target_alloca)
|
||||
if load_self_aug is not None:
|
||||
ovl_self_aug = load_self_aug
|
||||
# 仅当目标是结构体(类实例)时才尝试增量 dunder,避免无谓的实参池分配
|
||||
if self.Gen.StructGen.get_struct_type_from_value(ovl_self_aug) is not None:
|
||||
aug_extra: sizet* = pool.alloc(8)
|
||||
if aug_extra is not None:
|
||||
aug_extra[0] = sizet(rhs_val)
|
||||
aug_ovl: llvmlite.Value* = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, ovl_self_aug, aug_dup, trans, aug_extra, 1)
|
||||
if aug_ovl is None:
|
||||
aug_fb: str = self._op_to_dunder(aug.op)
|
||||
if aug_fb is not None:
|
||||
aug_ovl = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, ovl_self_aug, aug_fb, trans, aug_extra, 1)
|
||||
if aug_ovl is not None:
|
||||
aug_res: llvmlite.Value* = aug_ovl
|
||||
if target_ty is not None and aug_res.Ty is not None \
|
||||
and self.Gen.ExprGenBase._same_agg_ty(pool, aug_res.Ty, target_ty) == 0:
|
||||
# 目标为结构体值、返回为指针 → load 出结构体值(按值存储语义)
|
||||
if self.Gen.ExprGenBase.is_ptr_type(target_ty) == 0 \
|
||||
and self.Gen.ExprGenBase.is_ptr_type(aug_res.Ty) != 0 \
|
||||
and aug_res.Ty.Pointee != 0:
|
||||
aug_res = llvmlite.build_load(builder, aug_res.Ty.Pointee, aug_res)
|
||||
else:
|
||||
coerced_aug: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, aug_res, target_ty, node, trans)
|
||||
if coerced_aug is not None:
|
||||
aug_res = coerced_aug
|
||||
if aug_res is None or target_ty is None \
|
||||
or self.Gen.ExprGenBase._same_agg_ty(pool, aug_res.Ty, target_ty) == 0:
|
||||
# fail-fast:重载返回值与目标变量类型不匹配,禁止静默写坏内存
|
||||
self.Gen.TypeGenErr.fatal_error(node, "增量赋值运算符重载返回值类型与目标变量不匹配", "TypeError")
|
||||
llvmlite.build_store(builder, aug_res, target_alloca, vol_aa)
|
||||
return 0
|
||||
|
||||
# 4. 类型对齐 + 应用二元运算
|
||||
# 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__)
|
||||
result: llvmlite.Value* = self._apply_aug_op(pool, builder, aug.op, cur_val, rhs_val, node, trans, target)
|
||||
if result is None:
|
||||
# fail-fast: 二元运算失败
|
||||
@@ -3558,6 +3605,29 @@ novirtual class AssignGenMixin:
|
||||
if op == ast.OpKind.Invert: return "__invert__"
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# _aug_op_to_dunder - 增量运算符 → 增量 dunder 方法名(__iadd__ 等)
|
||||
#
|
||||
# 无对应增量 dunder 时返回 None;调用方回退普通 dunder(_op_to_dunder,
|
||||
# 即 __iadd__ 缺失时用 __add__),与 TPC HandlesAugAssign._AUGOP_MAP /
|
||||
# _AUGOP_FALLBACK 同口径。
|
||||
# ============================================================
|
||||
def _aug_op_to_dunder(self, op: int) -> str:
|
||||
"""AugAssign 运算符 → 增量 dunder 方法名,无映射返回 None"""
|
||||
if op == ast.OpKind.Add: return "__iadd__"
|
||||
if op == ast.OpKind.Sub: return "__isub__"
|
||||
if op == ast.OpKind.Mult: return "__imul__"
|
||||
if op == ast.OpKind.Div: return "__itruediv__"
|
||||
if op == ast.OpKind.FloorDiv: return "__ifloordiv__"
|
||||
if op == ast.OpKind.Mod: return "__imod__"
|
||||
if op == ast.OpKind.Pow: return "__ipow__"
|
||||
if op == ast.OpKind.BitAnd: return "__iand__"
|
||||
if op == ast.OpKind.BitOr: return "__ior__"
|
||||
if op == ast.OpKind.BitXor: return "__ixor__"
|
||||
if op == ast.OpKind.LShift: return "__ilshift__"
|
||||
if op == ast.OpKind.RShift: return "__irshift__"
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法
|
||||
#
|
||||
|
||||
@@ -1235,7 +1235,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
cond: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ifn.test, None, 0, trans)
|
||||
if cond is None:
|
||||
return
|
||||
cond1: llvmlite.Value* = self._normalize_cond(builder, pool, cond)
|
||||
cond1: llvmlite.Value* = self._normalize_cond(builder, pool, mod, cond, trans)
|
||||
func: llvmlite.Function* = trans._cur_func
|
||||
then_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.then")
|
||||
merge_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "coro.end")
|
||||
@@ -1296,7 +1296,7 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
cond: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, whn.test, None, 0, trans)
|
||||
if cond is None:
|
||||
cond = llvmlite.const_int32(pool, 0)
|
||||
cond1: llvmlite.Value* = self._normalize_cond(builder, pool, cond)
|
||||
cond1: llvmlite.Value* = self._normalize_cond(builder, pool, mod, cond, trans)
|
||||
llvmlite.build_cond_br(builder, cond1, body_bb, after_bb)
|
||||
# 循环体
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
@@ -1610,22 +1610,11 @@ novirtual class AsyncGenMixin(CallGenBase.CallGenBase):
|
||||
# ============================================================
|
||||
def _normalize_cond(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
cond: llvmlite.Value*) -> llvmlite.Value*:
|
||||
if cond is None:
|
||||
return None
|
||||
ty: llvmlite.LLVMType* = cond.Ty
|
||||
is_i1: int = 0
|
||||
if ty is not None:
|
||||
match ty:
|
||||
case LLVMType.Int():
|
||||
if ty.Bits == 1:
|
||||
is_i1 = 1
|
||||
case _:
|
||||
pass
|
||||
if is_i1 != 0:
|
||||
return cond
|
||||
zero: llvmlite.Value* = llvmlite.ConstZero(pool, ty)
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond, zero)
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cond: llvmlite.Value*,
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""条件归一到 i1(协程 if/while 用):委托 coerce_cond_to_bool,优先调度 __bool__"""
|
||||
return self.Gen.ExprGenOps.coerce_cond_to_bool(pool, builder, mod, cond, trans)
|
||||
|
||||
# ============================================================
|
||||
# 参数名读取(_coro_params 表)
|
||||
|
||||
@@ -242,6 +242,11 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
# str(x) / bytes(x) → i8* (bitcast)
|
||||
cast_arg: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
if cast_arg is not None:
|
||||
# 对象定义了 __str__ → 调度 __str__(对齐 TPC HandlesExprBuiltin)
|
||||
if string.strcmp(cast_fn_name, "str") == 0:
|
||||
str_ov: llvmlite.Value* = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, cast_arg, "__str__", trans)
|
||||
if str_ov is not None:
|
||||
return str_ov
|
||||
i8_ptr_ty_builtin: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin)
|
||||
return None
|
||||
|
||||
@@ -916,6 +916,11 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
self.Gen.TypeGenErr.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError")
|
||||
return
|
||||
|
||||
# 对象定义了 __str__ → 用其返回的字符串(i8*)按 %s 打印(对齐 TPC)
|
||||
str_ov_pr: llvmlite.Value* = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, arg_val, "__str__", trans)
|
||||
if str_ov_pr is not None:
|
||||
arg_val = str_ov_pr
|
||||
|
||||
# 数组名(如 print(l),l: t.CArray[char, N]):
|
||||
# translate_value 会 load 出数组值([N x T]),print 无法格式化;
|
||||
# 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容),
|
||||
|
||||
@@ -744,6 +744,20 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
is_seg2_mod = 1
|
||||
if is_seg2_cls != 0 or is_seg2_mod == 0:
|
||||
found_func = None
|
||||
# ---- abs(obj):对象定义了 __abs__ 时优先调度(对齐 TPC _HandleAbsLlvm)----
|
||||
# 仅当实参是类实例(注解类名可解析)且该类(含 MRO 祖先)定义了 __abs__ 时
|
||||
# 命中;否则保持既有内建/整数/浮点 abs 路径不变。
|
||||
if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name \
|
||||
and string.strcmp(func_name, "abs") == 0 and can == 1:
|
||||
abs_arg: ast.AST* = cargs.get(0)
|
||||
if abs_arg is not None:
|
||||
abs_cls: str = self.Gen.CallGenProp._resolve_obj_class_name(pool, trans, abs_arg)
|
||||
if abs_cls is not None:
|
||||
abs_sc: str = self.Gen.ExprGenOps._resolve_dunder_by_class(pool, mod, abs_cls, "__abs__", trans)
|
||||
if abs_sc is not None:
|
||||
abs_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, abs_arg, None, 0, trans)
|
||||
if abs_val is not None:
|
||||
return self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, abs_sc, "__abs__", abs_val, None, 0, trans)
|
||||
# C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare
|
||||
# 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用
|
||||
if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||||
@@ -935,6 +949,25 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name)
|
||||
if fp_alloca is not None:
|
||||
# ---- 可调用对象 __call__:变量是类实例且类内定义了 __call__ ----
|
||||
# obj(args) → obj.__call__(args)。仅当变量非闭包、非函数指针且其值
|
||||
# 指向结构体、该类(含 MRO 祖先)定义了 __call__ 时命中;其余情况
|
||||
# (get_struct_type_from_value 返回 None)保持既有闭包/函数指针路径。
|
||||
if trans is not None \
|
||||
and self.Gen.CallGenLeafKit.is_closure_name(func_name) == 0 \
|
||||
and self.Gen.CallGenLeafKit._is_func_ptr_alloca(fp_alloca) == 0:
|
||||
c_obj: llvmlite.Value* = self.Gen.ExprGenBase._deref_if_ptr_ptr(builder, fp_alloca)
|
||||
if c_obj is None:
|
||||
c_obj = fp_alloca
|
||||
c_struct: llvmlite.LLVMType* = None
|
||||
if c_obj is not None:
|
||||
c_struct = self.Gen.StructGen.get_struct_type_from_value(c_obj)
|
||||
if c_struct is not None:
|
||||
c_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, c_struct)
|
||||
if c_cls is not None:
|
||||
c_call_cls: str = self.Gen.ExprGenOps._resolve_dunder_by_class(pool, mod, c_cls, "__call__", trans)
|
||||
if c_call_cls is not None:
|
||||
return self.Gen.CallGenCall._translate_method_call(pool, builder, mod, c_call_cls, "__call__", c_obj, cl, trans)
|
||||
# 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用
|
||||
if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0:
|
||||
return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca,
|
||||
|
||||
@@ -71,6 +71,11 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
# fail-fast:f-string 格式化值翻译失败必须终止编译,绝不在
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
continue
|
||||
# 对象定义了 __str__ 且未指定格式 → 用其返回的字符串(对齐 TPC)
|
||||
if fv.format_spec is None:
|
||||
str_ov_fs: llvmlite.Value* = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, val, "__str__", trans)
|
||||
if str_ov_fs is not None:
|
||||
val = str_ov_fs
|
||||
# 确定 C 格式说明符(format_spec 优先,否则按值类型推断)
|
||||
c_fmt: str = None
|
||||
if fv.format_spec is not None:
|
||||
@@ -119,6 +124,11 @@ novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
# fail-fast:裸 FormattedValue 翻译失败必须终止编译,绝不在
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
else:
|
||||
# 对象定义了 __str__ 且未指定格式 → 用其返回的字符串(对齐 TPC)
|
||||
if fv.format_spec is None:
|
||||
str_ov_sf: llvmlite.Value* = self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, val, "__str__", trans)
|
||||
if str_ov_sf is not None:
|
||||
val = str_ov_sf
|
||||
c_fmt: str = None
|
||||
if fv.format_spec is not None:
|
||||
c_fmt = self._fstr_parse_format_spec(pool, fv.format_spec, val, fv.value)
|
||||
|
||||
@@ -42,18 +42,8 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
# 1. 求值条件
|
||||
cond_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ie.test, None, 0, trans)
|
||||
if cond_val is None: return None
|
||||
# 转换为 i1
|
||||
cond_bits: int = self.get_llvm_type_bits(cond_val.Ty)
|
||||
if cond_bits == 1:
|
||||
cond_i1: llvmlite.Value* = cond_val
|
||||
else:
|
||||
if self.is_ptr_type(cond_val.Ty) != 0:
|
||||
# 指针类型:与 null 比较
|
||||
null_cond: llvmlite.Value* = llvmlite.ConstNull(pool, cond_val.Ty, "null")
|
||||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
|
||||
else:
|
||||
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
|
||||
# 转换为 i1(优先调度 __bool__)
|
||||
cond_i1: llvmlite.Value* = self.coerce_cond_to_bool(pool, builder, mod, cond_val, trans)
|
||||
|
||||
# 2. 创建三个基本块
|
||||
cnt: int = trans._label_counter
|
||||
@@ -797,25 +787,12 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
# +x = x
|
||||
return operand
|
||||
elif uo.op == ast.OpKind.Not:
|
||||
# not x = (x == 0/null),返回 i1
|
||||
if self.is_ptr_type(operand.Ty) != 0:
|
||||
# 指针类型:与 null 比较
|
||||
null_op: llvmlite.Value* = llvmlite.ConstNull(pool, operand.Ty, "null")
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op)
|
||||
# 结构体值类型:永远为真(非空),not 返回 false
|
||||
operand_is_struct_not: int = 0
|
||||
match operand.Ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
operand_is_struct_not = 1
|
||||
case _:
|
||||
operand_is_struct_not = 0
|
||||
if operand_is_struct_not != 0:
|
||||
return llvmlite.const_int(pool, 1, 0)
|
||||
operand_bits_not: int = self.get_llvm_type_bits(operand.Ty)
|
||||
zero = llvmlite.const_int32(pool, 0)
|
||||
if operand_bits_not == 64:
|
||||
zero = llvmlite.const_int64(pool, 0)
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero)
|
||||
# not x = (bool(x) == 0),返回 i1;优先调度 __bool__
|
||||
not_cond: llvmlite.Value* = self.coerce_cond_to_bool(pool, builder, mod, operand, trans)
|
||||
if not_cond is None:
|
||||
return None
|
||||
true_val: llvmlite.Value* = llvmlite.const_int(pool, 1, 1)
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, not_cond, true_val)
|
||||
elif uo.op == ast.OpKind.Invert:
|
||||
# ~x = x ^ -1
|
||||
operand_bits_inv: int = self.get_llvm_type_bits(operand.Ty)
|
||||
@@ -1007,17 +984,8 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if val is None:
|
||||
return None
|
||||
|
||||
# 转为 i1(已经是 i1 的直接用,否则与 0/null 比较)
|
||||
val_bits: int = self.get_llvm_type_bits(val.Ty)
|
||||
val_i1: llvmlite.Value* = val
|
||||
if val_bits != 1:
|
||||
if self.is_ptr_type(val.Ty) != 0:
|
||||
# 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配)
|
||||
null_val: llvmlite.Value* = llvmlite.ConstNull(pool, val.Ty, "null")
|
||||
val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val)
|
||||
else:
|
||||
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero)
|
||||
# 转为 i1(已是 i1 直接使用;否则走 coerce_cond_to_bool:优先 __bool__)
|
||||
val_i1: llvmlite.Value* = self.coerce_cond_to_bool(pool, builder, mod, val, trans)
|
||||
|
||||
# 创建 next BB(求值下一个值)
|
||||
cnt = builder.Counter
|
||||
@@ -1049,16 +1017,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
last_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, last_node, funcs_ptr, func_count, trans)
|
||||
if last_val is None:
|
||||
return None
|
||||
last_bits: int = self.get_llvm_type_bits(last_val.Ty)
|
||||
last_i1: llvmlite.Value* = last_val
|
||||
if last_bits != 1:
|
||||
if self.is_ptr_type(last_val.Ty) != 0:
|
||||
# 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配)
|
||||
null_val2: llvmlite.Value* = llvmlite.ConstNull(pool, last_val.Ty, "null")
|
||||
last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2)
|
||||
else:
|
||||
zero = llvmlite.const_int32(pool, 0)
|
||||
last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero)
|
||||
last_i1: llvmlite.Value* = self.coerce_cond_to_bool(pool, builder, mod, last_val, trans)
|
||||
|
||||
llvmlite.build_br(builder, merge_bb)
|
||||
|
||||
@@ -1075,6 +1034,81 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
i1_ty: llvmlite.LLVMType* = llvmlite.Int1(pool)
|
||||
return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count)
|
||||
# ============================================================
|
||||
# emit_pow - `**` 幂运算(基础类型)
|
||||
#
|
||||
# 对齐 TPC ExprGen.emit_binary_op 的 Pow 分支:
|
||||
# 浮点(任一操作数浮点)→ llvm.pow(结果浮点,目标位宽取大者);
|
||||
# 整数 → 提升到 double 计算 llvm.pow;若指数为非负整数常量,则
|
||||
# 结果 fptosi 回写为左操作数类型(Python `int ** int = int`)。
|
||||
# 自定义类型的 `**` 由重载路径(__pow__)先行处理,不进入此处。
|
||||
# ============================================================
|
||||
def emit_pow(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
lhs: llvmlite.Value*,
|
||||
rhs: llvmlite.Value*,
|
||||
node: ast.AST* = None,
|
||||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||||
"""翻译 `**` 幂运算(基础类型走 llvm.pow)"""
|
||||
if lhs is None or rhs is None:
|
||||
return None
|
||||
lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty)
|
||||
rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty)
|
||||
f64_ty: llvmlite.LLVMType* = llvmlite.Double(pool)
|
||||
# 浮点路径:任一操作数为浮点 → 结果浮点
|
||||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||||
target_f: llvmlite.LLVMType* = f64_ty
|
||||
if lhs_fbits == 32 and rhs_fbits == 32:
|
||||
target_f = llvmlite.Float(pool)
|
||||
lf: llvmlite.Value* = self.coerce_to_type(builder, lhs, target_f, node, trans)
|
||||
rf: llvmlite.Value* = self.coerce_to_type(builder, rhs, target_f, node, trans)
|
||||
return self._call_llvm_pow(pool, builder, mod, lf, rf)
|
||||
# 整数路径:提升到 double 计算
|
||||
li: llvmlite.Value* = self.coerce_to_type(builder, lhs, f64_ty, node, trans)
|
||||
ri: llvmlite.Value* = self.coerce_to_type(builder, rhs, f64_ty, node, trans)
|
||||
res: llvmlite.Value* = self._call_llvm_pow(pool, builder, mod, li, ri)
|
||||
if res is None:
|
||||
return None
|
||||
# 指数为非负整数常量 → fptosi 回写为左操作数类型(Python int ** int = int)
|
||||
rhs_bits: int = self.get_llvm_type_bits(rhs.Ty)
|
||||
if rhs_bits != 0 and rhs.IsConst == 1 and rhs.IntVal >= 0:
|
||||
return self.coerce_to_type(builder, res, lhs.Ty, node, trans)
|
||||
return res
|
||||
|
||||
def _call_llvm_pow(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
lf: llvmlite.Value*,
|
||||
rf: llvmlite.Value*) -> llvmlite.Value*:
|
||||
"""调用 llvm.pow.f64 内联函数;f32 结果再截断回 float"""
|
||||
if lf is None or rf is None:
|
||||
return None
|
||||
f64_ty: llvmlite.LLVMType* = llvmlite.Double(pool)
|
||||
pow_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, "llvm.pow.f64")
|
||||
if pow_fn is None:
|
||||
pow_fn = llvmlite.create_declare(pool, mod, "llvm.pow.f64", f64_ty)
|
||||
if pow_fn is not None:
|
||||
llvmlite.add_param(pool, pow_fn, f64_ty, "x")
|
||||
llvmlite.add_param(pool, pow_fn, f64_ty, "y")
|
||||
lf_d: llvmlite.Value* = lf
|
||||
if self.get_llvm_float_bits(lf.Ty) != 64:
|
||||
lf_d = llvmlite.build_fpext(builder, lf, f64_ty)
|
||||
rf_d: llvmlite.Value* = rf
|
||||
if self.get_llvm_float_bits(rf.Ty) != 64:
|
||||
rf_d = llvmlite.build_fpext(builder, rf, f64_ty)
|
||||
if lf_d is None or rf_d is None:
|
||||
return None
|
||||
lf_d.Next = rf_d
|
||||
rf_d.Next = None
|
||||
res: llvmlite.Value* = llvmlite.build_call(builder, "llvm.pow.f64", lf_d, 2, f64_ty, 0)
|
||||
if res is None:
|
||||
return None
|
||||
# f32 目标:llvm.pow 恒为 f64,结果截断回 float
|
||||
if self.get_llvm_float_bits(lf.Ty) == 32 and self.get_llvm_float_bits(rf.Ty) == 32:
|
||||
res = llvmlite.build_fptrunc(builder, res, llvmlite.Float(pool))
|
||||
return res
|
||||
|
||||
# ============================================================
|
||||
# BinOp 运算符 → dunder 方法名
|
||||
# ============================================================
|
||||
def _binop_to_dunder(self, op: int) -> str:
|
||||
@@ -1087,6 +1121,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if op == ast.OpKind.Mult: return "__mul__"
|
||||
if op == ast.OpKind.Div: return "__truediv__"
|
||||
if op == ast.OpKind.Mod: return "__mod__"
|
||||
if op == ast.OpKind.Pow: return "__pow__"
|
||||
if op == ast.OpKind.BitAnd: return "__and__"
|
||||
if op == ast.OpKind.BitOr: return "__or__"
|
||||
if op == ast.OpKind.BitXor: return "__xor__"
|
||||
@@ -1095,6 +1130,27 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if op == ast.OpKind.FloorDiv: return "__floordiv__"
|
||||
return None
|
||||
# ============================================================
|
||||
# BinOp 运算符 → 反向 dunder 方法名(__radd__ 等)
|
||||
#
|
||||
# 左操作数无对应普通 dunder 时,调度右操作数的反向 dunder:
|
||||
# a + b → a.__add__(b) 缺失时 b.__radd__(a)
|
||||
# ============================================================
|
||||
def _rbinop_to_dunder(self, op: int) -> str:
|
||||
"""将 BinOp 运算符映射到反向 dunder 方法名,无映射时返回 None"""
|
||||
if op == ast.OpKind.Add: return "__radd__"
|
||||
if op == ast.OpKind.Sub: return "__rsub__"
|
||||
if op == ast.OpKind.Mult: return "__rmul__"
|
||||
if op == ast.OpKind.Div: return "__rtruediv__"
|
||||
if op == ast.OpKind.FloorDiv: return "__rfloordiv__"
|
||||
if op == ast.OpKind.Mod: return "__rmod__"
|
||||
if op == ast.OpKind.Pow: return "__rpow__"
|
||||
if op == ast.OpKind.BitAnd: return "__rand__"
|
||||
if op == ast.OpKind.BitOr: return "__ror__"
|
||||
if op == ast.OpKind.BitXor: return "__rxor__"
|
||||
if op == ast.OpKind.LShift: return "__rlshift__"
|
||||
if op == ast.OpKind.RShift: return "__rrshift__"
|
||||
return None
|
||||
# ============================================================
|
||||
# Compare 运算符 → dunder 方法名
|
||||
# ============================================================
|
||||
def _cmpop_to_dunder(self, op: int) -> str:
|
||||
@@ -1236,15 +1292,21 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
dunder: str = self._unaryop_to_dunder(op)
|
||||
if dunder is None:
|
||||
return None
|
||||
return self._try_named_dunder(pool, builder, mod, operand, dunder, trans)
|
||||
|
||||
# 检查 operand 是否为结构体指针
|
||||
struct_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(operand)
|
||||
if struct_ty is None:
|
||||
return None
|
||||
def _resolve_dunder_by_class(self, pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
class_name: str,
|
||||
dunder: str,
|
||||
trans: HT.Translator*,
|
||||
struct_ty: llvmlite.LLVMType* = None) -> str:
|
||||
"""在 class_name(含 MRO 祖先)中解析 dunder 方法的定义类名。
|
||||
|
||||
# 获取类名
|
||||
class_name: str = self.Gen.StructGen.get_class_name_by_type(pool, struct_ty)
|
||||
if class_name is None:
|
||||
返回「实际定义该方法的类名」(search_class);该类(含祖先)未定义则返回
|
||||
None。可选 struct_ty:提供时从其类型 entry 直接取 SHA1(跨模块类更可靠)。
|
||||
跨模块类以依赖模块 vpi stub 为准,避免发出幽灵 call(链接 undefined)。
|
||||
"""
|
||||
if class_name is None or dunder is None:
|
||||
return None
|
||||
|
||||
# 在继承链中查找 dunder 方法
|
||||
@@ -1274,9 +1336,10 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
|
||||
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入)
|
||||
cls_sha1: str = None
|
||||
uop_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||||
if uop_entry is not None:
|
||||
cls_sha1 = uop_entry.ModuleSha1
|
||||
if struct_ty is not None:
|
||||
uop_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty)
|
||||
if uop_entry is not None:
|
||||
cls_sha1 = uop_entry.ModuleSha1
|
||||
if cls_sha1 is None:
|
||||
cls_sha1 = self.Gen.StructGen.get_struct_sha1(search_class)
|
||||
if cls_sha1 is None:
|
||||
@@ -1288,7 +1351,7 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
cls_sha1 = self.Gen.StructGen.get_struct_sha1(anc_p)
|
||||
mj += 1
|
||||
|
||||
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算
|
||||
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法
|
||||
if found_func is None and cls_sha1 is None:
|
||||
return None
|
||||
|
||||
@@ -1297,9 +1360,86 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if found_func is None and trans is not None and trans.ModuleSha1 is not None:
|
||||
if cls_sha1 is not None and string.strcmp(cls_sha1, trans.ModuleSha1) == 0:
|
||||
return None
|
||||
# 跨模块类:stub 可能未注入,方法存在性以依赖模块 vpi stub 为准。
|
||||
# vpi 未命中 → 回退(不发幽灵 call,避免链接 undefined)
|
||||
if cls_sha1 is not None:
|
||||
vpi_dup: llvmlite.LLVMType* = self.Gen.CallGenBase._lookup_method_ret_ty_via_vpi(pool, cls_sha1, search_class, dunder)
|
||||
if vpi_dup is None:
|
||||
return None
|
||||
return search_class
|
||||
|
||||
# 一元方法无额外参数(extra_args 为空)
|
||||
return self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, search_class, dunder, operand, None, 0, trans)
|
||||
def _try_named_dunder(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
operand: llvmlite.Value*,
|
||||
dunder: str,
|
||||
trans: HT.Translator*,
|
||||
extra_args: sizet* = None,
|
||||
extra_count: int = 0) -> llvmlite.Value*:
|
||||
"""按名字在 operand 的类(含 MRO 祖先)中查找并调用 dunder 方法。
|
||||
|
||||
一元运算符(__neg__/__pos__/__invert__)、条件真值 __bool__ 与可调用
|
||||
对象 __call__ 共用此查找/发射逻辑。extra_args/extra_count:附加实参
|
||||
(__call__ 传入调用实参;一元/__bool__ 为空)。找不到方法返回 None。
|
||||
"""
|
||||
if operand is None or dunder is None:
|
||||
return None
|
||||
|
||||
# 检查 operand 是否为结构体指针
|
||||
struct_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(operand)
|
||||
if struct_ty is None:
|
||||
return None
|
||||
|
||||
# 获取类名
|
||||
class_name: str = self.Gen.StructGen.get_class_name_by_type(pool, struct_ty)
|
||||
if class_name is None:
|
||||
return None
|
||||
|
||||
search_class: str = self._resolve_dunder_by_class(pool, mod, class_name, dunder, trans, struct_ty)
|
||||
if search_class is None:
|
||||
return None
|
||||
|
||||
# 调用方法:operand.__dunder__(extra_args…)
|
||||
return self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, search_class, dunder, operand, extra_args, extra_count, trans)
|
||||
|
||||
# ============================================================
|
||||
# coerce_cond_to_bool - 条件真值归一到 i1(唯一实现)
|
||||
#
|
||||
# if / while / and / or / 三元条件的条件转换全部汇聚于此:
|
||||
# 1. 已是 i1 → 原样返回;
|
||||
# 2. 类实例定义了 __bool__ → 调用之,结果 != 0;
|
||||
# 3. 指针 → != null;
|
||||
# 4. 其他 → != 0。
|
||||
# 语义唯一来源,避免各处各自演化出「struct 恒真」这类不一致判据。
|
||||
# ============================================================
|
||||
def coerce_cond_to_bool(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
val: llvmlite.Value*,
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""把条件值归一到 i1,优先调度 __bool__(类实例),否则与 0/null 比较"""
|
||||
if val is None:
|
||||
return None
|
||||
bits: int = self.get_llvm_type_bits(val.Ty)
|
||||
if bits == 1:
|
||||
return val
|
||||
# 类实例:优先调用 __bool__(指针指向结构体且类内定义了该方法)
|
||||
bres: llvmlite.Value* = self._try_named_dunder(pool, builder, mod, val, "__bool__", trans)
|
||||
if bres is not None:
|
||||
b_bits: int = self.get_llvm_type_bits(bres.Ty)
|
||||
if b_bits == 1:
|
||||
return bres
|
||||
if self.is_ptr_type(bres.Ty) != 0:
|
||||
null_b: llvmlite.Value* = llvmlite.ConstNull(pool, bres.Ty, "null")
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, bres, null_b)
|
||||
zero_b: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, bres, zero_b)
|
||||
if self.is_ptr_type(val.Ty) != 0:
|
||||
# 指针类型:与 null 比较(不能用整数 0,否则 llc 报类型不匹配)
|
||||
null_val: llvmlite.Value* = llvmlite.ConstNull(pool, val.Ty, "null")
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val)
|
||||
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero)
|
||||
# ============================================================
|
||||
# fail_if_double_ptr_binop - 双指针算术 fail-fast(**唯一实现**)
|
||||
#
|
||||
@@ -1432,6 +1572,24 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
if ovl_result2 is not None:
|
||||
return ovl_result2
|
||||
|
||||
# === 运算符重载路径 3: 反向运算符 —— lhs 无对应 dunder 时调度 rhs.__rX__(lhs) ===
|
||||
# (Python 语义:a + b → 先 a.__add__(b),缺失再 b.__radd__(a))
|
||||
# 先判 rhs 是否为结构体(非结构体直接跳过,避免无谓的实参池分配)
|
||||
r_dunder: str = self._rbinop_to_dunder(op)
|
||||
if r_dunder is not None:
|
||||
if self.Gen.StructGen.get_struct_type_from_value(rhs) is not None:
|
||||
rev_extra: sizet* = pool.alloc(8)
|
||||
if rev_extra is not None:
|
||||
rev_extra[0] = sizet(lhs)
|
||||
r_ovl: llvmlite.Value* = self._try_named_dunder(pool, builder, mod, rhs, r_dunder, trans, rev_extra, 1)
|
||||
if r_ovl is not None:
|
||||
return r_ovl
|
||||
|
||||
# `**` 幂运算:基础类型 → llvm.pow(整数结果按指数常量回写)。
|
||||
# 必须在浮点/整数分流之前处理,且已在重载路径之后(自定义类型走 __pow__)。
|
||||
if op == ast.OpKind.Pow:
|
||||
return self.emit_pow(pool, builder, mod, lhs, rhs, node, trans)
|
||||
|
||||
# 获取操作数类型信息
|
||||
lhs_bits: int = self.get_llvm_type_bits(lhs.Ty)
|
||||
rhs_bits: int = self.get_llvm_type_bits(rhs.Ty)
|
||||
|
||||
@@ -745,21 +745,11 @@ novirtual class StmtGenCifMixin:
|
||||
cond_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, if_node.test,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
|
||||
# 2. 转换为 i1 条件
|
||||
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
|
||||
# 2. 转换为 i1 条件(优先调度 __bool__;Compare/Not 已返回 i1)
|
||||
if cond_val is None:
|
||||
# fail-fast: if 条件表达式翻译失败
|
||||
self.Gen.TypeGenErr.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError")
|
||||
cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty)
|
||||
if cond_bits == 1:
|
||||
cond_i1: llvmlite.Value* = cond_val
|
||||
elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0:
|
||||
# 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type")
|
||||
null_cond: llvmlite.Value* = llvmlite.ConstNull(pool, cond_val.Ty, "null")
|
||||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
|
||||
else:
|
||||
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
|
||||
cond_i1: llvmlite.Value* = self.Gen.ExprGenOps.coerce_cond_to_bool(pool, builder, trans.Module, cond_val, trans)
|
||||
|
||||
# 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享)
|
||||
cnt: int = trans._label_counter
|
||||
@@ -961,17 +951,8 @@ novirtual class StmtGenCifMixin:
|
||||
# fail-fast: while 条件表达式翻译失败
|
||||
self.Gen.TypeGenErr.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError")
|
||||
|
||||
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
|
||||
cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty)
|
||||
if cond_bits == 1:
|
||||
cond_i1: llvmlite.Value* = cond_val
|
||||
elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0:
|
||||
# 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type")
|
||||
null_cond: llvmlite.Value* = llvmlite.ConstNull(pool, cond_val.Ty, "null")
|
||||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
|
||||
else:
|
||||
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
|
||||
# 转换为 i1(优先调度 __bool__;Compare/Not 已返回 i1)
|
||||
cond_i1: llvmlite.Value* = self.Gen.ExprGenOps.coerce_cond_to_bool(pool, builder, trans.Module, cond_val, trans)
|
||||
llvmlite.build_cond_br(builder, cond_i1, body_bb, else_bb_while if else_bb_while is not None else end_bb)
|
||||
|
||||
# 4. body 块: 翻译循环体,跳回 cond
|
||||
|
||||
@@ -124,11 +124,25 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
tgt: ast.AST* = dnode.targets.get(ti)
|
||||
if tgt is None:
|
||||
continue
|
||||
# del obj.attr → property deleter
|
||||
if tgt.kind() == ast.ASTKind.Attribute:
|
||||
# del obj → __delete__(对齐 TPC HandlesDelete.py:Name 目标调用 __delete__,
|
||||
# 类未定义 __delete__ 时静默无操作)
|
||||
if tgt.kind() == ast.ASTKind.Name:
|
||||
del_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, tgt, None, 0, trans)
|
||||
if del_obj is not None:
|
||||
del_st_nm: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(del_obj)
|
||||
if del_st_nm is not None:
|
||||
del_cls_nm: str = self.Gen.StructGen.get_class_name_by_type(pool, del_st_nm)
|
||||
if del_cls_nm is not None:
|
||||
self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, del_obj, "__delete__", trans)
|
||||
# del obj.attr → property deleter;无 deleter 时回退对象 __del__(对齐 TPC)
|
||||
elif tgt.kind() == ast.ASTKind.Attribute:
|
||||
del_at: ast.Attribute* = ast.Attribute*(tgt)
|
||||
if del_at is not None:
|
||||
self.Gen.CallGenProp._try_property_deleter(pool, builder, mod, del_at, trans)
|
||||
del_prop: int = self.Gen.CallGenProp._try_property_deleter(pool, builder, mod, del_at, trans)
|
||||
if del_prop == 0:
|
||||
del_av: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, del_at, None, 0, trans)
|
||||
if del_av is not None:
|
||||
self.Gen.ExprGenOps._try_named_dunder(pool, builder, mod, del_av, "__del__", trans)
|
||||
# del obj[key] → __delitem__(obj, key)(对齐 TPC HandlesDelete.py)。
|
||||
# 不能静默忽略 Subscript 目标——否则 del 不生效(len 不变)。
|
||||
elif tgt.kind() == ast.ASTKind.Subscript:
|
||||
|
||||
Reference in new issue
Block a user