From a7728a8f2f8a2f62843b882f385017446afcd3aa Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 27 Nov 2024 21:10:37 +0800 Subject: [PATCH] Trans - Hack support for no-trait trait objects --- src/hir_typeck/static.cpp | 4 +++ src/mir/cleanup.cpp | 64 +++++++++++++++------------------------ src/trans/auto_impls.cpp | 57 ++++++++++++++++++++++++++++++++++ src/trans/enumerate.cpp | 16 +++++++++- 4 files changed, 101 insertions(+), 40 deletions(-) diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 88850ae3c..bf49d60cb 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -3208,6 +3208,10 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const throw ""; } TU_ARM(p.m_data, UfcsKnown, pe) { + if( pe.trait.m_path == HIR::SimplePath() && pe.item == "vtable#" ) { + DEBUG("Empty trait VTable, return NotYetKnown"); + return ValuePtr::make_NotYetKnown({}); + } out_params.self_ty = pe.type.clone(); out_params.pp_impl = &pe.trait.m_params; out_params.pp_method = &pe.params; diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 135dac439..e226a0d8c 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -741,52 +741,38 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } TU_ARMA(TraitObject, de) { - auto ty_unit_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()); - - // No data trait, vtable is a null unit pointer. - // - Shouldn't the vtable be just unit? - // - Codegen assumes it's a pointer. - if( de.m_trait.m_path.m_path == ::HIR::SimplePath() ) - { - auto null_lval = mutator.in_temporary( ::HIR::CoreType::Usize, ::MIR::Constant::make_Uint({ U128(0u), ::HIR::CoreType::Usize }) ); - out_meta_ty = ty_unit_ptr.clone(); - out_meta_val = mutator.in_temporary( out_meta_ty.clone(), ::MIR::RValue::make_Cast({ mv$(null_lval), mv$(ty_unit_ptr) }) ); - } - else + // Obtain vtable type `::"path"::to::Trait#vtable` + auto vtable_ty = de.m_trait.m_path != HIR::SimplePath() + ? de.m_trait.m_trait_ptr->get_vtable_type(state.sp, state.m_crate, de) + : ::HIR::TypeRef::new_unit(); + out_meta_ty = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, mv$(vtable_ty)); + + // If the data trait hasn't changed, return the vtable pointer + if( const auto* se = src_ty.data().opt_TraitObject() ) { - const auto& trait_path = de.m_trait; - const auto& trait = *de.m_trait.m_trait_ptr; - - // Obtain vtable type `::"path"::to::Trait#vtable` - auto vtable_ty = trait.get_vtable_type(state.sp, state.m_crate, de); - out_meta_ty = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, mv$(vtable_ty)); - - // If the data trait hasn't changed, return the vtable pointer - if( const auto* se = src_ty.data().opt_TraitObject() ) + out_src_is_dst = true; + if( se->m_trait.m_trait_ptr != de.m_trait.m_trait_ptr ) { - out_src_is_dst = true; - if( se->m_trait.m_trait_ptr != de.m_trait.m_trait_ptr ) - { - const auto& trait = *se->m_trait.m_trait_ptr; - auto vtable_ty = trait.get_vtable_type(state.sp, state.m_crate, *se); - auto in_meta_ty = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, mv$(vtable_ty)); - - auto parent_trait_field = trait.get_vtable_parent_index(state.sp, se->m_trait.m_path.m_params, de.m_trait.m_path); - MIR_ASSERT(state, parent_trait_field != 0, "Unable to find parent trait for trait object upcast - " << se->m_trait.m_path << " in " << de.m_trait.m_path); - auto in_meta_val = mutator.in_temporary( mv$(in_meta_ty), ::MIR::RValue::make_DstMeta({ ptr_value.clone() }) ); - out_meta_val = MIR::LValue::new_Field( MIR::LValue::new_Deref( mv$(in_meta_val) ), parent_trait_field ); - } - else - { - out_meta_val = mutator.in_temporary( out_meta_ty.clone(), ::MIR::RValue::make_DstMeta({ ptr_value.clone() }) ); - } + assert(se->m_trait.m_trait_ptr); + const auto& trait = *se->m_trait.m_trait_ptr; + auto vtable_ty = trait.get_vtable_type(state.sp, state.m_crate, *se); + auto in_meta_ty = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, mv$(vtable_ty)); + + auto parent_trait_field = trait.get_vtable_parent_index(state.sp, se->m_trait.m_path.m_params, de.m_trait.m_path); + MIR_ASSERT(state, parent_trait_field != 0, "Unable to find parent trait for trait object upcast - " << se->m_trait.m_path << " in " << de.m_trait.m_path); + auto in_meta_val = mutator.in_temporary( mv$(in_meta_ty), ::MIR::RValue::make_DstMeta({ ptr_value.clone() }) ); + out_meta_val = MIR::LValue::new_Field( MIR::LValue::new_Deref( mv$(in_meta_val) ), parent_trait_field ); } else { - MIR_ASSERT(state, state.m_resolve.type_is_sized(state.sp, src_ty), "Attempting to get vtable for unsized type - " << src_ty); - out_meta_val = create_vtable(src_ty.clone(), trait_path); + out_meta_val = mutator.in_temporary( out_meta_ty.clone(), ::MIR::RValue::make_DstMeta({ ptr_value.clone() }) ); } } + else + { + MIR_ASSERT(state, state.m_resolve.type_is_sized(state.sp, src_ty), "Attempting to get vtable for unsized type - " << src_ty); + out_meta_val = create_vtable(src_ty.clone(), de.m_trait); + } return true; } } diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index 5c8de0318..d33d738e5 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -689,6 +689,63 @@ void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list) Span sp; const auto& trait_path = ent.first.m_data.as_UfcsKnown().trait; const auto& type = ent.first.m_data.as_UfcsKnown().type; + if( trait_path.m_path != HIR::SimplePath() ) { + continue; + } + DEBUG("VTABLE for " << type); + + ::std::vector tuple_tys; + tuple_tys.push_back(::HIR::CoreType::Usize); + tuple_tys.push_back(::HIR::CoreType::Usize); + tuple_tys.push_back(::HIR::CoreType::Usize); // fn + auto vtable_ty = ::HIR::TypeRef(std::move(tuple_tys)); + + // Look up the size of the VTable, so we can allocate the right buffer size + const auto* repr = Target_GetTypeRepr(sp, state.resolve, vtable_ty); + assert(repr); + + HIR::Linkage linkage; + linkage.type = HIR::Linkage::Type::Weak; + HIR::Static vtable_static( ::std::move(linkage), /*is_mut*/false, mv$(vtable_ty), {} ); + auto& vtable_data = vtable_static.m_value_res; + const auto ptr_bytes = Target_GetPointerBits()/8; + vtable_data.bytes.resize( repr->size ); + size_t ofs = 0; + auto push_ptr = [&vtable_data,&ofs,ptr_bytes](HIR::Path p) { + DEBUG("@" << ofs << " = " << p); + assert(ofs + ptr_bytes <= vtable_data.bytes.size()); + vtable_data.relocations.push_back(Reloc::new_named( ofs, ptr_bytes, mv$(p) )); + vtable_data.write_uint(ofs, ptr_bytes, EncodedLiteral::PTR_BASE); + ofs += ptr_bytes; + assert(ofs <= vtable_data.bytes.size()); + }; + // Drop glue + trans_list.m_drop_glue.insert( type.clone() ); + push_ptr(::HIR::Path(type.clone(), "#drop_glue")); + // Size & align + { + size_t size, align; + // NOTE: Uses the Size+Align version because that doesn't panic on unsized + ASSERT_BUG(sp, Target_GetSizeAndAlignOf(sp, state.resolve, type, size, align), "Unexpected generic? " << type); + vtable_data.write_uint(ofs, ptr_bytes, size ); ofs += ptr_bytes; + vtable_data.write_uint(ofs, ptr_bytes, align); ofs += ptr_bytes; + } + assert(ofs == vtable_data.bytes.size()); + vtable_static.m_value_generated = true; + + // Add to list + trans_list.m_auto_statics.push_back( box$(vtable_static) ); + auto* e = trans_list.add_static(ent.first.clone()); + e->ptr = trans_list.m_auto_statics.back().get(); + } + for(const auto& ent : trans_list.m_vtables) + { + Span sp; + const auto& trait_path = ent.first.m_data.as_UfcsKnown().trait; + const auto& type = ent.first.m_data.as_UfcsKnown().type; + if( trait_path.m_path == HIR::SimplePath() ) { + continue; + } DEBUG("VTABLE " << trait_path << " for " << type); // TODO: What's the use of `ent.second` here? (it's a `Trans_Params`) diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 5c184dd24..6feb5560a 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -996,7 +996,18 @@ void Trans_Enumerate_Types(EnumState& state) for(const auto& ent : state.rv.m_vtables) { TRACE_FUNCTION_F("vtable " << ent.first); + const auto& ty = ent.first.m_data.as_UfcsKnown().type; const auto& gpath = ent.first.m_data.as_UfcsKnown().trait; + if( gpath.m_path == HIR::SimplePath() ) { + ::std::vector tuple_tys; + tuple_tys.push_back(::HIR::CoreType::Usize); + tuple_tys.push_back(::HIR::CoreType::Usize); + tuple_tys.push_back(::HIR::CoreType::Usize); // fn + auto vtable_ty = ::HIR::TypeRef(std::move(tuple_tys)); + tv.visit_type( ty ); + tv.visit_type( vtable_ty ); + continue ; + } const auto& trait = state.crate.get_trait_by_path(sp, gpath.m_path); const auto& vtable_ty_spath = trait.m_vtable_path; @@ -1016,7 +1027,6 @@ void Trans_Enumerate_Types(EnumState& state) } DEBUG("VTable: " << vtable_ty_spath << vtable_params); - const auto& ty = ent.first.m_data.as_UfcsKnown().type; tv.visit_type( ty ); tv.visit_type( ::HIR::TypeRef::new_path( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref ) ); @@ -1537,6 +1547,10 @@ void Trans_Enumerate_FillFrom_VTable(EnumState& state, ::HIR::Path vtable_path, static Span sp; const auto& type = vtable_path.m_data.as_UfcsKnown().type; const auto& trait_path = vtable_path.m_data.as_UfcsKnown().trait; + if( trait_path == HIR::SimplePath() ) { + // TODO: Ensure that the drop glue is available + return ; + } const auto& tr = state.crate.get_trait_by_path(Span(), trait_path.m_path); ASSERT_BUG(sp, !type.data().is_Slice(), "Getting vtable for unsized type - " << vtable_path);