diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/expr.hpp | 3 | ||||
-rw-r--r-- | src/hir/from_ast.cpp | 42 | ||||
-rw-r--r-- | src/hir_typeck/expr.cpp | 290 | ||||
-rw-r--r-- | src/hir_typeck/outer.cpp | 2 | ||||
-rw-r--r-- | src/include/debug.hpp | 2 | ||||
-rw-r--r-- | src/parse/paths.cpp | 3 |
6 files changed, 256 insertions, 86 deletions
diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 724126c9..4862651d 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -335,6 +335,9 @@ struct ExprNode_CallValue: { ::HIR::ExprNodeP m_value; ::std::vector<ExprNodeP> m_args; + + // - Cache for typeck + ::std::vector< ::HIR::TypeRef> m_arg_types; ExprNode_CallValue(Span sp, ::HIR::ExprNodeP val, ::std::vector< ::HIR::ExprNodeP> args): ExprNode(mv$(sp)), diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 21c3695d..3f297e89 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -10,6 +10,7 @@ ::HIR::Module LowerHIR_Module(const ::AST::Module& module, ::HIR::SimplePath path); ::HIR::Function LowerHIR_Function(const ::AST::Function& f); ::HIR::SimplePath LowerHIR_SimplePath(const Span& sp, const ::AST::Path& path, bool allow_final_generic = false); +::HIR::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& src_params); // -------------------------------------------------------------------- ::HIR::GenericParams LowerHIR_GenericParams(const ::AST::GenericParams& gp) @@ -46,10 +47,41 @@ })); ), (IsTrait, - rv.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ - LowerHIR_Type(e.type), - ::HIR::TraitPath { LowerHIR_GenericPath(bound.span, e.trait), e.hrls } - })); + auto type = LowerHIR_Type(e.type); + // Iterate associated types + for(const auto& assoc : e.trait.nodes().back().args().m_assoc) { + struct H { + static ::HIR::GenericPath get_trait_path_with_type(const Span& sp, const ::AST::Path& trait_p, const ::std::string& name) { + const auto& tr = *trait_p.binding().as_Trait().trait_; + auto it = ::std::find_if( tr.items().begin(), tr.items().end(), [&](const auto& x){return x.name == name;} ); + if( it != tr.items().end() ) + return LowerHIR_GenericPath(sp, trait_p); + + for(const auto& st : tr.supertraits()) + { + auto rv = H::get_trait_path_with_type(sp, st.ent, name); + if( rv.m_path.m_components.size() ) { + // TODO: Fix parameters based on self parameters + // - HACK! + rv.m_params = LowerHIR_PathParams(sp, trait_p.nodes().back().args()); + return rv; + } + } + + return ::HIR::GenericPath(); + } + }; + auto left_type = ::HIR::TypeRef( ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ + box$( type.clone() ), + H::get_trait_path_with_type(bound.span, e.trait, assoc.first), + assoc.first, + {} + }) ) ); + rv.m_bounds.push_back(::HIR::GenericBound::make_TypeEquality({ mv$(left_type), LowerHIR_Type(assoc.second) })); + } + + auto trait_path = LowerHIR_GenericPath(bound.span, e.trait); + rv.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ mv$(type), ::HIR::TraitPath { mv$(trait_path), e.hrls } })); ), (MaybeTrait, if( ! e.type.m_data.is_Generic() ) @@ -396,6 +428,8 @@ for(const auto& param : src_params.m_types) { params.m_types.push_back( LowerHIR_Type(param) ); } + + // Leave 'm_assoc' alone? return params; } diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index cdc1741c..987b3789 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -867,15 +867,29 @@ namespace { apply_equality(sp, left, [](const auto& x)->const auto&{return x;}, right, [](const auto& x)->const auto&{return x;}, node_ptr_ptr); } + const ::HIR::TypeRef& expand_associated_types_to(const Span& sp, const ::HIR::TypeRef& t, ::HIR::TypeRef& tmp_t) const { + TU_IFLET(::HIR::TypeRef::Data, t.m_data, Path, e, + if( e.path.m_data.is_Generic() ) + return t; + else { + tmp_t = this->expand_associated_types(sp, t.clone()); + DEBUG("Expanded " << t << " into " << tmp_t); + return tmp_t; + } + ) + else { + return t; + } + } void apply_equality(const Span& sp, const ::HIR::TypeRef& left, t_cb_generic cb_left, const ::HIR::TypeRef& right, t_cb_generic cb_right, ::HIR::ExprNodeP* node_ptr_ptr) { TRACE_FUNCTION_F(left << ", " << right); assert( ! left.m_data.is_Infer() || left.m_data.as_Infer().index != ~0u ); assert( !right.m_data.is_Infer() || right.m_data.as_Infer().index != ~0u ); // - Convert left/right types into resolved versions (either root ivar, or generic replacement) - const auto& l_t = left.m_data.is_Generic() ? cb_left (left ) : this->get_type(left ); - const auto& r_t = right.m_data.is_Generic() ? cb_right(right) : this->get_type(right); - if( l_t == r_t ) { + const auto& l_t1 = left.m_data.is_Generic() ? cb_left (left ) : this->get_type(left ); + const auto& r_t1 = right.m_data.is_Generic() ? cb_right(right) : this->get_type(right); + if( l_t1 == r_t1 ) { return ; } // If generic replacement happened, clear the callback @@ -885,6 +899,12 @@ namespace { if( right.m_data.is_Generic() ) { cb_right = [](const auto& x)->const auto&{return x;}; } + + ::HIR::TypeRef left_tmp; + const auto& l_t = this->expand_associated_types_to(sp, l_t1, left_tmp); + ::HIR::TypeRef right_tmp; + const auto& r_t = this->expand_associated_types_to(sp, r_t1, right_tmp); + DEBUG("- l_t = " << l_t << ", r_t = " << r_t); TU_IFLET(::HIR::TypeRef::Data, r_t.m_data, Infer, r_e, TU_IFLET(::HIR::TypeRef::Data, l_t.m_data, Infer, l_e, @@ -1114,14 +1134,43 @@ namespace { } } + bool check_trait_bound(const Span& sp, const ::HIR::TypeRef& type, const ::HIR::GenericPath& trait, ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> placeholder) const + { + if( this->find_trait_impls_bound(sp, trait.m_path, placeholder(type), [&](const auto& args){ + DEBUG("TODO: Check args for " << trait.m_path << args << " against " << trait); + return true; + }) + ) + { + // Satisfied by generic + return true; + } + else if( this->m_crate.find_trait_impls(trait.m_path, type, placeholder, [&](const auto& impl) { + DEBUG("- Bound " << type << " : " << trait << " satisfied by impl" << impl.m_params.fmt_args()); + // TODO: Recursively check + return true; + }) + ) + { + // Match! + return true; + } + else { + DEBUG("- Bound " << type << " : " << trait << " failed"); + return false; + } + } + /// + /// + /// ::HIR::TypeRef expand_associated_types(const Span& sp, ::HIR::TypeRef input) const { TRACE_FUNCTION_F(input); TU_MATCH(::HIR::TypeRef::Data, (input.m_data), (e), (Infer, - //auto& ty = this->get_type(input); - //return ty.clone(); + auto& ty = this->get_type(input); + return ty.clone(); ), (Diverge, ), @@ -1137,11 +1186,7 @@ namespace { TODO(sp, "Path - UfcsInherent - " << e.path); ), (UfcsKnown, - DEBUG("Checking UFCS types for " << e.path); - // HACK - Shortcut to prevent expensive search if the type is a parameter - if( e2.type->m_data.is_Generic() ) { - return input; - } + DEBUG("Locating associated type for " << e.path); *e2.type = expand_associated_types(sp, mv$(*e2.type)); @@ -1156,7 +1201,24 @@ namespace { return ty; }; - bool rv = this->m_crate.find_trait_impls(e2.trait.m_path, *e2.type, cb_get_infer, + // 1. Bounds + bool rv; + rv = this->iterate_bounds([&](const auto& b) { + TU_IFLET(::HIR::GenericBound, b, TypeEquality, be, + DEBUG("Equality - " << be.type << " = " << be.other_type); + if( input == be.type ) { + input = be.other_type.clone(); + return true; + } + ) + return false; + }); + if( rv ) { + return input; + } + + // 2. Crate-level impls + rv = this->m_crate.find_trait_impls(e2.trait.m_path, *e2.type, cb_get_infer, [&](const auto& impl) { DEBUG("Found impl" << impl.m_params.fmt_args() << " " << e2.trait.m_path << impl.m_trait_args << " for " << impl.m_type); // - Populate the impl's type arguments @@ -1181,30 +1243,24 @@ namespace { { impl.m_trait_args.m_types[i].match_generics(sp, e2.trait.m_params.m_types.at(i), cb_get_infer, cb_res); } + auto expand_placeholder = [&](const auto& ty)->const auto& { + if( ty.m_data.is_Infer() ) + return this->get_type(ty); + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, + assert( impl_args.at(e.binding) ); + return *impl_args.at(e.binding); + ) + else + return ty; + }; for( const auto& bound : impl.m_params.m_bounds ) { TU_MATCH_DEF(::HIR::GenericBound, (bound), (be), ( ), (TraitBound, - bool rv2 = this->m_crate.find_trait_impls(be.trait.m_path.m_path, be.type, - [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) - return this->get_type(ty); - else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, - assert( impl_args.at(e.binding) ); - return *impl_args.at(e.binding); - ) - else - return ty; - }, - [&](const auto& impl) { - DEBUG("- Bound " << be.type << " : " << be.trait.m_path << " satisfied by impl" << impl.m_params.fmt_args()); - // TODO: Recursively check - return true; - } - ); - if( !rv2 ) { + if( !this->check_trait_bound(sp, be.type, be.trait.m_path, expand_placeholder) ) + { DEBUG("- Bound " << be.type << " : " << be.trait.m_path << " failed"); return false; } @@ -1220,20 +1276,22 @@ namespace { impl_ptr = &impl; return true; }); - if( !rv ) - break; - - // An impl was found: - assert(impl_ptr); + if( rv ) + { + // An impl was found: + assert(impl_ptr); + + // - Monomorphise the output type + auto new_type = monomorphise_type_with(sp, impl_ptr->m_types.at( e2.item ), [&](const auto& ty)->const auto& { + const auto& ge = ty.m_data.as_Generic(); + assert(ge.binding < impl_args.size()); + return *impl_args[ge.binding]; + }); + DEBUG("Converted UfcsKnown - " << e.path << " = " << new_type << " using " << e2.item << " = " << impl_ptr->m_types.at( e2.item )); + return new_type; + } - // - Monomorphise the output type - auto new_type = monomorphise_type_with(sp, impl_ptr->m_types.at( e2.item ), [&](const auto& ty)->const auto& { - const auto& ge = ty.m_data.as_Generic(); - assert(ge.binding < impl_args.size()); - return *impl_args[ge.binding]; - }); - DEBUG("Converted UfcsKnown - " << e.path << " = " << new_type << " using " << e2.item << " = " << impl_ptr->m_types.at( e2.item )); - return new_type; + DEBUG("Couldn't resolve associated type for " << input); ), (UfcsUnknown, BUG(sp, "Encountered UfcsUnknown"); @@ -1269,36 +1327,67 @@ namespace { return input; } - /// Searches for a trait impl that matches the provided trait name and type - bool find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) + bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const { - TRACE_FUNCTION_F("trait = " << trait << ", type = " << type); - // 1. Search generic params const ::HIR::GenericParams* v[2] = { m_item_params, m_impl_params }; for(auto p : v) { if( !p ) continue ; for(const auto& b : p->m_bounds) - { - TU_IFLET(::HIR::GenericBound, b, TraitBound, e, - if( e.type != type ) - continue ; - if( e.trait.m_path.m_path == trait ) { - if( callback(e.trait.m_path.m_params) ) { - return true; - } - } - for( const auto& pt : e.trait.m_trait_ptr->m_parent_traits ) { - if( pt.m_path == trait ) { - TODO(Span(), "Fix arguments for a parent trait and call callback - " << pt << " with paramset " << e.trait.m_trait_ptr->m_params.fmt_args()); - } - } - ) - } + if(cb(b)) return true; } + return false; + } + + /// Searches for a trait impl that matches the provided trait name and type + bool find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) + { + Span sp = Span(); + TRACE_FUNCTION_F("trait = " << trait << ", type = " << type); + // 1. Search generic params + if( find_trait_impls_bound(sp, trait, type, callback) ) + return true; // 2. Search crate-level impls return find_trait_impls_crate(trait, type, callback); } + bool find_named_trait_in_trait(const Span& sp, const ::HIR::SimplePath& des, const ::HIR::Trait& trait_ptr, const ::HIR::PathParams& pp, ::std::function<bool(const ::HIR::PathParams&)> callback) const + { + assert( pp.m_types.size() == trait_ptr.m_params.m_types.size() ); + for( const auto& pt : trait_ptr.m_parent_traits ) + { + auto pt_pp = monomorphise_path_params_with(Span(), pt.m_params.clone(), [&](const auto& gt)->const auto& { + const auto& ge = gt.m_data.as_Generic(); + 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); + + if( pt.m_path == des ) { + //TODO(Span(), "Fix arguments for a parent trait and call callback - " << pt << " with paramset " << trait_ptr.m_params.fmt_args() << " = " << pt_pp); + callback( pt_pp ); + return true; + } + } + return false; + } + bool find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const + { + return this->iterate_bounds([&](const auto& b) { + TU_IFLET(::HIR::GenericBound, b, TraitBound, e, + if( e.type != type ) + return false; + if( e.trait.m_path.m_path == trait ) { + if( callback(e.trait.m_path.m_params) ) { + return true; + } + } + if( this->find_named_trait_in_trait(sp, trait, *e.trait.m_trait_ptr, e.trait.m_path.m_params, callback) ) { + return true; + } + ) + return false; + }); + } bool find_trait_impls_crate(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const { return this->m_crate.find_trait_impls(trait, type, [&](const auto& ty)->const auto&{ @@ -1504,7 +1593,8 @@ namespace { case ::HIR::InferClass::Float: switch(ct) { - case ::HIR::CoreType::F32: case ::HIR::CoreType::F64: + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: break; default: ERROR(sp, E0000, "Type unificiation of integer literal with non-integer - " << type); @@ -2508,21 +2598,64 @@ namespace { const auto& ty = this->context.get_type(node.m_value->m_res_type); DEBUG("(CallValue) ty = " << ty); - TU_MATCH_DEF(decltype(ty.m_data), (ty.m_data), (e), - ( - // Locate impl of FnOnce - this->context.find_trait_impls(this->context.m_crate.get_lang_item_path(node.span(), "fn_once"), ty, [&](const auto& args) { - DEBUG("TODO: Handle FnOnce for type, FnOnce" << args); - return false; - }); - TODO(node.span(), "CallValue with other type - " << ty); - ), - (Function, - TODO(node.span(), "CallValue with Function - " << ty); - ), - (Infer, + if( node.m_arg_types.size() == 0 ) + { + TU_MATCH_DEF(decltype(ty.m_data), (ty.m_data), (e), + ( + ::HIR::TypeRef fcn_args_tup; + ::HIR::TypeRef fcn_ret; + // Locate impl of FnOnce + const auto& lang_FnOnce = this->context.m_crate.get_lang_item_path(node.span(), "fn_once"); + auto was_bounded = this->context.find_trait_impls_bound(node.span(), lang_FnOnce, ty, [&](const auto& args) { + const auto& tup = args.m_types[0]; + if( !tup.m_data.is_Tuple() ) + ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); + fcn_args_tup = tup.clone(); + return true; + }); + if( was_bounded ) + { + // RV must be in a bound + fcn_ret = ::HIR::TypeRef( ::HIR::Path(::HIR::Path::Data::make_UfcsKnown({ + box$( ty.clone() ), + ::HIR::GenericPath(lang_FnOnce), + "Output", + {} + })) ); + fcn_ret.m_data.as_Path().path.m_data.as_UfcsKnown().trait.m_params.m_types.push_back( fcn_args_tup.clone() ); + } + else if( !ty.m_data.is_Generic() ) + { + TODO(node.span(), "Search for other implementations of FnOnce for " << ty); + } + else + { + // Didn't find anything. Error? + TODO(node.span(), "Unable to find an implementation of Fn* for " << ty); + } + + node.m_arg_types = mv$( fcn_args_tup.m_data.as_Tuple() ); + node.m_arg_types.push_back( mv$(fcn_ret) ); + ), + (Function, + TODO(node.span(), "CallValue with Function - " << ty); + ), + (Infer, + ) ) - ) + } + + if( node.m_args.size() + 1 != node.m_arg_types.size() ) { + ERROR(node.span(), E0000, "Incorrect number of arguments when calling " << ty); + } + + for( unsigned int i = 0; i < node.m_args.size(); i ++ ) + { + auto& arg_node = node.m_args[i]; + this->context.apply_equality(node.span(), node.m_arg_types[i], arg_node->m_res_type, &arg_node); + } + // TODO: Allow infer + this->context.apply_equality(node.span(), node.m_res_type, node.m_arg_types.back()); ::HIR::ExprVisitorDef::visit(node); } @@ -2723,8 +2856,9 @@ void Typecheck_Code(TypecheckContext context, const ::HIR::TypeRef& result_type, ExprVisitor_Run visitor { context }; unsigned int count = 0; do { - visitor.visit_node_ptr(root_ptr); count += 1; + DEBUG("==== PASS " << count << " ===="); + visitor.visit_node_ptr(root_ptr); assert(count < 1000); } while( context.take_changed() ); } diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index 9fc63f11..e1c83f55 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -190,7 +190,7 @@ namespace { ), (TypeEquality, // TODO: Check that two types are equal in this case - TODO(sp, "TypeEquality - " << e.type << " == " << e.other_type); + DEBUG("TODO: Check equality bound " << e.type << " == " << e.other_type); ) ) } diff --git a/src/include/debug.hpp b/src/include/debug.hpp index 8aace983..c9fd20eb 100644 --- a/src/include/debug.hpp +++ b/src/include/debug.hpp @@ -68,7 +68,7 @@ public: ~TraceLog() { UNINDENT(); if(debug_enabled()) { - auto& os = debug_output(g_debug_indent_level, __FUNCTION__); + auto& os = debug_output(g_debug_indent_level, "TraceLog"); os << " << " << m_tag; m_ret(os); os << ::std::endl; diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index 2c97075e..6b84ec0b 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -156,9 +156,8 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi params = ::AST::PathParams { {}, ::std::vector<TypeRef> { TypeRef(TypeRef::TagTuple(), lex.end_span(ps), ::std::move(args)) }, - { ::std::make_pair( (::std::string)"Output", mv$(ret_type) ) } + { ::std::make_pair( ::std::string("Output"), mv$(ret_type) ) } }; - // TODO: Use 'ret_type' as an associated type bound GET_TOK(tok, lex); } |