summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/hir/from_ast.cpp1
-rw-r--r--src/hir_typeck/outer.cpp76
-rw-r--r--src/hir_typeck/static.cpp570
-rw-r--r--src/hir_typeck/static.hpp102
4 files changed, 703 insertions, 46 deletions
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index 878e7d4c..46d2a19f 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -802,6 +802,7 @@ namespace {
}
::HIR::Function LowerHIR_Function(const ::AST::Function& f)
{
+ DEBUG("");
::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef > > args;
for(const auto& arg : f.args())
args.push_back( ::std::make_pair( LowerHIR_Pattern(arg.first), LowerHIR_Type(arg.second) ) );
diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp
index e91278a8..78e49191 100644
--- a/src/hir_typeck/outer.cpp
+++ b/src/hir_typeck/outer.cpp
@@ -3,6 +3,7 @@
*/
#include <hir/hir.hpp>
#include <hir/visitor.hpp>
+#include <hir_typeck/static.hpp>
namespace {
@@ -97,15 +98,13 @@ namespace {
public ::HIR::Visitor
{
::HIR::Crate& crate;
-
- ::HIR::GenericParams* m_impl_generics;
- //::HIR::GenericParams* m_item_generics;
+ StaticTraitResolve m_resolve;
+
::std::vector< ::HIR::TypeRef* > m_self_types;
public:
Visitor(::HIR::Crate& crate):
crate(crate),
- m_impl_generics(nullptr)/*,
- m_item_generics(nullptr)*/
+ m_resolve(crate)
{
}
@@ -200,6 +199,55 @@ namespace {
}
public:
+ void visit_type(::HIR::TypeRef& ty) override
+ {
+ static Span _sp;
+ const Span& sp = _sp;
+ ::HIR::Visitor::visit_type(ty);
+
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e,
+ TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe),
+ (Generic,
+ ),
+ (UfcsUnknown,
+ TODO(sp, "Should UfcsKnown be encountered here?");
+ ),
+ (UfcsInherent,
+ TODO(sp, "Locate impl block for UFCS Inherent");
+ ),
+ (UfcsKnown,
+ if( pe.type->m_data.is_Path() && pe.type->m_data.as_Path().binding.is_Opaque() ) {
+ // - Opaque type, opaque result
+ e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ }
+ else if( pe.type->m_data.is_Generic() ) {
+ // - Generic type, opaque resut. (TODO: Sometimes these are known - via generic bounds)
+ e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ }
+ else {
+ ::HIR::TypeRef new_ty;
+ bool found = m_resolve.find_impl(sp, pe.trait.m_path, pe.trait.m_params, *pe.type, [&](const auto& impl) {
+ DEBUG("TODO - Extract associated type '"<<pe.item<<"' from " << impl);
+ new_ty = impl.get_type(pe.item.c_str());
+ if( new_ty == ::HIR::TypeRef() ) {
+ ERROR(sp, E0000, "Associated type '"<<pe.item<<"' could not be found in " << pe.trait);
+ }
+ return true;
+ });
+ if( found ) {
+ assert( new_ty != ::HIR::TypeRef() );
+ DEBUG("Replaced " << ty << " with " << new_ty);
+ ty = mv$(new_ty);
+ }
+ else {
+ ERROR(sp, E0000, "Couldn't find an impl of " << pe.trait << " for " << *pe.type);
+ }
+ }
+ )
+ )
+ )
+ }
+
void visit_generic_path(::HIR::GenericPath& p, PathContext pc) override
{
TRACE_FUNCTION_F("p = " << p);
@@ -266,50 +314,50 @@ namespace {
void visit_trait(::HIR::PathChain p, ::HIR::Trait& item) override
{
+ auto _ = m_resolve.set_item_generics(item.m_params);
::HIR::TypeRef tr { "Self", 0xFFFF };
m_self_types.push_back(&tr);
::HIR::Visitor::visit_trait(p, item);
m_self_types.pop_back();
}
+ void visit_struct(::HIR::PathChain p, ::HIR::Struct& item) override
+ {
+ auto _ = m_resolve.set_item_generics(item.m_params);
+ ::HIR::Visitor::visit_struct(p, item);
+ }
void visit_type_impl(::HIR::TypeImpl& impl) override
{
TRACE_FUNCTION_F("impl " << impl.m_type);
- assert(m_impl_generics == nullptr);
- m_impl_generics = &impl.m_params;
+ auto _ = m_resolve.set_impl_generics(impl.m_params);
m_self_types.push_back( &impl.m_type );
::HIR::Visitor::visit_type_impl(impl);
// Check that the type is valid
m_self_types.pop_back();
- m_impl_generics = nullptr;
}
void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override
{
TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type);
- assert(m_impl_generics == nullptr);
- m_impl_generics = &impl.m_params;
+ auto _ = m_resolve.set_impl_generics(impl.m_params);
m_self_types.push_back( &impl.m_type );
::HIR::Visitor::visit_trait_impl(trait_path, impl);
// Check that the type+trait is valid
m_self_types.pop_back();
- m_impl_generics = nullptr;
}
void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl)
{
TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type << " { }");
- assert(m_impl_generics == nullptr);
- m_impl_generics = &impl.m_params;
+ auto _ = m_resolve.set_impl_generics(impl.m_params);
m_self_types.push_back( &impl.m_type );
::HIR::Visitor::visit_marker_impl(trait_path, impl);
// Check that the type+trait is valid
m_self_types.pop_back();
- m_impl_generics = nullptr;
}
};
}
diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp
index 5fc4dc5f..c8cb0df5 100644
--- a/src/hir_typeck/static.cpp
+++ b/src/hir_typeck/static.cpp
@@ -1,16 +1,131 @@
-
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir_typeck/static.cpp
+ * - Non-inferred type checking
+ */
#include "static.hpp"
bool StaticTraitResolve::find_impl(
const Span& sp,
- const ::HIR::Crate& crate, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& trait_params,
+ const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& trait_params,
const ::HIR::TypeRef& type,
t_cb_find_impl found_cb
- )
+ ) const
{
+ TRACE_FUNCTION_F(trait_path << trait_params << " for " << type);
auto cb_ident = [](const auto&ty)->const auto&{return ty;};
- return crate.find_trait_impls(trait_path, type, cb_ident, [&](const auto& impl) {
- DEBUG("TODO: impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " where " << impl.m_params.fmt_bounds());
+
+ struct H {
+ 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] ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ const ::HIR::Path::Data::Data_UfcsKnown* assoc_info = nullptr;
+ TU_IFLET(::HIR::TypeRef::Data, type.m_data, Path, e,
+ TU_IFLET(::HIR::Path::Data, e.path.m_data, UfcsKnown, pe,
+ assoc_info = &pe;
+ )
+ )
+
+ bool ret;
+
+ // TODO: A bound can imply something via its associated types. How deep can this go?
+ // E.g. `T: IntoIterator<Item=&u8>` implies `<T as IntoIterator>::IntoIter : Iterator<Item=&u8>`
+ ret = this->iterate_bounds([&](const auto& b) {
+ TU_IFLET(::HIR::GenericBound, b, TraitBound, e,
+ const auto& b_params = e.trait.m_path.m_params;
+ DEBUG("(bound) - " << e.type << " : " << e.trait);
+ if( e.type == type )
+ {
+ if( e.trait.m_path.m_path == trait_path ) {
+ // Check against `params`
+ DEBUG("Checking " << trait_params << " vs " << b_params);
+ if( !H::compare_pp(sp, trait_params, b_params) )
+ return false;
+ // Hand off to the closure, and return true if it does
+ if( found_cb(ImplRef(e.type, e.trait.m_path.m_params, e.trait.m_type_bounds)) ) {
+ 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,
+ trait_path,trait_params,
+ *e.trait.m_trait_ptr, e.trait.m_path.m_path,e.trait.m_path.m_params,
+ type,
+ [&](auto assoc) {
+ for(const auto& i : e.trait.m_type_bounds) {
+ // TODO: Only include from above when needed
+ //if( des_trait_ref.m_types.count(i.first) ) {
+ assoc.insert( ::std::make_pair(i.first, i.second.clone()) );
+ //}
+ }
+ return found_cb( ImplRef(type, trait_params, assoc) );
+ });
+ if( rv ) {
+ return true;
+ }
+ }
+
+ // If the input type is an associated type controlled by this trait bound, check for added bounds.
+ // TODO: This just checks a single layer, but it's feasable that there could be multiple layers
+ if( assoc_info && e.trait.m_path.m_path == assoc_info->trait.m_path && e.type == *assoc_info->type && H::compare_pp(sp, b_params, assoc_info->trait.m_params) ) {
+
+ const auto& trait_ref = *e.trait.m_trait_ptr;
+ const auto& at = trait_ref.m_types.at(assoc_info->item);
+ for(const auto& bound : at.m_params.m_bounds) {
+ if( ! bound.is_TraitBound() )
+ continue ;
+ const auto& be = bound.as_TraitBound();
+ if( be.type != ::HIR::TypeRef("Self", 0xFFFF) ) {
+ TODO(sp, "Handle associated type bounds on !Self");
+ continue ;
+ }
+ if( be.trait.m_path.m_path == trait_path && H::compare_pp(sp, be.trait.m_path.m_params, trait_params) ) {
+ DEBUG("- Found an associated type impl");
+
+ auto tp_mono = monomorphise_traitpath_with(sp, be.trait, [&assoc_info,&sp](const auto& gt)->const auto& {
+ const auto& ge = gt.m_data.as_Generic();
+ if( ge.binding == 0xFFFF ) {
+ return *assoc_info->type;
+ }
+ else {
+ if( ge.binding >= assoc_info->trait.m_params.m_types.size() )
+ BUG(sp, "find_trait_impls_bound - Generic #" << ge.binding << " " << ge.name << " out of range");
+ return assoc_info->trait.m_params.m_types[ge.binding];
+ }
+ }, false);
+ // - Expand associated types
+ for(auto& ty : tp_mono.m_type_bounds) {
+ this->expand_associated_types(sp, ty.second);
+ }
+ DEBUG("- tp_mono = " << tp_mono);
+ // TODO: Instead of using `type` here, build the real type
+ if( found_cb( ImplRef(type, tp_mono.m_path.m_params, tp_mono.m_type_bounds) ) ) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ )
+ return false;
+ });
+ if(ret)
+ return true;
+
+ // Search the crate for impls
+ ret = m_crate.find_trait_impls(trait_path, type, cb_ident, [&](const auto& impl) {
+ DEBUG("- impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " where " << impl.m_params.fmt_bounds());
::std::vector< const ::HIR::TypeRef*> impl_params;
impl_params.resize( impl.m_params.m_types.size() );
@@ -44,26 +159,26 @@ bool StaticTraitResolve::find_impl(
placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i);
}
}
- auto cb_match = [&](unsigned int idx, const auto& ty) {
- if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding == idx )
- return ::HIR::Compare::Equal;
- if( idx >> 8 == 2 ) {
- auto i = idx % 256;
- ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned");
- auto& ph = placeholders[i];
- if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
- DEBUG("Bind placeholder " << i << " to " << ty);
- ph = ty.clone();
- return ::HIR::Compare::Equal;
- }
- else {
- TODO(sp, "Compare placeholder " << i << " " << ph << " == " << ty);
- }
- }
- else {
- return ::HIR::Compare::Unequal;
- }
- };
+ //auto cb_match = [&](unsigned int idx, const auto& ty) {
+ // if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding == idx )
+ // return ::HIR::Compare::Equal;
+ // if( idx >> 8 == 2 ) {
+ // auto i = idx % 256;
+ // ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned");
+ // auto& ph = placeholders[i];
+ // if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) {
+ // DEBUG("Bind placeholder " << i << " to " << ty);
+ // ph = ty.clone();
+ // return ::HIR::Compare::Equal;
+ // }
+ // else {
+ // TODO(sp, "Compare placeholder " << i << " " << ph << " == " << ty);
+ // }
+ // }
+ // else {
+ // return ::HIR::Compare::Unequal;
+ // }
+ // };
auto cb_monomorph = [&](const auto& gt)->const auto& {
const auto& ge = gt.m_data.as_Generic();
ASSERT_BUG(sp, ge.binding >> 8 != 2, "");
@@ -80,14 +195,411 @@ bool StaticTraitResolve::find_impl(
(
),
(TraitBound,
- DEBUG("TODO: Trait bound " << e.type << " : " << e.trait);
- auto b_ty_mono = monomorphise_type_with(sp, e.type, cb_mono);
- DEBUG("- b_ty_mono = " << b_ty_mono);
+ DEBUG("Trait bound " << e.type << " : " << e.trait);
+ auto b_ty_mono = monomorphise_type_with(sp, e.type, cb_monomorph);
+ auto b_tp_mono = monomorphise_traitpath_with(sp, e.trait, cb_monomorph, false);
+ DEBUG("- b_ty_mono = " << b_ty_mono << ", b_tp_mono = " << b_tp_mono);
+ if( !this->find_impl(sp, b_tp_mono.m_path.m_path, b_tp_mono.m_path.m_params, b_ty_mono, [](const auto&){return true;}) ) {
+ DEBUG("> Fail");
+ return false;
+ }
)
)
}
- return found_cb(impl_params, impl);
+ return found_cb( ImplRef(impl_params, impl) );
});
+ if(ret)
+ return true;
+
+ return false;
+}
+
+void StaticTraitResolve::expand_associated_types(const Span& sp, ::HIR::TypeRef& input) const
+{
+ TRACE_FUNCTION_F(input);
+ TU_MATCH(::HIR::TypeRef::Data, (input.m_data), (e),
+ (Infer,
+ BUG(sp, "Encountered inferrence variable in static context");
+ ),
+ (Diverge,
+ ),
+ (Primitive,
+ ),
+ (Path,
+ TU_MATCH(::HIR::Path::Data, (e.path.m_data), (e2),
+ (Generic,
+ for(auto& arg : e2.m_params.m_types)
+ this->expand_associated_types(sp, arg);
+ ),
+ (UfcsInherent,
+ TODO(sp, "Path - UfcsInherent - " << e.path);
+ ),
+ (UfcsKnown,
+ // - Only try resolving if the binding isn't known
+ if( !e.binding.is_Unbound() )
+ return ;
+
+ this->expand_associated_types(sp, *e2.type);
+ for(auto& arg : e2.trait.m_params.m_types)
+ this->expand_associated_types(sp, arg);
+
+ DEBUG("Locating associated type for " << e.path);
+
+ // - If it's a closure, then the only trait impls are those generated by typeck
+ TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, Closure, te,
+ const auto trait_fn = this->m_crate.get_lang_item_path(sp, "fn");
+ const auto trait_fn_mut = this->m_crate.get_lang_item_path(sp, "fn_mut");
+ const auto trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once");
+ if( e2.trait.m_path == trait_fn || e2.trait.m_path == trait_fn_mut || e2.trait.m_path == trait_fn_once ) {
+ if( e2.item == "Output" ) {
+ input = te.m_rettype->clone();
+ return ;
+ }
+ else {
+ ERROR(sp, E0000, "No associated type " << e2.item << " for trait " << e2.trait);
+ }
+ }
+ else {
+ ERROR(sp, E0000, "No implementation of " << e2.trait << " for " << *e2.type);
+ }
+ )
+
+ // 1. Bounds
+ bool rv;
+ bool assume_opaque = true;
+ rv = this->iterate_bounds([&](const auto& b) {
+ TU_MATCH_DEF(::HIR::GenericBound, (b), (be),
+ (
+ ),
+ (TraitBound,
+ DEBUG("Trait bound - " << be.type << " : " << be.trait);
+ // 1. Check if the type matches
+ // - TODO: This should be a fuzzier match?
+ if( be.type != *e2.type )
+ return false;
+ // 2. Check if the trait (or any supertrait) includes e2.trait
+ if( be.trait.m_path == e2.trait ) {
+ auto it = be.trait.m_type_bounds.find(e2.item);
+ // 1. Check if the bounds include the desired item
+ 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");
+ }
+ else {
+ assume_opaque = false;
+ input = it->second.clone();
+ }
+ return true;
+ }
+
+ bool found_supertrait = this->find_named_trait_in_trait(sp,
+ e2.trait.m_path, e2.trait.m_params,
+ *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, *e2.type,
+ [&e2,&input,&assume_opaque](auto assoc){
+ auto it = assoc.find(e2.item);
+ if( it != assoc.end() ) {
+ assume_opaque = false;
+ DEBUG("Found associated type " << input << " = " << it->second);
+ input = it->second.clone();
+ }
+ return true;
+ }
+ );
+ if( found_supertrait ) {
+ auto it = be.trait.m_type_bounds.find(e2.item);
+ // 1. Check if the bounds include the desired item
+ 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>'
+ if( assume_opaque )
+ DEBUG("Found impl for " << input << " but no bound on item, assuming opaque");
+ }
+ else {
+ assume_opaque = false;
+ input = it->second.clone();
+ }
+ return true;
+ }
+
+ // - Didn't match
+ ),
+ (TypeEquality,
+ DEBUG("Equality - " << be.type << " = " << be.other_type);
+ if( input == be.type ) {
+ input = be.other_type.clone();
+ return true;
+ }
+ )
+ )
+ return false;
+ });
+ if( rv ) {
+ if( assume_opaque ) {
+ DEBUG("Assuming that " << input << " is an opaque name");
+ input.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ }
+ this->expand_associated_types(sp, input);
+ return;
+ }
+
+ // If the type of this UfcsKnown is ALSO a UfcsKnown - Check if it's bounded by this trait with equality
+ // Use bounds on other associated types too (if `e2.type` was resolved to a fixed associated type)
+ TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, Path, te_inner,
+ TU_IFLET(::HIR::Path::Data, te_inner.path.m_data, UfcsKnown, pe_inner,
+ // TODO: Search for equality bounds on this associated type (e3) that match the entire type (e2)
+ // - Does simplification of complex associated types
+ const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path);
+ const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item);
+ DEBUG("TODO: Search bounds on associated type - " << assoc_ty.m_params.fmt_bounds());
+
+ // Resolve where Self=e2.type, for the associated type check.
+ auto cb_placeholders_type = [&](const auto& ty)->const auto&{
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
+ if( e.binding == 0xFFFF )
+ return *e2.type;
+ else
+ TODO(sp, "Handle type params when expanding associated bound (#" << e.binding << " " << e.name);
+ )
+ else {
+ return ty;
+ }
+ };
+ // Resolve where Self=pe_inner.type (i.e. for the trait this inner UFCS is on)
+ auto cb_placeholders_trait = [&](const auto& ty)->const auto&{
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
+ if( e.binding == 0xFFFF )
+ return *pe_inner.type;
+ else {
+ // TODO: Look in pe_inner.trait.m_params
+ TODO(sp, "Handle type params when expanding associated bound (#" << e.binding << " " << e.name);
+ }
+ )
+ else {
+ return ty;
+ }
+ };
+ for(const auto& bound : assoc_ty.m_params.m_bounds)
+ {
+ TU_MATCH_DEF(::HIR::GenericBound, (bound), (be),
+ (
+ ),
+ (TraitBound,
+ // If the bound is for Self and the outer trait
+ // - TODO: Parameters?
+ if( be.type == ::HIR::TypeRef("Self", 0xFFFF) && be.trait.m_path == e2.trait ) {
+ auto it = be.trait.m_type_bounds.find( e2.item );
+ if( it != be.trait.m_type_bounds.end() ) {
+ if( monomorphise_type_needed(it->second) ) {
+ input = monomorphise_type_with(sp, it->second, cb_placeholders_trait);
+ }
+ else {
+ input = it->second.clone();
+ }
+ this->expand_associated_types(sp, input);
+ return ;
+ }
+ }
+ ),
+ (TypeEquality,
+ // IF: bound's type matches the input, replace with bounded equality
+ // `<Self::IntoIter as Iterator>::Item = Self::Item`
+ if( be.type.compare_with_placeholders(sp, input, cb_placeholders_type ) ) {
+ DEBUG("Match of " << be.type << " with " << input);
+ DEBUG("- Replace `input` with " << be.other_type << ", Self=" << *pe_inner.type);
+ if( monomorphise_type_needed(be.other_type) ) {
+ input = monomorphise_type_with(sp, be.other_type, cb_placeholders_trait);
+ }
+ else {
+ input = be.other_type.clone();
+ }
+ this->expand_associated_types(sp, input);
+ }
+ )
+ )
+ }
+ DEBUG("e2 = " << *e2.type << ", input = " << input);
+ )
+ )
+
+ // 2. Crate-level impls
+ // TODO: Search for the actual trait containing this associated type
+ ::HIR::GenericPath trait_path;
+ if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item, trait_path) )
+ BUG(sp, "Cannot find associated type " << e2.item << " anywhere in trait " << e2.trait);
+ //e2.trait = mv$(trait_path);
+
+ rv = this->find_impl(sp, trait_path.m_path, trait_path.m_params, *e2.type, [&](const auto& impl) {
+ DEBUG("Found impl" << impl);
+ //auto it = assoc.find( e2.item );
+ //if( it == assoc.end() )
+ // ERROR(sp, E0000, "Couldn't find assocated type " << e2.item << " in " << e2.trait);
+ //
+ //DEBUG("Converted UfcsKnown - " << e.path << " = " << it->second);
+ //input = it->second.clone();
+ return true;
+ });
+ if( rv ) {
+ this->expand_associated_types(sp, input);
+ return;
+ }
+
+ // If there are no ivars in this path, set its binding to Opaque
+ //if( !this->m_ivars.type_contains_ivars(input) ) {
+ // TODO: If the type is a generic or an opaque associated, we can't know.
+ // - If the trait contains any of the above, it's unknowable
+ // - Otherwise, it's an error
+ e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ DEBUG("Couldn't resolve associated type for " << input << " (and won't ever be able to)");
+ //}
+ //else {
+ // DEBUG("Couldn't resolve associated type for " << input << " (will try again later)");
+ //}
+ ),
+ (UfcsUnknown,
+ BUG(sp, "Encountered UfcsUnknown");
+ )
+ )
+ ),
+ (Generic,
+ ),
+ (TraitObject,
+ // Recurse?
+ ),
+ (Array,
+ expand_associated_types(sp, *e.inner);
+ ),
+ (Slice,
+ expand_associated_types(sp, *e.inner);
+ ),
+ (Tuple,
+ for(auto& sub : e) {
+ expand_associated_types(sp, sub);
+ }
+ ),
+ (Borrow,
+ expand_associated_types(sp, *e.inner);
+ ),
+ (Pointer,
+ expand_associated_types(sp, *e.inner);
+ ),
+ (Function,
+ // Recurse?
+ ),
+ (Closure,
+ // Recurse?
+ )
+ )
}
+// -------------------------------------------------------------------------------------------------------------------
+//
+// -------------------------------------------------------------------------------------------------------------------
+bool StaticTraitResolve::iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const
+{
+ const ::HIR::GenericParams* v[2] = { m_item_generics, m_impl_generics };
+ for(auto p : v)
+ {
+ if( !p ) continue ;
+ for(const auto& b : p->m_bounds)
+ if(cb(b)) return true;
+ }
+ return false;
+}
+// -------------------------------------------------------------------------------------------------------------------
+//
+// -------------------------------------------------------------------------------------------------------------------
+bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp,
+ const ::HIR::SimplePath& des, const ::HIR::PathParams& des_params,
+ const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp,
+ const ::HIR::TypeRef& target_type,
+ ::std::function<void(::std::map< ::std::string, ::HIR::TypeRef>)> callback
+ ) const
+{
+ TRACE_FUNCTION_F(des << " from " << trait_path << pp);
+ if( pp.m_types.size() != trait_ptr.m_params.m_types.size() ) {
+ BUG(sp, "Incorrect number of parameters for trait");
+ }
+ for( const auto& pt : trait_ptr.m_parent_traits )
+ {
+ auto pt_mono = monomorphise_traitpath_with(sp, pt, [&](const auto& gt)->const auto& {
+ const auto& ge = gt.m_data.as_Generic();
+ if( ge.binding == 0xFFFF ) {
+ return target_type;
+ }
+ else {
+ if( ge.binding >= pp.m_types.size() )
+ BUG(sp, "find_named_trait_in_trait - Generic #" << ge.binding << " " << ge.name << " out of range");
+ return pp.m_types[ge.binding];
+ }
+ }, false);
+
+ DEBUG(pt << " => " << pt_mono);
+ if( pt.m_path.m_path == des ) {
+ callback( mv$(pt_mono.m_type_bounds) );
+ return true;
+ }
+
+ const auto& tr = m_crate.get_trait_by_path(sp, pt.m_path.m_path);
+ if( find_named_trait_in_trait(sp, des, des_params, tr, pt.m_path.m_path, pt_mono.m_path.m_params, target_type, [](const auto&){}) ) {
+ return true;
+ }
+ }
+ return false;
+}
+bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const
+{
+ auto it = trait_ptr.m_types.find(name);
+ if( it != trait_ptr.m_types.end() ) {
+ out_path = trait_path.clone();
+ return true;
+ }
+
+ auto monomorph = [&](const auto& gt)->const auto& {
+ const auto& ge = gt.m_data.as_Generic();
+ assert(ge.binding < 256);
+ assert(ge.binding < trait_path.m_params.m_types.size());
+ return trait_path.m_params.m_types[ge.binding];
+ };
+ // TODO: Prevent infinite recursion
+ for(const auto& st : trait_ptr.m_parent_traits)
+ {
+ auto& st_ptr = this->m_crate.get_trait_by_path(sp, st.m_path.m_path);
+ if( trait_contains_type(sp, st.m_path, st_ptr, name, out_path) ) {
+ out_path.m_params = monomorphise_path_params_with(sp, mv$(out_path.m_params), monomorph, false);
+ return true;
+ }
+ }
+ return false;
+}
+
+::HIR::TypeRef StaticTraitResolve::ImplRef::get_type(const char* name) const
+{
+ static Span sp;
+ TU_MATCH(Data, (this->m_data), (e),
+ (TraitImpl,
+ DEBUG(*this);
+ auto it = e.impl->m_types.find(name);
+ if( it == e.impl->m_types.end() )
+ return ::HIR::TypeRef();
+ if( monomorphise_type_needed(it->second) ) {
+ auto cb_monomorph = [&](const auto& gt)->const auto& {
+ const auto& ge = gt.m_data.as_Generic();
+ assert(ge.binding < 256);
+ assert(ge.binding < e.params.size());
+ assert(e.params[ge.binding]);
+ return *e.params[ge.binding];
+ };
+ return monomorphise_type_with(sp, it->second, cb_monomorph);
+ }
+ else {
+ return it->second.clone();
+ }
+ ),
+ (Bounded,
+ TODO(Span(), *this);
+ )
+ )
+ return ::HIR::TypeRef();
+}
diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp
index 851e092d..8c540a6e 100644
--- a/src/hir_typeck/static.hpp
+++ b/src/hir_typeck/static.hpp
@@ -1,23 +1,119 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir_typeck/static.cpp
+ * - Non-inferred type checking
+ */
+#pragma once
#include <hir/hir.hpp>
+#include "helpers.hpp"
class StaticTraitResolve
{
+public:
const ::HIR::Crate& m_crate;
+
+ ::HIR::GenericParams* m_impl_generics;
+ ::HIR::GenericParams* m_item_generics;
public:
StaticTraitResolve(const ::HIR::Crate& crate):
- m_crate(crate)
+ m_crate(crate),
+ m_impl_generics(nullptr),
+ m_item_generics(nullptr)
{}
- typedef ::std::function<bool(const ::std::vector<const ::HIR::TypeRef*>& , const ::HIR::TraitImpl&)> t_cb_find_impl;
+ /// \brief State manipulation
+ /// \{
+ template<typename T>
+ class NullOnDrop {
+ T*& ptr;
+ public:
+ NullOnDrop(T*& ptr):
+ ptr(ptr)
+ {}
+ ~NullOnDrop() {
+ ptr = nullptr;
+ }
+ };
+ NullOnDrop< ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) {
+ assert( !m_impl_generics );
+ m_impl_generics = &gps;
+ return NullOnDrop< ::HIR::GenericParams>(m_impl_generics);
+ }
+ NullOnDrop< ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) {
+ assert( !m_item_generics );
+ m_item_generics = &gps;
+ return NullOnDrop< ::HIR::GenericParams>(m_item_generics);
+ }
+ /// \}
+
+
+ struct ImplRef
+ {
+ TAGGED_UNION(Data, TraitImpl,
+ (TraitImpl, struct {
+ ::std::vector<const ::HIR::TypeRef*> params;
+ const ::HIR::TraitImpl* impl;
+ }),
+ (Bounded, struct {
+ const ::HIR::TypeRef* type;
+ const ::HIR::PathParams* trait_args;
+ const ::std::map< ::std::string, ::HIR::TypeRef>* assoc;
+ })
+ );
+
+ Data m_data;
+
+ ImplRef(::std::vector<const ::HIR::TypeRef*> params, const ::HIR::TraitImpl& impl):
+ m_data(Data::make_TraitImpl({ mv$(params), &impl }))
+
+ {}
+ ImplRef(const ::HIR::TypeRef& type, const ::HIR::PathParams& args, const ::std::map< ::std::string, ::HIR::TypeRef>& assoc):
+ m_data(Data::make_Bounded({ &type, &args, &assoc }))
+ {}
+
+ ::HIR::TypeRef get_type(const char* name) const;
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const ImplRef& x) {
+ TU_MATCH(Data, (x.m_data), (e),
+ (TraitImpl,
+ os << "impl" << e.impl->m_params.fmt_args() << " SomeTrait" << e.impl->m_trait_args << " for " << e.impl->m_type << " where " << e.impl->m_params.fmt_bounds();
+ ),
+ (Bounded,
+ os << "bound";
+ )
+ )
+ return os;
+ }
+ };
+
+ /// \brief Lookups
+ /// \{
+ typedef ::std::function<bool(const ImplRef&)> t_cb_find_impl;
bool find_impl(
const Span& sp,
- const ::HIR::Crate& crate, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& trait_params,
+ const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& trait_params,
const ::HIR::TypeRef& type,
t_cb_find_impl found_cb
) const;
void expand_associated_types(const Span& sp, ::HIR::TypeRef& input) const;
+ /// \}
+
+ /// Iterate over in-scope bounds (function then top)
+ bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const;
+
+ /// Locate a named trait in the provied trait (either itself or as a parent trait)
+ bool find_named_trait_in_trait(const Span& sp,
+ const ::HIR::SimplePath& des, const ::HIR::PathParams& params,
+ const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp,
+ const ::HIR::TypeRef& self_type,
+ ::std::function<void(::std::map< ::std::string, ::HIR::TypeRef>)> callback
+ ) const;
+ ///
+ bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const;
};