feat(tpc): 类型解析 fail-fast 报文补充完整定位信息

报错从单行"类型注解 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' ...
This commit is contained in:
TermiNexus committed 2026-09-28 18:11:14 +08:00
1 parent 14af03577c
commit 8b657b9ac2
3 files changed
+54 -10

No files matched your search

+15 -2
View File
@@ -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 节点"""
+7 -3
View File
@@ -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}")
+32 -5
View File
@@ -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 值解析
# ------------------------------------------------------------------