diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index d3f4bd7..375570f 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -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")