summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-08-12 15:31:23 +0800
committerJohn Hodge <tpg@mutabah.net>2016-08-12 15:31:23 +0800
commit1ef94e6f5e6255fad4c6b8e9a351aa1f51dd8b0d (patch)
tree8c967ed3e3f7b5701bda339e935138ca0dfe2cdc
parent2506581e333bb382ee9b6e90bf014ef4b0a2fab0 (diff)
downloadmrust-1ef94e6f5e6255fad4c6b8e9a351aa1f51dd8b0d.tar.gz
MIR Match - Shift branch generator cases into helpers
-rw-r--r--src/mir/from_hir_match.cpp206
1 files changed, 122 insertions, 84 deletions
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp
index 008c5db4..e6ddab9c 100644
--- a/src/mir/from_hir_match.cpp
+++ b/src/mir/from_hir_match.cpp
@@ -346,11 +346,21 @@ struct DecisionTreeGen
void generate_branches_Unsigned(
const Span& sp,
+ const DecisionTreeNode::Branch& default_branch,
const DecisionTreeNode::Values::Data_Unsigned& branches,
const ::HIR::TypeRef& ty,/* unsigned int _ty_ofs,*/
const ::MIR::LValue& val,
::std::function<void(const DecisionTreeNode&)> and_then
);
+
+ void generate_branches_Enum(
+ const Span& sp,
+ const DecisionTreeNode::Branch& default_branch,
+ const DecisionTreeNode::Values::Data_Variant& branches,
+ const ::HIR::TypeRef& ty,/* unsigned int _ty_ofs,*/
+ const ::MIR::LValue& val,
+ ::std::function<void(const DecisionTreeNode&)> and_then
+ );
};
void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNode_Match& node, ::MIR::LValue match_val, t_arm_rules arm_rules )
@@ -1196,6 +1206,7 @@ void DecisionTreeGen::populate_tree_vals(
{
case ::HIR::CoreType::Bool: {
ASSERT_BUG(sp, node.m_branches.is_Bool(), "Tree for bool isn't a _Bool - node="<<node);
+ //this->generate_branches_Bool(sp, node.m_branches.as_Bool(), ty, val, mv$(and_then));
const auto& branches = node.m_branches.as_Bool();
if( node.m_default.is_Unset() )
@@ -1230,7 +1241,7 @@ void DecisionTreeGen::populate_tree_vals(
case ::HIR::CoreType::U64:
case ::HIR::CoreType::Usize:
ASSERT_BUG(sp, node.m_branches.is_Unsigned(), "Tree for unsigned isn't a _Unsigned - node="<<node);
- this->generate_branches_Unsigned(sp, node.m_branches.as_Unsigned(), ty, val, mv$(and_then));
+ this->generate_branches_Unsigned(sp, node.m_default, node.m_branches.as_Unsigned(), ty, val, mv$(and_then));
break;
default:
TODO(sp, "Primitive - " << ty);
@@ -1262,89 +1273,9 @@ void DecisionTreeGen::populate_tree_vals(
TODO(sp, "Match over struct - " << e.path);
),
(Enum,
- const auto& enum_path = e.path.m_data.as_Generic();
ASSERT_BUG(sp, node.m_branches.is_Variant(), "Tree for enum isn't a Variant - node="<<node);
- const auto& branches = node.m_branches.as_Variant();
- const auto& variants = pbe->m_variants;
- auto variant_count = pbe->m_variants.size();
- bool has_any = ! node.m_default.is_Unset();
-
- if( branches.size() < variant_count && ! has_any ) {
- ERROR(sp, E0000, "Non-exhaustive match");
- }
- // DISABLED: Some complex matches don't directly use some defaults
- //if( branches.size() == variant_count && has_any ) {
- // ERROR(sp, E0000, "Unreachable _ arm - " << branches.size() << " variants in " << enum_path);
- //}
-
- auto any_block = (has_any ? m_builder.new_bb_unlinked() : 0);
-
- // Emit a switch over the variant
- ::std::vector< ::MIR::BasicBlockId> variant_blocks;
- variant_blocks.reserve( variant_count );
- for( const auto& branch : branches )
- {
- if( variant_blocks.size() != branch.first ) {
- assert( variant_blocks.size() < branch.first );
- assert( has_any );
- variant_blocks.resize( branch.first, any_block );
- }
- variant_blocks.push_back( m_builder.new_bb_unlinked() );
- }
- if( variant_blocks.size() != variant_count )
- {
- assert( variant_blocks.size() < variant_count );
- assert( has_any );
- variant_blocks.resize( variant_count, any_block );
- }
-
- m_builder.end_block( ::MIR::Terminator::make_Switch({
- val.clone(), variant_blocks // NOTE: Copies the list, so it can be used lower down
- }) );
-
- // Emit sub-patterns, looping over variants
- for( const auto& branch : branches )
- {
- auto bb = variant_blocks[branch.first];
- const auto& var = variants[branch.first];
- DEBUG(branch.first << " " << var.first << " = " << branch);
- this->generate_branch(branch.second, bb, [&](auto& subnode) {
- TU_MATCHA( (var.second), (e),
- (Unit,
- and_then( subnode );
- ),
- (Value,
- and_then( subnode );
- ),
- (Tuple,
- // Make a fake tuple
- ::std::vector< ::HIR::TypeRef> ents;
- for( const auto& fld : e )
- {
- ents.push_back( monomorphise_type(sp, pbe->m_params, enum_path.m_params, fld.ent) );
- }
- ::HIR::TypeRef fake_ty { mv$(ents) };
- this->populate_tree_vals(sp, subnode, fake_ty, 0, ::MIR::LValue::make_Downcast({ box$(val.clone()), branch.first }), and_then);
- ),
- (Struct,
- TODO(sp, "Enum pattern - struct");
- )
- )
- });
- }
-
- DEBUG("_");
- TU_MATCHA( (node.m_default), (be),
- (Unset, ),
- (Terminal,
- m_builder.set_cur_block(any_block);
- m_builder.end_block( ::MIR::Terminator::make_Goto( this->get_block_for_rule( be ) ) );
- ),
- (Subtree,
- m_builder.set_cur_block(any_block);
- and_then( *be );
- )
- )
+ assert(pbe);
+ this->generate_branches_Enum(sp, node.m_default, node.m_branches.as_Variant(), ty, val, mv$(and_then));
)
)
),
@@ -1396,6 +1327,7 @@ void DecisionTreeGen::generate_branch(const DecisionTreeNode::Branch& branch, ::
void DecisionTreeGen::generate_branches_Unsigned(
const Span& sp,
+ const DecisionTreeNode::Branch& default_branch,
const DecisionTreeNode::Values::Data_Unsigned& branches,
const ::HIR::TypeRef& ty,/* unsigned int _ty_ofs,*/
const ::MIR::LValue& val,
@@ -1408,7 +1340,7 @@ void DecisionTreeGen::generate_branches_Unsigned(
for( const auto& branch : branches )
{
- auto next_block = m_builder.new_bb_unlinked();
+ auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked());
auto val_start = m_builder.lvalue_or_temp(ty, ::MIR::Constant(branch.first.start));
auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(ty, ::MIR::Constant(branch.first.end)));
@@ -1429,4 +1361,110 @@ void DecisionTreeGen::generate_branches_Unsigned(
m_builder.set_cur_block( next_block );
}
+ assert( m_builder.block_active() );
+
+ // TODO: default_branch
+ TU_MATCHA( (default_branch), (be),
+ (Unset,
+ m_builder.end_block( ::MIR::Terminator::make_Diverge({}) );
+ ),
+ (Terminal,
+ m_builder.end_block( ::MIR::Terminator::make_Goto( this->get_block_for_rule( be ) ) );
+ ),
+ (Subtree,
+ and_then( *be );
+ )
+ )
+}
+void DecisionTreeGen::generate_branches_Enum(
+ const Span& sp,
+ const DecisionTreeNode::Branch& default_branch,
+ const DecisionTreeNode::Values::Data_Variant& branches,
+ const ::HIR::TypeRef& ty,/* unsigned int _ty_ofs,*/
+ const ::MIR::LValue& val,
+ ::std::function<void(const DecisionTreeNode&)> and_then
+ )
+{
+ const auto& enum_ref = *ty.m_data.as_Path().binding.as_Enum();
+ const auto& enum_path = ty.m_data.as_Path().path.m_data.as_Generic();
+ const auto& variants = enum_ref.m_variants;
+ auto variant_count = variants.size();
+ bool has_any = ! default_branch.is_Unset();
+
+ if( branches.size() < variant_count && ! has_any ) {
+ ERROR(sp, E0000, "Non-exhaustive match");
+ }
+ // DISABLED: Some complex matches don't directly use some defaults
+ //if( branches.size() == variant_count && has_any ) {
+ // ERROR(sp, E0000, "Unreachable _ arm - " << branches.size() << " variants in " << enum_path);
+ //}
+
+ auto any_block = (has_any ? m_builder.new_bb_unlinked() : 0);
+
+ // Emit a switch over the variant
+ ::std::vector< ::MIR::BasicBlockId> variant_blocks;
+ variant_blocks.reserve( variant_count );
+ for( const auto& branch : branches )
+ {
+ if( variant_blocks.size() != branch.first ) {
+ assert( variant_blocks.size() < branch.first );
+ assert( has_any );
+ variant_blocks.resize( branch.first, any_block );
+ }
+ variant_blocks.push_back( m_builder.new_bb_unlinked() );
+ }
+ if( variant_blocks.size() != variant_count )
+ {
+ assert( variant_blocks.size() < variant_count );
+ assert( has_any );
+ variant_blocks.resize( variant_count, any_block );
+ }
+
+ m_builder.end_block( ::MIR::Terminator::make_Switch({
+ val.clone(), variant_blocks // NOTE: Copies the list, so it can be used lower down
+ }) );
+
+ // Emit sub-patterns, looping over variants
+ for( const auto& branch : branches )
+ {
+ auto bb = variant_blocks[branch.first];
+ const auto& var = variants[branch.first];
+ DEBUG(branch.first << " " << var.first << " = " << branch);
+ this->generate_branch(branch.second, bb, [&](auto& subnode) {
+ TU_MATCHA( (var.second), (e),
+ (Unit,
+ and_then( subnode );
+ ),
+ (Value,
+ and_then( subnode );
+ ),
+ (Tuple,
+ // Make a fake tuple
+ ::std::vector< ::HIR::TypeRef> ents;
+ for( const auto& fld : e )
+ {
+ ents.push_back( monomorphise_type(sp, enum_ref.m_params, enum_path.m_params, fld.ent) );
+ }
+ ::HIR::TypeRef fake_ty { mv$(ents) };
+ this->populate_tree_vals(sp, subnode, fake_ty, 0, ::MIR::LValue::make_Downcast({ box$(val.clone()), branch.first }), and_then);
+ ),
+ (Struct,
+ TODO(sp, "Enum pattern - struct");
+ )
+ )
+ });
+ }
+
+ DEBUG("_");
+ TU_MATCHA( (default_branch), (be),
+ (Unset, ),
+ (Terminal,
+ m_builder.set_cur_block(any_block);
+ m_builder.end_block( ::MIR::Terminator::make_Goto( this->get_block_for_rule( be ) ) );
+ ),
+ (Subtree,
+ m_builder.set_cur_block(any_block);
+ and_then( *be );
+ )
+ )
}