From 01ec57f596f89d4b52b378975f941e2ed8d2e563 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 3 Nov 2015 12:01:01 +1100 Subject: Move path binding logic into Resolve path to simplify --- src/ast/ast.cpp | 4 +- src/ast/ast.hpp | 45 ++--- src/ast/path.cpp | 370 +---------------------------------------- src/ast/path.hpp | 22 ++- src/convert/resolve.cpp | 385 +++++++++++++++++++++++++++++++++++++------ src/include/tagged_union.hpp | 2 +- 6 files changed, 379 insertions(+), 449 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index aa8a17e0..10a7d68a 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -715,7 +715,7 @@ Module::ItemRef Module::find_item(const ::std::string& needle, bool allow_leaves // not yet bound, so run resolution (recursion) DEBUG("Recursively resolving pub wildcard use " << imp.data); //imp.data.resolve(root_crate); - throw ParseError::Todo("Path::resolve() wildcard re-export call resolve"); + throw ParseError::Todo("AST::Module::find_item() - Wildcard `use` not bound, call resolve here?"); } TU_MATCH_DEF(AST::PathBinding, (binding), (info), @@ -730,7 +730,7 @@ Module::ItemRef Module::find_item(const ::std::string& needle, bool allow_leaves // - If it's a module, recurse (Module, auto rv = info.module_->find_item(needle); - if( rv.type() != Module::ItemRef::ITEM_none ) { + if( rv.tag() != Module::ItemRef::None ) { // Don't return RV, return the import (so caller can rewrite path if need be) return ItemRef(imp); //return rv; diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 94b217d1..f4f2b474 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -724,36 +724,37 @@ public: public: enum Type { - ITEM_none, - ITEM_Module, - ITEM_Crate, - ITEM_TypeAlias, - ITEM_Function, - ITEM_Trait, - ITEM_Struct, - ITEM_Enum, - ITEM_Static, - ITEM_Use, + None, + Module, + Crate, + TypeAlias, + Function, + Trait, + Struct, + Enum, + Static, + Use, }; private: Type m_type; const void* m_ref; public: - ItemRef(): m_type(ITEM_none) {} + ItemRef(): m_type(None) {} - Type type() { return m_type; } + Type tag() const { return m_type; } + const Type& as_None() const { return m_type; } // HACK: Returns &Type in place of &void #define _(ty,ident) \ - ItemRef(const ty& ref): m_type(ITEM_##ident), m_ref(&ref) {} \ - const ty& unwrap_##ident() { assert(m_type == ITEM_##ident); m_type = ITEM_none; return *(const ty*)m_ref; } - _(Module, Module) + ItemRef(const ty& ref): m_type(ident), m_ref(&ref) {} \ + const ty& as_##ident() const { assert(m_type == ident); return *(const ty*)m_ref; } + _(AST::Module, Module) _(::std::string, Crate) - _(TypeAlias, TypeAlias) - _(Function, Function) - _(Trait, Trait) - _(Struct, Struct) - _(Enum, Enum) - _(Static, Static) - _(Item, Use) + _(AST::TypeAlias, TypeAlias) + _(AST::Function, Function) + _(AST::Trait, Trait) + _(AST::Struct, Struct) + _(AST::Enum, Enum) + _(AST::Static, Static) + _(AST::Item, Use) #undef _ }; ItemRef find_item(const ::std::string& needle, bool allow_leaves = true, bool ignore_private_wildcard = true) const; diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 8fe42527..8668c386 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -136,367 +136,7 @@ AST::Path::Path(const Path& x): DEBUG("clone, x = " << x << ", this = " << *this ); } -/// Resolve a path into a canonical form, and bind it to the target value -void Path::resolve(const Crate& root_crate, bool expect_params) -{ - TRACE_FUNCTION_F("*this = "<< *this); - if( m_binding.is_Unbound() ) - { - if( m_class.is_Absolute() ) { - resolve_absolute(root_crate, expect_params); - } - else if(m_class.is_UFCS()) { - resolve_ufcs(root_crate, expect_params); - } - else - throw ParseError::BugCheck("Calling Path::resolve on non-absolute path"); - } -} -void Path::resolve_absolute(const Crate& root_crate, bool expect_params) -{ - auto& nodes = m_class.as_Absolute().nodes; - DEBUG("m_crate = '" << m_crate << "'"); - - unsigned int slice_from = 0; // Used when rewriting the path to be relative to its crate root - - ::std::vector mod_stack; - const Module* mod = &root_crate.get_root_module(m_crate); - for(unsigned int i = 0; i < nodes.size(); i ++ ) - { - mod_stack.push_back(mod); - const bool is_last = (i+1 == nodes.size()); - const bool is_sec_last = (i+2 == nodes.size()); - const PathNode& node = nodes[i]; - DEBUG("[" << i << "/"<anon_mods().at(index); - continue ; - } - - auto item = mod->find_item(node.name(), is_last); // Only allow leaf nodes (functions and statics) if this is the last node - switch( item.type() ) - { - // Not found - case AST::Module::ItemRef::ITEM_none: - // If parent node is anon, backtrack and try again - // TODO: I feel like this shouldn't be done here, instead perform this when absolutising (now that find_item is reusable) - if( i > 0 && nodes[i-1].name()[0] == '#' && nodes[i-1].name().size() > 1 ) - { - i --; - mod_stack.pop_back(); - mod = mod_stack.back(); - mod_stack.pop_back(); - nodes.erase(nodes.begin()+i); - i --; - DEBUG("Failed to locate item in nested, look upwards - " << *this); - - continue ; - } - throw ParseError::Generic("Unable to find component '" + node.name() + "'"); - - // Sub-module - case AST::Module::ItemRef::ITEM_Module: - DEBUG("Sub-module : " << node.name()); - if( node.args().size() ) - throw ParseError::Generic("Generic params applied to module"); - mod = &item.unwrap_Module(); - break; - - // Crate - case AST::Module::ItemRef::ITEM_Crate: { - const ::std::string& crate_name = item.unwrap_Crate(); - DEBUG("Extern crate '" << node.name() << "' = '" << crate_name << "'"); - if( node.args().size() ) - throw ParseError::Generic("Generic params applied to extern crate"); - m_crate = crate_name; - slice_from = i+1; - mod = &root_crate.get_root_module(crate_name); - break; } - - // Type Alias - case AST::Module::ItemRef::ITEM_TypeAlias: { - const auto& ta = item.unwrap_TypeAlias(); - DEBUG("Type alias <"< " << ta.type()); - //if( node.args().size() != ta.params().size() ) - // throw ParseError::Generic("Param count mismatch when referencing type alias"); - // Make a copy of the path, replace params with it, then replace *this? - // - Maybe leave that up to other code? - if( is_last ) { - check_param_counts(ta.params(), expect_params, nodes[i]); - m_binding = PathBinding::make_TypeAlias( {&ta} ); - goto ret; - } - else { - throw ParseError::Todo("Path::resolve() type method"); - } - break; } - - // Function - case AST::Module::ItemRef::ITEM_Function: { - const auto& fn = item.unwrap_Function(); - DEBUG("Found function"); - if( is_last ) { - check_param_counts(fn.params(), expect_params, nodes[i]); - m_binding = PathBinding::make_Function({&fn}); - goto ret; - } - else { - throw ParseError::Generic("Import of function, too many extra nodes"); - } - break; } - - // Trait - case AST::Module::ItemRef::ITEM_Trait: { - const auto& t = item.unwrap_Trait(); - DEBUG("Found trait"); - if( is_last ) { - check_param_counts(t.params(), expect_params, nodes[i]); - m_binding = PathBinding::make_Trait({&t}); - goto ret; - } - else if( is_sec_last ) { - check_param_counts(t.params(), expect_params, nodes[i]); - // TODO: Also check params on item - m_binding = PathBinding::make_TraitMethod( {&t, nodes[i+1].name()} ); - goto ret; - } - else { - throw ParseError::Generic("Import of trait, too many extra nodes"); - } - break; } - - // Struct - case AST::Module::ItemRef::ITEM_Struct: { - const auto& str = item.unwrap_Struct(); - DEBUG("Found struct"); - if( is_last ) { - check_param_counts(str.params(), expect_params, nodes[i]); - bind_struct(str, node.args()); - goto ret; - } - else if( is_sec_last ) { - check_param_counts(str.params(), expect_params, nodes[i]); - bind_struct_member(str, node.args(), nodes[i+1]); - goto ret; - } - else { - throw ParseError::Generic("Import of struct, too many extra nodes"); - } - break; } - - // Enum / enum variant - case AST::Module::ItemRef::ITEM_Enum: { - const auto& enm = item.unwrap_Enum(); - DEBUG("Found enum"); - if( is_last ) { - check_param_counts(enm.params(), expect_params, nodes[i]); - bind_enum(enm, node.args()); - goto ret; - } - else if( is_sec_last ) { - check_param_counts(enm.params(), expect_params, nodes[i]); - bind_enum_var(enm, nodes[i+1].name(), node.args()); - goto ret; - } - else { - throw ParseError::Generic("Binding path to enum, too many extra nodes"); - } - break; } - - case AST::Module::ItemRef::ITEM_Static: { - const auto& st = item.unwrap_Static(); - DEBUG("Found static/const"); - if( is_last ) { - if( node.args().size() ) - throw ParseError::Generic("Unexpected generic params on static/const"); - bind_static(st); - goto ret; - } - else { - throw ParseError::Generic("Binding path to static, trailing nodes"); - } - break; } - - // Re-export - case AST::Module::ItemRef::ITEM_Use: { - const auto& imp = item.unwrap_Use(); - AST::Path newpath = imp.data; - auto& newnodes = newpath.m_class.as_Absolute().nodes; - DEBUG("Re-exported path " << imp.data); - if( imp.name == "" ) - { - // Replace nodes 0:i-1 with source path, then recurse - for( unsigned int j = i; j < nodes.size(); j ++ ) - { - newnodes.push_back( nodes[j] ); - } - } - else - { - // replace nodes 0:i with the source path - for( unsigned int j = i+1; j < nodes.size(); j ++ ) - { - newnodes.push_back( nodes[j] ); - } - } - - DEBUG("- newpath = " << newpath); - // TODO: This should check for recursion somehow - newpath.resolve(root_crate, expect_params); - - *this = mv$(newpath); - DEBUG("Alias resolved, *this = " << *this); - return; } - } - - } - - // We only reach here if the path points to a module - m_binding = PathBinding::make_Module({mod}); -ret: - if( slice_from > 0 ) - { - DEBUG("Removing " << slice_from << " nodes to rebase path to crate root"); - nodes.erase(nodes.begin(), nodes.begin()+slice_from); - } - return ; -} - -void Path::resolve_ufcs(const Crate& root_crate, bool expect_params) -{ - auto& data = m_class.as_UFCS(); - auto& type = *data.type; - auto& trait = *data.trait; - - // TODO: I can forsee ::Assoc::Item desugaring into < ::Assoc >::Item, but that will be messy to code - assert(data.nodes.size()); - if(data.nodes.size() != 1) throw ParseError::Todo("Path::resolve_ufcs - Are multi-node UFCS paths valid?"); - auto& node = data.nodes.at(0); - - // If the type is unknown (at this time) - if( type.is_wildcard() || type.is_type_param() ) - { - // - _ as _ = BUG - if( !trait.is_path() ) - { - // Wait, what about , is that valid? - throw CompileError::BugCheck( FMT("Path::resolve_ufcs - Path invalid : " << *this) ); - } - // - /*arg*/T as Trait = Type parameter - else if( type.is_type_param() ) - { - // Check that the param is bound on that trait? - //if( !type.type_params_ptr() ) - // throw CompileError::BugCheck( FMT("Path::resolve_ufcs - No bound params on arg") ); - - //const auto& tps = *type.type_params_ptr(); - //for( const auto& bound : tps.bounds() ) - //{ - // // TODO: Check if this type impls the trait - // // - Not needed to do the bind, so ignore for now - //} - - // Search trait for an impl - //throw ParseError::Todo("Path::resolve_ufcs - Arg"); - resolve_ufcs_trait(trait.path(), node); - //throw ParseError::Todo("Path::resolve_ufcs - Arg2"); - } - // - _ as Trait = Inferred type (unknown at the moment) - else - { - throw ParseError::Todo("Path::resolve_ufcs - Handle binding when type is unknown"); - } - } - else - { - // - Type as _ = ? Infer the trait from any matching impls - if( trait.is_wildcard() ) - { - // Search inherent impl first, then (somehow) search in-scope traits - // - TODO: Shouldn't this be the job of CPathResolver? - throw ParseError::Todo("Path::resolve_ufcs - Unknown trait (resolve)"); - } - // - Type as Trait = Obtain from relevant impl - else if( trait.is_path() ) - { - // Locate in the trait, but store Self type somehow? - trait.path().resolve(root_crate, true); - resolve_ufcs_trait(trait.path(), node); - } - // - Type as ! = Item from the inherent impl (similar to above) - else if( trait == TypeRef(TypeRef::TagInvalid()) ) - { - // TODO: Handle case where 'type' is a trait object - // 1. Obtain the impl - AST::Impl* impl_ptr; - if( ! root_crate.find_impl(AST::Path(), type, &impl_ptr) ) - throw ParseError::Generic("Path::resolve_ufcs - No impl block for type"); - assert( impl_ptr ); - - for( const auto& it : impl_ptr->functions() ) - { - if( it.name == node.name() ) { - check_param_counts(it.data.params(), expect_params, node); - m_binding = PathBinding::make_Function( {&it.data} ); - goto _impl_item_bound; - } - } - throw ParseError::Generic( FMT("Path::resolve_ufcs - No item named '"<& args) { DEBUG("Bound to enum"); @@ -585,6 +229,10 @@ void Path::bind_static(const Static& ent) { m_binding = PathBinding::make_Static({&ent}); } +void Path::bind_trait(const Trait& ent, const ::std::vector& args) +{ + m_binding = PathBinding::make_Trait({&ent}); +} void Path::resolve_args(::std::function fcn) { diff --git a/src/ast/path.hpp b/src/ast/path.hpp index d0cc5648..fd1cf5dc 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -250,15 +250,7 @@ public: nodes().push_back(node); m_binding = PathBinding(); } - - /// Resolve the path, and set up binding - /// - /// expect_params enables checking of param counts (clear for handling 'use') - void resolve(const Crate& crate, bool expect_params=true); - void resolve_absolute(const Crate& root_crate, bool expect_params); - void resolve_ufcs(const Crate& root_crate, bool expect_params); - void resolve_ufcs_trait(const AST::Path& trait_path, AST::PathNode& node); - + /// Resolve generic arguments within the path void resolve_args(::std::function fcn); @@ -281,6 +273,7 @@ public: bool is_absolute() const { return m_class.is_Absolute(); } bool is_relative() const { return m_class.is_Relative() || m_class.is_Super() || m_class.is_Self(); } size_t size() const { return nodes().size(); } + const ::std::string& crate() const { return m_crate; } bool is_concrete() const; @@ -326,12 +319,17 @@ private: static int node_lists_equal_no_generic(const ::std::vector& nodes_a, const ::std::vector& nodes_b); void check_param_counts(const TypeParams& params, bool expect_params, PathNode& node); +public: void bind_module(const Module& mod); - void bind_enum(const Enum& ent, const ::std::vector& args); - void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector& args); - void bind_struct(const Struct& ent, const ::std::vector& args); + void bind_enum(const Enum& ent, const ::std::vector& args={}); + void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector& args={}); + void bind_struct(const Struct& ent, const ::std::vector& args={}); void bind_struct_member(const Struct& ent, const ::std::vector& args, const PathNode& member_node); void bind_static(const Static& ent); + void bind_trait(const Trait& ent, const ::std::vector& args={}); + void bind_function(const Function& ent, const ::std::vector& args={}) { + m_binding = PathBinding::make_Function({&ent}); + } }; } // namespace AST diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index ca5d8e4e..70bfc080 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -4,6 +4,8 @@ * * convert/resolve.cpp * - Resolve names into absolute format + * + * - Converts all paths into a canonical format (absolute, local, or UFCS) */ #include "../common.hpp" #include "../ast/ast.hpp" @@ -82,6 +84,7 @@ public: void handle_params(AST::TypeParams& params) override; virtual void handle_path(AST::Path& path, CASTIterator::PathMode mode) override; + void handle_path_abs(AST::Path& path, CASTIterator::PathMode mode); void handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mode); bool find_trait_item(const AST::Path& path, AST::Trait& trait, const ::std::string& item_name, bool& out_is_method, AST::Path& out_trait_path); virtual void handle_type(TypeRef& type) override; @@ -381,39 +384,43 @@ bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, c TRACE_FUNCTION_F("mod_path="< UFCS: Expand the types + // > UFCS: Resolve the type and trait case AST::Path::Class::UFCS: handle_path_ufcs(path, mode); break; // > Variable: (wait, how is this known already?) - // - 'self' + // - 'self', 'Self' case AST::Path::Class::Local: if( !path.binding().is_Unbound() ) { @@ -552,7 +557,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode 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); + //path.resolve(m_crate); break ; } else { @@ -564,7 +569,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode } // 3. Module items if( this->find_mod_item(path, info.name) ) { - path.resolve(m_crate); + //path.resolve(m_crate); break; } else { @@ -583,7 +588,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode { bool allow_variables = (mode == CASTIterator::MODE_EXPR && path.is_trivial()); if( this->find_local_item(path, path[0].name(), allow_variables) ) { - path.resolve(m_crate); + //path.resolve(m_crate); break ; } else { @@ -623,7 +628,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode // 3. current module { if( this->find_mod_item(path, path[0].name()) ) { - path.resolve(m_crate); + //path.resolve(m_crate); break; } else { @@ -663,6 +668,215 @@ 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_Unbound() ); } +void CPathResolver::handle_path_abs(AST::Path& path, CASTIterator::PathMode mode) +{ + //bool expect_params = false; + + assert( path.m_class.is_Absolute() ); + + auto& nodes = path.m_class.as_Absolute().nodes; + + unsigned int slice_from = 0; // Used when rewriting the path to be relative to its crate root + + // Iterate through nodes, starting at the root module of the specified crate + // - Locate the referenced item, and fail if the + ::std::vector mod_stack; + const AST::Module* mod = &this->m_crate.get_root_module(path.crate()); + for(unsigned int i = 0; i < nodes.size(); i ++ ) + { + mod_stack.push_back(mod); + const bool is_last = (i+1 == nodes.size()); + const AST::PathNode& node = nodes[i]; + DEBUG("[" << i << "/"<anon_mods().at(index); + continue ; + } + + auto item_ref = mod->find_item(node.name(), is_last); // Only allow leaf nodes (functions and statics) if this is the last node + TU_MATCH( AST::Module::ItemRef, (item_ref), (item), + // Not found + (None, + // If parent node is anon, backtrack and try again + // TODO: I feel like this shouldn't be done here, instead perform this when absolutising (now that find_item is reusable) + if( i > 0 && nodes[i-1].name()[0] == '#' && nodes[i-1].name().size() > 1 ) + { + i --; + mod_stack.pop_back(); + mod = mod_stack.back(); + mod_stack.pop_back(); + nodes.erase(nodes.begin()+i); + i --; + DEBUG("Failed to locate item in nested, look upwards"); + + continue ; + } + throw ParseError::Generic("Unable to find component '" + node.name() + "'"); + ), + // Sub-module + (Module, + DEBUG("Sub-module : " << node.name()); + if( node.args().size() ) + throw ParseError::Generic("Generic params applied to module"); + mod = &item; + ), + // Crate + (Crate, + const ::std::string& crate_name = item; + DEBUG("Extern crate '" << node.name() << "' = '" << crate_name << "'"); + if( node.args().size() ) + throw ParseError::Generic("Generic params applied to extern crate"); + path.set_crate( crate_name ); + slice_from = i+1; + mod = &this->m_crate.get_root_module(crate_name); + ), + + // Type Alias + (TypeAlias, + const auto& ta = item; + DEBUG("Type alias <"< " << ta.type()); + //if( node.args().size() != ta.params().size() ) + // throw ParseError::Generic("Param count mismatch when referencing type alias"); + // Make a copy of the path, replace params with it, then replace *this? + // - Maybe leave that up to other code? + if( is_last ) { + //check_param_counts(ta.params(), expect_params, nodes[i]); + goto ret; + } + else { + throw ParseError::Todo("Path::resolve() type method"); + } + ), + + // Function + (Function, + //const auto& fn = item; + DEBUG("Found function"); + if( is_last ) { + //check_param_counts(fn.params(), expect_params, nodes[i]); + goto ret; + } + else { + throw ParseError::Generic("Import of function, too many extra nodes"); + } + ), + + // Trait + (Trait, + //const auto& t = item; + DEBUG("Found trait"); + if( is_last ) { + //check_param_counts(t.params(), expect_params, nodes[i]); + goto ret; + } + else { + throw ParseError::Todo("CPathResolver::handle_path_abs - Trait into UFCS"); + } + ), + + // Struct + (Struct, + const auto& str = item; + DEBUG("Found struct"); + if( is_last ) { + //check_param_counts(str.params(), expect_params, nodes[i]); + path.bind_struct(str, node.args()); + goto ret; + } + else { + throw ParseError::Todo("CPathResolver::handle_path_abs - Struct into UFCS"); + } + ), + + // Enum / enum variant + (Enum, + const auto& enm = item; + DEBUG("Found enum"); + if( is_last ) { + //check_param_counts(enm.params(), expect_params, nodes[i]); + path.bind_enum(enm, node.args()); + goto ret; + } + else { + // TODO: Should enum variants be converted into UFCS, or left as is? + // - UFCS is actually valid... oddly enough, except in use statements + throw ParseError::Todo("CPathResolver::handle_path_abs - Enum into UFCS"); + } + ), + + (Static, + const auto& st = item; + DEBUG("Found static/const"); + if( is_last ) { + if( node.args().size() ) + throw ParseError::Generic("Unexpected generic params on static/const"); + path.bind_static(st); + goto ret; + } + else { + throw ParseError::Generic("Binding path to static, trailing nodes"); + } + ), + + // Re-export + (Use, + const auto& imp = item; + AST::Path newpath = imp.data; + auto& newnodes = newpath.m_class.as_Absolute().nodes; + DEBUG("Re-exported path " << imp.data); + if( imp.name == "" ) + { + // Replace nodes 0:i-1 with source path, then recurse + for( unsigned int j = i; j < nodes.size(); j ++ ) + { + newnodes.push_back( nodes[j] ); + } + } + else + { + // replace nodes 0:i with the source path + for( unsigned int j = i+1; j < nodes.size(); j ++ ) + { + newnodes.push_back( nodes[j] ); + } + } + + DEBUG("- newpath = " << newpath); + // TODO: This should check for recursion somehow + this->handle_path_abs(newpath, mode); + + path = mv$(newpath); + return; + ) + ) + } + + // We only reach here if the path points to a module + path.bind_module( *mod ); +ret: + if( slice_from > 0 ) + { + DEBUG("Removing " << slice_from << " nodes to rebase path to crate root"); + nodes.erase(nodes.begin(), nodes.begin()+slice_from); + } + return ; +} void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mode) { assert(path.m_class.is_UFCS()); @@ -768,8 +982,6 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod 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 ; }) } @@ -783,9 +995,6 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod 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 ; }) } @@ -793,13 +1002,9 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod throw ParseError::Todo("CPathResolver::handle_path_ufcs - UFCS, find trait"); } - - path.resolve(m_crate); } } else { - // 3. Call resolve to attempt binding - path.resolve(m_crate); } } @@ -910,7 +1115,7 @@ bool CPathResolver::find_super_mod_item(AST::Path& path, const ::std::string& na if( super_path.nodes().back().name()[0] == '#' ) throw ParseError::Todo("Correct handling of 'super' in anon modules (parent is anon)"); // 2. Resolve that path - super_path.resolve(m_crate); + //super_path.resolve(m_crate); // 3. Call lookup_path_in_module return lookup_path_in_module(m_crate, *super_path.binding().as_Module().module_, super_path, path, name, path.size()==1); } @@ -953,7 +1158,7 @@ void CPathResolver::handle_type(TypeRef& type) else { TU_MATCH(SelfType, (this->m_self_type.back()), (ent), (None, - assert(!""); + assert(!"SelfType is None in CPathResolver::handle_type"); ), (Type, type = ent.type; @@ -1072,7 +1277,7 @@ void CPathResolver::handle_module(AST::Path path, AST::Module& mod) } void CPathResolver::handle_trait(AST::Path path, AST::Trait& trait) { - path.resolve(m_crate); + //path.resolve(m_crate); // Handle local m_scope_stack.back().traits.push_back( ::std::pair(path, trait) ); @@ -1100,6 +1305,7 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod break; // 'super' - Add parent path // - TODO: Handle nested modules correctly. + // - TODO: Chaining 'super' is valid case AST::Path::Class::Super: { if( modpath.size() < 1 ) throw ParseError::Generic("Encountered 'super' at crate root"); @@ -1125,7 +1331,84 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod } // Run resolution on import - imp.data.resolve(crate, false); + // TODO: Need to truely absolutise? + { + const AST::Module* mod = &crate.root_module(); + for(const auto& node : p.nodes() ) { + if( node.args().size() > 0 ) { + throw ParseError::Generic("Unexpected generic params in use path"); + } + if( mod == nullptr ) { + if( p.binding().is_Enum() ) { + auto& enm = *p.binding().as_Enum().enum_; + for(const auto& variant : enm.variants()) { + if( variant.m_name == node.name() ) { + p.bind_enum_var(enm, node.name()); + break; + } + } + if( p.binding().is_Enum() ) { + throw ParseError::Generic( FMT("Unable to find component '" << node.name() << "' of import " << p) ); + } + break; + } + else { + throw ParseError::Generic("Extra path components after final item"); + } + } + auto item = mod->find_item(node.name()); + // HACK: Not actually a normal TU, but it fits the same pattern + TU_MATCH(AST::Module::ItemRef, (item), (i), + (None, + throw ParseError::Generic( FMT("Unable to find component '" << node.name() << "' of import " << p) ); + ), + (Module, + mod = &i; + ), + (Crate, + mod = &crate.get_root_module(i); + ), + (TypeAlias, + throw ParseError::Todo("Bind to type alias in use resolution"); + //p.bind_type_alias(i); + mod = nullptr; + ), + (Function, + p.bind_function(i); + mod = nullptr; + ), + (Trait, + p.bind_trait(i); + mod = nullptr; + ), + (Struct, + p.bind_struct(i); + mod = nullptr; + ), + (Enum, + // - Importing an enum item will be handled in the nullptr check above + p.bind_enum(i); + mod = nullptr; + ), + (Static, + p.bind_static(i); + mod = nullptr; + ), + (Use, + if(i.name == "") { + throw ParseError::Todo("Handle resolving to wildcard use in use resolution"); + } + else { + // Restart lookup using new path + } + ) + ) + } + if( mod != nullptr ) { + p.bind_module(*mod); + } + } + //imp.data.resolve(crate, false); DEBUG("Resolved import : " << imp.data); // If wildcard, make sure it's sane @@ -1136,7 +1419,7 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod throw ParseError::Generic("Wildcard imports are only allowed on modules and enums"); ), (Unbound, - throw ParseError::BugCheck("path unbound after calling .resolve()"); + throw ParseError::BugCheck("Wildcard import path unbound after calling .resolve()"); ), (Module, (void)0;), (Enum, (void)0;) @@ -1146,9 +1429,9 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod for( auto& new_imp : new_imports ) { - if( new_imp.binding().is_Unbound() ) { - new_imp.resolve(crate, false); - } + //if( new_imp.binding().is_Unbound() ) { + // new_imp.resolve(crate, false); + //} mod.add_alias(false, new_imp, new_imp[new_imp.size()-1].name()); } @@ -1163,7 +1446,7 @@ void SetCrateName_Type(const AST::Crate& crate, ::std::string name, TypeRef& typ if( type.is_path() ) { type.path().set_crate(name); - type.path().resolve(crate); + //type.path().resolve(crate); } } @@ -1176,7 +1459,7 @@ void SetCrateName_Mod(const AST::Crate& crate, ::std::string name, AST::Module& { imp.data.set_crate(name); // - Disable expectation of type parameters - imp.data.resolve(crate, false); + //imp.data.resolve(crate, false); } // TODO: All other types @@ -1209,7 +1492,7 @@ void ResolvePaths(AST::Crate& crate) UNINDENT(); // Then do path resolution on all other items - CPathResolver pr(crate); + CPathResolver pr(crate); DEBUG(" ---"); pr.handle_module(AST::Path("", {}), crate.root_module()); DEBUG(" <<<"); diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index 34657ff5..208e15ea 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -45,7 +45,7 @@ #define TU_DISPA7(n, a, a1,a2,a3, b1,b2, c1,c2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA2(n,a, b1,b2) TU_DISPA2(n,a, c1,c2) #define TU_DISPA8(n, a, a1,a2,a3, b1,b2,b3, c1,c2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA2(n,a, c1,c2) #define TU_DISPA9(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) -#define TU_DISPA10(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA(n,a, d1) +#define TU_DISPA10(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA(n, (TU_EXP a, TU_EXP d1)) #define TU_DISPA11(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1,d2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA2(n,a, d1,d2) #define TU_DISPA12(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1,d2,d3) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA3(n,a, d1,d2,d3) #define TU_DISPA13(n, a, a1,a2,a3,a4, b1,b2,b3, c1,c2,c3, d1,d2,d3) TU_DISPA4(n,a, a1,a2,a3,a4) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA3(n,a, d1,d2,d3) -- cgit v1.2.3