From 36e67e675aec3e488cd4ad07cbe81d2ec5150a04 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 20:09:54 +0800 Subject: Resolve UFCS - Fix non-wrapped marker impls --- src/hir_conv/resolve_ufcs.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/hir_conv/resolve_ufcs.cpp') diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 55fbf593..5481fbb9 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -91,6 +91,25 @@ namespace { auto _g = m_resolve.set_impl_generics(impl.m_params); ::HIR::Visitor::visit_type_impl(impl); } + void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override { + ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) ); + auto _g = m_resolve.set_impl_generics(impl.m_params); + + // TODO: Push a bound that `Self: ThisTrait` + m_current_type = &impl.m_type; + m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path); + m_current_trait_path = &p; + + // The implemented trait is always in scope + m_traits.push_back( ::std::make_pair( &trait_path, m_current_trait) ); + ::HIR::Visitor::visit_marker_impl(trait_path, impl); + m_traits.pop_back( ); + + m_current_trait = nullptr; + m_current_type = nullptr; + } void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); -- cgit v1.2.3 From 22afa5803a6b5466168f281f484826177e89128e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 Jan 2019 22:17:20 +0800 Subject: HIR Typecheck Outer - Duplicate the "Resolve UFCS" pass to use simpler logic for outer context --- Makefile | 4 +- src/hir_conv/main_bindings.hpp | 1 + src/hir_conv/resolve_ufcs.cpp | 9 + src/hir_conv/resolve_ufcs_outer.cpp | 345 ++++++++++++++++++++++++++++++++++++ src/hir_typeck/static.cpp | 19 +- src/main.cpp | 11 ++ 6 files changed, 382 insertions(+), 7 deletions(-) create mode 100644 src/hir_conv/resolve_ufcs_outer.cpp (limited to 'src/hir_conv/resolve_ufcs.cpp') diff --git a/Makefile b/Makefile index 29a8e39e..3eb72d0f 100644 --- a/Makefile +++ b/Makefile @@ -97,7 +97,7 @@ OBJ += hir/hir.o hir/generic_params.o OBJ += hir/crate_ptr.o hir/expr_ptr.o OBJ += hir/type.o hir/path.o hir/expr.o hir/pattern.o OBJ += hir/visitor.o hir/crate_post_load.o -OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/bind.o hir_conv/markings.o +OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/resolve_ufcs_outer.o hir_conv/bind.o hir_conv/markings.o OBJ += hir_typeck/outer.o hir_typeck/common.o hir_typeck/helpers.o hir_typeck/static.o hir_typeck/impl_ref.o OBJ += hir_typeck/expr_visit.o OBJ += hir_typeck/expr_cs.o @@ -222,7 +222,7 @@ rust_tests: RUST_TESTS_run-pass .PHONY: RUST_TESTS RUST_TESTS_run-pass RUST_TESTS: RUST_TESTS_run-pass -RUST_TESTS_run-pass: output/librust_test_helpers.a +RUST_TESTS_run-pass: @$(MAKE) -C tools/testrunner @mkdir -p output/rust_tests/run-pass ./tools/bin/testrunner -o output/rust_tests/run-pass $(RUST_TESTS_DIR)run-pass --exceptions disabled_tests_run-pass.txt diff --git a/src/hir_conv/main_bindings.hpp b/src/hir_conv/main_bindings.hpp index 37488dae..e2ec3e34 100644 --- a/src/hir_conv/main_bindings.hpp +++ b/src/hir_conv/main_bindings.hpp @@ -13,6 +13,7 @@ namespace HIR { extern void ConvertHIR_ExpandAliases(::HIR::Crate& crate); extern void ConvertHIR_Bind(::HIR::Crate& crate); +extern void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate); extern void ConvertHIR_ResolveUFCS(::HIR::Crate& crate); extern void ConvertHIR_Markings(::HIR::Crate& crate); extern void ConvertHIR_ConstantEvaluate(::HIR::Crate& hir_crate); diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 5481fbb9..9bdb2feb 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -5,6 +5,8 @@ * hir_conv/resolve_ufcs.cpp * - Resolve unkown UFCS traits into inherent or trait * - HACK: Will likely be replaced with a proper typeck pass (no it won't) + * + * - TODO: What are the rules for UFCS lookup? */ #include "main_bindings.hpp" #include @@ -115,6 +117,13 @@ namespace { TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) ); auto _g = m_resolve.set_impl_generics(impl.m_params); + // TODO: Handle resolution of all items in m_resolve.m_type_equalities + // - params might reference each other, so `set_item_generics` has to have been called + // - But `m_type_equalities` can end up with non-resolved UFCS paths + for(auto& e : m_resolve.m_type_equalities) + { + visit_type(e.second); + } // TODO: Push a bound that `Self: ThisTrait` m_current_type = &impl.m_type; diff --git a/src/hir_conv/resolve_ufcs_outer.cpp b/src/hir_conv/resolve_ufcs_outer.cpp new file mode 100644 index 00000000..a8accf4d --- /dev/null +++ b/src/hir_conv/resolve_ufcs_outer.cpp @@ -0,0 +1,345 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * hir_conv/resolve_ufcs_outer.cpp + * - Resolve UfcsUnknown paths in outer scope (signatures/types) + * + * RULES: + * - Only generics are allowed to be UfcsKnown in signatures/types (within bodies anything goes?) + */ +#include "main_bindings.hpp" +#include +#include +#include +#include // monomorphise_genericpath_needed + +namespace { + class Visitor: + public ::HIR::Visitor + { + const ::HIR::Crate& m_crate; + + const ::HIR::GenericParams* m_params_impl = nullptr; + const ::HIR::GenericParams* m_params_method = nullptr; + + const ::HIR::TypeRef* m_current_type = nullptr; // used because sometimes `Self` is already replaced + const ::HIR::Trait* m_current_trait = nullptr; + const ::HIR::ItemPath* m_current_trait_path = nullptr; + + public: + Visitor(const ::HIR::Crate& crate): + m_crate(crate) + {} + + void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override { + m_params_method = &item.m_params; + ::HIR::Visitor::visit_struct(p, item); + m_params_method = nullptr; + } + void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { + m_params_method = &item.m_params; + ::HIR::Visitor::visit_enum(p, item); + m_params_method = nullptr; + } + void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override { + m_params_method = &item.m_params; + ::HIR::Visitor::visit_function(p, item); + m_params_method = nullptr; + } + void visit_type_alias(::HIR::ItemPath p, ::HIR::TypeAlias& item) override { + // NOTE: Disabled, becuase generics in type aliases are never checked +#if 0 + auto _ = m_resolve.set_item_generics(item.m_params); + ::HIR::Visitor::visit_function(p, item); +#endif + } + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& trait) override { + m_params_impl = &trait.m_params; + m_current_trait = &trait; + m_current_trait_path = &p; + ::HIR::Visitor::visit_trait(p, trait); + m_current_trait = nullptr; + m_params_impl = nullptr; + } + void visit_type_impl(::HIR::TypeImpl& impl) override { + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + m_params_impl = &impl.m_params; + m_current_type = &impl.m_type; + ::HIR::Visitor::visit_type_impl(impl); + m_current_type = nullptr; + m_params_impl = nullptr; + } + void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override { + ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + + m_params_impl = &impl.m_params; + m_current_type = &impl.m_type; + m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path); + m_current_trait_path = &p; + + ::HIR::Visitor::visit_marker_impl(trait_path, impl); + + m_current_trait = nullptr; + m_current_type = nullptr; + m_params_impl = nullptr; + } + void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { + ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + + m_params_impl = &impl.m_params; + m_current_type = &impl.m_type; + m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path); + m_current_trait_path = &p; + + ::HIR::Visitor::visit_trait_impl(trait_path, impl); + + m_current_trait = nullptr; + m_current_type = nullptr; + m_params_impl = nullptr; + } + + void visit_expr(::HIR::ExprPtr& expr) override + { + // No inner visiting for expressions + } + + bool locate_trait_item_in_bounds(::HIR::Visitor::PathContext pc, const ::HIR::TypeRef& tr, const ::HIR::GenericParams& params, ::HIR::Path::Data& pd) { + static Span sp; + //const auto& name = pd.as_UfcsUnknown().item; + for(const auto& b : params.m_bounds) + { + TU_IFLET(::HIR::GenericBound, b, TraitBound, e, + DEBUG("- " << e.type << " : " << e.trait.m_path); + if( e.type == tr ) { + DEBUG(" - Match"); + if( locate_in_trait_and_set(pc, e.trait.m_path, m_crate.get_trait_by_path(sp, e.trait.m_path.m_path), pd) ) { + return true; + } + } + ); + // - + } + return false; + } + static ::HIR::Path::Data get_ufcs_known(::HIR::Path::Data::Data_UfcsUnknown e, ::HIR::GenericPath trait_path, const ::HIR::Trait& trait) + { + return ::HIR::Path::Data::make_UfcsKnown({ mv$(e.type), mv$(trait_path), mv$(e.item), mv$(e.params)} ); + } + static bool locate_item_in_trait(::HIR::Visitor::PathContext pc, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) + { + const auto& e = pd.as_UfcsUnknown(); + + switch(pc) + { + case ::HIR::Visitor::PathContext::VALUE: + if( trait.m_values.find( e.item ) != trait.m_values.end() ) { + return true; + } + break; + case ::HIR::Visitor::PathContext::TRAIT: + break; + case ::HIR::Visitor::PathContext::TYPE: + if( trait.m_types.find( e.item ) != trait.m_types.end() ) { + return true; + } + break; + } + return false; + } + static ::HIR::GenericPath make_generic_path(::HIR::SimplePath sp, const ::HIR::Trait& trait) + { + auto trait_path_g = ::HIR::GenericPath( mv$(sp) ); + for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++ ) { + //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef(trait.m_params.m_types[i].m_name, i) ); + //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef() ); + trait_path_g.m_params.m_types.push_back( trait.m_params.m_types[i].m_default.clone() ); + } + return trait_path_g; + } + // Locate the item in `pd` and set `pd` to UfcsResolved if found + // TODO: This code may end up generating paths without the type information they should contain + bool locate_in_trait_and_set(::HIR::Visitor::PathContext pc, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) { + // TODO: Get the span from caller + static Span _sp; + const auto& sp = _sp; + if( locate_item_in_trait(pc, trait, pd) ) { + pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), trait_path.clone() /*make_generic_path(trait_path.m_path, trait)*/, trait); + return true; + } + + auto monomorph_cb = [&](const auto& ty)->const ::HIR::TypeRef& { + const auto& ge = ty.m_data.as_Generic(); + if( ge.binding == 0xFFFF ) { + // TODO: This has to be the _exact_ same type, including future ivars. + return *pd.as_UfcsUnknown().type; + } + else if( (ge.binding >> 8) == 0 ) { + auto idx = ge.binding & 0xFF; + ASSERT_BUG(sp, idx < trait.m_params.m_types.size(), ""); + if( idx < trait_path.m_params.m_types.size() ) + return trait_path.m_params.m_types[idx]; + // If the param is omitted, but has a default, use the default. + else if( trait.m_params.m_types[idx].m_default != ::HIR::TypeRef() ) { + const auto& def = trait.m_params.m_types[idx].m_default; + if( ! monomorphise_type_needed(def) ) + return def; + if( def == ::HIR::TypeRef("Self", 0xFFFF) ) + // TODO: This has to be the _exact_ same type, including future ivars. + return *pd.as_UfcsUnknown().type; + TODO(sp, "Monomorphise default arg " << def << " for trait path " << trait_path); + } + else + BUG(sp, "Binding out of range in " << ty << " for trait path " << trait_path); + } + else { + ERROR(sp, E0000, "Unexpected generic binding " << ty); + } + }; + ::HIR::GenericPath par_trait_path_tmp; + auto monomorph_gp_if_needed = [&](const ::HIR::GenericPath& tpl)->const ::HIR::GenericPath& { + // NOTE: This doesn't monomorph if the parameter set is the same + if( monomorphise_genericpath_needed(tpl) && tpl.m_params != trait_path.m_params ) { + DEBUG("- Monomorph " << tpl); + return par_trait_path_tmp = monomorphise_genericpath_with(sp, tpl, monomorph_cb, false /*no infer*/); + } + else { + return tpl; + } + }; + + // Search supertraits (recursively) + for(const auto& pt : trait.m_parent_traits) + { + const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path); + DEBUG("- Check " << par_trait_path); + if( locate_in_trait_and_set(pc, par_trait_path, *pt.m_trait_ptr, pd) ) { + return true; + } + } + for(const auto& pt : trait.m_all_parent_traits) + { + const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path); + DEBUG("- Check (all) " << par_trait_path); + if( locate_item_in_trait(pc, *pt.m_trait_ptr, pd) ) { + // TODO: Don't clone if this is from the temp. + pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), par_trait_path.clone(), *pt.m_trait_ptr); + return true; + } + } + return false; + } + + bool resolve_UfcsUnknown_inherent(const ::HIR::Path& p, ::HIR::Visitor::PathContext pc, ::HIR::Path::Data& pd) + { + auto& e = pd.as_UfcsUnknown(); + return m_crate.find_type_impls(*e.type, [&](const auto& t)->const auto& { return t; }, [&](const auto& impl) { + DEBUG("- matched inherent impl" << impl.m_params.fmt_args() << " " << impl.m_type); + // Search for item in this block + switch( pc ) + { + case ::HIR::Visitor::PathContext::VALUE: + if( impl.m_methods.find(e.item) != impl.m_methods.end() ) { + } + else if( impl.m_constants.find(e.item) != impl.m_constants.end() ) { + } + else { + return false; + } + // Found it, just keep going (don't care about details here) + break; + case ::HIR::Visitor::PathContext::TRAIT: + case ::HIR::Visitor::PathContext::TYPE: + return false; + } + + auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} ); + pd = mv$(new_data); + DEBUG("- Resolved, replace with " << p); + return true; + }); + } + + void visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) override + { + static Span sp; + + // Explicitly handle UfcsUnknown (doesn't call default) + if(auto* pe = p.m_data.opt_UfcsUnknown()) + { + auto& e = *pe; + TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p); + + this->visit_type( *e.type ); + this->visit_path_params( e.params ); + + // Search for matching impls in current generic blocks + if( m_params_method != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_method, p.m_data) ) { + DEBUG("Found in item params, p = " << p); + return ; + } + if( m_params_impl != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_impl, p.m_data) ) { + DEBUG("Found in impl params, p = " << p); + return ; + } + + // If processing a trait, and the type is 'Self', search for the type/method on the trait + // - TODO: This could be encoded by a `Self: Trait` bound in the generics, but that may have knock-on issues? + // NOTE: `Self` can already be replaced by the self type (AST resolve does this) + if( *e.type == ::HIR::TypeRef("Self", 0xFFFF) || (m_current_type && *e.type == *m_current_type) ) + { + ::HIR::GenericPath trait_path; + if( m_current_trait_path->trait_path() ) + { + trait_path = ::HIR::GenericPath( *m_current_trait_path->trait_path() ); + trait_path.m_params = m_current_trait_path->trait_args()->clone(); + } + else + { + trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() ); + for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) { + trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) ); + } + } + if( locate_in_trait_and_set(pc, trait_path, *m_current_trait, p.m_data) ) { + DEBUG("Found in Self, p = " << p); + return ; + } + DEBUG("- Item " << e.item << " not found in Self - ty=" << *e.type); + } + + // Cases for the type: + // - Path:UfcsKnown - Search trait impl's ATY bounds (and our own bound set?) + // - Generic - Search local bound set for a suitable implemented trait + // - Anything else - ERROR + if( e.type->m_data.is_Path() && e.type->m_data.as_Path().path.m_data.is_UfcsKnown() ) + { + // TODO: Search bounds on this ATY (in the trait defintiion) + TODO(sp, "Get " << e.item << " for " << *e.type); + } + else if( e.type->m_data.is_Generic()) + { + // Local bounds have already been searched, error now? + TODO(sp, "Get " << e.item << " for " << *e.type); + } + else + { + ERROR(sp, E0000, "Ambigious associated type " << p); // rustc E0223 + } + } + else + { + ::HIR::Visitor::visit_path(p, pc); + } + } + }; + +} + +void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate) +{ + Visitor exp { crate }; + exp.visit_crate( crate ); +} diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index c9e2bae9..de9b6053 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -434,7 +434,9 @@ bool StaticTraitResolve::find_impl__check_bound( static bool compare_pp(const Span& sp, const ::HIR::PathParams& left, const ::HIR::PathParams& right) { ASSERT_BUG( sp, left.m_types.size() == right.m_types.size(), "Parameter count mismatch" ); for(unsigned int i = 0; i < left.m_types.size(); i ++) { - if( left.m_types[i] != right.m_types[i] ) { + // TODO: Permits fuzzy comparison to handle placeholder params, should instead do a match/test/assign + if( left.m_types[i].compare_with_placeholders(sp, right.m_types[i], [](const auto&t)->const ::HIR::TypeRef&{return t;}) == ::HIR::Compare::Unequal ) { + //if( left.m_types[i] != right.m_types[i] ) { return false; } } @@ -670,7 +672,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( }); } if( !rv ) { - DEBUG("> Fail (assoc) - " << b_ty_mono << " : " << aty_src_trait); + DEBUG("> Fail (assoc " << aty_name << ") - " << b_ty_mono << " : " << aty_src_trait); return false; } } @@ -1331,10 +1333,17 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false); DEBUG(pt << " => " << pt_mono); - if( pt.m_path.m_path == des && pt_mono.m_path.m_params == des_params ) + // TODO: When in pre-typecheck mode, this needs to be a fuzzy match (because there might be a UfcsUnknown in the + // monomorphed version) OR, there may be placeholders + if( pt.m_path.m_path == des ) { - callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) ); - return true; + auto cmp = pt_mono.m_path.m_params.compare_with_placeholders(sp, des_params, [](const auto& t)->const ::HIR::TypeRef&{return t;}); + // pt_mono.m_path.m_params == des_params ) + if( cmp != ::HIR::Compare::Unequal ) + { + callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) ); + return true; + } } } diff --git a/src/main.cpp b/src/main.cpp index 782e043f..c0f2df9b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,6 +52,7 @@ void init_debug_list() g_debug_disable_map.insert( "Resolve Type Aliases" ); g_debug_disable_map.insert( "Resolve Bind" ); + g_debug_disable_map.insert( "Resolve UFCS Outer" ); g_debug_disable_map.insert( "Resolve UFCS paths" ); g_debug_disable_map.insert( "Resolve HIR Markings" ); g_debug_disable_map.insert( "Constant Evaluate" ); @@ -477,6 +478,16 @@ int main(int argc, char *argv[]) CompilePhaseV("Resolve HIR Markings", [&]() { ConvertHIR_Markings(*hir_crate); }); + // Determine what trait to use for ::Foo in outer scope + CompilePhaseV("Resolve UFCS Outer", [&]() { + ConvertHIR_ResolveUFCS_Outer(*hir_crate); + }); + if( params.debug.dump_hir ) { + CompilePhaseV("Dump HIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); + HIR_Dump( os, *hir_crate ); + }); + } // Determine what trait to use for ::Foo (and does some associated type expansion) CompilePhaseV("Resolve UFCS paths", [&]() { ConvertHIR_ResolveUFCS(*hir_crate); -- cgit v1.2.3 From dc181591986dff3ceff82e865f5b7cc818716d2f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 Jan 2019 09:59:36 +0800 Subject: Typecheck Expressions - Tweak expand_associated_types to get associated type bounds on associated types --- src/hir_conv/resolve_ufcs.cpp | 4 +++- src/hir_typeck/common.hpp | 17 +++++++++++++++++ src/hir_typeck/helpers.cpp | 20 ++++++++++++-------- 3 files changed, 32 insertions(+), 9 deletions(-) (limited to 'src/hir_conv/resolve_ufcs.cpp') diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 9bdb2feb..19ec84ba 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -6,7 +6,9 @@ * - Resolve unkown UFCS traits into inherent or trait * - HACK: Will likely be replaced with a proper typeck pass (no it won't) * - * - TODO: What are the rules for UFCS lookup? + * TODO: Remove this pass, except maybe for running EAT on outer types + * - Expression code can handle picking UFCS functions better than this code can + * - Outer EAT is nice, but StaticTraitResolve will need to handle non-EAT-ed types when doing lookups */ #include "main_bindings.hpp" #include diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index c0e495a6..4de874a8 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -29,6 +29,23 @@ extern ::HIR::Path monomorphise_path_with(const Span& sp, const ::HIR::Path& tpl extern ::HIR::TypeRef monomorphise_type_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true); extern ::HIR::TypeRef monomorphise_type(const Span& sp, const ::HIR::GenericParams& params_def, const ::HIR::PathParams& params, const ::HIR::TypeRef& tpl); +// Wrappers to only monomorphise if required +static inline const ::HIR::TypeRef& monomorphise_type_with_opt(const Span& sp, ::HIR::TypeRef& tmp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_type_needed(tpl) ? tmp = monomorphise_type_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::Path& monomorphise_path_with_opt(const Span& sp, ::HIR::Path& tmp, const ::HIR::Path& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_path_needed(tpl) ? tmp = monomorphise_path_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::GenericPath& monomorphise_genericpath_with_opt(const Span& sp, ::HIR::GenericPath& tmp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_genericpath_needed(tpl) ? tmp = monomorphise_genericpath_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::TraitPath& monomorphise_traitpath_with_opt(const Span& sp, ::HIR::TraitPath& tmp, const ::HIR::TraitPath& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_traitpath_needed(tpl) ? tmp = monomorphise_traitpath_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::PathParams& monomorphise_pathparams_with_opt(const Span& sp, ::HIR::PathParams& tmp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_pathparams_needed(tpl) ? tmp = monomorphise_path_params_with(sp, tpl, callback, allow_infer) : tpl); +} + typedef ::std::function t_cb_visit_ty; /// Calls the provided callback on every type seen when recursing the type. /// If the callback returns `true`, no further types are visited and the function returns `true`. diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index d4d16aad..0c76b4e5 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1981,7 +1981,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, ( ), (TraitBound, - DEBUG("Trait bound - " << be.type << " : " << be.trait); + DEBUG("[expand_associated_types_inplace__UfcsKnown] Trait bound - " << be.type << " : " << be.trait); // 1. Check if the type matches // - TODO: This should be a fuzzier match? if( be.type != *pe.type ) @@ -1993,7 +1993,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, if( it == be.trait.m_type_bounds.end() ) { // If not, assume it's opaque and return as such // TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>' - DEBUG("Found impl for " << input << " but no bound on item, assuming opaque"); + DEBUG("[expand_associated_types_inplace__UfcsKnown] Found impl for " << input << " but no bound on item, assuming opaque"); } else { assume_opaque = false; @@ -2066,6 +2066,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } // If the type of this UfcsKnown is ALSO a UfcsKnown - Check if it's bounded by this trait with equality + // e.g. `<::Baz as Trait2>::Type` may have an ATY bound `trait Bar { type Baz: Trait2 }` // Use bounds on other associated types too (if `pe.type` was resolved to a fixed associated type) TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, Path, te_inner, TU_IFLET(::HIR::Path::Data, te_inner.path.m_data, UfcsKnown, pe_inner, @@ -2099,7 +2100,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, { // If the bound is for Self and the outer trait // - TODO: Fuzzy check the parameters? - if( bound.m_path == pe.trait ) { + ::HIR::GenericPath tmp_tp; + const auto& bound_tp = monomorphise_genericpath_with_opt(sp, tmp_tp, bound.m_path, cb_placeholders_trait); + DEBUG(bound_tp << " ?= " << pe.trait); + if( bound_tp == pe.trait ) { auto it = bound.m_type_bounds.find( pe.item ); if( it != bound.m_type_bounds.end() ) { if( monomorphise_type_needed(it->second) ) { @@ -2115,10 +2119,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } // TODO: Find trait in this trait. - const auto& bound_trait = m_crate.get_trait_by_path(sp, bound.m_path.m_path); + const auto& bound_trait = m_crate.get_trait_by_path(sp, bound_tp.m_path); bool replaced = this->find_named_trait_in_trait(sp, pe.trait.m_path,pe.trait.m_params, - bound_trait, bound.m_path.m_path,bound.m_path.m_params, *pe.type, + bound_trait, bound_tp.m_path,bound_tp.m_params, *pe.type, [&](const auto&, const auto& x, const auto& assoc){ auto it = assoc.find(pe.item); if( it != assoc.end() ) { @@ -2292,9 +2296,9 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple ) ) - //if(type.m_data.is_Infer()) { - // return false; - //} + if(type.m_data.is_Infer()) { + return false; + } // NOTE: Even if the type is completely unknown (infer or unbound UFCS), search the bound list. -- cgit v1.2.3 From 054faa303107d5940463465d729cc0d1e2ec8473 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 9 Feb 2019 22:32:40 +0800 Subject: Typecheck - Various fixes for librustc --- src/hir/pattern.hpp | 4 ++ src/hir/type.cpp | 30 +++++----- src/hir_conv/resolve_ufcs.cpp | 5 ++ src/hir_expand/annotate_value_usage.cpp | 6 ++ src/hir_typeck/expr_cs.cpp | 103 +++++++++++++++++++++++--------- src/hir_typeck/helpers.cpp | 3 +- 6 files changed, 108 insertions(+), 43 deletions(-) (limited to 'src/hir_conv/resolve_ufcs.cpp') diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index b17ebcb4..cd6c7422 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -102,6 +102,10 @@ struct Pattern const Struct* binding; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; bool is_exhaustive; + + bool is_wildcard() const { + return sub_patterns.empty() && !is_exhaustive; + } } ), // Refutable (Value, struct { Value val; } ), diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 981ed0b3..ff4742e6 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -177,12 +177,10 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const } TU_ARM(m_data, Closure, e) { os << "closure["< " << *e.m_rettype; - */ } } } @@ -901,6 +899,22 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return Compare::Equal; } + // Unbound paths and placeholder generics + if( left.m_data.tag() != right.m_data.tag() ) { + if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) { + return Compare::Fuzzy; + } + 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; + } + } + // If left is infer TU_IFLET(::HIR::TypeRef::Data, left.m_data, Infer, e, switch(e.ty_class) @@ -1025,18 +1039,6 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x // - See `(Generic,` below if( left.m_data.tag() != right.m_data.tag() ) { - if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) { - return Compare::Fuzzy; - } - 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), diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 19ec84ba..90b3868d 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -187,6 +187,11 @@ namespace { upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); ::HIR::ExprVisitorDef::visit(node); } + void visit(::HIR::ExprNode_StructLiteral& node) override + { + upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::TYPE); + ::HIR::ExprVisitorDef::visit(node); + } void visit(::HIR::ExprNode_Match& node) override { diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index 1754bdac..e763586c 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -520,6 +520,12 @@ namespace { ), (Struct, const auto& str = *pe.binding; + if( pe.is_wildcard() ) + return ::HIR::ValueUsage::Borrow; + if( pe.sub_patterns.empty() && (TU_TEST1(str.m_data, Tuple, .empty()) || str.m_data.is_Unit()) ) { + return ::HIR::ValueUsage::Borrow; + } + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-brace struct"); const auto& flds = str.m_data.as_Named(); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 794f3a9c..70b9c26c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1196,10 +1196,9 @@ namespace { { const auto& sp = node.span(); TRACE_FUNCTION_F(&node << " " << node.m_path << "{...} [" << (node.m_is_struct ? "struct" : "enum") << "]"); - ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path); - auto& ty_path = node.m_path.m_data.as_Generic(); - this->add_ivars_generic_path(node.span(), ty_path); + this->add_ivars_path(node.span(), node.m_path); + for( auto& val : node.m_values ) { this->context.add_ivars( val.second->m_res_type ); } @@ -1207,6 +1206,15 @@ namespace { this->context.add_ivars( node.m_base_value->m_res_type ); } + // TODO: The path can be a Ufcs (any type) + if( !node.m_path.m_data.is_Generic() ) + { + auto t = this->context.m_resolve.expand_associated_types(sp, ::HIR::TypeRef::new_path( mv$(node.m_path), {} )); + node.m_path = mv$(t.m_data.as_Path().path); + } + ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path); + auto& ty_path = node.m_path.m_data.as_Generic(); + // - Create ivars in path, and set result type const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, ty_path); this->context.equate_types(node.span(), node.m_res_type, ty); @@ -3997,8 +4005,21 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T rv = true; } TU_ARM(pattern.m_data, Box, pe) { - // TODO: inner pattern - TODO(sp, "Match ergonomics - box pattern"); + // Box + if( TU_TEST2(ty.m_data, Path, .path.m_data, Generic, .m_path == context.m_lang_Box) ) + { + const auto& path = ty.m_data.as_Path().path.m_data.as_Generic(); + const auto& inner = path.m_params.m_types.at(0); + rv = this->revisit_inner(context, *pe.sub, inner, binding_mode); + } + else + { + TODO(sp, "Match ergonomics - box pattern - Non Box type: " << ty); + //auto inner = this->m_ivars.new_ivar_tr(); + //this->handle_pattern_direct_inner(sp, *e.sub, inner); + //::HIR::GenericPath path { m_lang_Box, ::HIR::PathParams(mv$(inner)) }; + //this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(&m_crate.get_struct_by_path(sp, m_lang_Box))) ); + } } TU_ARM(pattern.m_data, Ref, pe) { BUG(sp, "Match ergonomics - & pattern"); @@ -4082,25 +4103,34 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T assert(e.binding); const auto& str = *e.binding; - // - assert check from earlier pass - ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct"); - const auto& sd = str.m_data.as_Named(); - const auto& params = e.path.m_params; - - rv = true; - for( auto& field_pat : e.sub_patterns ) + //if( ! e.is_wildcard() ) + if( e.sub_patterns.empty() ) { - unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin(); - if( f_idx == sd.size() ) { - ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first); - } - const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; - if( monomorphise_type_needed(field_type) ) { - auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type); - rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); - } - else { - rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); + // TODO: Check the field count? + rv = true; + } + else + { + // - assert check from earlier pass + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct"); + const auto& sd = str.m_data.as_Named(); + const auto& params = e.path.m_params; + + rv = true; + for( auto& field_pat : e.sub_patterns ) + { + unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin(); + if( f_idx == sd.size() ) { + ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first); + } + const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; + if( monomorphise_type_needed(field_type) ) { + auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type); + rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); + } + else { + rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); + } } } } @@ -4684,7 +4714,7 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c this->add_ivars_params( e.path.m_params ); this->equate_types( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); - if( e.sub_patterns.empty() ) + if( e.is_wildcard() ) return ; assert(e.binding); @@ -5140,6 +5170,7 @@ namespace { { DEBUG("- Moving into block"); assert( p->m_value_node ); + // Block result and the inner node's result must be the same type ASSERT_BUG( p->span(), context.m_ivars.types_equal(p->m_res_type, p->m_value_node->m_res_type), "Block and result mismatch - " << context.m_ivars.fmt_type(p->m_res_type) << " != " << context.m_ivars.fmt_type(p->m_value_node->m_res_type)); // - Override the the result type to the desired result @@ -5253,7 +5284,7 @@ namespace { return CoerceResult::Equality; } context.possible_equate_type_unsize_to(sep->index, dst); - DEBUG("Src ivar"); + DEBUG("Src is ivar (" << src << "), return Unknown"); return CoerceResult::Unknown; } else @@ -5926,10 +5957,20 @@ namespace { context.m_ivars.mark_change(); // Continue on with coercion (now that node_ptr is updated) - switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, node_ptr_ptr) ) + switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, &node_ptr) ) { case CoerceResult::Unknown: - return CoerceResult::Unknown; + // Add new coercion at the new inner point + if( &node_ptr != node_ptr_ptr ) + { + DEBUG("Unknown check_unsize_tys after autoderef - " << dst << " := " << node_ptr->m_res_type); + context.equate_types_coerce(sp, dst, node_ptr); + return CoerceResult::Custom; + } + else + { + return CoerceResult::Unknown; + } case CoerceResult::Custom: return CoerceResult::Custom; case CoerceResult::Equality: @@ -6824,9 +6865,17 @@ namespace { const auto& re_inner = r.m_data.is_Borrow() ? r.m_data.as_Borrow().inner : r.m_data.as_Pointer().inner; if( le.type < re_borrow_type ) { + if( !context.m_ivars.types_equal(*le.inner, *re_inner) ) { + return DedupKeep::Both; + } + DEBUG("- Remove " << r); return DedupKeep::Left; } else if( le.type > re_borrow_type ) { + if( !context.m_ivars.types_equal(*le.inner, *re_inner) ) { + return DedupKeep::Both; + } + DEBUG("- Remove " << l); return DedupKeep::Right; } else { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index dd6409c0..15c61bc7 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -3359,8 +3359,7 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa return ::HIR::Compare::Equal; ), (Array, - // TODO: Clone here? - return type_is_copy(sp, *e.inner); + return type_is_clone(sp, *e.inner); ) ) } -- cgit v1.2.3