summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge (sonata) <tpg@mutabah.net>2015-01-20 21:30:26 +0800
committerJohn Hodge (sonata) <tpg@mutabah.net>2015-01-20 21:30:26 +0800
commit2b9a03f6b71446dceb12f5d097f066e3c9354210 (patch)
tree4fb6f405b20aa52f161c80c5e6d994d48a574e1f
parentdcb89ac3be47b79af382fff4b10a25004072fe98 (diff)
downloadmrust-2b9a03f6b71446dceb12f5d097f066e3c9354210.tar.gz
Type merging hacked in
-rw-r--r--src/ast/path.hpp6
-rw-r--r--src/convert/typecheck_expr.cpp29
-rw-r--r--src/types.cpp95
-rw-r--r--src/types.hpp32
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);