feat(cast): 放行数组退让([N]T* → T* 单向),与 TPC 同口径

新增 _is_array_decay(复用 is_array_type + LLVMType.Array 解构 + AssignGen._stg_ty_equal),在 _pointee_convert_reason 的非基本分支里紧接 _is_inheritance_upcast 之后调用

与 TPC 真值表一致:数组→元素指针 ALLOW、反向 DENY、多维只退一层;其余规则(通用指针/层数/完全相同/None/构造物化/标量无损/继承上转)未动
This commit is contained in:
TermiNexus committed 2026-09-28 15:38:42 +08:00
1 parent e2c4c7645e
commit be1acdb602
1 file changed
+37 -2
+37 -2
View File
@@ -619,11 +619,41 @@ novirtual class ExprGenBase:
i += 1
return 0
# ============================================================
# _is_array_decay - 数组退让判据([N]T* → T*,单向)
#
# 规则 2 的豁免:源被指类型是**定长数组** Array(T, N),且目标被指类型恰为该
# 数组的**元素类型** T ⇒ 允许隐式转换(数组指针 → 元素指针,C/C++ 同口径)。
# 多维数组按「最外层退让一层」自然处理:Array(Array(T, M), N) 的元素是
# Array(T, M) ⇒ Array(Array(T,M),N)* → Array(T,M)* 命中;→ T* 不命中
# (元素是 Array(T,M) ≠ T)。反向 T* → Array(T,N)* 因源被指类型非数组而不命中。
# 元素类型同一性复用本仓既有 AssignGen._stg_ty_equal(内容比较),不新造表。
# 返回 1=允许退让 / 0=否。
# ============================================================
def _is_array_decay(self, pool: memhub.MemBuddy*,
src_pt: llvmlite.LLVMType*,
dst_pt: llvmlite.LLVMType*) -> int:
"""源被指类型是定长数组且目标被指类型是其元素类型:1=是 / 0=否"""
if src_pt is None or dst_pt is None:
return 0
if self.is_array_type(src_pt) == 0:
return 0
elem: llvmlite.LLVMType* = None
match src_pt:
case llvmlite.LLVMType.Array(et, _):
elem = et
case _:
return 0
if elem is None:
return 0
return self.Gen.AssignGen._stg_ty_equal(pool, elem, dst_pt)
# ============================================================
# _pointee_convert_reason - 被指类型 src_pt → dst_pt(T*→U* 的 T→U 关系)判定码
#
# 规则 2:T* → U*(T、U 都非通用指针)允许 ⇔ 被指类型 T → U 无损。
# 豁免:T、U 都是已注册类且 U 是 T 的基类(含多级)时,Derived* → Base*
# 豁免一:T、U 都是已注册类且 U 是 T 的基类(含多级)时,Derived* → Base*
# 继承上转允许(见 _is_inheritance_upcast)。
# 豁免二:T 是定长数组、U 恰为其元素类型时,数组退让 [N]T* → T* 允许(单向,
# 见 _is_array_decay)。反向 T* → [N]T* 不命中,仍禁止。
# 规则 3:非基本类型 T 与其指针 T* 之间(值/指针互换)一律禁止——此处体现为
# 被指类型一侧是「非基本值类型」、另一侧是「其指针(或其它的基本/非基本类型)」
# 时一律不匹配 ⇒ PC_NONBASIC。
@@ -645,9 +675,14 @@ novirtual class ExprGenBase:
return self._ptr_cast_reason(pool, src_pt, dst_pt)
# 一侧是非基本类型(结构体/类/联合/数组/函数)→ 一般禁止
if self._is_basic_scalar_ty(src_pt) == 0 or self._is_basic_scalar_ty(dst_pt) == 0:
# 豁免:Derived* → Base* 继承上转(含多级)允许(C++/GCC 同口径)
# 豁免一:Derived* → Base* 继承上转(含多级)允许(C++/GCC 同口径)
if self._is_inheritance_upcast(pool, src_pt, dst_pt) != 0:
return PC_OK
# 豁免二:数组退让(单向)——源被指类型是定长数组 Array(T, N)、目标被指
# 类型恰为其元素类型 T ⇒ 允许(数组指针 → 元素指针)。多维按最外层退让
# 一层;反向 T → Array(T, N) 与其它非基本类型规则不变,仍禁止。
if self._is_array_decay(pool, src_pt, dst_pt) != 0:
return PC_OK
return PC_NONBASIC
return self._scalar_convert_reason(src_pt, dst_pt)
# ============================================================