feat(viperc): 静态常量算式补上除法/整除/取模折叠(与运行期 sdiv/srem 同口径)
此前纯常量折叠只覆盖 + - * | & ^ << >>,Div/FloorDiv/Mod 一律落到运行期 sdiv/udiv/srem/urem。现按同一维护口径补上:以精确值折叠,再由既有逻辑按结果值自动提升位宽(不无故抬宽,避免把 A/1 这类算式整体抬成 i64)。语义与运行期一致:Div/FloorDiv → sdiv(向零截断)、Mod → srem(余数符号随被除数)——宿主侧 // 与 % 正是这两个语义,无须额外修正;无符号位型常量按规范恒为非负,与运行期 udiv/urem 取值一致。除零不交给宿主(会打挂编译器):先关掉折叠再 fail-fast,诊断文本与 AssignGenMixin 的常量求值器保持一致。
This commit is contained in:
1 parent
38a277a914
commit
3a687db0bb
1 file changed
+9
-11
@@ -1345,20 +1345,18 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
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。
|
||||
# 除法/整除/取模也做静态折叠(与 + - * 完全同口径:算精确值,再由下面按值自动提升位宽)。
|
||||
# 语义**与运行期一致**:Div/FloorDiv → sdiv(向零截断),Mod → srem(余数符号随被除数)
|
||||
# —— 宿主侧的 `//` / `%` 正是这两个语义(本语言把 FloorDiv 也映射成 sdiv,
|
||||
# 见本文件运行期分支;AssignGenMixin 的常量求值器同款)。无符号位型常量按规范
|
||||
# 恒为非负,负值常量必属有符号操作数集 ⇒ 与运行期 udiv/urem 的取值一致。
|
||||
# 除零:绝不交给宿主(Python 会直接把编译器打挂)——先关掉折叠再 fail-fast
|
||||
# (诊断文本与 AssignGenMixin 的常量求值器一致)。
|
||||
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.Mod: cf_v = lhs.IntVal % rhs.IntVal
|
||||
else: cf_v = lhs.IntVal // rhs.IntVal
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user