diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ast/expr.hpp | 1 | ||||
-rw-r--r-- | src/ast/path.cpp | 10 | ||||
-rw-r--r-- | src/ast/path.hpp | 3 | ||||
-rw-r--r-- | src/convert/resolve.cpp | 18 | ||||
-rw-r--r-- | src/convert/typecheck_params.cpp | 84 | ||||
-rw-r--r-- | src/types.cpp | 33 | ||||
-rw-r--r-- | src/types.hpp | 7 |
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( ¶ms ); +} + /// 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);
|