summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-08-03 11:10:53 +0800
committerJohn Hodge <tpg@mutabah.net>2016-08-03 11:23:55 +0800
commit8b7a6a120178305293318d0490f885d867c69783 (patch)
tree0f91966ae406230cec2d31ab7880f4fdc071ae66 /src
parentf74531bcbbd0de15996ff72d41132f89fd180509 (diff)
downloadmrust-8b7a6a120178305293318d0490f885d867c69783.tar.gz
HIR Typecheck - Trait object -> trait object coercions
Diffstat (limited to 'src')
-rw-r--r--src/hir_typeck/expr_cs.cpp81
-rw-r--r--src/hir_typeck/helpers.cpp53
-rw-r--r--src/hir_typeck/helpers.hpp2
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