summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2019-04-28 11:05:00 +0800
committerJohn Hodge <tpg@ucc.asn.au>2019-04-28 11:05:00 +0800
commit2aaec20f9f4f8fc002086cb1117126dd6ac53b22 (patch)
tree49fc8bb60c670f7e18db6674cc3d0d1e658e3e11 /src
parent9e5d8a66034e95217e00702647fdc6621862c9ae (diff)
downloadmrust-2aaec20f9f4f8fc002086cb1117126dd6ac53b22.tar.gz
MIR Gen - Support `match` in a `match` guard arm
Diffstat (limited to 'src')
-rw-r--r--src/mir/from_hir.hpp6
-rw-r--r--src/mir/mir.hpp3
-rw-r--r--src/mir/mir_builder.cpp51
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;