From 3663599d6d0748c3d79ac91dcc89982faaa820ed Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Sep 2015 13:40:54 +0800 Subject: Do two passes of resolve to handle UFCS resolve problems --- src/ast/ast.cpp | 1 + src/convert/resolve.cpp | 218 +++++++++++++++++++++++++----------------------- src/include/span.hpp | 4 +- src/types.cpp | 2 +- 4 files changed, 117 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 2fe36225..aa8a17e0 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -295,6 +295,7 @@ bool Crate::check_impls_wildcard(const Path& trait, const TypeRef& type) const for( auto implptr : m_impl_index ) { Impl& impl = *implptr; + DEBUG("- " << impl.def()); ::std::vector out_params; if( impl.def().matches(out_params, AST::Path(), type) ) { diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 38808831..ca5d8e4e 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -20,7 +20,6 @@ class CPathResolver: AST::Module* m_module; AST::Path m_module_path; - struct LocalItem { enum Type { @@ -76,6 +75,8 @@ class CPathResolver: friend class CResolvePaths_NodeVisitor; public: + bool m_second_pass = false; + CPathResolver(const AST::Crate& crate); void handle_params(AST::TypeParams& params) override; @@ -600,8 +601,10 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode if( tp != false /*nullptr*/ || path[0].name() == "Self" ) { if(path.size() > 1) { + auto ty = TypeRef(TypeRef::TagArg(), path[0].name()); + ty.set_span( path.span() ); // Repalce with UFCS - auto newpath = AST::Path(AST::Path::TagUfcs(), TypeRef(TypeRef::TagArg(), path[0].name()), TypeRef()); + auto newpath = AST::Path(AST::Path::TagUfcs(), ty, TypeRef()); newpath.add_tailing(path); path = mv$(newpath); handle_path_ufcs(path, mode); @@ -672,127 +675,127 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod // TODO: Disabled, as it requires having all traits (semi) path resolved, so that trait resolution works cleanly if( info.trait->is_wildcard() ) { - #if 0 - const ::std::string& item_name = info.nodes[0].name(); - DEBUG("Searching for matching trait for '"< params; - if( info.type->is_type_param() && info.type->type_param() == "Self" ) - { - DEBUG("Checking Self trait and sub-traits"); - // TODO: What is "Self" here? May want to use `GenericBound`s to replace Self with the actual type when possible. - // In which case, Self will refer to "implementor of this trait". - // - Look up applicable traits for this type, using bounds (basically same as next) - assert( !m_self_type.empty() ); - assert( m_self_type.back().is_Trait() ); - AST::Path p = m_self_type.back().as_Trait().path; - handle_path(p, MODE_TYPE); - AST::Trait& t = *const_cast(m_self_type.back().as_Trait().trait); + if( this->m_second_pass ) { + const ::std::string& item_name = info.nodes[0].name(); + DEBUG("Searching for matching trait for '"<find_trait_item(p, t, item_name, is_method, found_trait_path) ) { - if( is_method ) { - if( info.nodes.size() != 1 ) - ERROR(path.span(), E0000, "CPathResolver::handle_path_ufcs - Sub-nodes to method"); + // 1. Inherent + //AST::Impl* impl_ptr; + ::std::vector params; + if( info.type->is_type_param() && info.type->type_param() == "Self" ) + { + DEBUG("Checking Self trait and sub-traits"); + // TODO: What is "Self" here? May want to use `GenericBound`s to replace Self with the actual type when possible. + // In which case, Self will refer to "implementor of this trait". + // - Look up applicable traits for this type, using bounds (basically same as next) + assert( !m_self_type.empty() ); + assert( m_self_type.back().is_Trait() ); + AST::Path p = m_self_type.back().as_Trait().path; + handle_path(p, MODE_TYPE); + AST::Trait& t = *const_cast(m_self_type.back().as_Trait().trait); + + bool is_method; + AST::Path found_trait_path; + if( this->find_trait_item(p, t, item_name, is_method, found_trait_path) ) { + if( is_method ) { + if( info.nodes.size() != 1 ) + ERROR(path.span(), E0000, "CPathResolver::handle_path_ufcs - Sub-nodes to method"); + } + else { + if( info.nodes.size() != 1 ) + throw ParseError::Todo("CPathResolver::handle_path_ufcs - Sub nodes on associated type"); + } + *info.trait = TypeRef( mv$(found_trait_path) ); } else { - if( info.nodes.size() != 1 ) - throw ParseError::Todo("CPathResolver::handle_path_ufcs - Sub nodes on associated type"); + ERROR(path.span(), E0000, "Cannot find item '" << item_name << "' on Self"); } - *info.trait = TypeRef( mv$(found_trait_path) ); } - else { - ERROR(path.span(), E0000, "Cannot find item '" << item_name << "' on Self"); - } - } - else if( info.type->is_type_param() ) - { - DEBUG("Checking applicable generic bounds"); - const auto& tp = *info.type->type_params_ptr(); - assert(&tp != nullptr); - bool success = false; - - // Enumerate bounds - for( const auto& bound : tp.bounds() ) + else if( info.type->is_type_param() ) { - DEBUG("bound = " << bound); - TU_MATCH_DEF(AST::GenericBound, (bound), (ent), - (), - (IsTrait, - if( ent.type == *info.type ) { - auto& t = *const_cast(ent.trait.binding().as_Trait().trait_); - DEBUG("Type match, t.params() = " << t.params()); - bool is_method; - AST::Path found_trait_path; - DEBUG("find_trait_item(" << ent.trait << /*", t=" << t <<*/ ", item_name = " << item_name); - if( this->find_trait_item(ent.trait, t, item_name, is_method, found_trait_path) ) - { - if( is_method ) { - if( info.nodes.size() != 1 ) - throw ParseError::Generic("CPathResolver::handle_path_ufcs - Sub-nodes to method"); - } - else { - if( info.nodes.size() != 1 ) - throw ParseError::Todo("CPathResolver::handle_path_ufcs - Sub nodes on associated type"); + DEBUG("Checking applicable generic bounds"); + const auto& tp = *info.type->type_params_ptr(); + assert(&tp != nullptr); + bool success = false; + + // Enumerate bounds + for( const auto& bound : tp.bounds() ) + { + DEBUG("bound = " << bound); + TU_MATCH_DEF(AST::GenericBound, (bound), (ent), + (), + (IsTrait, + if( ent.type == *info.type ) { + auto& t = *const_cast(ent.trait.binding().as_Trait().trait_); + DEBUG("Type match, t.params() = " << t.params()); + bool is_method; + AST::Path found_trait_path; + DEBUG("find_trait_item(" << ent.trait << /*", t=" << t <<*/ ", item_name = " << item_name); + if( this->find_trait_item(ent.trait, t, item_name, is_method, found_trait_path) ) + { + if( is_method ) { + if( info.nodes.size() != 1 ) + throw ParseError::Generic("CPathResolver::handle_path_ufcs - Sub-nodes to method"); + } + else { + if( info.nodes.size() != 1 ) + throw ParseError::Todo("CPathResolver::handle_path_ufcs - Sub nodes on associated type"); + } + *info.trait = TypeRef( mv$(found_trait_path) ); + success = true; + break ; } - *info.trait = TypeRef( mv$(found_trait_path) ); - success = true; - break ; } - } - else { - DEBUG("Type mismatch " << ent.type << " != " << *info.type); - } + else { + DEBUG("Type mismatch " << ent.type << " != " << *info.type); + } + ) ) - ) - } - - if( !success ) - throw ParseError::Todo( FMT("CPathResolver::handle_path_ufcs - UFCS, find trait for generic matching '" << item_name << "'") ); - // - re-handle, to ensure that the bound is resolved - handle_type(*info.trait); - } - else - { - DEBUG("(maybe) known type"); - // Iterate all inherent impls - for( auto impl : m_crate.find_inherent_impls(*info.type) ) { - IF_OPTION_SOME(item, impl.find_named_item(item_name), { - DEBUG("Found matching inherent impl"); - *info.trait = TypeRef(TypeRef::TagInvalid()); - //path.set_binding(item); - path.resolve(m_crate); - return ; - }) + } + + if( !success ) + throw ParseError::Todo( FMT("CPathResolver::handle_path_ufcs - UFCS, find trait for generic matching '" << item_name << "'") ); + // - re-handle, to ensure that the bound is resolved + handle_type(*info.trait); } - // Iterate all traits in scope, and find one that is implemented for this type - // - TODO: Iterate traits to find match for - for( const auto& trait_ref : this->inscope_traits() ) + else { - const auto& trait_p = trait_ref.first; - const auto& trait = trait_ref.second; - bool is_fcn; - if( trait.has_named_item(item_name, is_fcn) ) { - IF_OPTION_SOME(impl, m_crate.find_impl( trait_p, *info.type ), { - *info.trait = TypeRef( trait_p ); - //auto item = impl.find_named_item(item_name).unwrap(); + DEBUG("(maybe) known type"); + // Iterate all inherent impls + for( auto impl : m_crate.find_inherent_impls(*info.type) ) { + IF_OPTION_SOME(item, impl.find_named_item(item_name), { + DEBUG("Found matching inherent impl"); + *info.trait = TypeRef(TypeRef::TagInvalid()); //path.set_binding(item); path.resolve(m_crate); return ; }) } - } + // Iterate all traits in scope, and find one that is implemented for this type + // - TODO: Iterate traits to find match for + for( const auto& trait_ref : this->inscope_traits() ) + { + const auto& trait_p = trait_ref.first; + const auto& trait = trait_ref.second; + bool is_fcn; + if( trait.has_named_item(item_name, is_fcn) ) { + IF_OPTION_SOME(impl, m_crate.find_impl( trait_p, *info.type ), { + *info.trait = TypeRef( trait_p ); + //auto item = impl.find_named_item(item_name).unwrap(); + //path.set_binding(item); + path.resolve(m_crate); + return ; + }) + } + } - throw ParseError::Todo("CPathResolver::handle_path_ufcs - UFCS, find trait"); + throw ParseError::Todo("CPathResolver::handle_path_ufcs - UFCS, find trait"); + } + + path.resolve(m_crate); } - - path.resolve(m_crate); - #endif } else { // 3. Call resolve to attempt binding @@ -1210,4 +1213,9 @@ void ResolvePaths(AST::Crate& crate) DEBUG(" ---"); pr.handle_module(AST::Path("", {}), crate.root_module()); DEBUG(" <<<"); + + pr.m_second_pass = true; + DEBUG(" ---"); + pr.handle_module(AST::Path("", {}), crate.root_module()); + DEBUG(" <<<"); } diff --git a/src/include/span.hpp b/src/include/span.hpp index 452f37ba..3df70b72 100644 --- a/src/include/span.hpp +++ b/src/include/span.hpp @@ -41,9 +41,9 @@ struct Span end_ofs(end_ofs) {} Span(): - filename(""), + filename("")/*, start_line(0), start_ofs(0), - end_line(0), end_ofs(0) + end_line(0), end_ofs(0) // */ {} void bug(::std::function msg) const; diff --git a/src/types.cpp b/src/types.cpp index ee6588a5..d25d3332 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -576,7 +576,7 @@ Ordering TypeRef::ord(const TypeRef& x) const DEBUG(*this << " == " << x); if( ent.params ) DEBUG("- (L) " << *ent.params); if( x_ent.params ) DEBUG("- (R) " << *x_ent.params); - throw ::std::runtime_error("BUGCHECK - Can't compare mismatched generic types"); + BUG(m_span, "Can't compare mismatched generic types"); } else { } -- cgit v1.2.3