diff --git a/lib/Projectrans/Phase2Translator.py b/lib/Projectrans/Phase2Translator.py index 91b2255..6971b1e 100644 --- a/lib/Projectrans/Phase2Translator.py +++ b/lib/Projectrans/Phase2Translator.py @@ -3913,8 +3913,12 @@ class Phase2Translator: for item in need_translate: src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item if not _CachedIsFile(ll_path): + # 翻译成功(worker 返回 ok)却没有产物 = 翻译失败:立即终止, + # 不允许跳过该模块继续后处理/编译/链接(否则只会得到链接期 + # undefined symbol,真因与现场脱节)。 _vlog().error(f" 翻译未生成 .ll 文件: {module_name}.py") - continue + raise ReportedCompileError( + f"include 翻译未生成 .ll 文件: {module_name}.py,编译立即停止") ll_content = _ReadTextCached(ll_path) diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 77c00ed..6c371db 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -11,7 +11,7 @@ from lib.constants.config import mode as _config_mode from lib.core import TypeSystem from lib.core.SymbolUtils import ( IsListAnnotation, ParseListAnnotation, RequireDefineConstStorable, - FindAutoAddrMode, + FindAutoAddrMode, MangleTypeArgByRegistry, ) @@ -973,7 +973,9 @@ class AnnAssignHandle(BaseHandle): sn2 = sn2.value r2: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(sn2) if r2: - resolved_cn = f'{CN}[{r2[0]}]' + # 与特化名同源(int → i32):直接拼 r2[0] 会得到 + # 'list[CInt]',方法分派查不到 'list[i32].get'。 + resolved_cn = f'{CN}[{MangleTypeArgByRegistry(r2[0])}]' if resolved_cn != Gen.var_struct_class.get(VarName): Gen.var_struct_class[VarName] = resolved_cn Gen.global_struct_class[VarName] = resolved_cn diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index 24083be..80c7d79 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -10,7 +10,7 @@ import llvmlite.ir as ir from lib.core.Exportable import EnumMember as ExportEnumMember from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.core.SymbolUtils import ( - MangleTypeArgByRegistry, + MangleTypeArgByRegistry, NormalizeGenericArgName, EnumClassIntWidth, EnumBodyMemberNames, EnumMemberCountMismatchError, ClassHasFuncLevelCVTable, IsVtableSlotMethod) @@ -90,8 +90,12 @@ class ClassHandle(BaseHandle): 单项 mangling 走 SymbolUtils.MangleTypeArgByRegistry(声明端 DeclarationGenerator 的泛型分支以 ResolveGenericTypeArgStr 调用同一函数, 两侧拼名规则唯一),'][' 分隔与 HandlesTypeMerge / DeclarationGenerator 一致。 + 源码短名先经 NormalizeGenericArgName 归一(int → CInt → i32):直接对 + 裸 'int' 调 MangleTypeArgByRegistry 会因注册表无 'int' 而原样保留,拼出 + 与声明端不一致的 'list[int]'。ResolveGenericTypeArgStr 正是同两步组合。 """ - mangled_args: list[str] = [MangleTypeArgByRegistry(ta) for ta in type_args] + mangled_args: list[str] = [ + MangleTypeArgByRegistry(NormalizeGenericArgName(ta)) for ta in type_args] return class_name + '[' + ']['.join(mangled_args) + ']' def _HasClassDefinition(self, Name: str, Gen: LlvmGeneratorMixin) -> bool: @@ -142,6 +146,13 @@ class ClassHandle(BaseHandle): type_param_names: list[str] = template['type_params'] if len(type_args) != len(type_param_names): return None + # 实参先归一为**唯一规范形**(int → CInt → i32;与声明端 + # ResolveGenericTypeArgStr、定义端 _mangle_generic_class_name 同一两步)。 + # spec_key / spec_name / type_map 全部只认这一种写法:否则同一 list[int] + # 会以 'list'、'list'、'list' 三个键各自特化一次 + # (struct 重复发射),或缓存键与特化名不同源导致补发方法体时找不到。 + type_args = [ + MangleTypeArgByRegistry(NormalizeGenericArgName(ta)) for ta in type_args] spec_key: str = ClassName + '<' + ','.join(type_args) + '>' # 缓存必须在 Gen 上(每个模块独立),不能在 ClassHandler 上跨模块共享, # 否则临时 Gen(如共享符号表构建阶段)的特化会污染正式翻译阶段的缓存 @@ -1059,7 +1070,10 @@ class ClassHandle(BaseHandle): _ec_gc: str | None = None if _iname_c: try: - _ec_gc = f'{_iname_c}[{self.Trans.ExprCallHandle._resolve_type_arg_str(_inner_sub_c.slice)}]' + # 实参必须先 mangling(int → i32、CInt → i32): + # _resolve_type_arg_str 只做源码名归一,直接拼会得到 + # 'list[CInt]',与特化名/struct 键 'list[i32]' 分裂。 + _ec_gc = f'{_iname_c}[{MangleTypeArgByRegistry(self.Trans.ExprCallHandle._resolve_type_arg_str(_inner_sub_c.slice))}]' except Exception: _ec_gc = None if _ec_gc: @@ -1105,7 +1119,10 @@ class ClassHandle(BaseHandle): if _elem_slice_c is not None: _ec_c: str | None = None try: - _ec_c = f'list[{self.Trans.ExprCallHandle._resolve_type_arg_str(_elem_slice_c)}]' + # 与特化名同源:实参 mangling 后拼(int → i32), + # 否则登记成 'list[CInt]',方法分派查不到 + # 'list[i32].get'(Undefined method)。 + _ec_c = f'list[{MangleTypeArgByRegistry(self.Trans.ExprCallHandle._resolve_type_arg_str(_elem_slice_c))}]' except Exception: _ec_c = None if _ec_c: diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 8f4750a..384d4c8 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -14,7 +14,7 @@ from lib.core import TypeSystem from lib.core.TypeSystem import CTypeRegistry from lib.core.SymbolUtils import ( ExtractTypeNameFromBinOp, IsPtrSubscriptNode, - ResolveTypeArgStr, GenericArgRawName, + ResolveTypeArgStr, GenericArgRawName, MangleTypeArgByRegistry, ClassHasFuncLevelCVTable, IsVtableSlotMethod) from lib.core.Handles.HandlesExpr import DefineUseWidthFromLLVMType from lib.vast.ExprParser import NEW_SRC_MEMGR @@ -835,6 +835,12 @@ class ExprCallHandle(BaseHandle): pass if Node.func.attr == '__sizeof__': if isinstance(Node.func.value, ast.Subscript): + # 指针下标(`T*` 的脱糖形态 CPtr[T] / rawptr[T],T 替换后可能是 + # CPtr[CInt] / CPtr[sha1.AST]):指针尺寸恒为 8。这就是原先把 + # 泛型指针实参 T 在 sizeof 上下文替换成裸 CPtr 所表达的唯一语义, + # 现在按真实类型节点判定,不再改写 T 本身。 + if IsPtrSubscriptNode(Node.func.value, self.Trans.SymbolTable): + return ir.Constant(ir.IntType(64), 8) spec_name = self._ResolveGenericSlice(Node.func.value) if spec_name: return self._HandleSizeofLlvm(ast.Name(id=spec_name, ctx=ast.Load())) @@ -3029,6 +3035,10 @@ class ExprCallHandle(BaseHandle): type_names=_TypeNames, declare_only=False) except Exception as _spec_err: Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}' + # 特化发射失败就是翻译失败:记录现场后立即上抛,禁止带着 + # 未生成的方法体继续编译(否则只剩链接期 undefined symbol, + # 或调用点按错误签名继续生成 IR)。 + raise return cached_name: str = cached[0] # 检查方法是否已有 define(blocks 非空表示已编译方法体) @@ -3052,13 +3062,10 @@ class ExprCallHandle(BaseHandle): # cached_declare_only=True 且 declare_only=False,自动补发方法体 # 并更新缓存为 (spec_name, False)。预注册机制(L117)防止递归。 # - # 上下文快照:本函数**吞掉**特化异常、让外层方法继续编译,故必须在失败时把 - # 编译器上下文复位——`_EmitFunctionLlvm` 的类名/构建器恢复只在**成功路径** - # 执行(失败路径直接 re-raise),异常穿过多层后 `Gen.builder/func` 与 - # `_CurrentCpythonObjectClass` 会停在内层特化方法的中间状态:外层方法随后 - # 的 `self.X` 被按内层类解析(ExprGenFstr.vp 的 `self.Gen` 被按 - # `list[cfc4ca8da95a30e1.AST*]` 解析 → "属性 'Gen' 在类中找不到"的连带错误), - # 且后续指令会误插进内层函数的块。 + # 上下文快照:特化失败时先复位编译器上下文再上抛——`_EmitFunctionLlvm` 的 + # 类名/构建器恢复只在**成功路径**执行(失败路径直接 re-raise),异常穿过 + # 多层后 `Gen.builder/func` 与 `_CurrentCpythonObjectClass` 会停在内层 + # 特化方法的中间状态,导致错误报文/后续阶段按内层类解析。 _saved_builder: object = Gen.builder _saved_func: object = Gen.func _saved_cpython_class: str | None = getattr(self.Trans, '_CurrentCpythonObjectClass', None) @@ -3069,14 +3076,15 @@ class ExprCallHandle(BaseHandle): type_names=cached_type_names, declare_only=False ) except Exception as _spec_err: - # 不静默吞特化异常:暴露到 Gen._generic_spec_error(Undefined method / - # len 失败时随报文输出),并恢复 declare_only 标记避免后续调用跳过补发。 + # fail-fast:暴露到 Gen._generic_spec_error 后立即上抛(不再吞掉让 + # 外层方法继续编译),并恢复 declare_only 标记与编译上下文。 Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}' Gen._generic_class_specializations[spec_key] = (cached_name, True) Gen.builder = _saved_builder Gen.func = _saved_func self.Trans._CurrentCpythonObjectClass = _saved_cpython_class Gen._current_class_name = _saved_class_name + raise def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None: """计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。 @@ -4218,10 +4226,13 @@ class ExprCallHandle(BaseHandle): """ Gen = self.Trans.LlvmGen StructSha1Map: dict[str, str] = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {} - return ResolveTypeArgStr( + # 归一 + mangling 两步与声明端 ResolveGenericTypeArgStr 完全相同: + # int → CInt → i32。只做 ResolveTypeArgStr 会返回 'CInt',据此拼出的 + # 特化名 'list[CInt]' 与 struct 键/方法名 'list[i32]' 分裂。 + return MangleTypeArgByRegistry(ResolveTypeArgStr( node, TCAliasMap=getattr(self.Trans, '_from_import_aliases', {}), - StructSha1Map=StructSha1Map) + StructSha1Map=StructSha1Map)) def _get_raw_type_name(self, node: ast.AST) -> str: """获取类型节点的原始名称(不带模块前缀),用于泛型 T 替换。 diff --git a/lib/core/Handles/HandlesExprUtils.py b/lib/core/Handles/HandlesExprUtils.py index f7cb924..b39a12b 100644 --- a/lib/core/Handles/HandlesExprUtils.py +++ b/lib/core/Handles/HandlesExprUtils.py @@ -183,6 +183,8 @@ class ExprUtils: self.Trans.ExprCallHandle._try_complete_generic_specialization(ClassName, op_name, Gen) except Exception as _spec_err: Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}' + # fail-fast:补发特化失败即翻译失败,禁止继续按未生成的方法分派。 + raise FullMethodName = f'{ClassName}.{op_name}' if not Gen._has_function(FullMethodName): FullMethodName = f'{ClassName}.{op_name}__' @@ -226,6 +228,8 @@ class ExprUtils: self.Trans.ExprCallHandle._try_complete_generic_specialization(best_candidates[0], op_name, Gen) except Exception as _spec_err: Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}' + # fail-fast:同上,补发失败立即终止。 + raise _fn2: str = f'{best_candidates[0]}.{op_name}' if Gen._has_function(f'{best_candidates[0]}.{op_name}') else f'{best_candidates[0]}.{op_name}__' _f2: Any = Gen._get_function(_fn2) if _f2 is not None and getattr(_f2, 'blocks', []): diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index 8d7c6dd..768ed32 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -595,10 +595,13 @@ class FunctionHandle(BaseHandle): spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class( ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True) except Exception as _spec_err: - # 不静默吞特化异常:记录到 Gen._generic_spec_error 后再 - # 交给外层返回类型回退(否则只剩一个错误的 CInt 返回类型)。 + # fail-fast:返回类型特化失败 = 翻译失败。转成 + # FailFastError 并穿过外层"默认 CInt"回退继续上抛, + # 不允许带着错误/缺失的返回类型继续编译。 + from lib.core.LLVMCG.FuncGen import FailFastError as _FFE Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}' - raise + raise _FFE( + f"泛型返回类型特化失败:{type(_spec_err).__name__}: {_spec_err}") from _spec_err if spec_name2 and spec_name2 in Gen.structs: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = TypeSystem.CStruct(name=spec_name2) @@ -608,7 +611,12 @@ class FunctionHandle(BaseHandle): ReturnTypeInfo.BaseType = TypeSystem.CInt() except TypeError: raise - except Exception: # 回退:设置默认返回类型为 CInt + except Exception as _ret_exc: # 回退:设置默认返回类型为 CInt + # fail-fast 信号不得被默认返回类型吞掉(否则调用点按 i32 + # 继续生成 IR,错误被伪装成运行期崩溃/链接期未定义符号)。 + from lib.core.LLVMCG.FuncGen import FailFastError as _FFE + if isinstance(_ret_exc, _FFE): + raise ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = TypeSystem.CInt() else: @@ -1002,14 +1010,12 @@ class FunctionHandle(BaseHandle): if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map: replacement: str = type_map[node.func.value.id] # 指针类型参数(如 list[CPtr[AST]] 中的 T):表达式里 T 的唯一 - # 用法是 `T.__sizeof__()`,指针大小恒为 8。替换成**裸 CPtr** - # (而不是 CPtr[]):mangled 串含 '.'/'*',既不是 - # 合法 Name,也会让 __sizeof__ 的 Subscript 分支(只认泛型切片) - # 落空后把 CPtr 当变量求值 → "未定义名称: 'CPtr'"。 - if cptr_params and node.func.value.id in cptr_params: - node.func.value = ast.Name(id='CPtr', ctx=ast.Load()) - else: - node.func.value = self._make_name_node(replacement) + # 用法是 `T.__sizeof__()`。统一替换成**真实类型节点** + # (_make_replacement_node:'sha1.AST*' → CPtr[sha1.AST]), + # 不再替换成裸 CPtr —— 裸 CPtr 把"指针实参"的语义写死进替换 + # 规则,标量实参一旦被误判进 cptr_params 就会得到错误的 8。 + # __sizeof__ 侧已直接识别指针下标并返回 8。 + node.func.value = self._make_replacement_node(replacement) else: self._apply_type_map_to_expr(node.func.value, type_map, cptr_params) elif isinstance(node.func, ast.Subscript): @@ -1020,12 +1026,9 @@ class FunctionHandle(BaseHandle): elif isinstance(node, ast.Attribute): if isinstance(node.value, ast.Name) and node.value.id in type_map: replacement: str = type_map[node.value.id] - if cptr_params and node.value.id in cptr_params: - # 同上:指针类型参数的表达式用法(T.__sizeof__ 等)只需 - # "指针语义",裸 CPtr 即指针大小 8;不要拼 mangled 串。 - node.value = ast.Name(id='CPtr', ctx=ast.Load()) - else: - node.value = ast.Name(id=replacement, ctx=ast.Load()) + # 同上:按真实类型节点替换(指针实参 → CPtr[<被指类>]), + # 不再退化为裸 CPtr。 + node.value = self._make_replacement_node(replacement) else: self._apply_type_map_to_expr(node.value, type_map, cptr_params) elif isinstance(node, ast.BinOp): @@ -1520,10 +1523,13 @@ class FunctionHandle(BaseHandle): spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class( ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True) except Exception as _spec_err: - # 不静默吞特化异常:记录到 Gen._generic_spec_error 后再 - # 交给外层返回类型回退(否则只剩一个错误的 CInt 返回类型)。 + # fail-fast:返回类型特化失败 = 翻译失败。转成 + # FailFastError 并穿过外层"默认 CInt"回退继续上抛, + # 不允许带着错误/缺失的返回类型继续编译。 + from lib.core.LLVMCG.FuncGen import FailFastError as _FFE Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}' - raise + raise _FFE( + f"泛型返回类型特化失败:{type(_spec_err).__name__}: {_spec_err}") from _spec_err if spec_name2 and spec_name2 in Gen.structs: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = TypeSystem.CStruct(name=spec_name2) @@ -1533,7 +1539,12 @@ class FunctionHandle(BaseHandle): ReturnTypeInfo.BaseType = TypeSystem.CInt() except TypeError: raise - except Exception: # 回退:设置默认返回类型为 CInt + except Exception as _ret_exc: # 回退:设置默认返回类型为 CInt + # fail-fast 信号不得被默认返回类型吞掉(否则调用点按 i32 + # 继续生成 IR,错误被伪装成运行期崩溃/链接期未定义符号)。 + from lib.core.LLVMCG.FuncGen import FailFastError as _FFE + if isinstance(_ret_exc, _FFE): + raise ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = TypeSystem.CInt() else: @@ -2037,14 +2048,8 @@ class FunctionHandle(BaseHandle): try: self.Trans.BodyHandler.HandleBodyLlvm(func_body) except Exception as _body_exc: - # 方法体编译失败:确保 block 终止(防止 expected instruction opcode 错误), - # 然后重新抛出异常让编译立即终止(不吞掉错误) - _fn_name: str = Node.name - _cls_name: str = ClassName if ClassName else '' - import sys as _sys - import traceback as _tb - print(f"[FATAL] 方法体编译失败 ({_cls_name}.{_fn_name}): {type(_body_exc).__name__}: {_body_exc}", file=_sys.stderr) - _tb.print_exc(file=_sys.stderr) + # 方法体编译失败:复位上下文后原样上抛,由 Phase2Translator 的 + # worker/主进程统一输出一次并终止(此处不打印,避免同一错误重复)。 if Gen.builder is not None: try: if not Gen.builder.block.is_terminated: diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 0108220..d11f245 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -15,7 +15,7 @@ from lib.constants.config import mode as _config_mode from lib.core import TypeSystem from lib.core.TypeSystem import CTypeRegistry from lib.core.SymbolUtils import ParseListAnnotation, AnnotationContainsName, FindAutoAddrMode -from lib.core.SymbolUtils import EnumClassIntWidth, ExpandSoftKeywords +from lib.core.SymbolUtils import EnumClassIntWidth, ExpandSoftKeywords, MangleTypeArgByRegistry from lib.core.SymbolUtils import ClassHasFuncLevelCVTable, IsVtableSlotMethod @@ -2442,7 +2442,9 @@ class ImportHandle(BaseHandle): _ec_gs: str | None = None if _iname_s: try: - _ec_gs = f'{_iname_s}[{self.Trans.ExprCallHandle._resolve_type_arg_str(_inner_sub_s.slice)}]' + # 实参先 mangling(int → i32):与特化名/struct 键 + # 'list[i32]' 保持同源,避免 'list[CInt]' 分派失败。 + _ec_gs = f'{_iname_s}[{MangleTypeArgByRegistry(self.Trans.ExprCallHandle._resolve_type_arg_str(_inner_sub_s.slice))}]' except Exception: _ec_gs = None if _ec_gs: @@ -2488,7 +2490,8 @@ class ImportHandle(BaseHandle): if _elem_slice_s is not None: _ec_s: str | None = None try: - _ec_s = f'list[{self.Trans.ExprCallHandle._resolve_type_arg_str(_elem_slice_s)}]' + # 同 HandlesClassDef:实参 mangling 后拼特化名(int → i32) + _ec_s = f'list[{MangleTypeArgByRegistry(self.Trans.ExprCallHandle._resolve_type_arg_str(_elem_slice_s))}]' except Exception: _ec_s = None if _ec_s: @@ -4257,10 +4260,12 @@ class ImportHandle(BaseHandle): gc_base, gc_type_args, Gen, type_names=gc_type_names, declare_only=True) except Exception as _spec_err: - # 不静默吞特化异常:记录现场,供后续 Undefined method / - # len 失败路径把真因带进报错。 + # fail-fast:特化发射失败即翻译失败。记录现场、恢复 + # module_sha1 后立即上抛,不带着缺失的方法体继续编译。 Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}' - gc_spec = None + Gen.module_sha1 = saved_module_sha1 + self.Trans._module_sha1 = saved_trans_sha1 + raise Gen.module_sha1 = saved_module_sha1 self.Trans._module_sha1 = saved_trans_sha1 if gc_spec and gc_spec in Gen.structs: diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index 03b7867..886b5ab 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -852,7 +852,11 @@ class HandlesTypeMerge(BaseHandle): _ig_args: list[str] = [] for _ig_elt in _ig_slices: _ig_res = self.Trans.ExprCallHandle._resolve_generic_slice_type(_ig_elt) - _ig_args.append(_ig_res[0] if _ig_res else self.Trans.ExprCallHandle._resolve_type_arg_str(_ig_elt)) + _ig_raw: str = _ig_res[0] if _ig_res else self.Trans.ExprCallHandle._resolve_type_arg_str(_ig_elt) + # 与 _mangle_generic_class_name 同口径(CInt/CInt32T → i32、 + # CFloat64T → f64):直接拼原始名会得到 'list[CInt]', + # 与 struct 键/方法名 'list[i32]' 分裂 → Undefined method。 + _ig_args.append(MangleTypeArgByRegistry(_ig_raw)) _ig_spec: str = f'{_inner_gsub.value.id}[' + ']['.join(_ig_args) + ']' ResultInfo.BaseType = TypeSystem.CStruct(name=_ig_spec) ResultInfo.Name = _ig_spec