diff options
Diffstat (limited to 'src/mir/mir_builder.cpp')
-rw-r--r-- | src/mir/mir_builder.cpp | 656 |
1 files changed, 347 insertions, 309 deletions
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 530ee0e9..a3c74ea9 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -32,7 +32,9 @@ MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const m_scopes.push_back( ScopeDef { sp, ScopeType::make_Temporaries({}) } ); m_scope_stack.push_back( 1 ); - m_variable_states.resize( output.named_variables.size(), VarState::Uninit ); + m_variable_states.reserve( output.named_variables.size() ); + for(unsigned int i = 0; i < output.named_variables.size(); i ++ ) + m_variable_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); } MirBuilder::~MirBuilder() { @@ -103,7 +105,7 @@ void MirBuilder::define_variable(unsigned int idx) DEBUG("DEFINE tmp" << rv << ": " << ty); m_output.temporaries.push_back( ty.clone() ); - m_temporary_states.push_back( VarState::Uninit ); + m_temporary_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); assert(m_output.temporaries.size() == m_temporary_states.size()); ScopeDef* top_scope = nullptr; @@ -253,7 +255,7 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal mark_value_assigned(sp, dst); m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) ); } -void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val) +void MirBuilder::push_stmt_drop(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, ""); @@ -264,7 +266,10 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val) } DEBUG("DROP " << val); - m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val) }) ); + + auto stmt = ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val), flag }); + + m_output.blocks.at(m_current_block).statements.push_back( mv$(stmt) ); } void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val) { @@ -278,7 +283,7 @@ void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val) //} DEBUG("DROP shallow " << val); - m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val) }) ); + m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val), ~0u }) ); } void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data) { @@ -291,61 +296,60 @@ void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data) // 2. Push m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Asm( mv$(data) ) ); } +void MirBuilder::push_stmt_set_dropflag(const Span& sp, unsigned int idx, bool value) +{ + ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); + m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_SetDropFlag({ idx, value }) ); +} void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) { + VarState* state_p = nullptr; TU_MATCH_DEF(::MIR::LValue, (dst), (e), ( ), (Temporary, - switch(get_temp_state(sp, e.idx)) + state_p = &get_temp_state_mut(sp, e.idx); + if( const auto* se = state_p->opt_Invalid() ) { - case VarState::Uninit: - break; - case VarState::Dropped: - // ERROR? - break; - case VarState::Moved: - case VarState::MaybeMoved: - // ERROR? Temporaries shouldn't be resassigned after becoming valid - break; - case VarState::InnerMoved: - BUG(sp, "Reassigning inner-moved temporary - " << dst); - break; - case VarState::Init: - // ERROR. Temporaries are single-assignment - break; + if( *se != InvalidType::Uninit ) { + BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); + } + } + else { + // TODO: This should be a bug, but some of the match code ends up reassigning so.. + //BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); } - set_temp_state(sp, e.idx, VarState::Init); ), (Return, // Don't drop. - //m_return_valid = true; + // No state tracking for the return value ), (Variable, // TODO: Ensure that slot is mutable (information is lost, assume true) - switch( get_variable_state(sp, e) ) - { - case VarState::Uninit: - case VarState::Moved: - break; - case VarState::Dropped: - // TODO: Is this an error? The variable has descoped. - break; - case VarState::Init: - // Drop (if not Copy) - Copy check is done within push_stmt_drop + state_p = &get_variable_state_mut(sp, e); + ) + ) + + if( state_p ) + { + TU_MATCHA( (*state_p), (se), + (Invalid, + ASSERT_BUG(sp, se != InvalidType::Descoped, "Assining of descoped variable - " << dst); + ), + (Valid, push_stmt_drop( sp, dst.clone() ); - break; - case VarState::InnerMoved: + ), + (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() ); - break; - case VarState::MaybeMoved: - // TODO: Conditional drop - break; - } - set_variable_state(sp, e, VarState::Init); + ) ) - ) + *state_p = VarState::make_Valid({}); + } } void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope) @@ -552,6 +556,25 @@ void MirBuilder::end_block(::MIR::Terminator term) return rv; } + +unsigned int MirBuilder::new_drop_flag(bool default_state) +{ + auto rv = m_output.drop_flags.size(); + m_output.drop_flags.push_back(default_state); + DEBUG("(" << default_state << ") = " << rv); + return rv; +} +unsigned int MirBuilder::new_drop_flag_and_set(const Span& sp, bool set_state) +{ + auto rv = new_drop_flag(!set_state); + push_stmt_set_dropflag(sp, rv, set_state); + return rv; +} +bool MirBuilder::get_drop_flag_default(const Span& sp, unsigned int idx) +{ + return m_output.drop_flags.at(idx); +} + ScopeHandle MirBuilder::new_scope_var(const Span& sp) { unsigned int idx = m_scopes.size(); @@ -638,11 +661,11 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, SplitArm sa; for(const auto& i : e.changed_vars) { - sa.var_states.insert( ::std::make_pair(i, get_variable_state(sp, i)) ); + sa.var_states.insert( ::std::make_pair(i, get_variable_state(sp, i).clone()) ); } for(const auto& i : e.changed_tmps) { - sa.tmp_states.insert( ::std::make_pair(i, get_temp_state(sp, i)) ); + sa.tmp_states.insert( ::std::make_pair(i, get_temp_state(sp, i).clone()) ); } e.exit_states.push_back( mv$(sa) ); } @@ -671,6 +694,98 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, } } } + +namespace +{ + static void merge_state(const Span& sp, MirBuilder& builder, const ::MIR::LValue& lv, VarState& old_state, const VarState& new_state) + { + DEBUG(lv << " : " << old_state << " <= " << new_state); + switch(old_state.tag()) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + switch( new_state.tag() ) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + // Invalid->Invalid :: Choose the highest of the invalid types (TODO) + return ; + case VarState::TAG_Valid: + // Allocate a drop flag + old_state = VarState::make_Optional( builder.new_drop_flag_and_set(sp, true) ); + return ; + case VarState::TAG_Optional: + // Was invalid, now optional. + if( builder.get_drop_flag_default( sp, new_state.as_Optional() ) != false ) { + TODO(sp, "Drop flag default not false when going Invalid->Optional"); + } + old_state = VarState::make_Optional( new_state.as_Optional() ); + return ; + case VarState::TAG_Partial: + TODO(sp, "Handle Invalid->Partial in split scope"); + } + break; + case VarState::TAG_Valid: + switch( new_state.tag() ) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + old_state = VarState::make_Optional( builder.new_drop_flag_and_set(sp, false) ); + return ; + case VarState::TAG_Valid: + return ; + case VarState::TAG_Optional: + // Was valid, now optional. + if( builder.get_drop_flag_default( sp, new_state.as_Optional() ) != true ) { + TODO(sp, "Drop flag default not true when going Valid->Optional"); + } + old_state = VarState::make_Optional( new_state.as_Optional() ); + return ; + case VarState::TAG_Partial: + TODO(sp, "Handle Valid->Partial in split scope"); + } + break; + case VarState::TAG_Optional: + switch( new_state.tag() ) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + builder.push_stmt_set_dropflag(sp, old_state.as_Optional(), false); + return ; + case VarState::TAG_Valid: + builder.push_stmt_set_dropflag(sp, old_state.as_Optional(), true); + return ; + case VarState::TAG_Optional: + if( old_state.as_Optional() != new_state.as_Optional() ) { + TODO(sp, "Handle Optional->Optional with mismatched flags"); + } + return ; + case VarState::TAG_Partial: + TODO(sp, "Handle Optional->Partial in split scope"); + } + break; + case VarState::TAG_Partial: + // 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"); + case VarState::TAG_Valid: + TODO(sp, "Handle Partial->Valid in split scope"); + case VarState::TAG_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"); + } + break; + } + BUG(sp, "Unhandled combination - " << old_state.tag_str() << " and " << new_state.tag_str()); + } +} + void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable) { ASSERT_BUG(sp, handle.idx < m_scopes.size(), ""); @@ -680,27 +795,66 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r ASSERT_BUG(sp, !sd_split.arms.empty(), ""); TRACE_FUNCTION_F("end split scope " << handle.idx << " arm " << (sd_split.arms.size()-1)); + if( reachable ) + ASSERT_BUG(sp, m_block_active, "Block must be active when ending a reachable split arm"); - sd_split.arms.back().always_early_terminated = /*sd_split.arms.back().has_early_terminated &&*/ !reachable; + auto& this_arm_state = sd_split.arms.back(); + this_arm_state.always_early_terminated = /*sd_split.arms.back().has_early_terminated &&*/ !reachable; - // HACK: If this arm's end is reachable, convert InnerMoved (shallow drop) variable states to Moved - // - I'm not 100% sure this is the correct place for calling drop. - #if 1 - if( reachable ) + if( sd_split.end_state_valid ) { - for(auto& vse : sd_split.arms.back().var_states) + if( reachable ) { - //auto i = vse.first; - auto& vs = vse.second; - if( vs == VarState::InnerMoved ) { - // TODO: Refactor InnerMoved to handle partial moves via Box - // Emit the shallow drop - //push_stmt_drop_shallow( sp, ::MIR::LValue::make_Variable(i) ); - vs = VarState::Moved; + // Insert copies of the parent state + for(const auto& ent : this_arm_state.var_states) { + if( sd_split.end_state.var_states.count(ent.first) == 0 ) { + sd_split.end_state.var_states.insert(::std::make_pair( ent.first, get_variable_state(sp, ent.first, 1).clone() )); + } + } + for(const auto& ent : this_arm_state.tmp_states) { + if( sd_split.end_state.tmp_states.count(ent.first) == 0 ) { + sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, get_temp_state(sp, ent.first, 1).clone() )); + } + } + + // Merge state + for(auto& ent : sd_split.end_state.var_states) + { + auto idx = ent.first; + auto& out_state = ent.second; + + // Merge the states + auto it = this_arm_state.var_states.find(idx); + const auto& src_state = (it != this_arm_state.var_states.end() ? it->second : get_variable_state(sp, idx, 1)); + + merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), out_state, src_state); + } + for(auto& ent : sd_split.end_state.tmp_states) + { + auto idx = ent.first; + auto& out_state = ent.second; + + // Merge the states + auto it = this_arm_state.tmp_states.find(idx); + const auto& src_state = (it != this_arm_state.tmp_states.end() ? it->second : get_temp_state(sp, idx, 1)); + + merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), out_state, src_state); } } } - #endif + else + { + // Clone this arm's state + for(auto& ent : this_arm_state.var_states) + { + sd_split.end_state.var_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + } + for(auto& ent : this_arm_state.tmp_states) + { + sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + } + sd_split.end_state_valid = true; + } sd_split.arms.push_back( {} ); } @@ -725,112 +879,7 @@ void MirBuilder::end_split_arm_early(const Span& sp) auto& sd_split = sd.data.as_Split(); sd_split.arms.back().has_early_terminated = true; - for(const auto& vse : sd_split.arms.back().var_states) - { - auto i = vse.first; - const auto& vs = vse.second; - if( vs == VarState::InnerMoved ) { - // Emit the shallow drop - push_stmt_drop_shallow( sp, ::MIR::LValue::make_Variable(i) ); - // - Don't update the state, because this drop isn't the end-of-scope drop - } - } - } -} -namespace { - static VarState merge_state(const Span& sp, VarState new_state, VarState old_state) - { - switch(old_state) - { - case VarState::Uninit: - switch( new_state ) - { - case VarState::Uninit: - //BUG(sp, "Variable state changed from Uninit to Uninit (wut?)"); - return VarState::Uninit; - case VarState::Init: - // TODO: MaybeInit? - return VarState::MaybeMoved; - case VarState::MaybeMoved: - return VarState::MaybeMoved; - case VarState::Moved: - return VarState::Uninit; - case VarState::InnerMoved: - TODO(sp, "Handle InnerMoved in Split scope (wa Uninit)"); - break; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - break; - } - BUG(sp, "Override from Uninit to " << new_state); - break; - case VarState::Init: - switch( new_state ) - { - case VarState::Uninit: - // TODO: MaybeInit? - return VarState::MaybeMoved; - case VarState::Init: - return VarState::Init; - case VarState::MaybeMoved: - return VarState::MaybeMoved; - case VarState::Moved: - return VarState::MaybeMoved; - case VarState::InnerMoved: - TODO(sp, "Handle InnerMoved in Split scope (was Init)"); - break; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - break; - } - break; - case VarState::InnerMoved: - // 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 ) - { - case VarState::Uninit: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now Uninit"); - case VarState::Init: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now Init"); - case VarState::MaybeMoved: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now MaybeMoved"); - case VarState::Moved: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now Moved"); - case VarState::InnerMoved: - return VarState::InnerMoved; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - } - break; - case VarState::MaybeMoved: - // Already optional, don't change - return VarState::MaybeMoved; - case VarState::Moved: - switch( new_state ) - { - case VarState::Uninit: - return VarState::Moved; - case VarState::Init: - // Wut? Reinited? - return VarState::MaybeMoved; - case VarState::MaybeMoved: - return VarState::MaybeMoved; - case VarState::Moved: - return VarState::Moved; - case VarState::InnerMoved: - TODO(sp, "Handle InnerMoved in Split scope (was Moved)"); - break; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - break; - } - break; - case VarState::Dropped: - TODO(sp, "How can an arm drop a value?"); - break; - } - BUG(sp, "Unhandled combination"); + // TODO: Create drop flags if required? } } void MirBuilder::complete_scope(ScopeDef& sd) @@ -850,100 +899,31 @@ void MirBuilder::complete_scope(ScopeDef& sd) (Split, ) ) - - struct H - { - static void apply_split_arms(MirBuilder& self, const Span& sp, ::std::vector<SplitArm>& arms) - { - // 1. Make a bitmap of changed states in all arms - // 2. Build up the final composite state of the first arm - ::std::map<unsigned int, VarState> new_var_states; - ::std::map<unsigned int, VarState> new_tmp_states; - const SplitArm* first_arm = nullptr; - for(const auto& arm : arms) - { - if( arm.always_early_terminated ) - continue ; - for(const auto& vse : arm.var_states) - { - auto i = vse.first; - if( new_var_states.count(i) == 0 ) - new_var_states.insert( ::std::make_pair(i, vse.second) ); - } - for(const auto& vse : arm.tmp_states) - { - auto i = vse.first; - if( new_tmp_states.count(i) == 0 ) - new_tmp_states.insert( ::std::make_pair(i, vse.second) ); - } - if( !first_arm ) - first_arm = &arm; - } - - if( !first_arm ) - { - DEBUG("No arms yeilded"); - return ; - } - - // 3. Compare the rest of the arms - for(const auto& arm : arms) - { - if( arm.always_early_terminated ) - continue ; - DEBUG("><"); - for(auto& se : new_var_states) - { - auto i = se.first; - DEBUG("- VAR" << i); - auto new_state = (arm.var_states.count(i) != 0 ? arm.var_states.at(i) : self.get_variable_state(sp, i)); - se.second = merge_state(sp, new_state, se.second); - } - for(auto& se : new_tmp_states) - { - auto i = se.first; - DEBUG("- TMP" << i); - auto new_state = (arm.tmp_states.count(i) != 0 ? arm.tmp_states.at(i) : self.get_temp_state(sp, i)); - se.second = merge_state(sp, new_state, se.second); - } - } - - // 4. Apply changes - for(const auto& se : new_var_states) - { - auto i = se.first; - auto new_state = se.second; - DEBUG("var" << i << " old_state = " << self.get_variable_state(sp, i) << ", new_state = " << new_state); - self.set_variable_state(sp, i, new_state); - } - for(const auto& se : new_tmp_states) - { - auto i = se.first; - auto new_state = se.second; - DEBUG("tmp" << i << " old_state = " << self.get_temp_state(sp, i) << ", new_state = " << new_state); - self.set_temp_state(sp, i, new_state); - } - } - }; - // No macro for better debug output. if( sd.data.is_Loop() ) { + #if 0 auto& e = sd.data.as_Loop(); TRACE_FUNCTION_F("Loop - " << e.exit_states.size() << " breaks"); // Merge all exit states and apply to output H::apply_split_arms(*this, sd.span, e.exit_states); + #endif } else if( sd.data.is_Split() ) { auto& e = sd.data.as_Split(); - - assert( e.arms.size() > 1 ); TRACE_FUNCTION_F("Split - " << (e.arms.size() - 1) << " arms"); - e.arms.pop_back(); - H::apply_split_arms(*this, sd.span, e.arms); + ASSERT_BUG(sd.span, e.end_state_valid, ""); + for(auto& ent : e.end_state.var_states) + { + auto& vs = get_variable_state_mut(sd.span, ent.first); + if( vs != ent.second ) + { + vs = ::std::move(ent.second); + } + } } } @@ -1130,7 +1110,7 @@ bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const return rv == 2; } -VarState MirBuilder::get_variable_state(const Span& sp, unsigned int idx) const +const VarState& MirBuilder::get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count) const { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1150,7 +1130,10 @@ VarState MirBuilder::get_variable_state(const Span& sp, unsigned int idx) const auto it = cur_arm.var_states.find(idx); if( it != cur_arm.var_states.end() ) { - return it->second; + if( ! skip_count -- ) + { + return it->second; + } } ) ) @@ -1159,7 +1142,7 @@ VarState MirBuilder::get_variable_state(const Span& sp, unsigned int idx) const ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); return m_variable_states[idx]; } -void MirBuilder::set_variable_state(const Span& sp, unsigned int idx, VarState state) +VarState& MirBuilder::get_variable_state_mut(const Span& sp, unsigned int idx) { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1176,8 +1159,10 @@ void MirBuilder::set_variable_state(const Span& sp, unsigned int idx, VarState s { auto& e = scope_def.data.as_Split(); auto& cur_arm = e.arms.back(); - cur_arm.var_states[idx] = state; - return ; + auto it = cur_arm.var_states.find(idx); + if( it == cur_arm.var_states.end() ) + return cur_arm.var_states[idx] = get_variable_state(sp, idx).clone(); + return it->second; } else if( scope_def.data.is_Loop() ) { @@ -1190,9 +1175,9 @@ void MirBuilder::set_variable_state(const Span& sp, unsigned int idx, VarState s } ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); - m_variable_states[idx] = state; + return m_variable_states[idx]; } -VarState MirBuilder::get_temp_state(const Span& sp, unsigned int idx) const +const VarState& MirBuilder::get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count) const { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1212,7 +1197,10 @@ VarState MirBuilder::get_temp_state(const Span& sp, unsigned int idx) const auto it = cur_arm.tmp_states.find(idx); if( it != cur_arm.tmp_states.end() ) { - return it->second; + if( ! skip_count -- ) + { + return it->second; + } } } } @@ -1220,7 +1208,7 @@ VarState MirBuilder::get_temp_state(const Span& sp, unsigned int idx) const ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); return m_temporary_states[idx]; } -void MirBuilder::set_temp_state(const Span& sp, unsigned int idx, VarState state) +VarState& MirBuilder::get_temp_state_mut(const Span& sp, unsigned int idx) { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1237,8 +1225,10 @@ void MirBuilder::set_temp_state(const Span& sp, unsigned int idx, VarState state { auto& e = scope_def.data.as_Split(); auto& cur_arm = e.arms.back(); - cur_arm.tmp_states[idx] = state; - return ; + auto it = cur_arm.tmp_states.find(idx); + if(it == cur_arm.tmp_states.end()) + return cur_arm.tmp_states[idx] = get_temp_state(sp, idx).clone(); + return it->second; } else if( scope_def.data.is_Loop() ) { @@ -1251,7 +1241,7 @@ void MirBuilder::set_temp_state(const Span& sp, unsigned int idx, VarState state } ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); - m_temporary_states[idx] = state; + return m_temporary_states[idx]; } void MirBuilder::drop_scope_values(const ScopeDef& sd) @@ -1260,52 +1250,41 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd) (Temporaries, for(auto tmp_idx : ::reverse(e.temporaries)) { - switch( get_temp_state(sd.span, tmp_idx) ) - { - case VarState::Uninit: - DEBUG("Temporary " << tmp_idx << " Uninit"); - break; - case VarState::Dropped: - DEBUG("Temporary " << tmp_idx << " Dropped"); - break; - case VarState::Moved: - DEBUG("Temporary " << tmp_idx << " Moved"); - break; - case VarState::Init: + 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 }) ); - //set_temp_state(sd.span, tmp_idx, VarState::Dropped); - break; - case VarState::InnerMoved: + ), + (Partial, + // TODO: Actual destructuring push_stmt_drop_shallow( sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }) ); - //set_temp_state(sd.span, tmp_idx, VarState::Dropped); - break; - case VarState::MaybeMoved: - //BUG(sd.span, "Optionally moved temporary? - " << tmp_idx); - break; - } + ), + (Optional, + push_stmt_drop(sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }), vse); + ) + ) } ), (Variables, for(auto var_idx : ::reverse(e.vars)) { - switch( get_variable_state(sd.span, var_idx) ) - { - case VarState::Uninit: - case VarState::Dropped: - case VarState::Moved: - break; - case VarState::Init: + 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) ); - break; - case VarState::InnerMoved: + ), + (Partial, + // TODO: Actual destructuring push_stmt_drop_shallow( sd.span, ::MIR::LValue::make_Variable(var_idx) ); - //set_variable_state(sd.span, var_idx, VarState::Dropped); - break; - case VarState::MaybeMoved: - // TODO: Drop flags - //push_stmt_drop_opt(sd.span, ::MIR::LValue::make_Variable(var_idx), drop_flag_idx); - break; - } + ), + (Optional, + push_stmt_drop(sd.span, ::MIR::LValue::make_Variable(var_idx), vse); + ) + ) } ), (Split, @@ -1323,12 +1302,12 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv) TU_MATCHA( (lv), (e), (Variable, if( !lvalue_is_copy(sp, lv) ) { - set_variable_state(sp, e, VarState::Moved); + get_variable_state_mut(sp, e) = VarState::make_Invalid(InvalidType::Moved); } ), (Temporary, if( !lvalue_is_copy(sp, lv) ) { - set_temp_state(sp, e.idx, VarState::Moved); + get_temp_state_mut(sp, e.idx) = VarState::make_Invalid(InvalidType::Moved); } ), (Argument, @@ -1381,15 +1360,17 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv) ) ) // 2. Mark the slot as requiring only a shallow drop + ::std::vector<VarState> ivs; + ivs.push_back(VarState::make_Invalid(InvalidType::Moved)); TU_MATCH_DEF( ::MIR::LValue, (inner_lv), (ei), ( BUG(sp, "Box move out of invalid LValue " << inner_lv << " - should have been moved"); ), (Variable, - set_variable_state(sp, ei, VarState::InnerMoved); + get_variable_state_mut(sp, ei) = VarState::make_Partial(mv$(ivs)); ), (Temporary, - set_temp_state(sp, ei.idx, VarState::InnerMoved); + get_temp_state_mut(sp, ei.idx) = VarState::make_Partial(mv$(ivs)); ), (Argument, TODO(sp, "Mark arg " << ei.idx << " for shallow drop"); @@ -1449,18 +1430,75 @@ ScopeHandle::~ScopeHandle() } } -::std::ostream& operator<<(::std::ostream& os, VarState x) +VarState VarState::clone() const { - switch(x) - { - #define _(V) case VarState::V: os << #V; break; - _(Uninit) - _(Init) - _(MaybeMoved) - _(Moved) - _(InnerMoved) - _(Dropped) - #undef _ - } + TU_MATCHA( (*this), (e), + (Invalid, + return VarState(e); + ), + (Valid, + return VarState(e); + ), + (Optional, + return VarState(e); + ), + (Partial, + ::std::vector<VarState> n; + n.reserve(e.size()); + for(const auto& a : e) + n.push_back( a.clone() ); + return VarState(mv$(n)); + ) + ) + throw ""; +} +bool VarState::operator==(VarState& x) const +{ + if( this->tag() != x.tag() ) + return false; + TU_MATCHA( (*this, x), (te, xe), + (Invalid, + return te == xe; + ), + (Valid, + return true; + ), + (Optional, + return te == xe; + ), + (Partial, + if( te.size() != xe.size() ) + return false; + for(unsigned int i = 0; i < te.size(); i ++) + { + if( te[i] != xe[i] ) + return false; + } + return true; + ) + ) + throw ""; +} +::std::ostream& operator<<(::std::ostream& os, const VarState& x) +{ + TU_MATCHA( (x), (e), + (Invalid, + switch(e) + { + case InvalidType::Uninit: os << "Uninit"; break; + case InvalidType::Moved: os << "Moved"; break; + case InvalidType::Descoped: os << "Descoped"; break; + } + ), + (Valid, + os << "Valid"; + ), + (Optional, + os << "Optional(" << e << ")"; + ), + (Partial, + os << "Partial(" << e << ")"; + ) + ) return os; } |