summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir/pattern.cpp3
-rw-r--r--src/hir/pattern.hpp1
-rw-r--r--src/hir_typeck/expr_cs.cpp57
-rw-r--r--src/mir/from_hir.cpp4
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,