diff options
-rw-r--r-- | src/hir/pattern.cpp | 3 | ||||
-rw-r--r-- | src/hir/pattern.hpp | 1 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 57 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 4 |
4 files changed, 62 insertions, 3 deletions
diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp index 5a6cc9c1..71b0a9bb 100644 --- a/src/hir/pattern.cpp +++ b/src/hir/pattern.cpp @@ -201,7 +201,8 @@ namespace { (SplitTuple, return Pattern(m_binding, Data::make_SplitTuple({ clone_pat_vec(e.leading), - clone_pat_vec(e.trailing) + clone_pat_vec(e.trailing), + e.total_size })); ), (StructValue, diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index de691b3a..f86907fb 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -85,6 +85,7 @@ struct Pattern (SplitTuple, struct { ::std::vector<Pattern> leading; ::std::vector<Pattern> trailing; + unsigned int total_size = 0; }), (StructValue, struct { GenericPath path; diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index c3e25c44..157ae6ae 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3494,13 +3494,68 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type } // TODO: Should this replace the pattern with a non-split? + // - Changing the address of the pattern means that the below revisit could fail. + e.total_size = te.size(); ) else { if( !ty.m_data.is_Infer() ) { ERROR(sp, E0000, "Tuple pattern on non-tuple"); } - TODO(sp, "Handle split tuple patterns when type isn't known in starting pass"); + ::std::vector<::HIR::TypeRef> leading_tys; + leading_tys.reserve(e.leading.size()); + for(auto& subpat : e.leading) { + leading_tys.push_back( this->m_ivars.new_ivar_tr() ); + this->add_binding(sp, subpat, leading_tys.back()); + } + ::std::vector<::HIR::TypeRef> trailing_tys; + for(auto& subpat : e.trailing) { + trailing_tys.push_back( this->m_ivars.new_ivar_tr() ); + this->add_binding(sp, subpat, trailing_tys.back()); + } + + struct SplitTuplePatRevisit: + public Revisitor + { + Span sp; + ::HIR::TypeRef m_outer_ty; + ::std::vector<::HIR::TypeRef> m_leading_tys; + ::std::vector<::HIR::TypeRef> m_trailing_tys; + unsigned int& m_pat_total_size; + + SplitTuplePatRevisit(Span sp, ::HIR::TypeRef outer, ::std::vector<::HIR::TypeRef> leading, ::std::vector<::HIR::TypeRef> trailing, unsigned int& pat_total_size): + sp(mv$(sp)), m_outer_ty(mv$(outer)), + m_leading_tys( mv$(leading) ), m_trailing_tys( mv$(trailing) ), + m_pat_total_size(pat_total_size) + {} + + void fmt(::std::ostream& os) const override { + os << "SplitTuplePatRevisit { " << m_outer_ty << " = (" << m_leading_tys << ", ..., " << m_trailing_tys << ") }"; + } + bool revisit(Context& context) override { + const auto& ty = context.get_type(m_outer_ty); + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te, + return false; + ) + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Tuple, te, + if( te.size() < m_leading_tys.size() + m_trailing_tys.size() ) + ERROR(sp, E0000, "Tuple pattern too large for tuple"); + for(unsigned int i = 0; i < m_leading_tys.size(); i ++) + context.equate_types(sp, te[i], m_leading_tys[i]); + unsigned int ofs = te.size() - m_trailing_tys.size(); + for(unsigned int i = 0; i < m_trailing_tys.size(); i ++) + context.equate_types(sp, te[ofs+i], m_trailing_tys[i]); + m_pat_total_size = te.size(); + return true; + ) + else { + ERROR(sp, E0000, "Tuple pattern on non-tuple - " << ty); + } + } + }; + + // Register a revisit and wait until the tuple is known - then bind through. + this->add_revisit_adv( box$(( SplitTuplePatRevisit { sp, ty.clone(), mv$(leading_tys), mv$(trailing_tys), e.total_size } )) ); } ), (Slice, diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index bd853e87..1edf7903 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -183,13 +183,15 @@ namespace { } ), (SplitTuple, + assert(e.total_size >= e.leading.size() + e.trailing.size()); for(unsigned int i = 0; i < e.leading.size(); i ++ ) { destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); } + unsigned int ofs = e.total_size - e.trailing.size(); for(unsigned int i = 0; i < e.trailing.size(); i ++ ) { - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable); } ), (StructValue, |