summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mir/from_hir.hpp10
-rw-r--r--src/mir/mir_builder.cpp219
2 files changed, 156 insertions, 73 deletions
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index f4fa3074..c33ba274 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -49,7 +49,10 @@ TAGGED_UNION_EX(VarState, (), Invalid, (
// Currently invalid
(Invalid, InvalidType),
// Partially valid (Map of field states, Box is assumed to have one field)
- (Partial, ::std::vector<VarState>),
+ (Partial, struct {
+ ::std::vector<VarState> inner_states;
+ unsigned int outer_flag = ~0u; // If ~0u there's no condition on the outer
+ }),
// Optionally valid (integer indicates the drop flag index)
(Optional, unsigned int),
// Fully valid
@@ -145,8 +148,6 @@ public:
const ::HIR::Crate& crate() const { return m_resolve.m_crate; }
const StaticTraitResolve& resolve() const { return m_resolve; }
- //::HIR::TypeRef* is_type_owned_box(::HIR::TypeRef& ty) const {
- //}
/// Check if the passed type is Box<T> and returns a pointer to the T type if so, otherwise nullptr
const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const;
@@ -170,7 +171,7 @@ public:
// Push a drop (likely only used by scope cleanup)
void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u);
// Push a shallow drop (for Box)
- void push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val);
+ void push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u);
// Push an inline assembly statement (NOTE: inputs aren't marked as moved)
void push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data);
// Push a setting/clearing of a drop flag
@@ -224,6 +225,7 @@ private:
const VarState& get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const;
VarState& get_temp_state_mut(const Span& sp, unsigned int idx);
+ void drop_value_from_state(const Span& sp, const VarState& vs, ::MIR::LValue lv);
void drop_scope_values(const ScopeDef& sd);
void complete_scope(ScopeDef& sd);
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 4523288e..62f8e9c3 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -271,19 +271,15 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int
m_output.blocks.at(m_current_block).statements.push_back( mv$(stmt) );
}
-void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val)
+void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, "");
- // TODO: Ensure that the type is a Box
- //if( lvalue_is_copy(sp, val) ) {
- // // Don't emit a drop for Copy values
- // return ;
- //}
+ // TODO: Ensure that the type is a Box?
DEBUG("DROP shallow " << val);
- m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val), ~0u }) );
+ m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val), flag }) );
}
void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data)
{
@@ -338,21 +334,10 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
if( state_p )
{
- TU_MATCHA( (*state_p), (se),
- (Invalid,
+ TU_IFLET( VarState, (*state_p), Invalid, se,
ASSERT_BUG(sp, se != InvalidType::Descoped, "Assining of descoped variable - " << dst);
- ),
- (Valid,
- push_stmt_drop( sp, dst.clone() );
- ),
- (Optional,
- push_stmt_drop( sp, dst.clone(), se );
- ),
- (Partial,
- // TODO: Check type, if Box emit _shallow, otherwise destructure drop
- push_stmt_drop_shallow( sp, dst.clone() );
- )
)
+ drop_value_from_state(sp, *state_p, dst.clone());
*state_p = VarState::make_Valid({});
}
}
@@ -734,8 +719,33 @@ namespace
old_state = VarState::make_Optional( flag_idx );
return ;
}
- case VarState::TAG_Partial:
- TODO(sp, "Handle Invalid->Partial in split scope");
+ case VarState::TAG_Partial: {
+ const auto& nse = new_state.as_Partial();
+ bool is_box = false;
+ builder.with_val_type(sp, lv, [&](const auto& ty){ is_box = builder.is_type_owned_box(ty); });
+ if( is_box ) {
+ ASSERT_BUG(sp, nse.inner_states.size() == 1, "");
+ }
+ if( nse.outer_flag != ~0u ) {
+ // Set the outer flag to `true` if its default isn't true
+ if( builder.get_drop_flag_default(sp, nse.outer_flag) != false ) {
+ builder.push_stmt_set_dropflag_val(sp, nse.outer_flag, false);
+ }
+ }
+
+ auto out = new_state.clone();
+ auto& ose = out.as_Partial();
+ if( is_box ) {
+ merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), ose.inner_states[0], old_state);
+ }
+ else {
+ for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
+ {
+ merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], old_state);
+ }
+ }
+ old_state = mv$(out);
+ } return;
}
break;
case VarState::TAG_Valid:
@@ -773,8 +783,33 @@ namespace
}
return ;
}
- case VarState::TAG_Partial:
- TODO(sp, "Handle Valid->Partial in split scope");
+ case VarState::TAG_Partial: {
+ const auto& nse = new_state.as_Partial();
+ bool is_box = false;
+ builder.with_val_type(sp, lv, [&](const auto& ty){ is_box = builder.is_type_owned_box(ty); });
+ if( is_box ) {
+ ASSERT_BUG(sp, nse.inner_states.size() == 1, "");
+ }
+ if( nse.outer_flag != ~0u ) {
+ // Set the outer flag to `true` if its default isn't true
+ if( builder.get_drop_flag_default(sp, nse.outer_flag) != true ) {
+ builder.push_stmt_set_dropflag_val(sp, nse.outer_flag, true);
+ }
+ }
+
+ auto out = new_state.clone();
+ auto& ose = out.as_Partial();
+ if( is_box ) {
+ merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), ose.inner_states[0], old_state);
+ }
+ else {
+ for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
+ {
+ merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], old_state);
+ }
+ }
+ old_state = mv$(out);
+ } return;
}
break;
case VarState::TAG_Optional:
@@ -800,23 +835,66 @@ namespace
TODO(sp, "Handle Optional->Partial in split scope");
}
break;
- case VarState::TAG_Partial:
+ case VarState::TAG_Partial: {
+ auto& ose = old_state.as_Partial();
+ bool is_box = false;
+ builder.with_val_type(sp, lv, [&](const auto& ty){ is_box = builder.is_type_owned_box(ty); });
+ if( is_box ) {
+ ASSERT_BUG(sp, ose.inner_states.size() == 1, "");
+ }
// Need to tag for conditional shallow drop? Or just do that at the end of the split?
// - End of the split means that the only optional state is outer drop.
switch( new_state.tag() )
{
case VarState::TAGDEAD: throw "";
case VarState::TAG_Invalid:
- TODO(sp, "Handle Partial->Invalid in split scope");
+ if( ose.outer_flag != ~0u ) {
+ // Set the outer flag to `false` if its default isn't false
+ if( builder.get_drop_flag_default(sp, ose.outer_flag) != false ) {
+ builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, false);
+ }
+ }
+ if( 0 )
+ // - Fall through
case VarState::TAG_Valid:
- TODO(sp, "Handle Partial->Valid in split scope");
- case VarState::TAG_Optional:
+ if( ose.outer_flag != ~0u ) {
+ // Set the outer flag to `true` if its default isn't true
+ if( builder.get_drop_flag_default(sp, ose.outer_flag) != true ) {
+ builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, true);
+ }
+ }
+
+ if( is_box ) {
+ merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), ose.inner_states[0], new_state);
+ }
+ else {
+ for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
+ {
+ merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], new_state);
+ }
+ }
+ return ;
+ case VarState::TAG_Optional: {
+ //auto flag_idx = new_state.as_Optional();
TODO(sp, "Handle Partial->Optional in split scope");
- case VarState::TAG_Partial:
- ASSERT_BUG(sp, old_state.as_Partial().size() == new_state.as_Partial().size(), "Partial->Partial with mismatchd sizes");
- TODO(sp, "Handle Partial->Partial in split scope");
+ } return;
+ case VarState::TAG_Partial: {
+ const auto& nse = new_state.as_Partial();
+ ASSERT_BUG(sp, ose.inner_states.size() == nse.inner_states.size(), "Partial->Partial with mismatched sizes - " << old_state << " <= " << new_state);
+ ASSERT_BUG(sp, ose.outer_flag == nse.outer_flag, "Partial->Partial with mismatched drop flags - " << old_state << " <= " << new_state);
+ if( is_box ) {
+ ASSERT_BUG(sp, nse.inner_states.size() == 1, "");
+ merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), ose.inner_states[0], nse.inner_states[0]);
+ }
+ else {
+ for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
+ {
+ merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ }
+ }
+ } return ;
}
- break;
+ } break;
}
BUG(sp, "Unhandled combination - " << old_state.tag_str() << " and " << new_state.tag_str());
}
@@ -1290,6 +1368,27 @@ VarState& MirBuilder::get_temp_state_mut(const Span& sp, unsigned int idx)
return m_temporary_states[idx];
}
+void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR::LValue lv)
+{
+ TU_MATCHA( (vs), (vse),
+ (Invalid,
+ ),
+ (Valid,
+ push_stmt_drop(sp, mv$(lv));
+ ),
+ (Partial,
+ // TODO: Actual destructuring based on the type
+ with_val_type(sp, lv, [&](const auto& ty){ ASSERT_BUG(sp, this->is_type_owned_box(ty), "TODO: Partial on non-Box"); });
+ assert( vse.inner_states.size() == 1 );
+ drop_value_from_state(sp, vse.inner_states[0], ::MIR::LValue::make_Deref({ box$(lv.clone()) }));
+ push_stmt_drop_shallow(sp, mv$(lv), vse.outer_flag);
+ ),
+ (Optional,
+ push_stmt_drop(sp, mv$(lv), vse);
+ )
+ )
+}
+
void MirBuilder::drop_scope_values(const ScopeDef& sd)
{
TU_MATCHA( (sd.data), (e),
@@ -1297,40 +1396,14 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
for(auto tmp_idx : ::reverse(e.temporaries))
{
const auto& vs = get_temp_state(sd.span, tmp_idx);
- TU_MATCHA( (vs), (vse),
- (Invalid,
- ),
- (Valid,
- push_stmt_drop( sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }) );
- ),
- (Partial,
- // TODO: Actual destructuring
- push_stmt_drop_shallow( sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }) );
- ),
- (Optional,
- push_stmt_drop(sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }), vse);
- )
- )
+ drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Temporary({ tmp_idx }) );
}
),
(Variables,
for(auto var_idx : ::reverse(e.vars))
{
const auto& vs = get_variable_state(sd.span, var_idx);
- TU_MATCHA( (vs), (vse),
- (Invalid,
- ),
- (Valid,
- push_stmt_drop( sd.span, ::MIR::LValue::make_Variable(var_idx) );
- ),
- (Partial,
- // TODO: Actual destructuring
- push_stmt_drop_shallow( sd.span, ::MIR::LValue::make_Variable(var_idx) );
- ),
- (Optional,
- push_stmt_drop(sd.span, ::MIR::LValue::make_Variable(var_idx), vse);
- )
- )
+ drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Variable(var_idx) );
}
),
(Split,
@@ -1406,6 +1479,7 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv)
)
)
// 2. Mark the slot as requiring only a shallow drop
+ // - TODO: Have a drop flag attached to the
::std::vector<VarState> ivs;
ivs.push_back(VarState::make_Invalid(InvalidType::Moved));
TU_MATCH_DEF( ::MIR::LValue, (inner_lv), (ei),
@@ -1413,10 +1487,10 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv)
BUG(sp, "Box move out of invalid LValue " << inner_lv << " - should have been moved");
),
(Variable,
- get_variable_state_mut(sp, ei) = VarState::make_Partial(mv$(ivs));
+ get_variable_state_mut(sp, ei) = VarState::make_Partial({ mv$(ivs) });
),
(Temporary,
- get_temp_state_mut(sp, ei.idx) = VarState::make_Partial(mv$(ivs));
+ get_temp_state_mut(sp, ei.idx) = VarState::make_Partial({ mv$(ivs) });
),
(Argument,
TODO(sp, "Mark arg " << ei.idx << " for shallow drop");
@@ -1490,10 +1564,10 @@ VarState VarState::clone() const
),
(Partial,
::std::vector<VarState> n;
- n.reserve(e.size());
- for(const auto& a : e)
+ n.reserve(e.inner_states.size());
+ for(const auto& a : e.inner_states)
n.push_back( a.clone() );
- return VarState(mv$(n));
+ return VarState::make_Partial({ mv$(n), e.outer_flag });
)
)
throw "";
@@ -1513,11 +1587,13 @@ bool VarState::operator==(VarState& x) const
return te == xe;
),
(Partial,
- if( te.size() != xe.size() )
+ if( te.outer_flag != xe.outer_flag )
return false;
- for(unsigned int i = 0; i < te.size(); i ++)
+ if( te.inner_states.size() != xe.inner_states.size() )
+ return false;
+ for(unsigned int i = 0; i < te.inner_states.size(); i ++)
{
- if( te[i] != xe[i] )
+ if( te.inner_states[i] != xe.inner_states[i] )
return false;
}
return true;
@@ -1543,7 +1619,12 @@ bool VarState::operator==(VarState& x) const
os << "Optional(" << e << ")";
),
(Partial,
- os << "Partial(" << e << ")";
+ os << "Partial(";
+ if( e.outer_flag == ~0u )
+ os << "-";
+ else
+ os << "df" << e.outer_flag;
+ os << ", [" << e.inner_states << "])";
)
)
return os;