diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/from_ast.cpp | 89 | ||||
-rw-r--r-- | src/hir/from_ast.hpp | 2 | ||||
-rw-r--r-- | src/hir/generic_params.hpp | 10 | ||||
-rw-r--r-- | src/hir/hir.hpp | 4 | ||||
-rw-r--r-- | src/hir/path.cpp | 57 | ||||
-rw-r--r-- | src/hir/path.hpp | 8 | ||||
-rw-r--r-- | src/hir/type.cpp | 2 | ||||
-rw-r--r-- | src/hir/type.hpp | 2 | ||||
-rw-r--r-- | src/hir/visitor.cpp | 12 | ||||
-rw-r--r-- | src/hir/visitor.hpp | 1 | ||||
-rw-r--r-- | src/hir_conv/resolve_ufcs.cpp | 4 | ||||
-rw-r--r-- | src/hir_typeck/expr.cpp | 42 | ||||
-rw-r--r-- | src/hir_typeck/expr.hpp | 13 | ||||
-rw-r--r-- | src/hir_typeck/expr_context.cpp | 170 | ||||
-rw-r--r-- | src/resolve/absolute.cpp | 6 |
15 files changed, 309 insertions, 113 deletions
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index d7f95d81..8a975c25 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -10,7 +10,8 @@ ::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::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& src_params, bool allow_assoc); +::HIR::TraitPath LowerHIR_TraitPath(const Span& sp, const ::AST::Path& path); const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); @@ -50,42 +51,11 @@ const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); ), (IsTrait, 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) })); - } // TODO: Check for `Sized` - 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 } })); + rv.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ mv$(type), LowerHIR_TraitPath(bound.span, e.trait) })); + rv.m_bounds.back().as_TraitBound().trait.m_hrls = e.hrls; ), (MaybeTrait, if( ! e.type.m_data.is_Generic() ) @@ -437,7 +407,7 @@ const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); throw "BUG: Encountered non-Absolute path when creating ::HIR::GenericPath"; } } -::HIR::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& src_params) +::HIR::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& src_params, bool allow_assoc) { ::HIR::PathParams params; @@ -450,14 +420,18 @@ const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); } // Leave 'm_assoc' alone? + if( !allow_assoc && src_params.m_assoc.size() > 0 ) + { + BUG(sp, "Encountered path parameters with associated type bounds where they are not allowed"); + } return params; } -::HIR::GenericPath LowerHIR_GenericPath(const Span& sp, const ::AST::Path& path) +::HIR::GenericPath LowerHIR_GenericPath(const Span& sp, const ::AST::Path& path, bool allow_assoc) { TU_IFLET(::AST::Path::Class, path.m_class, Absolute, e, auto simpepath = LowerHIR_SimplePath(sp, path, true); - ::HIR::PathParams params = LowerHIR_PathParams(sp, e.nodes.back().args()); + ::HIR::PathParams params = LowerHIR_PathParams(sp, e.nodes.back().args(), allow_assoc); auto rv = ::HIR::GenericPath(mv$(simpepath), mv$(params)); DEBUG(path << " => " << rv); return rv; @@ -466,6 +440,22 @@ const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); BUG(sp, "Encountered non-Absolute path when creating ::HIR::GenericPath - " << path); } } +::HIR::TraitPath LowerHIR_TraitPath(const Span& sp, const ::AST::Path& path) +{ + ::HIR::TraitPath rv { + LowerHIR_GenericPath(sp, path, true), + {}, + {}, + nullptr + }; + + for(const auto& assoc : path.nodes().back().args().m_assoc) + { + rv.m_type_bounds.insert(::std::make_pair( assoc.first, LowerHIR_Type(assoc.second) )); + } + + return rv; +} ::HIR::Path LowerHIR_Path(const Span& sp, const ::AST::Path& path) { TU_MATCH(::AST::Path::Class, (path.m_class), (e), @@ -490,7 +480,8 @@ const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); (UFCS, if( e.nodes.size() != 1 ) TODO(sp, "Handle UFCS with multiple nodes - " << path); - auto params = LowerHIR_PathParams(sp, e.nodes.front().args()); + // - No associated type bounds allowed in UFCS paths + auto params = LowerHIR_PathParams(sp, e.nodes.front().args(), false); if( ! e.trait ) { auto type = box$( LowerHIR_Type(*e.type) ); @@ -624,10 +615,11 @@ const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); v.m_markers.push_back( LowerHIR_GenericPath(ty.span(), t) ); } else { - if( v.m_trait.m_path.m_components.size() > 0 ) { + // TraitPath -> GenericPath -> SimplePath + if( v.m_trait.m_path.m_path.m_components.size() > 0 ) { ERROR(ty.span(), E0000, "Multiple data traits in trait object - " << ty); } - v.m_trait = LowerHIR_GenericPath(ty.span(), t); + v.m_trait = LowerHIR_TraitPath(ty.span(), t); } } return ::HIR::TypeRef( ::HIR::TypeRef::Data::make_TraitObject( mv$(v) ) ); @@ -737,23 +729,10 @@ const ::HIR::SimplePath path_Sized = ::HIR::SimplePath("", {"marker", "Sized"}); auto params = LowerHIR_GenericParams(f.params(), &trait_reqires_sized); ::std::string lifetime; - ::std::vector< ::HIR::GenericPath> supertraits; + ::std::vector< ::HIR::TraitPath> supertraits; for(const auto& st : f.supertraits()) { if( st.ent.is_valid() ) { - supertraits.push_back( LowerHIR_GenericPath(st.sp, st.ent) ); - const auto& atype_bounds = st.ent.nodes().back().args().m_assoc; - for(const auto& atype : atype_bounds) - { - params.m_bounds.push_back( ::HIR::GenericBound::make_TypeEquality({ - ::HIR::TypeRef(::HIR::Path(::HIR::Path::Data::make_UfcsKnown({ - box$( ::HIR::TypeRef("Self",0xFFFF) ), - supertraits.back().clone(), - atype.first, - {} - }))), - LowerHIR_Type(atype.second) - }) ); - } + supertraits.push_back( LowerHIR_TraitPath(st.sp, st.ent) ); } else { lifetime = "static"; diff --git a/src/hir/from_ast.hpp b/src/hir/from_ast.hpp index 0822c835..f0795fcf 100644 --- a/src/hir/from_ast.hpp +++ b/src/hir/from_ast.hpp @@ -4,7 +4,7 @@ extern ::HIR::ExprPtr LowerHIR_ExprNode(const ::AST::ExprNode& e); extern ::HIR::Path LowerHIR_Path(const Span& sp, const ::AST::Path& path); -extern ::HIR::GenericPath LowerHIR_GenericPath(const Span& sp, const ::AST::Path& path); +extern ::HIR::GenericPath LowerHIR_GenericPath(const Span& sp, const ::AST::Path& path, bool allow_assoc=false); extern ::HIR::TypeRef LowerHIR_Type(const ::TypeRef& ty); extern ::HIR::Pattern LowerHIR_Pattern(const ::AST::Pattern& pat); diff --git a/src/hir/generic_params.hpp b/src/hir/generic_params.hpp index 1870b904..52ba2976 100644 --- a/src/hir/generic_params.hpp +++ b/src/hir/generic_params.hpp @@ -27,11 +27,11 @@ TAGGED_UNION(GenericBound, Lifetime, (TraitBound, struct { ::HIR::TypeRef type; ::HIR::TraitPath trait; - }), - //(NotTrait, struct { - // ::HIR::TypeRef type; - // ::HIR::GenricPath trait; - // }), + })/*, + (NotTrait, struct { + ::HIR::TypeRef type; + ::HIR::GenricPath trait; + })*/, (TypeEquality, struct { ::HIR::TypeRef type; ::HIR::TypeRef other_type; diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 1b0b091f..fb27c44d 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -151,14 +151,14 @@ struct Trait { GenericParams m_params; ::std::string m_lifetime; - ::std::vector< ::HIR::GenericPath > m_parent_traits; + ::std::vector< ::HIR::TraitPath > m_parent_traits; bool m_is_marker; ::std::unordered_map< ::std::string, AssociatedType > m_types; ::std::unordered_map< ::std::string, TraitValueItem > m_values; - Trait( GenericParams gps, ::std::string lifetime, ::std::vector< ::HIR::GenericPath> parents): + Trait( GenericParams gps, ::std::string lifetime, ::std::vector< ::HIR::TraitPath> parents): m_params( mv$(gps) ), m_lifetime( mv$(lifetime) ), m_parent_traits( mv$(parents) ) diff --git a/src/hir/path.cpp b/src/hir/path.cpp index 3cc1d817..fb153d7d 100644 --- a/src/hir/path.cpp +++ b/src/hir/path.cpp @@ -50,6 +50,31 @@ namespace HIR { os << x.m_path << x.m_params; return os; } + ::std::ostream& operator<<(::std::ostream& os, const TraitPath& x) + { + if( x.m_hrls.size() > 0 ) { + os << "for<"; + for(const auto& lft : x.m_hrls) + os << "'" << lft << ","; + os << "> "; + } + os << x.m_path.m_path; + bool has_args = ( x.m_path.m_params.m_types.size() > 0 || x.m_type_bounds.size() > 0 ); + + if(has_args) { + os << "<"; + } + for(const auto& ty : x.m_path.m_params.m_types) { + os << ty << ","; + } + for(const auto& assoc : x.m_type_bounds) { + os << assoc.first << "=" << assoc.second << ","; + } + if(has_args) { + os << ">"; + } + return os; + } ::std::ostream& operator<<(::std::ostream& os, const Path& x) { TU_MATCH(::HIR::Path::Data, (x.m_data), (e), @@ -118,6 +143,38 @@ bool ::HIR::GenericPath::operator==(const GenericPath& x) const return m_params == x.m_params; } +::HIR::TraitPath HIR::TraitPath::clone() const +{ + ::HIR::TraitPath rv { + m_path.clone(), + m_hrls, + {}, + m_trait_ptr + }; + + for( const auto& assoc : m_type_bounds ) + rv.m_type_bounds.insert(::std::make_pair( assoc.first, assoc.second.clone() )); + + return rv; +} +bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const +{ + if( m_path != x.m_path ) + return false; + if( m_hrls != x.m_hrls ) + return false; + + if( m_type_bounds.size() != x.m_type_bounds.size() ) + return false; + + for(auto it_l = m_type_bounds.begin(), it_r = x.m_type_bounds.begin(); it_l != m_type_bounds.end(); it_l++, it_r++ ) { + if( it_l->first != it_r->first ) + return false; + if( it_l->second != it_r->second ) + return false; + } + return true; +} ::HIR::Path::Path(::HIR::GenericPath gp): m_data( ::HIR::Path::Data::make_Generic( mv$(gp) ) ) diff --git a/src/hir/path.hpp b/src/hir/path.hpp index 50973b85..a4603fe3 100644 --- a/src/hir/path.hpp +++ b/src/hir/path.hpp @@ -100,7 +100,15 @@ class TraitPath public: GenericPath m_path; ::std::vector< ::std::string> m_hrls; + ::std::map< ::std::string, ::HIR::TypeRef> m_type_bounds; + const ::HIR::Trait* m_trait_ptr; + + TraitPath clone() const; + bool operator==(const TraitPath& x) const; + bool operator!=(const TraitPath& x) const { return !(*this == x); } + + friend ::std::ostream& operator<<(::std::ostream& os, const TraitPath& x); }; class Path diff --git a/src/hir/type.cpp b/src/hir/type.cpp index f78c45ad..b57dcc7c 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -250,7 +250,7 @@ bool ::HIR::TypeRef::operator==(const ::HIR::TypeRef& x) const (Closure, if( te.node != xe.node ) return false; - assert( te.m_rettype == xe.m_rettype ); + //assert( te.m_rettype == xe.m_rettype ); return true; ) ) diff --git a/src/hir/type.hpp b/src/hir/type.hpp index e5ccf0ce..8a090b26 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -100,7 +100,7 @@ public: unsigned int binding; }), (TraitObject, struct { - ::HIR::GenericPath m_trait; // TODO: Use TraitPath? + ::HIR::TraitPath m_trait; ::std::vector< ::HIR::GenericPath > m_markers; ::HIR::LifetimeRef m_lifetime; }), diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index a2432971..cb168347 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -141,7 +141,7 @@ void ::HIR::Visitor::visit_trait(::HIR::PathChain p, ::HIR::Trait& item) TRACE_FUNCTION; this->visit_params(item.m_params); for(auto& par : item.m_parent_traits) { - this->visit_generic_path(par, ::HIR::Visitor::PathContext::TYPE); + this->visit_trait_path(par); } for(auto& i : item.m_types) { DEBUG("type " << i.first); @@ -245,7 +245,7 @@ void ::HIR::Visitor::visit_params(::HIR::GenericParams& params) ), (TraitBound, this->visit_type(e.type); - this->visit_generic_path(e.trait.m_path, ::HIR::Visitor::PathContext::TYPE); + this->visit_trait_path(e.trait); ), //(NotTrait, struct { // ::HIR::TypeRef type; @@ -273,7 +273,7 @@ void ::HIR::Visitor::visit_type(::HIR::TypeRef& ty) (Generic, ), (TraitObject, - this->visit_generic_path(e.m_trait, ::HIR::Visitor::PathContext::TYPE); + this->visit_trait_path(e.m_trait); for(auto& trait : e.m_markers) { this->visit_generic_path(trait, ::HIR::Visitor::PathContext::TYPE); } @@ -383,6 +383,12 @@ void ::HIR::Visitor::visit_pattern_val(::HIR::Pattern::Value& val) ) ) } +void ::HIR::Visitor::visit_trait_path(::HIR::TraitPath& p) +{ + this->visit_generic_path(p.m_path, ::HIR::Visitor::PathContext::TYPE); + for(auto& assoc : p.m_type_bounds) + this->visit_type(assoc.second); +} void ::HIR::Visitor::visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) { TU_MATCH(::HIR::Path::Data, (p.m_data), (e), diff --git a/src/hir/visitor.hpp b/src/hir/visitor.hpp index fb71ba35..8e0d6d39 100644 --- a/src/hir/visitor.hpp +++ b/src/hir/visitor.hpp @@ -81,6 +81,7 @@ public: VALUE, }; + virtual void visit_trait_path(::HIR::TraitPath& p); virtual void visit_path(::HIR::Path& p, PathContext ); virtual void visit_path_params(::HIR::PathParams& p); virtual void visit_generic_path(::HIR::GenericPath& p, PathContext ); diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 6cd5891c..daa075ba 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -196,7 +196,7 @@ namespace { // Search supertraits (recursively) for( unsigned int i = 0; i < trait.m_parent_traits.size(); i ++ ) { - const auto& par_trait_path = trait.m_parent_traits[i]; + const auto& par_trait_path = trait.m_parent_traits[i].m_path; //const auto& par_trait_ent = *trait.m_parent_trait_ptrs[i]; const auto& par_trait_ent = this->find_trait(par_trait_path.m_path); if( locate_in_trait_and_set(pc, par_trait_path, par_trait_ent, pd) ) { @@ -231,7 +231,7 @@ namespace { // Search supertraits (recursively) for( unsigned int i = 0; i < trait.m_parent_traits.size(); i ++ ) { - const auto& par_trait_path = trait.m_parent_traits[i]; + const auto& par_trait_path = trait.m_parent_traits[i].m_path; //const auto& par_trait_ent = *trait.m_parent_trait_ptrs[i]; const auto& par_trait_ent = this->find_trait(par_trait_path.m_path); // TODO: Modify path parameters based on the current trait's params diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index a41dfe93..00d6e096 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -37,6 +37,14 @@ namespace typeck { ) throw ""; } + bool monomorphise_traitpath_needed(const ::HIR::TraitPath& tpl) + { + if( monomorphise_pathparams_needed(tpl.m_path.m_params) ) return true; + for(const auto& assoc : tpl.m_type_bounds) + if( monomorphise_type_needed(assoc.second) ) + return true; + return false; + } bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) { TU_MATCH(::HIR::TypeRef::Data, (tpl.m_data), (e), @@ -56,9 +64,11 @@ namespace typeck { return true; ), (TraitObject, - if( monomorphise_pathparams_needed(e.m_trait.m_params) ) return true; + if( monomorphise_traitpath_needed(e.m_trait) ) + return true; for(const auto& trait : e.m_markers) - if( monomorphise_pathparams_needed(trait.m_params) ) return true; + if( monomorphise_pathparams_needed(trait.m_params) ) + return true; return false; ), (Array, @@ -101,6 +111,20 @@ namespace typeck { { return ::HIR::GenericPath( tpl.m_path, monomorphise_path_params_with(sp, tpl.m_params, callback, allow_infer) ); } + ::HIR::TraitPath monomorphise_traitpath_with(const Span& sp, const ::HIR::TraitPath& tpl, t_cb_generic callback, bool allow_infer) + { + ::HIR::TraitPath rv { + monomorphise_genericpath_with(sp, tpl.m_path, callback, allow_infer), + tpl.m_hrls, + {}, + tpl.m_trait_ptr + }; + + for(const auto& assoc : tpl.m_type_bounds) + rv.m_type_bounds.insert(::std::make_pair( assoc.first, monomorphise_type_with(sp, assoc.second, callback, allow_infer) )); + + return rv; + } ::HIR::TypeRef monomorphise_type_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer) { TRACE_FUNCTION_F("tpl = " << tpl); @@ -145,7 +169,7 @@ namespace typeck { ), (TraitObject, ::HIR::TypeRef::Data::Data_TraitObject rv; - rv.m_trait = monomorphise_genericpath_with(sp, e.m_trait, callback, allow_infer); + rv.m_trait = monomorphise_traitpath_with(sp, e.m_trait, callback, allow_infer); for(const auto& trait : e.m_markers) { rv.m_markers.push_back( monomorphise_genericpath_with(sp, trait, callback, allow_infer) ); @@ -700,7 +724,7 @@ namespace typeck { const auto& ops_trait = this->context.m_crate.get_lang_item_path(node.span(), item_name); DEBUG("Searching for impl " << ops_trait << "< " << ty_right << "> for " << ty_left); bool found_bound = this->context.find_trait_impls_bound(sp, ops_trait, ty_left, - [&](const auto& args) { + [&](const auto& args, const auto& assoc) { assert(args.m_types.size() == 1); const auto& arg_type = args.m_types[0]; // TODO: if arg_type mentions Self? @@ -1316,6 +1340,11 @@ namespace typeck { DEBUG("- No impl of " << be.trait.m_path << " for " << real_type); continue ; } + for( const auto& assoc : be.trait.m_type_bounds ) { + auto ty = ::HIR::TypeRef( ::HIR::Path(::HIR::Path::Data::Data_UfcsKnown { box$(real_type.clone()), be.trait.m_path.clone(), assoc.first, {} }) ); + this->context.apply_equality( sp, ty, [](const auto&x)->const auto&{return x;}, assoc.second, cache.m_monomorph_cb, nullptr ); + } + ), (TypeEquality, #if 0 @@ -1359,7 +1388,7 @@ namespace typeck { ::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) { + auto was_bounded = this->context.find_trait_impls_bound(node.span(), lang_FnOnce, ty, [&](const auto& args, const auto& assoc) { const auto& tup = args.m_types[0]; if( !tup.m_data.is_Tuple() ) ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); @@ -1384,7 +1413,7 @@ namespace typeck { else { // Didn't find anything. Error? - TODO(node.span(), "Unable to find an implementation of Fn* for " << ty); + ERROR(node.span(), E0000, "Unable to find an implementation of Fn* for " << ty); } node.m_arg_types = mv$( fcn_args_tup.m_data.as_Tuple() ); @@ -1476,6 +1505,7 @@ namespace typeck { BUG(sp, "Unknown target PathValue encountered with Generic path"); case ::HIR::ExprNode_PathValue::FUNCTION: { //const auto& f = this->context.m_crate.get_fcn_by_path(sp, e.m_path); + //TODO(sp, "Function address values"); } break; case ::HIR::ExprNode_PathValue::STATIC: { const auto& v = this->context.m_crate.get_static_by_path(sp, e.m_path); diff --git a/src/hir_typeck/expr.hpp b/src/hir_typeck/expr.hpp index 5fa558a3..a3a5147b 100644 --- a/src/hir_typeck/expr.hpp +++ b/src/hir_typeck/expr.hpp @@ -15,6 +15,7 @@ extern bool monomorphise_pathparams_needed(const ::HIR::PathParams& tpl); extern bool monomorphise_path_needed(const ::HIR::Path& tpl); extern ::HIR::PathParams monomorphise_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer); +extern ::HIR::TraitPath monomorphise_traitpath_with(const Span& sp, const ::HIR::TraitPath& tpl, t_cb_generic callback, bool allow_infer); extern ::HIR::TypeRef monomorphise_type_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true); extern ::HIR::TypeRef monomorphise_type(const Span& sp, const ::HIR::GenericParams& params_def, const ::HIR::PathParams& params, const ::HIR::TypeRef& tpl); @@ -128,14 +129,18 @@ public: /// 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) const; + + typedef ::std::function<bool(const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl; + /// 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::Trait& trait_ptr, - const ::HIR::PathParams& pp, const ::HIR::TypeRef& self_type, - ::std::function<bool(const ::HIR::PathParams&)> callback + const ::HIR::SimplePath& des, + const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp, + const ::HIR::TypeRef& self_type, + t_cb_trait_impl callback ) const; /// Search for a trait implementation in current bounds - bool find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const; + bool find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const; /// Search for a trait implementation in the crate bool find_trait_impls_crate(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const; diff --git a/src/hir_typeck/expr_context.cpp b/src/hir_typeck/expr_context.cpp index eea61da7..4c0ae071 100644 --- a/src/hir_typeck/expr_context.cpp +++ b/src/hir_typeck/expr_context.cpp @@ -641,6 +641,9 @@ const ::HIR::TypeRef& typeck::TypecheckContext::expand_associated_types_to(const TU_IFLET(::HIR::TypeRef::Data, t.m_data, Path, e, if( e.path.m_data.is_Generic() ) return t; + else if( !e.binding.is_Unbound() ) { + return t; + } else { tmp_t = this->expand_associated_types(sp, t.clone()); DEBUG("Expanded " << t << " into " << tmp_t); @@ -661,6 +664,7 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR 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 ) { + DEBUG(l_t1 << " == " << r_t1); return ; } @@ -669,6 +673,7 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR ::HIR::TypeRef right_tmp; const auto& r_t = this->expand_associated_types_to(sp, r_t1, right_tmp); if( l_t == r_t ) { + DEBUG(l_t << " == " << r_t); return ; } @@ -681,14 +686,14 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR else { // Righthand side is infer, alias it to the left // TODO: that `true` should be `false` if the callback isn't unity (for bug checking) - this->set_ivar_to(r_e.index, monomorphise_type_with(sp, left, cb_left, true)); + this->set_ivar_to(r_e.index, this->expand_associated_types(sp, monomorphise_type_with(sp, left, cb_left, true))); } ) else { TU_IFLET(::HIR::TypeRef::Data, l_t.m_data, Infer, l_e, // Lefthand side is infer, alias it to the right // TODO: that `true` should be `false` if the callback isn't unity (for bug checking) - this->set_ivar_to(l_e.index, monomorphise_type_with(sp, right, cb_right, true)); + this->set_ivar_to(l_e.index, this->expand_associated_types(sp, monomorphise_type_with(sp, right, cb_right, true))); ) else { // If generic replacement happened, clear the callback @@ -803,10 +808,16 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR } ), (TraitObject, - if( l_e.m_trait.m_path != r_e.m_trait.m_path ) { + if( l_e.m_trait.m_path.m_path != r_e.m_trait.m_path.m_path ) { ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t); } - equality_typeparams(l_e.m_trait.m_params, r_e.m_trait.m_params); + equality_typeparams(l_e.m_trait.m_path.m_params, r_e.m_trait.m_path.m_params); + for(auto it_l = l_e.m_trait.m_type_bounds.begin(), it_r = r_e.m_trait.m_type_bounds.begin(); it_l != l_e.m_trait.m_type_bounds.end(); it_l++, it_r++ ) { + if( it_l->first != it_r->first ) { + ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - associated bounds differ"); + } + this->apply_equality(sp, it_l->second, cb_left, it_r->second, cb_right, nullptr); + } // TODO: Possibly allow inferrence reducing the set? if( l_e.m_markers.size() != r_e.m_markers.size() ) { ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - trait counts differ"); @@ -886,7 +897,7 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR } // 1. Search for an implementation of the data trait for this type - bool succ = this->find_trait_impls(e.m_trait.m_path, right_inner_res, [&](const auto& args) { + bool succ = this->find_trait_impls(e.m_trait.m_path.m_path, right_inner_res, [&](const auto& args) { if( args.m_types.size() > 0 ) TODO(sp, "Handle unsizing to traits with params"); return true; @@ -902,6 +913,10 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR // return true; // }); } + for(const auto& assoc : e.m_trait.m_type_bounds) + { + TODO(sp, "Check for associated type ("<<assoc.first<<") validity when unsizing to " << left_inner_res << " from " << right_inner_res); + } // Valid unsize, insert unsize operation auto span = node_ptr->span(); @@ -969,7 +984,7 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR // ------------------------------------------------------------------------------------------------------------------- bool typeck::TypecheckContext::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){ + if( this->find_trait_impls_bound(sp, trait.m_path, placeholder(type), [&](const auto& args, const auto& _){ DEBUG("TODO: Check args for " << trait.m_path << args << " against " << trait); return true; }) @@ -1036,7 +1051,7 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, ) // 1. Search generic params - if( find_trait_impls_bound(sp, trait, type, callback) ) + if( find_trait_impls_bound(sp, trait, type, [&callback](const auto& pp, const auto& _) { return callback(pp); }) ) return true; // 2. Search crate-level impls return find_trait_impls_crate(trait, type, callback); @@ -1112,28 +1127,92 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, // 1. Bounds bool rv; + bool assume_opaque = true; rv = this->iterate_bounds([&](const auto& b) { - TU_IFLET(::HIR::GenericBound, b, TypeEquality, be, + 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, + *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, *e2.type, + [&e2,&input,&assume_opaque](const auto& x, const 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({}); + } return input; } + // 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, e3, - TU_IFLET(::HIR::Path::Data, e3.path.m_data, UfcsKnown, pe, + 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.trait.m_path); - const auto& assoc_ty = trait_ptr.m_types.at(pe.item); - DEBUG("TODO: Search bounds " << assoc_ty.m_params.fmt_bounds()); + 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, @@ -1146,13 +1225,13 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, return ty; } }; - // Resolve where Self=pe.type (i.e. for the trait this inner UFCS is on) + // 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.type; + return *pe_inner.type; else { - // TODO: Look in pe.trait.m_params + // TODO: Look in pe_inner.trait.m_params TODO(sp, "Handle type params when expanding associated bound (#" << e.binding << " " << e.name); } ) @@ -1162,12 +1241,30 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, }; for(const auto& bound : assoc_ty.m_params.m_bounds) { - TU_IFLET(::HIR::GenericBound, bound, TypeEquality, be, + 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) ) { + return monomorphise_type_with(sp, it->second, cb_placeholders_trait); + } + else { + return it->second.clone(); + } + } + } + ), + (TypeEquality, // IF: bound's type matches the input, replace with bounded equality // `<Self::IntoIter as Iterator>::Item = Self::Item` if( be.type.compare_with_paceholders(sp, input, cb_placeholders_type ) ) { DEBUG("Match of " << be.type << " with " << input); - DEBUG("- Replace `input` with " << be.other_type << ", Self=" << *pe.type); + DEBUG("- Replace `input` with " << be.other_type << ", Self=" << *pe_inner.type); if( monomorphise_type_needed(be.other_type) ) { return monomorphise_type_with(sp, be.other_type, cb_placeholders_trait); } @@ -1175,6 +1272,7 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, return be.other_type.clone(); } } + ) ) } DEBUG("e2 = " << *e2.type << ", input = " << input); @@ -1315,16 +1413,19 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, // // ------------------------------------------------------------------------------------------------------------------- bool typeck::TypecheckContext::find_named_trait_in_trait(const Span& sp, - const ::HIR::SimplePath& des, const ::HIR::Trait& trait_ptr, - const ::HIR::PathParams& pp, const ::HIR::TypeRef& target_type, - ::std::function<bool(const ::HIR::PathParams&)> callback + const ::HIR::SimplePath& des, + const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp, + const ::HIR::TypeRef& target_type, + t_cb_trait_impl callback ) const { - TRACE_FUNCTION_F(des << pp); - assert( pp.m_types.size() == trait_ptr.m_params.m_types.size() ); + 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_pp = monomorphise_path_params_with(Span(), pt.m_params.clone(), [&](const auto& gt)->const auto& { + 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; @@ -1335,27 +1436,27 @@ bool typeck::TypecheckContext::find_named_trait_in_trait(const Span& sp, 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 ); + + DEBUG(pt << " => " << pt_mono); + if( pt.m_path.m_path == des ) { + callback( pt_mono.m_path.m_params, pt_mono.m_type_bounds ); return true; } } return false; } -bool typeck::TypecheckContext::find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const +bool typeck::TypecheckContext::find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_trait_impl 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) ) { + if( callback(e.trait.m_path.m_params, e.trait.m_type_bounds) ) { return true; } } - if( this->find_named_trait_in_trait(sp, trait, *e.trait.m_trait_ptr, e.trait.m_path.m_params, type, callback) ) { + if( this->find_named_trait_in_trait(sp, trait, *e.trait.m_trait_ptr, e.trait.m_path.m_path, e.trait.m_path.m_params, type, callback) ) { return true; } ) @@ -1390,8 +1491,8 @@ bool typeck::TypecheckContext::trait_contains_method(const Span& sp, const ::HIR // 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); - if( trait_contains_method(sp, st, st_ptr, name, out_path) ) { + auto& st_ptr = this->m_crate.get_trait_by_path(sp, st.m_path.m_path); + if( trait_contains_method(sp, st.m_path, st_ptr, name, out_path) ) { out_path.m_params = monomorphise_path_params_with(sp, mv$(out_path.m_params), [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); assert(ge.binding < 256); @@ -1616,6 +1717,9 @@ void typeck::TypecheckContext::set_ivar_to(unsigned int slot, ::HIR::TypeRef typ root_ivar.alias = l_e.index; root_ivar.type.reset(); ) + else if( *root_ivar.type == type ) { + return ; + } else { // Otherwise, store left in right's slot DEBUG("Set IVar " << slot << " = " << type); diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 2a5b5561..0fd1a8d7 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -900,6 +900,12 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type) } assert( ufcs.nodes.size() == 1); ) + + TU_IFLET(::AST::PathBinding, e.path.binding(), Trait, be, + auto ty = ::TypeRef( type.span(), {}, ::make_vec1(mv$(e.path)) ); + type = mv$(ty); + return ; + ) ), (TraitObject, //context.push_lifetimes( e.hrls ); |