diff --git a/App/lib/core/Handles/HandlesClassDef.vp b/App/lib/core/Handles/HandlesClassDef.vp index 3d4a9c3..5875939 100644 --- a/App/lib/core/Handles/HandlesClassDef.vp +++ b/App/lib/core/Handles/HandlesClassDef.vp @@ -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 diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 91ab9c5..5d9ee28 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -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") diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index a984b4d..a9284c3 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -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: diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index 8ee35c2..c3bf2b3 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -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