From 8b657b9ac2d042fd216c66691f6251a091c711fe Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 28 Sep 2026 18:11:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(tpc):=20=E7=B1=BB=E5=9E=8B=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=20fail-fast=20=E6=8A=A5=E6=96=87=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E5=AE=9A=E4=BD=8D=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 报错从单行"类型注解 X 无法解析"改为分层多行: ① SymbolTable._LoadSymbolsFromFile 加 文件路径 + 模块命名空间 + 发起行; ② SymbolTypeResolver._resolve_function 加 函数名/行号/形参序号与形参名 + 注解源码原文 (新增 _AnnotationText 渲染 Name/Attribute/Subscript/BinOp/Tuple/Constant); ③ LLVMTypeMapper._resolve_name 列出全部已试来源(内置速记/BuiltinTypeMap/ builtins CTypedef/符号表 typedef/本模块类名数/枚举名数/符号表已加载条目数)与注解行列, 并给出"是否声明模块未先加载"的排查提示。 样例(VET/temp/24da8b5f154f7cc0.vpi): 函数 'open'(第 107 行)的返回类型无法解析 / 注解写法:INT | t.State / 裸名 'INT' ... --- lib/core/LLVMTypeMapper.py | 17 ++++++++++++++-- lib/core/SymbolTable.py | 10 ++++++--- lib/core/SymbolTypeResolver.py | 37 +++++++++++++++++++++++++++++----- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/lib/core/LLVMTypeMapper.py b/lib/core/LLVMTypeMapper.py index d481f62..ea62f90 100644 --- a/lib/core/LLVMTypeMapper.py +++ b/lib/core/LLVMTypeMapper.py @@ -288,9 +288,22 @@ class LLVMTypeMapper: if builtin_llvm: return builtin_llvm # fail-fast:类型信息缺失不再静默退化成 i32 + _node_line: object = getattr(node, 'lineno', None) + _node_col: object = getattr(node, 'col_offset', None) + _pos: str = "" + if _node_line: + _pos = f"(注解位置 第 {_node_line} 行" + _pos += f", 列 {_node_col})" if _node_col is not None else ")" + _loaded_cnt: int = len(getattr(self._symtab, '_symbols', None) or {}) raise TypeNameUnresolvedError( - f"类型注解 '{node.id}' 无法解析:既不是内置类型 / 符号表 typedef / " - f"builtins typedef,也不是本模块或已加载模块的类/枚举") + f"裸名 '{node.id}' 无法解析为类型{_pos}\n" + f" · 已尝试的解析来源(全部 miss):内置类型速记 / BuiltinTypeMap / " + f"builtins.vp 的 CTypedef / 符号表 typedef / " + f"本模块类名({len(self._ClassNames)} 个)/ 本模块枚举名({len(self._EnumWidths)} 个)/ " + f"符号表已加载条目({_loaded_cnt} 个)中的类与枚举\n" + f" · 若该名字确实是 typedef / 类:先确认声明它的模块已在本模块之前加载" + f"(未加载 ⇒ 符号表里没有它,与注解拼写无关);否则按「注解拼写错误或" + f"该类型不存在」处理") def _resolve_attribute(self, node: ast.Attribute) -> str: """解析 ast.Attribute 节点""" diff --git a/lib/core/SymbolTable.py b/lib/core/SymbolTable.py index 98b1e36..8331db7 100644 --- a/lib/core/SymbolTable.py +++ b/lib/core/SymbolTable.py @@ -400,11 +400,15 @@ class SymbolTable: return loaded - except TypeNameUnresolvedError: + except TypeNameUnresolvedError as e: # 类型解析 fail-fast:**不再**吞成"加载模块失败"后返回空符号表 # (那会让该模块的全部符号缺失,错误在下游以"找不到类/函数"的面目炸开, - # 根因被掩盖)。直接上抛 → 上层终止编译并打印带函数名/形参名的报文。 - raise + # 根因被掩盖)。补上文件/模块定位后上抛 → 上层终止编译。 + raise TypeNameUnresolvedError( + f"[类型解析失败] 声明文件 {FilePath}\n" + f" 模块命名空间:{namespace_prefix}\n" + f" 第 {lineno} 行发起加载(lineno=0 表示解析声明文件本身)\n" + f" {e}") from None except Exception as e: _vlog().error(traceback.format_exc()) self.diagnostics.error(FilePath, lineno, f"加载模块失败: {e}") diff --git a/lib/core/SymbolTypeResolver.py b/lib/core/SymbolTypeResolver.py index fa0ed6d..58fe0c7 100644 --- a/lib/core/SymbolTypeResolver.py +++ b/lib/core/SymbolTypeResolver.py @@ -218,9 +218,11 @@ class TypeResolver: try: func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node) except TypeNameUnresolvedError as _e: - # fail-fast:返回类型无法解析 → 终止编译(附函数名定位,不降级为 i32) + # fail-fast:返回类型无法解析 → 终止编译(附函数名/行号/注解原文定位) raise TypeNameUnresolvedError( - f"函数 '{func.name}' 的返回类型无法解析:{_e}") from None + f"函数 '{func.name}'(第 {func.lineno} 行)的返回类型无法解析\n" + f" 注解写法:{TypeResolver._AnnotationText(func.returns_node)}\n" + f" {_e}") from None # 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号) if func.returns_node is not None: try: @@ -230,17 +232,42 @@ class TypeResolver: func.param_types = [] _arg_name: str annotation: ast.expr | None - for _arg_name, annotation in func.params: + _idx: int + for _idx, (_arg_name, annotation) in enumerate(func.params): if annotation: try: func.param_types.append(self._type_mapper.get_func_param_type_str(annotation)) except TypeNameUnresolvedError as _e: - # fail-fast:形参类型无法解析 → 终止编译(附函数名/形参名定位) + # fail-fast:形参类型无法解析 → 终止编译(附函数名/序号/形参名/注解原文) raise TypeNameUnresolvedError( - f"函数 '{func.name}' 的形参 '{_arg_name}' 类型无法解析:{_e}") from None + f"函数 '{func.name}'(第 {func.lineno} 行)的第 {_idx} 个形参 " + f"'{_arg_name}' 类型无法解析\n" + f" 注解写法:{TypeResolver._AnnotationText(annotation)}\n" + f" {_e}") from None else: func.param_types.append('i8*') + @staticmethod + def _AnnotationText(node: ast.AST | None) -> str: + """把类型注解节点渲染成源码形态(仅用于 fail-fast 报错定位,不求完备)""" + if node is None: + return '' + if isinstance(node, ast.Name): + return node.id or '?' + if isinstance(node, ast.Attribute): + return f"{TypeResolver._AnnotationText(node.value)}.{node.attr}" + if isinstance(node, ast.Subscript): + return (f"{TypeResolver._AnnotationText(node.value)}" + f"[{TypeResolver._AnnotationText(node.slice)}]") + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + return (f"{TypeResolver._AnnotationText(node.left)} | " + f"{TypeResolver._AnnotationText(node.right)}") + if isinstance(node, (ast.Tuple, ast.List)): + return ', '.join(TypeResolver._AnnotationText(e) for e in (node.elts or [])) + if isinstance(node, ast.Constant): + return repr(node.value) + return f'<{type(node).__name__}>' + # ------------------------------------------------------------------ # Define 值解析 # ------------------------------------------------------------------