diff options
author | John Hodge <tpg@ucc.asn.au> | 2019-11-02 11:07:23 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2019-11-02 11:07:23 +0800 |
commit | 1d02810c3cf908bfba7c15ae50eb5314603b9d85 (patch) | |
tree | 79dd5e4ef4c3ff79db0912ba546f08e61a7a8c10 /src/resolve/use.cpp | |
parent | 7111acba04d72fe4084b1a1f3209ff83efe8614d (diff) | |
parent | 8b53b38f40625ab0510f541d69db3f83332a830a (diff) | |
download | mrust-1d02810c3cf908bfba7c15ae50eb5314603b9d85.tar.gz |
Merge branch 'nightly-1.29' - #95 Working support for rustc 1.29
Diffstat (limited to 'src/resolve/use.cpp')
-rw-r--r-- | src/resolve/use.cpp | 686 |
1 files changed, 398 insertions, 288 deletions
diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 23f7e70c..8a9a3167 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -22,8 +22,8 @@ enum class Lookup ::AST::Path Resolve_Use_AbsolutisePath(const ::AST::Path& base_path, ::AST::Path path); void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path, ::std::span< const ::AST::Module* > parent_modules={}); -::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow=Lookup::Any); -::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow); +::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules); +::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start); void Resolve_Use(::AST::Crate& crate) @@ -51,7 +51,7 @@ void Resolve_Use(::AST::Crate& crate) // How can this happen? DEBUG("Relative " << path); // EVIL HACK: If the current module is an anon module, refer to the parent - if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) { + if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) { AST::Path np("", {}); for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ ) np.nodes().push_back( base_path.nodes()[i] ); @@ -65,7 +65,7 @@ void Resolve_Use(::AST::Crate& crate) (Self, DEBUG("Self " << path); // EVIL HACK: If the current module is an anon module, refer to the parent - if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) { + if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) { AST::Path np("", {}); for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ ) np.nodes().push_back( base_path.nodes()[i] ); @@ -86,7 +86,7 @@ void Resolve_Use(::AST::Crate& crate) // TODO: Do this in a cleaner manner. unsigned int n_anon = 0; // Skip any anon modules in the way (i.e. if the current module is an anon, go to the parent) - while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name()[0] == '#' ) + while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name().c_str()[0] == '#' ) n_anon ++; for( unsigned int i = 0; i < base_path.nodes().size() - e.count - n_anon; i ++ ) np.nodes().push_back( base_path.nodes()[i] ); @@ -113,60 +113,42 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path auto& use_stmt_data = use_stmt.data.as_Use(); const Span& span = use_stmt_data.sp; - use_stmt_data.path = Resolve_Use_AbsolutisePath(span, path, mv$(use_stmt_data.path)); - if( !use_stmt_data.path.m_class.is_Absolute() ) - BUG(span, "Use path is not absolute after absolutisation"); - - // TODO: Have Resolve_Use_GetBinding return the actual path - use_stmt_data.path.bind( Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules) ); - DEBUG("'" << use_stmt.name << "' = " << use_stmt_data.path); - - // - If doing a glob, ensure the item type is valid - if( use_stmt.name == "" ) + for(auto& use_ent : use_stmt_data.entries) { - TU_MATCH_DEF(::AST::PathBinding, (use_stmt_data.path.binding()), (e), - ( - ERROR(span, E0000, "Wildcard import of invalid item type - " << use_stmt_data.path); - ), - (Enum, - ), - (Crate, - ), - (Module, + use_ent.path = Resolve_Use_AbsolutisePath(span, path, mv$(use_ent.path)); + if( !use_ent.path.m_class.is_Absolute() ) + BUG(span, "Use path is not absolute after absolutisation"); + + // NOTE: Use statements can refer to _three_ different items + // - types/modules ("type namespace") + // - values ("value namespace") + // - macros ("macro namespace") + // TODO: Have Resolve_Use_GetBinding return the actual path + use_ent.path.m_bindings = Resolve_Use_GetBinding(span, crate, path, use_ent.path, parent_modules); + if( !use_ent.path.m_bindings.has_binding() ) + { + ERROR(span, E0000, "Unable to resolve `use` target " << use_ent.path); + } + DEBUG("'" << use_ent.name << "' = " << use_ent.path); + + // - If doing a glob, ensure the item type is valid + if( use_ent.name == "" ) + { + TU_MATCH_DEF(::AST::PathBinding_Type, (use_ent.path.m_bindings.type), (e), + ( + ERROR(span, E0000, "Wildcard import of invalid item type - " << use_ent.path); + ), + (Enum, + ), + (Crate, + ), + (Module, + ) ) - ) - } - else - { - // TODO: Handle case where a use can resolve to two different items (one value, one type/namespace) - // - Easiest way is with an extra binding slot - Lookup allow = Lookup::Any; - switch( use_stmt_data.path.binding().tag() ) + } + else { - case ::AST::PathBinding::TAG_Crate: - case ::AST::PathBinding::TAG_Module: - case ::AST::PathBinding::TAG_Trait: - case ::AST::PathBinding::TAG_TypeAlias: - case ::AST::PathBinding::TAG_Enum: - allow = Lookup::Value; - break; - case ::AST::PathBinding::TAG_Struct: - case ::AST::PathBinding::TAG_Union: - allow = Lookup::Value; - break; - case ::AST::PathBinding::TAG_EnumVar: - allow = Lookup::Value; - break; - case ::AST::PathBinding::TAG_Static: - case ::AST::PathBinding::TAG_Function: - allow = Lookup::Type; - break; - // DEAD, Unbound, ... - default: break; - } - ASSERT_BUG(span, allow != Lookup::Any, "Invalid path binding type in use statement - " << use_stmt_data.path); - use_stmt_data.alt_binding = Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules, allow); - DEBUG("- Alt Binding: " << use_stmt_data.alt_binding); + } } } @@ -235,6 +217,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path (None, // Deleted, ignore ), + (MacroInv, + // TODO: Should this already be deleted? + ), (Type, ), (Function, @@ -264,25 +249,24 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path } } -::AST::PathBinding Resolve_Use_GetBinding_Mod( +::AST::Path::Bindings Resolve_Use_GetBinding_Mod( const Span& span, - const ::AST::Crate& crate, const ::AST::Module& mod, - const ::std::string& des_item_name, - ::std::span< const ::AST::Module* > parent_modules, - Lookup allow + const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Module& mod, + const RcString& des_item_name, + ::std::span< const ::AST::Module* > parent_modules ) { + ::AST::Path::Bindings rv; // If the desired item is an anon module (starts with #) then parse and index - if( des_item_name.size() > 0 && des_item_name[0] == '#' ) { + if( des_item_name.size() > 0 && des_item_name.c_str()[0] == '#' ) { unsigned int idx = 0; if( ::std::sscanf(des_item_name.c_str(), "#%u", &idx) != 1 ) { BUG(span, "Invalid anon path segment '" << des_item_name << "'"); } - if( idx >= mod.anon_mods().size() ) { - BUG(span, "Invalid anon path segment '" << des_item_name << "'"); - } + ASSERT_BUG(span, idx < mod.anon_mods().size(), "Invalid anon path segment '" << des_item_name << "'"); assert( mod.anon_mods()[idx] ); - return ::AST::PathBinding::make_Module({&*mod.anon_mods()[idx], nullptr}); + rv.type = ::AST::PathBinding_Type::make_Module({&*mod.anon_mods()[idx], nullptr}); + return rv; } // Seach for the name defined in the module. @@ -292,8 +276,6 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path continue ; if( item.name == des_item_name ) { - //if( allow != Lookup::Any ) - // DEBUG(mod.path() << " " << des_item_name << " " << item.data.tag_str()); TU_MATCH(::AST::Item, (item.data), (e), (None, // IMPOSSIBLE - Handled above @@ -301,6 +283,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path (MacroInv, BUG(span, "Hit MacroInv in use resolution"); ), + (Macro, + //rv.macro = ::AST::PathBinding_Macro::make_MacroRules({nullptr, e.get()}); + ), (Use, continue; // Skip for now ), @@ -314,48 +299,48 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path BUG(span, "Hit Extern in use resolution"); ), (Crate, - if( allow != Lookup::Value ) - ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded"); - return ::AST::PathBinding::make_Crate({ &crate.m_extern_crates.at(e.name) }); + ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded"); + rv.type = ::AST::PathBinding_Type::make_Crate({ &crate.m_extern_crates.at(e.name) }); ), (Type, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_TypeAlias({&e}); + rv.type = ::AST::PathBinding_Type::make_TypeAlias({&e}); ), (Trait, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Trait({&e}); + rv.type = ::AST::PathBinding_Type::make_Trait({&e}); ), (Function, - if( allow != Lookup::Type ) - return ::AST::PathBinding::make_Function({&e}); + rv.value = ::AST::PathBinding_Value::make_Function({&e}); ), (Static, - if( allow != Lookup::Type ) - return ::AST::PathBinding::make_Static({&e}); + rv.value = ::AST::PathBinding_Value::make_Static({&e}); ), (Struct, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Struct({&e}); - if( e.m_data.is_Tuple() && allow != Lookup::Type ) - return ::AST::PathBinding::make_Struct({&e}); + // TODO: What happens with name collisions? + if( !e.m_data.is_Struct() ) + rv.value = ::AST::PathBinding_Value::make_Struct({&e}); + rv.type = ::AST::PathBinding_Type::make_Struct({&e}); ), (Enum, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Enum({&e}); + rv.type = ::AST::PathBinding_Type::make_Enum({&e}); ), (Union, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Union({&e}); + rv.type = ::AST::PathBinding_Type::make_Union({&e}); ), (Module, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Module({&e}); + rv.type = ::AST::PathBinding_Type::make_Module({&e}); ) ) } } + // TODO: macros + for(const auto& mac : mod.macros()) + { + if( mac.name == des_item_name ) { + rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ nullptr, &*mac.data }); + break; + } + } // Imports for( const auto& imp : mod.items() ) @@ -363,127 +348,153 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path if( ! imp.data.is_Use() ) continue ; const auto& imp_data = imp.data.as_Use(); - const Span& sp2 = imp_data.sp; - if( imp.name == des_item_name ) { - DEBUG("- Named import " << imp.name << " = " << imp_data); - if( imp_data.path.binding().is_Unbound() ) { - DEBUG(" > Needs resolve"); - // TODO: Handle possibility of recursion - //out_path = imp_data.path; - return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules, allow); - } - else { - if( allow != Lookup::Any && allow != Lookup::AnyOpt ) + for( const auto& imp_e : imp_data.entries ) + { + const Span& sp2 = imp_e.sp; + if( imp_e.name == des_item_name ) { + DEBUG("- Named import " << imp_e.name << " = " << imp_e.path); + if( !imp_e.path.m_bindings.has_binding() ) { - switch( imp_data.path.binding().tag() ) + DEBUG(" > Needs resolve p=" << &imp_e.path); + static ::std::vector<const ::AST::Path*> s_mods; + if( ::std::find(s_mods.begin(), s_mods.end(), &imp_e.path) == s_mods.end() ) { - case ::AST::PathBinding::TAG_Crate: - case ::AST::PathBinding::TAG_Module: - case ::AST::PathBinding::TAG_Trait: - case ::AST::PathBinding::TAG_TypeAlias: - case ::AST::PathBinding::TAG_Enum: - if( allow != Lookup::Type ) - continue; - break; - case ::AST::PathBinding::TAG_Struct: - break; - case ::AST::PathBinding::TAG_EnumVar: - break; - case ::AST::PathBinding::TAG_Static: - case ::AST::PathBinding::TAG_Function: - if( allow != Lookup::Value ) - continue; - break; - default: - break; + s_mods.push_back(&imp_e.path); + rv.merge_from( Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules) ); + s_mods.pop_back(); + } + else + { + DEBUG("Recursion on path " << &imp_e.path << " " << imp_e.path); } - } - //out_path = imp_data.path; - return imp_data.path.binding().clone(); - } - } - if( imp.is_pub && imp.name == "" ) { - DEBUG("- Search glob of " << imp_data.path); - // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here) - ::AST::PathBinding binding_; - const auto* binding = &imp_data.path.binding(); - if( binding->is_Unbound() ) { - DEBUG("Temp resolving wildcard " << imp_data); - // Handle possibility of recursion - static ::std::vector<const ::AST::UseStmt*> resolve_stack_ptrs; - if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() ) - { - resolve_stack_ptrs.push_back( &imp_data ); - binding_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules); - // *waves hand* I'm not evil. - const_cast< ::AST::PathBinding&>( imp_data.path.binding() ) = binding_.clone(); - binding = &binding_; - resolve_stack_ptrs.pop_back(); } else { - continue ; + //out_path = imp_e.path; + rv.merge_from( imp_e.path.m_bindings.clone() ); } - } - else { - //out_path = imp_data.path; + continue ; } - TU_MATCH_DEF(::AST::PathBinding, (*binding), (e), - ( - BUG(sp2, "Wildcard import expanded to an invalid item class - " << binding->tag_str()); - ), - (Crate, - assert(e.crate_); - const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module; - auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0, allow); - if( ! rv.is_Unbound() ) { - return mv$(rv); - } - ), - (Module, - auto allow_inner = (allow == Lookup::Any ? Lookup::AnyOpt : allow); - assert(e.module_); - // TODO: Prevent infinite recursion? - auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}, allow_inner); - if( ! rv.is_Unbound() ) { - return mv$(rv); - } - ), - (Enum, - assert(e.enum_ || e.hir); - if( e.enum_ ) { - const auto& enm = *e.enum_; - unsigned int i = 0; - for(const auto& var : enm.variants()) + // TODO: Correct privacy rules (if the origin of this lookup can see this item) + if( (imp.is_pub || mod.path().is_parent_of(source_mod_path)) && imp_e.name == "" ) + { + DEBUG("- Search glob of " << imp_e.path << " in " << mod.path()); + // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here) + ::AST::Path::Bindings bindings_; + const auto* bindings = &imp_e.path.m_bindings; + if( bindings->type.is_Unbound() ) { + DEBUG("Temp resolving wildcard " << imp_e.path); + // Handle possibility of recursion + static ::std::vector<const ::AST::UseItem*> resolve_stack_ptrs; + if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() ) { - if( var.m_name == des_item_name ) { - return ::AST::PathBinding::make_EnumVar({ &enm, i }); + resolve_stack_ptrs.push_back( &imp_data ); + bindings_ = Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules); + if( bindings_.type.is_Unbound() ) { + DEBUG("Recursion detected, skipping " << imp_e.path); + continue ; } - i ++; + // *waves hand* I'm not evil. + const_cast< ::AST::Path::Bindings&>( imp_e.path.m_bindings ) = bindings_.clone(); + bindings = &bindings_; + resolve_stack_ptrs.pop_back(); + } + else { + continue ; } } else { - const auto& enm = *e.hir; - auto idx = enm.find_variant(des_item_name); - if( idx != SIZE_MAX ) - { - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm }); + //out_path = imp_e.path; + } + + TU_MATCH_HDRA( (bindings->type), {) + TU_ARMA(Crate, e) { + assert(e.crate_); + const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module; + auto imp_rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); + if( imp_rv.has_binding() ) { + rv.merge_from( imp_rv ); + } } + TU_ARMA(Module, e) { + if( e.module_ ) { + // TODO: Prevent infinite recursion? + static ::std::vector<const AST::Module*> s_use_glob_mod_stack; + if( ::std::find(s_use_glob_mod_stack.begin(), s_use_glob_mod_stack.end(), &*e.module_) == s_use_glob_mod_stack.end() ) + { + s_use_glob_mod_stack.push_back( &*e.module_ ); + rv.merge_from( Resolve_Use_GetBinding_Mod(span, crate, mod.path(), *e.module_, des_item_name, {}) ); + s_use_glob_mod_stack.pop_back(); + } + else + { + DEBUG("Recursion prevented of " << e.module_->path()); + } + } + else if( e.hir ) { + const ::HIR::Module& hmod = *e.hir; + rv.merge_from( Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0) ); + } + else { + BUG(span, "NULL module for binding on glob of " << imp_e.path); + } + } + TU_ARMA(Enum, e) { + assert(e.enum_ || e.hir); + if( e.enum_ ) { + const auto& enm = *e.enum_; + unsigned int i = 0; + for(const auto& var : enm.variants()) + { + if( var.m_name == des_item_name ) { + ::AST::Path::Bindings tmp_rv; + if( var.m_data.is_Struct() ) + tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i }); + else + tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i }); + rv.merge_from(tmp_rv); + break; + } + i ++; + } + } + else { + const auto& enm = *e.hir; + auto idx = enm.find_variant(des_item_name); + if( idx != SIZE_MAX ) + { + ::AST::Path::Bindings tmp_rv; + if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) { + tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm }); + } + else { + tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm }); + } + rv.merge_from(tmp_rv); + break; + } + } + } break; + default: + BUG(sp2, "Wildcard import expanded to an invalid item class - " << bindings->type.tag_str()); + break; } - ) - ) + } } } + if( rv.has_binding() ) + { + return rv; + } - if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name()[0] == '#' ) { + if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name().c_str()[0] == '#' ) { assert( parent_modules.size() > 0 ); - return Resolve_Use_GetBinding_Mod(span, crate, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1), allow); + return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1)); } else { - if( allow == Lookup::Any ) - ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path()); - else - return ::AST::PathBinding::make_Unbound({}); + //if( allow == Lookup::Any ) + // ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path()); + return ::AST::Path::Bindings(); } } @@ -532,13 +543,15 @@ namespace { } } -::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow) +::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start) { - TRACE_FUNCTION_F(path); + ::AST::Path::Bindings rv; + TRACE_FUNCTION_F(path << " offset " << start); const auto& nodes = path.nodes(); const ::HIR::Module* hmod = &hmodr; for(unsigned int i = start; i < nodes.size() - 1; i ++) { + DEBUG("m_mod_items = {" << FMT_CB(ss, for(const auto& e : hmod->m_mod_items) ss << e.first << ", ";) << "}"); auto it = hmod->m_mod_items.find(nodes[i].name()); if( it == hmod->m_mod_items.end() ) { // BZZT! @@ -566,7 +579,13 @@ namespace { if( idx == SIZE_MAX ) { ERROR(span, E0000, "Unable to find variant " << path); } - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm }); + if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) { + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm }); + } + else { + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm }); + } + return rv; } else { hmod = reinterpret_cast<const ::HIR::Module*>(ptr); @@ -586,16 +605,23 @@ namespace { if(idx == SIZE_MAX) { ERROR(span, E0000, "Unable to find variant " << path); } - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e }); + if( e.m_data.is_Data() && e.m_data.as_Data()[idx].is_struct ) { + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e }); + } + else { + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e }); + } + return rv; ) ) } - if( allow != Lookup::Value ) + // - namespace/type items { auto it = hmod->m_mod_items.find(nodes.back().name()); - if( it != hmod->m_mod_items.end() ) { + if( it != hmod->m_mod_items.end() ) + { const auto* item_ptr = &it->second->ent; - DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str()); + DEBUG("E : Mod " << nodes.back().name() << " = " << item_ptr->tag_str()); if( item_ptr->is_Import() ) { const auto& e = item_ptr->as_Import(); const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name ); @@ -605,94 +631,139 @@ namespace { p.m_components.pop_back(); const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum(); assert(e.idx < enm.num_variants()); - return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm }); + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, e.idx, &enm }); + } + else if( e.path.m_components.empty() ) + { + rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &ec.m_hir->m_root_module}); + } + else + { + item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true } - if( e.path.m_components.empty() ) - return ::AST::PathBinding::make_Module({nullptr, &ec.m_hir->m_root_module}); - item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true } - TU_MATCHA( (*item_ptr), (e), - (Import, - BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path); - ), - (Module, - return ::AST::PathBinding::make_Module({nullptr, &e}); - ), - (TypeAlias, - return ::AST::PathBinding::make_TypeAlias({nullptr}); - ), - (Enum, - return ::AST::PathBinding::make_Enum({nullptr, &e}); - ), - (Struct, - return ::AST::PathBinding::make_Struct({nullptr, &e}); - ), - (Union, - return ::AST::PathBinding::make_Union({nullptr, &e}); - ), - (Trait, - return ::AST::PathBinding::make_Trait({nullptr, &e}); + if( rv.type.is_Unbound() ) + { + TU_MATCHA( (*item_ptr), (e), + (Import, + BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path); + ), + (Module, + rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); + ), + (TypeAlias, + rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); + ), + (ExternType, + rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); // Lazy. + ), + (Enum, + rv.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e}); + ), + (Struct, + rv.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e}); + ), + (Union, + rv.type = ::AST::PathBinding_Type::make_Union({nullptr, &e}); + ), + (Trait, + rv.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e}); + ) ) - ) + } + } + else + { + DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - if( allow != Lookup::Type ) + // - Values { auto it2 = hmod->m_value_items.find(nodes.back().name()); if( it2 != hmod->m_value_items.end() ) { const auto* item_ptr = &it2->second->ent; - DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str()); + DEBUG("E : Value " << nodes.back().name() << " = " << item_ptr->tag_str()); if( item_ptr->is_Import() ) { const auto& e = item_ptr->as_Import(); // This doesn't need to recurse - it can just do a single layer (as no Import should refer to another) const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name ); - if( e.is_variant ) { + if( e.is_variant ) + { auto p = e.path; p.m_components.pop_back(); const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum(); assert(e.idx < enm.num_variants()); - return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm }); + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, e.idx, &enm }); + } + else + { + item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true } - item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true } - TU_MATCHA( (*item_ptr), (e), - (Import, - BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path); - ), - (Constant, - return ::AST::PathBinding::make_Static({ nullptr }); - ), - (Static, - return ::AST::PathBinding::make_Static({ nullptr }); - ), - // TODO: What happens if these two refer to an enum constructor? - (StructConstant, - ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); - return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); - ), - (StructConstructor, - ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); - return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); - ), - (Function, - return ::AST::PathBinding::make_Function({ nullptr }); + if( rv.value.is_Unbound() ) + { + TU_MATCHA( (*item_ptr), (e), + (Import, + BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path); + ), + (Constant, + rv.value = ::AST::PathBinding_Value::make_Static({ nullptr }); + ), + (Static, + rv.value = ::AST::PathBinding_Value::make_Static({ nullptr }); + ), + // TODO: What happens if these two refer to an enum constructor? + (StructConstant, + ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); + rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); + ), + (StructConstructor, + ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); + rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); + ), + (Function, + rv.value = ::AST::PathBinding_Value::make_Function({ nullptr }); + ) ) - ) + } + } + else + { + DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - - DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - DEBUG("E : None"); - return ::AST::PathBinding::make_Unbound({}); + if( rv.type.is_Unbound() && rv.value.is_Unbound() ) + { + DEBUG("E : None"); + } + return rv; } -::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start, Lookup allow) +::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start) { - return Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start, allow); + DEBUG("Crate " << ec.m_name); + auto rv = Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start); + if( start + 1 == path.nodes().size() ) + { + const auto& name = path.nodes().back().name(); + auto it = ec.m_hir->m_exported_macros.find( name ); + if( it != ec.m_hir->m_exported_macros.end() ) + { + rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ &ec, &*it->second }); + } + + { + auto it = ::std::find_if( ec.m_hir->m_proc_macros.begin(), ec.m_hir->m_proc_macros.end(), [&](const auto& pm){ return pm.name == name;} ); + if( it != ec.m_hir->m_proc_macros.end() ) + { + rv.macro = ::AST::PathBinding_Macro::make_ProcMacro({ &ec, name }); + } + } + } + return rv; } -::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow) +::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) { TRACE_FUNCTION_F(path); //::AST::Path rv; @@ -701,15 +772,18 @@ namespace { if( path.m_class.is_Absolute() && path.m_class.as_Absolute().crate != "" ) { const auto& path_abs = path.m_class.as_Absolute(); - ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate), "Crate '" << path_abs.crate << "' not loaded"); - return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate ), 0, allow); + ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate.c_str()), "Crate '" << path_abs.crate << "' not loaded"); + return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate.c_str() ), 0); } + ::AST::Path::Bindings rv; + const AST::Module* mod = &crate.m_root_module; const auto& nodes = path.nodes(); if( nodes.size() == 0 ) { // An import of the root. - return ::AST::PathBinding::make_Module({ mod, nullptr }); + rv.type = ::AST::PathBinding_Type::make_Module({ mod, nullptr }); + return rv; } for( unsigned int i = 0; i < nodes.size()-1; i ++ ) { @@ -718,54 +792,90 @@ namespace { //rv = Resolve_Use_CanoniseAndBind_Mod(span, crate, *mod, mv$(rv), nodes[i].name(), parent_modules, Lookup::Type); //const auto& b = rv.binding(); assert(mod); - auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.at(i).name(), parent_modules, Lookup::Type); - TU_MATCH_DEF(::AST::PathBinding, (b), (e), - ( - ERROR(span, E0000, "Unexpected item type " << b.tag_str() << " in import of " << path); - ), - (Unbound, - ERROR(span, E0000, "Cannot find component " << i << " of " << path); - ), - (Crate, + auto b = Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.at(i).name(), parent_modules); + TU_MATCH_HDRA( (b.type), {) + default: + ERROR(span, E0000, "Unexpected item type " << b.type.tag_str() << " in import of " << path); + TU_ARMA(Unbound, e) { + ERROR(span, E0000, "Cannot find component " << i << " of " << path << " (" << b.type << ")"); + } + TU_ARMA(Crate, e) { // TODO: Mangle the original path (or return a new path somehow) - return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1, allow); - ), - (Enum, - const auto& enum_ = *e.enum_; + return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1); + } + TU_ARMA(Enum, e) { + ASSERT_BUG(span, e.enum_ || e.hir, "nullptr enum pointer in node " << i << " of " << path); + ASSERT_BUG(span, e.enum_ == nullptr || e.hir == nullptr, "both AST and HIR pointers set in node " << i << " of " << path); i += 1; if( i != nodes.size() - 1 ) { ERROR(span, E0000, "Encountered enum at unexpected location in import"); } + ASSERT_BUG(span, i < nodes.size(), "Enum import position error, " << i << " >= " << nodes.size() << " - " << path); const auto& node2 = nodes[i]; - int variant_index = -1; - for( unsigned int j = 0; j < enum_.variants().size(); j ++ ) + + unsigned variant_index = 0; + bool is_value = false; + if(e.hir) { - if( enum_.variants()[j].m_name == node2.name() ) { - variant_index = j; - break ; + const auto& enum_ = *e.hir; + size_t idx = enum_.find_variant(node2.name()); + if( idx == ~0u ) { + ERROR(span, E0000, "Unknown enum variant " << path); } + TU_MATCH_HDRA( (enum_.m_data), {) + TU_ARMA(Value, ve) { + is_value = true; + } + TU_ARMA(Data, ve) { + is_value = !ve[idx].is_struct; + } + } + DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value); } - if( variant_index < 0 ) { - ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'"); - } + else + { + const auto& enum_ = *e.enum_; + for( const auto& var : enum_.variants() ) + { + if( var.m_name == node2.name() ) { + is_value = !var.m_data.is_Struct(); + break ; + } + variant_index ++; + } + if( variant_index == enum_.variants().size() ) { + ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'"); + } - return ::AST::PathBinding::make_EnumVar({&enum_, static_cast<unsigned int>(variant_index)}); - ), - (Module, + DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value << " " << enum_.variants()[variant_index].m_data.tag_str()); + } + if( is_value ) { + rv.value = ::AST::PathBinding_Value::make_EnumVar({e.enum_, variant_index, e.hir}); + } + else { + rv.type = ::AST::PathBinding_Type::make_EnumVar({e.enum_, variant_index, e.hir}); + } + return rv; + } + TU_ARMA(Module, e) { ASSERT_BUG(span, e.module_ || e.hir, "nullptr module pointer in node " << i << " of " << path); if( !e.module_ ) { assert(e.hir); // TODO: Mangle the original path (or return a new path somehow) - return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1, allow); + return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1); } mod = e.module_; - ) - ) + } + } } assert(mod); - return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name(), parent_modules, allow); + return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.back().name(), parent_modules); } +//::AST::PathBinding_Macro Resolve_Use_GetBinding_Macro(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) +//{ +// throw ""; +//} |