diff options
author | John Hodge <tpg@ucc.asn.au> | 2019-04-28 11:05:00 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2019-04-28 11:05:00 +0800 |
commit | 2aaec20f9f4f8fc002086cb1117126dd6ac53b22 (patch) | |
tree | 49fc8bb60c670f7e18db6674cc3d0d1e658e3e11 /src/mir/mir_builder.cpp | |
parent | 9e5d8a66034e95217e00702647fdc6621862c9ae (diff) | |
download | mrust-2aaec20f9f4f8fc002086cb1117126dd6ac53b22.tar.gz |
MIR Gen - Support `match` in a `match` guard arm
Diffstat (limited to 'src/mir/mir_builder.cpp')
-rw-r--r-- | src/mir/mir_builder.cpp | 51 |
1 files changed, 45 insertions, 6 deletions
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; |