diff options
author | John Hodge (sonata) <tpg@mutabah.net> | 2015-01-20 21:30:26 +0800 |
---|---|---|
committer | John Hodge (sonata) <tpg@mutabah.net> | 2015-01-20 21:30:26 +0800 |
commit | 2b9a03f6b71446dceb12f5d097f066e3c9354210 (patch) | |
tree | 4fb6f405b20aa52f161c80c5e6d994d48a574e1f | |
parent | dcb89ac3be47b79af382fff4b10a25004072fe98 (diff) | |
download | mrust-2b9a03f6b71446dceb12f5d097f066e3c9354210.tar.gz |
Type merging hacked in
-rw-r--r-- | src/ast/path.hpp | 6 | ||||
-rw-r--r-- | src/convert/typecheck_expr.cpp | 29 | ||||
-rw-r--r-- | src/types.cpp | 95 | ||||
-rw-r--r-- | src/types.hpp | 32 |
4 files changed, 152 insertions, 10 deletions
diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 02e028d7..4576ceec 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -165,9 +165,13 @@ public: _(Static, static, STATIC) #undef _ const Enum& bound_enum() const { - assert(m_binding_type == ENUM || m_binding_type == ENUM_VAR); + assert(m_binding_type == ENUM || m_binding_type == ENUM_VAR); // Kinda evil, given that it has its own union entry return *m_binding.enum_; } + const unsigned int bound_idx() const { + assert(m_binding_type == ENUM_VAR); + return m_binding.enumvar.idx; + } ::std::vector<PathNode>& nodes() { return m_nodes; } const ::std::vector<PathNode>& nodes() const { return m_nodes; } diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp index 3886c2ea..7f14ad2a 100644 --- a/src/convert/typecheck_expr.cpp +++ b/src/convert/typecheck_expr.cpp @@ -65,8 +65,10 @@ void CTypeChecker::lookup_method(const TypeRef& type, const char* name) //} } +/// 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() ) { @@ -76,8 +78,32 @@ void CTC_NodeVisitor::visit(AST::ExprNode_NamedValue& node) case AST::Path::STATIC: node.get_res_type() = p.bound_static().type(); break; + case AST::Path::ENUM_VAR: { + const AST::Enum& enm = p.bound_enum(); + auto idx = p.bound_idx(); + // Enum variant: + // - Check that this variant takes no arguments + if( !enm.variants()[idx].second.is_unit() ) + throw ::std::runtime_error( FMT("Used a non-unit variant as a raw value - " << enm.variants()[idx].second)); + // - 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().n_params(); + 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(tp); + break; } + default: + throw ::std::runtime_error( FMT("Unknown binding type on named value : "<<p) ); } } + else + { + throw ::std::runtime_error( FMT("TODO: Get type from local : "<<p) ); + } } void CTC_NodeVisitor::visit(AST::ExprNode_LetBinding& node) @@ -115,7 +141,8 @@ void CTC_NodeVisitor::visit(AST::ExprNode_LetBinding& node) // - If neither concrete, merge requirements of both else { - throw ::std::runtime_error("TODO - Merge type requirements"); + 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); diff --git a/src/types.cpp b/src/types.cpp index c5a29695..d0bd0cc3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -26,6 +26,99 @@ const char* coretype_name(const eCoreType ct ) { return "NFI"; } +void TypeRef::merge_with(const TypeRef& other) +{ + // Ignore if other is wildcard + if( other.m_class == TypeRef::ANY ) + return; + + if( m_class == TypeRef::ANY ) { + *this = other; + } + + if( m_class != other.m_class ) + throw ::std::runtime_error("TypeRef::merge_with - Types not compatible"); + + switch(m_class) + { + case TypeRef::ANY: + break; + case TypeRef::UNIT: + case TypeRef::PRIMITIVE: + if( other != *this && other.is_concrete() ) + throw ::std::runtime_error("TypeRef::merge_with - Types not compatible"); + break; + case TypeRef::TUPLE: + // Other is known not to be wildcard, and is also a tuple, so it must be the same size + if( m_inner_types.size() != other.m_inner_types.size() ) + throw ::std::runtime_error("TypeRef::merge_with - Types not compatible [tuple sz]"); + for(unsigned int i = 0; i < m_inner_types.size(); i ++) + { + m_inner_types[i].merge_with( other.m_inner_types[i] ); + } + break; + case TypeRef::REFERENCE: + case TypeRef::POINTER: + if( m_is_inner_mutable != other.m_is_inner_mutable ) + throw ::std::runtime_error("TypeRef::merge_with - Types not compatible [inner mut]"); + assert( m_inner_types.size() == 1 ); + assert( other.m_inner_types.size() == 1 ); + m_inner_types[0].merge_with( other.m_inner_types[0] ); + break; + case TypeRef::ARRAY: + throw ::std::runtime_error("TODO: TypeRef::merge_with on ARRAY"); + case TypeRef::GENERIC: + throw ::std::runtime_error("TODO: TypeRef::merge_with on GENERIC"); + case TypeRef::PATH: + throw ::std::runtime_error("TODO: TypeRef::merge_with on PATH"); + case TypeRef::ASSOCIATED: + throw ::std::runtime_error("TODO: TypeRef::merge_with on ASSOCIATED"); + } +} + +bool TypeRef::is_concrete() const +{ + switch(m_class) + { + case TypeRef::ANY: + return false; + case TypeRef::UNIT: + case TypeRef::PRIMITIVE: + return true; + case TypeRef::TUPLE: + case TypeRef::REFERENCE: + case TypeRef::POINTER: + case TypeRef::ARRAY: + for(const auto& t : m_inner_types ) + if( not t.is_concrete() ) + return false; + return true; + case TypeRef::GENERIC: + // Well, I guess a generic param is "concrete" + return true; + case TypeRef::PATH: + for(const auto& n : m_path.nodes()) + { + for(const auto& p : n.args()) + if( not p.is_concrete() ) + return false; + } + return true; + case TypeRef::ASSOCIATED: + for(const auto& t : m_inner_types ) + if( not t.is_concrete() ) + return false; + for(const auto& n : m_path.nodes()) + { + for(const auto& p : n.args()) + if( not p.is_concrete() ) + return false; + } + return true; + } + throw ::std::runtime_error( FMT("BUGCHECK - Invalid type class on " << *this) ); +} + bool TypeRef::operator==(const TypeRef& x) const { if(m_class != x.m_class) @@ -82,7 +175,7 @@ bool TypeRef::operator==(const TypeRef& x) const break; case TypeRef::TUPLE: //os << "TagTuple, {" << tr.m_inner_types << "}"; - os << "(" << tr.m_inner_types << ")"; + os << "(" << tr.m_inner_types << ",)"; break; case TypeRef::REFERENCE: //os << "TagReference, " << (tr.m_is_inner_mutable ? "mut" : "const") << ", " << tr.m_inner_types[0]; diff --git a/src/types.hpp b/src/types.hpp index 7e478df5..2c3a2056 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -13,13 +13,26 @@ class ExprNode; class Expr;
}
+/// Representation of restrictions placed on a type before it is made concrete
+// Possible bounds:
+// - Known to be a tuple of various inner types
+// - Unknown struct / enum
+// - Impls a trait
+// - Unknown
+class TypeBounds
+{
+
+};
+
+/// A type
class TypeRef:
public Serialisable
{
+ /// Class
enum Class {
- ANY,
- UNIT,
- PRIMITIVE,
+ ANY, //< '_' - Wildcard
+ UNIT, //< '()' - Unit / void
+ PRIMITIVE, //< Any primitive (builtin type)
TUPLE,
REFERENCE,
POINTER,
@@ -108,17 +121,22 @@ public: m_inner_types( {::std::move(base), ::std::move(trait)} )
{}
+ /// Merge with another type (combines known aspects, conflitcs cause an exception)
+ void merge_with(const TypeRef& other);
+
+ /// Returns true if the type is fully known (all sub-types are not wildcards)
+ bool is_concrete() const;
+
bool is_wildcard() const { return m_class == ANY; }
+ bool is_unit() const { return m_class == UNIT; }
bool is_path() const { return m_class == PATH; }
bool is_type_param() const { return m_class == GENERIC; }
- AST::Path& path() { assert(is_path()); return m_path; }
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; }
::std::vector<TypeRef>& sub_types() { return m_inner_types; }
bool operator==(const TypeRef& x) const;
- bool operator!=(const TypeRef& x) const {
- return !(*this == x);
- }
+ bool operator!=(const TypeRef& x) const { return !(*this == x); }
friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr);
|