diff options
-rw-r--r-- | src/mir/from_hir.hpp | 6 | ||||
-rw-r--r-- | src/mir/mir.hpp | 3 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 51 |
3 files changed, 51 insertions, 9 deletions
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 0dcbd65b..194fd0e0 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -70,8 +70,8 @@ TAGGED_UNION_EX(VarState, (), Invalid, ( (), (), ( VarState clone() const; - bool operator==(VarState& x) const; - bool operator!=(VarState& x) const { return !(*this == x); } + bool operator==(const VarState& x) const; + bool operator!=(const VarState& x) const { return !(*this == x); } ) ); extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x); @@ -110,7 +110,7 @@ TAGGED_UNION(ScopeType, Owning, }), // State which should end up with no mutation of variable states (Freeze, struct { - //::std::map<unsigned int,VarState> changed_slots; + ::std::map<unsigned int,VarState> changed_slots; //::std::map<unsigned int,VarState> changed_args; }) ); diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 6969225d..7100d4aa 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -159,6 +159,9 @@ TAGGED_UNION_EX(Constant, (), Int, ( }), (Bytes, ::std::vector< ::std::uint8_t>), // Byte string (StaticString, ::std::string), // String + // TODO: Should these ::HIR::Path structures be behind pointers? + // - HIR::Path is ~11 words long, without it MIR::Constant is 4 instead of 12 + // - MIR::Param is quite common, potential large space saving. (Const, struct { ::HIR::Path p; }), // `const` (ItemAddr, ::HIR::Path) // address of a value ), (), (), ( diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 81816535..8d534314 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -1554,7 +1554,6 @@ void MirBuilder::complete_scope(ScopeDef& sd) (Split, ), (Freeze, - //DEBUG("Freeze"); ) ) @@ -1607,6 +1606,28 @@ void MirBuilder::complete_scope(ScopeDef& sd) ASSERT_BUG(sd.span, e.end_state_valid, ""); H::apply_end_state(sd.span, *this, e.end_state); } + else if( const auto* e = sd.data.opt_Freeze() ) + { + TRACE_FUNCTION_F("Freeze"); + for(auto& ent : e->changed_slots) + { + auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local); + auto lv = ::MIR::LValue::make_Local(ent.first); + DEBUG(lv << " " << vs << " => " << ent.second); + if( vs != ent.second ) + { + if( vs.is_Valid() ) { + ERROR(sd.span, E0000, "Value went from " << vs << " => " << ent.second << " over freeze"); + } + else if( !this->lvalue_is_copy(sd.span, lv) ) { + ERROR(sd.span, E0000, "Non-Copy value went from " << vs << " => " << ent.second << " over freeze"); + } + else { + // It's a Copy value, and it wasn't originally fully Valid - allowable + } + } + } + } } void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const @@ -1919,20 +1940,38 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT } } } - else if( scope_def.data.is_Freeze() ) + // Freeze is used for `match` guards + // - These are only allowed to modify the (known `bool`) condition variable + // TODO: Some guards have more complex pieces of code, with self-contained scopes, allowable? + // - Those should already have defined their own scope? + // - OR, allow mutations here but ONLY if it's of a Copy type, and force it uninit at the end of the scope + else if( auto* e = scope_def.data.opt_Freeze() ) { + // If modified variable is the guard's result variable, allow it. + if( type != SlotType::Local ) { + DEBUG("Mutating state of arg" << idx); + ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed"); + } if( type == SlotType::Local && idx == m_if_cond_lval.as_Local() ) { + // The guard condition variable is allowed to be mutated, and falls through to the upper scope } else { - // NOTE: This is only used in match conditions - DEBUG("Mutating state of ?" << idx); - ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed"); + DEBUG("Mutating state of local" << idx); + auto& states = e->changed_slots; + if( states.count(idx) == 0 ) + { + auto state = get_slot_state(sp, idx, type).clone(); + states.insert(::std::make_pair( idx, mv$(state) )); + } + ret = &states[idx]; + break; // Stop searching } } else { + // Unknown scope type? } } if( ret ) @@ -2259,7 +2298,7 @@ VarState VarState::clone() const ) throw ""; } -bool VarState::operator==(VarState& x) const +bool VarState::operator==(const VarState& x) const { if( this->tag() != x.tag() ) return false; |