summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir/deserialise.cpp16
-rw-r--r--src/hir/hir.hpp2
-rw-r--r--src/hir/serialise.cpp16
-rw-r--r--src/hir_expand/vtable.cpp178
-rw-r--r--src/mir/cleanup.cpp122
-rw-r--r--src/mir/helpers.hpp2
6 files changed, 213 insertions, 123 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 45876d88..348b016c 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -60,6 +60,20 @@ namespace {
}
return rv;
}
+ template<typename V>
+ ::std::unordered_multimap< ::std::string,V> deserialise_strummap()
+ {
+ size_t n = m_in.read_count();
+ ::std::unordered_multimap< ::std::string, V> rv;
+ //rv.reserve(n);
+ for(size_t i = 0; i < n; i ++)
+ {
+ auto s = m_in.read_string();
+ DEBUG("- " << s);
+ rv.insert( ::std::make_pair( mv$(s), D<V>::des(*this) ) );
+ }
+ return rv;
+ }
template<typename T>
::std::vector<T> deserialise_vec()
@@ -871,7 +885,7 @@ namespace {
rv.m_is_marker = m_in.read_bool();
rv.m_types = deserialise_strumap< ::HIR::AssociatedType>();
rv.m_values = deserialise_strumap< ::HIR::TraitValueItem>();
- rv.m_value_indexes = deserialise_strumap< unsigned int>();
+ rv.m_value_indexes = deserialise_strummap< ::std::pair<unsigned int, ::HIR::GenericPath> >();
rv.m_type_indexes = deserialise_strumap< unsigned int>();
return rv;
}
diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp
index 20cac608..ac1748c0 100644
--- a/src/hir/hir.hpp
+++ b/src/hir/hir.hpp
@@ -248,7 +248,7 @@ struct Trait
::std::unordered_map< ::std::string, TraitValueItem > m_values;
// Indexes into the vtable for each present method and value
- ::std::unordered_map< ::std::string, unsigned int > m_value_indexes;
+ ::std::unordered_multimap< ::std::string, ::std::pair<unsigned int,::HIR::GenericPath> > m_value_indexes;
// Indexes in the vtable parameter list for each associated type
::std::unordered_map< ::std::string, unsigned int > m_type_indexes;
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index 33f8123f..35acaa93 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -40,6 +40,16 @@ namespace {
serialise(v.second);
}
}
+ template<typename V>
+ void serialise_strmap(const ::std::unordered_multimap< ::std::string,V>& map)
+ {
+ m_out.write_count(map.size());
+ for(const auto& v : map) {
+ DEBUG("- " << v.first);
+ m_out.write_string(v.first);
+ serialise(v.second);
+ }
+ }
template<typename T>
void serialise_vec(const ::std::vector<T>& vec)
{
@@ -62,6 +72,11 @@ namespace {
m_out.write_string(e.first);
serialise(e.second);
}
+ template<typename T>
+ void serialise(const ::std::pair<unsigned int, T>& e) {
+ m_out.write_count(e.first);
+ serialise(e.second);
+ }
void serialise_type(const ::HIR::TypeRef& ty)
{
@@ -150,6 +165,7 @@ namespace {
serialise_simplepath(path.m_path);
serialise_pathparams(path.m_params);
}
+ void serialise(const ::HIR::GenericPath& path) { serialise_genericpath(path); }
void serialise_traitpath(const ::HIR::TraitPath& path)
{
serialise_genericpath(path.m_path);
diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp
index ea578237..baf5a016 100644
--- a/src/hir_expand/vtable.cpp
+++ b/src/hir_expand/vtable.cpp
@@ -88,84 +88,113 @@ namespace {
visitor.add_types_from_trait(tr);
auto args = mv$(visitor.params);
- auto clone_cb = [&](const auto& t, auto& o) {
- if(t.m_data.is_Path() && t.m_data.as_Path().path.m_data.is_UfcsKnown()) {
- const auto& pe = t.m_data.as_Path().path.m_data.as_UfcsKnown();
- DEBUG("t=" << t);
- if( *pe.type == ::HIR::TypeRef("Self", 0xFFFF) /*&& pe.trait == trait_path*/ && tr.m_type_indexes.count(pe.item) ) {
- // Replace with a new type param, need to know the index of it
- o = ::HIR::TypeRef("a#"+pe.item, tr.m_type_indexes.at(pe.item));
- return true;
+ struct VtableConstruct {
+ const OuterVisitor* m_outer;
+ ::HIR::Trait* trait_ptr;
+ ::HIR::t_struct_fields fields;
+
+ bool add_ents_from_trait(const ::HIR::Trait& tr, const ::HIR::GenericPath& trait_path)
+ {
+ TRACE_FUNCTION_F(trait_path);
+ auto clone_cb = [&](const auto& t, auto& o) {
+ if(t.m_data.is_Path() && t.m_data.as_Path().path.m_data.is_UfcsKnown()) {
+ const auto& pe = t.m_data.as_Path().path.m_data.as_UfcsKnown();
+ DEBUG("t=" << t);
+ if( *pe.type == ::HIR::TypeRef("Self", 0xFFFF) /*&& pe.trait == trait_path*/ && tr.m_type_indexes.count(pe.item) ) {
+ // Replace with a new type param, need to know the index of it
+ o = ::HIR::TypeRef("a#"+pe.item, tr.m_type_indexes.at(pe.item));
+ return true;
+ }
+ }
+ return false;
+ };
+ auto clone_self_cb = [](const auto& t, auto&o) {
+ if( t == ::HIR::TypeRef("Self", 0xFFFF) ) {
+ o = ::HIR::TypeRef::new_unit();
+ return true;
+ }
+ return false;
+ };
+ for(auto& vi : tr.m_values)
+ {
+ TU_MATCHA( (vi.second), (ve),
+ (Function,
+ if( ve.m_receiver == ::HIR::Function::Receiver::Free ) {
+ DEBUG("- '" << vi.first << "' Skip free function"); // ?
+ continue ;
+ }
+ if( ::std::any_of(ve.m_params.m_bounds.begin(), ve.m_params.m_bounds.end(), [&](const auto& b){
+ return b.is_TraitBound()
+ && b.as_TraitBound().type == ::HIR::TypeRef("Self", 0xFFFF)
+ && b.as_TraitBound().trait.m_path.m_path == m_outer->m_lang_Sized;
+ }) )
+ {
+ DEBUG("- '" << vi.first << "' Skip where `Self: Sized`");
+ continue ;
+ }
+ if( ve.m_params.m_types.size() > 0 ) {
+ DEBUG("- '" << vi.first << "' NOT object safe (generic), not creating vtable");
+ return false;
+ }
+
+ ::HIR::FunctionType ft;
+ ft.is_unsafe = ve.m_unsafe;
+ ft.m_abi = ve.m_abi;
+ ft.m_rettype = box$( clone_ty_with(sp, ve.m_return, clone_cb) );
+ ft.m_arg_types.reserve( ve.m_args.size() );
+ ft.m_arg_types.push_back( clone_ty_with(sp, ve.m_args[0].second, clone_self_cb) );
+ for(unsigned int i = 1; i < ve.m_args.size(); i ++)
+ ft.m_arg_types.push_back( clone_ty_with(sp, ve.m_args[i].second, clone_cb) );
+ // Clear the first argument (the receiver)
+ ::HIR::TypeRef fcn_type( mv$(ft) );
+
+ // Detect use of `Self` and don't create the vtable if there is.
+ if( visit_ty_with(fcn_type, [&](const auto& t){ return (t == ::HIR::TypeRef("Self", 0xFFFF)); }) )
+ {
+ DEBUG("- '" << vi.first << "' NOT object safe (Self), not creating vtable - " << fcn_type);
+ return false;
+ }
+
+ trait_ptr->m_value_indexes.insert( ::std::make_pair(
+ vi.first,
+ ::std::make_pair(fields.size(), trait_path.clone())
+ ) );
+ DEBUG("- '" << vi.first << "' is @" << fields.size());
+ fields.push_back( ::std::make_pair(
+ vi.first,
+ ::HIR::VisEnt< ::HIR::TypeRef> { true, mv$(fcn_type) }
+ ) );
+ ),
+ (Static,
+ if( vi.first != "#vtable" )
+ {
+ TODO(Span(), "Associated static in vtable");
+ }
+ ),
+ (Constant,
+ //TODO(Span(), "Associated const in vtable");
+ )
+ )
}
- }
- return false;
- };
- auto clone_self_cb = [](const auto& t, auto&o) {
- if( t == ::HIR::TypeRef("Self", 0xFFFF) ) {
- o = ::HIR::TypeRef::new_unit();
+ for(const auto& st : tr.m_parent_traits) {
+ ::HIR::TypeRef self("Self", 0xFFFF);
+ auto st_gp = monomorphise_genericpath_with(sp, st.m_path, monomorphise_type_get_cb(sp, &self, &trait_path.m_params, nullptr), false);
+ // NOTE: Doesn't trigger non-object-safe
+ add_ents_from_trait(*st.m_trait_ptr, st_gp);
+ }
+ // TODO: Iterate supertraits from bounds too
return true;
}
- return false;
- };
+ };
- ::HIR::t_struct_fields fields;
- for(auto& vi : tr.m_values)
+ VtableConstruct vtc { this, &tr, {} };
+ if( ! vtc.add_ents_from_trait(tr, trait_path) )
{
- TU_MATCHA( (vi.second), (ve),
- (Function,
- if( ve.m_receiver == ::HIR::Function::Receiver::Free ) {
- DEBUG("- '" << vi.first << "' Skip free function"); // ?
- continue ;
- }
- if( ::std::any_of(ve.m_params.m_bounds.begin(), ve.m_params.m_bounds.end(), [&](const auto& b){
- return b.is_TraitBound() && b.as_TraitBound().type == ::HIR::TypeRef("Self", 0xFFFF) && b.as_TraitBound().trait.m_path.m_path == m_lang_Sized;
- }) )
- {
- DEBUG("- '" << vi.first << "' Skip where `Self: Sized`");
- continue ;
- }
- if( ve.m_params.m_types.size() > 0 ) {
- DEBUG("- '" << vi.first << "' NOT object safe (generic), not creating vtable");
- tr.m_value_indexes.clear();
- tr.m_type_indexes.clear();
- return ;
- }
-
- ::HIR::FunctionType ft;
- ft.is_unsafe = ve.m_unsafe;
- ft.m_abi = ve.m_abi;
- ft.m_rettype = box$( clone_ty_with(sp, ve.m_return, clone_cb) );
- ft.m_arg_types.reserve( ve.m_args.size() );
- ft.m_arg_types.push_back( clone_ty_with(sp, ve.m_args[0].second, clone_self_cb) );
- for(unsigned int i = 1; i < ve.m_args.size(); i ++)
- ft.m_arg_types.push_back( clone_ty_with(sp, ve.m_args[i].second, clone_cb) );
- // Clear the first argument (the receiver)
- ::HIR::TypeRef fcn_type( mv$(ft) );
-
- // Detect use of `Self` and don't create the vtable if there is.
- if( visit_ty_with(fcn_type, [&](const auto& t){ return (t == ::HIR::TypeRef("Self", 0xFFFF)); }) )
- {
- DEBUG("- '" << vi.first << "' NOT object safe (Self), not creating vtable - " << fcn_type);
- tr.m_value_indexes.clear();
- tr.m_type_indexes.clear();
- return ;
- }
-
- tr.m_value_indexes[vi.first] = fields.size();
- DEBUG("- '" << vi.first << "' is @" << fields.size());
- fields.push_back( ::std::make_pair(
- vi.first,
- ::HIR::VisEnt< ::HIR::TypeRef> { true, mv$(fcn_type) }
- ) );
- ),
- (Static,
- TODO(Span(), "Associated static in vtable");
- ),
- (Constant,
- //TODO(Span(), "Associated const in vtable");
- )
- )
+ tr.m_value_indexes.clear();
+ tr.m_type_indexes.clear();
+ return ;
}
+ auto fields = mv$(vtc.fields);
::HIR::PathParams params;
{
@@ -207,6 +236,7 @@ namespace {
const auto& tr = m_crate.get_trait_by_path(sp, trait_path);
if(tr.m_value_indexes.size() > 0)
{
+ auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &impl.m_type, &impl.m_trait_args, nullptr);
auto trait_gpath = ::HIR::GenericPath(trait_path, impl.m_trait_args.clone());
::std::vector< ::HIR::Literal> vals;
@@ -214,7 +244,9 @@ namespace {
for(const auto& m : tr.m_value_indexes)
{
//ASSERT_BUG(sp, tr.m_values.at(m.first).is_Function(), "TODO: Handle generating vtables with non-function items");
- vals.at(m.second) = ::HIR::Literal::make_BorrowOf( ::HIR::Path(impl.m_type.clone(), trait_gpath.clone(), m.first) );
+ DEBUG("- " << m.second.first << " = " << m.second.second << " :: " << m.first);
+ auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false);
+ vals.at(m.second.first) = ::HIR::Literal::make_BorrowOf( ::HIR::Path(impl.m_type.clone(), mv$(gpath), m.first) );
}
auto vtable_sp = trait_path;
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp
index bcbeb167..a0d9e0fb 100644
--- a/src/mir/cleanup.cpp
+++ b/src/mir/cleanup.cpp
@@ -35,6 +35,71 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR
return nullptr;
}
+::MIR::Terminator MIR_Cleanup_Virtualize(
+ const Span& sp, const ::MIR::TypeResolve& state, ::MIR::Function& fcn,
+ ::MIR::BasicBlock& block, ::MIR::Terminator::Data_CallPath& e,
+ const ::HIR::TypeRef::Data::Data_TraitObject& te, const ::HIR::Path::Data::Data_UfcsKnown& pe
+ )
+{
+ assert( te.m_trait.m_trait_ptr );
+ const auto& trait = *te.m_trait.m_trait_ptr;
+
+ // 1. Get the vtable index for this function
+ auto it = trait.m_value_indexes.find( pe.item );
+ while( it != trait.m_value_indexes.end() )
+ {
+ DEBUG("- " << it->second.second);
+ if( it->second.second.m_path == pe.trait.m_path )
+ {
+ // TODO: Match generics using match_test_generics comparing to the trait args
+ break ;
+ }
+ ++ it;
+ }
+ if( it == trait.m_value_indexes.end() || it->first != pe.item )
+ BUG(sp, "Calling method '" << pe.item << "' from " << pe.trait << " through " << te.m_trait.m_path << " which isn't in the vtable");
+ unsigned int vtable_idx = it->second.first;
+
+ // 2. Load from the vtable
+ auto vtable_ty_spath = pe.trait.m_path;
+ vtable_ty_spath.m_components.back() += "#vtable";
+ const auto& vtable_ref = state.m_resolve.m_crate.get_struct_by_path(sp, vtable_ty_spath);
+ // Copy the param set from the trait in the trait object
+ ::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone();
+ // - Include associated types on bound
+ for(const auto& ty_b : te.m_trait.m_type_bounds) {
+ auto idx = trait.m_type_indexes.at(ty_b.first);
+ if(vtable_params.m_types.size() <= idx)
+ vtable_params.m_types.resize(idx+1);
+ vtable_params.m_types[idx] = ty_b.second.clone();
+ }
+ auto vtable_ty = ::HIR::TypeRef::new_pointer(
+ ::HIR::BorrowType::Shared,
+ ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref )
+ );
+
+ // Allocate a temporary for the vtable pointer itself
+ auto vtable_lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(fcn.temporaries.size()) });
+ fcn.temporaries.push_back( mv$(vtable_ty) );
+ // - Load the vtable and store it
+ auto vtable_rval = ::MIR::RValue::make_DstMeta({ ::MIR::LValue::make_Deref({ box$(e.args.front().clone()) }) });
+ block.statements.push_back( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) );
+
+ auto ptr_rval = ::MIR::RValue::make_DstPtr({ ::MIR::LValue::make_Deref({ box$(e.args.front().clone()) }) });
+ auto ptr_lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(fcn.temporaries.size()) });
+ fcn.temporaries.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()) );
+ block.statements.push_back( ::MIR::Statement::make_Assign({ ptr_lv.clone(), mv$(ptr_rval) }) );
+ e.args.front() = mv$(ptr_lv);
+
+ // Update the terminator with the new information.
+ auto vtable_fcn = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx });
+ return ::MIR::Terminator::make_CallValue({
+ e.ret_block, e.panic_block,
+ mv$(e.ret_val), mv$(vtable_fcn),
+ mv$(e.args)
+ });
+}
+
void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type)
{
Span sp;
@@ -142,55 +207,16 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
const auto& pe = e.fcn_path.m_data.as_UfcsKnown();
const auto& te = pe.type->m_data.as_TraitObject();
// TODO: What if the method is from a supertrait?
- if( pe.trait == te.m_trait.m_path )
+
+ if( te.m_trait.m_path == pe.trait || resolve.find_named_trait_in_trait(
+ sp, pe.trait.m_path, pe.trait.m_params,
+ *te.m_trait.m_trait_ptr, te.m_trait.m_path.m_path, te.m_trait.m_path.m_params,
+ *pe.type,
+ [](const auto&, auto){}
+ )
+ )
{
- assert( te.m_trait.m_trait_ptr );
- const auto& trait = *te.m_trait.m_trait_ptr;
-
- // 1. Get the vtable index for this function
- if( trait.m_value_indexes.count(pe.item) == 0 )
- BUG(sp, "Calling method '" << pe.item << "' of " << pe.trait << " which isn't in the vtable");
- unsigned int vtable_idx = trait.m_value_indexes.at( pe.item );
-
- // 2. Load from the vtable
- auto vtable_ty_spath = pe.trait.m_path;
- vtable_ty_spath.m_components.back() += "#vtable";
- const auto& vtable_ref = resolve.m_crate.get_struct_by_path(sp, vtable_ty_spath);
- // Copy the param set from the trait in the trait object
- ::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone();
- // - Include associated types on bound
- for(const auto& ty_b : te.m_trait.m_type_bounds) {
- auto idx = trait.m_type_indexes.at(ty_b.first);
- if(vtable_params.m_types.size() <= idx)
- vtable_params.m_types.resize(idx+1);
- vtable_params.m_types[idx] = ty_b.second.clone();
- }
- auto vtable_ty = ::HIR::TypeRef::new_pointer(
- ::HIR::BorrowType::Shared,
- ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref )
- );
-
- // Allocate a temporary for the vtable pointer itself
- auto vtable_lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(fcn.temporaries.size()) });
- fcn.temporaries.push_back( mv$(vtable_ty) );
- // - Load the vtable and store it
- auto vtable_rval = ::MIR::RValue::make_DstMeta({ ::MIR::LValue::make_Deref({ box$(e.args.front().clone()) }) });
- block.statements.push_back( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) );
-
- auto ptr_rval = ::MIR::RValue::make_DstPtr({ ::MIR::LValue::make_Deref({ box$(e.args.front().clone()) }) });
- auto ptr_lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(fcn.temporaries.size()) });
- fcn.temporaries.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()) );
- block.statements.push_back( ::MIR::Statement::make_Assign({ ptr_lv.clone(), mv$(ptr_rval) }) );
- e.args.front() = mv$(ptr_lv);
-
- // Update the terminator with the new information.
- auto vtable_fcn = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx });
- auto new_term = ::MIR::Terminator::make_CallValue({
- e.ret_block, e.panic_block,
- mv$(e.ret_val), mv$(vtable_fcn),
- mv$(e.args)
- });
-
+ auto new_term = MIR_Cleanup_Virtualize(sp, state, fcn, block, e, te, pe);
block.terminator = mv$(new_term);
}
}
diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp
index 60deccad..2a4f81d5 100644
--- a/src/mir/helpers.hpp
+++ b/src/mir/helpers.hpp
@@ -39,8 +39,10 @@ private:
const unsigned int STMT_TERM = ~0u;
const Span& sp;
+public:
const ::StaticTraitResolve& m_resolve;
const ::HIR::Crate& m_crate;
+private:
::FmtLambda m_path;
const ::HIR::TypeRef& m_ret_type;
const args_t& m_args;