fix(gen): 复合赋值取消「右值有符号 vs 左值无符号」拦截,与二元 x = x op y 口径一致(修 sizet += int 误报)

This commit is contained in:
TermiNexus committed 2026-10-12 21:16:50 +08:00
1 parent c9562a6e04
commit c0ff5c9d96
1 file changed
+9 -11
+9 -11
View File
@@ -1446,11 +1446,15 @@ novirtual class AssignGenMixin:
# Double-pointer arithmetic: delegate the check to ExprGenOps.fail_if_double_ptr_binop
self.Gen.ExprGenOps.fail_if_double_ptr_binop(pool, op, lhs, rhs, node, 1)
# x op= y 的操作数约束(fail-fast,先于运算与提升):
# ① y 的有效宽度必须 <= x 的宽度。变量按其 LLVM 类型宽度;常量按其值的**最小可存宽度**
# (所以 `u8 += 1` 合法、`u8 += 300` 报错)。y 更宽 = 隐式收窄,必须先显式收窄再写。
# ② 不允许 y 显式有符号而 x 无符号:负值经符号扩展会变成巨大的无符号值,属静默语义改变。
# 移位(<<= / >>=)**豁免** ①②:计数不是写回目标的值,改用静态范围检查(见下方)。
# x op= y 的操作数宽度约束(fail-fast,先于运算与提升):
# y 的有效宽度必须 <= x 的宽度。变量按其 LLVM 类型宽度;常量按其值的**最小可存宽度**
# (所以 `u8 += 1` 合法、`u8 += 300` 报错)。y 更宽 = 隐式收窄,必须先显式收窄再写。
# 移位(<<= / >>=)**豁免**:计数不是写回目标的值,改用静态范围检查(见下方)。
#
# 说明:右值有符号而左值无符号**不再单独拦截**——拓宽方向已由 sext/zext 规则统一决定
# (i 类 sext、u 类 zext,见 wiki/Implicit.md §1.1),且二元形态 `x = x op y` 本就允许
# (如 `sizet += int` 里 int 先拓宽到 u64 再相加)。两条路径口径必须一致,否则同一语义
# 换个写法就报错。
y_node_aa: ast.AST* = None
if node is not None and node.kind() == ast.ASTKind.AugAssign: y_node_aa = ast.AugAssign*(node).value
if lhs_bits != 0 and rhs_bits != 0 and op != ast.OpKind.LShift and op != ast.OpKind.RShift:
@@ -1460,12 +1464,6 @@ novirtual class AssignGenMixin:
if cn_aa.const_kind == ast.CONST_INT: y_bits_eff = self.define_min_width(cn_aa.int_val)
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")
x_uns_aa: int = 0
if lhs_node is not None: x_uns_aa = self.Gen.ExprGenOps._node_type_unsigned(pool, lhs_node, trans)
y_sgn_aa: int = 0
if y_node_aa is not None: y_sgn_aa = self.Gen.ExprGenOps._node_type_signed(pool, y_node_aa, trans)
if x_uns_aa != 0 and y_sgn_aa != 0:
self.Gen.TypeGenErr.fatal_error(node, "[VPC] augmented assignment operand signedness conflict: the right-hand side is explicitly signed " "while the target is unsigned; sign extension would turn negative values into huge unsigned values. " "Fix: use an unsigned right-hand side (e.g. uint32(...)), or make the target signed.", "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)