diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py index 4918840..12ffba7 100644 --- a/lib/Projectrans/DeclarationGenerator.py +++ b/lib/Projectrans/DeclarationGenerator.py @@ -10,7 +10,7 @@ import llvmlite.ir as ir from lib.core import TypeSystem from lib.core.TypeSystem import CTypeRegistry from lib.core.SymbolUtils import ( - IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode, + IsListAnnotation, AnnotationContainsName, RejectTypeUnion, IsCPtrSubscriptNode, IsCPtrNode, IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr, EnumClassIntWidth, ClassHasFuncLevelCVTable) @@ -1187,6 +1187,8 @@ class DeclarationGenerator: if annotation is None: return 'i8*' + RejectTypeUnion(annotation) + non_struct_types: set[str] = {'list', 'dict', 'tuple', 'set', 'array', 'CArray', 'rawarray'} if isinstance(annotation, ast.Name): diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index 36562cc..746ef0f 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -5,7 +5,7 @@ if TYPE_CHECKING: from typing import List from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo from lib.core.SymbolUtils import ( - IsListAnnotation, IsPtrSubscriptNode, IsCPtrMarkerNode, + IsListAnnotation, IsPtrSubscriptNode, IsCPtrMarkerNode, RejectTypeUnion, DesugarPtrSubscriptToUnion) from lib.core import TypeSystem import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib) @@ -27,6 +27,7 @@ class HandlesTypeMerge(BaseHandle): def GetCTypeInfo(self, Node: ast.AST) -> CTypeInfo: """获取 CTypeInfo 对象""" + RejectTypeUnion(Node) Result = self._GetCTypeInfoInternal(Node) if isinstance(Result, CTypeInfo): return Result diff --git a/lib/core/LLVMTypeMapper.py b/lib/core/LLVMTypeMapper.py index 13d428e..93ce774 100644 --- a/lib/core/LLVMTypeMapper.py +++ b/lib/core/LLVMTypeMapper.py @@ -19,7 +19,7 @@ if TYPE_CHECKING: from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap from lib.core.SymbolUtils import ( - IsListAnnotation, IsCPtrNode, IsCPtrSubscriptNode, + IsListAnnotation, RejectTypeUnion, IsCPtrNode, IsCPtrSubscriptNode, IsRawPtrSubscriptNode, EnumIntWidth, ResolveGenericClassSpecName, GetStructSha1MapFromSymtab, GetTCAliasMapFromSymtab) from lib.core import TypeSystem as _t @@ -121,6 +121,7 @@ class LLVMTypeMapper: if node is None: self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32") return 'i32' + RejectTypeUnion(node) if isinstance(node, ast.Name): return self._resolve_name(node) elif isinstance(node, ast.Attribute): diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py index 43a73a8..d2491ae 100644 --- a/lib/core/SymbolUtils.py +++ b/lib/core/SymbolUtils.py @@ -2160,6 +2160,51 @@ def RequireNameDefined(Gen: object, Trans: object, Node: object, Name: str) -> N ) +# 类型注解中允许出现在 `|` 一侧的内建修饰标记。除此之外的任何 `T1 | T2` +# 都视为「类型联合」并直接拒绝:类型注解只能是单一类型。 +_UNION_MARKER_NAMES: frozenset[str] = frozenset({ + 'CConst', 'CVolatile', 'CExport', 'CExtern', 'CStatic', 'CInline', 'State', + 'CDefine', 'CTypedef', 'CPtr', 'CArrayPtr', 'CAutoPtr', 'CRef', 'CTempRef', + 'BigEndian', 'LittleEndian', 'Bit', +}) + + +def _IsUnionMarkerNode(node: ast.AST) -> bool: + """节点是否为内建修饰标记(裸名、attr.* 或带调用括号的标记)。""" + if isinstance(node, ast.Name): + return node.id in _UNION_MARKER_NAMES + if isinstance(node, ast.Attribute): + cur: ast.AST = node + while isinstance(cur, ast.Attribute): + cur = cur.value + return isinstance(cur, ast.Name) and cur.id == 'attr' + if isinstance(node, ast.Call): + return _IsUnionMarkerNode(node.func) + return False + + +def _ContainsUnionMarker(node: ast.AST) -> bool: + if _IsUnionMarkerNode(node): + return True + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + return _ContainsUnionMarker(node.left) or _ContainsUnionMarker(node.right) + return False + + +def RejectTypeUnion(Annotation: ast.AST | None) -> None: + """拒绝 `T1 | T2` 类型联合;只允许「单一类型 | 内建修饰标记」。""" + if not (isinstance(Annotation, ast.BinOp) and isinstance(Annotation.op, ast.BitOr)): + return + if _ContainsUnionMarker(Annotation): + return + Line: int = getattr(Annotation, 'lineno', 0) or 0 + raise TypeError( + f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行)。" + f"类型注解只能是单一类型:指针请写 CPtr[T] / rawptr[T];" + f"const / volatile / static / export / extern 请使用对应关键字。" + ) + + def AnnotationContainsMarker(node: ast.AST, MarkerName: str) -> bool: """注解 AST 中是否出现指定内建标记名(裸名,或属性形态的尾名)。""" if isinstance(node, ast.Name): diff --git a/lib/core/TypeAnnotationResolver.py b/lib/core/TypeAnnotationResolver.py index 92fa6de..750a428 100644 --- a/lib/core/TypeAnnotationResolver.py +++ b/lib/core/TypeAnnotationResolver.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING from lib.core.Handles.HandlesBase import CTypeInfo, BuiltinTypeMap, CTypeHelper from lib.core.ConstEvaluator import ConstEvaluator from lib.core.SymbolUtils import ( - IsListAnnotation, + IsListAnnotation, RejectTypeUnion, ResolveGenericClassSpecName, GetStructSha1MapFromSymtab, GetTCAliasMapFromSymtab) from lib.core import TypeSystem from lib.constants.config import mode as _config_mode @@ -91,6 +91,7 @@ class TypeAnnotationResolver: Node: AST 节点(如 ast.Name, ast.Attribute 等) SymbolTable: 符号表字典 """ + RejectTypeUnion(Node) if isinstance(Node, ast.Constant): return TypeAnnotationResolver._from_node_constant(Node, SymbolTable) if isinstance(Node, ast.Name):