summaryrefslogtreecommitdiff
path: root/src/trans/auto_impls.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/trans/auto_impls.cpp')
-rw-r--r--src/trans/auto_impls.cpp248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp
new file mode 100644
index 00000000..71f95a26
--- /dev/null
+++ b/src/trans/auto_impls.cpp
@@ -0,0 +1,248 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * trans/auto_impls.cpp
+ * - Automatic trait/method impls
+ *
+ * Handles implementing Clone (when in 1.29 mode)
+ */
+#include "main_bindings.hpp"
+#include "trans_list.hpp"
+#include <hir/hir.hpp>
+#include <mir/mir.hpp>
+#include <hir_typeck/common.hpp> // monomorph
+#include <hir_typeck/static.hpp> // StaticTraitResolve
+#include <deque>
+#include <algorithm> // find_if
+
+namespace {
+ struct State
+ {
+ ::HIR::Crate& crate;
+ StaticTraitResolve resolve;
+ const TransList& trans_list;
+ ::std::deque<::HIR::TypeRef> todo_list;
+ ::std::set<::HIR::TypeRef> done_list;
+
+ ::HIR::SimplePath lang_Clone;
+
+ State(::HIR::Crate& crate, const TransList& trans_list):
+ crate(crate),
+ resolve( crate ),
+ trans_list(trans_list)
+ {
+ lang_Clone = crate.get_lang_item_path(Span(), "clone");
+ }
+
+ void enqueue_type(const ::HIR::TypeRef& ty) {
+ if( this->trans_list.auto_clone_impls.count(ty) == 0 && this->done_list.count(ty) == 0 ) {
+ this->done_list.insert( ty.clone() );
+ this->todo_list.push_back( ty.clone() );
+ }
+ }
+ };
+}
+
+namespace {
+ ::MIR::Param clone_field(const State& state, const Span& sp, ::MIR::Function& mir_fcn, const ::HIR::TypeRef& subty, ::MIR::LValue fld_lvalue)
+ {
+ if( state.resolve.type_is_copy(sp, subty) )
+ {
+ return ::std::move(fld_lvalue);
+ }
+ else
+ {
+ const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone");
+ // Allocate to locals (one for the `&T`, the other for the cloned `T`)
+ auto borrow_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
+ mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone()));
+ auto res_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
+ mir_fcn.locals.push_back(subty.clone());
+
+ // Call `<T as Clone>::clone`, passing a borrow of the field
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ borrow_lv.clone(),
+ ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Call({
+ static_cast<unsigned>(mir_fcn.blocks.size() + 2), // return block (after the panic block below)
+ static_cast<unsigned>(mir_fcn.blocks.size() + 1), // panic block (next block)
+ res_lv.clone(),
+ ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ),
+ ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) )
+ });
+ mir_fcn.blocks.push_back(::std::move( bb ));
+
+ // Stub panic handling (TODO: Make this iterate `values` and drop all of them)
+ ::MIR::BasicBlock panic_bb;
+ panic_bb.terminator = ::MIR::Terminator::make_Diverge({});
+ mir_fcn.blocks.push_back(::std::move( panic_bb ));
+
+ // Save the output of the `clone` call
+ return ::std::move(res_lv);
+ }
+ }
+}
+
+void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
+{
+ Span sp;
+ TRACE_FUNCTION_F(ty);
+
+ // Create MIR
+ ::MIR::Function mir_fcn;
+ if( state.resolve.type_is_copy(sp, ty) )
+ {
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Use( ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) ) )
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ else
+ {
+ TU_MATCH_HDRA( (ty.m_data), {)
+ default:
+ TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
+ TU_ARMA(Path, te) {
+ // closures are identified by the name starting with 'closure#'
+ if( TU_TEST1(te.path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) {
+ const auto& gp = te.path.m_data.as_Generic();
+ const auto& str = state.resolve.m_crate.get_struct_by_path(sp, gp.m_path);
+ Trans_Params p;
+ p.sp = sp;
+ p.pp_impl = gp.m_params.clone();
+ ::std::vector< ::MIR::Param> values; values.reserve( str.m_data.as_Tuple().size() );
+ for(const auto& fld : str.m_data.as_Tuple())
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(state.resolve, fld.ent)) : fld.ent;
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, ty_m, mv$(fld_lvalue)) );
+ }
+ // Construct the result value
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Struct({ gp.clone(), mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ else {
+ TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
+ }
+ }
+ TU_ARMA(Array, te) {
+ ASSERT_BUG(sp, te.size_val < 256, "TODO: Is more than 256 elements sane for auto-generated non-Copy Clone impl? " << ty);
+ ::std::vector< ::MIR::Param> values; values.reserve(te.size_val);
+ for(size_t i = 0; i < te.size_val; i ++)
+ {
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, *te.inner, mv$(fld_lvalue)) );
+ }
+ // Construct the result
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Array({ mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ TU_ARMA(Tuple, te) {
+ assert(te.size() > 0);
+
+ ::std::vector< ::MIR::Param> values; values.reserve(te.size());
+ // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone)
+ for(const auto& subty : te)
+ {
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
+ values.push_back( clone_field(state, sp, mir_fcn, subty, mv$(fld_lvalue)) );
+ }
+
+ // Construct the result tuple
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Tuple({ mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ }
+ }
+
+ // Function
+ ::HIR::Function fcn {
+ /*m_save_code=*/false,
+ ::HIR::Linkage {},
+ ::HIR::Function::Receiver::BorrowShared,
+ /*m_abi=*/ABI_RUST,
+ /*m_unsafe =*/false,
+ /*m_const=*/false,
+ ::HIR::GenericParams {},
+ /*m_args=*/::make_vec1(::std::make_pair(
+ ::HIR::Pattern( ::HIR::PatternBinding(false, ::HIR::PatternBinding::Type::Move, "self", 0), ::HIR::Pattern::Data::make_Any({}) ),
+ ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone())
+ )),
+ /*m_variadic=*/false,
+ /*m_return=*/ty.clone(),
+ ::HIR::ExprPtr {}
+ };
+ fcn.m_code.m_mir = ::MIR::FunctionPointer( new ::MIR::Function(mv$(mir_fcn)) );
+
+ // Impl
+ ::HIR::TraitImpl impl;
+ impl.m_type = mv$(ty);
+ impl.m_methods.insert(::std::make_pair( RcString::new_interned("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } ));
+
+ // Add impl to the crate
+ auto& list = state.crate.m_trait_impls[state.lang_Clone].get_list_for_type_mut(impl.m_type);
+ list.push_back( box$(impl) );
+}
+
+void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list)
+{
+ if( TARGETVER_1_19 )
+ return ;
+
+ State state { crate, trans_list };
+
+ // Generate for all
+ for(const auto& ty : trans_list.auto_clone_impls)
+ {
+ state.done_list.insert( ty.clone() );
+ Trans_AutoImpl_Clone(state, ty.clone());
+ }
+
+ while( !state.todo_list.empty() )
+ {
+ auto ty = ::std::move(state.todo_list.front());
+ state.todo_list.pop_back();
+
+ Trans_AutoImpl_Clone(state, mv$(ty));
+ }
+
+ auto impl_list_it = crate.m_trait_impls.find(state.lang_Clone);
+ for(const auto& ty : state.done_list)
+ {
+ assert(impl_list_it != crate.m_trait_impls.end());
+ // TODO: Find a way of turning a set into a vector so items can be erased.
+
+ auto p = ::HIR::Path(ty.clone(), ::HIR::GenericPath(state.lang_Clone), "clone");
+ //DEBUG("add_function(" << p << ")");
+ auto e = trans_list.add_function(::std::move(p));
+
+ const auto* impl_list = impl_list_it->second.get_list_for_type(ty);
+ ASSERT_BUG(Span(), impl_list, "No impl list of Clone for " << ty);
+ auto& impl = **::std::find_if( impl_list->begin(), impl_list->end(), [&](const auto& i){ return i->m_type == ty; });
+ assert( impl.m_methods.size() == 1 );
+ e->ptr = &impl.m_methods.begin()->second.data;
+ }
+}
+