diff options
author | John Hodge <tpg@mutabah.net> | 2016-10-02 16:59:59 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-10-02 16:59:59 +0800 |
commit | b5674644bdd2f2e9f1caa027632bed9e09af2f6f (patch) | |
tree | e6c41a430c6583bc8c00195449ce100232a28da2 | |
parent | c62444606070e7876a0c90d1e60c517ba5da8e02 (diff) | |
download | mrust-b5674644bdd2f2e9f1caa027632bed9e09af2f6f.tar.gz |
HIR Typecheck Expr - Handle use of slice/array patterns with arrays
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 126 |
1 files changed, 117 insertions, 9 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index bde64b7f..7d219e4c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -22,6 +22,13 @@ namespace { // PLAN: Build up a set of conditions that are easier to solve struct Context { + class Revisitor + { + public: + virtual void fmt(::std::ostream& os) const = 0; + virtual bool revisit(Context& context) = 0; + }; + struct Binding { ::std::string name; @@ -83,6 +90,8 @@ struct Context ::std::vector<Associated> link_assoc; /// Nodes that need revisiting (e.g. method calls when the receiver isn't known) ::std::vector< ::HIR::ExprNode*> to_visit; + /// Callback-based revisits (e.g. for slice patterns handling slices/arrays) + ::std::vector< ::std::unique_ptr<Revisitor> > adv_revisits; ::std::vector< IVarPossible> possible_ivar_vals; @@ -96,7 +105,7 @@ struct Context bool take_changed() { return m_ivars.take_changed(); } bool has_rules() const { - return link_coerce.size() > 0 || link_assoc.size() > 0 || to_visit.size() > 0; + return !(link_coerce.empty() && link_assoc.empty() && to_visit.empty() && adv_revisits.empty()); } inline void add_ivars(::HIR::TypeRef& ty) { @@ -142,6 +151,7 @@ struct Context // - Add a revisit entry void add_revisit(::HIR::ExprNode& node); + void add_revisit_adv(::std::unique_ptr<Revisitor> ent); const ::HIR::TypeRef& get_type(const ::HIR::TypeRef& ty) const { return m_ivars.get_type(ty); } @@ -2710,7 +2720,7 @@ void Context::dump() const { } DEBUG("--- Ivars"); m_ivars.dump(); - DEBUG("--- CS Context - " << link_coerce.size() << " Coercions, " << link_assoc.size() << " associated, " << to_visit.size() << " nodes"); + DEBUG("--- CS Context - " << link_coerce.size() << " Coercions, " << link_assoc.size() << " associated, " << to_visit.size() << " nodes, " << adv_revisits.size() << " callbacks"); for(const auto& v : link_coerce) { DEBUG(v); } @@ -2720,6 +2730,9 @@ void Context::dump() const { for(const auto& v : to_visit) { DEBUG(&*v << " " << typeid(*v).name() << " -> " << this->m_ivars.fmt_type(v->m_res_type)); } + for(const auto& v : adv_revisits) { + DEBUG(FMT_CB(ss, v->fmt(ss);)); + } DEBUG("---"); } @@ -3077,31 +3090,113 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type for(auto& sub : e.sub_patterns) this->add_binding(sp, sub, *te.inner ); ) - else { + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, + for(auto& sub : e.sub_patterns) + this->add_binding(sp, sub, *te.inner ); + ) + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te, auto inner = this->m_ivars.new_ivar_tr(); for(auto& sub : e.sub_patterns) this->add_binding(sp, sub, inner); - this->equate_types(sp, type, ::HIR::TypeRef::new_slice(mv$(inner))); + + struct SlicePatRevisit: + public Revisitor + { + Span sp; + ::HIR::TypeRef inner; + ::HIR::TypeRef type; + unsigned int size; + + SlicePatRevisit(Span sp, ::HIR::TypeRef inner, ::HIR::TypeRef type, unsigned int size): + sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), size(size) + {} + + void fmt(::std::ostream& os) const override { os << "SlicePatRevisit { " << inner << ", " << type << ", " << size; } + bool revisit(Context& context) override { + const auto& ty = context.get_type(type); + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, + context.equate_types(sp, *te.inner, inner); + return true; + ) + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, + if( te.size_val != size ) { + ERROR(sp, E0000, "Slice pattern on an array if differing size"); + } + context.equate_types(sp, *te.inner, inner); + return true; + ) + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te, + return false; + ) + else { + ERROR(sp, E0000, "Slice pattern on non-array/-slice - " << ty); + } + } + }; + this->add_revisit_adv( box$(( SlicePatRevisit { sp, mv$(inner), ty.clone(), static_cast<unsigned int>(e.sub_patterns.size()) } )) ); + ) + else { + ERROR(sp, E0000, "Slice pattern on non-array/-slice - " << ty); } ), (SplitSlice, ::HIR::TypeRef inner; + unsigned int min_len = e.leading.size() + e.trailing.size(); const auto& ty = this->get_type(type); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, inner = te.inner->clone(); + if( e.extra_bind.is_valid() ) { + this->add_var( e.extra_bind.m_slot, e.extra_bind.m_name, ty.clone() ); + } ) - else { + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, + inner = te.inner->clone(); + if( te.size_val < min_len ) { + ERROR(sp, E0000, "Slice pattern on an array smaller than the pattern"); + } + unsigned extra_len = te.size_val - min_len; + + if( e.extra_bind.is_valid() ) { + this->add_var( e.extra_bind.m_slot, e.extra_bind.m_name, ::HIR::TypeRef::new_array(inner.clone(), extra_len) ); + } + ) + else if( ty.m_data.is_Infer() ) { inner = this->m_ivars.new_ivar_tr(); - this->equate_types(sp, type, ::HIR::TypeRef::new_slice(inner.clone())); + ::HIR::TypeRef var_ty; + if( e.extra_bind.is_valid() ) { + var_ty = this->m_ivars.new_ivar_tr(); + this->add_var( e.extra_bind.m_slot, e.extra_bind.m_name, var_ty.clone() ); + } + + struct SplitSlicePatRevisit: + public Revisitor + { + Span sp; + ::HIR::TypeRef inner; + ::HIR::TypeRef type; + ::HIR::TypeRef var_ty; + unsigned int min_size; + + SplitSlicePatRevisit(Span sp, ::HIR::TypeRef inner, ::HIR::TypeRef type, ::HIR::TypeRef var_ty, unsigned int size): + sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), var_ty(mv$(var_ty)), min_size(size) + {} + + void fmt(::std::ostream& os) const override { os << "SplitSlice inner=" << inner << ", outer=" << type << ", binding="<<var_ty<<", " << min_size; } + bool revisit(Context& context) override { + TODO(sp, "SplitSlicePatRevisit"); + } + }; + // Callback + this->add_revisit_adv( box$(( SplitSlicePatRevisit { sp, inner.clone(), ty.clone(), mv$(var_ty), min_len } )) ); + } + else { + ERROR(sp, E0000, "Slice pattern on non-array/-slice - " << ty); } for(auto& sub : e.leading) this->add_binding( sp, sub, inner ); for(auto& sub : e.trailing) this->add_binding( sp, sub, inner ); - if( e.extra_bind.is_valid() ) { - this->add_var( e.extra_bind.m_slot, e.extra_bind.m_name, ty.clone() ); - } ), // - Enums/Structs @@ -3369,6 +3464,9 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const void Context::add_revisit(::HIR::ExprNode& node) { this->to_visit.push_back( &node ); } +void Context::add_revisit_adv(::std::unique_ptr<Revisitor> ent_ptr) { + this->adv_revisits.push_back( mv$(ent_ptr) ); +} void Context::possible_equate_type_to(unsigned int ivar_index, const ::HIR::TypeRef& t) { // TODO: If the other side is an ivar, add to the other list too @@ -4668,6 +4766,16 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: ++ it; } } + for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); ) + { + auto& ent = **it; + if( ent.revisit(context) ) { + it = context.adv_revisits.erase(it); + } + else { + ++ it; + } + } // If nothing changed this pass, apply ivar possibilities // - This essentially forces coercions not to happen. |