feat(gen): 复合赋值统一二元运算口径(常量无损适配另一侧、不做整数提升、RHS 按左值类型翻译),修 u16 -= 1 误报窄化
This commit is contained in:
1 parent
d2138678ef
commit
c1e5a11962
1 file changed
+57
-9
@@ -1494,15 +1494,57 @@ novirtual class AssignGenMixin:
|
||||
if y_node_aa is not None and y_node_aa.kind() == ast.ASTKind.Constant:
|
||||
cn_aa: ast.Constant* = ast.Constant*(y_node_aa)
|
||||
if cn_aa.const_kind == ast.CONST_INT: y_bits_eff = self.define_min_width(cn_aa.int_val)
|
||||
# 与 translate_binop 同口径:右值是能**无损落进左值位宽**的编译期常量时一律放行(复用同一处
|
||||
# 判定 _const_fits_int_type),交由下方等宽化的常量适配处理。覆盖 `-1` / `~x` / `True` 等
|
||||
# **折叠出的常量**(它们的 AST 不是 Constant,旧检查会误按 i32 宽度拦下,而二元形态
|
||||
# `u16 = u16 - (-1)` 却合法)——两条路径必须一致。
|
||||
if rhs.IsConst == 1 and self.Gen.ExprGenBase._const_fits_int_type(rhs, lhs.Ty) != 0: y_bits_eff = 0
|
||||
if y_bits_eff > lhs_bits:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"[VPC] augmented assignment operand too wide: the right-hand side needs {y_bits_eff} bits, " f"but the target provides only {lhs_bits} bits; an implicit narrowing is forbidden. " f"Fix: narrow the right-hand side explicitly (e.g. uint{lhs_bits}(...) / int{lhs_bits}(...)) before the operation.", "CastError")
|
||||
|
||||
# Integer op: type promotion
|
||||
if lhs_bits > rhs_bits and rhs_bits > 0: rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node, trans)
|
||||
elif rhs_bits > lhs_bits and lhs_bits > 0: lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node, trans)
|
||||
# 整型等宽化:与 translate_binop 的**非移位**口径逐项对齐,使 `x op= y` ≡ `x = x op y`。
|
||||
# 旧行为只做「谁宽就抬窄的一侧」,于是 `page.free_count(u16) -= 1` 会把 u16 抬到常量 1 的 i32
|
||||
# 宽度、再在收尾 coerce 回 i16 时撞「隐式窄化」;而二元形态 `x = x - 1` 因走 translate_binop 的
|
||||
# 常量适配(_const_operand_demotes)并不报错。这里复用**同一处**判定:左值类型即上下文目标位宽
|
||||
# (tgt_bits = lhs_bits),更宽的一侧若是能**无损落进另一侧**的编译期常量(`1` 默认 i32,但能
|
||||
# 无损落进 u16),就把常量降到左值位宽,而不是把左值抬到常量位宽。
|
||||
is_shift_aa: int = 0
|
||||
if op == ast.OpKind.LShift or op == ast.OpKind.RShift: is_shift_aa = 1
|
||||
if is_shift_aa != 0:
|
||||
# 移位:结果位宽 = 左操作数位宽(计数不代表结果类型,不参与位宽比较)。计数一律适配到左
|
||||
# 操作数类型:能静态确定且无损的常量按 coerce,运行时更宽的值按 C 语义 trunc——与
|
||||
# `x = x << y` 的 translate_binop 移位分支一致。
|
||||
if lhs_bits != 0 and rhs_bits != 0 and rhs.Ty != lhs.Ty:
|
||||
if rhs_bits < lhs_bits or self.Gen.ExprGenBase._const_fits_int_type(rhs, lhs.Ty) != 0:
|
||||
rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node, trans)
|
||||
else:
|
||||
rhs = mlirlite.build_trunc(builder, rhs, lhs.Ty)
|
||||
rhs_bits = lhs_bits
|
||||
else:
|
||||
is_bitwise_aa: int = 0
|
||||
if op == ast.OpKind.BitAnd or op == ast.OpKind.BitOr or op == ast.OpKind.BitXor: is_bitwise_aa = 1
|
||||
tgt_bits_aa: int = lhs_bits
|
||||
if lhs_bits > rhs_bits and rhs_bits > 0:
|
||||
# 更宽的一侧是左值(load,必非常量):能无损适配的右值常量降回右值类型,否则按 §1.1
|
||||
# 的统一方向(zext/sext)把更窄的右值拓宽到左值类型。
|
||||
if self.Gen.ExprGenOps._const_operand_demotes(is_bitwise_aa, lhs, lhs_bits, rhs, rhs.Ty, tgt_bits_aa) != 0:
|
||||
lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node, trans)
|
||||
elif self.Gen.ExprGenOps.should_zext_widen(pool, rhs, lhs, y_node_aa, trans) != 0:
|
||||
rhs = mlirlite.build_zext(builder, rhs, lhs.Ty)
|
||||
else:
|
||||
rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node, trans)
|
||||
elif rhs_bits > lhs_bits and lhs_bits > 0:
|
||||
# 更宽的一侧是右值:能无损落进左值位宽的常量降回左值类型(`u16 -= 1`),否则如实拓宽
|
||||
# 左值——左值被抬宽后会在收尾 coerce 处按「隐式窄化」fail-fast,与 `x = x op y` 一致。
|
||||
if self.Gen.ExprGenOps._const_operand_demotes(is_bitwise_aa, rhs, rhs_bits, lhs, lhs.Ty, tgt_bits_aa) != 0:
|
||||
rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node, trans)
|
||||
elif self.Gen.ExprGenOps.should_zext_widen(pool, lhs, rhs, lhs_node, trans) != 0:
|
||||
lhs = mlirlite.build_zext(builder, lhs, rhs.Ty)
|
||||
else:
|
||||
lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node, trans)
|
||||
|
||||
# 移位:计数本身豁免宽度/符号规则,改按**提升后**的左操作数位宽做静态范围检查
|
||||
if op == ast.OpKind.LShift or op == ast.OpKind.RShift:
|
||||
# 移位:计数本身豁免宽度/符号规则,改按左操作数位宽(= 结果位宽)做静态范围检查
|
||||
if is_shift_aa != 0:
|
||||
self.require_shift_count_in_range(pool, trans, node, y_node_aa, self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty))
|
||||
|
||||
# Unsigned operands use udiv/urem; signed use sdiv/srem
|
||||
@@ -1598,7 +1640,9 @@ novirtual class AssignGenMixin:
|
||||
cur_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, cur_val, bo_fa)
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
# 与 `x = x op y` 同口径:RHS 在左值类型(target_ty)上下文中翻译,嵌套 binop / CDefine 的
|
||||
# 目标感知与常量适配据此生效(旧行为 target_ty=None 使 RHS 口径与二元形态不一致)。
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans, target_ty)
|
||||
if rhs_val is None:
|
||||
# fail-fast: RHS translation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
@@ -1671,7 +1715,9 @@ novirtual class AssignGenMixin:
|
||||
cur_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, cur_val, bo_sa)
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
# 与 `x = x op y` 同口径:RHS 在左值类型(target_ty)上下文中翻译,嵌套 binop / CDefine 的
|
||||
# 目标感知与常量适配据此生效(旧行为 target_ty=None 使 RHS 口径与二元形态不一致)。
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans, target_ty)
|
||||
if rhs_val is None:
|
||||
# fail-fast: RHS translation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
@@ -1709,7 +1755,8 @@ novirtual class AssignGenMixin:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "deref augmented-assignment target type missing (pointee is empty)", "TypeError")
|
||||
old_ag: mlirlite.Value* = mlirlite.build_load(builder, ty_ag, ptr_ag, 0)
|
||||
if old_ag is None: self.Gen.TypeGenErr.fatal_error(target, "cannot load the current dereferenced value", "TypeError")
|
||||
rhs_ag: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
# 与 `x = x op y` 同口径:RHS 在解引用目标类型(ty_ag)上下文中翻译
|
||||
rhs_ag: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans, ty_ag)
|
||||
if rhs_ag is None: self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
res_ag: mlirlite.Value* = self._apply_aug_op(pool, builder, aug.op, old_ag, rhs_ag, node, trans, target)
|
||||
if res_ag is None: self.Gen.TypeGenErr.fatal_error(target, f"deref binary op failed op={aug.op}", "TypeError")
|
||||
@@ -1784,7 +1831,8 @@ novirtual class AssignGenMixin:
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"cannot load the current value of target variable '{nm.id}'", "TypeError")
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
# 与 `x = x op y` 同口径:RHS 在左值变量类型(target_ty)上下文中翻译
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans, target_ty)
|
||||
if rhs_val is None:
|
||||
# fail-fast: RHS translation failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "rhs translation failed", "TypeError")
|
||||
|
||||
Reference in new issue
Block a user