fix(gen): 泛型类构造只在真有 __init__ 时才调 __before_init__/__init__

无方法的泛型类(如 NewTest 的 Box[T])没有 __init__,ClassGenVTable 也就不会生成 __before_init__,但 _translate_generic_ctor_call 无条件发射这两个调用,导致链接期 undefined symbol(1cf2df6387df0bbf.Box[int].__before_init__ / .__init__)。改为与非泛型 _translate_struct_ctor 同判据:有 __init__ 才走 __before_init__ + __init__,否则按字段顺序逐字段 store。
This commit is contained in:
TermiNexus committed 2026-10-08 22:16:23 +08:00
1 parent c02aa3a2eb
commit 8fb0e38f4c
1 file changed
+46 -4
+46 -4
View File
@@ -1016,10 +1016,52 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase):
nw_bc: mlirlite.Value* = mlirlite.build_bitcast(builder, new_ptr, nw_ty)
if nw_bc is not None: storage_ptr = nw_bc
# call __before_init__(storage_ptr) (auto-generated by TransPyV, zero-fills)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans, None, gc_volatile)
# 有 __init__ 才调 __before_init__/__init__(与非泛型 _translate_struct_ctor 的 is_oop 判据一致):
# ClassGenVTable 只对"有方法"的类生成 __before_init__,无条件调用会在无方法类(如 Box[T])上
# 产生 undefined symbol(__before_init__ / __init__ 都没有定义)。
gi_has_init: int = 0
if struct_entry is not None: gi_has_init = struct_entry.HasInit
if gi_has_init == 0:
# 特化类的 HasInit 可能没被传播:再按非泛型路径同口径查"该方法是否真的存在"
# (模块内声明 或 全局默认参数表),避免有 __init__ 的泛型类被漏掉。
init_lk: str = pool.alloc(256)
if init_lk is not None:
viperlib.snprintf(init_lk, 256, "%s.__init__", spec_name)
if self.find_func_in_module(mod, init_lk) is not None: gi_has_init = 1
elif self.Gen.CallGenLeafKit.find_func_defaults(init_lk) is not None: gi_has_init = 1
if gi_has_init != 0:
# call __before_init__(storage_ptr) (auto-generated by TransPyV, zero-fills)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans, None, gc_volatile)
# call __init__(storage_ptr, *args) (arg_count = slots 0..highest filled)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, arg_count, trans, None, gc_volatile, gc_arg_nodes)
# call __init__(storage_ptr, *args) (arg_count = slots 0..highest filled)
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, arg_count, trans, None, gc_volatile, gc_arg_nodes)
elif has_new_flag == 0:
# 无 __init__ 也无 __new__:按字段顺序逐字段 store(与非泛型路径同语义;字段 0 若是
# __vtable__ 占位则跳过)。这条分支保证 `Box[int](7)` 仍然把 7 写进字段 v。
for ai_sf in range(can):
arg_sf: ast.AST* = cargs.get(ai_sf)
if arg_sf is None: continue
fe_sf: GenTypes.FieldEntry* = None
if struct_entry is not None:
tidx_sf: int = 0
for fi_sf in range(struct_entry.FieldCount):
cand_sf: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(struct_entry, fi_sf)
if cand_sf is None: continue
cn_sf: str = self.Gen.StructGen.get_field_name_ptr(cand_sf)
if cn_sf is not None and string.strcmp(cn_sf, "__vtable__") == 0: continue
if tidx_sf == ai_sf:
fe_sf = cand_sf
break
tidx_sf += 1
else: fe_sf = self.Gen.StructGen.get_field_by_index(spec_name, ai_sf)
if fe_sf is None:
self.Gen.TypeGenErr.fatal_error(arg_sf, f"Generic class ctor '{spec_name}': too many arguments (field index out of range)", "TypeError")
continue
av_sf: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg_sf, None, 0, trans, fe_sf.Ty)
if av_sf is None: continue
fp_sf: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, fe_sf.Ty, storage_ptr, fe_sf.Index)
if fp_sf is None: continue
av_sf = self.Gen.ExprGenBase.coerce_to_type(builder, av_sf, fe_sf.Ty, arg_sf)
mlirlite.build_store(builder, av_sf, fp_sf, gc_volatile)
return storage_ptr