summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/expr.hpp1
-rw-r--r--src/ast/path.cpp10
-rw-r--r--src/ast/path.hpp3
-rw-r--r--src/convert/resolve.cpp18
-rw-r--r--src/convert/typecheck_params.cpp84
-rw-r--r--src/types.cpp33
-rw-r--r--src/types.hpp7
7 files changed, 148 insertions, 8 deletions
diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp
index 60ed6f2f..db55c80c 100644
--- a/src/ast/expr.hpp
+++ b/src/ast/expr.hpp
@@ -435,6 +435,7 @@ public:
{
}
+ bool is_valid() const { return m_node.get() != nullptr; }
ExprNode& node() { assert(m_node.get()); return *m_node; }
::std::shared_ptr<ExprNode> take_node() { assert(m_node.get()); return ::std::move(m_node); }
void visit_nodes(NodeVisitor& v);
diff --git a/src/ast/path.cpp b/src/ast/path.cpp
index aff3586d..fd543120 100644
--- a/src/ast/path.cpp
+++ b/src/ast/path.cpp
@@ -25,6 +25,10 @@ const ::std::vector<TypeRef>& PathNode::args() const
{
return m_params;
}
+bool PathNode::operator==(const PathNode& x) const
+{
+ return m_name == x.m_name && m_params == x.m_params;
+}
::std::ostream& operator<<(::std::ostream& os, const PathNode& pn) {
#if PRETTY_PATH_PRINT
os << "::";
@@ -299,6 +303,12 @@ Path& Path::operator+=(const Path& other)
append(node);
return *this;
}
+
+bool Path::operator==(const Path& x) const
+{
+ return m_class == x.m_class && m_crate == x.m_crate && m_nodes == x.m_nodes;
+}
+
::std::ostream& operator<<(::std::ostream& os, const Path& path)
{
#if PRETTY_PATH_PRINT
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index e390d9aa..01c8ed03 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -37,6 +37,7 @@ public:
::std::vector<TypeRef>& args() { return m_params; }
const ::std::vector<TypeRef>& args() const;
+ bool operator==(const PathNode& x) const;
friend ::std::ostream& operator<<(::std::ostream& os, const PathNode& pn);
SERIALISABLE_PROTOTYPES();
@@ -169,6 +170,8 @@ public:
PathNode& operator[](size_t idx) { return m_nodes[idx]; }
const PathNode& operator[](size_t idx) const { return m_nodes[idx]; }
+ bool operator==(const Path& x) const;
+
SERIALISABLE_PROTOTYPES();
friend ::std::ostream& operator<<(::std::ostream& os, const Path& path);
friend ::Serialiser& operator<<(Serialiser& s, Path::Class pc);
diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp
index 3fd7b7ea..2e961f1f 100644
--- a/src/convert/resolve.cpp
+++ b/src/convert/resolve.cpp
@@ -44,6 +44,7 @@ public:
CPathResolver(const AST::Crate& crate);
virtual void handle_path(AST::Path& path, CASTIterator::PathMode mode) override;
+ 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;
@@ -207,6 +208,7 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode)
if( mode == MODE_TYPE )
{
DEBUG("Local type " << path[0].name());
+ throw ParseError::BugCheck("Local types should be handled in handle_type");
return ;
}
@@ -271,6 +273,22 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode)
throw ParseError::Generic("Name resolution failed");
}
}
+void CPathResolver::handle_type(TypeRef& type)
+{
+ if( type.is_path() && type.path().is_relative() && type.path().size() == 1 )
+ {
+ const auto& name = type.path()[0].name();
+ if( lookup_local(LocalItem::TYPE, name).is_some() )
+ {
+ type = TypeRef(TypeRef::TagArg(), name);
+ }
+ else
+ {
+ // Not a type param, fall back to other checks
+ }
+ }
+ CASTIterator::handle_type(type);
+}
void CPathResolver::handle_expr(AST::ExprNode& node)
{
CResolvePaths_NodeVisitor nv(*this);
diff --git a/src/convert/typecheck_params.cpp b/src/convert/typecheck_params.cpp
index 31b578d7..e6afeac5 100644
--- a/src/convert/typecheck_params.cpp
+++ b/src/convert/typecheck_params.cpp
@@ -10,9 +10,18 @@ class CGenericParamChecker:
public CASTIterator
{
int m_within_expr = 0;
+ ::std::vector<const AST::TypeParams*> m_params_stack;
public:
virtual void handle_path(AST::Path& path, CASTIterator::PathMode pm) override;
virtual void handle_expr(AST::ExprNode& root) override;
+ virtual void start_scope() override;
+ virtual void end_scope() override;
+ virtual void handle_params(AST::TypeParams& params) override;
+
+private:
+ bool has_impl_for_param(const ::std::string name, const TypeRef& trait) const;
+ bool has_impl(const TypeRef& type, const TypeRef& trait) const;
+ void check_generic_params(const AST::TypeParams& info, ::std::vector<TypeRef>& types, bool allow_infer = false);
};
class CNodeVisitor:
@@ -25,14 +34,62 @@ public:
{}
};
-bool has_impl(const TypeRef& type, const TypeRef& trait)
+// === CODE ===
+bool CGenericParamChecker::has_impl_for_param(const ::std::string name, const TypeRef& trait) const
+{
+ const AST::TypeParams* tps = nullptr;
+ // Locate params set that contains the passed name
+ DEBUG("Searching stack for '" << name << "'");
+ for( const auto ptr : m_params_stack )
+ {
+ if( ptr )
+ {
+ DEBUG("Trying " << *ptr);
+ for( const auto& p : ptr->params() )
+ {
+ if(p.name() == name) {
+ DEBUG(" - Found " << p);
+ tps = ptr;
+ break ;
+ }
+ }
+ }
+ }
+
+ if( !tps )
+ {
+ throw ::std::runtime_error(FMT("Param '"<<name<<"' isn't in scope"));
+ }
+ DEBUG("Found block " << *tps);
+
+ // Search bound list for the passed trait
+ for( const auto& bound : tps->bounds() )
+ {
+ if( bound.is_trait() && bound.name() == name )
+ {
+ DEBUG("bound.type() {" << bound.type() << "} == trait {" << trait << "}");
+ if( bound.type() == 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 TypeRef& trait) const
{
+ DEBUG("(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)
- throw ::std::runtime_error( FMT("TODO: Enumerate bounds on type param " << type.type_param() << " for matches to trait") );
+ if( has_impl_for_param(type.type_param(), trait) )
+ {
+ return true;
+ }
}
else
{
@@ -47,7 +104,7 @@ bool has_impl(const TypeRef& type, const TypeRef& trait)
/// \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 check_generic_params(const AST::TypeParams& info, ::std::vector<TypeRef>& types, bool allow_infer = false)
+void CGenericParamChecker::check_generic_params(const AST::TypeParams& info, ::std::vector<TypeRef>& types, bool allow_infer)
{
DEBUG("(info = " << info << ", types = {" << types << "}");
// TODO: Need to correctly handle lifetime params here, they should be in a different list
@@ -114,15 +171,12 @@ void check_generic_params(const AST::TypeParams& info, ::std::vector<TypeRef>& t
{
throw ::std::runtime_error( FMT("No matching impl of "<<trait<<" for "<<type));
}
-
- throw ::std::runtime_error( FMT("TODO: Check if " << type << " impls " << trait) );
}
}
}
}
}
-// === CODE ===
void CGenericParamChecker::handle_path(AST::Path& path, CASTIterator::PathMode pm)
{
DEBUG("path = " << path);
@@ -165,11 +219,27 @@ void CGenericParamChecker::handle_expr(AST::ExprNode& root)
m_within_expr -= 1;
}
+void CGenericParamChecker::start_scope()
+{
+ m_params_stack.push_back(nullptr);
+}
+void CGenericParamChecker::end_scope()
+{
+ assert( m_params_stack.size() > 0 );
+ while( m_params_stack.back() != nullptr )
+ m_params_stack.pop_back();
+}
+void CGenericParamChecker::handle_params(AST::TypeParams& params)
+{
+ m_params_stack.push_back( &params );
+}
+
/// Typecheck generic parameters (ensure that they match all generic bounds)
void Typecheck_GenericParams(AST::Crate& crate)
{
- DEBUG(" --- ");
+ DEBUG(" >>> ");
CGenericParamChecker chk;
chk.handle_module(AST::Path({}), crate.root_module());
+ DEBUG(" <<< ");
}
diff --git a/src/types.cpp b/src/types.cpp
index 230fae77..f674d446 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -4,6 +4,39 @@
#include "ast/ast.hpp"
+bool TypeRef::operator==(const TypeRef& x) const
+{
+ if(m_class != x.m_class)
+ return false;
+ switch(m_class)
+ {
+ case TypeRef::ANY:
+ case TypeRef::UNIT:
+ return true;
+ case TypeRef::PRIMITIVE:
+ return m_core_type == x.m_core_type;
+ case TypeRef::TUPLE:
+ return m_inner_types == x.m_inner_types;
+ case TypeRef::REFERENCE:
+ case TypeRef::POINTER:
+ return m_is_inner_mutable == x.m_is_inner_mutable && m_inner_types == x.m_inner_types;
+ case TypeRef::ARRAY:
+ if(m_inner_types[0] != x.m_inner_types[0])
+ return false;
+ if(m_size_expr.get())
+ {
+ throw ::std::runtime_error("TODO: Sized array comparisons");
+ }
+ return true;
+ case TypeRef::GENERIC:
+ throw ::std::runtime_error("BUGCHECK - Can't compare generic type");
+ case TypeRef::PATH:
+ return m_path == x.m_path;
+ case TypeRef::ASSOCIATED:
+ return m_path == x.m_path && m_inner_types == x.m_inner_types;
+ }
+}
+
::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr) {
os << "TypeRef(";
switch(tr.m_class)
diff --git a/src/types.hpp b/src/types.hpp
index 175e9c48..7e478df5 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -114,7 +114,12 @@ public:
AST::Path& path() { assert(is_path()); return m_path; }
const ::std::string& type_param() const { assert(is_type_param()); return m_path[0].name(); }
::std::vector<TypeRef>& sub_types() { return m_inner_types; }
-
+
+ bool operator==(const TypeRef& x) const;
+ bool operator!=(const TypeRef& x) const {
+ return !(*this == x);
+ }
+
friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr);
static const char* class_name(TypeRef::Class c);