diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | src/ast/ast.hpp | 3 | ||||
-rw-r--r-- | src/ast/crate.cpp | 22 | ||||
-rw-r--r-- | src/ast/crate.hpp | 1 | ||||
-rw-r--r-- | src/ast/provided_module.cpp | 59 | ||||
-rw-r--r-- | src/convert/ast_iterate.cpp | 552 | ||||
-rw-r--r-- | src/convert/ast_iterate.hpp | 80 | ||||
-rw-r--r-- | src/convert/decorators.cpp | 78 | ||||
-rw-r--r-- | src/convert/resolve.cpp | 1856 | ||||
-rw-r--r-- | src/convert/typecheck_bounds.cpp | 58 | ||||
-rw-r--r-- | src/convert/typecheck_expr.cpp | 609 | ||||
-rw-r--r-- | src/convert/typecheck_params.cpp | 344 | ||||
-rw-r--r-- | src/main.cpp | 8 |
13 files changed, 0 insertions, 3675 deletions
@@ -29,7 +29,6 @@ BIN := bin/mrustc$(EXESUF) OBJ := main.o macros.o types.o serialise.o OBJ += span.o rc_string.o OBJ += ast/ast.o ast/crate.o ast/path.o ast/expr.o ast/pattern.o -OBJ += ast/provided_module.o OBJ += parse/parseerror.o parse/lex.o parse/token.o OBJ += parse/root.o parse/paths.o parse/types.o parse/expr.o parse/pattern.o parse/macro_rules.o OBJ += expand/mod.o expand/macro_rules.o expand/cfg.o @@ -42,10 +41,6 @@ OBJ += hir/from_ast.o hir/from_ast_expr.o OBJ += hir/crate_ptr.o hir/type_ptr.o hir/expr_ptr.o OBJ += hir/type.o hir/path.o hir/expr.o OBJ += dump_as_rust.o -OBJ += convert/ast_iterate.o -#OBJ += convert/decorators.o -#OBJ += convert/resolve.o -OBJ += convert/typecheck_bounds.o convert/typecheck_params.o convert/typecheck_expr.o PCHS := ast/ast.hpp diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index b7601192..b7de73ac 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -713,8 +713,5 @@ public: }
};
-extern AST::Module g_compiler_module;
-extern void AST_InitProvidedModule();
-
#endif // AST_HPP_INCLUDED
diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp index 699bd288..d40879f3 100644 --- a/src/ast/crate.cpp +++ b/src/ast/crate.cpp @@ -45,28 +45,6 @@ void Crate::load_externs() 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) { diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp index a25d2480..dbb9ca0d 100644 --- a/src/ast/crate.hpp +++ b/src/ast/crate.hpp @@ -45,7 +45,6 @@ public: /// Load referenced crates void load_externs(); - void index_impls(); bool is_trait_implicit(const Path& trait) const; diff --git a/src/ast/provided_module.cpp b/src/ast/provided_module.cpp deleted file mode 100644 index e36784f0..00000000 --- a/src/ast/provided_module.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - */ -#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() -{ - // "struct str([u8])" - ::std::vector<AST::StructItem> fields; - fields.push_back( AST::StructItem(AST::MetaItems(), false, "", TypeRef(TypeRef::TagUnsizedArray(), Span(), TypeRef(Span(), CORETYPE_U8))) ); - g_compiler_module.add_struct(true, "str", AST::Struct(AST::GenericParams(), mv$(fields)), AST::MetaItems()); - - 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::GenericParams(), type, trait)) - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_U8)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_U16)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_U32)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_U64)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_UINT)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_I8)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_I16)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_I32)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_I64)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_INT)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_F32)); - impl(g_copy_marker_path, TypeRef(Span(), CORETYPE_F64)); - - // A hacky default impl of 'Sized', with a negative impl on [T] - impl(g_sized_marker_path, TypeRef()); - - { - AST::GenericParams tps; - tps.add_ty_param( AST::TypeParam("T") ); - g_compiler_module.add_neg_impl(AST::ImplDef( - AST::MetaItems(), ::std::move(tps), - g_sized_marker_path, - TypeRef(TypeRef::TagUnsizedArray(), Span(), TypeRef(TypeRef::TagArg(), "T")) - )); - } -} - diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp deleted file mode 100644 index 7e70f1f0..00000000 --- a/src/convert/ast_iterate.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/** - */ -#include "ast_iterate.hpp" -#include "../ast/ast.hpp" - -void CASTIterator::handle_path(AST::Path& path, CASTIterator::PathMode pm) -{ -} -void CASTIterator::handle_type(TypeRef& type) -{ - TRACE_FUNCTION_F("type = " << type); - - TU_MATCH(TypeData, (type.m_data), (ent), - (None), - (Any), - (Unit), - (Macro), - (Primitive), - (Path, - handle_path(ent.path, MODE_TYPE); - ), - (Tuple, - for(auto& subtype : ent.inner_types) - handle_type(subtype); - ), - (Borrow, - handle_type(*ent.inner); - ), - (Pointer, - handle_type(*ent.inner); - ), - (Array, - handle_type(*ent.inner); - ), - (Function, - handle_type(*ent.info.m_rettype); - for(auto& arg : ent.info.m_arg_types) - handle_type(arg); - ), - (Generic), - (TraitObject, - for(auto& trait : ent.traits) - handle_path(trait, MODE_TYPE); - ) - ) -} -void CASTIterator::handle_expr(AST::ExprNode& node) -{ -} -void CASTIterator::handle_params(AST::GenericParams& params) -{ - DEBUG("params"); - for( auto& param : params.ty_params() ) - { - handle_type(param.get_default()); - local_type( param.name(), TypeRef(TypeRef::TagArg(), param.name(), params) ); - } - DEBUG("Bounds"); - for( auto& bound : params.bounds() ) - { - TU_MATCH( AST::GenericBound, (bound), (ent), - (Lifetime, - DEBUG("namecheck lifetime bounds?"); - ), - (TypeLifetime, - handle_type(ent.type); - DEBUG("namecheck lifetime bounds?"); - ), - (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); - handle_type(ent.replacement); - ) - ) - } -} - - -void CASTIterator::start_scope() -{ - INDENT(); -} -void CASTIterator::local_type(::std::string name, TypeRef type) -{ - DEBUG("type " << name << " = " << type); -} -void CASTIterator::local_variable(bool is_mut, ::std::string name, const TypeRef& type) -{ - DEBUG( (is_mut ? "mut " : "") << name << " : " << type ); -} -void CASTIterator::local_use(::std::string name, AST::Path path) -{ - DEBUG( name << " = " << path ); -} -void CASTIterator::end_scope() -{ - UNINDENT(); -} - -void CASTIterator::handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) -{ - //DEBUG("pat = " << pat); - // Resolve names - TU_MATCH(AST::Pattern::Data, (pat.data()), (v), - (Any, - // Wildcard, nothing to do - ), - (Macro, - // Macro, nothing really (should be impossible?) - ), - (Box, { - auto& v = pat.data().as_Box(); - if( type_hint.is_wildcard() ) - handle_pattern(*v.sub, (const TypeRef&)TypeRef()); - else { - throw ::std::runtime_error("TODO: Handle box patterns in CASTIterator::handle_pattern"); - handle_pattern(*v.sub, type_hint.inner_type()); - } - }), - (Ref, { - auto& v = pat.data().as_Ref(); - if( type_hint.is_wildcard() ) - handle_pattern(*v.sub, (const TypeRef&)TypeRef()); - else if( !type_hint.is_reference() ) - throw ::std::runtime_error( FMT("Ref pattern on non-ref value: " << type_hint) ); - else - handle_pattern(*v.sub, type_hint.inner_type()); - }), - (MaybeBind, - throw ::std::runtime_error("Calling CASTIterator::handle_pattern on MAYBE_BIND, not valid"); - ), - (Value, - TU_IFLET(AST::Pattern::Value, v.start, Named, e, - handle_path(e, CASTIterator::MODE_TYPE); - ) - TU_IFLET(AST::Pattern::Value, v.end, Named, e, - handle_path(e, CASTIterator::MODE_TYPE); - ) - ), - (Tuple, { - auto& v = pat.data().as_Tuple(); - // Tuple is handled by subpattern code - if( type_hint.is_wildcard() ) - { - for( auto& sp : v.sub_patterns ) - handle_pattern(sp, (const TypeRef&)TypeRef()); - } - else if( !type_hint.is_tuple() ) - { - throw ::std::runtime_error("Tuple pattern on non-tuple value"); - } - else - { - const auto& inner_types = type_hint.m_data.as_Tuple().inner_types; - if( inner_types.size() != v.sub_patterns.size() ) - { - throw ::std::runtime_error("Tuple pattern count doesn't match"); - } - for( unsigned int i = 0; i < v.sub_patterns.size(); i ++ ) - { - handle_pattern(v.sub_patterns[i], inner_types[i]); - } - } - }), - (Struct, { - auto& v = pat.data().as_Struct(); - handle_path( v.path, CASTIterator::MODE_TYPE ); - if( type_hint.is_wildcard() ) - { - for( auto& sp : v.sub_patterns ) - handle_pattern(sp.second, (const TypeRef&)TypeRef()); - } - else if( !type_hint.is_path() ) - { - throw ::std::runtime_error("Tuple struct pattern on non-tuple value"); - } - else - { - auto& path = type_hint.m_data.as_Path().path; - if( path.is_bound() ) { - throw ::std::runtime_error("TODO: Typecheck/iterate struct pattern (with known type)"); - } - else { - for( auto& sp : v.sub_patterns ) - handle_pattern(sp.second, (const TypeRef&)TypeRef()); - } - } - }), - (StructTuple, { - auto& v = pat.data().as_StructTuple(); - // Resolve the path! - handle_path( v.path, CASTIterator::MODE_TYPE ); - // Handle sub-patterns - if( type_hint.is_wildcard() ) - { - for( auto& sp : v.sub_patterns ) - handle_pattern(sp, (const TypeRef&)TypeRef()); - } - else if( !type_hint.is_path() ) - { - throw ::std::runtime_error("Tuple struct pattern on non-tuple value"); - } - else - { - auto& hint_path = type_hint.path(); - auto& pat_path = v.path; - const auto& hint_binding = hint_path.binding(); - const auto& pat_binding = pat_path.binding(); - DEBUG("Pat: " << pat_path << ", Type: " << type_hint.path()); - TU_MATCH_DEF( AST::PathBinding, (hint_binding), (info), - ( - throw ::std::runtime_error(FMT("Bad type in tuple struct pattern : " << type_hint.path())) - ), - (Unbound, - throw ::std::runtime_error("Unbound path in pattern"); - ), - (Enum, - // The pattern's path must refer to a variant of the hint path - // - Actual type params are checked by the 'handle_pattern_enum' code - if( !pat_binding.is_EnumVar() ) - throw ::std::runtime_error(FMT("Paths in pattern are invalid")); - if( pat_binding.as_EnumVar().enum_ != info.enum_ ) - throw ::std::runtime_error(FMT("Paths in pattern are invalid")); - const auto& enm = *pat_binding.as_EnumVar().enum_; - auto idx = pat_binding.as_EnumVar().idx; - auto& var = enm.variants().at(idx); - handle_pattern_enum(pat_path[-2].args(), hint_path[-1].args(), enm.params(), var, v.sub_patterns); - ) - ) - } - }), - (Slice, - TypeRef null_type; - const auto* inner_type = &null_type; - if( !type_hint.is_wildcard() ) - { - TU_MATCH_DEF( TypeData, (type_hint.m_data), (v), - ( - ERROR(Span(), E0000, "Slice pattern on non-slice/array"); - ), - (Array, - inner_type = v.inner.get(); - ), - (Borrow, - if( v.inner->is_wildcard() ) { - } - else if( v.inner->m_data.is_Array() ) { - inner_type = v.inner->m_data.as_Array().inner.get(); - } - else { - // TODO: Deref more? - ERROR(Span(), E0000, "Slice pattern on non-slice/array"); - } - ) - ) - } - for( auto& sp : v.leading ) - handle_pattern(sp, *inner_type); - for( auto& sp : v.trailing ) - handle_pattern(sp, *inner_type); - ) - ) - // Extract bindings and add to namespace - if( pat.binding().size() > 0 ) - { - // TODO: Mutable bindings - if(pat.binding() != "_") - { - local_variable( false, pat.binding(), type_hint ); - } - } -} -void CASTIterator::handle_pattern_enum( - ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, - const AST::GenericParams& enum_params, const AST::EnumVariant& var, - ::std::vector<AST::Pattern>& sub_patterns - ) -{ - // This implementation doesn't attempt to do anything with types, just propagates _ - for( auto& sp : sub_patterns ) - handle_pattern(sp, (const TypeRef&)TypeRef()); -} - -void CASTIterator::handle_module(AST::Path path, AST::Module& mod) -{ - INDENT(); - start_scope(); - - for( auto& item : mod.items() ) - { - TU_MATCH(::AST::Item, (item.data), (e), - (None, - // Explicitly ignored (represents a deleted item) - ), - (Crate, - // Nothing to be done - ), - (Struct, - DEBUG("Handling struct " << item.name); - handle_struct(path + item.name, e); - ), - (Enum, - DEBUG("Handling enum " << item.name); - handle_enum(path + item.name, e); - ), - (Trait, - DEBUG("Handling trait " << item.name); - handle_trait(path + item.name, e); - ), - (Type, - DEBUG("Handling alias " << item.name); - handle_alias(path + item.name, e); - ), - (Static, - DEBUG("handling static " << item.name); - handle_type(e.type()); - if( e.value().is_valid() ) - { - handle_expr(e.value().node()); - } - ), - (Function, - DEBUG("Handling function '" << item.name << "'"); - handle_function(path + item.name, e); - ), - (Module, - // Skip, done after all items - ) - ) - } - - for( auto& impl : mod.impls() ) - { - DEBUG("Handling 'impl' " << impl); - handle_impl(path, impl); - } - - // End scope before handling sub-modules - end_scope(); - - for( auto& item : mod.items() ) - { - if(!item.data.is_Module()) continue; - auto& submod = item.data.as_Module(); - DEBUG("Handling submod '" << item.name << "'"); - handle_module(path + item.name, submod); - } - unsigned int anon_mod_idx = 0; - for( auto& anonmod : mod.anon_mods() ) - { - auto& submod = *anonmod; - DEBUG("Handling submod #" << anon_mod_idx); - handle_module(path + FMT("#" << anon_mod_idx), submod); - anon_mod_idx += 1; - } - UNINDENT(); -} -void CASTIterator::handle_function(AST::Path path, AST::Function& fcn) -{ - TRACE_FUNCTION_F("path = " << path << ", fcn.params() = " << fcn.params()); - start_scope(); - - DEBUG("params"); - handle_params(fcn.params()); - - DEBUG("ret type"); - handle_type(fcn.rettype()); - - //switch( fcn.fcn_class() ) - //{ - //case AST::Function::CLASS_UNBOUND: - // break; - //case AST::Function::CLASS_REFMETHOD: - // local_variable(false, "self", TypeRef(TypeRef::TagReference(), false, TypeRef(TypeRef::TagArg(), "Self"))); - // break; - //case AST::Function::CLASS_MUTMETHOD: - // local_variable(false, "self", TypeRef(TypeRef::TagReference(), true, TypeRef(TypeRef::TagArg(), "Self"))); - // break; - //case AST::Function::CLASS_VALMETHOD: - // local_variable(false, "self", TypeRef(TypeRef::TagArg(), "Self")); - // break; - //case AST::Function::CLASS_MUTVALMETHOD: - // local_variable(true, "self", TypeRef(TypeRef::TagArg(), "Self")); - // break; - //} - - DEBUG("args"); - for( auto& arg : fcn.args() ) - { - handle_type(arg.second); - // TODO: Check if pattern is irrefutable? - handle_pattern( arg.first, arg.second ); - } - - DEBUG("code"); - if( fcn.code().is_valid() ) - { - INDENT(); - handle_expr( fcn.code().node() ); - UNINDENT(); - } - - end_scope(); -} - -void CASTIterator::handle_impl_def(AST::ImplDef& impl) -{ - // 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 ); -} - -void CASTIterator::handle_impl(AST::Path modpath, AST::Impl& impl) -{ - start_scope(); - - handle_impl_def(impl.def()); - - // Associated types - for( auto& it : impl.items() ) - { - TU_MATCH_DEF(AST::Item, (it.data), (e), - ( - ), - (Type, - DEBUG("- Type '" << it.name << "'"); - handle_type( e.type() ); - ), - (Function, - DEBUG("- Function '" << it.name << "'"); - handle_function(AST::Path(AST::Path::TagRelative(), { AST::PathNode(it.name) }), e); - ) - ) - } - - pop_self(); - end_scope(); -} - -void CASTIterator::handle_struct(AST::Path path, AST::Struct& str) -{ - start_scope(); - handle_params( str.params() ); - TU_MATCH(AST::StructData, (str.m_data), (e), - (Tuple, - for( auto& f : e.ents ) - handle_type( f.m_type ); - ), - (Struct, - for( auto& f : e.ents ) - handle_type( f.m_type ); - ) - ) - end_scope(); -} -void CASTIterator::handle_enum(AST::Path path, AST::Enum& enm) -{ - start_scope(); - handle_params( enm.params() ); - for( auto& f : enm.variants() ) - { - TU_MATCH(AST::EnumVariantData, (f.m_data), (e), - (Value, - ), - (Tuple, - for( auto& t : e.m_sub_types ) - handle_type(t); - ), - (Struct, - for( auto& t : e.m_fields ) - handle_type(t.m_type); - ) - ) - } - end_scope(); -} -void CASTIterator::handle_trait(AST::Path path, AST::Trait& trait) -{ - start_scope(); - push_self(path, trait); - handle_params( trait.params() ); - - 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& i : trait.items() ) - { - TU_MATCH_DEF(AST::Item, (i.data), (e), - ( - ), - (Type, - // TODO: Can trait associated types have default types? - ), - (Static, - handle_type(e.type()); - ), - (Function, - handle_function( path + i.name, e ); - ) - ) - } - pop_self(); - end_scope(); -} -void CASTIterator::handle_alias(AST::Path path, AST::TypeAlias& alias) -{ - start_scope(); - handle_params( alias.params() ); - 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 deleted file mode 100644 index fc57cf57..00000000 --- a/src/convert/ast_iterate.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _AST_ITERATE_HPP_INCLUDED_ -#define _AST_ITERATE_HPP_INCLUDED_ - -#include <string> -#include "../types.hpp" -#include "../ast/path.hpp" - -namespace AST { - -class ExprNode; -class Pattern; -class GenericParams; -class Impl; -class ImplDef; -class EnumVariant; -template<typename T> struct Named; - -}; - -// Iterator for the AST, calls virtual functions on paths/types -class CASTIterator -{ -public: - enum PathMode { - MODE_EXPR, // Variables allowed - MODE_TYPE, - MODE_BIND, // Failure is allowed - }; - virtual void handle_path(AST::Path& path, PathMode mode); - virtual void handle_type(TypeRef& type); - virtual void handle_expr(AST::ExprNode& node); - - virtual void handle_params(AST::GenericParams& params); - - virtual void start_scope(); - virtual void local_type(::std::string name, TypeRef type); - virtual void local_variable(bool is_mut, ::std::string name, const TypeRef& type); - virtual void local_use(::std::string name, AST::Path path); - virtual void end_scope(); - - virtual void handle_pattern(AST::Pattern& pat, const TypeRef& type_hint); - virtual void handle_pattern_enum( - ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, - const AST::GenericParams& enum_params, const AST::EnumVariant& var, - ::std::vector<AST::Pattern>& sub_patterns - ); - - virtual void handle_module(AST::Path path, AST::Module& mod); - - virtual void handle_function(AST::Path path, AST::Function& fcn); - virtual void handle_impl(AST::Path modpath, AST::Impl& impl); - - virtual void handle_struct(AST::Path path, AST::Struct& str); - 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); -}; - -static inline ::std::ostream& operator<<(::std::ostream& os, const CASTIterator::PathMode& mode) { - switch(mode) - { - case CASTIterator::MODE_EXPR: return os << "MODE_EXPR"; - case CASTIterator::MODE_TYPE: return os << "MODE_TYPE"; - case CASTIterator::MODE_BIND: return os << "MODE_BIND"; - } - return os; -} - - - -#endif - diff --git a/src/convert/decorators.cpp b/src/convert/decorators.cpp deleted file mode 100644 index 06716e5f..00000000 --- a/src/convert/decorators.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * MRustC - Rust Compiler - * - By John Hodge (Mutabah/thePowersGang) - * - * convert/decorators.cpp - * - Handles #[...] item decorators by delegating - */ -#include "ast_iterate.hpp" -#include "../ast/ast.hpp" -#include "../ast/crate.hpp" -#include <main_bindings.hpp> -#include <unordered_map> // C++11, hashmap -#include <synext.hpp> - -::std::unordered_map< ::std::string, ::std::unique_ptr<CDecoratorHandler> > g_decorators; - -template<typename T> -void Decorator_Apply(AST::Crate& crate, AST::Module& mod, const AST::MetaItems& attrs, const AST::Path& path, T& ent) -{ - // For all attributes on the item, search for a handler and call handler - for( const auto& attr : attrs.m_items ) - { - 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 { - } - } -} - -class CProcessor: - public CASTIterator -{ - AST::Crate& m_crate; - ::std::vector<AST::Module*> m_modstack; -public: - CProcessor(AST::Crate& crate): - m_crate(crate) - {} - - void handle_module(AST::Path path, AST::Module& mod) override - { - m_modstack.push_back(&mod); - CASTIterator::handle_module(mv$(path), mod); - m_modstack.pop_back(); - } - - void handle_struct(AST::Path path, AST::Struct& str) override - { - 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); - } -}; - -void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<CDecoratorHandler> handler) -{ - auto res = g_decorators.insert( ::std::make_pair(name, mv$(handler)) ); - if( res.second == false ) - { - DEBUG("Duplicate definition of decorator '"<<name<<"'"); - } -} - -void Process_Decorators(AST::Crate& crate) -{ - CProcessor processor(crate); - - processor.handle_module(AST::Path("", {}), crate.root_module()); -} - diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp deleted file mode 100644 index a240c6fc..00000000 --- a/src/convert/resolve.cpp +++ /dev/null @@ -1,1856 +0,0 @@ -/*
- * "mrustc" Rust->C converter
- * - By John Hodge (Mutabah / thePowersGang)
- *
- * convert/resolve.cpp
- * - Resolve names into absolute format
- *
- * - Converts all paths into a canonical format (absolute, local, or UFCS)
- */
-#include "../common.hpp"
-#include "../ast/ast.hpp"
-#include "../ast/crate.hpp"
-#include "../parse/parseerror.hpp"
-#include "ast_iterate.hpp"
-
-// ====================================================================
-// -- Path resolver (converts paths to absolute form)
-// ====================================================================
-class CPathResolver:
- public CASTIterator
-{
- const AST::Crate& m_crate;
- AST::Module* m_module;
- AST::Path m_module_path;
- ::std::vector< ::std::pair<AST::Module*, AST::Path> > m_module_stack;
-
- struct LocalItem
- {
- enum Type {
- TYPE,
- VAR,
- } type;
- ::std::string name;
- TypeRef tr;
-
- LocalItem():
- type(VAR), name()
- {}
- LocalItem(Type t, ::std::string name, TypeRef tr=TypeRef()):
- type(t),
- name( ::std::move(name) ),
- tr( ::std::move(tr) )
- {}
-
- friend ::std::ostream& operator<<(::std::ostream& os, const LocalItem& x) {
- if( x.name == "" )
- return os << "#";
- else if( x.type == TYPE )
- return os << "type '" << x.name << "' = " << x.tr;
- else
- return os << "var '" << x.name << "'";
- }
- };
- ::std::vector< LocalItem > m_locals;
-
- struct Scope {
- unsigned int module_idx;
- AST::Module *module; // can be NULL
- AST::Path module_path;
- ::std::vector< ::std::string > locals;
-
- ::std::vector< ::std::pair<AST::Path, const AST::Trait&> > traits;
- };
- ::std::vector<Scope> m_scope_stack;
-
-
- TAGGED_UNION(SelfType, None,
- (None, struct {}),
- (Type, struct {
- TypeRef type;
- }),
- (Trait, struct {
- AST::Path path;
- const AST::Trait* trait;
- })
- );
- ::std::vector<SelfType> m_self_type;
-
- friend class CResolvePaths_NodeVisitor;
-
-public:
- bool m_second_pass = false;
-
- CPathResolver(const AST::Crate& crate);
-
- void handle_params(AST::GenericParams& params) override;
-
- virtual void handle_path(AST::Path& path, CASTIterator::PathMode mode) override;
- void handle_path_abs(const Span& span, AST::Path& path, CASTIterator::PathMode mode);
- void handle_path_abs__into_ufcs(const Span& span, AST::Path& path, unsigned slice_from, unsigned split_point);
- void handle_path_ufcs(const Span& span, AST::Path& path, CASTIterator::PathMode mode);
- void handle_path_rel(const Span& span, AST::Path& path, CASTIterator::PathMode mode);
- bool find_trait_item(const Span& span, const AST::Path& path, AST::Trait& trait, const ::std::string& item_name, bool& out_is_method, const void*& out_ptr, AST::Path& out_trait_path);
- virtual void handle_type(TypeRef& type) override;
- virtual void handle_expr(AST::ExprNode& node) override;
-
- virtual void handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) override;
- virtual void handle_module(AST::Path path, AST::Module& mod) override;
- virtual void handle_trait(AST::Path path, AST::Trait& trait) override;
- virtual void handle_function(AST::Path path, AST::Function& fcn) override;
-
- virtual void start_scope() override;
- virtual void local_type(::std::string name, TypeRef type) override {
- DEBUG("(name = " << name << ", type = " << type << ")");
- if( lookup_local(LocalItem::TYPE, name).is_some() ) {
- // Shadowing the type... check for recursion by doing a resolve check?
- type.resolve_args([&](const char *an){ if(an == name) return TypeRef(name+" "); else return TypeRef(an); });
- }
- m_locals.push_back( LocalItem(LocalItem::TYPE, ::std::move(name), ::std::move(type)) );
- }
- virtual void local_variable(bool _is_mut, ::std::string name, const TypeRef& _type) override {
- assert(m_scope_stack.size() > 0);
- m_scope_stack.back().locals.push_back( ::std::move(name) );
- }
- virtual void local_use(::std::string name, AST::Path path) override {
- assert( !path.binding().is_Unbound() );
- if( path.binding().is_Trait() ) {
- m_scope_stack.back().traits.push_back( ::std::pair<AST::Path, const AST::Trait&>(path, *path.binding().as_Trait().trait_) );
- }
- }
- virtual void end_scope() override;
-
- ::rust::option<const LocalItem&> lookup_local(LocalItem::Type type, const ::std::string& name) const;
-
- bool find_local_item(const Span& span, AST::Path& path, const ::std::string& name, bool allow_variables);
- //bool find_local_item(AST::Path& path, bool allow_variables);
- bool find_mod_item(const Span& span, AST::Path& path, const ::std::string& name);
- bool find_self_mod_item(const Span& span, AST::Path& path, const ::std::string& name);
- bool find_super_mod_item(const Span& span, 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 {
- // 'Self' must be resolved because ...
- //if( real_type.is_path() && real_type.path().binding().is_Unbound() ) {
- // assert( !"Unbound path passed to push_self" );
- //}
- 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(const Span& span, AST::Path& path, CASTIterator::PathMode mode);
-
- ::std::vector< ::std::pair<AST::Path, const AST::Trait&> > inscope_traits() const
- {
- ::std::vector< ::std::pair<AST::Path, const AST::Trait&> > ret;
- DEBUG("m_module_path = " << m_module_path);
- for( auto it = m_scope_stack.rbegin(); it != m_scope_stack.rend(); ++it )
- {
- for( const auto& t : it->traits ) {
- DEBUG("t = " << t.first);
- //assert(t.first.binding().is_Trait());
- ret.push_back(t);
- }
- if( it->module ) {
- for( const auto& i : it->module->items() ) {
- if( !i.data.is_Trait() ) continue ;
- const auto& t = i.data.as_Trait();
- auto trait_path = it->module_path + i.name;
- DEBUG("t = " << trait_path);
- ret.push_back( ::std::pair<AST::Path, const AST::Trait&>(trait_path, t) );
- }
- }
- }
-
- for( const auto& i : m_module->items() ) {
- if( !i.data.is_Trait() ) continue ;
- const auto& t = i.data.as_Trait();
- auto trait_path = m_module_path + i.name;
- DEBUG("(mod) t = " << trait_path);
- ret.push_back( ::std::pair<AST::Path, const AST::Trait&>(trait_path, t) );
- }
- for( const auto& i : m_module->imports() ) {
- if( i.data.path.binding().is_Trait() )
- {
- auto& t = *i.data.path.binding().as_Trait().trait_;
-
- DEBUG("(use) t = " << i.data);
- ::std::pair<AST::Path, const AST::Trait&> tr(i.data.path, t);
- ret.push_back( tr );
- }
- }
-
- return ret;
- }
-
-
-};
-
-// Path resolution checking
-void ResolvePaths(AST::Crate& crate);
-void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& modpath, AST::Module& mod);
-
-class CResolvePaths_NodeVisitor:
- public AST::NodeVisitorDef
-{
- CPathResolver& m_res;
-public:
- CResolvePaths_NodeVisitor(CPathResolver& res):
- m_res(res)
- {
- }
-
- void visit(AST::ExprNode_Macro& node) {
- BUG(node.get_pos(), "Un-resolved macro in expression");
-
- //MacroExpander expanded_macro = Macro_Invoke(node.m_name.c_str(), node.m_tokens);
- // TODO: Requires being able to replace the node with a completely different type of node
- //node.replace( Parse_Expr0(expanded_macro) );
- }
-
- void visit(AST::ExprNode_NamedValue& node) {
- DEBUG("ExprNode_NamedValue");
- m_res.handle_path(node.m_path, CASTIterator::MODE_EXPR);
- }
- void visit(AST::ExprNode_CallPath& node) {
- DEBUG(node.get_pos() << " ExprNode_CallPath - " << node);
- AST::NodeVisitorDef::visit(node);
- m_res.handle_path(node.m_path, CASTIterator::MODE_EXPR);
- }
-
- void visit(AST::ExprNode_Block& node) {
- // If there's an inner module on this node
- if( node.m_local_mod.get() )
- {
-
- // Add a reference to it to the parent node (add_anon_module will do dedup)
- AST::Module* parent_mod_p = m_res.m_module;
- for(const auto& e : m_res.m_scope_stack)
- if(e.module != nullptr)
- parent_mod_p = e.module;
- AST::Module& parent_mod = *parent_mod_p;
- auto idx = parent_mod.add_anon_module( node.m_local_mod.get() );
-
- // Obtain the path
- AST::Path local_path = m_res.m_module_path;
- for(const auto& e : m_res.m_scope_stack ) {
- if( e.module != nullptr ) {
- local_path.nodes().push_back( AST::PathNode( FMT("#" << e.module_idx), {} ) );
- }
- }
- local_path.nodes().push_back( AST::PathNode(FMT("#" << idx), {}) );
-
- // And add to the list of modules to use in lookup
- m_res.m_scope_stack.push_back( {idx, node.m_local_mod.get(), local_path, {}} );
-
- // Do use resolution on this module
- // TODO: When is more advanced resolution done?
- ResolvePaths_HandleModule_Use(m_res.m_crate, m_res.m_scope_stack.back().module_path, *node.m_local_mod);
- }
- else {
- m_res.m_scope_stack.push_back( {0, nullptr, AST::Path(), {}} );
- }
- AST::NodeVisitorDef::visit(node);
- // Once done, pop the module
- m_res.m_scope_stack.pop_back();
- }
-
- void visit(AST::ExprNode_IfLet& node)
- {
- DEBUG("ExprNode_IfLet");
- AST::NodeVisitor::visit(node.m_value);
-
- m_res.start_scope();
- m_res.handle_pattern(node.m_pattern, TypeRef());
- AST::NodeVisitor::visit(node.m_true);
- m_res.end_scope();
-
- AST::NodeVisitor::visit(node.m_false);
- }
-
- void visit(AST::ExprNode_Match& node)
- {
- DEBUG("ExprNode_Match");
- AST::NodeVisitor::visit(node.m_val);
-
- for( auto& arm : node.m_arms )
- {
- m_res.start_scope();
- for( auto& pat : arm.m_patterns )
- m_res.handle_pattern(pat, TypeRef());
- AST::NodeVisitor::visit(arm.m_cond);
- AST::NodeVisitor::visit(arm.m_code);
- m_res.end_scope();
- }
- }
-
- void visit(AST::ExprNode_Loop& node)
- {
- switch( node.m_type )
- {
- case AST::ExprNode_Loop::FOR:
- AST::NodeVisitor::visit(node.m_cond);
- m_res.start_scope();
- m_res.handle_pattern(node.m_pattern, TypeRef());
- AST::NodeVisitor::visit(node.m_code);
- m_res.end_scope();
- break;
- case AST::ExprNode_Loop::WHILELET:
- AST::NodeVisitor::visit(node.m_cond);
- m_res.start_scope();
- m_res.handle_pattern(node.m_pattern, TypeRef());
- AST::NodeVisitor::visit(node.m_code);
- m_res.end_scope();
- break;
- default:
- AST::NodeVisitorDef::visit(node);
- break;
- }
- }
-
- void visit(AST::ExprNode_LetBinding& node)
- {
- DEBUG("ExprNode_LetBinding");
-
- AST::NodeVisitor::visit(node.m_value);
- m_res.handle_type(node.m_type);
- m_res.handle_pattern(node.m_pat, TypeRef());
- }
-
- void visit(AST::ExprNode_StructLiteral& node) override
- {
- DEBUG("ExprNode_StructLiteral");
-
- m_res.handle_path(node.m_path, CASTIterator::MODE_EXPR);
- AST::NodeVisitorDef::visit(node);
- }
-
- void visit(AST::ExprNode_Closure& node) override
- {
- DEBUG("ExprNode_Closure");
- m_res.start_scope();
- for( auto& param : node.m_args )
- {
- DEBUG("- ExprNode_Closure: pat=" << param.first << ", ty=" << param.second);
- m_res.handle_type(param.second);
- m_res.handle_pattern(param.first, param.second);
- }
- DEBUG("- ExprNode_Closure: rt=" << node.m_return);
- m_res.handle_type(node.m_return);
- AST::NodeVisitor::visit(node.m_code);
- m_res.end_scope();
- }
-
- void visit(AST::ExprNode_Cast& node) override
- {
- DEBUG("ExprNode_Cast");
- m_res.handle_type(node.m_type);
- AST::NodeVisitorDef::visit(node);
- }
-
- void visit(AST::ExprNode_CallMethod& node) override
- {
- DEBUG("ExprNode_CallMethod");
- for( auto& arg : node.m_method.args() )
- m_res.handle_type(arg);
- AST::NodeVisitorDef::visit(node);
- }
-};
-
-/// Do simple path resolution on this path
-/// - Simple involves only doing item name lookups, no checks of generic params at all or handling UFCS
-void resolve_path(const Span& span, const AST::Crate& root_crate, AST::Path& path)
-{
- if( !path.is_absolute() ) {
- BUG(span, "Calling resolve_path on non-absolute path - " << path);
- }
- const AST::Module* mod = &root_crate.root_module();
- for(const auto& node : path.nodes() ) {
- if( node.args().size() > 0 ) {
- throw ParseError::Generic("Unexpected generic params in use path");
- }
- if( mod == nullptr ) {
- if( path.binding().is_Enum() ) {
- auto& enm = *path.binding().as_Enum().enum_;
- for(const auto& variant : enm.variants()) {
- if( variant.m_name == node.name() ) {
- path.bind_enum_var(enm, node.name());
- break;
- }
- }
- if( path.binding().is_Enum() ) {
- ERROR(span, E0000, "Unable to find component '" << node.name() << "' of import " << path << " (enum)" );
- }
- break;
- }
- else {
- throw ParseError::Generic("Extra path components after final item");
- }
- }
- auto item = mod->find_item(node.name());
- //while( item.is_None() && node.name()[0] == '#' ) {
- //}
- // HACK: Not actually a normal TU, but it fits the same pattern
- TU_MATCH(AST::Module::ItemRef, (item), (i),
- (None,
- ERROR(span, E0000, "Unable to find component '" << node.name() << "' of import " << path);
- ),
- (Module,
- mod = &i;
- ),
- (Crate,
- mod = &root_crate.get_root_module(i);
- ),
- (TypeAlias,
- path.bind_type_alias(i);
- mod = nullptr;
- ),
- (Function,
- path.bind_function(i);
- mod = nullptr;
- ),
- (Trait,
- path.bind_trait(i);
- mod = nullptr;
- ),
- (Struct,
- path.bind_struct(i);
- mod = nullptr;
- ),
- (Enum,
- // - Importing an enum item will be handled in the nullptr check above
- path.bind_enum(i);
- mod = nullptr;
- ),
- (Static,
- path.bind_static(i);
- mod = nullptr;
- ),
- (Use,
- if(i.name == "") {
- throw ParseError::Todo("Handle resolving to wildcard use in use resolution");
- }
- else {
- // Restart lookup using new path
- }
- )
- )
- }
- if( mod != nullptr ) {
- path.bind_module(*mod);
- }
-}
-
-CPathResolver::CPathResolver(const AST::Crate& crate):
- m_crate(crate),
- m_module(nullptr)
-{
-}
-void CPathResolver::start_scope()
-{
- DEBUG("");
- m_scope_stack.push_back( {0, nullptr, AST::Path(), {}} );
- m_locals.push_back( LocalItem() );
-}
-void CPathResolver::end_scope()
-{
- m_scope_stack.pop_back( );
- DEBUG(m_locals.size() << " items");
- for( auto it = m_locals.end(); it-- != m_locals.begin(); )
- {
- if( it->name == "" ) {
- m_locals.erase(it, m_locals.end());
- return ;
- }
- }
- m_locals.clear();
-}
-// Returns the bound path for the local item
-::rust::option<const CPathResolver::LocalItem&> CPathResolver::lookup_local(LocalItem::Type type, const ::std::string& src_name) const
-{
- DEBUG("m_locals = [" << m_locals << "]");
- ::std::string name = src_name;
- unsigned int count = 0;
- while( name.size() > 0 && name.back() == ' ') {
- name.pop_back();
- count ++;
- }
- for( auto it = m_locals.end(); it -- != m_locals.begin(); )
- {
- if( it->type == type )
- {
- if( it->name == name && count-- == 0 )
- return ::rust::option<const LocalItem&>(*it);
- }
- }
- return ::rust::option<const LocalItem&>();
-}
-
-// Search relative to current module
-// > Search local use definitions (function-level)
-// - TODO: Local use statements (scoped)
-// > Search module-level definitions
-bool lookup_path_in_module(const Span& span, const AST::Crate& crate, const AST::Module& module, const AST::Path& mod_path, AST::Path& path, const ::std::string& name, bool is_leaf)
-{
- TRACE_FUNCTION_F("mod_path="<<mod_path);
- // - Allow leaf nodes if path is a single node, don't skip private wildcard imports
- auto item = module.find_item(name, is_leaf, false);
- TU_MATCH_DEF(AST::Module::ItemRef, (item), (i),
- (
- path = mod_path + path;
- //path.resolve( crate );
- return true;
- ),
- (None,
- return false;
- ),
- (Use,
- const auto& imp = i;
- if( imp.name == "" )
- {
- DEBUG("Wildcard import found, " << imp.data << " + " << path);
- // Wildcard path, prefix entirely with the path
- path = imp.data.path + path;
- //path.resolve( crate );
- return true;
- }
- else
- {
- DEBUG("Named import found, " << imp.data << " + " << path << " [1..]");
- path = AST::Path::add_tailing(imp.data.path, path);
- //path.resolve( crate );
- return true;
- }
- return false;
- ),
- (Module,
- // Check name down?
- // Add current module path
- path = mod_path + path;
- //path.resolve( crate );
- return true;
- )
- )
- assert(!"");
-}
-bool lookup_path_in_module(const Span &span, const AST::Crate& crate, const AST::Module& module, const AST::Path& mod_path, AST::Path& path) {
- return lookup_path_in_module(span, crate, module, mod_path, path, path[0].name(), path.size() == 1);
-}
-
-/// Perform path resolution within a generic definition block
-void CPathResolver::handle_params(AST::GenericParams& params)
-{
- TRACE_FUNCTION;
- // Parameters
- DEBUG("params");
- for( auto& param : params.ty_params() )
- {
- // - Resolve the default type
- handle_type(param.get_default());
- // - Register each param as a type name within this scope
- local_type( param.name(), TypeRef(TypeRef::TagArg(), param.name(), params) );
- }
- DEBUG("Bounds");
- for( auto& bound : params.bounds() )
- {
- DEBUG("- Bound " << bound);
-
- TU_MATCH(AST::GenericBound, (bound), (ent),
- (Lifetime,
- {}
- ),
- (TypeLifetime,
- handle_type(ent.type);
- ),
- (IsTrait,
- handle_type(ent.type);
- // TODO: Should 'Self' in this trait be ent.type?
-
- //if(ent.type.is_path() && ent.type.path().binding().is_Unbound())
- // BUG(span, "Unbound path after handle_type in handle_params - ent.type=" << ent.type);
- push_self(ent.type);
- handle_path(ent.trait, MODE_TYPE);
- pop_self();
- ),
- (MaybeTrait,
- handle_type(ent.type);
- push_self();
- handle_path(ent.trait, MODE_TYPE);
- pop_self();
- ),
- (NotTrait,
- handle_type(ent.type);
- push_self();
- handle_path(ent.trait, MODE_TYPE);
- pop_self();
- ),
- (Equality,
- handle_type(ent.type);
- handle_type(ent.replacement);
- )
- )
- }
-}
-
-/// Resolve names within a path
-void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode)
-{
- const Span span = Span();
- TRACE_FUNCTION_F("(path = " << path << ", mode = "<<mode<<"), m_module_path = " << m_module_path);
-
- handle_path_int(span, path, mode);
-
- // Handle generic components of the path
- // - Done AFTER resoltion, as binding might introduce defaults (which may not have been resolved)
- TU_MATCH(AST::Path::Class, (path.m_class), (info),
- (Invalid),
- (Local),
- (Relative,
- DEBUG("Relative path after handle_path_int - path=" << path);
- assert( !"Relative path after handle_path_int");
- ),
- (Self,
- assert( !"Relative (self) path after handle_path_int");
- ),
- (Super,
- assert( !"Relative (super) path after handle_path_int");
- ),
- (Absolute,
- if( path.binding().is_Unbound() ) {
- BUG(span, "Path wasn't bound after handle_path - path=" << path);
- }
- for( auto& ent : info.nodes )
- for( auto& arg : ent.args() )
- handle_type(arg);
- ),
- (UFCS,
- handle_type(*info.type);
- handle_type(*info.trait);
- for( auto& ent : info.nodes )
- for( auto& arg : ent.args() )
- handle_type(arg);
- )
- )
-}
-
-void CPathResolver::handle_path_int(const Span& span, 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() )
- {
- case AST::Path::Class::TAG_Invalid:
- // TODO: Throw an error
- assert( !path.m_class.is_Invalid() );
- return;
- // --- Already absolute forms
- // > Absolute: Resolve
- case AST::Path::Class::TAG_Absolute:
- DEBUG("Absolute - binding");
- INDENT();
- handle_path_abs(span, path, mode);
- // TODO: Move Path::resolve() to this file
- // Already absolute, our job is done
- // - However, if the path isn't bound, bind it
- if( path.binding().is_Unbound() ) {
- //path.resolve(m_crate);
- }
- else {
- DEBUG("- Path " << path << " already bound");
- }
- UNINDENT();
- break;
- // > UFCS: Resolve the type and trait
- case AST::Path::Class::TAG_UFCS:
- handle_path_ufcs(span, path, mode);
- break;
- // > Variable: (wait, how is this known already?)
- // - 'self', 'Self'
- case AST::Path::Class::TAG_Local:
- DEBUG("Check local");
- if( !path.binding().is_Unbound() )
- {
- DEBUG("- Path " << path << " already bound");
- }
- else
- {
- const auto& info = path.m_class.as_Local();
- // 1. Check for local items
- if( this->find_local_item(span, path, info.name, (mode == CASTIterator::MODE_EXPR)) ) {
- if( path.is_absolute() ) {
- handle_path_abs(span, path, mode);
- }
- break ;
- }
- else {
- // No match, fall through
- }
- // 2. Type parameters (ONLY when in type mode)
- if( mode == CASTIterator::MODE_TYPE ) {
- throw ::std::runtime_error("TODO: Local in CPathResolver::handle_path_int type param");
- }
- // 3. Module items
- if( this->find_mod_item(span, path, info.name) ) {
- handle_path_abs(span, path, mode);
- break;
- }
- else {
- }
-
- DEBUG("no matches found for path = " << path);
- if( mode != MODE_BIND )
- throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed (Local)");
- return ;
- }
- if(0)
-
- // Unannotated relative
- case AST::Path::Class::TAG_Relative:
- handle_path_rel(span, path, mode);
- if(0)
-
- // Module relative
- case AST::Path::Class::TAG_Self:
- {
- if( this->find_self_mod_item(span, path, path[0].name()) ) {
- // Fall
- }
- else {
- DEBUG("no matches found for path = " << path);
- if( mode != MODE_BIND )
- throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed");
- }
- }
- if(0)
- // Parent module relative
- // TODO: "super::" can be chained
- case AST::Path::Class::TAG_Super:
- {
- if( this->find_super_mod_item(span, path, path[0].name()) ) {
- // Fall
- }
- else {
- DEBUG("no matches found for path = " << path);
- if( mode != MODE_BIND )
- throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed");
- }
- }
- // Common for Relative, Self, and Super
- DEBUG("Post relative resolve - path=" << path);
- if( path.is_absolute() ) {
- handle_path_abs(span, path, mode);
- }
- else {
- }
- return ;
- }
-
- // TODO: Are there any reasons not to be bound at this point?
- //assert( !path.binding().is_Unbound() );
-}
-
-// Validates all components are able to be located, and converts Trait/Struct/Enum::Item into UFCS format
-void CPathResolver::handle_path_abs(const Span& span, AST::Path& path, CASTIterator::PathMode mode)
-{
- //bool expect_params = false;
-
- if( !path.m_class.is_Absolute() ) {
- BUG(span, "Non-absolute path passed to CPathResolver::handle_path_abs - path=" << path);
- }
-
- auto& nodes = path.m_class.as_Absolute().nodes;
-
- unsigned int slice_from = 0; // Used when rewriting the path to be relative to its crate root
-
- // Iterate through nodes, starting at the root module of the specified crate
- // - Locate the referenced item, and fail if any component isn't found
- ::std::vector<const AST::Module*> mod_stack;
- const AST::Module* mod = &this->m_crate.get_root_module(path.crate());
- for(unsigned int i = 0; i < nodes.size(); i ++ )
- {
- mod_stack.push_back(mod);
- const bool is_last = (i+1 == nodes.size());
- const AST::PathNode& node = nodes[i];
- DEBUG("[" << i << "/"<<nodes.size()<<"]: " << node);
-
- if( node.name()[0] == '#' )
- {
- // HACK - Compiler-provided functions/types live in the special '#' module
- if( node.name() == "#" ) {
- if( i != 0 )
- throw ParseError::BugCheck("# module not at path root");
- mod = &g_compiler_module;
- continue ;
- }
-
- // Hacky special case - Anon modules are indexed
- // - Darn you C++ and no string views
- unsigned int index = ::std::strtoul(node.name().c_str()+1, nullptr, 10); // Parse the number at +1
- DEBUG(" index = " << index);
- if( index >= mod->anon_mods().size() )
- throw ParseError::Generic("Anon module index out of range");
- mod = mod->anon_mods().at(index);
- continue ;
- }
-
- auto item_ref = mod->find_item(node.name(), is_last); // Only allow leaf nodes (functions and statics) if this is the last node
- TU_MATCH( AST::Module::ItemRef, (item_ref), (item),
- // Not found
- (None,
- // If parent node is anon, backtrack and try again
- // TODO: I feel like this shouldn't be done here, instead perform this when absolutising (now that find_item is reusable)
- if( i > 0 && nodes[i-1].name()[0] == '#' && nodes[i-1].name().size() > 1 )
- {
- i --;
- mod_stack.pop_back();
- mod = mod_stack.back();
- mod_stack.pop_back();
- nodes.erase(nodes.begin()+i);
- i --;
- DEBUG("Failed to locate item in nested, look upwards");
-
- continue ;
- }
- ERROR(span, E0000, "Unable to find component '" << node.name() << "' of path " << path);
- ),
- // Sub-module
- (Module,
- DEBUG("Sub-module : " << node.name());
- if( node.args().size() )
- throw ParseError::Generic("Generic params applied to module");
- mod = &item;
- ),
- // Crate
- (Crate,
- const ::std::string& crate_name = item;
- DEBUG("Extern crate '" << node.name() << "' = '" << crate_name << "'");
- if( node.args().size() )
- throw ParseError::Generic("Generic params applied to extern crate");
- path.set_crate( crate_name );
- slice_from = i+1;
- mod = &this->m_crate.get_root_module(crate_name);
- ),
-
- // Type Alias
- (TypeAlias,
- const auto& ta = item;
- DEBUG("Type alias <"<<ta.params()<<"> " << ta.type());
- //if( node.args().size() != ta.params().size() )
- // throw ParseError::Generic("Param count mismatch when referencing type alias");
- // Make a copy of the path, replace params with it, then replace *this?
- // - Maybe leave that up to other code?
- if( is_last ) {
- //check_param_counts(ta.params(), expect_params, nodes[i]);
- // TODO: Bind / replace
- // - Replacing requires checking type params (well, at least the count)
- path.bind_type_alias(ta);
- goto ret;
- }
- else {
- this->handle_path_abs__into_ufcs(span, path, slice_from, i+1);
- this->handle_path_ufcs(span, path, mode);
- // Explicit return - rebase slicing is already done
- return ;
- }
- ),
-
- // Function
- (Function,
- const auto& fn = item;
- DEBUG("Found function");
- if( is_last ) {
- //check_param_counts(fn.params(), expect_params, nodes[i]);
- path.bind_function(fn);
- goto ret;
- }
- else {
- throw ParseError::Generic("Import of function, too many extra nodes");
- }
- ),
-
- // Trait
- (Trait,
- const auto& t = item;
- DEBUG("Found trait");
- auto& node_args = nodes[i].args();
- if( mode == MODE_TYPE )
- {
- const auto& params = t.params();
- if( params.ty_params().size() != node_args.size() )
- {
- if( node_args.size() == 0 )
- {
- while( node_args.size() < params.ty_params().size() )
- node_args.push_back( params.ty_params()[node_args.size()].get_default() );
- }
- else
- {
- ERROR(span, E0000, "Incorrect number of type parameters");
- }
- }
- }
- if( is_last ) {
- //check_param_counts(t.params(), expect_params, nodes[i]);
- path.bind_trait(t);
- goto ret;
- }
- else {
- this->handle_path_abs__into_ufcs(span, path, slice_from, i+1);
- this->handle_path_ufcs(span, path, mode);
- // Explicit return - rebase slicing is already done
- return ;
- }
- ),
-
- // Struct
- (Struct,
- const auto& str = item;
- DEBUG("Found struct");
- auto& node_args = nodes[i].args();
- if( mode == MODE_TYPE )
- {
- if( str.params().ty_params().size() != node_args.size() )
- {
- if( node_args.size() == 0 )
- {
- while( node_args.size() < str.params().ty_params().size() )
- node_args.push_back( str.params().ty_params()[node_args.size()].get_default() );
- }
- else
- {
- ERROR(span, E0000, "Incorrect number of type parameters");
- }
- }
- }
- if( is_last ) {
- //check_param_counts(str.params(), expect_params, nodes[i]);
- path.bind_struct(str, node.args());
- goto ret;
- }
- else {
- this->handle_path_abs__into_ufcs(span, path, slice_from, i+1);
- this->handle_path_ufcs(span, path, mode);
- // Explicit return - rebase slicing is already done
- return ;
- }
- ),
-
- // Enum / enum variant
- (Enum,
- const auto& enm = item;
- DEBUG("Found enum");
- if( is_last ) {
- //check_param_counts(enm.params(), expect_params, nodes[i]);
- path.bind_enum(enm, node.args());
- goto ret;
- }
- else {
- this->handle_path_abs__into_ufcs(span, path, slice_from, i+1);
- this->handle_path_ufcs(span, path, mode);
- // Explicit return - rebase slicing is already done
- return ;
- }
- ),
-
- (Static,
- const auto& st = item;
- DEBUG("Found static/const");
- if( is_last ) {
- if( node.args().size() )
- throw ParseError::Generic("Unexpected generic params on static/const");
- path.bind_static(st);
- goto ret;
- }
- else {
- throw ParseError::Generic("Binding path to static, trailing nodes");
- }
- ),
-
- // Re-export
- (Use,
- const auto& imp = item;
- AST::Path newpath = imp.data.path;
- auto& newnodes = newpath.m_class.as_Absolute().nodes;
- DEBUG("Re-exported path " << imp.data);
- if( imp.name == "" )
- {
- // Replace nodes 0:i-1 with source path, then recurse
- for( unsigned int j = i; j < nodes.size(); j ++ )
- {
- newnodes.push_back( nodes[j] );
- }
- }
- else
- {
- // replace nodes 0:i with the source path
- for( unsigned int j = i+1; j < nodes.size(); j ++ )
- {
- newnodes.push_back( nodes[j] );
- }
- }
-
- DEBUG("- newpath = " << newpath);
- // TODO: This should check for recursion somehow
- this->handle_path_abs(span, newpath, mode);
-
- path = mv$(newpath);
- return;
- )
- )
- }
-
- // We only reach here if the path points to a module
- path.bind_module( *mod );
-ret:
- if( slice_from > 0 )
- {
- DEBUG("Removing " << slice_from << " nodes to rebase path to crate root");
- nodes.erase(nodes.begin(), nodes.begin()+slice_from);
- }
- return ;
-}
-// Starting from the `slice_from`th element, take until `split_point` as the type path, and the rest of the nodes as UFCS items
-void CPathResolver::handle_path_abs__into_ufcs(const Span& span, AST::Path& path, unsigned slice_from, unsigned split_point)
-{
- TRACE_FUNCTION_F("(path = " << path << ", slice_from=" << slice_from << ", split_point=" << split_point << ")");
- assert(slice_from < path.size());
- assert(slice_from < split_point);
- // Split point must be at most the last index
- assert(split_point < path.size());
-
- const auto& nodes = path.nodes();
- AST::Path type_path(path.crate(), ::std::vector<AST::PathNode>( nodes.begin() + slice_from, nodes.begin() + split_point ));
- for(unsigned i = split_point; i < nodes.size(); i ++)
- {
- DEBUG("type_path = " << type_path << ", nodes[i] = " << nodes[i]);
- resolve_path(span, m_crate, type_path);
- // If the type path refers to a trait, put it in the trait location
- if(type_path.binding().is_Trait()) {
- type_path = AST::Path(AST::Path::TagUfcs(), TypeRef(span), TypeRef(span, mv$(type_path)), {mv$(nodes[i])} );
- }
- else {
- type_path = AST::Path(AST::Path::TagUfcs(), TypeRef(span, mv$(type_path)), TypeRef(span), {mv$(nodes[i])} );
- }
- }
-
- path = mv$(type_path);
-}
-
-
-/// Handles path resolution for UFCS format paths (<Type as Trait>::Item)
-void CPathResolver::handle_path_ufcs(const Span& span, AST::Path& path, CASTIterator::PathMode mode)
-{
- assert(path.m_class.is_UFCS());
- auto& info = path.m_class.as_UFCS();
- TRACE_FUNCTION_F("info={< " << *info.type << " as " << *info.trait << ">::" << info.nodes << "}");
- // 1. Handle sub-types
- handle_type(*info.type);
- handle_type(*info.trait);
-
- // - Some quick assertions
- if( info.type->is_path() )
- {
- TU_MATCH_DEF(AST::PathBinding, (info.type->path().binding()), (i),
- (
- // Invalid
- BUG(span, "Invalid item class for type in path " << path);
- ),
- //(Unbound,
- // ),
- //(Trait, ),
- (Struct, ),
- (Enum, )
- )
- }
-
- // 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
- // - Impl heads and trait heads could be resolved in an earlier pass
- if( info.trait->is_wildcard() )
- {
- // 1. Search inherent impls
- // 2. If doing a late pass (after module-level names are resolved) search for traits
- if( this->m_second_pass ) {
- #if 1
- const ::std::string& item_name = info.nodes[0].name();
- DEBUG("Searching for matching trait for '"<<item_name<<"' on type " << *info.type);
-
- // Search applicable type parameters for known implementations
-
- // 1. Inherent
- //AST::Impl* impl_ptr;
- ::std::vector<TypeRef> 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)
- 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<AST::Trait*>(m_self_type.back().as_Trait().trait);
-
- bool is_method;
- const void* ptr;
- AST::Path found_trait_path;
- if( this->find_trait_item(span, p, t, item_name, is_method, ptr, found_trait_path) ) {
- if( is_method ) {
- if( info.nodes.size() != 1 )
- ERROR(span, E0000, "CPathResolver::handle_path_ufcs - Sub-nodes to method");
- auto f = reinterpret_cast<const ::AST::Function*>(ptr);
- path.bind_function(*f, path.nodes()[0].args());
- }
- else {
- if( info.nodes.size() != 1 )
- TODO(span, "CPathResolver::handle_path_ufcs - Sub nodes on associated type");
- auto t = reinterpret_cast<const ::AST::TypeAlias*>(ptr);
- path.bind_type_alias(*t);
- }
- *info.trait = TypeRef( span, mv$(found_trait_path) );
- }
- else {
- ERROR(span, E0000, "Cannot find item '" << item_name << "' on Self");
- }
- }
- else if( info.type->is_type_param() )
- {
- #if 0
- DEBUG("Checking applicable generic bounds");
- const auto& tp = *info.type->type_params_ptr();
- assert(&tp != nullptr);
- bool success = false;
-
- // Enumerate bounds
- for( const auto& bound : tp.bounds() )
- {
- DEBUG("bound = " << bound);
- TU_MATCH_DEF(AST::GenericBound, (bound), (ent),
- (),
- (IsTrait,
- if( ent.type == *info.type ) {
- auto& t = *const_cast<AST::Trait*>(ent.trait.binding().as_Trait().trait_);
- DEBUG("Type match, t.params() = " << t.params());
- bool is_method;
- AST::Path found_trait_path;
- DEBUG("find_trait_item(" << ent.trait << /*", t=" << t <<*/ ", item_name = " << item_name);
- if( this->find_trait_item(span, ent.trait, t, item_name, is_method, found_trait_path) )
- {
- if( is_method ) {
- if( info.nodes.size() != 1 )
- throw ParseError::Generic("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) );
- success = true;
- break ;
- }
- }
- else {
- DEBUG("Type mismatch " << ent.type << " != " << *info.type);
- }
- )
- )
- }
-
- if( !success )
- throw ParseError::Todo( FMT("CPathResolver::handle_path_ufcs - UFCS, find trait for generic matching '" << item_name << "'") );
- // - re-handle, to ensure that the bound is resolved
- handle_type(*info.trait);
- #endif
- }
- else
- {
- const auto& name = path.nodes()[0].name();
- DEBUG("(maybe) known type");
- // Iterate all inherent impls
- DEBUG("Searching for inherent impls on " << *info.type);
- bool found = m_crate.find_inherent_impls( *info.type, [&](const AST::Impl& impl, ::std::vector<TypeRef> _) -> bool {
- DEBUG("Searching impl " << impl);
- for( const auto& i : impl.items() )
- {
- if( i.name == name ) {
- TU_MATCH_DEF(AST::Item, (i.data), (e),
- (
- // Ignore?
- ),
- (Function,
- path.bind_function(e, path.nodes()[0].args());
- info.trait = make_unique_ptr( TypeRef(TypeRef::TagInvalid(), span) );
- return true;
- )
- )
- }
- }
- return false;
- });
- if( found )
- return ;
-
- DEBUG("Searching traits");
- // Iterate all traits in scope, and find one that is implemented for this type
- // - TODO: Iterate traits to find match for <Type as _>
- for( const auto& trait_ref : this->inscope_traits() )
- {
- const auto& trait_p = trait_ref.first;
- const auto& trait = trait_ref.second;
- DEBUG("Searching trait: " << trait_p);
- bool is_fcn;
- if( trait.has_named_item(item_name, is_fcn) ) {
- IF_OPTION_SOME(impl, m_crate.find_impl( trait_p, *info.type ),
- *info.trait = TypeRef( span, trait_p );
- return ;
- )
- }
- }
-
- TODO(span, "CPathResolver::handle_path_ufcs - UFCS, find trait, for type " << *info.type << " - name='"<<name<<"'");
- }
- #endif
- }
- else
- {
- const auto& name = path.nodes()[0].name();
- if( info.type->is_path() )
- {
- // 1. Search for enum constructors
- TU_MATCH_DEF(AST::PathBinding, (info.type->path().binding()), (i),
- ( ),
- (Enum,
- const auto& e = *i.enum_;
- for(const auto& var : e.variants())
- {
- if( var.m_name == name ) {
- path.bind_enum_var(e, name);
- info.trait = make_unique_ptr( TypeRef(TypeRef::TagInvalid(), span) );
- return ;
- }
- }
- )
- )
- }
- }
- }
- else
- {
- #if 0
- const auto& name = path.nodes()[0].name();
- // Trait is known, need to ensure that the named item exists
- assert(info.trait->path().binding().is_Trait());
- const auto &tr = *info.trait->path().binding().as_Trait().trait_;
-
- // TODO: Need to try super-traits AND applicable type impls
- // - E.g. "impl Any {"
- switch(mode)
- {
- case MODE_EXPR:
- for( const auto& fcn : tr.functions() )
- {
- DEBUG("fcn.name = " << fcn.name);
- if(fcn.name == name) {
- path.bind_function(fcn.data);
- break;
- }
- }
- //for( const auto& fcn : tr.constants() )
- //{
- //}
- break;
- case MODE_BIND:
- //for( const auto& fcn : tr.constants() )
- //{
- //}
- break;
- case MODE_TYPE:
- for( const auto& it : tr.types() )
- {
- if(it.name == name) {
- path.bind_type_alias(it.data);
- break;
- }
- }
- break;
- }
- if(mode == MODE_EXPR && path.binding().is_Unbound()) {
- // TODO: Locate an 'impl Trait' block for methods
- }
- if(path.binding().is_Unbound()) {
- ERROR(span, E0000, "Unable to locate item '" << name << "' in trait " << *info.trait << " (mode=" << mode << ")");
- }
- #endif
- }
-}
-void CPathResolver::handle_path_rel(const Span& span, AST::Path& path, CASTIterator::PathMode mode)
-{
- // 1. function scopes (variables and local items)
- // > Return values: name or path
- {
- bool allow_variables = (mode == CASTIterator::MODE_EXPR && path.is_trivial());
- if( this->find_local_item(span, path, path[0].name(), allow_variables) ) {
- return ;
- }
- }
-
- // 2. Type parameters
- // - Should probably check if this is expression mode, bare types are invalid there
- // NOTES:
- // - If the path is bare (i.e. there are no more nodes), then ensure that the mode is TYPE
- // - If there are more nodes, replace with a UFCS block
- {
- auto tp = this->find_type_param(path[0].name());
- if( tp != false /*nullptr*/ || path[0].name() == "Self" )
- {
- if(path.size() > 1) {
- auto ty = TypeRef(TypeRef::TagArg(), path[0].name());
- //ty.set_span( path.span() );
- // Repalce with UFCS
- auto newpath = AST::Path(AST::Path::TagUfcs(), ty, TypeRef());
- newpath.add_tailing(path);
- path = mv$(newpath);
- }
- else {
- // Mark as local
- // - TODO: Not being trivial is an error, not a bug
- assert( path.is_trivial() );
- path = AST::Path(AST::Path::TagLocal(), path[0].name());
- // - TODO: Need to bind this to the source parameter block
- }
- return ;
- }
- }
-
- // 3. current module
- {
- if( this->find_mod_item(span, path, path[0].name()) ) {
- return ;
- }
- else {
- }
- }
-
- // 4. If there was no match above, and we're in bind mode, set the path to local and return
- DEBUG("no matches found for path = " << path);
- if( mode == MODE_BIND )
- {
- // If mode == MODE_BIND, must be trivial
- if( !path.is_trivial() )
- throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed (non-trivial path failed to resolve in MODE_BIND)");
- path = AST::Path(AST::Path::TagLocal(), path[0].name());
- return ;
- }
-
- // 5. Check if the unresolved name is a primitive type
- {
- if( path[0].name() == "str" ) {
- TODO(span, "Expand `str` to internal path");
- }
- else if( auto ct = coretype_fromstring(path[0].name()) ) {
- auto ty = TypeRef(TypeRef::TagPrimitive(), span, ct);
- auto newpath = AST::Path(AST::Path::TagUfcs(), ty, TypeRef());
- newpath.add_tailing(path);
- path = mv$(newpath);
- return ;
- }
- else {
- }
- }
-
- // Z. Otherwise, error
- ERROR(span, E0000, "CPathResolver::handle_path - Name resolution failed");
-}
-
-bool CPathResolver::find_trait_item(const Span& span, const AST::Path& path, AST::Trait& trait, const ::std::string& item_name, bool& out_is_method, const void*& out_ptr, AST::Path& out_trait_path)
-{
- TRACE_FUNCTION_F("path=" << path << ", trait=..., item_name=" << item_name);
- {
- const auto& items = trait.items();
- auto it = ::std::find_if( items.begin(), items.end(), [&](const auto& a) { DEBUG("fcn " << a.name); return a.name == item_name; } );
- if( it != items.end() ) {
- // Found it.
- const auto& i = *it;
- TU_MATCH_DEF(AST::Item, (i.data), (e),
- (
- BUG(Span(), "Unknown item type in trait");
- ),
- (Function,
- out_is_method = true;
- out_ptr = &e;
- out_trait_path = AST::Path(path);
- DEBUG("Fcn, out_trait_path = " << out_trait_path);
- return true;
- ),
- (Type,
- out_is_method = false;
- out_ptr = &it->data;
- out_trait_path = AST::Path(path);
- DEBUG("Ty, out_trait_path = " << out_trait_path << " path=" << path);
- return true;
- ),
- (Static,
- TODO(Span(), "Handle resolving associated statics/consts in traits (CPathResolver::find_trait_item)");
- )
- )
- }
- }
-
- for( auto& st : trait.supertraits() ) {
- if(!st.is_bound()) {
- handle_path(st, MODE_TYPE);
- //BUG(st.span(), "Supertrait path '"<<st<<"' of '"<<path<<"' is not bound");
- }
- AST::Trait& super_t = *const_cast<AST::Trait*>(st.binding().as_Trait().trait_);
- if( this->find_trait_item(span, st, super_t, item_name, out_is_method, out_ptr, 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) -> TypeRef {
- int idx = trait.params().find_name(name);
- if(idx < 0)
- ERROR(span, E0000, "Parameter " << name << " not found");
- if(static_cast<unsigned int>(idx) >= path.nodes().back().args().size())
- ERROR(span, E0000, "Path '"<<path<<"' had too few args");
- const auto& tr = path.nodes().back().args().at(idx);
- DEBUG("Replacing '" << name << "' with " << tr);
- return tr;
- });
- return true;
- }
- }
-
- return false;
-}
-
-bool CPathResolver::find_local_item(const Span& span, AST::Path& path, const ::std::string& name, bool allow_variables)
-{
- TRACE_FUNCTION_F("path="<<path<<", allow_variables="<<allow_variables);
- // Search current scopes for a name
- // - This should search both the expression stack
- // - and the scope's module (if any)
- for(auto it = m_scope_stack.rbegin(); it != m_scope_stack.rend(); ++it)
- {
- const auto& s = *it;
- if( allow_variables )
- {
- for( auto it2 = s.locals.rbegin(); it2 != s.locals.rend(); ++it2 )
- {
- if( *it2 == name ) {
- path = AST::Path(AST::Path::TagLocal(), name);
- path.bind_variable(0);
- return true;
- }
- }
- }
- if( s.module != nullptr )
- {
- DEBUG("- Looking in sub-module '" << s.module_path << "'");
- if( lookup_path_in_module(span, m_crate, *s.module, s.module_path, path, name, path.is_trivial()) )
- return true;
- }
- }
- DEBUG("- find_local_item: Not found");
- return false;
-}
-bool CPathResolver::find_mod_item(const Span& span, AST::Path& path, const ::std::string& name) {
- TRACE_FUNCTION_F("path="<<path<<", name="<<name);
- const AST::Module* mod = m_module;
- const AST::Path* modpath = &m_module_path;
- unsigned int idx = m_module_stack.size() - 1;
- for(;;)
- {
- DEBUG("modpath = " << *modpath << ", mod->path() = '" << mod->path() << "'");
- if( lookup_path_in_module(span, m_crate, *mod, *modpath, path, name, path.size()==1) )
- return true;
- DEBUG("mod->path() = '" << mod->path() << "', idx = " << idx);
- if( mod->is_anon() && idx > 0 ) {
- idx --;
- mod = m_module_stack[idx].first;
- modpath = &m_module_stack[idx].second;
- }
- else {
- break ;
- }
- }
- return false;
-}
-bool CPathResolver::find_self_mod_item(const Span& span, AST::Path& path, const ::std::string& name) {
- if( m_module->is_anon() )
- throw ParseError::Todo("Correct handling of 'self' in anon modules");
-
- return lookup_path_in_module(span, m_crate, *m_module, m_module_path, path, name, path.size()==1);
-}
-bool CPathResolver::find_super_mod_item(const Span& span, AST::Path& path, const ::std::string& name) {
- if( m_module->is_anon() )
- throw ParseError::Todo("Correct handling of 'super' in anon modules");
-
- // 1. Construct path to parent module
- AST::Path super_path = m_module_path;
- super_path.nodes().pop_back();
- assert( super_path.nodes().size() > 0 );
- if( super_path.nodes().back().name()[0] == '#' )
- throw ParseError::Todo("Correct handling of 'super' in anon modules (parent is anon)");
- // 2. Resolve that path
- resolve_path(span, m_crate, super_path);
- // 3. Call lookup_path_in_module
- assert( super_path.binding().is_Module() );
- return lookup_path_in_module(span, m_crate, *super_path.binding().as_Module().module_, super_path, path, name, path.size()==1);
-}
-bool CPathResolver::find_type_param(const ::std::string& name) {
- for( auto it = m_locals.end(); it -- != m_locals.begin(); )
- {
- if( it->type == LocalItem::TYPE ) {
- if( it->name == name ) {
- return true;
- }
- }
- }
- return false;
-}
-
-void CPathResolver::handle_type(TypeRef& type)
-{
- TRACE_FUNCTION_F("type = " << type);
- // PROBLEM: Recursion when evaluating Self that expands to UFCS mentioning Self
- // > The inner Self shouldn't be touched, but it gets hit by this method, and sudden recursion
- //if( type.is_locked() )
- //{
- //}
- //else
- if( type.is_path() && type.path().is_trivial() )
- {
- const auto& name = type.path()[0].name();
- auto opt_local = lookup_local(LocalItem::TYPE, name);
-
- if( opt_local.is_some() )
- {
- DEBUG("Found local '" << name << "' aliasing to " << opt_local.unwrap().tr);
- type = opt_local.unwrap().tr;
- }
- else if( name == "Self" )
- {
- // TODO: Should I always resolve `Self` when it's concretely known?
- // If the name was "Self", but Self isn't already defined... then we need to make it an arg?
- if( this->m_self_type.empty() || this->m_self_type.back().is_None() ) {
- ERROR(Span(), E0000, "Unexpected 'Self'");
- }
- else {
- TU_MATCH(SelfType, (this->m_self_type.back()), (ent),
- (None,
- assert(!"SelfType is None in CPathResolver::handle_type");
- ),
- (Type,
- DEBUG("Self type is " << ent.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
- {
- // Not a type param, fall back to other checks
- }
- }
- else if( type.is_type_param() )
- {
- const auto& name = type.type_param();
- auto opt_local = lookup_local(LocalItem::TYPE, name);
- if( name == "Self" )
- {
- 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,
- DEBUG("Self type is " << ent.type);
- type = ent.type;
- return ;
- ),
- (Trait,
- // Valid...
- )
- )
- }
- else if( opt_local.is_some() )
- {
- type = opt_local.unwrap().tr;
- }
- else
- {
- // Not a type param, fall back to other checks
- throw CompileError::Generic( FMT("CPathResolver::handle_type - Invalid parameter '" << name << "'") );
- }
- }
- else
- {
- // No change
- }
- DEBUG("type = " << type);
-
- //if
-
- //if( type.is_type_param() && type.type_param() == "Self" )
- //{
- // auto l = lookup_local(LocalItem::TYPE, "Self");
- // if( l.is_some() )
- // {
- // type = l.unwrap().tr;
- // DEBUG("Replacing Self with " << type);
- // // TODO: Can this recurse?
- // handle_type(type);
- // return ;
- // }
- //}
- CASTIterator::handle_type(type);
- DEBUG("res = " << type);
-}
-void CPathResolver::handle_expr(AST::ExprNode& node)
-{
- CResolvePaths_NodeVisitor nv(*this);
- node.visit(nv);
-}
-
-void CPathResolver::handle_pattern(AST::Pattern& pat, const TypeRef& type_hint)
-{
- TRACE_FUNCTION_F("pat = " << pat);
- // Resolve "Maybe Bind" entries
- if( pat.data().is_MaybeBind() )
- {
- ::std::string name = pat.binding();
- // Locate a _constant_ within the current namespace which matches this name
- // - Variables don't count
- AST::Path newpath = AST::Path(AST::Path::TagRelative(), { AST::PathNode(name) });
- handle_path(newpath, CASTIterator::MODE_BIND);
- if( newpath.is_relative() || newpath.is_trivial() )
- {
- // It's a name binding (desugar to 'name @ _')
- pat = AST::Pattern();
- pat.set_bind(name, AST::Pattern::BIND_MOVE, false);
- }
- else
- {
- // It's a constant (enum variant usually)
- pat = AST::Pattern(
- AST::Pattern::TagValue(),
- AST::Pattern::Value::make_Named( mv$(newpath) )
- );
- }
- }
-
- // hand off to original code
- CASTIterator::handle_pattern(pat, type_hint);
-}
-void CPathResolver::handle_module(AST::Path path, AST::Module& mod)
-{
- ::std::vector<Scope> saved = mv$(m_scope_stack);
- // NOTE: Assigning here is safe, as the CASTIterator handle_module iterates submodules as the last action
- m_module = &mod;
- m_module_path = AST::Path(path);
- m_module_stack.push_back( ::std::make_pair(&mod, m_module_path) );
- CASTIterator::handle_module(mv$(path), mod);
- m_module_stack.pop_back();
- m_scope_stack = mv$(saved);
-}
-void CPathResolver::handle_trait(AST::Path path, AST::Trait& trait)
-{
- //path.resolve(m_crate);
-
- // Handle local
- m_scope_stack.back().traits.push_back( ::std::pair<AST::Path, const AST::Trait&>(path, trait) );
- CASTIterator::handle_trait(path, trait);
-}
-void CPathResolver::handle_function(AST::Path path, AST::Function& fcn)
-{
- m_scope_stack.push_back( {0, nullptr, AST::Path(), {}} );
- CASTIterator::handle_function(::std::move(path), fcn);
- m_scope_stack.pop_back();
-}
-
-
-void absolutise_path(const Span& span, const AST::Crate& crate, const AST::Module& mod, const AST::Path& modpath, AST::Path& path)
-{
- // TODO: Should this code resolve encountered use statements into the real path?
- TU_MATCH(AST::Path::Class, (path.m_class), (info),
- (Invalid,
- BUG(span, "Invalid path type encountered - Class::Invalid");
- ),
- (Local,
- // Known-local paths don't need to be absolutised
- ),
- (Absolute,
- // Nothing needs to be done
- ),
- (Super,
- // TODO: Super supports multiple instances
- auto newpath = modpath;
- newpath.nodes().pop_back();
- newpath += path;
- DEBUG("Absolutised path " << path << " into " << newpath);
- path = ::std::move(newpath);
- ),
- (Self,
- auto modpath_tmp = modpath;
- const AST::Module* mod_ptr = &mod;
- while( modpath_tmp.size() > 0 && modpath_tmp.nodes().back().name()[0] == '#' )
- {
- if( !mod_ptr->find_item(path.nodes()[0].name()).is_None() ) {
- break ;
- }
- modpath_tmp.nodes().pop_back();
- resolve_path(span, crate, modpath_tmp);
- DEBUG("modpath_tmp = " << modpath_tmp);
- assert( modpath_tmp.binding().is_Module() );
- mod_ptr = modpath_tmp.binding().as_Module().module_;
- }
- auto newpath = modpath_tmp + path;
- DEBUG("Absolutised path " << path << " into " << newpath);
- path = ::std::move(newpath);
- ),
- (Relative,
- auto newpath = modpath + path;
- DEBUG("Absolutised path " << path << " into " << newpath);
- path = ::std::move(newpath);
- ),
- (UFCS,
- throw ParseError::Generic( FMT("Invalid path type encounted - UFCS " << path) );
- )
- )
-}
-
-void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& modpath, AST::Module& mod)
-{
- TRACE_FUNCTION_F("modpath = " << modpath << ", mod = {path:" << mod.path() << "}");
- ::std::vector<AST::Path> new_imports;
- for( auto& imp : mod.imports() )
- {
- const Span& span = imp.data.sp;
- DEBUG("p = " << imp.data);
- absolutise_path(span, crate, mod, modpath, imp.data.path);
-
- resolve_path(span, crate, imp.data.path);
- DEBUG("Resolved import : " << imp.data);
-
- // If wildcard, make sure it's sane
- if( imp.name == "" )
- {
- TU_MATCH_DEF(AST::PathBinding, (imp.data.path.binding()), (info),
- (
- throw ParseError::Generic("Wildcard imports are only allowed on modules and enums");
- ),
- (Unbound,
- throw ParseError::BugCheck("Wildcard import path unbound after calling .resolve()");
- ),
- (Module, (void)0;),
- (Enum, (void)0;)
- )
- }
- }
-
- for( auto& new_imp : new_imports )
- {
- //if( new_imp.binding().is_Unbound() ) {
- // new_imp.resolve(crate, false);
- //}
- // TODO: Get attributes from the source import
- mod.add_alias(false, ::AST::UseStmt(Span(), new_imp), new_imp[new_imp.size()-1].name(), ::AST::MetaItems());
- }
-
- for(auto& item : mod.items()) {
- if( item.data.is_Module() ) {
- ResolvePaths_HandleModule_Use(crate, modpath + item.name, item.data.as_Module());
- }
- }
-}
-
-void SetCrateName_Type(const AST::Crate& crate, ::std::string name, TypeRef& type)
-{
- if( type.is_path() )
- {
- type.path().set_crate(name);
- //type.path().resolve(crate);
- }
-}
-
-void SetCrateName_Mod(const AST::Crate& crate, ::std::string name, AST::Module& mod)
-{
- for(auto& item : mod.items()) {
- if( item.data.is_Module() ) {
- SetCrateName_Mod(crate, name, item.data.as_Module());
- }
- }
- // Imports 'use' statements
- for(auto& imp : mod.imports())
- {
- imp.data.path.set_crate(name);
- // - Disable expectation of type parameters
- //imp.data.resolve(crate, false);
- }
-
- // TODO: All other types
- for(auto& item : mod.items()) {
- if( item.data.is_Function() ) {
- SetCrateName_Type(crate, name, item.data.as_Function().rettype());
- }
- }
-}
-
-
-// First pass of conversion
-// - Tag paths of external crate items with crate name
-// - Convert all paths into absolute paths (or local variable references)
-void ResolvePaths(AST::Crate& crate)
-{
- DEBUG(" >>>");
- // Pre-process external crates to tag all paths
- #if 0
- DEBUG(" --- Extern crates");
- INDENT();
- for(auto& ec : crate.extern_crates())
- {
- SetCrateName_Mod(crate, ec.first, ec.second.root_module());
- }
- UNINDENT();
- #endif
-
- // Handle 'use' statements in an initial parss
- DEBUG(" --- Use Statements");
- INDENT();
- ResolvePaths_HandleModule_Use(crate, AST::Path("", {}), crate.root_module());
- UNINDENT();
-
- // Resolve traits next, to ensure they're usable
- //ResolvePaths_HandleModule_Trait(crate, AST::Path("", {}), crate.root_module());
- // Resolve impl block headers
- //ResolvePaths_HandleModule_Impl(crate, AST::Path("", {}), crate.root_module());
-
- // Then do path resolution on all other items
- CPathResolver pr(crate);
- DEBUG(" ---");
- pr.handle_module(AST::Path("", {}), crate.root_module());
- DEBUG(" <<<");
-
- pr.m_second_pass = true;
- DEBUG(" ---");
- pr.handle_module(AST::Path("", {}), crate.root_module());
- DEBUG(" <<<");
-}
diff --git a/src/convert/typecheck_bounds.cpp b/src/convert/typecheck_bounds.cpp deleted file mode 100644 index f2cda828..00000000 --- a/src/convert/typecheck_bounds.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - */ -#include <main_bindings.hpp> -#include "ast_iterate.hpp" -#include "../ast/crate.hpp" -#include "../common.hpp" -#include <stdexcept> - -class CGenericBoundChecker: - public CASTIterator -{ - void check_is_trait(const AST::Path& trait) const; -public: - virtual void handle_expr(AST::ExprNode& root) override; - virtual void handle_params(AST::GenericParams& params) override; -}; - -void CGenericBoundChecker::handle_expr(AST::ExprNode& root) -{ - // Do nothing (this iterator shouldn't recurse into expressions) -} - -void CGenericBoundChecker::check_is_trait(const AST::Path& trait) const { - assert( !trait.binding().is_Unbound() ); - DEBUG("trait = " << trait); - if( trait.binding().is_Trait() ) - { - //throw CompileError::BoundNotTrait( bound.lex_scope(), bound.param(), trait ); - throw ::std::runtime_error(FMT("TODO - Bound " << trait << " not a trait : " << trait.binding())); - } - else { - DEBUG("Bound is a trait, good"); - } -} - -void CGenericBoundChecker::handle_params(AST::GenericParams& params) -{ - for(auto& bound : params.bounds()) - { - TU_MATCH(AST::GenericBound, (bound), (ent), - (Lifetime, {}), - (TypeLifetime, {}), - (IsTrait, this->check_is_trait(ent.trait);), - (MaybeTrait, this->check_is_trait(ent.trait);), - (NotTrait, this->check_is_trait(ent.trait);), - (Equality, {}) - ) - } -} - -/// Typecheck generic bounds (where clauses) -void Typecheck_GenericBounds(AST::Crate& crate) -{ - DEBUG(" --- "); - CGenericBoundChecker chk; - chk.handle_module(AST::Path("", {}), crate.root_module()); -} - diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp deleted file mode 100644 index 59e9a4aa..00000000 --- a/src/convert/typecheck_expr.cpp +++ /dev/null @@ -1,609 +0,0 @@ -/* - * MRustC - Mutabah's Rust Compiler - * - By John Hodge (Mutabah/thePowersGang) - * - * convert/typecheck_expr.cpp - * - Handles type checking, expansion, and method resolution for expressions (function bodies) - */ -#include <main_bindings.hpp> -#include "ast_iterate.hpp" -#include "../ast/expr.hpp" -#include "../ast/crate.hpp" -#include "../common.hpp" -#include <stdexcept> - -// === PROTOTYPES === -class CTypeChecker: - public CASTIterator -{ - friend class CTC_NodeVisitor; - - struct Scope { - ::std::vector< ::std::tuple<bool, ::std::string, TypeRef> > vars; - ::std::vector< ::std::tuple< ::std::string, TypeRef> > types; - ::std::map< ::std::string, TypeRef > params; - ::std::vector< AST::Path > traits; - }; - - AST::Crate& m_crate; - ::std::vector<Scope> m_scopes; - -public: - CTypeChecker(AST::Crate& crate): - m_crate(crate) - {} - - virtual void start_scope() override; - virtual void local_variable(bool is_mut, ::std::string name, const TypeRef& type) override; - virtual void local_type(::std::string name, TypeRef type) override; - virtual void end_scope() override; - - virtual void handle_params(AST::GenericParams& params) override; - - virtual void handle_pattern_enum( - ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, - const AST::GenericParams& enum_params, const AST::EnumVariant& var, - ::std::vector<AST::Pattern>& sub_patterns - ) override; - - virtual void handle_function(AST::Path path, AST::Function& fcn) override; - // - Ignore all non-function items on this pass - virtual void handle_enum(AST::Path path, AST::Enum& ) override {} - virtual void handle_struct(AST::Path path, AST::Struct& str) override {} - virtual void handle_alias(AST::Path path, AST::TypeAlias& ) override {} - -private: - TypeRef& get_local_var(const char* name); - const TypeRef& get_local_type(const char* name); - const TypeRef& get_type_param(const char* name); - - void check_enum_variant( - ::std::vector<TypeRef>& path_args, const ::std::vector<TypeRef>& argtypes, - const AST::GenericParams& params, const AST::EnumVariant& var - ); - void iterate_traits(::std::function<bool(const TypeRef& trait)> fcn); -}; -class CTC_NodeVisitor: - public AST::NodeVisitorDef -{ - CTypeChecker& m_tc; -public: - CTC_NodeVisitor(CTypeChecker& tc): - m_tc(tc) - {} - - virtual void visit(AST::ExprNode_NamedValue& node) override; - - virtual void visit(AST::ExprNode_LetBinding& node) override; - virtual void visit(AST::ExprNode_Assign& node) override; - - virtual void visit(AST::ExprNode_Match& node) override; - - virtual void visit(AST::ExprNode_Field& node) override; - virtual void visit(AST::ExprNode_Cast& node) override; - - virtual void visit(AST::ExprNode_CallMethod& node) override; - virtual void visit(AST::ExprNode_CallPath& node) override; -}; - -void CTypeChecker::start_scope() -{ - m_scopes.push_back( Scope() ); -} -void CTypeChecker::local_variable(bool is_mut, ::std::string name, const TypeRef& type) -{ - DEBUG("is_mut=" << is_mut << " name=" << name << " type=" << type); - m_scopes.back().vars.push_back( make_tuple(is_mut, name, TypeRef(type)) ); -} -void CTypeChecker::local_type(::std::string name, TypeRef type) -{ - DEBUG("name=" << name << " type=" << type); - m_scopes.back().types.push_back( make_tuple(name, ::std::move(type)) ); -} -void CTypeChecker::end_scope() -{ - m_scopes.pop_back(); -} - -void CTypeChecker::handle_params(AST::GenericParams& params) -{ - ::std::map<std::string,TypeRef> trs; - - for( const auto& param : params.ty_params() ) - { - trs.insert( make_pair(param.name(), TypeRef()) ); - } - - for( const auto& bound : params.bounds() ) - { - if( bound.is_IsTrait() && bound.as_IsTrait().type.is_type_param() ) - { - const auto& name = bound.as_IsTrait().type.type_param(); - int i = params.find_name(name.c_str()); - assert(i >= 0); - // - Just assert that it's valid. - //trs[name].add_trait( bound.bound() ); - } - } - - assert(m_scopes.back().params.size() == 0); - m_scopes.back().params = trs; -} -void CTypeChecker::handle_pattern_enum( - ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, - const AST::GenericParams& enum_params, const AST::EnumVariant& var, - ::std::vector<AST::Pattern>& sub_patterns - ) -{ - #if 0 - check_enum_variant(pat_args, hint_args, enum_params, var); - - // Ensure that sub_patterns is the same length as the variant - const auto& var_types = var.m_sub_types; - if( sub_patterns.size() != var_types.size() ) - throw ::std::runtime_error(FMT("Enum pattern size mismatch")); - for( unsigned int i = 0; i < sub_patterns.size(); i ++ ) - { - // TODO: Need to propagate types through here correctly. - // - hint_args -> enum -> this - TypeRef arg = var_types[i]; - arg.resolve_args([&](const char *name){ - int i = enum_params.find_name(name); - if(i < 0) throw ""; - return hint_args[i]; - }); - handle_pattern(sub_patterns[i], var_types[i]); - } - #else - throw ::std::runtime_error("TODO: CTypeChecker::handle_pattern_enum "); - #endif -} - -TypeRef& CTypeChecker::get_local_var(const char* name) -{ - for( auto it = m_scopes.end(); it-- != m_scopes.begin(); ) - { - for( auto it2 = it->vars.end(); it2-- != it->vars.begin(); ) - { - if( name == ::std::get<1>(*it2) ) - { - return ::std::get<2>(*it2); - } - } - } - throw ::std::runtime_error(FMT("get_local_var - name " << name << " not found")); -} -const TypeRef& CTypeChecker::get_local_type(const char* name) -{ - for( auto it = m_scopes.end(); it-- != m_scopes.begin(); ) - { - for( auto it2 = it->types.end(); it2-- != it->types.begin(); ) - { - if( name == ::std::get<0>(*it2) ) - { - return ::std::get<1>(*it2); - } - } - } - throw ::std::runtime_error(FMT("get_local_type - name " << name << " not found")); -} -const TypeRef& CTypeChecker::get_type_param(const char* name) -{ - DEBUG("name = " << name); - for( auto it = m_scopes.end(); it-- != m_scopes.begin(); ) - { - DEBUG("- params = " << it->params); - auto ent = it->params.find(name); - if( ent != it->params.end() ) - { - DEBUG("> match " << ent->second); - return ent->second; - } - } - throw ::std::runtime_error(FMT("get_type_param - name " << name << " not found")); -} - -void CTypeChecker::handle_function(AST::Path path, AST::Function& fcn) -{ - DEBUG("(path = " << path << ")"); - start_scope(); - - handle_params(fcn.params()); - - handle_type(fcn.rettype()); - - for( auto& arg : fcn.args() ) - { - handle_type(arg.second); - handle_pattern( arg.first, arg.second ); - } - - CTC_NodeVisitor nv(*this); - if( fcn.code().is_valid() ) - { - fcn.code().node().get_res_type() = fcn.rettype(); - fcn.code().visit_nodes(nv); - } - - end_scope(); -} - -void CTypeChecker::iterate_traits(::std::function<bool(const TypeRef& trait)> fcn) -{ - for( auto scopei = m_scopes.end(); scopei-- != m_scopes.begin(); ) - { - for( auto& trait : scopei->traits ) - { - if( !fcn(TypeRef(Span(), trait)) ) - { - return; - } - } - } -} - -void CTypeChecker::check_enum_variant(::std::vector<TypeRef>& path_args, const ::std::vector<TypeRef>& argtypes, const AST::GenericParams& params, const AST::EnumVariant& var) -{ - #if 0 - // We know the enum, but it might have type params, need to handle that case - // TODO: Check for more parameters than required - if( params.ty_params().size() > 0 ) - { - // 1. Obtain the pattern set from the path (should it be pre-marked with _ types?) - while( path_args.size() < params.ty_params().size() ) - path_args.push_back( TypeRef() ); - DEBUG("path_args = [" << path_args << "]"); - // 2. Create a pattern from the argument types and the format of the variant - DEBUG("argtypes = [" << argtypes << "]"); - ::std::vector<TypeRef> item_args(params.ty_params().size()); - DEBUG("variant type = " << var.m_sub_types << ""); - for( unsigned int i = 0; i < var.m_sub_types.size(); i ++ ) - { - var.m_sub_types[i].match_args( - TypeRef(TypeRef::TagTuple(), Span(), argtypes), - [&](const char *name, const TypeRef& t) { - DEBUG("Binding " << name << " to type " << t); - int idx = params.find_name(name); - if( idx == -1 ) { - throw ::std::runtime_error(FMT("Can't find generic " << name)); - } - item_args.at(idx).merge_with( t ); - } - ); - } - DEBUG("item_args = [" << item_args << "]"); - // 3. Merge the two sets of arguments - for( unsigned int i = 0; i < path_args.size(); i ++ ) - { - path_args[i].merge_with( item_args[i] ); - } - DEBUG("new path_args = [" << path_args << "]"); - } - #else - throw ::std::runtime_error("TODO: CTypeChecker::check_enum_variant"); - #endif -} - -/// Named value - leaf -void CTC_NodeVisitor::visit(AST::ExprNode_NamedValue& node) -{ - DEBUG("ExprNode_NamedValue - " << node.m_path); - const AST::Path& p = node.m_path; - if( p.is_absolute() ) - { - // grab bound item - TU_MATCH_DEF(AST::PathBinding, (p.binding()), (info), - ( - throw ::std::runtime_error( FMT("Unknown binding type on named value : "<<p) ); - ), - (Static, - node.get_res_type() = info.static_->type(); - ), - (EnumVar, - const AST::Enum& enm = *info.enum_; - auto idx = info.idx; - // Enum variant: - // - Check that this variant takes no arguments - if( ! enm.variants()[idx].m_data.is_Value() ) - throw ::std::runtime_error( "Used a non-unit variant as a raw value" ); - // - Set output type to the enum (wildcard params, not default) - AST::Path tp = p; - tp.nodes().pop_back(); - AST::PathNode& pn = tp.nodes().back(); - unsigned int num_params = enm.params().ty_params().size(); - if(pn.args().size() > num_params) - throw ::std::runtime_error( FMT("Too many arguments to enum variant - " << p) ); - while(pn.args().size() < num_params) - pn.args().push_back( TypeRef() ); - node.get_res_type() = TypeRef(Span(node.get_pos()), tp); - ) - ) - } - else - { - TypeRef& local_type = m_tc.get_local_var( p[0].name().c_str() ); - node.get_res_type().merge_with( local_type ); - DEBUG("res type = " << node.get_res_type()); - local_type = node.get_res_type(); - } -} - -void CTC_NodeVisitor::visit(AST::ExprNode_LetBinding& node) -{ - DEBUG("ExprNode_LetBinding"); - - node.get_res_type() = TypeRef(TypeRef::TagUnit(), Span(node.get_pos())); - - // Evaluate value - AST::NodeVisitor::visit(node.m_value); - - const TypeRef& bind_type = node.m_type; - const TypeRef& val_type = node.m_value->get_res_type(); - - // Obtain resultant type from value - // Compare to binding type - // - If both concrete, but different : error - if( bind_type.is_concrete() && val_type.is_concrete() ) - { - if( bind_type != val_type ) { - throw ::std::runtime_error( FMT("Type mismatch on let, expected " << bind_type << ", got " << val_type) ); - } - } - // - If neither concrete, merge requirements of both - else - { - node.m_type.merge_with( val_type ); - node.m_value->get_res_type() = node.m_type; - } - - m_tc.handle_pattern(node.m_pat, node.m_type); -} - -void CTC_NodeVisitor::visit(AST::ExprNode_Assign& node) -{ - node.get_res_type() = TypeRef(TypeRef::TagUnit(), Span(node.get_pos())); - AST::NodeVisitor::visit(node.m_slot); - AST::NodeVisitor::visit(node.m_value); -} - -void CTC_NodeVisitor::visit(AST::ExprNode_Match& node) -{ - DEBUG("ExprNode_Match"); - AST::NodeVisitor::visit(node.m_val); - - for( auto& arm : node.m_arms ) - { - m_tc.start_scope(); - for( auto& pat : arm.m_patterns ) - m_tc.handle_pattern(pat, node.m_val->get_res_type()); - AST::NodeVisitor::visit(arm.m_cond); - AST::NodeVisitor::visit(arm.m_code); - m_tc.end_scope(); - } -} - -void CTC_NodeVisitor::visit(AST::ExprNode_Field& node) -{ - DEBUG("ExprNode_Field " << node.m_name); - - AST::NodeVisitor::visit(node.m_obj); - - TypeRef* tr = &node.m_obj->get_res_type(); - DEBUG("ExprNode_Field - tr = " << *tr); - if( tr->is_concrete() ) - { - // Must be a structure type (what about associated items?) - unsigned int deref_count = 0; - while( tr->is_reference() ) - { - tr = &tr->inner_type(); - DEBUG("ExprNode_Field - ref deref to " << *tr); - deref_count ++; - } - if( !tr->is_path() ) - { - throw ::std::runtime_error("ExprNode_Field - Type not a path"); - } - - // TODO Move this logic to types.cpp? - const AST::Path& p = tr->path(); - TU_MATCH_DEF( AST::PathBinding, (p.binding()), (info), - ( - throw ::std::runtime_error("TODO: Get field from non-structure"); - ), - (Struct, - const AST::PathNode& lastnode = p.nodes().back(); - AST::Struct& s = const_cast<AST::Struct&>( *info.struct_ ); - node.get_res_type().merge_with( s.get_field_type(node.m_name.c_str(), lastnode.args()) ); - ) - ) - DEBUG("deref_count = " << deref_count); - for( unsigned i = 0; i < deref_count; i ++ ) - { - node.m_obj = ::std::unique_ptr<AST::ExprNode>(new AST::ExprNode_Deref( ::std::move(node.m_obj) )); - } - } - else - { - DEBUG("ExprNode_Field - Type not concrete, can't get field"); - } -} - -void CTC_NodeVisitor::visit(AST::ExprNode_Cast& node) -{ - DEBUG("ExprNode_Cast " << node.m_type); - - AST::NodeVisitor::visit(node.m_value); - - node.get_res_type().merge_with( node.m_type ); -} - -void CTC_NodeVisitor::visit(AST::ExprNode_CallMethod& node) -{ - DEBUG("ExprNode_CallMethod " << node.m_method); - - AST::NodeVisitor::visit(node.m_val); - - for( auto& arg : node.m_args ) - { - AST::NodeVisitor::visit(arg); - } - - // Locate method - const TypeRef& type = node.m_val->get_res_type(); - DEBUG("CallMethod - type = " << type); - - // Replace generic references in 'type' (copying the type) with - // '_: Bounds' (allowing method lookup to succeed) - TypeRef ltype = type; - unsigned int deref_count = 0; - ltype.resolve_args( [&](const char* name) { - return m_tc.get_type_param(name); - } ); - - // Begin trying options (attempting an autoderef each time) - const char * const name = node.m_method.name().c_str(); - AST::Function* fcnp = nullptr; - do - { - // 1. Handle bounded wildcard types - if( ltype.is_wildcard() ) - { - throw ::std::runtime_error("TODO: _ in CallMethod"); - //if( ltype.traits().size() == 0 ) { - // DEBUG("- Unconstrained wildcard, returning"); - // return ; - //} - // - //for( const auto& t : ltype.traits() ) - //{ - // DEBUG("- Trait " << t.path()); - // AST::Trait& trait = const_cast<AST::Trait&>( t.path().binding().bound_trait() ); - // // - Find method on one of them - // for( auto& m : trait.functions() ) - // { - // DEBUG(" > method: " << m.name << " search: " << node.m_method.name()); - // if( m.name == node.m_method.name() ) - // { - // DEBUG(" > Found method"); - // fcnp = &m.data; - // break; - // } - // } - // if(fcnp) break; - //} - //if(fcnp) break; - } - else - { - // 2. Find inherent impl - auto oimpl = m_tc.m_crate.get_impl(AST::Path(), ltype); - if( oimpl.is_some() ) - { - AST::Impl& impl = oimpl.unwrap(); - // 1.1. Search impl for this method - for(auto& i : impl.items()) - { - if( i.name == name && i.data.is_Function() ) - { - fcnp = &i.data.as_Function(); - break; - } - } - if(fcnp) break; - } - - // 2. Iterate in-scope traits - m_tc.iterate_traits( [&](const TypeRef& trait) { - // TODO: Check trait first, then find an impl - auto oimpl = m_tc.m_crate.get_impl(trait.path(), ltype); - if( oimpl.is_some() ) - { - AST::Impl& impl = oimpl.unwrap(); - for(auto& i : impl.items()) - { - if( i.name == name && i.data.is_Function() ) - { - fcnp = &i.data.as_Function(); - break; - } - } - } - return fcnp == nullptr; - }); - } - if( fcnp ) - break; - deref_count ++; - } while( ltype.deref(true) ); - - if( fcnp ) - { - DEBUG("deref_count = " << deref_count); - for( unsigned i = 0; i < deref_count; i ++ ) - { - node.m_val = ::std::unique_ptr<AST::ExprNode>(new AST::ExprNode_Deref( ::std::move(node.m_val) )); - } - - AST::Function& fcn = *fcnp; - if( fcn.params().ty_params().size() != node.m_method.args().size() ) - { - throw ::std::runtime_error("CallMethod with param count mismatch"); - } - if( fcn.params().ty_params().size() ) - { - throw ::std::runtime_error("TODO: CallMethod with params"); - } - node.get_res_type().merge_with( fcn.rettype() ); - } -} -void CTC_NodeVisitor::visit(AST::ExprNode_CallPath& node) -{ - DEBUG("ExprNode_CallPath - " << node.m_path); - ::std::vector<TypeRef> argtypes; - for( auto& arg : node.m_args ) - { - AST::NodeVisitor::visit(arg); - argtypes.push_back( arg->get_res_type() ); - } - - TU_MATCH_DEF( AST::PathBinding, (node.m_path.binding()), (info), - ( - throw ::std::runtime_error("CallPath on non-function"); - ), - (Function, - const AST::Function& fcn = *info.func_; - - if( fcn.params().ty_params().size() > 0 ) - { - throw ::std::runtime_error("CallPath - TODO: Params on functions"); - } - - DEBUG("ExprNode_CallPath - rt = " << fcn.rettype()); - node.get_res_type().merge_with( fcn.rettype() ); - ), - (EnumVar, - const AST::Enum& enm = *info.enum_; - const unsigned int idx = info.idx; - - auto& path_node_enum = node.m_path[node.m_path.size()-2]; - m_tc.check_enum_variant(path_node_enum.args(), argtypes, enm.params(), enm.variants().at(idx)); - - AST::Path p = node.m_path; - p.nodes().pop_back(); - TypeRef ty(Span(), ::std::move(p) ); - - DEBUG("ExprNode_CallPath - enum t = " << ty); - node.get_res_type().merge_with(ty); - ) - ) -} - -void Typecheck_Expr(AST::Crate& crate) -{ - DEBUG(" >>>"); - CTypeChecker tc(crate); - tc.handle_module(AST::Path("", {}), crate.root_module()); - DEBUG(" <<<"); -} - diff --git a/src/convert/typecheck_params.cpp b/src/convert/typecheck_params.cpp deleted file mode 100644 index aa53d3bd..00000000 --- a/src/convert/typecheck_params.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/* -/// Typecheck generic parameters (ensure that they match all generic bounds) - */ -#include <main_bindings.hpp> -#include "ast_iterate.hpp" -#include "../ast/crate.hpp" -#include "../common.hpp" -#include <stdexcept> - -// === PROTOTYPES === -class CGenericParamChecker: - public CASTIterator -{ - int m_within_expr = 0; - struct LocalType { - const ::std::string name; - const AST::GenericParams* source_params; // if nullptr, use fixed_type - TypeRef fixed_type; - - LocalType(): - name("") - {} - LocalType(const ::std::string& n, const AST::GenericParams* tps): - name(n), source_params(tps) - {} - LocalType(const ::std::string& n, TypeRef ty): - name(n), source_params(nullptr), fixed_type( ::std::move(ty) ) - {} - - bool is_separator() const { return name == ""; } - }; - // name == "" indicates edge of a scope - ::std::vector<LocalType> m_types_stack; - - AST::Crate& m_crate; -public: - CGenericParamChecker(AST::Crate& c): - m_crate(c) - { - } - - virtual void handle_path(AST::Path& path, CASTIterator::PathMode pm) override; - virtual void handle_expr(AST::ExprNode& root) override; - void start_scope() override; - void local_type(::std::string name, TypeRef type) override; - void end_scope() override; - virtual void handle_params(AST::GenericParams& params) override; - -private: - bool has_impl_for_param(const ::std::string name, const AST::Path& trait) const; - bool has_impl(const TypeRef& type, const AST::Path& trait) const; - void check_generic_params(const AST::GenericParams& info, ::std::vector<TypeRef>& types, TypeRef self_type, bool allow_infer = false); - - const LocalType* find_type_by_name(const ::std::string& name) const; -}; - -class CNodeVisitor: - public AST::NodeVisitorDef -{ - CGenericParamChecker& m_pc; -public: - CNodeVisitor(CGenericParamChecker& pc): - m_pc(pc) - {} -}; - -// === CODE === -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::GenericParams* tps = nullptr; - // Locate params set that contains the passed name - for( const auto lt : m_types_stack ) - { - if( lt.name == name ) - { - if( lt.source_params != nullptr ) { - tps = lt.source_params; - } - else { - DEBUG("Type name '" << name << "' isn't a param"); - return has_impl(lt.fixed_type, trait); - } - //break ; - } - } - - if( !tps ) - { - throw ::std::runtime_error(FMT("Param '"<<name<<"' isn't in scope")); - } - - // Search bound list for the passed trait - for( const auto& bound : tps->bounds() ) - { - DEBUG("bound = " << bound); - TU_IFLET( AST::GenericBound, bound, IsTrait, ent, - if( ent.type.is_type_param() && ent.type.type_param() == name ) - { - DEBUG("bound.type() {" << ent.trait << "} == trait {" << trait << "}"); - if( ent.trait == trait ) - return true; - } - ) - } - - // TODO: Search for generic ("impl<T: Trait2> Trait1 for T") that fits bounds - - DEBUG("No match in generics, returning failure"); - return false; -} - -bool CGenericParamChecker::has_impl(const TypeRef& type, const AST::Path& trait) const -{ - TRACE_FUNCTION_F("type = " << type << ", trait = " << trait); - if( type.is_type_param() ) - { - // TODO: Search current scope (requires access to CGenericParamChecker) for this type, - // and search the bounds for this trait - // - Also accept bounded generic impls (somehow) - { - return true; - } - } - else - { - // Search all known impls of this trait (TODO: keep a list at the crate level) for a match to this type - if( m_crate.find_impl(trait, type, nullptr, nullptr) == false ) { - DEBUG("- Nope"); - return false; - } - - return true; - } - return false; -} - -/// Check that the passed set of parameters match the requiremens for a generic item -/// -/// \param info Generic item information (param names and bounds) -/// \param types Type parameters being passed to the generic item -/// \param allow_infer Allow inferrence (mutates \a types with conditions from \a info) -void CGenericParamChecker::check_generic_params(const AST::GenericParams& info, ::std::vector<TypeRef>& types, TypeRef self_type, bool allow_infer) -{ - TRACE_FUNCTION_F("info = " << info << ", types = {" << types << "}"); - // TODO: Need to correctly handle lifetime params here, they should be in a different list - const auto& params = info.ty_params(); - - if( types.size() > params.size() ) - { - throw ::std::runtime_error(FMT("Too many generic params ("<<types.size()<<" passed, expecting "<< params.size()<<")")); - } - else if( types.size() < params.size() ) - { - // Fill with defaults - while( types.size() < params.size() && params[types.size()].get_default() != TypeRef() ) - types.push_back( params[types.size()].get_default() ); - - // And (optionally) infer - if( allow_infer ) - { - while( types.size() < params.size() ) - { - types.push_back( TypeRef() ); - } - } - else if( types.size() < params.size() ) - { - throw ::std::runtime_error(FMT("Too few generic params, ("<<types.size()<<" passed, expecting "<<params.size()<<")")); - } - } - else - { - // Counts are good, time to validate types - } - - for( unsigned int i = 0; i < types.size(); i ++ ) - { - auto& type = types[i]; - auto& param = params[i].name(); - DEBUG("#" << i << " - checking type " << type << " against " << param); - if( type.is_wildcard() ) - { - // Type is a wildcard - this can match any condition - if( allow_infer ) - { - // Apply conditions for this param to the type - // TODO: Requires supporting type "ranges" on the TypeRef - // Should also check for conflicting requirements (negative bounds?) - DEBUG("TODO: Type inferrence"); - } - else - { - // This is an error, as inferrence is not currently allowed - throw ::std::runtime_error(FMT("Type of '_' present for param " << param << " when inferrence isn't allowed")); - } - } - else - { - // Not a wildcard! - // Check that the type fits the bounds applied to it - TypeRef param_type(TypeRef::TagArg(), param); - } - } - - for( const auto& bound : info.bounds() ) - { - TU_IFLET(AST::GenericBound, bound, IsTrait, ent, - auto ra_fcn = [&](const char *a){ - if( strcmp(a, "Self") == 0 ) { - if( ! self_type.is_valid() ) - throw CompileError::Generic("Unexpected use of 'Self' in bounds"); - return self_type; - } - return types.at(info.find_name(a)); - }; - auto bound_type = ent.type; - bound_type.resolve_args(ra_fcn); - - auto trait = ent.trait; - trait.resolve_args(ra_fcn); - - // Check if 'type' impls 'trait' - if( !has_impl(bound_type, trait) ) - { - throw ::std::runtime_error( FMT("No matching impl of "<<trait<<" for "<<bound_type)); - } - ) - } -} - -void CGenericParamChecker::handle_path(AST::Path& path, CASTIterator::PathMode pm) -{ - TRACE_FUNCTION_F("path = " << path); - AST::PathNode& last_node = path[path.size()-1]; - - auto comm = [&](const AST::GenericParams& params) { - auto lt = find_type_by_name("Self"); - TypeRef self_type; // =TypeRef(TypeRef::TagPath(), path) - if( lt ) - self_type = lt->fixed_type; - check_generic_params(params, last_node.args(), self_type, (m_within_expr > 0)); - }; - - TU_MATCH( AST::PathBinding, (path.binding()), (info), - (Unbound, - throw CompileError::BugCheck( FMT("CGenericParamChecker::handle_path - Unbound path : " << path) ); - ), - (Module, - DEBUG("WTF - Module path, isn't this invalid at this stage?"); - ), - (Trait, - comm( info.trait_->params() ); - ), - (Struct, - comm( info.struct_->params() ); - ), - (Enum, - comm( info.enum_->params() ); - ), - (TypeAlias, - comm( info.alias_->params() ); - ), - (Function, - check_generic_params(info.func_->params(), last_node.args(), TypeRef(TypeRef::TagInvalid(), Span()), (m_within_expr > 0)); - ), - - (EnumVar, - throw ::std::runtime_error("TODO: handle_path EnumVar"); - ), - (Static, - throw ::std::runtime_error("TODO: handle_path Static"); - ), - (StructMethod, - throw ::std::runtime_error("TODO: handle_path StructMethod"); - ), - (TraitMethod, - throw ::std::runtime_error("TODO: handle_path TraitMethod"); - ), - (TypeParameter, - throw ::std::runtime_error("TODO: handle_path TypeParameter"); - ), - (Variable, - throw ::std::runtime_error("TODO: handle_path Variable"); - ) - ) -} - -void CGenericParamChecker::handle_expr(AST::ExprNode& root) -{ - m_within_expr += 1; - // Do nothing (this iterator shouldn't recurse into expressions) - CNodeVisitor nv(*this); - root.visit(nv); - m_within_expr -= 1; -} - -void CGenericParamChecker::start_scope() -{ - m_types_stack.push_back( LocalType() ); -} -void CGenericParamChecker::local_type(::std::string name, TypeRef type) -{ - DEBUG("name = " << name << ", type = " << type); - m_types_stack.push_back( LocalType(::std::move(name), ::std::move(type)) ); -} -void CGenericParamChecker::end_scope() -{ - assert( m_types_stack.size() > 0 ); - while( !m_types_stack.back().is_separator() ) - m_types_stack.pop_back(); - // pop the separator - m_types_stack.pop_back(); -} -void CGenericParamChecker::handle_params(AST::GenericParams& params) -{ - DEBUG("params = " << params); - for( const auto& p : params.ty_params()) - m_types_stack.push_back( LocalType(p.name(), ¶ms) ); -} - -const CGenericParamChecker::LocalType* CGenericParamChecker::find_type_by_name(const ::std::string& name) const -{ - for( unsigned int i = m_types_stack.size(); i --; ) - { - if( m_types_stack[i].name == name ) - return &m_types_stack[i]; - } - return nullptr; -} - -/// Typecheck generic parameters (ensure that they match all generic bounds) -void Typecheck_GenericParams(AST::Crate& crate) -{ - DEBUG(" >>> "); - CGenericParamChecker chk(crate); - chk.handle_module(AST::Path("", {}), crate.root_module()); - DEBUG(" <<< "); -} - diff --git a/src/main.cpp b/src/main.cpp index b6dd9254..963491d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,9 +69,6 @@ void CompilePhaseV(const char *name, Fcn f) { /// main!
int main(int argc, char *argv[])
{
- AST_InitProvidedModule();
-
-
ProgramParams params(argc, argv);
// Set up cfg values
@@ -104,11 +101,6 @@ int main(int argc, char *argv[]) CompilePhaseV("Expand", [&]() {
Expand(crate);
});
-
- // Run a quick post-parse pass
- CompilePhaseV("PostParse", [&]() {
- crate.index_impls();
- });
// XXX: Dump crate before resolve
CompilePhaseV("Temp output - Parsed", [&]() {
|