summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2018-12-30 14:51:21 +0800
committerJohn Hodge <tpg@ucc.asn.au>2018-12-30 14:51:21 +0800
commit852050a97d8304d30d1ea51b7acacf1ece387973 (patch)
treea21d04b3456569262938a7202468383d6ee790ca
parent823ad74acb87dced844acade9b7799e9793c59a4 (diff)
downloadmrust-852050a97d8304d30d1ea51b7acacf1ece387973.tar.gz
Auto Impls - Automatic delegating impl of Clone for tuples
-rw-r--r--src/trans/auto_impls.cpp60
-rw-r--r--src/trans/enumerate.cpp1
2 files changed, 60 insertions, 1 deletions
diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp
index ffd0d30a..418a338b 100644
--- a/src/trans/auto_impls.cpp
+++ b/src/trans/auto_impls.cpp
@@ -63,7 +63,65 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
}
else
{
- TODO(Span(), "auto Clone for " << ty << " - Not Copy");
+ const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone");
+ TU_MATCH_HDRA( (ty.m_data), {)
+ default:
+ TODO(sp, "auto Clone for " << ty << " - Not Copy");
+ TU_ARMA(Tuple, te) {
+ assert(te.size() > 0);
+
+ ::std::vector< ::MIR::Param> values;
+ // 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::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), values.size() });
+ if( state.resolve.type_is_copy(sp, subty) )
+ {
+ values.push_back( ::std::move(fld_lvalue) );
+ }
+ else
+ {
+ // Allocate to locals (one for the `&T`, the other for the cloned `T`)
+ auto borrow_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() );
+ mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone()));
+ auto res_lv = ::MIR::LValue::make_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({
+ mir_fcn.blocks.size() + 2, // return block (after the panic block below)
+ 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;
+ bb.terminator = ::MIR::Terminator::make_Diverge({});
+ mir_fcn.blocks.push_back(::std::move( panic_bb ));
+
+ // Save the output of the `clone` call
+ values.push_back( ::std::move(res_lv) );
+ }
+ }
+
+ // Construct the result tuple
+ ::MIR::BasicBlock bb;
+ bb.statements.push_back(::MIR::Statement::make_Assign({
+ ::MIR::LValue::make_Return({}),
+ ::MIR::RValue::make_Tuple({ mv$(values) })
+ }));
+ bb.terminator = ::MIR::Terminator::make_Return({});
+ mir_fcn.blocks.push_back(::std::move( bb ));
+ }
+ }
}
// Function
diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp
index 06ca92a3..bb6d6e6f 100644
--- a/src/trans/enumerate.cpp
+++ b/src/trans/enumerate.cpp
@@ -1393,6 +1393,7 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co
{
const auto& pe = path_mono.m_data.as_UfcsKnown();
ASSERT_BUG(sp, pe.item == "clone", "");
+ // TODO: If this is !Copy, then we need to ensure that the inner type's clone impls are also available
// Add this type to a list of types that will have the impl auto-generated
state.rv.auto_clone_impls.insert( pe.type->clone() );
}