fix(gen): 取消「宽整型 -> bool(i1)」的隐式真值归一化,改为 fail-fast(仅保留编译期常量豁免)
This commit is contained in:
1 parent
d7c5af9b80
commit
97c0a1c6fd
2 files changed
+17
-10
No files matched your search
@@ -784,8 +784,10 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if self.Gen.ExprGenBase._zext_or_sext_val(pool, val, src_node, trans) != 0: return mlirlite.build_zext(builder, val, target_ty)
|
||||
return mlirlite.build_sext(builder, val, target_ty)
|
||||
else:
|
||||
# Target i1 (bool / t.CBool): both explicit casts and implicit stores normalise
|
||||
# truth as `x != 0 -> 1/0` (not trunc, which would make x=2 false while `if 2:` is true).
|
||||
# Target i1 (bool / t.CBool) via an EXPLICIT cast `t.CBool(x)` / `(bool)(x)`:
|
||||
# normalise truth as `x != 0 -> 1/0` (not trunc, which would make x=2 false while
|
||||
# `if 2:` is true). Implicit wide-int -> bool stores no longer normalise here; they
|
||||
# fail fast in coerce_to_type (rule 2026-10-13), so only explicit casts reach this.
|
||||
if target_bits == 1:
|
||||
zero_tc: mlirlite.Value* = mlirlite.const_int(pool, val_bits, 0)
|
||||
return mlirlite.build_icmp(builder, mlirlite.ICMP_NE, val, zero_tc)
|
||||
|
||||
@@ -598,20 +598,16 @@ novirtual class ExprGenBase:
|
||||
return val
|
||||
if val_bits != 0 and target_bits != 0:
|
||||
if val_bits == target_bits: return val
|
||||
# Target i1 (bool / t.CBool): truth normalization `x != 0 -> 1/0`
|
||||
# (C 6.3.1.2), not trunc; keeps parity with `bool(x)` and condition paths.
|
||||
if target_bits == 1:
|
||||
zero_i1: mlirlite.Value* = mlirlite.const_int(builder.Pool, val_bits, 0)
|
||||
return mlirlite.build_icmp(builder, mlirlite.ICMP_NE, val, zero_i1)
|
||||
if val_bits < target_bits:
|
||||
# Unified zext/sext: i1/i8 default zext, unsigned AST nodes zext,
|
||||
# otherwise sext. trans is required so unsigned annotations resolve.
|
||||
if self._zext_or_sext_val(builder.Pool, val, node, trans) != 0: return mlirlite.build_zext(builder, val, target_ty)
|
||||
return mlirlite.build_sext(builder, val, target_ty)
|
||||
# 隐式窄化**禁止**(规则 2026-10-10 收紧,取代"整数↔整数 所有方向都允许"):
|
||||
# 位宽高→低会丢高位,必须显式 cast 或加宽目标类型。仅两类豁免:
|
||||
# ① 目标 i1:真值归一化(x != 0),语义明确,不是位截断(已在上方返回);
|
||||
# ② 源是**编译期常量且值能落进目标位宽**(如字面量 5 → i32),无信息损失。
|
||||
# 位宽高→低会丢高位,必须显式 cast 或加宽目标类型。豁免只剩一类:
|
||||
# 源是**编译期常量且值能落进目标位宽**(如字面量 5 → i32、True/False → i1),无信息损失。
|
||||
# (注意 `True`/`False` 常量按 i32 1/0 物化,见 ExprGenConst.translate_constant,
|
||||
# 正是靠此豁免才能赋给 i1 目标。)
|
||||
if val.IsConst == 1:
|
||||
iv: int64 = val.IntVal
|
||||
lo_c: int64 = -(int64(1) << (target_bits - 1))
|
||||
@@ -619,6 +615,15 @@ novirtual class ExprGenBase:
|
||||
if iv < lo_c or iv > hi_c:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"narrowing truncation overflow: constant {iv} is outside the {target_bits}-bit representable range [{lo_c}, {hi_c}]; use an explicit cast or widen the target type", "OverflowError")
|
||||
return mlirlite.build_trunc(builder, val, target_ty)
|
||||
# 规则 2026-10-13:目标 i1(bool / t.CBool)**不再**对宽整型做隐式真值归一化
|
||||
# (旧的 `x != 0 -> 1/0`)。真值归一化会掩盖真实的位宽不匹配(如 `b: bool = some_i32`),
|
||||
# 属静默转换,必须 fail-fast;需要显式 `bool(x)` / `t.CBool(x)`。
|
||||
# 合法写法不受影响:比较(!=/==/…)、`and` / `or`、`not` 本身即产出 i1
|
||||
# (translate_compare / translate_boolop / translate_unaryop),i1 源走上面的
|
||||
# `val_bits == target_bits` 直接放行;True/False 常量走上面的常量豁免。
|
||||
if target_bits == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"implicit narrowing is forbidden: a {val_bits}-bit value cannot be implicitly assigned to bool (i1) (it would be silently reduced to its truthiness); use an explicit cast (e.g. bool(x) / t.CBool(x))", "CastError")
|
||||
return val
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"implicit narrowing is forbidden: a {val_bits}-bit value cannot be implicitly assigned to a {target_bits}-bit type (the high bits would be lost); use an explicit cast (e.g. int32(x) / t.CInt32T(x)) or widen the target type", "CastError")
|
||||
return val
|
||||
# Float conversion.
|
||||
|
||||
Reference in new issue
Block a user