diff options
author | John Hodge <tpg@mutabah.net> | 2018-12-16 16:53:46 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-12-16 16:53:46 +0800 |
commit | f4c39e95caf3c9a8ccd302dbd9eca92b32564c27 (patch) | |
tree | 4311eda5b198f8ef9ade0ecf6ab130bb01559e5c /src | |
parent | 937b161b40dd6dfdaa0a55c1399b3af2d23227d7 (diff) | |
download | mrust-f4c39e95caf3c9a8ccd302dbd9eca92b32564c27.tar.gz |
Typecheck Expressions - Extended possibility checking, fallback default (HACK)
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_typeck/common.cpp | 21 | ||||
-rw-r--r-- | src/hir_typeck/common.hpp | 1 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 94 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 22 |
4 files changed, 110 insertions, 28 deletions
diff --git a/src/hir_typeck/common.cpp b/src/hir_typeck/common.cpp index 4b0328e7..1bb21f99 100644 --- a/src/hir_typeck/common.cpp +++ b/src/hir_typeck/common.cpp @@ -144,7 +144,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) } -::HIR::PathParams clone_ty_with__path_params(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) { +::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) { ::HIR::PathParams rv; rv.m_types.reserve( tpl.m_types.size() ); for( const auto& ty : tpl.m_types) @@ -152,7 +152,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) return rv; } ::HIR::GenericPath clone_ty_with__generic_path(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_clone_ty callback) { - return ::HIR::GenericPath( tpl.m_path, clone_ty_with__path_params(sp, tpl.m_params, callback) ); + return ::HIR::GenericPath( tpl.m_path, clone_path_params_with(sp, tpl.m_params, callback) ); } ::HIR::TraitPath clone_ty_with__trait_path(const Span& sp, const ::HIR::TraitPath& tpl, t_cb_clone_ty callback) { ::HIR::TraitPath rv { @@ -181,22 +181,22 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) box$( clone_ty_with(sp, *e2.type, callback) ), clone_ty_with__generic_path(sp, e2.trait, callback), e2.item, - clone_ty_with__path_params(sp, e2.params, callback) + clone_path_params_with(sp, e2.params, callback) }); ), (UfcsUnknown, return ::HIR::Path::Data::make_UfcsUnknown({ box$( clone_ty_with(sp, *e2.type, callback) ), e2.item, - clone_ty_with__path_params(sp, e2.params, callback) + clone_path_params_with(sp, e2.params, callback) }); ), (UfcsInherent, return ::HIR::Path::Data::make_UfcsInherent({ box$( clone_ty_with(sp, *e2.type, callback) ), e2.item, - clone_ty_with__path_params(sp, e2.params, callback), - clone_ty_with__path_params(sp, e2.impl_params, callback) + clone_path_params_with(sp, e2.params, callback), + clone_path_params_with(sp, e2.impl_params, callback) }); ) ) @@ -207,7 +207,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) ::HIR::TypeRef rv; if( callback(tpl, rv) ) { - DEBUG(tpl << " => " << rv); + //DEBUG(tpl << " => " << rv); return rv; } @@ -226,8 +226,9 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) clone_ty_with__path(sp, e.path, callback), e.binding.clone() } ); - // If the input binding was Opaque, clear it back to Unbound - if( e.binding.is_Opaque() ) { + // If the input binding was Opaque, AND the type changed, clear it back to Unbound + if( e.binding.is_Opaque() /*&& rv != tpl*/ ) { + // NOTE: The replacement can be Self=Self, which should trigger a binding clear. rv.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding(); } ), @@ -323,7 +324,7 @@ namespace { ::HIR::PathParams monomorphise_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer) { - return clone_ty_with__path_params(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer)); + return clone_path_params_with(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer)); } ::HIR::GenericPath monomorphise_genericpath_with(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer) { diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index 14d9162f..c0e495a6 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -38,6 +38,7 @@ extern bool visit_path_tys_with(const ::HIR::Path& ty, t_cb_visit_ty callback); typedef ::std::function<bool(const ::HIR::TypeRef&, ::HIR::TypeRef&)> t_cb_clone_ty; /// Clones a type, calling the provided callback on every type (optionally providing a replacement) extern ::HIR::TypeRef clone_ty_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_clone_ty callback); +extern ::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback); // Helper for passing a group of params around struct MonomorphState diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 23ac0afd..a7c5ddee 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2713,6 +2713,13 @@ namespace { // ivars (node.m_trait_param_ivars) for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1) { + if( it_1->first != possible_methods.front().first ) + { + it_1 = possible_methods.erase(it_1) - 1; + } + } + for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1) + { if( !it_1->second.m_data.is_UfcsKnown() ) continue; bool was_found = false; @@ -2727,10 +2734,17 @@ namespace { } const auto& e2 = it_2->second.m_data.as_UfcsKnown(); + // TODO: If the trait is the same, but the type differs, pick the first? + if( e1.trait == e2.trait ) { + DEBUG("Duplicate trait, different type - " << e1.trait << " for " << *e1.type << " or " << *e2.type << ", picking the first"); + it_2 = possible_methods.erase(it_2) - 1; + continue ; + } if( *e1.type != *e2.type ) continue; if( e1.trait.m_path != e2.trait.m_path ) continue; + assert( !(e1.trait.m_params == e2.trait.m_params) ); DEBUG("Duplicate trait in possible_methods - " << it_1->second << " and " << it_2->second); if( !was_found ) @@ -2745,11 +2759,8 @@ namespace { trait_params.m_types.push_back( ::HIR::TypeRef::new_infer(ivars[i], ::HIR::InferClass::None) ); //ASSERT_BUG(sp, m_ivars.get_type( trait_params.m_types.back() ).m_data.as_Infer().index == ivars[i], "A method selection ivar was bound"); } - // If one of these was already using the placeholder ivars, then maintain the other one? - if( e2.trait.m_params == trait_params ) - { - } - else + // If one of these was already using the placeholder ivars, then maintain the one with the palceholders + if( e1.trait.m_params != trait_params ) { e1.trait.m_params = mv$(trait_params); } @@ -2759,6 +2770,12 @@ namespace { } } } + assert( !possible_methods.empty() ); + if( possible_methods.size() != 1 && possible_methods.front().second.m_data.is_UfcsKnown() ) + { + DEBUG("- Multiple options, deferring"); + return; + } auto& ad_borrow = possible_methods.front().first; auto& fcn_path = possible_methods.front().second; DEBUG("- deref_count = " << deref_count << ", fcn_path = " << fcn_path); @@ -4261,7 +4278,6 @@ void Context::possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef list.push_back( t.clone() ); } void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::TypeRef& t) { - DEBUG(ivar_index << " bounded as " << t << " " << this->m_ivars.get_type(t)); { ::HIR::TypeRef ty_l; ty_l.m_data.as_Infer().index = ivar_index; @@ -4278,9 +4294,21 @@ void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::T } auto& ent = possible_ivar_vals[ivar_index]; for(const auto& e : ent.bounded) + { if( e == t ) + { + if( t.m_data.is_Infer() ) + DEBUG(ivar_index << " duplicate bounded " << t << " " << this->m_ivars.get_type(t)); + else + DEBUG(ivar_index << " duplicate bounded " << t); return ; + } + } ent.bounded.push_back( t.clone() ); + if( t.m_data.is_Infer() ) + DEBUG(ivar_index << " bounded as " << t << " " << this->m_ivars.get_type(t)); + else + DEBUG(ivar_index << " bounded as " << t); } void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) { DEBUG(ivar_index << " ?= ?? (" << (is_to ? "to" : "from") << ")"); @@ -5593,17 +5621,49 @@ namespace { { for(const auto& bound : context.link_assoc) { - // TODO: Monomorphise this type replacing mentions of the current ivar with the replacement? - if( bound.impl_ty != ty_l ) - continue ; + bool used_ty = false; + auto cb = [&](const ::HIR::TypeRef& ty, ::HIR::TypeRef& out_ty){ if( ty == ty_l ) { out_ty = new_ty.clone(); used_ty = true; return true; } else { return false; }}; + auto t = clone_ty_with(sp, bound.impl_ty, cb); + auto p = clone_path_params_with(sp, bound.params, cb); + if(!used_ty) + continue; + // - Run EAT on t and p + t = context.m_resolve.expand_associated_types( sp, mv$(t) ); + // TODO: EAT on `p` + DEBUG("Check " << t << " : " << bound.trait << p); + DEBUG("- From " << bound.impl_ty << " : " << bound.trait << bound.params); // Search for any trait impl that could match this, - bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;}); - if( !has ) { + bool bound_failed = true; + context.m_resolve.find_trait_impls(sp, bound.trait, p, t, [&](const auto impl, auto cmp){ + // If this bound specifies an associated type, then check that that type could match + if( bound.name != "" ) + { + auto aty = impl.get_type(bound.name.c_str()); + if( aty == ::HIR::TypeRef() ) { + // A possible match was found, so don't delete just yet + bound_failed = false; + // - Return false to keep searching + return false; + } + else if( aty.compare_with_placeholders(sp, bound.left_ty, context.m_ivars.callback_resolve_infer()) == HIR::Compare::Unequal ) { + bound_failed = true; + // - Bail instantly + return true; + } + else { + } + } + bound_failed = false; + return true; + }); + if( bound_failed ) { // If none was found, remove from the possibility list DEBUG("Remove possibility " << new_ty << " because it failed a bound"); return true; } + + // TODO: Check for the resultant associated type } // Handle methods @@ -6276,8 +6336,9 @@ namespace { if( !ivar_ent.bounded.empty() ) { // TODO: Search know possibilties and check if they satisfy the bounds for this ivar + DEBUG("Options: " << ivar_ent.bounded); unsigned int n_good = 0; - const ::HIR::TypeRef* only_good; + const ::HIR::TypeRef* only_good = nullptr; for(const auto& new_ty : ivar_ent.bounded) { DEBUG("- Test " << new_ty << " against current rules"); @@ -6287,11 +6348,14 @@ namespace { else { n_good ++; - only_good = &new_ty; + if( !only_good ) + only_good = &new_ty; DEBUG("> " << new_ty << " feasible"); } } - if(n_good == 1 + // Picks the first if in fallback mode (which is signalled by `honour_disable` being false) + // - This handles the case where there's multiple valid options (needed for libcompiler_builtins) + if( (honour_disable ? n_good == 1 : n_good > 0) && ivar_ent.types_coerce_from.size() == 0 && ivar_ent.types_coerce_to.size() == 0 && ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0 ) @@ -6635,7 +6699,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: const auto& sp = node->span(); if( const auto* np = dynamic_cast<::HIR::ExprNode_CallMethod*>(node) ) { - WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method); + WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method << " -> " << context.m_ivars.fmt_type(np->m_res_type)); } else { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 27728dbe..b353e6a7 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2247,7 +2247,7 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, { auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false); - DEBUG(pt << " => " << pt_mono); + //DEBUG(pt << " => " << pt_mono); if( pt.m_path.m_path == des ) { // NOTE: Doesn't quite work... //auto cmp = this->compare_pp(sp, pt_mono.m_path.m_params, des_params); @@ -3890,6 +3890,7 @@ bool TraitResolution::find_method(const Span& sp, method_name, {} }) ) )); + DEBUG("++ " << possibilities.back()); rv = true; } else if( cmp == ::HIR::Compare::Fuzzy ) @@ -3904,6 +3905,7 @@ bool TraitResolution::find_method(const Span& sp, method_name, {} }) ) )); + DEBUG("++ " << possibilities.back()); rv = true; } else @@ -3959,6 +3961,7 @@ bool TraitResolution::find_method(const Span& sp, if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -3981,6 +3984,7 @@ bool TraitResolution::find_method(const Span& sp, if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -4039,6 +4043,7 @@ bool TraitResolution::find_method(const Span& sp, // Found the method, return the UFCS path for it possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -4077,6 +4082,7 @@ bool TraitResolution::find_method(const Span& sp, // Found the method, return the UFCS path for it possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -4104,6 +4110,7 @@ bool TraitResolution::find_method(const Span& sp, if( *self_ty_p == *cur_check_ty ) { possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), method_name, {}) )); + DEBUG("++ " << possibilities.back()); return true; } } @@ -4156,10 +4163,19 @@ bool TraitResolution::find_method(const Span& sp, // TODO: Re-monomorphise the trait path! - //if( find_trait_impls(sp, *trait_ref.first, trait_params, self_ty, [](auto , auto ) { return true; }) ) { - if( find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [](auto , auto ) { return true; }) ) { + bool magic_found = false; + bool crate_impl_found = false; + // NOTE: THis just detects the presence of a trait impl, not the specifics + find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [&](auto impl, auto cmp) { + DEBUG("[find_method] " << impl << ", cmp = " << cmp); + magic_found = true; + crate_impl_found = true; + return true; + }); + if( crate_impl_found ) { DEBUG("Found trait impl " << *trait_ref.first << trait_params << " for " << self_ty << " ("<<m_ivars.fmt_type(self_ty)<<")"); possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty.clone(), ::HIR::GenericPath( *trait_ref.first, mv$(trait_params) ), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } |