From e6738ed57d644572e7cbefa6d68a4118935a5f80 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 Sep 2015 18:16:36 +0800 Subject: Disable UFCS resolve (due to ordering issues), fix Self handling --- src/ast/path.cpp | 23 +++++- src/ast/path.hpp | 3 +- src/convert/ast_iterate.cpp | 40 ++++++++--- src/convert/ast_iterate.hpp | 5 ++ src/convert/resolve.cpp | 172 +++++++++++++++++++++++++++++++++++--------- src/include/span.hpp | 3 +- src/main.cpp | 5 +- src/parse/root.cpp | 1 + src/types.hpp | 1 + 9 files changed, 202 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 247a6b2b..8fe42527 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -115,6 +115,24 @@ AST::Path::Path(const Path& x): ) ) + memcpy(&m_binding, &x.m_binding, sizeof(PathBinding)); + //TU_MATCH(PathBinding, (x.m_binding), (ent), + //(Unbound, m_binding = PathBinding::make_Unbound({}); ), + //(Module, os << "Module"; ), + //(Trait, os << "Trait"; ), + //(Struct, os << "Struct"; ), + //(Enum, os << "Enum"; ), + //(Static, os << "Static"; ), + //(Function, os << "Function";), + //(EnumVar, os << "EnumVar(" << i.idx << ")"; ), + //(TypeAlias, os << "TypeAlias";), + //(StructMethod, os << "StructMethod"; ), + //(TraitMethod, os << "TraitMethod"; ), + // + //(TypeParameter, os << "TypeParameter(" << i.level << " # " << i.idx << ")"; ), + //(Variable, os << "Variable(" << i.slot << ")"; ) + //) + DEBUG("clone, x = " << x << ", this = " << *this ); } @@ -454,7 +472,7 @@ void Path::resolve_ufcs(const Crate& root_crate, bool expect_params) void Path::resolve_ufcs_trait(const AST::Path& trait_path, AST::PathNode& node) { if( !trait_path.m_binding.is_Trait() ) - throw ParseError::Generic("Path::resolve_ufcs - Trait in UFCS path is not a trait"); + ERROR(trait_path.span(), E0000, "Trait in UFCS path is not a trait"); const auto& trait_def = *trait_path.m_binding.as_Trait().trait_; // Check that the requested item exists within the trait, and bind to that item @@ -843,7 +861,6 @@ void Path::print_pretty(::std::ostream& os) const #endif os << n; } - os << "/*" << path.m_binding << "*/"; ), (UFCS, os << "/*ufcs*/<" << *ent.type << " as " << *ent.trait << ">"; @@ -851,7 +868,7 @@ void Path::print_pretty(::std::ostream& os) const os << "::" << n; ) ) - os << "/*[" << path.span().filename << ":" << path.span().start_line << "]*/"; + os << "/*" << path.m_binding << " [" << path.span().filename << ":" << path.span().start_line << "]*/"; #else switch(path.m_class) { diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 9e190453..d0cc5648 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -145,7 +145,8 @@ public: m_crate = mv$(x.m_crate); m_class = mv$(x.m_class); //m_span = mv$(x.m_span); - x.m_binding = mv$(x.m_binding); + m_binding = mv$(x.m_binding); + //DEBUG("Path, " << x); return *this; } diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index cdb927e6..2946fd63 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -70,16 +70,22 @@ void CASTIterator::handle_params(AST::TypeParams& params) (IsTrait, handle_type(ent.type); // TODO: Define HRLs + push_self(ent.type); handle_path(ent.trait, CASTIterator::MODE_TYPE); + pop_self(); ), (MaybeTrait, handle_type(ent.type); + push_self(ent.type); handle_path(ent.trait, CASTIterator::MODE_TYPE); + pop_self(); // TODO: Process trait, ensuring that it's a valid lang item ), (NotTrait, handle_type(ent.type); + push_self(ent.type); handle_path(ent.trait, CASTIterator::MODE_TYPE); + pop_self(); ), (Equality, handle_type(ent.type); @@ -347,24 +353,24 @@ void CASTIterator::handle_function(AST::Path path, AST::Function& fcn) void CASTIterator::handle_impl_def(AST::ImplDef& impl) { - // First, so that handle_params can use it - local_type("Self", impl.type()); - // Generic params handle_params( impl.params() ); + // Type + handle_type( impl.type() ); + + push_self(impl.type()); + // Trait if( impl.trait() != AST::Path() ) handle_path( impl.trait(), MODE_TYPE ); - // Type - handle_type( impl.type() ); } void CASTIterator::handle_impl(AST::Path modpath, AST::Impl& impl) { start_scope(); - handle_impl_def(impl.def()); + handle_impl_def(impl.def()); // Associated types for( auto& at : impl.types() ) @@ -380,6 +386,7 @@ void CASTIterator::handle_impl(AST::Path modpath, AST::Impl& impl) handle_function(AST::Path(AST::Path::TagRelative(), { AST::PathNode(fcn.name) }), fcn.data); } + pop_self(); end_scope(); } @@ -405,14 +412,21 @@ void CASTIterator::handle_enum(AST::Path path, AST::Enum& enm) void CASTIterator::handle_trait(AST::Path path, AST::Trait& trait) { start_scope(); - local_type("Self", TypeRef(TypeRef::TagArg(), "Self")); + push_self(path, trait); handle_params( trait.params() ); - //local_type("Self", TypeRef(path)); - //local_type("Self", TypeRef(TypeRef::TagArg(), "Self")); + for( auto& st : trait.supertraits() ) { + if( st.m_class.is_Invalid() ) { + // An invalid path is used for 'static + } + else { + handle_path(st, MODE_TYPE); + } + } for( auto& fcn : trait.functions() ) handle_function( path + fcn.name, fcn.data ); + pop_self(); end_scope(); } void CASTIterator::handle_alias(AST::Path path, AST::TypeAlias& alias) @@ -422,3 +436,11 @@ void CASTIterator::handle_alias(AST::Path path, AST::TypeAlias& alias) handle_type( alias.type() ); end_scope(); } +void CASTIterator::push_self() { +} +void CASTIterator::push_self(AST::Path path, const AST::Trait& trait) { +} +void CASTIterator::push_self(TypeRef real_type) { +} +void CASTIterator::pop_self() { +} diff --git a/src/convert/ast_iterate.hpp b/src/convert/ast_iterate.hpp index 14537b10..4b271bfb 100644 --- a/src/convert/ast_iterate.hpp +++ b/src/convert/ast_iterate.hpp @@ -54,6 +54,11 @@ public: virtual void handle_enum(AST::Path path, AST::Enum& enm); virtual void handle_trait(AST::Path path, AST::Trait& trait); virtual void handle_alias(AST::Path path, AST::TypeAlias& alias); + + virtual void push_self(); + virtual void push_self(AST::Path path, const AST::Trait& trait); + virtual void push_self(TypeRef real_type); + virtual void pop_self(); private: void handle_impl_def(AST::ImplDef& impl); diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index bdbf1854..38808831 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -16,6 +16,11 @@ class CPathResolver: public CASTIterator { + const AST::Crate& m_crate; + AST::Module* m_module; + AST::Path m_module_path; + + struct LocalItem { enum Type { @@ -43,10 +48,8 @@ class CPathResolver: return os << "var '" << x.name << "'"; } }; - const AST::Crate& m_crate; - AST::Module* m_module; - AST::Path m_module_path; ::std::vector< LocalItem > m_locals; + struct Scope { unsigned int module_idx; AST::Module *module; // can be NULL @@ -56,7 +59,19 @@ class CPathResolver: ::std::vector< ::std::pair > traits; }; ::std::vector m_scope_stack; - ::std::vector< TypeRef > m_self_type; + + + TAGGED_UNION(SelfType, None, + (None, ()), + (Type, ( + TypeRef type; + )), + (Trait, ( + AST::Path path; + const AST::Trait* trait; + )) + ); + ::std::vector m_self_type; friend class CResolvePaths_NodeVisitor; @@ -106,6 +121,19 @@ public: bool find_super_mod_item(AST::Path& path, const ::std::string& name); bool find_type_param(const ::std::string& name); + virtual void push_self() override { + m_self_type.push_back( SelfType::make_None({}) ); + } + virtual void push_self(AST::Path path, const AST::Trait& trait) override { + m_self_type.push_back( SelfType::make_Trait( {path, &trait} ) ); + } + virtual void push_self(TypeRef real_type) override { + m_self_type.push_back( SelfType::make_Type( {real_type} ) ); + } + virtual void pop_self() override { + m_self_type.pop_back(); + } + // TODO: Handle a block and obtain the local module (if any) private: void handle_path_int(AST::Path& path, CASTIterator::PathMode mode); @@ -393,6 +421,7 @@ bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, c /// Perform path resolution within a generic definition block void CPathResolver::handle_params(AST::TypeParams& params) { + TRACE_FUNCTION; // Parameters DEBUG("params"); for( auto& param : params.ty_params() ) @@ -405,6 +434,8 @@ void CPathResolver::handle_params(AST::TypeParams& params) DEBUG("Bounds"); for( auto& bound : params.bounds() ) { + DEBUG("- Bound " << bound); + TU_MATCH(AST::GenericBound, (bound), (ent), (Lifetime, {} @@ -414,21 +445,22 @@ void CPathResolver::handle_params(AST::TypeParams& params) ), (IsTrait, handle_type(ent.type); - m_self_type.push_back( TypeRef() ); + // TODO: Should 'Self' in this trait be ent.type? + push_self(ent.type); handle_path(ent.trait, MODE_TYPE); - m_self_type.pop_back(); + pop_self(); ), (MaybeTrait, handle_type(ent.type); - m_self_type.push_back( TypeRef() ); + push_self(); handle_path(ent.trait, MODE_TYPE); - m_self_type.pop_back(); + pop_self(); ), (NotTrait, handle_type(ent.type); - m_self_type.push_back( TypeRef() ); + push_self(); handle_path(ent.trait, MODE_TYPE); - m_self_type.pop_back(); + pop_self(); ), (Equality, handle_type(ent.type); @@ -480,7 +512,7 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) ) } void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode) -{ +{ // Convert to absolute // - This means converting all partial forms (i.e. not UFCS, Variable, or Absolute) switch( path.class_tag() ) @@ -565,7 +597,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode // - If there are more nodes, replace with a UFCS block { auto tp = this->find_type_param(path[0].name()); - if( tp != false /*nullptr*/ ) + if( tp != false /*nullptr*/ || path[0].name() == "Self" ) { if(path.size() > 1) { // Repalce with UFCS @@ -633,14 +665,16 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod 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) + // TODO: Disabled, as it requires having all traits (semi) path resolved, so that trait resolution works cleanly if( info.trait->is_wildcard() ) { - DEBUG("Searching for impls when trait is _ (trait = " << *info.trait << ")"); + #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) - throw ParseError::Todo("CPathResolver::handle_path_ufcs - Handle '::...'"); + 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 { + ERROR(path.span(), E0000, "Cannot find item '" << item_name << "' on Self"); + } } else if( info.type->is_type_param() ) { @@ -703,6 +759,7 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod } 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), { @@ -733,13 +790,19 @@ 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); + #endif + } + else { + // 3. Call resolve to attempt binding + path.resolve(m_crate); } - // 3. Call resolve to attempt binding - path.resolve(m_crate); } bool CPathResolver::find_trait_item(const AST::Path& path, AST::Trait& trait, const ::std::string& item_name, bool& out_is_method, AST::Path& out_trait_path) { + TRACE_FUNCTION_F("path=" << path << ", trait=..., item_name=" << item_name); { const auto& fcns = trait.functions(); //DEBUG("fcns = " << fcns); @@ -747,8 +810,8 @@ bool CPathResolver::find_trait_item(const AST::Path& path, AST::Trait& trait, co if( it != fcns.end() ) { // Found it. out_is_method = true; - DEBUG("&out_trait_path = " << &out_trait_path); out_trait_path = AST::Path(path); + DEBUG("Fcn, out_trait_path = " << out_trait_path); return true; } } @@ -759,14 +822,30 @@ bool CPathResolver::find_trait_item(const AST::Path& path, AST::Trait& trait, co // Found it. out_is_method = false; out_trait_path = AST::Path(path); + DEBUG("Ty, out_trait_path = " << out_trait_path << " path=" << path); return true; } } for( auto& st : trait.supertraits() ) { - assert(st.is_bound()); - if( this->find_trait_item(st, *const_cast(st.binding().as_Trait().trait_), item_name, out_is_method, out_trait_path) ) + if(!st.is_bound()) { + handle_path(st, MODE_TYPE); + //BUG(st.span(), "Supertrait path '"<(st.binding().as_Trait().trait_); + if( this->find_trait_item(st, super_t, item_name, out_is_method, out_trait_path) ) { + DEBUG("path = " << path << ", super_t.params() = " << super_t.params() << ", out_trait_path = " << out_trait_path); + // + out_trait_path.resolve_args([&](const char* name) { + int idx = trait.params().find_name(name); + if(idx < 0) + ERROR(st.span(), E0000, "Parameter " << name << " not found"); + const auto& tr = path.nodes().back().args().at(idx); + DEBUG("Replacing '" << name << "' with " << tr); + return tr; + }); return true; + } } return false; @@ -865,11 +944,25 @@ void CPathResolver::handle_type(TypeRef& type) else if( name == "Self" ) { // If the name was "Self", but Self isn't already defined... then we need to make it an arg? - ERROR(type.path().span(), E0000, "Unexpected 'Self'"); - - TypeRef nt = TypeRef(TypeRef::TagArg(), "Self"); - nt.set_span(type.span()); - type = nt; + if( this->m_self_type.empty() || this->m_self_type.back().is_None() ) { + ERROR(type.path().span(), E0000, "Unexpected 'Self'"); + } + else { + TU_MATCH(SelfType, (this->m_self_type.back()), (ent), + (None, + assert(!""); + ), + (Type, + type = ent.type; + return ; + ), + (Trait, + // TODO: Need to have the trait encoded in the type. To avoid interpolation and bad replacement + // - Would also reduce the need to look at the m_self_type stack + type = TypeRef(TypeRef::TagArg(), "Self"); + ) + ) + } } else { @@ -880,14 +973,25 @@ void CPathResolver::handle_type(TypeRef& type) { const auto& name = type.type_param(); auto opt_local = lookup_local(LocalItem::TYPE, name); - /*if( name == "Self" ) + if( name == "Self" ) { - // Good as it is - // - TODO: Allow replacing this with the real Self (e.g. in an impl block) - // - NEED to annotate with the relevant impl block, and with other bounds - // > So that you can handle 'where Self: Sized' etc + if( m_self_type.empty() ) { + ERROR(type.span(), E0000, "Self type not set"); + } + TU_MATCH(SelfType, (m_self_type.back()), (ent), + (None, + ERROR(type.span(), E0000, "Self type not set"); + ), + (Type, + type = ent.type; + return ; + ), + (Trait, + // Valid... + ) + ) } - else*/ if( opt_local.is_some() ) + else if( opt_local.is_some() ) { type = opt_local.unwrap().tr; } @@ -965,11 +1069,11 @@ void CPathResolver::handle_module(AST::Path path, AST::Module& mod) } void CPathResolver::handle_trait(AST::Path path, AST::Trait& trait) { + path.resolve(m_crate); + // Handle local - for( auto& st : trait.supertraits() ) { - handle_path(st, MODE_TYPE); - } m_scope_stack.back().traits.push_back( ::std::pair(path, trait) ); + CASTIterator::handle_trait(path, trait); } void CPathResolver::handle_function(AST::Path path, AST::Function& fcn) { diff --git a/src/include/span.hpp b/src/include/span.hpp index c8c61627..452f37ba 100644 --- a/src/include/span.hpp +++ b/src/include/span.hpp @@ -52,5 +52,6 @@ struct Span void note(::std::function msg) const; }; -#define ERROR(span, code, msg) do { (span).error(code, [](::std::ostream& os) { os << msg; }); throw ::std::runtime_error("Error fell through" #code); } while(0) +#define ERROR(span, code, msg) do { (span).error(code, [&](::std::ostream& os) { os << msg; }); throw ::std::runtime_error("Error fell through" #code); } while(0) +#define BUG(span, msg) do { (span).bug([&](::std::ostream& os) { os << msg; }); throw ::std::runtime_error("Bug fell through"); } while(0) diff --git a/src/main.cpp b/src/main.cpp index 6515685a..e883b7ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,13 +45,12 @@ Rv CompilePhase(const char *name, Fcn f) { g_cur_phase = name; auto rv = f(); g_cur_phase = ""; + ::std::cout << name << ": DONE" << ::std::endl; return rv; } template void CompilePhaseV(const char *name, Fcn f) { - g_cur_phase = name; - f(); - g_cur_phase = ""; + CompilePhase(name, [&]() { f(); return 0; }); } /// main! diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 422f036e..d0bf795c 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -227,6 +227,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaIt if( tok.type() == TOK_AMP ) { // By-reference method? + // TODO: If a lifetime is seen (and not a prototype), it is definitely a self binding unsigned int ofs = 0; if( lex.lookahead(0) == TOK_LIFETIME ) diff --git a/src/types.hpp b/src/types.hpp index 5bb257c7..90f9ee3b 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -103,6 +103,7 @@ public: TypeData m_data; TypeRef(TypeRef&& other) noexcept: + //m_span( mv$(other.m_span) ), m_data( mv$(other.m_data) ) {} -- cgit v1.2.3