diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 2c9ef8c..d4d822e 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -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 diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 634d85b..fb7dac4 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -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)就变成被禁止的 + **向下转型** —— 现场 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 diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index 36982b4..ceb3873 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -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_* 与 diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index 7c3157a..3876ccc 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -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 = ` 就被判成被禁止的向下转型 + # (现场 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 字节指针步长