From 68607811e4e8d6feba95f55c3e49da9923fc35fd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 31 Aug 2015 14:06:26 +0800 Subject: Convert path bindings to TAGGED_UNION, improve resolve logic (leading to error) --- src/convert/resolve.cpp | 182 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 139 insertions(+), 43 deletions(-) (limited to 'src/convert/resolve.cpp') diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 901a3acb..821d4810 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -89,9 +89,11 @@ public: ::rust::option lookup_local(LocalItem::Type type, const ::std::string& name) const; - bool find_local_item(AST::Path& path, bool allow_variables); - bool find_mod_item(AST::Path& path); - bool find_super_mod_item(AST::Path& path); + bool find_local_item(AST::Path& path, const ::std::string& name, bool allow_variables); + //bool find_local_item(AST::Path& path, bool allow_variables); + bool find_mod_item(AST::Path& path, const ::std::string& name); + bool find_self_mod_item(AST::Path& path, const ::std::string& name); + bool find_super_mod_item(AST::Path& path, const ::std::string& name); bool find_type_param(const ::std::string& name); // TODO: Handle a block and obtain the local module (if any) @@ -319,11 +321,11 @@ void CPathResolver::end_scope() // > Search local use definitions (function-level) // - TODO: Local use statements (scoped) // > Search module-level definitions -bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, const AST::Path& mod_path, AST::Path& path) +bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, const AST::Path& mod_path, AST::Path& path, const ::std::string& name, bool is_leaf) { TRACE_FUNCTION_F("mod_path="< Variable: (wait, how is this known already?) // - 'self' case AST::Path::Class::Local: - //if( - // 1. Check for local items - // 2. Type parameters (ONLY when in expression mode) - // 3. Module items - //throw ::std::runtime_error("TODO: Local in CPathResolver::handle_path_int"); + if( !path.binding().is_Unbound() ) + { + DEBUG("- Path " << path << " already bound"); + } + else + { + const auto& info = path.m_class.as_Local(); + // 1. Check for local items + if( this->find_local_item(path, info.name, (mode == CASTIterator::MODE_EXPR)) ) { + path.resolve(m_crate); + break ; + } + else { + // No match, fall through + } + // 2. Type parameters (ONLY when in type mode) + if( mode == CASTIterator::MODE_TYPE ) { + throw ::std::runtime_error("TODO: Local in CPathResolver::handle_path_int type param"); + } + // 3. Module items + if( this->find_mod_item(path, info.name) ) { + path.resolve(m_crate); + break; + } + else { + } + + DEBUG("no matches found for path = " << path); + if( mode != MODE_BIND ) + throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed (Local)"); + return ; + } break; case AST::Path::Class::Relative: @@ -472,8 +504,8 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode // > Return values: name or path { bool allow_variables = (mode == CASTIterator::MODE_EXPR && path.is_trivial()); - if( this->find_local_item(path, allow_variables) ) { - //path.resolve(m_crate); + if( this->find_local_item(path, path[0].name(), allow_variables) ) { + path.resolve(m_crate); break ; } else { @@ -495,13 +527,14 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode auto newpath = AST::Path(AST::Path::TagUfcs(), TypeRef(TypeRef::TagArg(), path[0].name()), TypeRef()); newpath.add_tailing(path); path = mv$(newpath); + handle_path_ufcs(path, mode); } else { // Mark as local - // - TODO: Also need to annotate // - TODO: Not being trivial is an error, not a bug assert( path.is_trivial() ); path = AST::Path(AST::Path::TagLocal(), path[0].name()); + // - TODO: Need to bind this to the source parameter block } break; } @@ -509,7 +542,8 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode // 3. current module { - if( this->find_mod_item(path) ) { + if( this->find_mod_item(path, path[0].name()) ) { + path.resolve(m_crate); break; } else { @@ -524,7 +558,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode // Module relative case AST::Path::Class::Self:{ - if( this->find_mod_item(path) ) { + if( this->find_self_mod_item(path, path[0].name()) ) { break; } else { @@ -535,7 +569,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode break; } // Parent module relative case AST::Path::Class::Super:{ - if( this->find_super_mod_item(path) ) { + if( this->find_super_mod_item(path, path[0].name()) ) { break; } else { @@ -547,25 +581,76 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode } // TODO: Are there any reasons not to be bound at this point? - //assert( path.binding().is_bound() ); + //assert( !path.binding().is_Unbound() ); } void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mode) { + assert(path.m_class.is_UFCS()); auto& info = path.m_class.as_UFCS(); + TRACE_FUNCTION_F("info={< " << *info.type << " as " << *info.trait << ">::" << info.nodes << "}"); + const ::std::string& item_name = info.nodes[0].name(); // 1. Handle sub-types handle_type(*info.type); handle_type(*info.trait); // 2. Handle wildcard traits (locate in inherent impl, or from an in-scope trait) if( info.trait->is_wildcard() ) { - DEBUG("Searching for impls when trait is _"); + DEBUG("Searching for impls when trait is _ (trait = " << *info.trait << ")"); // Search applicable type parameters for known implementations // 1. Inherent AST::Impl* impl_ptr; ::std::vector params; - if( m_crate.find_impl(AST::Path(), *info.type, &impl_ptr, ¶ms) ) + if( info.type->is_type_param() && info.type->type_param() == "Self" ) + { + throw ParseError::Todo("CPathResolver::handle_path_ufcs - Handle '::...'"); + } + 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() ) + { + DEBUG("bound = " << bound); + if( bound.is_trait() && bound.test() == *info.type ) + { + const auto& t = *bound.bound().binding().as_Trait().trait_; + { + const auto& fcns = t.functions(); + auto it = ::std::find_if( fcns.begin(), fcns.end(), [&](const AST::Item& a) { return a.name == item_name; } ); + if( it != fcns.end() ) { + // Found it. + if( info.nodes.size() != 1 ) + throw ParseError::Generic("CPathResolver::handle_path_ufcs - Multiple arguments"); + *info.trait = bound.bound(); + success = true; + break; + } + } + { + const auto& types = t.types(); + auto it = ::std::find_if( types.begin(), types.end(), [&](const AST::Item& a) { return a.name == item_name; } ); + if( it != types.end() ) { + // Found it. + *info.trait = bound.bound(); + success = true; + break; + } + } + } + } + + if( !success ) + throw ParseError::Todo("CPathResolver::handle_path_ufcs - UFCS, find trait for generic"); + // - re-handle, to ensure that the bound is resolved + handle_type(*info.trait); + } + else if( m_crate.find_impl(AST::Path(), *info.type, &impl_ptr, ¶ms) ) { DEBUG("Found matching inherent impl"); // - Mark as being from the inherent, and move along @@ -573,16 +658,18 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod *info.trait = TypeRef(TypeRef::TagInvalid()); } else - { - // Iterate all traits in scope, and find one that is impled for this type - throw ParseError::Todo("CPathResolver::handle_path - UFCS, find trait"); + { + // Iterate all traits in scope, and find one that is implemented for this type + // - TODO: Iterate traits to find match for + throw ParseError::Todo("CPathResolver::handle_path_ufcs - UFCS, find trait"); } } // 3. Call resolve to attempt binding path.resolve(m_crate); } -bool CPathResolver::find_local_item(AST::Path& path, bool allow_variables) { +bool CPathResolver::find_local_item(AST::Path& path, const ::std::string& name, bool allow_variables) +{ TRACE_FUNCTION_F("path="<name() == "" ) + throw ParseError::Todo("Handle anon modules when resoling unqualified relative paths"); + } while( mod->name() == "" ); + return false; +} +bool CPathResolver::find_self_mod_item(AST::Path& path, const ::std::string& name) { if( m_module->name() == "" ) throw ParseError::Todo("Correct handling of 'self' in anon modules"); - return lookup_path_in_module(m_crate, *m_module, m_module_path, path); + return lookup_path_in_module(m_crate, *m_module, m_module_path, path, name, path.size()==1); } -bool CPathResolver::find_super_mod_item(AST::Path& path) { +bool CPathResolver::find_super_mod_item(AST::Path& path, const ::std::string& name) { if( m_module->name() == "" ) throw ParseError::Todo("Correct handling of 'super' in anon modules"); @@ -628,7 +726,7 @@ bool CPathResolver::find_super_mod_item(AST::Path& path) { // 2. Resolve that path super_path.resolve(m_crate); // 3. Call lookup_path_in_module - return lookup_path_in_module(m_crate, super_path.binding().bound_module(), super_path, path); + return lookup_path_in_module(m_crate, *super_path.binding().as_Module().module_, super_path, path, name, path.size()==1); } bool CPathResolver::find_type_param(const ::std::string& name) { for( auto it = m_locals.end(); it -- != m_locals.begin(); ) @@ -810,24 +908,22 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod // If wildcard, make sure it's sane if( imp.name == "" ) { - switch(imp.data.binding().type()) - { - case AST::PathBinding::UNBOUND: - throw ParseError::BugCheck("path unbound after calling .resolve()"); - case AST::PathBinding::MODULE: - break; - case AST::PathBinding::ENUM: - break; - - default: + TU_MATCH_DEF(AST::PathBinding, (imp.data.binding()), (info), + ( throw ParseError::Generic("Wildcard imports are only allowed on modules and enums"); - } + ), + (Unbound, + throw ParseError::BugCheck("path unbound after calling .resolve()"); + ), + (Module, (void)0;), + (Enum, (void)0;) + ) } } for( auto& new_imp : new_imports ) { - if( not new_imp.binding().is_bound() ) { + if( new_imp.binding().is_Unbound() ) { new_imp.resolve(crate, false); } mod.add_alias(false, new_imp, new_imp[new_imp.size()-1].name()); -- cgit v1.2.3