From 76d70d4cbfbdf09082d35a224a4c7f2d2b501974 Mon Sep 17 00:00:00 2001 From: "John Hodge (sonata)" Date: Thu, 22 Jan 2015 14:51:07 +0800 Subject: Added bounds to _ types, propagating type params further (and replacing when needed) --- Makefile | 8 ++-- samples/std.rs | 1 + src/ast/ast.cpp | 5 +++ src/ast/ast.hpp | 1 + src/common.hpp | 17 +++++++++ src/convert/resolve.cpp | 8 ++++ src/convert/typecheck_expr.cpp | 85 ++++++++++++++++++++++++++++++++++++++++-- src/types.cpp | 5 +++ src/types.hpp | 12 +++++- 9 files changed, 134 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 12469c9b..6cff5d01 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,9 @@ EXESUF ?= CXX ?= g++ V ?= @ -LINKFLAGS := +LINKFLAGS := -g LIBS := -CXXFLAGS := -Wall -std=c++11 +CXXFLAGS := -g -Wall -std=c++11 CPPFLAGS := -I src/include/ @@ -29,8 +29,8 @@ clean: test: $(BIN) samples/1.rs mkdir -p output/ - time $(BIN) samples/std.rs --emit ast -o output/std.ast - time $(BIN) samples/1.rs --crate-path output/std.ast + time $(DBG) $(BIN) samples/std.rs --emit ast -o output/std.ast + time $(DBG) $(BIN) samples/1.rs --crate-path output/std.ast $(BIN): $(OBJ) @mkdir -p $(dir $@) diff --git a/samples/std.rs b/samples/std.rs index a0110c40..a44ae54e 100644 --- a/samples/std.rs +++ b/samples/std.rs @@ -27,6 +27,7 @@ pub mod io pub trait Reader { + fn read_byte(&mut self) -> IoResult; } } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 7fb84100..a5af04f5 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -105,6 +105,11 @@ const Module& Crate::get_root_module(const ::std::string& name) const { throw ParseError::Generic("crate name unknown"); } +Impl& Crate::find_impl(const TypeRef& trait, const TypeRef& type) +{ + throw ParseError::Generic( FMT("TODO: Lookup impl of " << trait << " for type " << type)); +} + Function& Crate::lookup_method(const TypeRef& type, const char *name) { throw ParseError::Generic( FMT("TODO: Lookup method "<& extern_crates() { return m_extern_crates; } const ::std::map< ::std::string, ExternCrate>& extern_crates() const { return m_extern_crates; } + Impl& find_impl(const TypeRef& trait, const TypeRef& type); Function& lookup_method(const TypeRef& type, const char *name); void load_extern_crate(::std::string name); diff --git a/src/common.hpp b/src/common.hpp index b9b90270..c73db0e8 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -115,6 +116,22 @@ inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector& v) return os; } +template +inline ::std::ostream& operator<<(::std::ostream& os, const ::std::map& v) { + if( v.size() > 0 ) + { + bool is_first = true; + for( const auto& i : v ) + { + if(!is_first) + os << ", "; + is_first = false; + os << i.first << ": " << i.second; + } + } + return os; +} + } #endif diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 787b50f3..4c79a401 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -274,6 +274,14 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) return ; } } + for( const auto& item : m_module->type_aliases() ) + { + if( item.name == path[0].name() ) { + path = m_module_path + path; + path.resolve( m_crate ); + return ; + } + } // Values / Functions for( const auto& item_fcn : m_module->functions() ) diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp index 21ad40b8..b5ee6e0d 100644 --- a/src/convert/typecheck_expr.cpp +++ b/src/convert/typecheck_expr.cpp @@ -14,6 +14,7 @@ class CTypeChecker: struct Scope { ::std::vector< ::std::tuple > vars; ::std::vector< ::std::tuple< ::std::string, TypeRef> > types; + ::std::map< ::std::string, TypeRef > params; }; AST::Crate& m_crate; @@ -29,6 +30,8 @@ public: virtual void local_type(::std::string name, TypeRef type) override; virtual void end_scope() override; + virtual void handle_params(AST::TypeParams& params) 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 {} @@ -38,6 +41,7 @@ public: 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 lookup_method(const TypeRef& type, const char* name); }; class CTC_NodeVisitor: @@ -82,6 +86,26 @@ void CTypeChecker::end_scope() m_scopes.pop_back(); } +void CTypeChecker::handle_params(AST::TypeParams& params) +{ + ::std::map trs; + + for( const auto& param : params.params() ) + { + trs.insert( make_pair(param.name(), TypeRef()) ); + } + + for( const auto& bound : params.bounds() ) + { + int i = params.find_name(bound.name().c_str()); + assert(i >= 0); + trs[bound.name()].add_trait( bound.type() ); + } + + assert(m_scopes.back().params.size() == 0); + m_scopes.back().params = trs; +} + TypeRef& CTypeChecker::get_local_var(const char* name) { for( auto it = m_scopes.end(); it-- != m_scopes.begin(); ) @@ -94,7 +118,7 @@ TypeRef& CTypeChecker::get_local_var(const char* name) } } } - throw ::std::runtime_error(FMT("get_local_type - name " << name << " not found")); + throw ::std::runtime_error(FMT("get_local_var - name " << name << " not found")); } const TypeRef& CTypeChecker::get_local_type(const char* name) { @@ -110,6 +134,21 @@ const TypeRef& CTypeChecker::get_local_type(const char* name) } 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) { @@ -339,13 +378,53 @@ void CTC_NodeVisitor::visit(AST::ExprNode_CallMethod& node) // - TODO: Support case where a trait is known throw ::std::runtime_error("Unknown type in CallMethod"); } + else if( type.is_type_param() ) + { + const char *name = type.type_param().c_str(); + // Find this name in the current set of type params + const TypeRef& p_type = m_tc.get_type_param(name); + // Iterate bounds on type param + TypeRef ret_type; + for( const auto& t : p_type.traits() ) + { + DEBUG("- Trait " << t.path()); + const AST::Trait& trait = t.path().bound_trait(); + // - Find method on one of them + for( const auto& m : trait.functions() ) + { + DEBUG(" > method: " << m.name << " search: " << node.m_method.name()); + if( m.name == node.m_method.name() ) + { + DEBUG(" > Found method"); + if( m.data.params().n_params() ) + { + throw ::std::runtime_error("TODO: Call method with params"); + } + ret_type = m.data.rettype(); + } + } + } + if( ret_type.is_wildcard() ) + { + throw ::std::runtime_error("Couldn't find method"); + } + } else { + TypeRef ltype = type; + DEBUG("Resolving args in " << ltype); + ltype.resolve_args( [&](const char* name) { + DEBUG("- Looking up " << name); + return m_tc.get_type_param(name); + } ); + // TODO: Replace generic references in 'type' (copying the type) with + // '_: Bounds' (allowing method lookup to succeed) // - Search for a method on this type - AST::Function& fcn = m_tc.m_crate.lookup_method(type, node.m_method.name().c_str()); + // TODO: Requires passing knowledge of in-scope traits (or trying traits) + AST::Function& fcn = m_tc.m_crate.lookup_method(ltype, node.m_method.name().c_str()); if( fcn.params().n_params() != node.m_method.args().size() ) { - throw ::std::runtime_error("TODO: CallMethod with param count mismatch"); + throw ::std::runtime_error("CallMethod with param count mismatch"); } if( fcn.params().n_params() ) { diff --git a/src/types.cpp b/src/types.cpp index 7445dd03..e0287d01 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -85,6 +85,7 @@ void TypeRef::merge_with(const TypeRef& other) /// Resolve all Generic/Argument types to the value returned by the passed closure void TypeRef::resolve_args(::std::function fcn) { + DEBUG("" << *this); switch(m_class) { case TypeRef::ANY: @@ -99,6 +100,7 @@ void TypeRef::resolve_args(::std::function fcn) case TypeRef::ARRAY: for( auto& t : m_inner_types ) t.resolve_args(fcn); + break; case TypeRef::GENERIC: *this = fcn(m_path[0].name().c_str()); break; @@ -255,6 +257,9 @@ bool TypeRef::operator==(const TypeRef& x) const case TypeRef::ANY: //os << "TagAny"; os << "_"; + if( tr.m_inner_types.size() ) { + os << ": {" << tr.m_inner_types << "}"; + } break; case TypeRef::UNIT: //os << "TagUnit"; diff --git a/src/types.hpp b/src/types.hpp index 27d74662..b40c9424 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -53,6 +53,11 @@ public: TypeRef(): m_class(ANY) {} + struct TagBoundedAny {}; + TypeRef(TagBoundedAny, ::std::vector traits): + m_class(ANY), + m_inner_types( ::std::move(traits) ) + {} struct TagUnit {}; // unit maps to a zero-length tuple, just easier to type TypeRef(TagUnit): @@ -138,8 +143,13 @@ public: bool is_reference() const { return m_class == REFERENCE; } const ::std::string& type_param() const { assert(is_type_param()); return m_path[0].name(); } AST::Path& path() { assert(is_path() || m_class == ASSOCIATED); return m_path; } + const AST::Path& path() const { assert(is_path() || m_class == ASSOCIATED); return m_path; } ::std::vector& sub_types() { return m_inner_types; } - + const ::std::vector& sub_types() const { return m_inner_types; } + + void add_trait(TypeRef trait) { assert(is_wildcard()); m_inner_types.push_back( ::std::move(trait) ); } + const ::std::vector& traits() const { assert(is_wildcard()); return m_inner_types; } + bool operator==(const TypeRef& x) const; bool operator!=(const TypeRef& x) const { return !(*this == x); } -- cgit v1.2.3