fix(compiler): 支持模块限定泛型类类型注解 numpy.ndarray[t.CDouble]

Subscript value 为 Attribute 时仅支持 t.CArray/t.Callable,模块限定
泛型类(numpy.ndarray[T])触发 fail-fast。提取 _resolve_generic_subscript_ty
辅助函数,Name 泛型类与 Attribute 泛型类共用(收集实参→mangled→特化)。
This commit is contained in:
TermiNexus committed 2026-08-08 16:41:47 +08:00
1 parent 16d0302b08
commit aa6eee54e9
1 file changed
+105 -78
+105 -78
View File
@@ -1526,6 +1526,100 @@ def extract_class_name_from_annotation(node: ast.AST | t.CPtr,
return None
# ============================================================
# _resolve_generic_subscript_ty - 解析泛型类类型注解
# (list[int] / numpy.ndarray[t.CDouble])
#
# 收集 slice 类型实参,构造 mangled name("list[int]"),查找已特化结构体;
# 未特化时检查是否泛型模板并主动触发特化。Name 泛型类与模块限定泛型类
# (Attribute value,如 numpy.ndarray[t.CDouble])共用此逻辑。
# ============================================================
def _resolve_generic_subscript_ty(pool: memhub.MemBuddy | t.CPtr,
sub: ast.Subscript | t.CPtr,
gen_cls_name: str,
trans: HT.Translator | t.CPtr,
imported_modules: str,
from_imports: str) -> llvmlite.LLVMType | t.CPtr:
"""解析泛型类类型注解(特化或查找已注册结构体),失败返回 None"""
if pool is None or sub is None or gen_cls_name is None:
return None
# tuple[...] 类型注解:TransPyV 暂不支持 tuple 返回类型,返回 None 让上层默认处理
# 避免走到 list[str](pool, 4) 构造路径崩溃(tuple 未定义为泛型类)
if string.strcmp(gen_cls_name, "tuple") == 0:
return None
# 先收集类型实参名,再分配缓冲区拼接 mangled name(elem_size=8:str 是指针)
gen_arg_names: list[str] | t.CPtr = list[str](pool, 8)
if sub.slice.kind() == ast.ASTKind.Tuple:
gen_tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice)
gen_elts: list[ast.AST | t.CPtr] | t.CPtr = gen_tp.elts
if gen_elts is not None:
gen_en: t.CSizeT = gen_elts.__len__()
gen_ei: t.CSizeT
for gen_ei in range(gen_en):
gen_elt: ast.AST | t.CPtr = gen_elts.get(gen_ei)
gen_tn: str = _get_type_name_from_annotation(pool, gen_elt)
gen_arg_names.append(gen_tn)
else:
gen_tn_single: str = _get_type_name_from_annotation(pool, sub.slice)
gen_arg_names.append(gen_tn_single)
# 计算总长度并分配缓冲区
gen_total: t.CSizeT = string.strlen(gen_cls_name) + 2 # "[" 和 "]"
gen_an: t.CSizeT = gen_arg_names.__len__()
gen_ai: t.CSizeT
for gen_ai in range(gen_an):
if gen_ai > 0:
gen_total += 1 # ","
gen_atn: str = gen_arg_names.get(gen_ai)
if gen_atn is not None:
gen_total += string.strlen(gen_atn)
gen_total += 1 # NUL
gen_mangled: str = pool.alloc(gen_total)
if gen_mangled is None:
return None
gen_mangled[0] = '\0'
string.strcat(gen_mangled, gen_cls_name)
string.strcat(gen_mangled, "[")
for gen_ai in range(gen_an):
if gen_ai > 0:
string.strcat(gen_mangled, ",")
gen_atn: str = gen_arg_names.get(gen_ai)
if gen_atn is not None:
string.strcat(gen_mangled, gen_atn)
string.strcat(gen_mangled, "]")
# 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发)
gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
# 治本修复:Phase B 补译泛型特化类方法体
# Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0),
# Phase B(declare_only==0)解析字段类型命中已注册结构体时本会早返回,
# 导致方法体永远不生成 → GSList[Line].append 等符号只有 declare 无 define → 链接失败。
# 此处 Phase B 且方法体未译时,调用 _specialize_generic_class 走其已注册分支补译方法体。
if trans is not None and trans._declare_only == 0:
import lib.core.Handles.HandlesClassDef as HandlesClassDef
gen_spec_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(gen_mangled)
if gen_spec_entry is not None and gen_spec_entry.MethodsEmitted == 0:
HandlesClassDef._specialize_generic_class(trans, gen_cls_name, gen_arg_names)
return gen_spec_ty
# 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐)
# 当 trans 可用时,检查是否是泛型模板并触发特化
if trans is not None:
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesExprCall as HandlesExprCall
template_cd_chk: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_cls_name)
if template_cd_chk is not None:
type_args_chk: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(
pool, sub.slice)
if type_args_chk is not None and type_args_chk.__len__() > 0:
spec_name_chk: str = HandlesClassDef._specialize_generic_class(
trans, gen_cls_name, type_args_chk)
if spec_name_chk is not None:
gen_spec_ty = HandlesStruct.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
return gen_spec_ty
# 未特化:返回 None(不报错,让后续流程处理)
return None
# ============================================================
# 解析类型注解节点为 LLVMType
#
@@ -1771,92 +1865,25 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
if sub.value is None or sub.slice is None:
fatal_type_error(node, "Subscript 节点缺少 value 或 slice")
# 泛型类类型注解: list[int] → 查找已特化的 struct
# value 是 Name(泛型类名),slice 是类型实参
# 泛型类类型注解: list[int] → 查找已特化的 struct(value 是 Name 泛型类名)
if sub.value.kind() == ast.ASTKind.Name:
gen_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
# tuple[...] 类型注解:TransPyV 暂不支持 tuple 返回类型,返回 None 让上层默认处理
# 避免走到 list[str](pool, 4) 构造路径崩溃(tuple 未定义为泛型类)
if gen_nm.id is not None:
if string.strcmp(gen_nm.id, "tuple") == 0:
return None
# 先收集类型实参名,再分配缓冲区拼接 mangled name(elem_size=8:str 是指针)
gen_arg_names: list[str] | t.CPtr = list[str](pool, 8)
if sub.slice.kind() == ast.ASTKind.Tuple:
gen_tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice)
gen_elts: list[ast.AST | t.CPtr] | t.CPtr = gen_tp.elts
if gen_elts is not None:
gen_en: t.CSizeT = gen_elts.__len__()
gen_ei: t.CSizeT
for gen_ei in range(gen_en):
gen_elt: ast.AST | t.CPtr = gen_elts.get(gen_ei)
gen_tn: str = _get_type_name_from_annotation(pool, gen_elt)
gen_arg_names.append(gen_tn)
else:
gen_tn_single: str = _get_type_name_from_annotation(pool, sub.slice)
gen_arg_names.append(gen_tn_single)
# 计算总长度并分配缓冲区
gen_total: t.CSizeT = string.strlen(gen_nm.id) + 2 # "[" 和 "]"
gen_an: t.CSizeT = gen_arg_names.__len__()
gen_ai: t.CSizeT
for gen_ai in range(gen_an):
if gen_ai > 0:
gen_total += 1 # ","
gen_atn: str = gen_arg_names.get(gen_ai)
if gen_atn is not None:
gen_total += string.strlen(gen_atn)
gen_total += 1 # NUL
gen_mangled: str = pool.alloc(gen_total)
if gen_mangled is None:
return None
gen_mangled[0] = '\0'
string.strcat(gen_mangled, gen_nm.id)
string.strcat(gen_mangled, "[")
for gen_ai in range(gen_an):
if gen_ai > 0:
string.strcat(gen_mangled, ",")
gen_atn: str = gen_arg_names.get(gen_ai)
if gen_atn is not None:
string.strcat(gen_mangled, gen_atn)
string.strcat(gen_mangled, "]")
# 查找已特化的 struct(特化由实例化调用 list[int](pool) 触发)
gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
# 治本修复:Phase B 补译泛型特化类方法体
# Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0),
# Phase B(declare_only==0)解析字段类型命中已注册结构体时本会早返回,
# 导致方法体永远不生成 → GSList[Line].append 等符号只有 declare 无 define → 链接失败。
# 此处 Phase B 且方法体未译时,调用 _specialize_generic_class 走其已注册分支补译方法体。
if trans is not None and trans._declare_only == 0:
import lib.core.Handles.HandlesClassDef as HandlesClassDef
gen_spec_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(gen_mangled)
if gen_spec_entry is not None and gen_spec_entry.MethodsEmitted == 0:
HandlesClassDef._specialize_generic_class(trans, gen_nm.id, gen_arg_names)
return gen_spec_ty
# 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐)
# 当 trans 可用时,检查是否是泛型模板并触发特化
if trans is not None:
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesExprCall as HandlesExprCall
template_cd_chk: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_nm.id)
if template_cd_chk is not None:
type_args_chk: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(
pool, sub.slice)
if type_args_chk is not None and type_args_chk.__len__() > 0:
spec_name_chk: str = HandlesClassDef._specialize_generic_class(
trans, gen_nm.id, type_args_chk)
if spec_name_chk is not None:
gen_spec_ty = HandlesStruct.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
return gen_spec_ty
# 未特化:返回 None(不报错,让后续流程处理)
return None
# 检查 value 是否是 Attribute(Name('t'), 'CArray'/'Callable')
return _resolve_generic_subscript_ty(pool, sub, gen_nm.id, trans,
imported_modules, from_imports)
# 检查 value 是否是 Attribute(t.CArray / t.Callable / 模块限定泛型类如 numpy.ndarray[T])
if sub.value.kind() != ast.ASTKind.Attribute:
fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)")
arr_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value)
if arr_at.attr is None:
fatal_type_error(node, "Subscript Attribute 缺少 attr")
# 模块限定泛型类: numpy.ndarray[t.CDouble] → 裸类名 ndarray 走泛型特化
# (在 t.CArray / t.Callable 检查之前;模板已注册即视为泛型类)
if trans is not None:
import lib.core.Handles.HandlesClassDef as HandlesClassDef
if HandlesClassDef._find_generic_template(arr_at.attr) is not None:
return _resolve_generic_subscript_ty(pool, sub, arr_at.attr, trans,
imported_modules, from_imports)
if arr_at.value is None or arr_at.value.kind() != ast.ASTKind.Name:
fatal_type_error(node, "t.CArray / t.Callable 必须通过模块名限定")
arr_val_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arr_at.value)