From 1806e3626bd756811ab9cbbba8ee8d418089a0a7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 22 Oct 2016 19:22:16 +0800 Subject: HIR Typecheck Expr - Error earlier if an impl can't be found --- src/hir/type.cpp | 30 +++++++++++++++++++++++++++++- src/hir_typeck/expr_cs.cpp | 14 ++++++++++---- src/hir_typeck/helpers.cpp | 46 ++++++++++++++++++++++++++++++---------------- src/main.cpp | 4 ++++ 4 files changed, 73 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 6f465c44..812e01e4 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -575,6 +575,11 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x DEBUG("- Fuzzy match due to opaque"); return Compare::Fuzzy; } + // HACK: If RHS is unbound, fuzz it + if( x.m_data.is_Path() && x.m_data.as_Path().binding.is_Unbound() ) { + DEBUG("- Fuzzy match due to unbound"); + return Compare::Fuzzy; + } // HACK: If the RHS is a placeholder generic, allow it. if( x.m_data.is_Generic() && (x.m_data.as_Generic().binding >> 8) == 2 ) { DEBUG("- Fuzzy match due to placeholder"); @@ -854,6 +859,9 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return Compare::Unequal; } ) + else TU_IFLET(::HIR::TypeRef::Data, right.m_data, Path, oe, + return oe.binding.is_Unbound() ? Compare::Fuzzy : Compare::Unequal; + ) else { return Compare::Unequal; } @@ -879,6 +887,9 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return Compare::Unequal; } ) + else TU_IFLET(::HIR::TypeRef::Data, right.m_data, Path, oe, + return oe.binding.is_Unbound() ? Compare::Fuzzy : Compare::Unequal; + ) else { return Compare::Unequal; } @@ -907,6 +918,9 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return Compare::Unequal; } ) + else TU_IFLET(::HIR::TypeRef::Data, left.m_data, Path, oe, + return oe.binding.is_Unbound() ? Compare::Fuzzy : Compare::Unequal; + ) else { return Compare::Unequal; } @@ -921,6 +935,9 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return Compare::Unequal; } ) + else TU_IFLET(::HIR::TypeRef::Data, left.m_data, Path, oe, + return oe.binding.is_Unbound() ? Compare::Fuzzy : Compare::Unequal; + ) else { return Compare::Unequal; } @@ -938,6 +955,12 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x if( right.m_data.is_Path() && right.m_data.as_Path().binding.is_Unbound() ) { return Compare::Fuzzy; } + if( left.m_data.is_Generic() && (left.m_data.as_Generic().binding >> 8) == 2 ) { + return Compare::Fuzzy; + } + if( right.m_data.is_Generic() && (right.m_data.as_Generic().binding >> 8) == 2 ) { + return Compare::Fuzzy; + } return Compare::Unequal; } TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re), @@ -952,8 +975,13 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return le.path.compare_with_placeholders( sp, re.path, resolve_placeholder ); ), (Generic, - if( le.binding != re.binding ) + if( le.binding != re.binding ) { + if( (le.binding >> 8) == 2 ) + return Compare::Fuzzy; + if( (re.binding >> 8) == 2 ) + return Compare::Fuzzy; return Compare::Unequal; + } return Compare::Equal; ), (TraitObject, diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index b0d8f0b5..14b40cc8 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4579,13 +4579,19 @@ namespace { // No applicable impl // - TODO: This should really only fire when there isn't an impl. But it currently fires when _ DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty)); - //bool is_known = !context.get_type(v.impl_ty).m_data.is_Infer(); - bool is_known = !context.m_ivars.type_contains_ivars(v.impl_ty); - for(const auto& t : v.params.m_types) - is_known &= !context.m_ivars.type_contains_ivars(t); + + const auto& ty = context.get_type(v.impl_ty); + bool is_known = !ty.m_data.is_Infer() && !(ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound()); + //bool is_known = !context.m_ivars.type_contains_ivars(v.impl_ty); + //for(const auto& t : v.params.m_types) + // is_known &= !context.m_ivars.type_contains_ivars(t); if( is_known ) { ERROR(sp, E0000, "Failed to find an impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty)); } + + //if( v.trait == context.m_crate.get_lang_item_path(sp, "unsize") ) + //{ + //} return false; } else if( count == 1 ) { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index ccedfb07..500f6b79 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1897,30 +1897,40 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple assoc_info = &pe; ) ) + + if( m_ivars.get_type(type).m_data.is_Infer() ) + return false; // TODO: A bound can imply something via its associated types. How deep can this go? // E.g. `T: IntoIterator` implies `::IntoIter : Iterator` return this->iterate_bounds([&](const auto& b) { TU_IFLET(::HIR::GenericBound, b, TraitBound, e, const auto& b_params = e.trait.m_path.m_params; + + auto cmp = e.type .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer()); + if( cmp == ::HIR::Compare::Unequal ) + return false; + + if( e.trait.m_path.m_path == trait ) { + // Check against `params` + DEBUG("Checking " << params << " vs " << b_params); + auto ord = cmp; + ord &= this->compare_pp(sp, b_params, params); + if( ord == ::HIR::Compare::Unequal ) + return false; + if( ord == ::HIR::Compare::Fuzzy ) { + DEBUG("Fuzzy match"); + } + // Hand off to the closure, and return true if it does + // TODO: The type bounds are only the types that are specified. + if( callback( ImplRef(&e.type, &e.trait.m_path.m_params, &e.trait.m_type_bounds), ord) ) { + return true; + } + } + // TODO: Allow fuzzy equality? - if( e.type == type ) + if( cmp == ::HIR::Compare::Equal ) { - if( e.trait.m_path.m_path == trait ) { - // Check against `params` - DEBUG("Checking " << params << " vs " << b_params); - auto ord = this->compare_pp(sp, b_params, params); - if( ord == ::HIR::Compare::Unequal ) - return false; - if( ord == ::HIR::Compare::Fuzzy ) { - DEBUG("Fuzzy match"); - } - // Hand off to the closure, and return true if it does - // TODO: The type bounds are only the types that are specified. - if( callback( ImplRef(&e.type, &e.trait.m_path.m_params, &e.trait.m_type_bounds), ord) ) { - return true; - } - } // HACK: The wrapping closure takes associated types from this bound and applies them to the returned set // - XXX: This is actually wrong (false-positive) in many cases. FIXME bool rv = this->find_named_trait_in_trait(sp, @@ -2416,6 +2426,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, const auto& real_trait_path = real_trait.m_path; DEBUG("[find_trait_impls_crate] - bound mono " << real_type << " : " << real_trait); bool found_fuzzy_match = false; + if( real_type.m_data.is_Path() && real_type.m_data.as_Path().binding.is_Unbound() ) { + DEBUG("- Bounded type is unbound UFCS, assuming fuzzy match"); + found_fuzzy_match = true; + } auto rv = this->find_trait_impls(sp, real_trait_path.m_path, real_trait_path.m_params, real_type, [&](auto impl, auto impl_cmp) { auto cmp = impl_cmp; for(const auto& assoc_bound : real_trait.m_type_bounds) { diff --git a/src/main.cpp b/src/main.cpp index b8ba315d..24a5ad57 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -312,6 +312,10 @@ int main(int argc, char *argv[]) ConvertHIR_ConstantEvaluate(*hir_crate); }); + CompilePhaseV("Dump HIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); + HIR_Dump( os, *hir_crate ); + }); // === Type checking === // - This can recurse and call the MIR lower to evaluate constants -- cgit v1.2.3