diff options
author | John Hodge <tpg@mutabah.net> | 2016-08-03 11:10:53 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-08-03 11:23:55 +0800 |
commit | 8b7a6a120178305293318d0490f885d867c69783 (patch) | |
tree | 0f91966ae406230cec2d31ab7880f4fdc071ae66 /src | |
parent | f74531bcbbd0de15996ff72d41132f89fd180509 (diff) | |
download | mrust-8b7a6a120178305293318d0490f885d867c69783.tar.gz |
HIR Typecheck - Trait object -> trait object coercions
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 81 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 53 | ||||
-rw-r--r-- | src/hir_typeck/helpers.hpp | 2 |
3 files changed, 113 insertions, 23 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 78c5bd5e..2bf0d083 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2739,6 +2739,35 @@ void fix_param_count(const Span& sp, Context& context, const ::HIR::GenericPath& } namespace { + void add_coerce_borrow(Context& context, ::HIR::ExprNodeP& node_ptr, const ::HIR::TypeRef& des_borrow_inner, ::std::function<void(::HIR::ExprNodeP& n)> cb) + { + // Since this function operates on destructured &-ptrs, the dereferences have to be added behind a borrow + ::HIR::ExprNodeP* node_ptr_ptr = nullptr; + // - If the pointed node is a borrow operation, add the dereferences within its value + if( auto* p = dynamic_cast< ::HIR::ExprNode_UniOp*>(&*node_ptr) ) { + if( p->m_op == ::HIR::ExprNode_UniOp::Op::Ref || p->m_op == ::HIR::ExprNode_UniOp::Op::RefMut ) { + node_ptr_ptr = &p->m_value; + } + } + // - Otherwise, create a new borrow operation and add the dereferences + if( !node_ptr_ptr ) { + auto span = node_ptr->span(); + node_ptr_ptr = &node_ptr; + ::HIR::ExprNode_UniOp::Op op = ::HIR::ExprNode_UniOp::Op::Ref; + auto borrow_type = context.m_ivars.get_type(node_ptr->m_res_type).m_data.as_Borrow().type; + switch(borrow_type) + { + case ::HIR::BorrowType::Shared: op = ::HIR::ExprNode_UniOp::Op::Ref; break; + case ::HIR::BorrowType::Unique: op = ::HIR::ExprNode_UniOp::Op::RefMut; break; + case ::HIR::BorrowType::Owned: TODO(sp, "Move borrow autoderef"); + } + node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_UniOp( mv$(span), op, mv$(node_ptr) )); + node_ptr->m_res_type = ::HIR::TypeRef::new_borrow(borrow_type, des_borrow_inner.clone()); + } + + cb(*node_ptr_ptr); + } + bool check_coerce_borrow(Context& context, const ::HIR::TypeRef& inner_l, const ::HIR::TypeRef& inner_r, ::HIR::ExprNodeP& node_ptr) { const auto& sp = node_ptr->span(); @@ -2894,15 +2923,38 @@ namespace { DEBUG("TraitObject coerce from - cmp="<<cmp<<", " << impl); return cmp == ::HIR::Compare::Equal; }); - if( found ) { - // TODO: Add CoerceUnsized - context.m_ivars.mark_change(); - return true; + if( !found ) { + if( !context.m_ivars.type_contains_ivars(ty_src) ) { + // TODO: Error + ERROR(sp, E0000, "The trait " << e.m_trait << " is not implemented for " << ty_src); + } + return false; } - if( !ty_src.m_data.is_Infer() ) { - // TODO: Error + + for(const auto& marker : e.m_markers) + { + bool found = context.m_resolve.find_trait_impls(sp, marker.m_path, marker.m_params, ty_src, [&](auto impl, auto cmp) { + DEBUG("TraitObject coerce from - cmp="<<cmp<<", " << impl); + return cmp == ::HIR::Compare::Equal; + }); + if( !found ) { + if( !context.m_ivars.type_contains_ivars(ty_src) ) { + // TODO: Error + ERROR(sp, E0000, "The trait " << marker << " is not implemented for " << ty_src); + } + return false; + } } - return false; + + // Add CoerceUnsized + //{ + // auto span = node_ptr->span(); + // node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) )); + // DEBUG("- Deref " << &*node_ptr << " -> " << dst_type); + // node_ptr->m_res_type = mv$(ty); + //} + context.m_ivars.mark_change(); + return true; ) ) @@ -2920,6 +2972,21 @@ namespace { // return true; ) ) + + // Search for Unsize + { + const auto& lang_Unsize = context.m_resolve.m_crate.get_lang_item_path(sp, "unsize"); + ::HIR::PathParams pp; + pp.m_types.push_back( ty_dst.clone() ); + bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, ty_src, [&](auto impl, auto cmp) { + return cmp == ::HIR::Compare::Equal; + }); + if( found ) { + context.m_ivars.mark_change(); + return true; + } + } + DEBUG("TODO - Borrow Coercion " << context.m_ivars.fmt_type(ty_dst) << " from " << context.m_ivars.fmt_type(ty_src)); return false; } diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 6f3edf0c..dec6151d 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2,7 +2,6 @@ #include "helpers.hpp" #include "expr_simple.hpp" - bool monomorphise_type_needed(const ::HIR::TypeRef& tpl); bool monomorphise_pathparams_needed(const ::HIR::PathParams& tpl) @@ -1032,6 +1031,18 @@ void TraitResolution::prep_indexes() } +::HIR::Compare TraitResolution::compare_pp(const Span& sp, const ::HIR::PathParams& left, const ::HIR::PathParams& right) const +{ + ASSERT_BUG( sp, left.m_types.size() == right.m_types.size(), "Parameter count mismatch" ); + ::HIR::Compare ord = ::HIR::Compare::Equal; + for(unsigned int i = 0; i < left.m_types.size(); i ++) { + ord &= left.m_types[i].compare_with_placeholders(sp, right.m_types[i], this->m_ivars.callback_resolve_infer()); + if( ord == ::HIR::Compare::Unequal ) + return ord; + } + return ord; +} + // ------------------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------- @@ -1185,6 +1196,28 @@ bool TraitResolution::find_trait_impls(const Span& sp, // Continue ) + // Trait objects automatically implement their own traits + // - IF object safe (TODO) + TU_IFLET(::HIR::TypeRef::Data, type.m_data, TraitObject, e, + if( trait == e.m_trait.m_path.m_path ) { + auto cmp = compare_pp(sp, e.m_trait.m_path.m_params, params); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &e.m_trait.m_path.m_params, &e.m_trait.m_type_bounds), cmp ); + } + } + // Markers too + for( const auto& mt : e.m_markers ) + { + if( trait == mt.m_path ) { + auto cmp = compare_pp(sp, mt.m_params, params); + if( cmp != ::HIR::Compare::Unequal ) { + static ::std::map< ::std::string, ::HIR::TypeRef> types; + return callback( ImplRef(&type, &mt.m_params, &types), cmp ); + } + } + } + ) + // 1. Search generic params if( find_trait_impls_bound(sp, trait, params, type, callback) ) return true; @@ -1684,18 +1717,6 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, } bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const { - struct H { - static ::HIR::Compare compare_pp(const Span& sp, const TraitResolution& self, const ::HIR::PathParams& left, const ::HIR::PathParams& right) { - ASSERT_BUG( sp, left.m_types.size() == right.m_types.size(), "Parameter count mismatch" ); - ::HIR::Compare ord = ::HIR::Compare::Equal; - for(unsigned int i = 0; i < left.m_types.size(); i ++) { - ord &= left.m_types[i].compare_with_placeholders(sp, right.m_types[i], self.m_ivars.callback_resolve_infer()); - if( ord == ::HIR::Compare::Unequal ) - return ord; - } - return ord; - } - }; const ::HIR::Path::Data::Data_UfcsKnown* assoc_info = nullptr; TU_IFLET(::HIR::TypeRef::Data, type.m_data, Path, e, TU_IFLET(::HIR::Path::Data, e.path.m_data, UfcsKnown, pe, @@ -1715,7 +1736,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple if( e.trait.m_path.m_path == trait ) { // Check against `params` DEBUG("Checking " << params << " vs " << b_params); - auto ord = H::compare_pp(sp, *this, b_params, params); + auto ord = this->compare_pp(sp, b_params, params); if( ord == ::HIR::Compare::Unequal ) return false; if( ord == ::HIR::Compare::Fuzzy ) { @@ -1756,7 +1777,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple // TODO: This just checks a single layer, but it's feasable that there could be multiple layers if( assoc_info && e.trait.m_path.m_path == assoc_info->trait.m_path && e.type == *assoc_info->type ) { // Check the trait params - auto ord = H::compare_pp(sp, *this, b_params, assoc_info->trait.m_params); + auto ord = this->compare_pp(sp, b_params, assoc_info->trait.m_params); if( ord == ::HIR::Compare::Fuzzy ) { TODO(sp, "Handle fuzzy matches searching for associated type bounds"); } @@ -1766,7 +1787,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple for(const auto& bound : at.m_trait_bounds) { if( bound.m_path.m_path == trait ) { DEBUG("- Found an associated type impl"); - auto ord = H::compare_pp(sp, *this, b_params, params); + auto ord = this->compare_pp(sp, b_params, params); if( ord == ::HIR::Compare::Unequal ) return false; if( ord == ::HIR::Compare::Fuzzy ) { diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index d5f7e94f..478d89c5 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -159,6 +159,8 @@ public: void prep_indexes(); + ::HIR::Compare compare_pp(const Span& sp, const ::HIR::PathParams& left, const ::HIR::PathParams& right) const; + void compact_ivars(HMTypeInferrence& m_ivars); /// Check if a trait bound applies, using the passed function to expand Generic/Infer types |