summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast/ast.cpp23
-rw-r--r--src/ast/ast.hpp3
-rw-r--r--src/convert/typecheck_expr.cpp149
-rw-r--r--src/types.cpp33
-rw-r--r--src/types.hpp2
5 files changed, 157 insertions, 53 deletions
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index b8de6d4c..80bc3c57 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -105,10 +105,27 @@ 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)
+::rust::option<Impl&> Crate::find_impl(const TypeRef& trait, const TypeRef& type)
{
- // TODO: Support autoderef here?
- throw ParseError::Generic( FMT("TODO: Lookup impl of " << trait << " for type " << type));
+ // TODO: Support autoderef here? NO
+ if( trait.is_wildcard() && !type.is_path() )
+ {
+ // You can only have 'impl <type> { }' for user-defined types (i.e. paths)
+ // - Return failure
+ return ::rust::option<Impl&>();
+ }
+
+ for( auto implptr : m_impl_index )
+ {
+ Impl& impl = *implptr;
+ // TODO: Pass to impl for comparison (handles type params)
+ if( impl.trait() == trait && impl.type() == type )
+ {
+ return ::rust::option<Impl&>(impl);
+ }
+ }
+ DEBUG("No impl of " << trait << " for " << type);
+ return ::rust::option<Impl&>();
}
Function& Crate::lookup_method(const TypeRef& type, const char *name)
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 94ffbb79..40a44b78 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -483,6 +483,7 @@ public:
class Crate:
public Serialisable
{
+ ::std::vector<Impl*> m_impl_index;
public:
Module m_root_module;
::std::map< ::std::string, ExternCrate> m_extern_crates;
@@ -499,7 +500,7 @@ public:
::std::map< ::std::string, ExternCrate>& 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);
+ ::rust::option<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/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp
index 4fa62fe2..c647ed54 100644
--- a/src/convert/typecheck_expr.cpp
+++ b/src/convert/typecheck_expr.cpp
@@ -1,4 +1,9 @@
/*
+ * 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"
@@ -15,6 +20,7 @@ class CTypeChecker:
::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;
@@ -42,7 +48,8 @@ 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);
+
+ void iterate_traits(::std::function<bool(const TypeRef& trait)> fcn);
};
class CTC_NodeVisitor:
public AST::NodeVisitor
@@ -191,19 +198,18 @@ void CTypeChecker::handle_function(AST::Path path, AST::Function& fcn)
end_scope();
}
-void CTypeChecker::lookup_method(const TypeRef& type, const char* name)
+void CTypeChecker::iterate_traits(::std::function<bool(const TypeRef& trait)> fcn)
{
- DEBUG("(type = " << type << ", name = " << name << ")");
- // 1. Look for inherent methods on the type
- // 2. Iterate all in-scope traits, and locate an impl of that trait for this type
- //for(auto traitptr : m_scope_traits )
- //{
- // if( !traitptr ) continue;
- // const auto& trait = *traitptr;
- // if( trait.has_method(name) && trait.find_impl(type) )
- // {
- // }
- //}
+ for( auto scopei = m_scopes.end(); scopei-- != m_scopes.begin(); )
+ {
+ for( auto& trait : scopei->traits )
+ {
+ if( !fcn(trait) )
+ {
+ return;
+ }
+ }
+ }
}
/// Named value - leaf
@@ -372,54 +378,99 @@ void CTC_NodeVisitor::visit(AST::ExprNode_CallMethod& node)
// Locate method
const TypeRef& type = node.m_val->get_res_type();
DEBUG("CallMethod - type = " << type);
- if( type.is_wildcard() )
- {
- // No idea (yet)
- // - TODO: Support case where a trait is known
- throw ::std::runtime_error("Unknown type in CallMethod");
- }
- else if( type.is_type_param() )
+
+ // 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
{
- 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() )
+ // 1. Handle bounded wildcard types
+ if( ltype.is_wildcard() )
{
- DEBUG("- Trait " << t.path());
- const AST::Trait& trait = t.path().bound_trait();
- // - Find method on one of them
- for( const auto& m : trait.functions() )
+ if( ltype.traits().size() == 0 ) {
+ DEBUG("- Unconstrained wildcard, returning");
+ return ;
+ }
+
+ for( const auto& t : ltype.traits() )
{
- DEBUG(" > method: " << m.name << " search: " << node.m_method.name());
- if( m.name == node.m_method.name() )
+ DEBUG("- Trait " << t.path());
+ AST::Trait& trait = const_cast<AST::Trait&>( t.path().bound_trait() );
+ // - Find method on one of them
+ for( auto& m : trait.functions() )
{
- DEBUG(" > Found method");
- if( m.data.params().n_params() )
+ DEBUG(" > method: " << m.name << " search: " << node.m_method.name());
+ if( m.name == node.m_method.name() )
{
- throw ::std::runtime_error("TODO: Call method with params");
+ DEBUG(" > Found method");
+ fcnp = &m.data;
+ break;
}
- ret_type = m.data.rettype();
}
+ if(fcnp) break;
}
+ if(fcnp) break;
}
- if( ret_type.is_wildcard() )
+ else
{
- throw ::std::runtime_error("Couldn't find method");
+ // 2. Find inherent impl
+ auto oimpl = m_tc.m_crate.find_impl(TypeRef(), ltype);
+ if( oimpl.is_some() )
+ {
+ AST::Impl& impl = oimpl.unwrap();
+ // 1.1. Search impl for this method
+ for(auto& fcn : impl.functions())
+ {
+ if( fcn.name == name )
+ {
+ fcnp = &fcn.data;
+ 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.find_impl(trait, ltype);
+ if( oimpl.is_some() )
+ {
+ AST::Impl& impl = oimpl.unwrap();
+ for(auto& fcn : impl.functions())
+ {
+ if( fcn.name == name )
+ {
+ fcnp = &fcn.data;
+ break;
+ }
+ }
+ }
+ return fcnp == nullptr;
+ });
}
- }
- else
+ if( fcnp )
+ break;
+ deref_count ++;
+ } while( ltype.deref(true) );
+
+ if( fcnp )
{
- // Replace generic references in 'type' (copying the type) with
- // '_: Bounds' (allowing method lookup to succeed)
- TypeRef ltype = type;
- ltype.resolve_args( [&](const char* name) {
- return m_tc.get_type_param(name);
- } );
- // - Search for a method on this type
- // 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());
+ 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().n_params() != node.m_method.args().size() )
{
throw ::std::runtime_error("CallMethod with param count mismatch");
diff --git a/src/types.cpp b/src/types.cpp
index 58d820f5..33b564dd 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -33,6 +33,39 @@ const char* coretype_name(const eCoreType ct ) {
return "NFI";
}
+/// Replace this type reference with a dereferenced version
+bool TypeRef::deref(bool is_implicit)
+{
+ switch(m_class)
+ {
+ case TypeRef::ANY:
+ // TODO: Check if the _ is bounded by Deref<Output=?>, if so use that
+ throw ::std::runtime_error("Dereferencing _");
+ break;
+ case TypeRef::UNIT:
+ throw ::std::runtime_error("Dereferencing ()");
+ case TypeRef::PRIMITIVE:
+ throw ::std::runtime_error("Dereferencing a primtive type");
+ case TypeRef::GENERIC:
+ throw ::std::runtime_error("Dereferencing a generic");
+ case TypeRef::REFERENCE:
+ *this = m_inner_types[0];
+ return true;
+ case TypeRef::POINTER:
+ // raw pointers can't be implicitly dereferenced
+ if( is_implicit )
+ return false;
+ *this = m_inner_types[0];
+ return true;
+ case TypeRef::TUPLE:
+ case TypeRef::ARRAY:
+ case TypeRef::PATH:
+ throw ::std::runtime_error("TODO: Search for an impl of Deref");
+ case TypeRef::ASSOCIATED:
+ throw ::std::runtime_error("TODO: TypeRef::deref on ASSOCIATED");
+ }
+}
+
/// Merge the contents of the passed type with this type
///
/// \note Both types must be of the same form (i.e. both be tuples)
diff --git a/src/types.hpp b/src/types.hpp
index b40c9424..2cbbd0bb 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -126,6 +126,8 @@ public:
m_inner_types( {::std::move(base), ::std::move(trait)} )
{}
+ /// Dereference the type (return the result of *type_instance)
+ bool deref(bool is_implicit);
/// Merge with another type (combines known aspects, conflitcs cause an exception)
void merge_with(const TypeRef& other);
/// Replace 'GENERIC' entries with the return value of the closure