diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index 2608592..c4ac825 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -115,13 +115,7 @@ class ClassHandle(BaseHandle): spec_name: str = self._mangle_generic_class_name(ClassName, type_args) # 预注册到缓存,防止特化过程中方法体引用自身类型导致无限递归 Gen._generic_class_specializations[spec_key] = (spec_name, declare_only) - type_map: dict[str, str] = {} - for i, tp_name in enumerate(type_param_names): - if type_names and i < len(type_names): - type_map[tp_name] = type_names[i] - else: - type_map[tp_name] = type_args[i] - # 内建类型名集合(必须在 cptr_params 检测之前定义) + # 内建类型名集合(必须在 type_map/cptr_params 检测之前定义) _BUILTIN_TYPE_NAMES: set = { 'CInt', 'CUInt', 'CInt8T', 'CUInt8T', 'CInt16T', 'CUInt16T', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CChar', 'CShort', @@ -131,6 +125,22 @@ class ClassHandle(BaseHandle): 'int', 'double', 'float', 'i8', 'i16', 'i32', 'i64', 'void', 'half', 'fp128', 'char', 'bool', } + type_map: dict[str, str] = {} + for i, tp_name in enumerate(type_param_names): + if type_names and i < len(type_names): + tn: str = type_names[i] + # 类类型参数(非内建)用 mangled type_arg 替换 T(带 sha1 前缀 + + # ptr 后缀,如 'f467978339422f32.ASTptr'),避免模板内部嵌套注解 + # (如 list[T].__iter__ 返回 list[T])被替换成裸短名('AST')后 + # 重新特化出只有 declare、无方法体的错误特化(list[AST].__len__ + # undefined symbol 根因)。_make_replacement_node 会把它还原为 + # 'sha1.AST | t.CPtr',重新解析时拼回一致的 mangled 名。 + if tn not in _BUILTIN_TYPE_NAMES and i < len(type_args): + type_map[tp_name] = type_args[i] + else: + type_map[tp_name] = tn + else: + type_map[tp_name] = type_args[i] # 检测哪些类型参数在原始类型实参中带有 | t.CPtr # 当 type_arg 以 'ptr' 结尾(_resolve_type_arg_str 将 t.CPtr 规范化为 'ptr') # 且对应的 type_name 不是内建类型名时,说明调用方写了 list[AST | t.CPtr] diff --git a/lib/core/Handles/HandlesExprUtils.py b/lib/core/Handles/HandlesExprUtils.py index b2fd047..6f9da6c 100644 --- a/lib/core/Handles/HandlesExprUtils.py +++ b/lib/core/Handles/HandlesExprUtils.py @@ -89,14 +89,31 @@ class ExprUtils: # var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。 # 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。 if '[' not in ClassName: - SpecClass: str | None = None + # 先收集所有候选特化(有方法 declare 或 define 的) + best_candidates: list[str] = [] for CN in Gen.structs.keys(): - if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'): - SpecClass = CN - break - if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'): + if CN.startswith(f'{ClassName}[') and (Gen._has_function(f'{CN}.{op_name}') or Gen._has_function(f'{CN}.{op_name}__')): + best_candidates.append(CN) + # 优先选已编译方法体(define)的特化:dict 插入序选第一个会命中 + # 只有 declare 无 define 的错误特化(如 list[AST]),生成 undefined + # symbol(ld.lld undefined symbol: list[AST].__len__ 根因)。 + for CN in best_candidates: + _fn: str = f'{CN}.{op_name}' if Gen._has_function(f'{CN}.{op_name}') else f'{CN}.{op_name}__' + _f: Any = Gen._get_function(_fn) + if _f is not None and getattr(_f, 'blocks', []): SpecClass = CN break + if SpecClass is None and best_candidates: + # 全部只有 declare:按需补发方法体(幂等,_specialize_generic_class + # 缓存机制会从 declare_only 升级为完整特化),补发后重新检查 + try: + self.Trans.ExprCallHandle._try_complete_generic_specialization(best_candidates[0], op_name, Gen) + except Exception: + pass + _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', []): + SpecClass = best_candidates[0] if SpecClass: FullMethodName = f'{SpecClass}.{op_name}' if not Gen._has_function(FullMethodName):