diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common.hpp | 14 | ||||
-rw-r--r-- | src/hir/from_ast.cpp | 6 | ||||
-rw-r--r-- | src/hir/hir.cpp | 3 | ||||
-rw-r--r-- | src/hir_typeck/expr.cpp | 176 |
4 files changed, 145 insertions, 54 deletions
diff --git a/src/common.hpp b/src/common.hpp index da2c3898..bb3ef72e 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -208,4 +208,18 @@ inline ::std::ostream& operator<<(::std::ostream& os, const ::std::multimap<T,U, } +// ------------------------------------------------------------------- +// --- Reversed iterable +template <typename T> +struct reversion_wrapper { T& iterable; }; + +template <typename T> +auto begin (reversion_wrapper<T> w) { return ::std::rbegin(w.iterable); } + +template <typename T> +auto end (reversion_wrapper<T> w) { return ::std::rend(w.iterable); } + +template <typename T> +reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; } + #endif diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 9a9b7a85..0c094484 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -824,6 +824,12 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H // TODO: Impl blocks // TODO: Populate trait list + for(const auto& item : module.m_type_items) + { + if( item.second.path.binding().is_Trait() ) { + mod.m_traits.push_back( LowerHIR_SimplePath(Span(), item.second.path) ); + } + } return mod; } diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index fa9954d3..66f09379 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -32,6 +32,7 @@ namespace HIR { namespace { bool matches_type_int(const ::HIR::GenericParams& params, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right) { + //DEBUG("left = " << left << ", right = " << right); assert(! left.m_data.is_Infer() ); if( right.m_data.is_Infer() ) { // TODO: Why is this false? A _ type could match anything @@ -39,7 +40,7 @@ namespace { } if( left.m_data.is_Generic() ) { - // True? + // True? (TODO: Check bounds?) return true; } diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index a4ec14cf..177e36dd 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -194,6 +194,7 @@ namespace { { public: const ::HIR::Crate& m_crate; + ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; private: ::std::vector< Variable> m_locals; ::std::vector< IVar> m_ivars; @@ -1069,6 +1070,24 @@ namespace { } } // 2. Search crate-level impls + return find_trait_impls_crate(trait, type, callback); + } + bool find_trait_impls_crate(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const + { + auto its = m_crate.m_trait_impls.equal_range( trait ); + if( its.first != its.second ) + { + for( auto it = its.first; it != its.second; ++ it ) + { + const auto& impl = it->second; + DEBUG("Compare " << type << " and " << impl.m_type); + if( impl.matches_type(type) ) { + if( callback(impl.m_trait_args) ) { + return true; + } + } + } + } return false; } /// Locate the named method by applying auto-dereferencing. @@ -1117,25 +1136,44 @@ namespace { ) } } - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, - if( e.name == "Self" ) { - TODO(sp, "Search for methods on 'Self'"); - } - else { - TODO(sp, "Search for methods on parameter #" << e.binding << " '" << e.name << "'"); - } + // No match, keep trying. ) else { - // 1. Search for inherent methods + // 2. Search for inherent methods for(const auto& impl : m_crate.m_type_impls) { if( impl.matches_type(ty) ) { DEBUG("Mactching impl " << impl.m_type); + fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsInherent({ + box$(ty.clone()), + method_name, + {} + }) ); + return deref_count; + } + } + // 3. Search for trait methods (using currently in-scope traits) + for(const auto& trait_ref : ::reverse(m_traits)) + { + auto it = trait_ref.second->m_values.find(method_name); + if( it == trait_ref.second->m_values.end() ) + continue ; + if( !it->second.is_Function() ) + continue ; + DEBUG("Search for impl of " << *trait_ref.first); + if( find_trait_impls_crate(*trait_ref.first, ty, [](const auto&) { return true; }) ) { + DEBUG("Found trait impl " << *trait_ref.first << " for " << ty); + fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ + box$( ty.clone() ), + trait_ref.first->clone(), + method_name, + {} + }) ); + return deref_count; } } - // 2. Search for trait methods (using currently in-scope traits) } // 3. Dereference and try again @@ -1144,6 +1182,7 @@ namespace { current_ty = &*e.inner; ) else { + // TODO: Search for a Deref impl current_ty = nullptr; } } while( current_ty ); @@ -1674,68 +1713,81 @@ namespace { } ::HIR::ExprVisitorDef::visit(node); } - // - Call Path: Locate path and build return - void visit(::HIR::ExprNode_CallPath& node) override + + void fix_param_count(const Span& sp, const ::HIR::Path& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params) { - TRACE_FUNCTION_F("CallPath " << node.m_path); - // TODO: Construct method to get a reference to an item along with the params decoded out of the pat - TU_MATCH(::HIR::Path::Data, (node.m_path.m_data), (e), - (Generic, - const auto& fcn = this->context.m_crate.get_function_by_path(node.span(), e.m_path); - if( node.m_args.size() != fcn.m_args.size() ) { - ERROR(node.span(), E0000, "Incorrect number of arguments to " << node.m_path); + if( params.m_types.size() == param_defs.m_types.size() ) { + // Nothing to do, all good + return ; + } + + if( params.m_types.size() == 0 ) { + for(const auto& typ : param_defs.m_types) { + (void)typ; + params.m_types.push_back( this->context.new_ivar_tr() ); } - - // - Ensure that the number of paramters is correct - // TODO: Abstract this - if( e.m_params.m_types.size() != fcn.m_params.m_types.size() ) { - if( e.m_params.m_types.size() == 0 ) { - for(const auto& typ : fcn.m_params.m_types) { - (void)typ; - e.m_params.m_types.push_back( this->context.new_ivar_tr() ); - } - } - else if( e.m_params.m_types.size() > fcn.m_params.m_types.size() ) { - ERROR(node.span(), E0000, ""); + } + else if( params.m_types.size() > param_defs.m_types.size() ) { + ERROR(sp, E0000, "Too many type parameters passed to " << path); + } + else { + while( params.m_types.size() < param_defs.m_types.size() ) { + const auto& typ = param_defs.m_types[params.m_types.size()]; + if( typ.m_default.m_data.is_Infer() ) { + ERROR(sp, E0000, "Omitted type parameter with no default in " << path); } else { - while( e.m_params.m_types.size() < fcn.m_params.m_types.size() ) { - const auto& typ = fcn.m_params.m_types[e.m_params.m_types.size()]; - if( typ.m_default.m_data.is_Infer() ) { - ERROR(node.span(), E0000, ""); - } - else { - // TODO: What if this contains a generic param? (is that valid?) - e.m_params.m_types.push_back( typ.m_default.clone() ); - } - } + // TODO: What if this contains a generic param? (is that valid?) + params.m_types.push_back( typ.m_default.clone() ); } } + } + } + + void visit_call(const Span& sp, ::HIR::Path& path, bool is_method, ::std::vector< ::HIR::ExprNodeP>& args, ::HIR::TypeRef& res_type) + { + unsigned int arg_ofs = (is_method ? 1 : 0); + // TODO: Construct method to get a reference to an item along with the params decoded out of the pat + TU_MATCH(::HIR::Path::Data, (path.m_data), (e), + (Generic, + const auto& fcn = this->context.m_crate.get_function_by_path(sp, e.m_path); + if( args.size() + (is_method ? 1 : 0) != fcn.m_args.size() ) { + ERROR(sp, E0000, "Incorrect number of arguments to " << path); + } + // - Ensure that the number of paramters is correct + this->fix_param_count(sp, path, fcn.m_params, e.m_params); // TODO: Avoid needing to monomorphise here // - Have two callbacks to apply_equality that are used to expand `Generic`s (cleared once used) - for( unsigned int i = 0; i < fcn.m_args.size(); i ++ ) + for( unsigned int i = arg_ofs; i < fcn.m_args.size(); i ++ ) { const auto& arg_ty = fcn.m_args[i].second; DEBUG("arg_ty = " << arg_ty); ::HIR::TypeRef mono_type; - const auto& ty = (monomorphise_type_needed(arg_ty) ? (mono_type = monomorphise_type(node.span(), fcn.m_params, e.m_params, arg_ty)) : arg_ty); - this->context.apply_equality(node.span(), ty, node.m_args[i]->m_res_type); + const auto& ty = (monomorphise_type_needed(arg_ty) ? (mono_type = monomorphise_type(sp, fcn.m_params, e.m_params, arg_ty)) : arg_ty); + this->context.apply_equality(sp, ty, args[i-arg_ofs]->m_res_type); } ::HIR::TypeRef mono_type; - const auto& ty = (monomorphise_type_needed(fcn.m_return) ? (mono_type = monomorphise_type(node.span(), fcn.m_params, e.m_params, fcn.m_return)) : fcn.m_return); - this->context.apply_equality(node.span(), node.m_res_type, ty); + const auto& ty = (monomorphise_type_needed(fcn.m_return) ? (mono_type = monomorphise_type(sp, fcn.m_params, e.m_params, fcn.m_return)) : fcn.m_return); + this->context.apply_equality(sp, res_type, ty); ), (UfcsKnown, - DEBUG("TODO - Locate functions in UFCS known"); + TODO(sp, "Locate functions in UFCS known - " << path); ), (UfcsUnknown, - TODO(node.span(), "Hit a UfcsUnknown (" << node.m_path << ") - Is this an error?"); + TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?"); ), (UfcsInherent, - DEBUG("TODO - Locate functions in UFCS inherent"); + TODO(sp, "Locate functions in UFCS inherent - " << path); ) ) + } + + // - Call Path: Locate path and build return + void visit(::HIR::ExprNode_CallPath& node) override + { + TRACE_FUNCTION_F("CallPath " << node.m_path); + visit_call(node.span(), node.m_path, false, node.m_args, node.m_res_type); ::HIR::ExprVisitorDef::visit(node); } // - Call Value: If type is known, locate impl of Fn/FnMut/FnOnce @@ -1751,12 +1803,11 @@ namespace { { const auto& ty = this->context.get_type(node.m_val->m_res_type); DEBUG("ty = " << ty); - // TODO: Using autoderef, locate this method on the type + // Using autoderef, locate this method on the type ::HIR::Path fcn_path { ::HIR::SimplePath() }; unsigned int deref_count = this->context.autoderef_find_method(node.span(), ty, node.m_method, fcn_path); - if( deref_count != ~0u ) { - // TODO: Add derefs (or record somewhere) - // TODO: Replace this node with CallPath + if( deref_count != ~0u ) + { DEBUG("Found method " << fcn_path); node.m_method_path = mv$(fcn_path); // NOTE: Steals the params from the node @@ -1782,7 +1833,8 @@ namespace { } } - // TODO: Look up method based on node.m_method_path + // TODO: Look up method based on node.m_method_path, using shared code with ExprNode_CallPath + visit_call(node.span(), node.m_method_path, true, node.m_args, node.m_res_type); } // - Field: Locate field on type void visit(::HIR::ExprNode_Field& node) override @@ -1952,6 +2004,7 @@ namespace { ::HIR::GenericParams* m_impl_generics; ::HIR::GenericParams* m_item_generics; + ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; public: OuterVisitor(::HIR::Crate& crate): m_crate(crate), @@ -1984,6 +2037,18 @@ namespace { } public: + void visit_module(::HIR::PathChain p, ::HIR::Module& mod) override + { + DEBUG("Module has " << mod.m_traits.size() << " in-scope traits"); + for( const auto& trait_path : mod.m_traits ) { + DEBUG("Push " << trait_path); + m_traits.push_back( ::std::make_pair( &trait_path, &this->m_crate.get_trait_by_path(Span(), trait_path) ) ); + } + ::HIR::Visitor::visit_module(p, mod); + for(unsigned int i = 0; i < mod.m_traits.size(); i ++ ) + m_traits.pop_back(); + } + // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure void visit_expr(::HIR::ExprPtr& exp) { TODO(Span(), "visit_expr"); @@ -2022,6 +2087,7 @@ namespace { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, this->visit_type( *e.inner ); TypecheckContext typeck_context { m_crate, m_impl_generics, m_item_generics }; + typeck_context.m_traits = this->m_traits; DEBUG("Array size " << ty); Typecheck_Code( mv$(typeck_context), ::HIR::TypeRef(::HIR::CoreType::Usize), e.size ); ) @@ -2037,6 +2103,7 @@ namespace { if( item.m_code ) { TypecheckContext typeck_context { m_crate, m_impl_generics, m_item_generics }; + typeck_context.m_traits = this->m_traits; for( auto& arg : item.m_args ) { typeck_context.add_binding( Span(), arg.first, arg.second ); } @@ -2049,6 +2116,7 @@ namespace { if( item.m_value ) { TypecheckContext typeck_context { m_crate, m_impl_generics, m_item_generics }; + typeck_context.m_traits = this->m_traits; DEBUG("Static value " << p); Typecheck_Code( mv$(typeck_context), item.m_type, item.m_value ); } @@ -2058,6 +2126,7 @@ namespace { if( item.m_value ) { TypecheckContext typeck_context { m_crate, m_impl_generics, m_item_generics }; + typeck_context.m_traits = this->m_traits; DEBUG("Const value " << p); Typecheck_Code( mv$(typeck_context), item.m_type, item.m_value ); } @@ -2073,6 +2142,7 @@ namespace { { TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, TypecheckContext typeck_context { m_crate, m_impl_generics, m_item_generics }; + typeck_context.m_traits = this->m_traits; DEBUG("Enum value " << p << " - " << var.first); Typecheck_Code( mv$(typeck_context), enum_type, e ); ) |