summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-10-01 15:37:45 +0800
committerJohn Hodge <tpg@mutabah.net>2016-10-01 15:37:45 +0800
commitddf6c491e0cedd196ef46b2f698965c45227c4f7 (patch)
tree19c0dc073b74a0318043c9ddcef2b15078b6d447
parente5a51fcee6b0fd19cba97ce5e5f37f6889258581 (diff)
downloadmrust-ddf6c491e0cedd196ef46b2f698965c45227c4f7.tar.gz
HIR Typecheck Expr - Better TraitObject trait searching, _CallValue extended
-rw-r--r--src/hir_typeck/expr_cs.cpp57
-rw-r--r--src/hir_typeck/helpers.cpp26
2 files changed, 64 insertions, 19 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 9d2af58e..8ecbfeb8 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -2089,6 +2089,11 @@ namespace {
return ;
}
+ const auto& lang_FnOnce = this->context.m_crate.get_lang_item_path(node.span(), "fn_once");
+ const auto& lang_FnMut = this->context.m_crate.get_lang_item_path(node.span(), "fn_mut");
+ const auto& lang_Fn = this->context.m_crate.get_lang_item_path(node.span(), "fn");
+
+
// 1. Create a param set with a single tuple (of all argument types)
::HIR::PathParams trait_pp;
{
@@ -2113,36 +2118,36 @@ namespace {
DEBUG("- ty = " << ty);
TU_MATCH_DEF(decltype(ty.m_data), (ty.m_data), (e),
(
- // Search for FnOnce impl
- const auto& lang_FnOnce = this->context.m_crate.get_lang_item_path(node.span(), "fn_once");
- const auto& lang_FnMut = this->context.m_crate.get_lang_item_path(node.span(), "fn_mut");
- const auto& lang_Fn = this->context.m_crate.get_lang_item_path(node.span(), "fn");
-
::HIR::TypeRef fcn_args_tup;
::HIR::TypeRef fcn_ret;
- // 2. Locate an impl of FnOnce (exists for all other Fn* traits)
- auto was_bounded = this->context.m_resolve.find_trait_impls_bound(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp) {
+ // TODO: Use `find_trait_impls` instead of two different calls
+ // - This will get the TraitObject impl search too
+
+ // Locate an impl of FnOnce (exists for all other Fn* traits)
+ unsigned int count = 0;
+ this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp) {
+ count ++;
+
auto tup = impl.get_trait_ty_param(0);
if( !tup.m_data.is_Tuple() )
ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup);
fcn_args_tup = mv$(tup);
- return true;
+
+ fcn_ret = impl.get_type("Output");
+ return cmp == ::HIR::Compare::Equal;
});
- if( was_bounded )
+ if( count > 1 ) {
+ return ;
+ }
+ if( count == 1 )
{
- // RV must be in a bound
- fcn_ret = ::HIR::TypeRef( ::HIR::Path(::HIR::Path::Data::make_UfcsKnown({
- box$( ty.clone() ),
- ::HIR::GenericPath(lang_FnOnce),
- "Output",
- {}
- })) );
- fcn_ret.m_data.as_Path().path.m_data.as_UfcsKnown().trait.m_params.m_types.push_back( fcn_args_tup.clone() );
// 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce)
// NOTE: Borrowing is added by the expansion to CallPath
- if( this->context.m_resolve.find_trait_impls_bound(node.span(), lang_Fn, trait_pp, ty, [&](auto , auto cmp) {
+ if( this->context.m_resolve.find_trait_impls(node.span(), lang_Fn, trait_pp, ty, [&](auto impl, auto cmp) {
+ // TODO: Take the value of `cmp` into account
+ fcn_ret = impl.get_type("Output");
return true;
//return cmp == ::HIR::Compare::Equal;
})
@@ -2151,7 +2156,9 @@ namespace {
DEBUG("-- Using Fn");
node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn;
}
- else if( this->context.m_resolve.find_trait_impls_bound(node.span(), lang_FnMut, trait_pp, ty, [&](auto , auto cmp) {
+ else if( this->context.m_resolve.find_trait_impls(node.span(), lang_FnMut, trait_pp, ty, [&](auto impl, auto cmp) {
+ // TODO: Take the value of `cmp` into account
+ fcn_ret = impl.get_type("Output");
return true;
//return cmp == ::HIR::Compare::Equal;
})
@@ -2165,6 +2172,18 @@ namespace {
DEBUG("-- Using FnOnce (default)");
node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnOnce;
}
+
+ // If the return type wasn't found in the impls, emit it as a UFCS
+ if( fcn_ret == ::HIR::TypeRef() )
+ {
+ fcn_ret = ::HIR::TypeRef( ::HIR::Path(::HIR::Path::Data::make_UfcsKnown({
+ box$( ty.clone() ),
+ // - Clone argument tuple, as it's stolen into cache below
+ ::HIR::GenericPath(lang_FnOnce, ::HIR::PathParams( fcn_args_tup.clone() )),
+ "Output",
+ {}
+ })) );
+ }
}
else TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Borrow, e,
deref_count ++;
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index ade4cf6d..3e76cb54 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -1177,6 +1177,31 @@ bool TraitResolution::find_trait_impls(const Span& sp,
}
}
+ // - Check if the desired trait is a supertrait of this.
+ // NOTE: `params` (aka des_params) is not used (TODO)
+ bool rv = false;
+ bool is_supertrait = this->find_named_trait_in_trait(sp, trait,params, *e.m_trait.m_trait_ptr, e.m_trait.m_path.m_path,e.m_trait.m_path.m_params, type,
+ [&](const auto& i_ty, const auto& i_params, const auto& i_assoc) {
+ // The above is just the monomorphised params and associated set. Comparison is still needed.
+ auto cmp = this->compare_pp(sp, i_params, params);
+ if( cmp != ::HIR::Compare::Unequal ) {
+ // Invoke callback with a proper ImplRef
+ ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone;
+ for(const auto& e : i_assoc)
+ assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) );
+ auto ir = ImplRef(i_ty.clone(), i_params.clone(), mv$(assoc_clone));
+ DEBUG("- ir = " << ir);
+ rv = callback(mv$(ir), cmp);
+ return true;
+ }
+ return false;
+ });
+ if( is_supertrait )
+ {
+ return rv;
+ }
+
+ // Trait objects can unsize to a subset of their traits.
if( trait == m_crate.get_lang_item_path(sp, "unsize") )
{
ASSERT_BUG(sp, params.m_types.size() == 1, "");
@@ -1761,6 +1786,7 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp,
DEBUG(pt << " => " << pt_mono);
if( pt.m_path.m_path == des ) {
+ // TODO: What if there's two bounds of the same trait with different params?
callback( target_type, pt_mono.m_path.m_params, pt_mono.m_type_bounds );
return true;
}