fix(Handles): 注解声明的类是权威类型,赋值不得改掉它
新增 var_annotated_class 台账(AnnAssign 声明完成时登记真实类名,随 var_struct_class 在函数作用域清空),HandlesAssign 三处「右值推出类」登记点命中该台账时不再覆盖声明类型。否则 node: rawptr[AST] = Name(...) 会把 node 记成 Name,后续 node = <AST*> 被判成被禁止的向下转型(includes/ast/parser.vp:1919)。
This commit is contained in:
1 parent
ecd336771f
commit
b0aa9f6d76
4 files changed
+61
-5
No files matched your search
@@ -449,6 +449,28 @@ class AnnAssignHandle(BaseHandle):
|
||||
self._HandleAnnAssignLlvmInner(Node)
|
||||
finally:
|
||||
self.Trans._current_assign_node = None
|
||||
# 【注解声明类台账(2026-09-30)】带注解声明过的变量,其类名由**声明**决定,
|
||||
# 是权威类型:后续赋值只能把右值**转换进**该类型,不能反过来改掉它。
|
||||
# 放在 Inner **返回之后**:Inner 内部多处(BinOp 联合短名回退、rawptr[X] 恢复等)
|
||||
# 会按注解写 var_struct_class,此处取的是**终值**。
|
||||
# 反例(现场 includes/ast/parser.vp:1899 与 :1919):
|
||||
# `node: rawptr[AST] = Name(ps.pool, name_str, ASTCtx.Load)` —— 本行本身合法(上转)
|
||||
# 但若让右值推出的类 `Name` 覆盖声明的 `AST`,则下一处
|
||||
# `node = _parse_fstring(...)`(返回 rawptr[AST])就变成被禁止的**向下转型**:
|
||||
# TPV 报 "指针隐式转指针已禁止:源类型 %AST* → 目标类型 %Name*"。
|
||||
if isinstance(getattr(Node, 'target', None), ast.Name) and getattr(Node, 'annotation', None) is not None:
|
||||
_VarName: str = Node.target.id
|
||||
_DeclCls: str | None = Gen.var_struct_class.get(_VarName)
|
||||
# 只把**真实类名**记为权威:指针/未知标记名(rawptr/CPtr/... 这些是联合
|
||||
# 注解 `rawptr[T]`/`X | t.CPtr` 折叠后的占位名,可能恰好在 Gen.structs 里)
|
||||
# 不表态具体类,若一并记为权威会挡住"无注解赋值从右值推断类名"的正常路径
|
||||
# (如 `p: t.CPtr = Point()` 之后 `p.x` 需要 Point)。
|
||||
if _DeclCls and _DeclCls not in _PTR_MARKER_CLASS_NAMES:
|
||||
_M: dict = getattr(Gen, 'var_annotated_class', None)
|
||||
if _M is None:
|
||||
_M = {}
|
||||
Gen.var_annotated_class = _M
|
||||
_M[_VarName] = _DeclCls
|
||||
|
||||
def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None:
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
|
||||
@@ -18,6 +18,23 @@ class AssignHandle(BaseHandle):
|
||||
super().__init__(translator)
|
||||
self._CurrentCpythonObjectClass: str | None = None
|
||||
|
||||
@staticmethod
|
||||
def _DeclaredClassBlocksOverride(Gen: Any, VarName: str) -> bool:
|
||||
"""该变量是否**已由类型注解声明**了类名(是 ⇒ 本次赋值不得改掉它的类)。
|
||||
|
||||
判据(正向事实):`Gen.var_annotated_class[VarName]` 由 HandlesAnnAssign 在
|
||||
**带注解的声明完成时**登记(取注解解析的终值)。有它就意味着这个变量的类型是
|
||||
**声明**出来的 ⇒ 赋值只能把右值**转换进**声明类型,不能反过来把变量重新定型。
|
||||
|
||||
为什么要这条:`node: rawptr[AST] = Name(...)` 里右值构造调用推出的是 `Name`,
|
||||
若覆盖声明的 `AST`,下一处 `node = <AST*>`(函数返回类型 AST)就变成被禁止的
|
||||
**向下转型** —— 现场 includes/ast/parser.vp:1919,TPV 报
|
||||
"指针隐式转指针已禁止:源类型 %AST* → 目标类型 %Name*"(本判据是两侧同源的唯一真源)。
|
||||
"""
|
||||
if not VarName:
|
||||
return False
|
||||
return VarName in (getattr(Gen, 'var_annotated_class', None) or {})
|
||||
|
||||
@staticmethod
|
||||
def _contains_identified_struct(var_type: ir.Type) -> bool:
|
||||
if isinstance(var_type, ir.IdentifiedStructType):
|
||||
@@ -198,7 +215,10 @@ class AssignHandle(BaseHandle):
|
||||
# → i32 返回值被 zext+inttoptr 当指针 → 崩溃。因此变量已有
|
||||
# 同 base 的声明类型时不覆盖(保留声明名,方法解析走声明名)。
|
||||
_prev_cls: str | None = Gen.var_struct_class.get(VarName)
|
||||
if _prev_cls and '[' in _prev_cls and '[' in CN and _prev_cls.split('[')[0] == CN.split('[')[0]:
|
||||
if self._DeclaredClassBlocksOverride(Gen, VarName):
|
||||
# 注解声明的类是权威类型(见 _DeclaredClassBlocksOverride)
|
||||
pass
|
||||
elif _prev_cls and '[' in _prev_cls and '[' in CN and _prev_cls.split('[')[0] == CN.split('[')[0]:
|
||||
pass
|
||||
else:
|
||||
Gen.var_struct_class[VarName] = CN
|
||||
@@ -219,7 +239,10 @@ class AssignHandle(BaseHandle):
|
||||
# 同类特化覆盖保护(见上方 L189 注释):短名匹配的
|
||||
# sha1 前缀变体不覆盖声明注解类型
|
||||
_prev_cls2: str | None = Gen.var_struct_class.get(VarName)
|
||||
if _prev_cls2 and '[' in _prev_cls2 and '[' in found_class and _prev_cls2.split('[')[0] == found_class.split('[')[0]:
|
||||
if self._DeclaredClassBlocksOverride(Gen, VarName):
|
||||
# 注解声明的类是权威类型(见 _DeclaredClassBlocksOverride)
|
||||
pass
|
||||
elif _prev_cls2 and '[' in _prev_cls2 and '[' in found_class and _prev_cls2.split('[')[0] == found_class.split('[')[0]:
|
||||
pass
|
||||
else:
|
||||
Gen.var_struct_class[VarName] = found_class
|
||||
@@ -345,7 +368,7 @@ class AssignHandle(BaseHandle):
|
||||
Gen.variables[VarName] = GVar
|
||||
if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee)
|
||||
if found:
|
||||
if found and not self._DeclaredClassBlocksOverride(Gen, VarName):
|
||||
CN: str = found[0]
|
||||
ST: ir.Type = found[1]
|
||||
Gen.var_struct_class[VarName] = CN
|
||||
|
||||
@@ -2208,7 +2208,11 @@ class FunctionHandle(BaseHandle):
|
||||
Gen.var_signedness = {}
|
||||
Gen._reg_values = {}
|
||||
Gen._direct_values = {}
|
||||
Gen.var_struct_class = {}
|
||||
Gen.var_struct_class = {}
|
||||
# 注解声明类台账是**函数作用域**的(局部变量的声明随函数出栈失效),
|
||||
# 与 var_struct_class 同处清空 —— 否则同名变量会在别的函数里被误判为
|
||||
# "已由注解声明",从而挡住右值推出类的正常登记。
|
||||
Gen.var_annotated_class = {}
|
||||
Gen.var_ptr_element = {}
|
||||
Gen.var_const_flags = {}
|
||||
# const/volatile 的**函数作用域层**随函数出栈清空(模块级层 global_* 与
|
||||
|
||||
@@ -356,7 +356,14 @@ class BaseGenMixin:
|
||||
self.global_vars: set[str] = set()
|
||||
self.nonlocal_params: dict[str, Any] = {}
|
||||
self._variable_scope_stack: list[dict[str, Any]] = [] # Stack of outer scope variables for nested function nonlocal lookup
|
||||
self.var_struct_class: dict[str, str] = {}
|
||||
self.var_struct_class: dict[str, str] = {}
|
||||
# 【注解声明类台账(2026-09-30)】带类型注解声明过的变量 → 其**权威**类名。
|
||||
# 由 HandlesAnnAssign 在声明完成时登记;HandlesAssign 的"右值推出类"登记点
|
||||
# 见 var_annotated_class 命中即**不覆盖** —— 声明决定变量类型,赋值只能把右值
|
||||
# 转换进该类型。否则 `node: rawptr[AST] = Name(...)` 会把 node 记成 Name,
|
||||
# 后续 `node = <AST*>` 就被判成被禁止的向下转型
|
||||
# (现场 includes/ast/parser.vp:1919:%AST* → %Name*)。
|
||||
self.var_annotated_class: dict[str, str] = {}
|
||||
self.var_ptr_element: dict[str, bool] = {}
|
||||
# 全局变量的指针元素标志(持久,不受函数重置影响)
|
||||
# 用于全局变量 _argv: bytes | t.CPtr 等,使 _argv[index] 使用 8 字节指针步长
|
||||
|
||||
Reference in new issue
Block a user