diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 74a1e2a..3d88c4d 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -2312,6 +2312,18 @@ def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr, "__new__", tmp, new_arg_vals, new_arg_count, trans) if new_ptr is not None: storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 _call_method_on_ptr(pool, builder, mod, class_name, @@ -4029,6 +4041,18 @@ def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr, "__new__", tmp, new_arg_vals, new_arg_count, trans) if new_ptr is not None: storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc # 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加 init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) @@ -4394,6 +4418,18 @@ def _translate_generic_ctor_call(pool: memhub.MemBuddy | t.CPtr, pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) if new_ptr is not None: storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc # call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充) _call_method_on_ptr( diff --git a/App/lib/core/Phase2.vp b/App/lib/core/Phase2.vp index bc65600..0803600 100644 --- a/App/lib/core/Phase2.vp +++ b/App/lib/core/Phase2.vp @@ -295,6 +295,21 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, inc_dir_len_pre: t.CSizeT = string.strlen(includes_dir) deps_filled_pre: int = 0 PHASE_A_INC_MAX_PASSES: t.CInt = 3 + # [修复] 记录预注册失败的 includes:多遍后仍失败 → 报错终止编译。 + # 不允许静默降级——静默失败会让 App 源文件的跨模块类构造退化为 + # 普通函数调用(返回类型默认推断成 i32),调用点报误导性的 + # "跨模块调用 'parser.add_argument' 找不到模块 SHA1" + # (如 argparse.ArgumentParser 类未注册导致 parser 变量类型崩坏)。 + # declare_only=1 时 import 的 SHA1 检查跳过(容忍依赖未注册), + # 因此预注册失败只可能是文件自身无法翻译(语法/解析/编译错误)。 + # 注意:Sha1Store 因 AppendToSha1MapStore 追加了 App 源文件 SHA1 + # (供跨模块 CDefine 查找),此处必须跳过 App 文件——App 文件的 + # 预注册由 Phase A-pre(遍历 entries,declare_only=1)负责。 + # App 文件是严格模式(仅本地+import 可见)且预注册阶段依赖未就绪, + # 若在此预注册必然失败,误报"预注册失败: main.vp"。 + inc_fail_flags: bytes = stdlib.malloc(store_count_inc_pre) + if inc_fail_flags is not None: + string.memset(inc_fail_flags, 1, store_count_inc_pre) for pass_inc_i in range(PHASE_A_INC_MAX_PASSES): struct_count_before_inc: int = HandlesStruct.get_struct_count() for si_inc in range(store_count_inc_pre): @@ -302,6 +317,19 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, inc_rel_pre: str = store_rel_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_REL_PATH_LEN if inc_rel_pre is None or inc_rel_pre[0] == '\0': continue + # 跳过 App 源文件(main.vp 等):由 Phase A-pre 预注册,不算失败 + is_app_file_inc: int = 0 + for i_app_inc in range(file_count): + ea_app_inc: t.CUInt64T = t.CUInt64T(entries) + i_app_inc * entry_size + ent_app_inc: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_app_inc, t.CPtr)) + if ent_app_inc is not None and ent_app_inc.Sha1 is not None: + if string.strcmp(ent_app_inc.Sha1, inc_sha1_pre) == 0: + is_app_file_inc = 1 + break + if is_app_file_inc != 0: + if inc_fail_flags is not None: + inc_fail_flags[si_inc] = 0 + continue rel_len_pre: t.CSizeT = string.strlen(inc_rel_pre) full_path_pre: bytes = stdlib.malloc(inc_dir_len_pre + rel_len_pre + 2) if full_path_pre is None: @@ -313,6 +341,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, mb, full_path_pre, inc_sha1_pre, pkg_inc_pre, 1) stdlib.free(full_path_pre) if tr_inc_pre is not None: + # 预注册成功:清除失败标记 + if inc_fail_flags is not None: + inc_fail_flags[si_inc] = 0 # 依赖填充只在第一遍执行(PopulateIncludesDeps 内部有去重) if pass_inc_i == 0: if tr_inc_pre._imported_modules is not None: @@ -322,6 +353,19 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, # 收敛检查:本遍没有新结构体注册 → 所有类已注册 if struct_count_after_inc == struct_count_before_inc: break + # 多遍后仍预注册失败的 includes → 报错终止(不允许降级) + if inc_fail_flags is not None: + for si_inc_f in range(store_count_inc_pre): + if inc_fail_flags[si_inc_f] != 0: + rel_f: str = store_rel_inc_pre + t.CSizeT(si_inc_f) * StubMerger.MAX_REL_PATH_LEN + fb_inc_f: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_inc_f is not None: + viperlib.snprintf(fb_inc_f, 1024, + "includes 预注册失败: %s(文件无法翻译,可能是语法/解析/编译错误),终止编译", + rel_f) + VLogger.error(fb_inc_f, "prePhaseA") + sys.exit(1) + stdlib.free(inc_fail_flags) fb_inc_pre: t.CChar | t.CPtr = VLogger.fmt_buf() if fb_inc_pre is not None: viperlib.snprintf(fb_inc_pre, 1024, "includes 预注册 + 依赖填充: %d/%d", deps_filled_pre, store_count_inc_pre)