diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 6e7c6b5..72f4a3d 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -278,6 +278,25 @@ class AssignHandle(BaseHandle): else: if VarName in ('mctx', 's1ctx', 's2ctx', 's5ctx'): pass + # 【联合返回注解的被指类恢复】RHS 是调用、且值的 LLVM 类型是**通用指针** + # (i8*/i8**,pointee 不是结构体)时,上面那块类名推断整块失效 —— 现场 + # `parts = s1.split(',')`:`split` 的返回注解 `list[str]*` ≡ + # `list[str] | t.CPtr`(只读探针确认二者 AST 逐字同形)被映射成 i8* + # ⇒ 类名丢失 ⇒ 随后 `parts[0]` 不走 `list[str].__getitem__` 而按通用 + # 指针/字节索引 ⇒ 得到整数 ⇒ 赋给 `str` 时报"整数隐式转指针已禁止" + # (真因在 4 行之前,报文完全指不到)。此处从被调者的**返回注解** + # 取回被指类名(判据与 HandlesAnnAssign 的同类恢复同源)。 + if (not Gen.var_struct_class.get(VarName) + and isinstance(Node.value, ast.Call) + and isinstance(Value.type, ir.PointerType) + and not isinstance(Value.type.pointee, + (ir.IdentifiedStructType, ir.LiteralStructType))): + _rc: str | None = self.Trans.ExprCallHandle._CallReturnClass(Node.value, Gen) + if _rc: + Gen.var_struct_class[VarName] = _rc + if getattr(Gen, 'global_struct_class', None) is not None: + Gen.global_struct_class[VarName] = _rc + Gen._var_to_heap_ptr[VarName] = Value if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): # BUG-8 修复:清除读取全局变量时缓存的 GlobalVariable(非显式 global 声明) if (VarName in Gen.variables and VarName not in Gen.global_vars diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 0da4df0..46f22f7 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -4266,6 +4266,108 @@ class ExprCallHandle(BaseHandle): raw_name: str = self._get_raw_type_name(sn) return (type_str, raw_name) + @staticmethod + def _IsCPtrMark(Node: ast.AST) -> bool: + """`t.CPtr` / 裸名 `CPtr` 标记节点。""" + if isinstance(Node, ast.Attribute): + return Node.attr == 'CPtr' + if isinstance(Node, ast.Name): + return Node.id == 'CPtr' + return False + + def _CallReturnClass(self, Node: ast.Call, Gen: LlvmGeneratorMixin) -> str | None: + """调用结果的**被指类名**:从被调者的返回注解恢复。 + + 背景:`list[str]*` ≡ `list[str] | t.CPtr`(只读探针已确认二者 AST 逐字同形, + 都是 `BinOp(BitOr, Subscript(...), Attribute(t.CPtr))`)这类返回注解在 LLVM 层 + 被映射成通用指针 `i8*`,类名随之丢失 ⇒ 调用点只能按通用指针处理 + (`parts = s1.split(',')` 之后 `parts[0]` 退化成按字节索引、得到整数,赋给 + `str` 时报"整数隐式转指针已禁止",真因在 4 行之前)。 + 本方法把类名从**注解**取回;判据与 HandlesAnnAssign 的同类恢复 + (:644-684 `rawptr[X]`、:1012-1034 联合注解构特化名)同源。 + 取不到返回 None —— 调用方据此不改动既有行为。 + """ + _fn: ast.AST = Node.func + _cands: list[str] = [] + if isinstance(_fn, ast.Name): + _cands.append(_fn.id) + elif isinstance(_fn, ast.Attribute): + _m: str = _fn.attr + _recv_cls: str | None = None + if isinstance(_fn.value, ast.Name): + _recv_cls = (Gen.var_struct_class.get(_fn.value.id) + or (getattr(Gen, 'global_struct_class', {}) or {}).get(_fn.value.id)) + # FakeDuck 影子类(str→_str / bytes→_bytes)与接收者真实类名两条线都试; + # FuncDefCache 的方法键在仓库里既有 'cls.method' 也有裸 'method' 两种形态。 + for _c in ([_recv_cls] if _recv_cls else []) + ['_str', '_bytes']: + _cands.append(f'{_c}.{_m}') + _cands.append(_m) + for _nm in _cands: + _fd: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(_nm) + if _fd is not None and _fd.returns is not None: + _cls: str | None = self._ClassFromAnnotation(_fd.returns, Gen) + if _cls: + return _cls + return None + + def _ClassFromAnnotation(self, Ann: ast.AST, Gen: LlvmGeneratorMixin) -> str | None: + """从注解恢复"类名(含泛型特化名)":剔除 `| t.CPtr` 侧与指针层后取核类型。 + + - `list[str] | t.CPtr` / `list[str]*` → `list[str]`(泛型特化名,与 + HandlesAnnAssign:1012-1034 的构名方式一致); + - `Foo | t.CPtr` / `Foo*` → `Foo`; + - 核类型名必须能在 `Gen.structs` / `Gen.class_members` 命中(含 sha1 前缀 + 全名的短名归一),否则返回 None(类型信息不完整时不硬塞名字)。 + """ + _core: ast.AST = Ann + if isinstance(_core, ast.BinOp) and isinstance(_core.op, ast.BitOr): + _l: ast.AST = _core.left + _r: ast.AST = _core.right + if self._IsCPtrMark(_r): + _core = _l + elif self._IsCPtrMark(_l): + _core = _r + else: + return None + if isinstance(_core, ast.Subscript): + _base: ast.expr = _core.value + _bn: str | None = None + if isinstance(_base, ast.Name): + _bn = _base.id + elif isinstance(_base, ast.Attribute): + _bn = _base.attr + if not _bn: + return None + _sl: ast.AST = _core.slice + if hasattr(ast, 'Index') and isinstance(_sl, ast.Index): + _sl = _sl.value + _r2: tuple[str, str] | None = self._resolve_generic_slice_type(_sl) + if not _r2: + return None + _spec: str = f'{_bn}[{_r2[0]}]' + if _spec in Gen.structs or _spec in Gen.class_members: + return _spec + # 端键归一:特化键可能是 sha1 前缀全名 + for _k in Gen.structs: + if _k.split('.')[-1] == _spec: + return _k + return _spec + if isinstance(_core, ast.Name): + if _core.id in Gen.structs or _core.id in Gen.class_members: + return _core.id + for _k in Gen.structs: + if _k.split('.')[-1] == _core.id: + return _k + return None + if isinstance(_core, ast.Attribute): + if _core.attr in Gen.structs or _core.attr in Gen.class_members: + return _core.attr + for _k in Gen.structs: + if _k.split('.')[-1] == _core.attr: + return _k + return None + return None + def _ResolveGenericSlice(self, Sub: ast.Subscript) -> str | None: """从泛型 Subscript (如 Stack[int]) 解析特化名,确保特化类型已生成。""" if not isinstance(Sub.value, ast.Name):