summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--src/hir_conv/main_bindings.hpp1
-rw-r--r--src/hir_conv/resolve_ufcs.cpp9
-rw-r--r--src/hir_conv/resolve_ufcs_outer.cpp345
-rw-r--r--src/hir_typeck/static.cpp19
-rw-r--r--src/main.cpp11
6 files changed, 382 insertions, 7 deletions
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 <hir/hir.hpp>
@@ -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 <hir/hir.hpp>
+#include <hir/expr.hpp>
+#include <hir/visitor.hpp>
+#include <hir_typeck/common.hpp> // 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 <T>::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 <T>::Foo (and does some associated type expansion)
CompilePhaseV("Resolve UFCS paths", [&]() {
ConvertHIR_ResolveUFCS(*hir_crate);