diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/from_ast.cpp | 1 | ||||
-rw-r--r-- | src/hir_typeck/outer.cpp | 76 | ||||
-rw-r--r-- | src/hir_typeck/static.cpp | 570 | ||||
-rw-r--r-- | src/hir_typeck/static.hpp | 102 |
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; }; |