diff options
Diffstat (limited to 'src/mir/from_hir_match.cpp')
-rw-r--r-- | src/mir/from_hir_match.cpp | 454 |
1 files changed, 227 insertions, 227 deletions
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 5e48eab3..2a9a8dd8 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -17,14 +17,14 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod struct field_path_t { ::std::vector<uint8_t> data; - + size_t size() const { return data.size(); } void push_back(uint8_t v) { data.push_back(v); } void pop_back() { data.pop_back(); } uint8_t& back() { return data.back(); } - + bool operator==(const field_path_t& x) const { return data == x.data; } - + friend ::std::ostream& operator<<(::std::ostream& os, const field_path_t& x) { for(const auto idx : x.data) os << "." << static_cast<unsigned int>(idx); @@ -61,9 +61,9 @@ struct PatternRuleset unsigned int pat_idx; ::std::vector<PatternRule> m_rules; - + static ::Ordering rule_is_before(const PatternRule& l, const PatternRule& r); - + bool is_before(const PatternRuleset& other) const; }; /// Generated code for an arm @@ -88,7 +88,7 @@ struct PatternRulesetBuilder bool m_is_impossible; ::std::vector<PatternRule> m_rules; field_path_t m_field_path; - + PatternRulesetBuilder(const StaticTraitResolve& resolve): m_resolve(resolve), m_is_impossible(false) @@ -97,7 +97,7 @@ struct PatternRulesetBuilder m_lang_Box = &resolve.m_crate.m_lang_items.at("owned_box"); } } - + void append_from_lit(const Span& sp, const ::HIR::Literal& lit, const ::HIR::TypeRef& ty); void append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty); void push_rule(PatternRule r); @@ -113,17 +113,17 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod { // TODO: If any arm moves a non-Copy value, then mark `match_val` as moved TRACE_FUNCTION; - + bool fall_back_on_simple = false; - + auto result_val = builder.new_temporary( node.m_res_type ); auto next_block = builder.new_bb_unlinked(); - + // 1. Stop the current block so we can generate code auto first_cmp_block = builder.new_bb_unlinked(); builder.end_block( ::MIR::Terminator::make_Goto(first_cmp_block) ); - + struct H { static bool is_pattern_move(const Span& sp, const MirBuilder& builder, const ::HIR::Pattern& pat) { if( pat.m_binding.is_valid() ) @@ -221,7 +221,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod return false; } }; - + bool has_move_pattern = false; for(const auto& arm : node.m_arms) { @@ -234,7 +234,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod if( has_move_pattern ) break ; } - + auto match_scope = builder.new_scope_split(node.span()); // Map of arm index to ruleset @@ -245,12 +245,12 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod DEBUG("ARM " << arm_idx); /*const*/ auto& arm = node.m_arms[arm_idx]; ArmCode ac; - + // Register introduced bindings to be dropped on return/diverge within this scope auto drop_scope = builder.new_scope_var( arm.m_code->span() ); // - Define variables from the first pattern conv.define_vars_from(node.span(), arm.m_patterns.front()); - + auto pat_scope = builder.new_scope_split(node.span()); for( unsigned int pat_idx = 0; pat_idx < arm.m_patterns.size(); pat_idx ++ ) { @@ -267,7 +267,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod DEBUG("ARM PAT (" << arm_idx << "," << pat_idx << ") " << pat << " ==> [" << pat_builder.m_rules << "]"); arm_rules.push_back( PatternRuleset { arm_idx, pat_idx, mv$(pat_builder.m_rules) } ); } - + // - Emit code to destructure the matched pattern ac.destructures.push_back( builder.new_bb_unlinked() ); builder.set_cur_block( ac.destructures.back() ); @@ -277,14 +277,14 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod // NOTE: Paused block resumed upon successful match } builder.terminate_scope( arm.m_code->span(), mv$(pat_scope) ); - + // TODO: If this pattern ignores fields with Drop impls, this will lead to leaks. // - Ideally, this would trigger a drop of whatever wasn't already taken by the pattern. if( has_move_pattern ) { builder.moved_lvalue(node.span(), match_val); } - + // Condition // NOTE: Lack of drop due to early exit from this arm isn't an issue. All captures must be Copy // - The above is rustc E0008 "cannot bind by-move into a pattern guard" @@ -294,13 +294,13 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod ac.has_condition = true; ac.cond_start = builder.new_bb_unlinked(); builder.set_cur_block( ac.cond_start ); - + // TODO: Temp scope. conv.visit_node_ptr( arm.m_cond ); ac.cond_lval = builder.get_result_in_lvalue(arm.m_cond->span(), ::HIR::TypeRef(::HIR::CoreType::Bool)); ac.cond_end = builder.pause_cur_block(); // NOTE: Paused so that later code (which knows what the false branch will be) can end it correctly - + // TODO: What to do with contidionals in the fast model? // > Could split the match on each conditional - separating such that if a conditional fails it can fall into the other compatible branches. fall_back_on_simple = true; @@ -338,10 +338,10 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod // - Go to the next block builder.end_block( ::MIR::Terminator::make_Goto(next_block) ); } - + arm_code.push_back( mv$(ac) ); } - + // Sort columns of `arm_rules` to maximise effectiveness if( arm_rules[0].m_rules.size() > 1 ) { @@ -357,7 +357,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod } } } - + DEBUG("- Column weights = [" << column_weights << "]"); // - Sort columns such that the largest (most specific) comes first ::std::vector<unsigned> columns_sorted(column_weights.size()); @@ -374,12 +374,12 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod arm_rule.m_rules = mv$(sorted); } } - + for(const auto& arm_rule : arm_rules) { DEBUG("> (" << arm_rule.arm_idx << ", " << arm_rule.pat_idx << ") - " << arm_rule.m_rules); } - + // TODO: Detect if a rule is ordering-dependent. In this case we currently have to fall back on the simple match code // - A way would be to search for `_` rules with non _ rules following. Would false-positive in some cases, but shouldn't false negative // TODO: Merge equal rulesets if there's one with no condition. @@ -390,7 +390,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod else { MIR_LowerHIR_Match_DecisionTree( builder, conv, node, mv$(match_val), mv$(arm_rules), mv$(arm_code), first_cmp_block ); } - + builder.set_cur_block( next_block ); builder.set_result( node.span(), mv$(result_val) ); builder.terminate_scope( node.span(), mv$(match_scope) ); @@ -442,7 +442,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod else return ::OrdLess; } - + TU_MATCHA( (l,r), (le,re), (Any, return ::OrdEqual; @@ -584,7 +584,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal (Struct, ASSERT_BUG(sp, lit.is_List(), "Matching struct non-list literal - " << ty << " with " << lit); const auto& list = lit.as_List(); - + auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty); this->m_resolve.expand_associated_types(sp, rv); @@ -603,7 +603,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal { ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(sd[i].ent) ? tmp = monomorph(sd[i].ent) : sd[i].ent); - + this->append_from_lit(sp, list[i], sty_mono); m_field_path.back() ++; } @@ -617,7 +617,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal const auto& fld_ty = sd[i].second.ent; ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld_ty) ? tmp = monomorph(fld_ty) : fld_ty); - + this->append_from_lit(sp, list[i], sty_mono); m_field_path.back() ++; } @@ -636,14 +636,14 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal this->m_resolve.expand_associated_types(sp, rv); return rv; }; - + ASSERT_BUG(sp, var_idx < pbe->m_variants.size(), "Literal refers to a variant out of range"); const auto& var_def = pbe->m_variants.at(var_idx); - + PatternRulesetBuilder sub_builder { this->m_resolve }; sub_builder.m_field_path = m_field_path; sub_builder.m_field_path.push_back(0); - + TU_MATCH( ::HIR::Enum::Variant, (var_def.second), (fields_def), (Unit, ), @@ -657,10 +657,10 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal sub_builder.m_field_path.back() = i; const auto& val = list[i]; const auto& ty_tpl = fields_def[i].ent; - + ::HIR::TypeRef tmp; const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); - + sub_builder.append_from_lit( sp, val, subty ); } ), @@ -672,15 +672,15 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal sub_builder.m_field_path.back() = i; const auto& val = list[i]; const auto& ty_tpl = fields_def[i].second.ent; - + ::HIR::TypeRef tmp; const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); - + sub_builder.append_from_lit( sp, val, subty ); } ) ) - + this->push_rule( PatternRule::make_Variant({ var_idx, mv$(sub_builder.m_rules) }) ); ) ) @@ -700,7 +700,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal ASSERT_BUG(sp, lit.is_List(), "Matching array with non-list literal - " << lit); const auto& list = lit.as_List(); ASSERT_BUG(sp, e.size_val == list.size(), "Matching array with mismatched literal size - " << e.size_val << " != " << list.size()); - + // Sequential match just like tuples. m_field_path.push_back(0); for(unsigned int i = 0; i < e.size_val; i ++) { @@ -712,7 +712,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal (Slice, ASSERT_BUG(sp, lit.is_List(), "Matching array with non-list literal - " << lit); const auto& list = lit.as_List(); - + PatternRulesetBuilder sub_builder { this->m_resolve }; sub_builder.m_field_path = m_field_path; sub_builder.m_field_path.push_back(0); @@ -775,7 +775,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa throw ""; } }; - + // TODO: Outer handling for Value::Named patterns // - Convert them into either a pattern, or just a variant of this function that operates on ::HIR::Literal // > It does need a way of handling unknown-value constants (e.g. <GenericT as Foo>::CONST) @@ -793,7 +793,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa } ) ) - + TU_MATCHA( (ty.m_data), (e), (Infer, BUG(sp, "Ivar for in match type"); ), (Diverge, @@ -942,7 +942,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa return rv; }; const auto& str_data = pbe->m_data; - + if( m_lang_Box && e.path.m_data.as_Generic().m_path == *m_lang_Box ) { const auto& inner_ty = e.path.m_data.as_Generic().m_params.m_types.at(0); @@ -997,7 +997,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa { const auto& fld = sd[i]; const auto& fld_pat = pe.sub_patterns[i]; - + ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld.ent) ? tmp = monomorph(fld.ent) : fld.ent); this->append_from(sp, fld_pat, sty_mono); @@ -1028,7 +1028,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa { ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld.second.ent) ? tmp = monomorph(fld.second.ent) : fld.second.ent); - + auto it = ::std::find_if( pe.sub_patterns.begin(), pe.sub_patterns.end(), [&](const auto& x){ return x.first == fld.first; } ); if( it == pe.sub_patterns.end() ) { @@ -1073,7 +1073,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ), (EnumTuple, const auto& var_def = pe.binding_ptr->m_variants.at(pe.binding_idx); - + const auto& fields_def = var_def.second.as_Tuple(); PatternRulesetBuilder sub_builder { this->m_resolve }; sub_builder.m_field_path = m_field_path; @@ -1083,10 +1083,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa sub_builder.m_field_path.back() = i; const auto& subpat = pe.sub_patterns[i]; const auto& ty_tpl = fields_def[i].ent; - + ::HIR::TypeRef tmp; const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); - + sub_builder.append_from( sp, subpat, subty ); } if( sub_builder.m_is_impossible ) @@ -1114,7 +1114,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa for( unsigned int i = 0; i < tmp.size(); i ++ ) { sub_builder.m_field_path.back() = i; - + auto subty = monomorph(fields_def[i].second.ent); if( tmp[i] == ~0u ) { sub_builder.append_from( sp, ::HIR::Pattern(), subty ); @@ -1197,7 +1197,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa sub_builder.append_from( sp, subpat, *e.inner ); sub_builder.m_field_path.back() ++; } - + // Encodes length check and sub-pattern rules this->push_rule( PatternRule::make_Slice({ static_cast<unsigned int>(pe.sub_patterns.size()), mv$(sub_builder.m_rules) }) ); ), @@ -1211,14 +1211,14 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa sub_builder.m_field_path.back() ++; } auto leading = mv$(sub_builder.m_rules); - + sub_builder.m_field_path.back() = 0; if( pe.trailing.size() ) { TODO(sp, "SplitSlice on [T] with trailing - " << pat); } auto trailing = mv$(sub_builder.m_rules); - + this->push_rule( PatternRule::make_SplitSlice({ static_cast<unsigned int>(pe.leading.size() + pe.trailing.size()), mv$(leading), mv$(trailing) @@ -1248,7 +1248,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa data.reserve(s.size()); for(auto c : s) data.push_back(c); - + this->push_rule( PatternRule::make_Value( mv$(data) ) ); } // TODO: Handle named values @@ -1294,13 +1294,13 @@ namespace { ::MIR::LValue lval = top_val.clone(); ::HIR::TypeRef tmp_ty; const ::HIR::TypeRef* cur_ty = &top_ty; - + // TODO: Cache the correspondance of path->type (lval can be inferred) ASSERT_BUG(sp, field_path_ofs <= field_path.size(), "Field path offset " << field_path_ofs << " is larger than the path [" << field_path << "]"); for(unsigned int i = field_path_ofs; i < field_path.size(); i ++ ) { auto idx = field_path.data[i]; - + TU_MATCHA( (cur_ty->m_data), (e), (Infer, BUG(sp, "Ivar for in match type"); ), (Diverge, BUG(sp, "Diverge in match type"); ), @@ -1424,7 +1424,7 @@ namespace { ) ) } - + out_ty = (cur_ty == &tmp_ty ? mv$(tmp_ty) : cur_ty->clone()); out_val = mv$(lval); } @@ -1438,7 +1438,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNode_Match& node, ::MIR::LValue match_val, t_arm_rules arm_rules, ::std::vector<ArmCode> arms_code, ::MIR::BasicBlockId first_cmp_block ) { TRACE_FUNCTION; - + // 1. Generate pattern matches unsigned int rule_idx = 0; builder.set_cur_block( first_cmp_block ); @@ -1446,18 +1446,18 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: { const auto& arm = node.m_arms[arm_idx]; auto& arm_code = arms_code[arm_idx]; - + auto next_arm_bb = builder.new_bb_unlinked(); - + for( unsigned int i = 0; i < arm.m_patterns.size(); i ++ ) { if( arm_code.destructures[i] == 0 ) continue ; - + const auto& pat_rule = arm_rules[rule_idx]; bool is_last_pat = (i+1 == arm.m_patterns.size()); auto next_pattern_bb = (!is_last_pat ? builder.new_bb_unlinked() : next_arm_bb); - + // 1. Check // - If the ruleset is empty, this is a _ arm over a value if( pat_rule.m_rules.size() > 0 ) @@ -1466,7 +1466,7 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: } builder.end_block( ::MIR::Terminator::make_Goto(arm_code.destructures[i]) ); builder.set_cur_block( arm_code.destructures[i] ); - + // - Go to code/condition check if( arm_code.has_condition ) { @@ -1476,12 +1476,12 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: { builder.end_block( ::MIR::Terminator::make_Goto(arm_code.code) ); } - + if( !is_last_pat ) { builder.set_cur_block( next_pattern_bb ); } - + rule_idx ++; } if( arm_code.has_condition ) @@ -1502,17 +1502,17 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& { const auto& rule = rules[rule_idx]; DEBUG("rule = " << rule); - + // Don't emit anything for '_' matches if( rule.is_Any() ) continue ; - + ::MIR::LValue val; ::HIR::TypeRef ity; - + get_ty_and_val(sp, builder.resolve(), top_ty, top_val, rule.field_path, field_path_ofs, ity, val); DEBUG("ty = " << ity << ", val = " << val); - + const auto& ty = ity; TU_MATCHA( (ty.m_data), (te), (Infer, @@ -1527,9 +1527,9 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& case ::HIR::CoreType::Bool: { ASSERT_BUG(sp, rule.is_Bool(), "PatternRule for bool isn't _Bool"); bool test_val = rule.as_Bool(); - + auto succ_bb = builder.new_bb_unlinked(); - + if( test_val ) { builder.end_block( ::MIR::Terminator::make_If({ val.clone(), succ_bb, fail_bb }) ); } @@ -1549,7 +1549,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ), (Value, auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.as_Uint())); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1571,7 +1571,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ), (Value, auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.as_Int())); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1589,7 +1589,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ), (Value, auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.as_Uint())); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1598,19 +1598,19 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& (ValueRange, auto succ_bb = builder.new_bb_unlinked(); auto test_bb_2 = builder.new_bb_unlinked(); - + // IF `val` < `first` : fail_bb auto test_lt_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.first.as_Uint())); auto cmp_lt_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(test_lt_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lt_lval), fail_bb, test_bb_2 }) ); - + builder.set_cur_block(test_bb_2); - + // IF `val` > `last` : fail_bb auto test_gt_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.last.as_Uint())); auto cmp_gt_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::GT, mv$(test_gt_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_gt_lval), fail_bb, succ_bb }) ); - + builder.set_cur_block(succ_bb); ) ) @@ -1622,9 +1622,9 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& case ::HIR::CoreType::Str: { ASSERT_BUG(sp, rule.is_Value() && rule.as_Value().is_StaticString(), ""); const auto& v = rule.as_Value(); - + auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), ::MIR::RValue(::MIR::Constant( v.as_StaticString() ))); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, ::MIR::LValue::make_Deref({box$(test_lval)}) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1662,17 +1662,17 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ASSERT_BUG(sp, rule.is_Variant(), "Rule for enum isn't Any or Variant"); const auto& re = rule.as_Variant(); unsigned int var_idx = re.idx; - + auto next_bb = builder.new_bb_unlinked(); auto var_count = pbe->m_variants.size(); - + // Generate a switch with only one option different. ::std::vector< ::MIR::BasicBlockId> arms(var_count, fail_bb); arms[var_idx] = next_bb; builder.end_block( ::MIR::Terminator::make_Switch({ val.clone(), mv$(arms) }) ); - + builder.set_cur_block(next_bb); - + if( re.sub_rules.size() > 0 ) { const auto& var_data = pbe->m_variants.at(re.idx).second; @@ -1692,7 +1692,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& fake_ty_ents.push_back( monomorph(ve[i].ent) ); } ::HIR::TypeRef fake_tup = ::HIR::TypeRef( mv$(fake_ty_ents) ); - + // Recurse with the new ruleset MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), @@ -1709,7 +1709,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& fake_ty_ents.push_back( monomorph(ve[i].second.ent) ); } ::HIR::TypeRef fake_tup = ::HIR::TypeRef( mv$(fake_ty_ents) ); - + // Recurse with the new ruleset MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), @@ -1755,11 +1755,11 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& if( rule.is_Value() ) { ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]"); auto cloned_val = ::MIR::Constant( rule.as_Value().as_Bytes() ); - + auto succ_bb = builder.new_bb_unlinked(); - + auto inner_val = val.as_Deref().val->clone(); - + auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), ::MIR::RValue(mv$(cloned_val))); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(inner_val), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1767,16 +1767,16 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& } else if( rule.is_Slice() ) { const auto& re = rule.as_Slice(); - + // Compare length auto test_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue( ::MIR::Constant::make_Uint(re.len) )); auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ val.clone() })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_lval) })); - + auto len_succ_bb = builder.new_bb_unlinked(); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), len_succ_bb, fail_bb }) ); builder.set_cur_block(len_succ_bb); - + // Recurse checking values MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), @@ -1786,22 +1786,22 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& } else if( rule.is_SplitSlice() ) { const auto& re = rule.as_SplitSlice(); - + // Compare length auto test_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue( ::MIR::Constant::make_Uint(re.min_len) )); auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ val.clone() })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_lval) })); - + auto len_succ_bb = builder.new_bb_unlinked(); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), fail_bb, len_succ_bb }) ); // if len < test : FAIL builder.set_cur_block(len_succ_bb); - + MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.leading.data(), re.leading.size(), top_ty, top_val, field_path_ofs, fail_bb ); - + if( re.trailing.size() > 0 ) { TODO(sp, "Match over Slice using SplitSlice with trailing - " << rule); @@ -1844,13 +1844,13 @@ struct DecisionTreeNode (Subtree, ::std::unique_ptr<DecisionTreeNode>), (Terminal, unsigned int) ); - + template<typename T> struct Range { T start; T end; - + // `x` starts after this range ends bool operator<(const Range<T>& x) const { return (end < x.start); @@ -1859,7 +1859,7 @@ struct DecisionTreeNode bool operator<(const T& x) const { return (end < x); } - + // `x` ends before this starts, or overlaps bool operator>=(const Range<T>& x) const { return start > x.end || ovelaps(x); @@ -1868,28 +1868,28 @@ struct DecisionTreeNode bool operator>=(const T& x) const { return start > x || contains(x); } - + bool operator>(const Range<T>& x) const { return (start > x.end); } bool operator>(const T& x) const { return (start > x); } - + bool operator==(const Range<T>& x) const { return start == x.start && end == x.end; } bool operator!=(const Range<T>& x) const { return start != x.start || end != x.end; } - + bool contains(const T& x) const { return (start <= x && x <= end); } bool overlaps(const Range<T>& x) const { return (x.start <= start && start <= x.end) || (x.start <= end && end <= x.end); } - + friend ::std::ostream& operator<<(::std::ostream& os, const Range<T>& x) { if( x.start == x.end ) { return os << x.start; @@ -1899,7 +1899,7 @@ struct DecisionTreeNode } } }; - + TAGGED_UNION( Values, Unset, (Unset, struct {}), (Bool, struct { Branch false_branch, true_branch; }), @@ -1913,23 +1913,23 @@ struct DecisionTreeNode //::std::vector< ::std::pair< unsigned int, Branch> > variable_arms; }) ); - + // TODO: Arm specialisation? field_path_t m_field_path; Values m_branches; Branch m_default; - + DecisionTreeNode( field_path_t field_path ): // TODO: This is commented out fo a reason, but I don't know why. //m_field_path( mv$(field_path) ), m_branches(), m_default() {} - + static Branch clone(const Branch& b); static Values clone(const Values& x); DecisionTreeNode clone() const; - + void populate_tree_from_rule(const Span& sp, unsigned int arm_index, const PatternRule* first_rule, unsigned int rule_count) { populate_tree_from_rule(sp, first_rule, rule_count, [sp,arm_index](auto& branch){ TU_MATCHA( (branch), (e), @@ -1954,14 +1954,14 @@ struct DecisionTreeNode } // `and_then` - Closure called after processing the final rule void populate_tree_from_rule(const Span& sp, const PatternRule* first_rule, unsigned int rule_count, ::std::function<void(Branch&)> and_then); - + /// Simplifies the tree by eliminating nodes that don't make a decision void simplify(); /// Propagate the m_default arm's contents to value arms, and vice-versa void propagate_default(); /// HELPER: Unfies the rules from the provided branch with this node void unify_from(const Branch& b); - + ::MIR::LValue get_field(const ::MIR::LValue& base, unsigned int base_depth) const { ::MIR::LValue cur = base.clone(); for(unsigned int i = base_depth; i < m_field_path.size(); i ++ ) { @@ -1975,7 +1975,7 @@ struct DecisionTreeNode } return cur; } - + friend ::std::ostream& operator<<(::std::ostream& os, const Branch& x); friend ::std::ostream& operator<<(::std::ostream& os, const DecisionTreeNode& x); }; @@ -1984,16 +1984,16 @@ 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 generate_tree_code(const Span& sp, const DecisionTreeNode& node, const ::HIR::TypeRef& ty, const ::MIR::LValue& val) { generate_tree_code(sp, node, ty, 0, val, [&](const auto& n){ DEBUG("node = " << n); @@ -2007,9 +2007,9 @@ struct DecisionTreeGen const ::HIR::TypeRef& ty, unsigned int path_ofs, const ::MIR::LValue& base_val, ::std::function<void(const DecisionTreeNode&)> and_then ); - + void generate_branch(const DecisionTreeNode::Branch& branch, ::std::function<void(const DecisionTreeNode&)> cb); - + void generate_branches_Signed( const Span& sp, const DecisionTreeNode::Branch& default_branch, @@ -2052,7 +2052,7 @@ struct DecisionTreeGen const ::HIR::TypeRef& ty, ::MIR::LValue val, ::std::function<void(const DecisionTreeNode&)> and_then ); - + void generate_branches_Enum( const Span& sp, const DecisionTreeNode::Branch& default_branch, @@ -2080,7 +2080,7 @@ struct DecisionTreeGen void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNode_Match& node, ::MIR::LValue match_val, t_arm_rules arm_rules, ::std::vector<ArmCode> arms_code, ::MIR::BasicBlockId first_cmp_block ) { TRACE_FUNCTION; - + // XXX XXX XXX: The current codegen (below) will generate incorrect code if ordering matters. // ``` // match ("foo", "bar") @@ -2094,14 +2094,14 @@ void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, : // TODO: Sort the columns in `arm_rules` to ensure that the most specific rule is parsed first. // - Ordering within a pattern doesn't matter, only the order of arms matters. // - This sort could be designed such that the above case would match correctly? - + DEBUG("- Generating rule bindings"); ::std::vector< ::MIR::BasicBlockId> rule_blocks; for(const auto& rule : arm_rules) { const auto& arm_code = arms_code[rule.arm_idx]; ASSERT_BUG(node.span(), !arm_code.has_condition, "Decision tree doesn't (yet) support conditionals"); - + assert( rule.pat_idx < arm_code.destructures.size() ); // Set the target for when a rule succeeds to the destructuring code for this rule rule_blocks.push_back( arm_code.destructures[rule.pat_idx] ); @@ -2109,8 +2109,8 @@ void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, : builder.set_cur_block( rule_blocks.back() ); builder.end_block( ::MIR::Terminator::make_Goto(arm_code.code) ); } - - + + // - Build tree by running each arm's pattern across it DEBUG("- Building decision tree"); DecisionTreeNode root_node({}); @@ -2128,7 +2128,7 @@ void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, : root_node.propagate_default(); DEBUG("root_node = " << root_node); // TODO: Pretty print `root_node` - + // - Convert the above decision tree into MIR DEBUG("- Emitting decision tree"); DecisionTreeGen gen { builder, rule_blocks }; @@ -2147,7 +2147,7 @@ DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree(const Span& sp, t_arm rules.push_back( arm_rules[i].m_rules ); indexes.push_back(i); } - + return MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(sp, indexes, rules); } DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(const Span& sp, slice<unsigned int> arm_indexes, slice< slice<PaternRule>> arm_rules) @@ -2155,13 +2155,13 @@ DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(const Span& sp, assert( arm_indexes.size() == arm_rules.size() ); assert( arm_rules.size() > 1 ); assert( arm_rules[0].size() > 0 ); - + // 1. Sort list (should it already be sorted?) for(const auto& rules : arm_rules) { ASSERT_BUG(sp, rules.size() != arm_rules[0].size(), ""); } - + // 2. Detect all arms being `_` and move on to the next condition while( ::std::all_of(arm_rules.begin(), arm_rules.end(), [](const auto& r){ return r.m_rules[0].is_Any(); }) ) { @@ -2170,27 +2170,27 @@ DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(const Span& sp, // No rules left? BUG(sp, "Duplicate match arms"); } - + for(auto& rules : arm_rules) { rules = rules.subslice_from(1); } } - + // We have a codition. for(const auto& rules : arm_rules) { ASSERT_BUG(sp, rules[0].is_Any() || rules[0].tag() == arm_rules[0][0].tag(), "Mismatched rules in match"); } - + bool has_any = arm_rules.back()[0].is_Any(); - + // All rules must either be _ or the same type, and can't all be _ switch( arm_rules[0][0].tag() ) { case PatternRule::TAGDEAD: throw ""; case PatternRule::TAG_Any: throw ""; - + case PatternRule::TAG_Variant: break; // TODO: Value and ValueRange can appear together. @@ -2276,7 +2276,7 @@ namespace { return DecisionTreeNode::Branch( box$(DecisionTreeNode( mv$(path) )) ); } - + // Common code for numerics (Int, Uint, and Float) template<typename T> static void from_rule_valuerange( @@ -2287,7 +2287,7 @@ namespace { ASSERT_BUG(sp, ve_start != ve_end, "Range pattern with one value - " << ve_start); ASSERT_BUG(sp, ve_start < ve_end, "Range pattern with a start after the end - " << ve_start << "..." << ve_end); - + TRACE_FUNCTION_F("[" << FMT_CB(os, for(const auto& i:be) os << i.first <<" , ";) << "]"); // - Find the first entry that ends after the new one starts. auto it = ::std::find_if(be.begin(), be.end(), [&](const auto& v){ return v.first.end >= ve_start; }); @@ -2335,7 +2335,7 @@ namespace DEBUG("- Shared head, continue"); //assert(it->first.start == ve_start); assert((it->first.end) < ve_end); - + if( it->first.start != it->first.end ) and_then(it->second); ve_start = it->first.end + 1; @@ -2343,7 +2343,7 @@ namespace } } } - + template<typename T> static void from_rule_value( const Span& sp, @@ -2369,14 +2369,14 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule { assert( rule_count > 0 ); const auto& rule = *first_rule; - + if( m_field_path.size() == 0 ) { m_field_path = rule.field_path; } else { ASSERT_BUG(sp, m_field_path == rule.field_path, "Patterns with mismatched field paths - " << m_field_path << " != " << rule.field_path); } - + #define GET_BRANCHES(fld, var) (({if( fld.is_Unset() ) {\ fld = Values::make_##var({}); \ } \ @@ -2385,7 +2385,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule }}), \ fld.as_##var()) - + TU_MATCHA( (rule), (e), (Any, { if( rule_count == 1 ) @@ -2411,7 +2411,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule }), (Variant, { auto& be = GET_BRANCHES(m_branches, Variant); - + auto it = ::std::find_if( be.begin(), be.end(), [&](const auto& x){ return x.first >= e.idx; }); // If this variant isn't yet processed, add a new subtree for it if( it == be.end() || it->first != e.idx ) { @@ -2426,7 +2426,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule assert( it->second.is_Subtree() ); } auto& subtree = *it->second.as_Subtree(); - + if( e.sub_rules.size() > 0 && rule_count > 1 ) { subtree.populate_tree_from_rule(sp, e.sub_rules.data(), e.sub_rules.size(), [&](auto& branch){ @@ -2458,7 +2458,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule }), (Slice, auto& be = GET_BRANCHES(m_branches, Slice); - + auto it = ::std::find_if( be.fixed_arms.begin(), be.fixed_arms.end(), [&](const auto& x){ return x.first >= e.len; } ); if( it == be.fixed_arms.end() || it->first != e.len ) { it = be.fixed_arms.insert(it, ::std::make_pair(e.len, new_branch_subtree(rule.field_path))); @@ -2471,7 +2471,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule } assert( it->second.is_Subtree() ); auto& subtree = *it->second.as_Subtree(); - + if( e.sub_rules.size() > 0 && rule_count > 1 ) { subtree.populate_tree_from_rule(sp, e.sub_rules.data(), e.sub_rules.size(), [&](auto& branch){ @@ -2507,7 +2507,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (Bool, auto& be = GET_BRANCHES(m_branches, Bool); - + auto& branch = (e ? be.true_branch : be.false_branch); if( branch.is_Unset() ) { branch = new_branch_subtree( rule.field_path ); @@ -2532,7 +2532,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule TU_MATCHA( (e), (ve), (Int, auto& be = GET_BRANCHES(m_branches, Signed); - + // TODO: De-duplicate this code between Uint and Float from_rule_value(sp, be, ve, "Signed", rule.field_path, [&](auto& branch) { @@ -2549,7 +2549,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (Uint, auto& be = GET_BRANCHES(m_branches, Unsigned); - + from_rule_value(sp, be, ve, "Unsigned", rule.field_path, [&](auto& branch) { if( rule_count > 1 ) { @@ -2565,7 +2565,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (Float, auto& be = GET_BRANCHES(m_branches, Float); - + from_rule_value(sp, be, ve, "Float", rule.field_path, [&](auto& branch) { if( rule_count > 1 ) { @@ -2586,7 +2586,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (StaticString, auto& be = GET_BRANCHES(m_branches, String); - + auto it = ::std::find_if(be.begin(), be.end(), [&](const auto& v){ return v.first >= ve; }); if( it == be.end() || it->first != ve ) { it = be.insert( it, ::std::make_pair(ve, new_branch_subtree(rule.field_path) ) ); @@ -2612,7 +2612,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ) ), (ValueRange, - + ASSERT_BUG(sp, e.first.tag() == e.last.tag(), ""); TU_MATCHA( (e.first, e.last), (ve_start, ve_end), (Int, @@ -2698,7 +2698,7 @@ void DecisionTreeNode::simplify() ) } }; - + TU_MATCHA( (m_branches), (e), (Unset, H::simplify_branch(m_default); @@ -2745,7 +2745,7 @@ void DecisionTreeNode::simplify() } ) ) - + H::simplify_branch(m_default); } @@ -2765,7 +2765,7 @@ void DecisionTreeNode::propagate_default() ) } }; - + TU_MATCHA( (m_branches), (e), (Unset, ), @@ -2815,7 +2815,7 @@ void DecisionTreeNode::propagate_default() DEBUG("- default"); TU_IFLET(Branch, m_default, Subtree, be, be->propagate_default(); - + if( be->m_default.is_Unset() ) { // Propagate default from value branches TU_MATCHA( (m_branches), (e), @@ -2872,7 +2872,7 @@ namespace { // Terminal, no unify } } - + template<typename T> void unify_from_vals_range(::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& dst, const ::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& src) { @@ -2896,7 +2896,7 @@ namespace { } } } - + template<typename T> void unify_from_vals_pt(::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& dst, const ::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& src) { @@ -2918,9 +2918,9 @@ namespace { void DecisionTreeNode::unify_from(const Branch& b) { TRACE_FUNCTION_FR(*this << " with " << b, *this); - + assert( b.is_Terminal() || b.is_Subtree() ); - + if( m_default.is_Unset() ) { if( b.is_Terminal() ) { m_default = clone(b); @@ -2929,7 +2929,7 @@ void DecisionTreeNode::unify_from(const Branch& b) m_default = clone(b.as_Subtree()->m_default); } } - + if( b.is_Subtree() && b.as_Subtree()->m_branches.tag() != m_branches.tag() ) { // Is this a bug, or expected (and don't unify in?) DEBUG("TODO - Unify mismatched arms? - " << b.as_Subtree()->m_branches.tag_str() << " and " << m_branches.tag_str()); @@ -2939,7 +2939,7 @@ void DecisionTreeNode::unify_from(const Branch& b) //if( b.is_Subtree() ) { // ASSERT_BUG(Span(), this->m_field_path == b.as_Subtree()->m_field_path, "Unifiying DTNs with mismatched paths - " << this->m_field_path << " != " << b.as_Subtree()->m_field_path); //} - + TU_MATCHA( (m_branches), (dst), (Unset, if( b.is_Subtree() ) { @@ -2951,7 +2951,7 @@ void DecisionTreeNode::unify_from(const Branch& b) ), (Bool, auto* src = (b.is_Subtree() ? &b.as_Subtree()->m_branches.as_Bool() : nullptr); - + unify_branch( dst.false_branch, (src ? src->false_branch : b) ); unify_branch( dst.true_branch , (src ? src->true_branch : b) ); ), @@ -3023,7 +3023,7 @@ void DecisionTreeNode::unify_from(const Branch& b) if( should_unify_subtree ) { auto& sb = b.as_Subtree()->m_branches; ASSERT_BUG(Span(), sb.is_Slice(), "Unifying Slice with " << sb.tag_str()); - + const auto& src = sb.as_Slice(); unify_from_vals_pt(dst.fixed_arms, src.fixed_arms); } @@ -3116,7 +3116,7 @@ void DecisionTreeNode::unify_from(const Branch& b) } ) ) - + os << "* = " << x.m_default; os << " }"; return os; @@ -3135,13 +3135,13 @@ void DecisionTreeGen::generate_tree_code( ) { TRACE_FUNCTION_F("top_ty=" << top_ty << ", field_path_ofs=" << field_path_ofs << ", top_val=" << top_val << ", node=" << node); - + ::MIR::LValue val; ::HIR::TypeRef ty; - + get_ty_and_val(sp, m_builder.resolve(), top_ty, top_val, node.m_field_path, field_path_ofs, ty, val); DEBUG("ty = " << ty << ", val = " << val); - + TU_MATCHA( (ty.m_data), (e), (Infer, BUG(sp, "Ivar for in match type"); ), (Diverge, BUG(sp, "Diverge in match type"); ), @@ -3268,7 +3268,7 @@ void DecisionTreeGen::generate_branch(const DecisionTreeNode::Branch& branch, :: else { assert( branch.is_Subtree() ); const auto& subnode = *branch.as_Subtree(); - + cb(subnode); } } @@ -3282,16 +3282,16 @@ void DecisionTreeGen::generate_branches_Signed( ) { auto default_block = m_builder.new_bb_unlinked(); - + // TODO: Convert into an integer switch w/ offset instead of chained comparisons - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3303,14 +3303,14 @@ void DecisionTreeGen::generate_branches_Signed( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Emit error if non-exhaustive m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); @@ -3329,16 +3329,16 @@ void DecisionTreeGen::generate_branches_Unsigned( ) { auto default_block = m_builder.new_bb_unlinked(); - + // TODO: Convert into an integer switch w/ offset instead of chained comparisons - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3350,14 +3350,14 @@ void DecisionTreeGen::generate_branches_Unsigned( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Emit error if non-exhaustive m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); @@ -3376,14 +3376,14 @@ void DecisionTreeGen::generate_branches_Float( ) { auto default_block = m_builder.new_bb_unlinked(); - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3395,14 +3395,14 @@ void DecisionTreeGen::generate_branches_Float( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { ERROR(sp, E0000, "Match over floating point with no `_` arm"); } @@ -3420,16 +3420,16 @@ void DecisionTreeGen::generate_branches_Char( ) { auto default_block = m_builder.new_bb_unlinked(); - + // TODO: Convert into an integer switch w/ offset instead of chained comparisons - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp( sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3441,14 +3441,14 @@ void DecisionTreeGen::generate_branches_Char( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Error if not exhaustive. m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); @@ -3466,7 +3466,7 @@ void DecisionTreeGen::generate_branches_Bool( ) { //assert( ty.m_data.is_Boolean() ); - + if( default_branch.is_Unset() ) { if( branches.false_branch.is_Unset() || branches.true_branch.is_Unset() ) { @@ -3479,16 +3479,16 @@ void DecisionTreeGen::generate_branches_Bool( // Unreachable default (NOTE: Not an error here) } } - + // Emit an if based on the route taken auto bb_false = m_builder.new_bb_unlinked(); auto bb_true = m_builder.new_bb_unlinked(); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val), bb_true, bb_false }) ); - + // Recurse into sub-patterns const auto& branch_false = ( !branches.false_branch.is_Unset() ? branches.false_branch : default_branch ); const auto& branch_true = ( !branches. true_branch.is_Unset() ? branches. true_branch : default_branch ); - + m_builder.set_cur_block(bb_true ); this->generate_branch(branch_true , and_then); m_builder.set_cur_block(bb_false); @@ -3508,35 +3508,35 @@ void DecisionTreeGen::generate_branches_Borrow_str( // - rustc emits calls to PartialEq::eq for this and for slices. mrustc could use PartialOrd and fall back to PartialEq if unavaliable? // > Requires crate access here! - A memcmp call is probably better, probably via a binop // NOTE: The below implementation gets the final codegen to call memcmp on the strings by emitting eBinOp::{LT,GT} - + // - Remove the wrapping Deref (which must be there) ASSERT_BUG(sp, val.is_Deref(), "Match over str without a deref - " << val); auto tmp = mv$( *val.as_Deref().val ); val = mv$(tmp); - + auto default_bb = m_builder.new_bb_unlinked(); - + assert( !branches.empty() ); for(const auto& branch : branches) { auto have_val = val.clone(); - + auto next_bb = (&branch == &branches.back() ? default_bb : m_builder.new_bb_unlinked()); - + auto test_val = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str), ::MIR::Constant(branch.first) ); auto cmp_gt_bb = m_builder.new_bb_unlinked(); - + auto lt_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ have_val.clone(), ::MIR::eBinOp::LT, test_val.clone() }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(lt_val), default_bb, cmp_gt_bb }) ); m_builder.set_cur_block(cmp_gt_bb); - + auto eq_bb = m_builder.new_bb_unlinked(); auto gt_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(have_val), ::MIR::eBinOp::GT, test_val.clone() }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(gt_val), next_bb, eq_bb }) ); m_builder.set_cur_block(eq_bb); - + this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block(next_bb); } this->generate_branch(default_branch, and_then); @@ -3556,7 +3556,7 @@ void DecisionTreeGen::generate_branches_Enum( 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 over " << ty << " - " << branches.size() << " out of " << variant_count << " present"); } @@ -3564,9 +3564,9 @@ void DecisionTreeGen::generate_branches_Enum( //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 ); @@ -3586,22 +3586,22 @@ void DecisionTreeGen::generate_branches_Enum( variant_blocks.resize( variant_count, any_block ); } bool any_arm_used = ::std::any_of( variant_blocks.begin(), variant_blocks.end(), [any_block](const auto& blk){ return blk == 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.second); - + auto var_lval = ::MIR::LValue::make_Downcast({ box$(val.clone()), branch.first }); - + ::HIR::TypeRef fake_ty; - + TU_MATCHA( (var.second), (e), (Unit, DEBUG("- Unit"); @@ -3631,7 +3631,7 @@ void DecisionTreeGen::generate_branches_Enum( DEBUG("- Struct - " << fake_ty); ) ) - + m_builder.set_cur_block( bb ); if( fake_ty == ::HIR::TypeRef() || fake_ty.m_data.as_Tuple().size() == 0 ) { this->generate_branch(branch.second, and_then); @@ -3643,7 +3643,7 @@ void DecisionTreeGen::generate_branches_Enum( }); } } - + if( any_arm_used ) { DEBUG("_ = " << default_branch); @@ -3671,46 +3671,46 @@ void DecisionTreeGen::generate_branches_Slice( if( default_branch.is_Unset() ) { ERROR(sp, E0000, "Non-exhaustive match over " << ty); } - + // NOTE: Un-deref the slice ASSERT_BUG(sp, val.is_Deref(), "slice matches must be passed a deref"); auto tmp = mv$( *val.as_Deref().val ); val = mv$(tmp); - + auto any_block = m_builder.new_bb_unlinked(); - + // TODO: Select one of three ways of picking the arm: // - Integer switch (unimplemented) // - Binary search // - Sequential comparisons - + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ val.clone() })); - + // TODO: Binary search instead. for( const auto& branch : branches.fixed_arms ) { auto val_des = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::Constant(static_cast<uint64_t>(branch.first))); - + // Special case - final just does equality if( &branch == &branches.fixed_arms.back() ) { auto val_cmp_eq = m_builder.lvalue_or_temp( sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val_len.clone(), ::MIR::eBinOp::EQ, mv$(val_des) }) ); - + auto success_block = m_builder.new_bb_unlinked(); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_eq), any_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( any_block ); } // TODO: Special case for zero (which can't have a LT) else { auto next_block = m_builder.new_bb_unlinked(); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp( sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val_len.clone(), ::MIR::eBinOp::LT, val_des.clone() @@ -3722,15 +3722,15 @@ void DecisionTreeGen::generate_branches_Slice( val_len.clone(), ::MIR::eBinOp::GT, mv$(val_des) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Emit error if non-exhaustive m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); |