From 3f2bca3ef58095ff20607b2cb66d6886c34df6cf Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 May 2024 21:08:15 +0800 Subject: [PATCH] HIR/Trans - Add support for trait upcasting (with a test!) --- samples/test/trait_upcast.rs | 27 ++++++++ src/hir/deserialise.cpp | 3 +- src/hir/hir.cpp | 2 +- src/hir/hir.hpp | 4 ++ src/hir/hir_ops.cpp | 13 ++++ src/hir/serialise.cpp | 1 + src/hir_expand/vtable.cpp | 125 ++++++++++++++++++++++++++++++++--- src/hir_typeck/expr_cs.cpp | 3 + src/hir_typeck/helpers.cpp | 1 + src/hir_typeck/outer.cpp | 6 +- src/hir_typeck/static.cpp | 27 +++++++- src/mir/cleanup.cpp | 18 ++++- src/mir/from_hir.cpp | 1 + src/trans/auto_impls.cpp | 90 ++++++++++++++++--------- src/trans/enumerate.cpp | 13 ++++ 15 files changed, 284 insertions(+), 50 deletions(-) create mode 100644 samples/test/trait_upcast.rs diff --git a/samples/test/trait_upcast.rs b/samples/test/trait_upcast.rs new file mode 100644 index 000000000..fd616c5d7 --- /dev/null +++ b/samples/test/trait_upcast.rs @@ -0,0 +1,27 @@ +// + +trait A { + fn bar(&self) -> i32; +} +trait B: A { + fn baz(&self) -> i32; +} + +struct Foo; +impl A for Foo { + fn bar(&self) -> i32 { + 12345 + } +} +impl B for Foo { + fn baz(&self) -> i32 { + 54321 + } +} + +fn main() { + let v = Foo; + let b: &dyn B = &v; + let a: &dyn A = b; + assert_eq!( a.bar(), 12345 ); +} diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 57332dec6..4bed07a08 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -1366,11 +1366,12 @@ namespace { rv.m_values = deserialise_istrumap< ::HIR::TraitValueItem>(); rv.m_value_indexes = deserialise_istrummap< ::std::pair >(); rv.m_type_indexes = deserialise_istrumap< unsigned int>(); + rv.m_vtable_parent_traits_start = m_in.read_count(); rv.m_all_parent_traits = deserialise_vec< ::HIR::TraitPath>(); rv.m_vtable_path = deserialise_simplepath(); return rv; } - + ::HIR::ConstGeneric HirDeserialiser::deserialise_constgeneric() { switch( auto tag = m_in.read_tag() ) diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index f24e60103..2f8587e12 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -302,7 +302,7 @@ const ::HIR::TypeItem& ::HIR::Crate::get_typeitem_by_path(const Span& sp, const auto it = mod.m_mod_items.find( ignore_last_node ? path.m_components[path.m_components.size()-2] : path.m_components.back() ); if( it == mod.m_mod_items.end() ) { - BUG(sp, "Could not find type name in " << path); + BUG(sp, "Could not find type " << path); } return it->second->ent; diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 03f332065..d4fcd19e4 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -450,6 +450,8 @@ class Trait ::std::unordered_multimap< RcString, ::std::pair > m_value_indexes; // Indexes in the vtable parameter list for each associated type ::std::unordered_map< RcString, unsigned int > m_type_indexes; + /// Index of the first vtable entry for parent traits + unsigned m_vtable_parent_traits_start; // Flattend set of parent traits (monomorphised and associated types fixed) ::std::vector< ::HIR::TraitPath > m_all_parent_traits; @@ -461,10 +463,12 @@ class Trait m_lifetime( mv$(lifetime) ), m_parent_traits( mv$(parents) ), m_is_marker( false ) + , m_vtable_parent_traits_start(0) {} ::HIR::TypeRef get_vtable_type(const Span& sp, const ::HIR::Crate& crate, const ::HIR::TypeData::Data_TraitObject& te) const; unsigned get_vtable_value_index(const HIR::GenericPath& trait_path, const RcString& name) const; + unsigned get_vtable_parent_index(const Span& sp, const HIR::PathParams& this_params, const HIR::GenericPath& trait_path) const; }; class ProcMacro diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp index c2d674e0c..2ca5d56ca 100644 --- a/src/hir/hir_ops.cpp +++ b/src/hir/hir_ops.cpp @@ -1255,6 +1255,19 @@ unsigned HIR::Trait::get_vtable_value_index(const HIR::GenericPath& trait_path, } return 0; } +unsigned HIR::Trait::get_vtable_parent_index(const Span& sp, const HIR::PathParams& this_params, const HIR::GenericPath& trait_path) const +{ + for(const auto& pt : this->m_all_parent_traits) { + if( pt.m_path.m_path == trait_path.m_path ) + { + auto p = MonomorphStatePtr(nullptr, &this_params, nullptr).monomorph_genericpath(sp, pt.m_path); + if( p == trait_path ) { + return m_vtable_parent_traits_start + (&pt - this->m_all_parent_traits.data()); + } + } + } + return 0; +} /// Helper for getting the struct associated with a pattern path const ::HIR::Struct& HIR::pattern_get_struct(const Span& sp, const ::HIR::Path& path, const ::HIR::Pattern::PathBinding& binding, bool is_tuple) diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index fc9191f2b..e8ef639c4 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -1335,6 +1335,7 @@ serialise_strmap( item.m_values ); serialise_strmap( item.m_value_indexes ); serialise_strmap( item.m_type_indexes ); + m_out.write_count(item.m_vtable_parent_traits_start); serialise_vec( item.m_all_parent_traits ); serialise( item.m_vtable_path ); } diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp index a11c112a0..e76e9e250 100644 --- a/src/hir_expand/vtable.cpp +++ b/src/hir_expand/vtable.cpp @@ -107,7 +107,7 @@ namespace { ::HIR::Trait* trait_ptr; ::HIR::t_struct_fields fields; - bool add_ents_from_trait(const ::HIR::Trait& tr, const ::HIR::GenericPath& trait_path) + bool add_ents_from_trait(const ::HIR::Trait& tr, const ::HIR::GenericPath& trait_path, std::vector* supertrait_flags) { TRACE_FUNCTION_F(trait_path); struct M: public Monomorphiser { @@ -230,11 +230,14 @@ namespace { } } } - for(const auto& st : tr.m_all_parent_traits) { - ::HIR::TypeRef self("Self", 0xFFFF); - auto st_gp = MonomorphStatePtr(&self, &trait_path.m_params, nullptr).monomorph_genericpath(sp, st.m_path, false); - // NOTE: Doesn't trigger non-object-safe - add_ents_from_trait(*st.m_trait_ptr, st_gp); + if( supertrait_flags ) { + supertrait_flags->reserve(tr.m_all_parent_traits.size()); + for(const auto& st : tr.m_all_parent_traits) { + ::HIR::TypeRef self("Self", 0xFFFF); + auto st_gp = MonomorphStatePtr(&self, &trait_path.m_params, nullptr).monomorph_genericpath(sp, st.m_path, false); + // NOTE: Doesn't trigger non-object-safe + supertrait_flags->push_back( add_ents_from_trait(*st.m_trait_ptr, st_gp, nullptr) ); + } } return true; } @@ -253,12 +256,30 @@ namespace { // - Alignment of data vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::CoreType::Usize } )); // - Add methods - if( ! vtc.add_ents_from_trait(tr, trait_path) || has_conflicting_aty_name ) + ::std::vector supertrait_flags; + if( ! vtc.add_ents_from_trait(tr, trait_path, &supertrait_flags) || has_conflicting_aty_name ) { tr.m_value_indexes.clear(); tr.m_type_indexes.clear(); return ; } + tr.m_vtable_parent_traits_start = vtc.fields.size(); + // Add parent vtables too. + for(size_t i = 0; i < tr.m_all_parent_traits.size(); i ++ ) + { + const auto& pt = tr.m_all_parent_traits[i]; + auto parent_vtable_spath = pt.m_path.m_path; + parent_vtable_spath.m_components.back() = RcString::new_interned(FMT( parent_vtable_spath.m_components.back().c_str() << "#vtable" )); + auto parent_vtable_path = ::HIR::GenericPath(mv$(parent_vtable_spath), pt.m_path.m_params.clone()); + auto ty = true || supertrait_flags[i] + ? ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef::new_path(mv$(parent_vtable_path), {}) ) + : ::HIR::TypeRef::new_unit() + ; + vtc.fields.push_back(::std::make_pair( + RcString::new_interned(FMT("#parent_" << i)), + ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), mv$(ty) } + )); + } auto fields = mv$(vtc.fields); ::HIR::PathParams params; @@ -335,11 +356,99 @@ namespace { #endif } }; -} + + class FixupVisitor: + public ::HIR::Visitor + { + const ::HIR::Crate& m_crate; + public: + FixupVisitor(const ::HIR::Crate& crate): + m_crate(crate) + { + } + + void visit_struct(HIR::ItemPath ip, HIR::Struct& str) + { + static Span sp; + auto p = std::strchr(ip.name, '#'); + if( p && std::strcmp(p, "#vtable") == 0 ) + { + auto trait_path = ip.parent->get_simple_path(); + trait_path.m_components.push_back( RcString::new_interned(ip.name, p - ip.name) ); + const auto& trait = m_crate.get_trait_by_path(sp, trait_path); + + auto& fields = str.m_data.as_Named(); + for(size_t i = 0; i < trait.m_all_parent_traits.size(); i ++) + { + const auto& pt = trait.m_all_parent_traits[i]; + const auto& parent_trait = *pt.m_trait_ptr; + auto& fld_ty = fields[trait.m_vtable_parent_traits_start + i].second.ent; + DEBUG(pt << " " << fld_ty); + + if( parent_trait.m_vtable_path == HIR::SimplePath() ) { + // Not object safe, so clear this entry + fld_ty = ::HIR::TypeRef::new_unit(); + } + else { + auto& te = fld_ty.data_mut().as_Borrow().inner.data_mut().as_Path(); + auto& vtable_gpath = te.path.m_data.as_Generic(); + te.binding = &m_crate.get_struct_by_path(sp, vtable_gpath.m_path); + + for(const auto& aty_idx : parent_trait.m_type_indexes) + { + if( vtable_gpath.m_params.m_types.size() <= aty_idx.second ) { + vtable_gpath.m_params.m_types.resize( aty_idx.second+1 ); + } + auto& slot = vtable_gpath.m_params.m_types[aty_idx.second]; + // If this associated type is in the trait path `pt` + auto it = pt.m_type_bounds.find( aty_idx.first ); + if( it != pt.m_type_bounds.end() ) { + slot = it->second.type.clone(); + } + // If this type is not in the trait path, then check if it has a defined generic + else if( trait.m_type_indexes.count(aty_idx.first) != 0 ) { + slot = HIR::TypeRef(RcString(), trait.m_type_indexes.at(aty_idx.first)); + } + else { + // Otherwise, it has to have been defined in another parent trait + const HIR::GenericPath* gp = nullptr; + for( const auto& pptrait_path : parent_trait.m_all_parent_traits ) { + if( pptrait_path.m_trait_ptr->m_types.count(aty_idx.first) != 0 ) { + // Found the trait that defined this ATY + DEBUG("Found " << aty_idx.first << " in " << pptrait_path); + gp = &pptrait_path.m_path; + } + } + ASSERT_BUG(sp, gp, "Failed to a find trait that defined " << aty_idx.first << " in " << pt.m_path.m_path); + + // Monomorph into the top trait + auto gp_mono = MonomorphStatePtr(nullptr, &pt.m_path.m_params, nullptr).monomorph_genericpath(sp, *gp); + // Search the parent list + const HIR::TraitPath* p = nullptr; + for(const auto& pt : trait.m_all_parent_traits) { + if( pt.m_path == gp_mono ) { + p = &pt; + } + } + ASSERT_BUG(sp, p, "Failed to find " << gp_mono << " in parent trait list for " << trait_path); + auto it = p->m_type_bounds.find( aty_idx.first ); + ASSERT_BUG(sp, it != p->m_type_bounds.end(), "Failed to find " << aty_idx.first << " in " << *p); + slot = it->second.type.clone(); + } + } + } + } + } + } + }; +} // namespace void HIR_Expand_VTables(::HIR::Crate& crate) { OuterVisitor ov(crate); ov.visit_crate( crate ); + + FixupVisitor fv(crate); + fv.visit_crate(crate); } diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index d8474f470..c72b64f9c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4286,6 +4286,9 @@ namespace { if( dep->m_trait.m_path.m_path != sep->m_trait.m_path.m_path ) { // Trait mismatch! + #if 1 // 1.74: `trait_upcasting` feature + return CoerceResult::Unsize; + #endif return CoerceResult::Equality; } const auto& tys_d = dep->m_trait.m_path.m_params.m_types; diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 8e4c594c4..5ece7c0c0 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1036,6 +1036,7 @@ bool HMTypeInferrence::type_contains_ivars(const ::HIR::TypeRef& ty, bool only_u return type_contains_ivars(ee, only_unbound); } TU_ARMA(Alias, ee) { + return false; } } ), diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index 52bc7ac95..8c1214048 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -905,12 +905,12 @@ namespace { { auto _ = m_resolve.set_item_generics(e.second.data.m_params); - const auto& vi = trait.m_values.at(e.first); - if(!vi.is_Function()) { + const auto v_it = trait.m_values.find(e.first); + if( v_it == trait.m_values.end() || !v_it->second.is_Function() ) { ERROR(sp, E0000, "Trait " << trait_path << " doesn't have a method named " << e.first); } auto& impl_fcn = e.second.data; - const auto& trait_fcn = vi.as_Function(); + const auto& trait_fcn = v_it->second.as_Function(); auto fcn_params = impl_fcn.m_params.make_nop_params(1); MonomorphStatePtr ms { &impl.m_type, &impl.m_trait_args, &fcn_params }; diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 4f42ad67c..8db0a28cd 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -2391,11 +2391,32 @@ bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty if( const auto* se = src_ty.data().opt_TraitObject() ) { // 1. Data trait must be the same - if( de->m_trait != se->m_trait ) + if( de->m_trait.m_path.m_path != se->m_trait.m_path.m_path ) { - return false; + // Ensure that `de->m_trait` is a parent of `se->m_trait` + const auto& trait = *se->m_trait.m_trait_ptr; + bool found = false; + for(const auto& pt : trait.m_all_parent_traits) { + if( pt.m_path.m_path == de->m_trait.m_path.m_path ) + { + auto p = MonomorphStatePtr(nullptr, &se->m_trait.m_path.m_params, nullptr).monomorph_genericpath(sp, pt.m_path); + if( p == de->m_trait.m_path ) { + found = true; + break; + } + } + } + if( !found ) { + DEBUG("Not a parent trait"); + return false; + } + } + else { + if( de->m_trait.m_path != se->m_trait.m_path ) { + DEBUG("Mismatched data trait params"); + return false; + } } - // 2. Destination markers must be a strict subset for(const auto& mt : de->m_markers) { diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 63089c595..502f428cc 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -754,10 +754,24 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& 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( src_ty.data().is_TraitObject() ) + if( const auto* se = src_ty.data().opt_TraitObject() ) { out_src_is_dst = true; - out_meta_val = mutator.in_temporary( out_meta_ty.clone(), ::MIR::RValue::make_DstMeta({ ptr_value.clone() }) ); + 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() }) ); + } } else { diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 7ef37038e..fb2ba139a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1609,6 +1609,7 @@ namespace { } } TU_ARMA(TraitObject, e) { + // NOTE: This pattern (an empty ItemAddr) is detected by cleanup, which populates the vtable properly m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), ::MIR::Constant::make_ItemAddr({}) }) ); } } diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index 178f1bfae..d0a3eb1ab 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -591,41 +591,43 @@ void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list) fcn_p.m_data.as_UfcsKnown().item = ent.fcn_name; fcn_p.m_data.as_UfcsKnown().trait.m_path = ent.trait_path->clone(); - ::std::vector arg_tys; - for(const auto& ty : te->m_arg_types) - arg_tys.push_back( ty.clone() ); - auto arg_ty = ::HIR::TypeRef(mv$(arg_tys)); + auto* e = trans_list.add_function(mv$(fcn_p)); + if( e ) { + ::std::vector arg_tys; + for(const auto& ty : te->m_arg_types) + arg_tys.push_back( ty.clone() ); + auto arg_ty = ::HIR::TypeRef(mv$(arg_tys)); - HIR::Function fcn; - fcn.m_return = te->m_rettype.clone(); - fcn.m_args.push_back(std::make_pair( HIR::Pattern(), !is_by_value ? HIR::TypeRef::new_borrow(ent.bt, type.clone()) : type.clone() )); - fcn.m_args.push_back(std::make_pair( HIR::Pattern(), mv$(arg_ty) )); + HIR::Function fcn; + fcn.m_return = te->m_rettype.clone(); + fcn.m_args.push_back(std::make_pair( HIR::Pattern(), !is_by_value ? HIR::TypeRef::new_borrow(ent.bt, type.clone()) : type.clone() )); + fcn.m_args.push_back(std::make_pair( HIR::Pattern(), mv$(arg_ty) )); - fcn.m_code.m_mir = MIR::FunctionPointer(new MIR::Function()); - Builder builder(state, *fcn.m_code.m_mir); + fcn.m_code.m_mir = MIR::FunctionPointer(new MIR::Function()); + Builder builder(state, *fcn.m_code.m_mir); - std::vector arg_params; - for(size_t i = 0; i < te->m_arg_types.size(); i ++) - { - arg_params.push_back(MIR::LValue::new_Field(MIR::LValue::new_Argument(1), i)); + std::vector arg_params; + for(size_t i = 0; i < te->m_arg_types.size(); i ++) + { + arg_params.push_back(MIR::LValue::new_Field(MIR::LValue::new_Argument(1), i)); + } + builder.terminate_Call(MIR::LValue::new_Return(), + !is_by_value ? MIR::LValue::new_Deref(MIR::LValue::new_Argument(0)) : MIR::LValue::new_Argument(0), + mv$(arg_params), + 1, 2 + ); + // BB1: Return + builder.ensure_open(); + builder.terminate_block(MIR::Terminator::make_Return({})); + // BB1: Diverge + builder.ensure_open(); + builder.terminate_block(MIR::Terminator::make_Diverge({})); + + MIR_Validate(state.resolve, HIR::ItemPath(path), *fcn.m_code.m_mir, fcn.m_args, fcn.m_return); + trans_list.m_auto_functions.push_back(box$(fcn)); + e->ptr = trans_list.m_auto_functions.back().get(); } - builder.terminate_Call(MIR::LValue::new_Return(), - !is_by_value ? MIR::LValue::new_Deref(MIR::LValue::new_Argument(0)) : MIR::LValue::new_Argument(0), - mv$(arg_params), - 1, 2 - ); - // BB1: Return - builder.ensure_open(); - builder.terminate_block(MIR::Terminator::make_Return({})); - // BB1: Diverge - builder.ensure_open(); - builder.terminate_block(MIR::Terminator::make_Diverge({})); - - MIR_Validate(state.resolve, HIR::ItemPath(path), *fcn.m_code.m_mir, fcn.m_args, fcn.m_return); - trans_list.m_auto_functions.push_back(box$(fcn)); - auto* e = trans_list.add_function(mv$(fcn_p)); - e->ptr = trans_list.m_auto_functions.back().get(); } } } @@ -650,18 +652,29 @@ void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list) const auto& vtable_ref = crate.get_struct_by_path(sp, vtable_sp); auto vtable_ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(mv$(vtable_sp), mv$(vtable_params)), &vtable_ref ); + // Ensure that the type is defined/populated + if( !std::any_of(trans_list.m_types.begin(), trans_list.m_types.end(), [&](const ::std::pair& v) { + return v.first == vtable_ty && v.second == false; + }) ) { + trans_list.m_types.push_back(std::make_pair( vtable_ty.clone(), false )); + } + + // 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); + // Create vtable contents auto monomorph_cb_trait = MonomorphStatePtr(&type, &trait_path.m_params, nullptr); - 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( (3+trait.m_value_indexes.size()) * ptr_bytes ); + 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); @@ -756,6 +769,19 @@ void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list) push_ptr(mv$(item_path)); } } + // Parent trait vtables + for(size_t i = 0; i < trait.m_all_parent_traits.size(); i ++) + { + const auto& pt = trait.m_all_parent_traits[i]; + const auto& fld = repr->fields.at(trait.m_vtable_parent_traits_start + i); + ASSERT_BUG(sp, fld.offset == ofs, ""); + if( !fld.ty.data().is_Tuple() ) + { + auto pt_mono = MonomorphStatePtr(nullptr, &trait_path.m_params, nullptr).monomorph_genericpath(sp, pt.m_path); + auto pt_vtable_path = ::HIR::Path(type.clone(), mv$(pt_mono), ent.first.m_data.as_UfcsKnown().item); + push_ptr( mv$(pt_vtable_path) ); + } + } assert(ofs == vtable_data.bytes.size()); vtable_static.m_value_generated = true; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index a159bc04c..04cd500ac 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1536,6 +1536,7 @@ void Trans_Enumerate_FillFrom_VTable(EnumState& state, ::HIR::Path vtable_path, 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); + ASSERT_BUG(sp, !type.data().is_TraitObject(), "Getting vtable for unsized type - " << vtable_path); auto monomorph_cb_trait = MonomorphStatePtr(&type, &trait_path.m_params, nullptr); for(const auto& m : tr.m_value_indexes) @@ -1545,6 +1546,18 @@ void Trans_Enumerate_FillFrom_VTable(EnumState& state, ::HIR::Path vtable_path, const auto& fcn = state.crate.get_trait_by_path(sp, gpath.m_path).m_values.at(m.first).as_Function(); Trans_Enumerate_FillFrom_PathMono(state, ::HIR::Path(type.clone(), mv$(gpath), m.first, fcn.m_params.make_empty_params(true))); } + for(const auto& pt_path : tr.m_all_parent_traits) + { + ASSERT_BUG(sp, pt_path.m_trait_ptr, "Unset trait pointer - " << pt_path); + const auto& pt = *pt_path.m_trait_ptr; + if( pt.m_vtable_path != HIR::SimplePath() ) + { + auto pt_mono = MonomorphStatePtr(nullptr, &trait_path.m_params, nullptr).monomorph_genericpath(sp, pt_path.m_path); + auto pt_vtable_path = ::HIR::Path(type.clone(), mv$(pt_mono), vtable_path.m_data.as_UfcsKnown().item); + state.rv.add_vtable( mv$(pt_vtable_path), {} ); + // No need to recurse. + } + } } void Trans_Enumerate_FillFrom_Literal(EnumState& state, const EncodedLiteral& lit, const Trans_Params& pp)