/* */ #include "crate.hpp" #include "ast.hpp" #include "../parse/parseerror.hpp" #include namespace { void iterate_module(::AST::Module& mod, ::std::function fcn) { fcn(mod); for( auto& sm : mod.items() ) { TU_MATCH_DEF(::AST::Item, (sm.data), (e), ( ), (Module, iterate_module(e.e, fcn); ) ) } } } namespace AST { Crate::Crate(): m_root_module(::AST::Path()), m_load_std(LOAD_STD) { } void Crate::load_externs() { auto cb = [this](Module& mod) { for( const auto& it : mod.items() ) { if( it.data.is_Crate() ) { const auto& name = it.data.as_Crate().name; throw ::std::runtime_error( FMT("TODO: Load crate '" << name << "' as '" << it.name << "'") ); } } }; iterate_module(m_root_module, cb); } void Crate::index_impls() { // Iterate all modules, grabbing pointers to all impl blocks auto cb = [this](Module& mod){ for( auto& impl : mod.impls() ) m_impl_index.push_back( &impl ); for( auto& impl : mod.neg_impls() ) m_neg_impl_index.push_back( &impl ); }; iterate_module(m_root_module, cb); iterate_module(g_compiler_module, cb); // Create a map of inherent impls for( const auto& impl : m_impl_index ) { if( impl->def().trait().is_valid() == false ) { auto& ent = m_impl_map[impl->def().type()]; ent.push_back( impl ); } } } void Crate::iterate_functions(fcn_visitor_t* visitor) { m_root_module.iterate_functions(visitor, *this); } Module& Crate::get_root_module(const ::std::string& name) { return const_cast( const_cast(this)->get_root_module(name) ); } const Module& Crate::get_root_module(const ::std::string& name) const { if( name == "" ) return m_root_module; auto it = m_extern_crates.find(name); if( it != m_extern_crates.end() ) throw ::std::runtime_error("TODO: Get root module for extern crate"); // return it->second.root_module(); 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 * \param type Type in question * \note Wildcard trait = A trait for which there exists a 'impl Trait for ..' definition * * \return True if the trait is implemented (either exlicitly, or implicitly) */ bool Crate::check_impls_wildcard(const Path& trait, const TypeRef& type) const { ::std::vector _params; TRACE_FUNCTION_F("trait="< )> callback) const { assert( !type.is_type_param() ); for( auto implptr : m_impl_index ) { Impl& impl = *implptr; if( impl.def().trait().is_valid() ) { // Trait } else { DEBUG("- " << impl.def()); ::std::vector out_params; if( impl.def().matches(out_params, AST::Path(), type) ) { if( callback(impl, out_params) ) { return true; } } } } return false; } ::rust::option Crate::find_impl(const Path& trait, const TypeRef& type) const { ::std::vector params; Impl *out_impl; if( find_impl(trait, type, &out_impl, ¶ms) ) { return ::rust::Some( ImplRef(*out_impl, params) ); } else { return ::rust::None(); } } bool Crate::find_impl(const Path& trait, const TypeRef& type, Impl** out_impl, ::std::vector* out_params) const { TRACE_FUNCTION_F("trait = " << trait << ", type = " << type); // If no params output provided, use a dud locaton ::std::vector dud_params; if(out_params) *out_params = ::std::vector(); else out_params = &dud_params; // Zero output if(out_impl) *out_impl = nullptr; if( is_trait_implicit(trait) ) { if(out_impl) throw CompileError::BugCheck("find_impl - Asking for concrete impl of a marker trait"); return true; } // 0. Handle generic bounds // TODO: Handle more complex bounds like "[T]: Trait" if( type.is_type_param() ) { if( trait.is_valid() ) { assert(type.type_params_ptr()); // Search bounds for type: trait for( const auto& bound : type.type_params_ptr()->bounds() ) { DEBUG("bound = " << bound); TU_MATCH_DEF(GenericBound, (bound), (ent), (), (IsTrait, if(ent.type == type && ent.trait == trait) { // If found, success! DEBUG("- Success!"); // TODO: What should be returned, kinda need to return a boolean if(out_impl) throw CompileError::BugCheck("find_impl - Asking for a concrete impl, but generic passed"); return true; } ) ) } // Else, failure DEBUG("- No impl :("); //if(out_impl) throw CompileError::BugCheck("find_impl - Asking for a concrete impl, but generic passed"); return false; } else { DEBUG("- No inherent impl for generic params"); return false; } } // TODO: Do a sort to allow a binary search // 1. Search for wildcard traits (i.e. ones like "impl Send for ..") // - These require special handling, as negatives apply for( auto implptr : m_impl_index ) { Impl& impl = *implptr; ::std::vector _p; if( impl.def().matches(_p, trait, TypeRef()) ) { assert(_p.size() == 0); // This is a wildcard trait, need to locate either a negative, or check contents if( check_impls_wildcard(trait, type) ) { if(out_impl) *out_impl = &impl; return true; } else { return false; } } } // 2. Check real impls DEBUG("Not wildcard"); for( auto implptr : m_impl_index ) { Impl& impl = *implptr; // TODO: What if there's two impls that match this combination? if( impl.def().matches(*out_params, trait, type) ) { if(out_impl) *out_impl = &impl; return true; } } DEBUG("No impl of " << trait << " for " << type); return false; } Function& Crate::lookup_method(const TypeRef& type, const char *name) { throw ParseError::Generic( FMT("TODO: Lookup method "<