diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/ast/ast.cpp | 16 | ||||
-rw-r--r-- | src/ast/ast.hpp | 33 | ||||
-rw-r--r-- | src/ast/path.cpp | 59 | ||||
-rw-r--r-- | src/ast/path.hpp | 9 | ||||
-rw-r--r-- | src/ast/provided_module.cpp | 49 | ||||
-rw-r--r-- | src/convert/ast_iterate.cpp | 2 | ||||
-rw-r--r-- | src/convert/decorators.cpp | 38 | ||||
-rw-r--r-- | src/convert/resolve.cpp | 46 | ||||
-rw-r--r-- | src/convert/typecheck_params.cpp | 11 | ||||
-rw-r--r-- | src/include/synext.hpp | 11 | ||||
-rw-r--r-- | src/parse/expr.cpp | 2 | ||||
-rw-r--r-- | src/synexts/derive.cpp | 2 |
13 files changed, 213 insertions, 67 deletions
@@ -24,7 +24,7 @@ OBJ += convert/ast_iterate.o OBJ += convert/decorators.o OBJ += convert/resolve.o convert/typecheck_bounds.o convert/typecheck_params.o convert/typecheck_expr.o OBJ += convert/flatten.o convert/render.o -OBJ += synexts/derive.o +OBJ += synexts/derive.o synexts/lang_item.o OBJ := $(addprefix $(OBJDIR),$(OBJ)) 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 <typename T>
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<Function>& functions() const { return m_functions; }
const ItemList<TypeRef>& 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<EnumVariant>& 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<Impl*> m_impl_index;
::std::vector<const ImplDef*> 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<Impl&> 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<Item<T> >::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<TypeRef(const char*)> 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<TypeRef>& ufcs() { return m_ufcs; } + ::std::vector<PathNode>& nodes() { return m_nodes; } const ::std::vector<PathNode>& 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<CDecoratorHandler> > g_decorators; template<typename T> -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");
// - "<Type as _>::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 <memory> 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); } |