From b438b28eb173aba78027b50fcf1091b150711114 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 Apr 2015 23:05:49 +0800 Subject: Suport for #[lang], start work on resolving UFCS paths --- src/ast/ast.cpp | 16 +++++++++++ src/ast/ast.hpp | 33 ++++++++++++++++++---- src/ast/path.cpp | 59 +++++++++++++++++++++++++++++++++++++++- src/ast/path.hpp | 9 +++++- src/ast/provided_module.cpp | 49 ++++++++++++++++++++++----------- src/convert/ast_iterate.cpp | 2 +- src/convert/decorators.cpp | 38 ++++++++++++++++---------- src/convert/resolve.cpp | 46 +++++++++++++++++-------------- src/convert/typecheck_params.cpp | 11 +++++--- src/include/synext.hpp | 11 +++++++- src/parse/expr.cpp | 2 +- src/synexts/derive.cpp | 2 +- 12 files changed, 212 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index aadade4f..b6bc74a2 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -221,6 +221,16 @@ const Module& Crate::get_root_module(const ::std::string& name) const { throw ParseError::Generic("crate name unknown"); } +bool Crate::is_trait_implicit(const Path& trait) const +{ + // 1. Handle lang_item traits (e.g. FhantomFn) + if( m_lang_item_PhantomFn.is_valid() && trait.equal_no_generic( m_lang_item_PhantomFn ) >= 0 ) + { + return true; + } + return false; +} + /** * \brief Checks if a type implements the provided wildcard trait * \param trait Trait path @@ -267,6 +277,12 @@ bool Crate::find_impl(const Path& trait, const TypeRef& type, Impl** out_impl) if(out_impl) *out_impl = nullptr; + if( is_trait_implicit(trait) ) + { + if(out_impl) throw CompileError::BugCheck("find_impl - Asking for concrete impl of PhantomFn"); + return true; + } + // 0. Handle generic bounds // TODO: Handle more complex bounds like "[T]: Trait" if( type.is_type_param() ) diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 671a0aa9..c3d4860d 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -198,6 +198,13 @@ public: }; +enum eItemType +{ + ITEM_TRAIT, + ITEM_STRUCT, + ITEM_FN, +}; + template struct ItemNS { @@ -262,6 +269,7 @@ public: m_type( move(type) ) {} + const MetaItems& attrs() const { return m_attrs; } const TypeParams& params() const { return m_params; } const TypeRef& type() const { return m_type; } @@ -297,6 +305,7 @@ public: m_value( move(value) ) {} + const MetaItems& attrs() const { return m_attrs; } const Class& s_class() const { return m_class; } const TypeRef& type() const { return m_type; } const Expr& value() const { return m_value; } @@ -348,17 +357,18 @@ public: void set_self_lifetime(::std::string s) { m_lifetime = s; } const Class fcn_class() const { return m_fcn_class; } - - TypeParams& params() { return m_params; } - Expr& code() { return m_code; } - TypeRef& rettype() { return m_rettype; } - Arglist& args() { return m_args; } + const MetaItems& attrs() const { return m_attrs; } const TypeParams& params() const { return m_params; } const Expr& code() const { return m_code; } const TypeRef& rettype() const { return m_rettype; } const Arglist& args() const { return m_args; } + TypeParams& params() { return m_params; } + Expr& code() { return m_code; } + TypeRef& rettype() { return m_rettype; } + Arglist& args() { return m_args; } + SERIALISABLE_PROTOTYPES(); }; @@ -377,6 +387,7 @@ public: { } + const MetaItems& attrs() const { return m_attrs; } const TypeParams& params() const { return m_params; } const ItemList& functions() const { return m_functions; } const ItemList& types() const { return m_types; } @@ -444,6 +455,7 @@ public: m_variants( move(variants) ) {} + const MetaItems& attrs() const { return m_attrs; } const TypeParams& params() const { return m_params; } const ::std::vector& variants() const { return m_variants; } @@ -497,9 +509,11 @@ public: {} // Accessors + const MetaItems& attrs() const { return m_attrs; } const TypeParams& params() const { return m_params; } const Path& trait() const { return m_trait; } const TypeRef& type() const { return m_type; } + TypeParams& params() { return m_params; } Path& trait() { return m_trait; } TypeRef& type() { return m_type; } @@ -736,12 +750,19 @@ public: private: void resolve_macro_import(const Crate& crate, const ::std::string& modname, const ::std::string& macro_name); }; +} +extern void handle_lang_item(AST::Crate& , const AST::Path& h, const ::std::string& , AST::eItemType ); +namespace AST { class Crate: public Serialisable { ::std::vector m_impl_index; ::std::vector m_neg_impl_index; + + // XXX: EVIL - Make the method that handles #[lang] a friend, so it can twiddle these paths + friend void ::handle_lang_item(AST::Crate& , const AST::Path& h, const ::std::string& , AST::eItemType ); + AST::Path m_lang_item_PhantomFn; public: Module m_root_module; ::std::map< ::std::string, ExternCrate> m_extern_crates; @@ -762,6 +783,8 @@ public: void post_parse(); + bool is_trait_implicit(const Path& trait) const; + bool find_impl(const Path& trait, const TypeRef& type, Impl** out_impl); ::rust::option find_impl(const Path& trait, const TypeRef& type) { Impl* impl_ptr; diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 80344d01..2b1a6fb2 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -71,8 +71,15 @@ typename ::std::vector >::const_iterator find_named(const ::std::vector< void Path::resolve(const Crate& root_crate, bool expect_params) { TRACE_FUNCTION_F("*this = "<< *this); - if(m_class != ABSOLUTE) + if(m_class == ABSOLUTE) + resolve_absolute(root_crate, expect_params); + else if(m_class == 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) +{ DEBUG("m_crate = '" << m_crate << "'"); unsigned int slice_from = 0; // Used when rewriting the path to be relative to its crate root @@ -303,6 +310,56 @@ ret: } return ; } +void Path::resolve_ufcs(const Crate& root_crate, bool expect_params) +{ + auto& type = m_ufcs.at(0); + auto& trait = m_ufcs.at(1); + + // If the type is unknown (at this time) + if( type.is_wildcard() || type.is_type_param() ) + { + // - _ as _ = BUG + if( !trait.is_path() ) + { + throw CompileError::BugCheck( FMT("Path::resolve_ufcs - Path invalid : " << *this) ); + } + // - /*arg*/T as Trait = Type parameter + else if( type.is_type_param() ) + { + // Just check that the param is bound on that trait? + throw ParseError::Todo("Path::resolve_ufcs - Handle binding on generic"); + } + // - _ 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() ) + { + 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? + throw ParseError::Todo("Path::resolve_ufcs - Fully known"); + } + // - Type as ! = Item from the inherent impl (similar to above) + else if( trait == TypeRef(TypeRef::TagInvalid()) ) + { + throw ParseError::Todo("Path::resolve_ufcs - Fully known (inherent)"); + } + // - Type as * = Bug + else + { + throw CompileError::BugCheck( FMT("Path::resolve_ufcs - Path invalid : " << *this) ); + } + } +} void Path::check_param_counts(const TypeParams& params, bool expect_params, PathNode& node) { if( !expect_params ) diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 390271fe..8ba9e93c 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -146,7 +146,7 @@ public: class Path: public ::Serialisable { -private: +public: enum Class { RELATIVE, ABSOLUTE, @@ -154,6 +154,7 @@ private: UFCS, }; +private: /// The crate defining the root of this path (used for path resolution) ::std::string m_crate; @@ -254,6 +255,8 @@ public: /// /// 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); /// Resolve generic arguments within the path void resolve_args(::std::function fcn); @@ -265,12 +268,16 @@ public: return m_class == RELATIVE && m_nodes.size() == 1 && m_nodes[0].args().size() == 0; } + bool is_valid() const { return *this != Path(); } + Class type() const { return m_class; } bool is_absolute() const { return m_class == ABSOLUTE; } bool is_relative() const { return m_class == RELATIVE; } size_t size() const { return m_nodes.size(); } const PathBinding& binding() const { return m_binding; } + ::std::vector& ufcs() { return m_ufcs; } + ::std::vector& nodes() { return m_nodes; } const ::std::vector& nodes() const { return m_nodes; } diff --git a/src/ast/provided_module.cpp b/src/ast/provided_module.cpp index f8e53bdf..460b7494 100644 --- a/src/ast/provided_module.cpp +++ b/src/ast/provided_module.cpp @@ -2,7 +2,11 @@ */ #include "ast.hpp" +void AST_InitProvidedModule_Impls(); + AST::Module g_compiler_module; +AST::Path g_copy_marker_path; +AST::Path g_sized_marker_path; void AST_InitProvidedModule() { @@ -12,31 +16,44 @@ void AST_InitProvidedModule() AST::StructItem("", TypeRef(TypeRef::TagUnsizedArray(), TypeRef(CORETYPE_U8)), false), })); - AST::Path copy_marker_path({AST::PathNode("marker"),AST::PathNode("Copy")}); + // TODO: Defer this until AFTER + AST_InitProvidedModule_Impls(); +} + +void AST_InitProvidedModule_Impls() +{ + if( !g_copy_marker_path.is_valid() ) { + g_copy_marker_path = AST::Path( {AST::PathNode("marker"),AST::PathNode("Copy")} ); + } + + if( !g_sized_marker_path.is_valid() ) { + g_sized_marker_path = AST::Path( {AST::PathNode("marker"),AST::PathNode("Sized")} ); + } + #define impl(trait, type) \ g_compiler_module.add_impl(AST::Impl(AST::MetaItems(), AST::TypeParams(), type, trait)) - impl(copy_marker_path, TypeRef(CORETYPE_U8)); - impl(copy_marker_path, TypeRef(CORETYPE_U16)); - impl(copy_marker_path, TypeRef(CORETYPE_U32)); - impl(copy_marker_path, TypeRef(CORETYPE_U64)); - impl(copy_marker_path, TypeRef(CORETYPE_UINT)); - impl(copy_marker_path, TypeRef(CORETYPE_I8)); - impl(copy_marker_path, TypeRef(CORETYPE_I16)); - impl(copy_marker_path, TypeRef(CORETYPE_I32)); - impl(copy_marker_path, TypeRef(CORETYPE_I64)); - impl(copy_marker_path, TypeRef(CORETYPE_INT)); - impl(copy_marker_path, TypeRef(CORETYPE_F32)); - impl(copy_marker_path, TypeRef(CORETYPE_F64)); + impl(g_copy_marker_path, TypeRef(CORETYPE_U8)); + impl(g_copy_marker_path, TypeRef(CORETYPE_U16)); + impl(g_copy_marker_path, TypeRef(CORETYPE_U32)); + impl(g_copy_marker_path, TypeRef(CORETYPE_U64)); + impl(g_copy_marker_path, TypeRef(CORETYPE_UINT)); + impl(g_copy_marker_path, TypeRef(CORETYPE_I8)); + impl(g_copy_marker_path, TypeRef(CORETYPE_I16)); + impl(g_copy_marker_path, TypeRef(CORETYPE_I32)); + impl(g_copy_marker_path, TypeRef(CORETYPE_I64)); + impl(g_copy_marker_path, TypeRef(CORETYPE_INT)); + impl(g_copy_marker_path, TypeRef(CORETYPE_F32)); + impl(g_copy_marker_path, TypeRef(CORETYPE_F64)); // A hacky default impl of 'Sized', with a negative impl on [T] - AST::Path sized_marker_path({AST::PathNode("marker"),AST::PathNode("Sized")}); - impl(sized_marker_path, TypeRef()); + impl(g_sized_marker_path, TypeRef()); + { AST::TypeParams tps; tps.add_ty_param( AST::TypeParam("T") ); g_compiler_module.add_neg_impl(AST::ImplDef( AST::MetaItems(), ::std::move(tps), - sized_marker_path, + g_sized_marker_path, TypeRef(TypeRef::TagUnsizedArray(), TypeRef(TypeRef::TagArg(), "T")) )); } diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index a2fed087..49aa64c2 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -8,7 +8,7 @@ void CASTIterator::handle_path(AST::Path& path, CASTIterator::PathMode pm) } void CASTIterator::handle_type(TypeRef& type) { - //DEBUG("type = " << type); + TRACE_FUNCTION_F("type = " << type); if( type.is_path() ) { handle_path(type.path(), MODE_TYPE); diff --git a/src/convert/decorators.cpp b/src/convert/decorators.cpp index 0ccb16d4..8f9bb461 100644 --- a/src/convert/decorators.cpp +++ b/src/convert/decorators.cpp @@ -1,4 +1,9 @@ /* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * convert/decorators.cpp + * - Handles #[...] item decorators by delegating */ #include "ast_iterate.hpp" #include "../ast/ast.hpp" @@ -9,18 +14,21 @@ ::std::unordered_map< ::std::string, ::std::unique_ptr > g_decorators; template -bool Decorator_Apply(AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, T& ent) +void Decorator_Apply(AST::Crate& crate, AST::Module& mod, const AST::MetaItems& attrs, const AST::Path& path, T& ent) { - auto it = g_decorators.find(attr.name()); - if( it == g_decorators.end() ) + // For all attributes on the item, search for a handler and call handler + for( const auto& attr : attrs.m_items ) { - return false; + auto it = g_decorators.find(attr.name()); + if( it != g_decorators.end() ) + { + const CDecoratorHandler& handler = *it->second; + + handler.handle_item(crate, mod, attr, path, ent); + } + else { + } } - - const CDecoratorHandler& handler = *it->second; - - handler.handle_item(mod, attr, path, ent); - return true; } class CProcessor: @@ -42,12 +50,12 @@ public: void handle_struct(AST::Path path, AST::Struct& str) override { - // For all attributes on the struct, search for a handler and call handler - auto& attrs = str.attrs(); - for( auto& attr : attrs.m_items ) - { - Decorator_Apply(*m_modstack.back(), attr, path, str); - } + Decorator_Apply(m_crate, *m_modstack.back(), str.attrs(), path, str); + } + + void handle_trait(AST::Path path, AST::Trait& tr) override + { + Decorator_Apply(m_crate, *m_modstack.back(), tr.attrs(), path, tr); } }; diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 35187b5f..53f20f94 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -384,8 +384,9 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode) { // Convert to absolute - if( path.is_absolute() ) + switch( path.type() ) { + case AST::Path::ABSOLUTE: DEBUG("Absolute - binding"); INDENT(); // Already absolute, our job is done @@ -397,9 +398,8 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode DEBUG("- Path " << path << " already bound"); } UNINDENT(); - } - else if( path.is_relative() ) - { + break; + case AST::Path::RELATIVE: { assert(path.size() > 0); DEBUG("Relative, local"); @@ -425,11 +425,13 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode throw ParseError::Todo("TODO: MODE_EXPR, but not a single identifer, what do?"); DEBUG("Local variable " << path[0].name()); path = AST::Path(AST::Path::TagLocal(), path[0].name()); + return ; } - else + if( is_trivial_path ) + throw ParseError::Generic("Type used in expression context?"); + // Type parameter + case MODE_TYPE: { - if( is_trivial_path ) - throw ParseError::Generic("Type used in expression context?"); // Convert to a UFCS path DEBUG("Local type"); // - "::nodes" @@ -441,12 +443,6 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode DEBUG("path = " << path); } return ; - // Type parameter - case MODE_TYPE: - DEBUG("Local type " << path); - // - Switch the path to be a "LOCAL" - path.set_local(); - return ; // Binding is valid case MODE_BIND: //break ; @@ -501,6 +497,17 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode assert( path.is_relative() ); if( mode != MODE_BIND ) throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed"); + break; } + case AST::Path::LOCAL: + // Don't touch locals, they're already known + break; + case AST::Path::UFCS: + // 1. Handle sub-types + handle_type(path.ufcs().at(0)); + handle_type(path.ufcs().at(1)); + // 2. Call resolve to attempt binding + path.resolve(m_crate); + break; } } void CPathResolver::handle_type(TypeRef& type) @@ -511,16 +518,15 @@ void CPathResolver::handle_type(TypeRef& type) const auto& name = type.path()[0].name(); auto opt_local = lookup_local(LocalItem::TYPE, name); - /*if( name == "Self" ) + if( opt_local.is_some() ) { - // TODO: Handle "Self" correctly - // - Needs to be tagged with the soure params, but since Self is special... - // - Shouldn't matter, as Self should be resolved out before it needs that tagging - type = TypeRef(TypeRef::TagArg(), "Self"); + type = opt_local.unwrap().tr; } - else*/ if( opt_local.is_some() ) + else if( name == "Self" ) { - type = opt_local.unwrap().tr; + // If the name was "Self", but Self isn't already defined... then we need to make it an arg? + throw CompileError::Generic( FMT("CPathResolver::handle_type - Unexpected 'Self'") ); + type = TypeRef(TypeRef::TagArg(), "Self"); } else { diff --git a/src/convert/typecheck_params.cpp b/src/convert/typecheck_params.cpp index da3cf724..a3a432e0 100644 --- a/src/convert/typecheck_params.cpp +++ b/src/convert/typecheck_params.cpp @@ -67,6 +67,10 @@ public: bool CGenericParamChecker::has_impl_for_param(const ::std::string name, const AST::Path& trait) const { TRACE_FUNCTION_F("name = " << name << ", trait = " << trait); + + if( m_crate.is_trait_implicit(trait) ) + return true; + const AST::TypeParams* tps = nullptr; // Locate params set that contains the passed name for( const auto lt : m_types_stack ) @@ -115,7 +119,6 @@ bool CGenericParamChecker::has_impl(const TypeRef& type, const AST::Path& trait) // TODO: Search current scope (requires access to CGenericParamChecker) for this type, // and search the bounds for this trait // - Also accept bounded generic impls (somehow) - if( has_impl_for_param(type.type_param(), trait) ) { return true; } @@ -207,7 +210,7 @@ void CGenericParamChecker::check_generic_params(const AST::TypeParams& info, ::s { auto ra_fcn = [&](const char *a){ if( strcmp(a, "Self") == 0 ) { - if( self_type == TypeRef() ) + if( self_type == TypeRef(TypeRef::TagInvalid()) ) throw CompileError::Generic("Unexpected use of 'Self' in bounds"); return self_type; } @@ -236,7 +239,7 @@ void CGenericParamChecker::handle_path(AST::Path& path, CASTIterator::PathMode p switch(path.binding().type()) { case AST::PathBinding::UNBOUND: - throw ::std::runtime_error("CGenericParamChecker::handle_path - Unbound path"); + throw CompileError::BugCheck( FMT("CGenericParamChecker::handle_path - Unbound path : " << path) ); case AST::PathBinding::MODULE: DEBUG("WTF - Module path, isn't this invalid at this stage?"); break; @@ -264,7 +267,7 @@ void CGenericParamChecker::handle_path(AST::Path& path, CASTIterator::PathMode p case AST::PathBinding::FUNCTION: params = &path.binding().bound_func().params(); - check_generic_params(*params, last_node.args(), TypeRef(), (m_within_expr > 0)); + check_generic_params(*params, last_node.args(), TypeRef(TypeRef::TagInvalid()), (m_within_expr > 0)); break; default: throw ::std::runtime_error("Unknown path type in CGenericParamChecker::handle_path"); diff --git a/src/include/synext.hpp b/src/include/synext.hpp index 6688c1c7..d4026930 100644 --- a/src/include/synext.hpp +++ b/src/include/synext.hpp @@ -8,16 +8,25 @@ #include namespace AST { + class Crate; class MetaItem; class Path; + class Module; + class Struct; + class Trait; } class CDecoratorHandler { public: - virtual void handle_item(AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, AST::Struct& str) const = 0; + virtual void handle_item(AST::Crate&, AST::Module&, const AST::MetaItem&, const AST::Path&, AST::Struct& ) const + { + } + virtual void handle_item(AST::Crate&, AST::Module&, const AST::MetaItem&, const AST::Path&, AST::Trait& ) const + { + } }; #define STATIC_SYNEXT(_type, ident, _typename) \ diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index b4138057..b9a3d003 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -985,7 +985,7 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) lex.putback(tok); case TOK_LT: { TypeRef ty = Parse_Type(lex); - TypeRef trait; + TypeRef trait;// = TypeRef(TypeRef::TagInvalid()); if( GET_TOK(tok, lex) == TOK_RWORD_AS ) { trait = Parse_Type(lex); } diff --git a/src/synexts/derive.cpp b/src/synexts/derive.cpp index e6f191d0..d52823aa 100644 --- a/src/synexts/derive.cpp +++ b/src/synexts/derive.cpp @@ -143,7 +143,7 @@ class Decorator_Derive: public CDecoratorHandler { public: - void handle_item(AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, AST::Struct& str) const override + void handle_item(AST::Crate& , AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, AST::Struct& str) const override { derive_item(mod, attr, path, str); } -- cgit v1.2.3