diff options
author | John Hodge <tpg@mutabah.net> | 2016-10-01 15:37:45 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-10-01 15:37:45 +0800 |
commit | ddf6c491e0cedd196ef46b2f698965c45227c4f7 (patch) | |
tree | 19c0dc073b74a0318043c9ddcef2b15078b6d447 | |
parent | e5a51fcee6b0fd19cba97ce5e5f37f6889258581 (diff) | |
download | mrust-ddf6c491e0cedd196ef46b2f698965c45227c4f7.tar.gz |
HIR Typecheck Expr - Better TraitObject trait searching, _CallValue extended
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 57 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 26 |
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; } |