fix(compiler): 泛型注解收集类型实参时替换泛型参数 T + 属性访问 fail-fast traceback
- _get_type_name_from_annotation Name 分支应用 resolve_generic_type_name, 修复 ndarray[T] 二次递归特化崩溃(SimdTest numpy) - _specialize_generic_class 入口防御性替换残留类型参数名 - translate_attribute/get_attribute_ptr 非指针属性访问改 fatal_error(Python traceback 风格) - c.Deref(ptr).attr 属性访问 base 取指针本身不做 load - list[str] 容器 elem_size 4→8 修复(str 是指针 8 字节) - 泛型函数显式类型参数 xxx[T](x) 回退普通函数调用;T(v) 转换走 resolve_annotation_type
This commit is contained in:
1 parent
ba6beb439c
commit
ee8f532dc5
4 files changed
+136
-43
No files matched your search
@@ -539,8 +539,8 @@ def _trigger_base_specialization(trans: HT.Translator | t.CPtr,
|
||||
arg_nm = sl_nm.id
|
||||
if arg_nm is None:
|
||||
continue
|
||||
# 构建 type_args 列表
|
||||
type_args: list[str] | t.CPtr = list[str](pool, 1)
|
||||
# 构建 type_args 列表(elem_size=8:str 是指针,1 会导致双元素重叠损坏)
|
||||
type_args: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if type_args is None:
|
||||
continue
|
||||
type_args.append(arg_nm)
|
||||
@@ -2266,6 +2266,17 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr,
|
||||
"""
|
||||
if trans is None or class_name is None or type_args is None:
|
||||
return None
|
||||
# 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"),
|
||||
# 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。
|
||||
# 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。
|
||||
ta_cnt_g: t.CSizeT = type_args.__len__()
|
||||
ta_i_g: t.CSizeT
|
||||
for ta_i_g in range(ta_cnt_g):
|
||||
ta_raw_g: str = type_args.get(ta_i_g)
|
||||
if ta_raw_g is not None:
|
||||
ta_rsv_g: str = HandlesType.resolve_generic_type_name(ta_raw_g)
|
||||
if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0:
|
||||
type_args.set(ta_i_g, ta_rsv_g)
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
|
||||
|
||||
@@ -595,8 +595,8 @@ def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
if pool_val is None:
|
||||
return None
|
||||
|
||||
# 特化 list[T] 类
|
||||
type_args: list[str] | t.CPtr = list[str](pool, 4)
|
||||
# 特化 list[T] 类(elem_size=8:str 是指针,4 会导致双元素重叠损坏)
|
||||
type_args: list[str] | t.CPtr = list[str](pool, 8)
|
||||
type_args.append(inferred_type_name)
|
||||
spec_name: str = HandlesClassDef._specialize_generic_class(trans, "list", type_args)
|
||||
if spec_name is None:
|
||||
@@ -2640,6 +2640,48 @@ def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
|
||||
#
|
||||
# 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体)
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针
|
||||
#
|
||||
# c.Deref(ptr) 作为属性访问 base 时(如 c.Deref(p).a),需要 ptr
|
||||
# 指针本身而非 load 后的结构体值(*p.a → p->a),与 TPC
|
||||
# _handle_attr_call_result 语义一致。否则 c.Deref 返回结构体值,
|
||||
# 后续 GEP 在非指针上做属性访问会误报"base=非指针类型"。
|
||||
#
|
||||
# 返回:
|
||||
# ptr 指针值(Ptr(Struct) 或 Ptr(Ptr(Struct)),交由 _deref_if_ptr_ptr 解层级)
|
||||
# 非 c.Deref 模式返回 None
|
||||
# ============================================================
|
||||
def _get_cderef_attr_base(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
at_value: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)"""
|
||||
if at_value is None or at_value.kind() != ast.ASTKind.Call:
|
||||
return None
|
||||
cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(at_value)
|
||||
if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute:
|
||||
return None
|
||||
f_cd: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_cd.func)
|
||||
if f_cd.attr is None or string.strcmp(f_cd.attr, "Deref") != 0:
|
||||
return None
|
||||
if f_cd.value is None or f_cd.value.kind() != ast.ASTKind.Name:
|
||||
return None
|
||||
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(f_cd.value)
|
||||
if nm_cd.id is None or string.strcmp(nm_cd.id, "c") != 0:
|
||||
return None
|
||||
if cl_cd.args is None or cl_cd.args.__len__() < 1:
|
||||
return None
|
||||
inner_cd: llvmlite.Value | t.CPtr = translate_value(
|
||||
builder, pool, mod, cl_cd.args.get(0), None, 0, trans)
|
||||
if inner_cd is not None and is_ptr_type(inner_cd.Ty) != 0:
|
||||
return inner_cd
|
||||
return None
|
||||
|
||||
|
||||
def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
@@ -2885,7 +2927,14 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
|
||||
# 非 Name 路径:翻译对象值(会 load)
|
||||
if obj_ptr is None:
|
||||
obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||||
# c.Deref(ptr).attr: 属性访问 base 取指针本身而非 load 后的结构体值
|
||||
# (如 c.Deref(p).a 语义是 (*p).a,直接对 p 做 GEP)
|
||||
cd_base_rd: llvmlite.Value | t.CPtr = _get_cderef_attr_base(
|
||||
builder, pool, mod, at.value, trans)
|
||||
if cd_base_rd is not None:
|
||||
obj_ptr = cd_base_rd
|
||||
else:
|
||||
obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||||
|
||||
if obj_ptr is None or obj_ptr.Ty is None:
|
||||
return None
|
||||
@@ -3014,19 +3063,20 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
return None
|
||||
case _:
|
||||
# fast-fail: 对非指针类型做属性访问(如 i32.x),
|
||||
# 静默返回 None 会导致下游 "store to None" 崩溃,丢失错误现场
|
||||
diag_buf_ap: bytes = stdlib.malloc(256)
|
||||
if diag_buf_ap is not None:
|
||||
attr_nm_ap: str = "?"
|
||||
if at is not None and at.attr is not None:
|
||||
attr_nm_ap = at.attr
|
||||
viperlib.snprintf(diag_buf_ap, 256,
|
||||
"属性访问失败: .%s (base=非指针类型,无法做属性访问 sha1=%s:%d)",
|
||||
attr_nm_ap,
|
||||
trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?",
|
||||
at.lineno if at is not None and at.lineno is not None else 0)
|
||||
VLogger.error(diag_buf_ap, "ATTR")
|
||||
return None
|
||||
# Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃,丢失错误现场)
|
||||
attr_nm_ap: str = "?"
|
||||
if at is not None and at.attr is not None:
|
||||
attr_nm_ap = at.attr
|
||||
sha1_ap: str = "?"
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
sha1_ap = trans.ModuleSha1
|
||||
ln_ap: int = 0
|
||||
if at is not None and at.lineno is not None:
|
||||
ln_ap = at.lineno
|
||||
HandlesType.fatal_error(
|
||||
at,
|
||||
f"属性访问失败: .{attr_nm_ap} (base=非指针类型,无法做属性访问 sha1={sha1_ap}:{ln_ap})",
|
||||
"TypeError")
|
||||
|
||||
# ============================================================
|
||||
# 获取下标表达式的元素指针(不加载值,用于赋值)
|
||||
@@ -3181,7 +3231,14 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
|
||||
# 非 Name 路径:翻译对象值(会 load)
|
||||
if obj_ptr is None:
|
||||
obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||||
# c.Deref(ptr).attr: 属性写入 base 取指针本身而非 load 后的结构体值
|
||||
# (如 c.Deref(p).a = val 语义是 (*p).a = val,直接对 p 做 GEP)
|
||||
cd_base_wr: llvmlite.Value | t.CPtr = _get_cderef_attr_base(
|
||||
builder, pool, mod, at.value, trans)
|
||||
if cd_base_wr is not None:
|
||||
obj_ptr = cd_base_wr
|
||||
else:
|
||||
obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||||
|
||||
if obj_ptr is None or obj_ptr.Ty is None:
|
||||
return None
|
||||
@@ -3262,16 +3319,17 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
return None
|
||||
case _:
|
||||
# fast-fail: 对非指针类型做属性写入(如 i32.x = ...),
|
||||
# 静默返回 None 会导致下游 "store to None" 崩溃
|
||||
diag_buf_gp: bytes = stdlib.malloc(256)
|
||||
if diag_buf_gp is not None:
|
||||
attr_nm_gp: str = "?"
|
||||
if at is not None and at.attr is not None:
|
||||
attr_nm_gp = at.attr
|
||||
viperlib.snprintf(diag_buf_gp, 256,
|
||||
"属性写入失败: .%s (base=非指针类型,无法做属性写入 sha1=%s:%d)",
|
||||
attr_nm_gp,
|
||||
trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?",
|
||||
at.lineno if at is not None and at.lineno is not None else 0)
|
||||
VLogger.error(diag_buf_gp, "ATTR")
|
||||
return None
|
||||
# Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃)
|
||||
attr_nm_gp: str = "?"
|
||||
if at is not None and at.attr is not None:
|
||||
attr_nm_gp = at.attr
|
||||
sha1_gp: str = "?"
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
sha1_gp = trans.ModuleSha1
|
||||
ln_gp: int = 0
|
||||
if at is not None and at.lineno is not None:
|
||||
ln_gp = at.lineno
|
||||
HandlesType.fatal_error(
|
||||
at,
|
||||
f"属性写入失败: .{attr_nm_gp} (base=非指针类型,无法做属性写入 sha1={sha1_gp}:{ln_gp})",
|
||||
"TypeError")
|
||||
@@ -4498,7 +4498,9 @@ def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr,
|
||||
"""
|
||||
if slice_node is None or pool is None:
|
||||
return None
|
||||
result: list[str] | t.CPtr = list[str](pool, 4)
|
||||
# elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节
|
||||
# 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃
|
||||
result: list[str] | t.CPtr = list[str](pool, 8)
|
||||
k: int = slice_node.kind()
|
||||
if k == ast.ASTKind.Tuple:
|
||||
tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node)
|
||||
@@ -4696,12 +4698,20 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
return _translate_generic_ctor_call(
|
||||
pool, builder, mod, spec_name, cl, trans)
|
||||
else:
|
||||
# 泛型类模板未找到:可能未 import 定义模块
|
||||
gt_err: str = pool.alloc(256)
|
||||
if gt_err is not None:
|
||||
viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name)
|
||||
HandlesType.fatal_error(gen_nm_node, gt_err)
|
||||
HandlesType.fatal_error(gen_nm_node, "泛型类模板未找到")
|
||||
# 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x)
|
||||
# (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化,
|
||||
# 泛型函数按普通函数编译,类型参数 [T] 仅在函数定义处消费)。
|
||||
# 检查当前模块是否已定义同名函数(def double[T] 编译后即普通函数
|
||||
# double),若是则丢弃 [t.CInt] 显式类型参数,退回普通函数调用。
|
||||
if find_func_in_module(mod, gen_class_name) is not None:
|
||||
func_name = gen_class_name
|
||||
else:
|
||||
# 泛型类模板未找到:可能未 import 定义模块
|
||||
gt_err: str = pool.alloc(256)
|
||||
if gt_err is not None:
|
||||
viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name)
|
||||
HandlesType.fatal_error(gen_nm_node, gt_err)
|
||||
HandlesType.fatal_error(gen_nm_node, "泛型类模板未找到")
|
||||
if func_name is None:
|
||||
# 检查是否是 (A | t.CPtr)(value) 形式的类型转换
|
||||
# BinOp 节点作为 Call func: 联合类型注解用作类型转换
|
||||
@@ -4878,6 +4888,19 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
bare_ty = llvmlite.Double(pool)
|
||||
else:
|
||||
bare_ty = HandlesType.map_t_type(pool, bare_fn_name)
|
||||
# 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名),
|
||||
# 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。
|
||||
# GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。
|
||||
if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0:
|
||||
gp_ast: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, bare_fn_name, 0)
|
||||
if gp_ast is not None:
|
||||
imp_gp: str = None
|
||||
fi_gp: str = None
|
||||
if trans is not None:
|
||||
imp_gp = trans._imported_modules
|
||||
fi_gp = trans._from_imports
|
||||
bare_ty = HandlesType.resolve_annotation_type(
|
||||
pool, gp_ast, imp_gp, fi_gp, trans)
|
||||
if bare_ty is not None and can == 1:
|
||||
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
if bare_arg_node is not None:
|
||||
|
||||
@@ -579,10 +579,11 @@ def _get_type_name_from_annotation(pool: memhub.MemBuddy | t.CPtr,
|
||||
if cn.const_kind == ast.CONST_STR and cn.str_val is not None:
|
||||
return cn.str_val
|
||||
return None
|
||||
# Name: 直接返回 id
|
||||
# Name: 直接返回 id(泛型特化上下文内先做 T 替换,避免 ndarray[T] 中 T 未解析
|
||||
# 导致 _specialize_generic_class("ndarray", ["T"]) 二次递归崩溃)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
return nm.id
|
||||
return resolve_generic_type_name(nm.id)
|
||||
# Attribute: 构造 "module.attr" 格式
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
@@ -1761,8 +1762,8 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
||||
if gen_nm.id is not None:
|
||||
if string.strcmp(gen_nm.id, "tuple") == 0:
|
||||
return None
|
||||
# 先收集类型实参名,再分配缓冲区拼接 mangled name
|
||||
gen_arg_names: list[str] | t.CPtr = list[str](pool, 4)
|
||||
# 先收集类型实参名,再分配缓冲区拼接 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
|
||||
|
||||
Reference in new issue
Block a user