feat(viperc): 纯常量折叠补上 / // %,与 + - * 同口径(精确值 + 按值自动提升位宽)

口径与 AssignGenMixin 的常量求值器逐字对齐:①除零先关折叠再 fail-fast(同一条诊断文案,避免交给宿主 Python 打挂编译器);②结果按精确值自动提升位宽,不无故抬宽;③负数语义待定 ⇒ 本轮只折叠两侧都非负的情形(此时 sdiv 与 udiv 结果相同、无歧义),含负操作数的算式不折叠,照旧走运行期 sdiv/udiv/srem/urem。
This commit is contained in:
TermiNexus committed 2026-10-14 22:27:55 +08:00
1 parent dc4468593c
commit 38a277a914
1 file changed
+15
+15
View File
@@ -1344,6 +1344,21 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
elif op == ast.OpKind.BitOr: cf_v = lhs.IntVal | rhs.IntVal
elif op == ast.OpKind.BitAnd: cf_v = lhs.IntVal & rhs.IntVal
elif op == ast.OpKind.BitXor: cf_v = lhs.IntVal ^ rhs.IntVal
elif op == ast.OpKind.Div or op == ast.OpKind.FloorDiv or op == ast.OpKind.Mod:
# 除法/整除/取模也做静态折叠(与 + - * 同口径:算精确值,再由下面按值自动提升位宽)。
# ① 除零:绝不交给宿主(Python 会直接把编译器打挂)——先关掉折叠再 fail-fast
# (诊断口径与 AssignGenMixin 的常量求值器一致)。
# ② 负数语义**待定**(负值参与时 sdiv/srem 的向零截断 vs 地板语义尚无结论)⇒
# 暂只折叠两侧都非负的情形(此时 sdiv 与 udiv 结果相同,无歧义);
# 含负操作数的算式不折叠,照旧走运行期 sdiv/udiv/srem/urem。
if rhs.IntVal == 0:
cf_ok = 0
self.Gen.TypeGenErr.fatal_error(node, "constant expression division by zero: the right operand of '/', '//' or '%' evaluates to 0 at compile time.", "ValueError")
elif lhs.IntVal >= 0 and rhs.IntVal >= 0:
if op == ast.OpKind.Mod: cf_v = lhs.IntVal % rhs.IntVal
else: cf_v = lhs.IntVal // rhs.IntVal
else:
cf_ok = 0
elif op == ast.OpKind.LShift or op == ast.OpKind.RShift:
if rhs.IntVal >= 0 and rhs.IntVal < 64:
if op == ast.OpKind.LShift: cf_v = lhs.IntVal << rhs.IntVal