diff options
author | John Hodge <tpg@mutabah.net> | 2016-08-10 21:32:23 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-08-10 21:32:23 +0800 |
commit | 8cb134e7fbad5fb4b2c445fa51548d96f3a078d7 (patch) | |
tree | d78168d282b830fd46b474bd76c46e85c851f4e6 | |
parent | e21656f68bab1e3021be97c4708c9854f4da76e1 (diff) | |
download | mrust-8cb134e7fbad5fb4b2c445fa51548d96f3a078d7.tar.gz |
MIR - Match coming along
-rw-r--r-- | src/mir/from_hir.cpp | 164 |
1 files changed, 98 insertions, 66 deletions
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index c8d909e3..633caf8e 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -516,9 +516,8 @@ namespace { // - Generate code for arms. ::std::vector< ::MIR::BasicBlockId> arm_blocks; arm_blocks.reserve( arm_rules.size() ); - for(unsigned int i = 0; i < arm_rules.size(); i ++) + for(auto& arm : node.m_arms) { - auto& arm = node.m_arms[i]; // TODO: Register introduced bindings to be dropped on return/diverge arm_blocks.push_back( m_builder.new_bb_unlinked() ); m_builder.set_cur_block(arm_blocks.back()); @@ -534,6 +533,20 @@ namespace { } } + ::std::vector< ::MIR::BasicBlockId> rule_blocks; + for(const auto& rule : arm_rules) + { + rule_blocks.push_back( m_builder.new_bb_unlinked() ); + m_builder.set_cur_block(arm_blocks.back()); + + const auto& arm = node.m_arms[ rule.first ]; + ASSERT_BUG(node.span(), arm.m_patterns.size() == 1, "TODO: Handle multiple patterns on one arm"); + const auto& pat = arm.m_patterns[0 /*rule.first.second*/]; + + // Assign bindings (drop registration happens in previous loop) + this->destructure_from( arm.m_code->span(), pat, match_val.clone() ); + } + // ## Create descision tree in-memory based off the ruleset // > Tree contains an lvalue and a set of possibilities (PatternRule) connected to another tree or to a branch index struct DecisionTreeNode { @@ -641,27 +654,48 @@ namespace { ) ) } + }; + + struct DecisionTreeGen + { + MirBuilder& m_builder; + const ::std::vector< ::MIR::BasicBlockId>& m_rule_blocks; + + DecisionTreeGen(MirBuilder& builder, const ::std::vector< ::MIR::BasicBlockId >& rule_blocks): + m_builder( builder ), + m_rule_blocks( rule_blocks ) + {} + + ::MIR::BasicBlockId get_block_for_rule(unsigned int rule_index) { + return m_rule_blocks.at( rule_index ); + } - /* - void populate_tree_vals(const ::HIR::TypeRef& ty, unsigned int ty_ofs, const ::MIR::LValue& val) + void populate_tree_vals(const Span& sp, const DecisionTreeNode& node, const ::HIR::TypeRef& ty, const ::MIR::LValue& val) { + populate_tree_vals(sp, node, ty, 0, val, [](const auto&){}); + } + void populate_tree_vals( + const Span& sp, + const DecisionTreeNode& node, + const ::HIR::TypeRef& ty, unsigned int ty_ofs, const ::MIR::LValue& val, + ::std::function<void(const DecisionTreeNode&)> and_then + ) { TU_MATCHA( (ty.m_data), (e), - ( (Infer, BUG(sp, "Ivar for in match type"); ), (Diverge, BUG(sp, "Diverge in match type"); ), (Primitive, TODO(sp, "Primitive"); ), (Tuple, - if( ty_ofs == 0 && e.size() == 0 ) { + // Tuple - Recurse on each sub-type (increasing the index) + if( ty_ofs == e.size() ) { + and_then(node); } else { - assert(ty_ofs < e.size()); - populate_tree_from_rule( e[ty_ofs], 0, ::MIR::LValue::make_Field({ box$(val.clone()), FMT(ty_ofs)}), arm_index, first_rule, rule_count ); - } - // Tuple - Recurse on each sub-type (increasing the index) - for(unsigned int i = 0; i < e.size(); i ++) { - idx += this->create_match_tree(sp, view, idx, e[i]); + populate_tree_vals( sp, node, + e[ty_ofs], 0, ::MIR::LValue::make_Field({ box$(val.clone()), ty_ofs}), + [&](auto& n){ this->populate_tree_vals(sp, node, ty, ty_ofs+1, val, and_then); } + ); } ), (Path, @@ -671,71 +705,75 @@ namespace { BUG(sp, "Encounterd unbound path - " << e.path); ), (Opaque, - // TODO: Why did this push a pattern? There's no chance of fail. - return 1; ), (Struct, TODO(sp, "Match over struct - " << e.path); ), (Enum, + const auto& branches = node.m_branches.as_Variant(); + const auto& variants = pbe->m_variants; + bool has_any = ! node.m_default.is_Unset(); + auto variant_count = pbe->m_variants.size(); - auto first_any = variant_count; - for( unsigned int i = 0; i < view.rule_count(); i ++ ) { - if( view.get(i, idx).is_Any() ) { - first_any = i; - break; - } + if( branches.size() < variant_count && ! has_any ) { + ERROR(sp, E0000, "Non-exhaustive match"); } - auto any_block = (first_any < variant_count ? m_builder.new_bb_unlinked() : 0); + if( branches.size() == variant_count && has_any ) { + ERROR(sp, E0000, "Unreachable _ arm"); + } + + auto any_block = (has_any ? m_builder.new_bb_unlinked() : 0); // Emit a switch over the variant - ::std::vector< ::MIR::BasicBlockId> variants; - variants.reserve( pbe->m_variants.size() ); - for( unsigned int i = 0; i < view.rule_count(); i ++ ) { - const auto& pat = view.get(i, idx); - if( pat.is_Any() ) { - break ; - } - else TU_IFLET( PatternRule, pat, Variant, e ) { - if( variants.size() == e.idx + 1 ) { - // Repeated index, will be unified later? - } - else { - if( variants.size() != e.idx ) { - assert( variants.size() < e.idx ); - if( ! has_any ) { - ERROR(sp, E0000, "Non-exhaustive match, variant " << pbe->m_variants[variants.size()].first << " missing"); - } - variants.resize( e.idx, any_block ); - } - variants.push_back( m_builder.new_bb_unlinked() ); - } - } - else { - BUG(sp, "Encountered unexpected pattern rule in enum, arm " << i); + ::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( variants.size() != variant_count ) + if( variant_blocks.size() != variant_count ) { - if( ! has_any ) { - ERROR(sp, E0000, "Non-exhaustive match, variant " << pbe->m_variants[variants.size()].first << " missing"); - } - variants.resize( e.idx, any_block ); + assert( variant_blocks.size() < variant_count ); + assert( has_any ); + variant_blocks.resize( variant_count, any_block ); } m_builder.end_block( ::MIR::Terminator::make_Switch({ - view.get_lvalue(idx), mv$(variants) + val.clone(), variant_blocks // NOTE: Copies the list, so it can be used lower down }) ); - - // Enums consume one rule - return 1; + // Emit sub-patterns, looping over variants + for( const auto& branch : branches ) + { + auto bb = variant_blocks[branch.first]; + const auto& var = variants[branch.first]; + m_builder.set_cur_block(bb); + TU_MATCHA( (var.second), (e), + (Unit, + assert( branch.second.is_Terminal() ); + m_builder.end_block( ::MIR::Terminator::make_Goto( this->get_block_for_rule( branch.second.as_Terminal() ) ) ); + ), + (Value, + assert( branch.second.is_Terminal() ); + m_builder.end_block( ::MIR::Terminator::make_Goto( this->get_block_for_rule( branch.second.as_Terminal() ) ) ); + ), + (Tuple, + TODO(sp, "Enum pattern - tuple"); + ), + (Struct, + TODO(sp, "Enum pattern - struct"); + ) + ) + } ) ) ), (Generic, - // TODO: Why did this push a pattern? There's no chance of fail. - return 1; ), (TraitObject, ERROR(sp, E0000, "Attempting to match over a trait object"); @@ -748,15 +786,10 @@ namespace { BUG(sp, "Hit match over `[T]` - must be `&[T]`"); ), (Borrow, - TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), - ( throw ""; ), - (Any, - this->append_from( sp, pat, *e.inner ); - ), - (Ref, - this->append_from( sp, *pe.sub, *e.inner ); - ) - ) + populate_tree_vals( sp, node, + *e.inner, 0, ::MIR::LValue::make_Deref({ box$(val.clone()) }), + and_then + ); ), (Pointer, ERROR(sp, E0000, "Attempting to match over a pointer"); @@ -769,7 +802,6 @@ namespace { ) ) } - */ }; // - Build tree by running each arm's pattern across it |