fix(decl): 声明端看穿「装饰器标记 + 裸类引用」联合,修 t.CExtern|X|t.CPtr 多外包一层指针

根因:vpi 记录的模块级全局是 `_mbuddy: t.CExtern | memhub.MemBuddy | t.CPtr` 形态,_get_type_str 把该联合展开为 %"sha1.MemBuddy"*(标记 t.CExtern 展开为空串,已被 BinOp 分支丢弃),但外层 | t.CPtr 走 _is_bare_class_ref_annotation 时对 ast.BinOp 一律 return False ⇒ 未吸收"裸类引用自身即指针"那一层 ⇒ 声明端 %X** 与定义端 %X* 差一层。

后果:Phase1 生成的 .stub.ll 声明 @_mbuddy = external global %X**,消费模块按下声明取值得到 %X**,赋给 %X* 字段(VLogger.vp:105 self.__mbuddy__ = _mbuddy)即报"指针隐式转换已禁止(层数不同)"。

修法:BinOp 分支内若恰一侧展开为空/void(纯装饰器标记 CExtern/CExport/State/CStatic...)则按另一侧递归判定,对齐 TPV TypeGenResolve.vp:2596 第 3 条语义「ActualType | DecoratorMarker → ActualType」(TPV 无此问题,故只改 TPC)。

探针验证:t.CExtern|X|t.CPtr / X|None|t.CPtr / t.State|X|t.CPtr → %X*(修正);X|t.CPtr、rawptr[X]|t.CPtr → %X**、bytes|t.CPtr → i8**、int|t.CPtr → i32*(均不变)。注意 .stub.ll 有全局缓存,需 --clear-cache 重编生效。
This commit is contained in:
TermiNexus committed 2026-09-28 16:35:53 +08:00
1 parent 809f9d08fa
commit 5d1620505e
1 file changed
+19
+19
View File
@@ -1121,10 +1121,29 @@ class DeclarationGenerator:
下标(rawptr[...] / t.CPtr[...])不是裸类引用——它们已自带指针层数,
须逐层外包(rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr
→ AST**,与定义端整体拉平后只吸收一次 CPtr 一致)。
**例外:纯装饰器标记联合**。`t.CExtern | X` / `t.CExport | X` / `t.State | X`
(vpi 记录的模块级全局就是这种写法,见 lib.Phase.Phase1.__init__.vpi 的
`_mbuddy: t.CExtern | memhub.MemBuddy | t.CPtr`)里标记侧展开为**空串**
(CTypeRegistry.NameToLLVM('CExtern') == ''),该联合语义上仍是 X 这一个
裸类引用,故 `t.CExtern | X | t.CPtr` 必须与 `X | t.CPtr` 同判(吸收)——
对齐 TPV TypeGenResolve 的第 3 条语义「ActualType | DecoratorMarker →
ActualType」。漏此判据时联合被当成"已自带指针层数的左值"而多外包一层:
声明端 `%"sha1.X"**` 与定义端 `%"sha1.X"*` 差一层,消费模块里
`self.__mbuddy__ = _mbuddy` 之类的赋值即报"层数不同"fail-fast。
"""
if not inner_type:
return False
if isinstance(inner, ast.BinOp):
if not isinstance(inner.op, ast.BitOr):
return False
LeftType: str = self._get_type_str(inner.left)
RightType: str = self._get_type_str(inner.right)
# 恰一侧是纯装饰器标记(展开为空/void)⇒ 类型全部来自另一侧,按另一侧判
if LeftType in ('', 'void') and RightType not in ('', 'void'):
return self._is_bare_class_ref_annotation(inner.right, RightType)
if RightType in ('', 'void') and LeftType not in ('', 'void'):
return self._is_bare_class_ref_annotation(inner.left, LeftType)
return False
if isinstance(inner, ast.Subscript):
return not (IsRawPtrSubscriptNode(inner) or IsCPtrSubscriptNode(inner))