Skip to content

Commit

Permalink
Trans - Hack support for no-trait trait objects
Browse files Browse the repository at this point in the history
  • Loading branch information
thepowersgang committed Nov 27, 2024
1 parent 7e17e3a commit a7728a8
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 40 deletions.
4 changes: 4 additions & 0 deletions src/hir_typeck/static.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
64 changes: 25 additions & 39 deletions src/mir/cleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
57 changes: 57 additions & 0 deletions src/trans/auto_impls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <empty> for " << type);

::std::vector<HIR::TypeRef> 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`)

Expand Down
16 changes: 15 additions & 1 deletion src/trans/enumerate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<HIR::TypeRef> 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;
Expand All @@ -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 ) );

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit a7728a8

Please sign in to comment.