diff options
author | John Hodge <tpg@mutabah.net> | 2016-06-04 11:43:45 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-06-04 11:43:45 +0800 |
commit | f9e94f5e907af0ce205a6b04deb5b0d35a4e1bc4 (patch) | |
tree | 55562cd226fa90c5c9ac24efa7eb4e4d74cf719f | |
parent | 6fad166a1c3b18bda2c9c6c981d72628cd256a00 (diff) | |
download | mrust-f9e94f5e907af0ce205a6b04deb5b0d35a4e1bc4.tar.gz |
HIR Typeck - Coming along, close to needing coercions
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/hir/expr.hpp | 49 | ||||
-rw-r--r-- | src/hir/from_ast.cpp | 4 | ||||
-rw-r--r-- | src/hir/from_ast_expr.cpp | 57 | ||||
-rw-r--r-- | src/hir/pattern.cpp | 118 | ||||
-rw-r--r-- | src/hir/pattern.hpp | 3 | ||||
-rw-r--r-- | src/hir/type.cpp | 9 | ||||
-rw-r--r-- | src/hir/type.hpp | 4 | ||||
-rw-r--r-- | src/hir/visitor.cpp | 11 | ||||
-rw-r--r-- | src/hir_typeck/expr.cpp | 52 |
10 files changed, 290 insertions, 19 deletions
@@ -44,7 +44,7 @@ OBJ += resolve/use.o resolve/index.o resolve/absolute.o OBJ += hir/from_ast.o hir/from_ast_expr.o OBJ += hir/hir.o OBJ += hir/crate_ptr.o hir/type_ptr.o hir/expr_ptr.o -OBJ += hir/type.o hir/path.o hir/expr.o +OBJ += hir/type.o hir/path.o hir/expr.o hir/pattern.o OBJ += hir/visitor.o OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/bind.o OBJ += hir_typeck/outer.o hir_typeck/expr.o diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 1f36158c..5343228e 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -55,7 +55,7 @@ struct ExprNode_Return: ::HIR::ExprNodeP m_value; ExprNode_Return(::HIR::ExprNodeP value): - ExprNode(::HIR::TypeRef({})), + ExprNode(::HIR::TypeRef(TypeRef::TagUnit{})), m_value( mv$(value) ) { } @@ -69,7 +69,7 @@ struct ExprNode_Loop: ::HIR::ExprNodeP m_code; ExprNode_Loop(::std::string label, ::HIR::ExprNodeP code): - ExprNode(::HIR::TypeRef({})), + ExprNode(::HIR::TypeRef(TypeRef::TagUnit{})), m_label( mv$(label) ), m_code( mv$(code) ) {} @@ -84,7 +84,7 @@ struct ExprNode_LoopControl: //::HIR::ExprNodeP m_value; ExprNode_LoopControl(::std::string label, bool cont): - ExprNode(::HIR::TypeRef({})), + ExprNode(::HIR::TypeRef(TypeRef::TagUnit{})), m_label( mv$(label) ), m_continue( cont ) {} @@ -99,7 +99,7 @@ struct ExprNode_Let: ::HIR::ExprNodeP m_value; ExprNode_Let(::HIR::Pattern pat, ::HIR::TypeRef ty, ::HIR::ExprNodeP val): - ExprNode(::HIR::TypeRef({})), + ExprNode(::HIR::TypeRef(TypeRef::TagUnit{})), m_pattern( mv$(pat) ), m_type( mv$(ty) ), m_value( mv$(val) ) @@ -161,7 +161,7 @@ struct ExprNode_Assign: ExprNodeP m_value; ExprNode_Assign(Op op, ::HIR::ExprNodeP slot, ::HIR::ExprNodeP value): - ExprNode(::HIR::TypeRef({})), + ExprNode(::HIR::TypeRef(TypeRef::TagUnit{})), m_op(op), m_slot( mv$(slot) ), m_value( mv$(value) ) @@ -340,7 +340,39 @@ struct ExprNode_Literal: ExprNode_Literal(Data data): m_data( mv$(data) ) - {} + { + TU_MATCH(Data, (m_data), (e), + (Integer, + if( e.m_type != ::HIR::CoreType::Str ) { + m_res_type = ::HIR::TypeRef::Data::make_Primitive(e.m_type); + } + ), + (Float, + if( e.m_type != ::HIR::CoreType::Str ) { + m_res_type = ::HIR::TypeRef::Data::make_Primitive(e.m_type); + } + ), + (Boolean, + m_res_type = ::HIR::TypeRef::Data::make_Primitive( ::HIR::CoreType::Bool ); + ), + (String, + m_res_type = ::HIR::TypeRef::Data::make_Borrow({ + ::HIR::BorrowType::Shared, + box$( ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Primitive(::HIR::CoreType::Str) ) ) + }); + ), + (ByteString, + m_res_type = ::HIR::TypeRef::Data::make_Borrow({ + ::HIR::BorrowType::Shared, + box$( ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Array({ + box$( ::HIR::TypeRef(::HIR::TypeRef::Data::make_Primitive(::HIR::CoreType::U8)) ), + ::HIR::ExprPtr(), + e.size() + }) ) ) + }); + ) + ) + } NODE_METHODS(); }; @@ -403,6 +435,11 @@ struct ExprNode_ArrayList: ::std::vector< ::HIR::ExprNodeP> m_vals; ExprNode_ArrayList(::std::vector< ::HIR::ExprNodeP> vals): + ExprNode( ::HIR::TypeRef::Data::make_Array({ + box$( ::HIR::TypeRef() ), + ::HIR::ExprPtr(), + vals.size() + }) ), m_vals( mv$(vals) ) {} diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 8681a078..626b3348 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -478,8 +478,8 @@ switch(e.core_type) { case CORETYPE_BOOL: return ::HIR::TypeRef( ::HIR::CoreType::Bool ); - case CORETYPE_CHAR: return ::HIR::TypeRef( ::HIR::CoreType::Str ); - case CORETYPE_STR : return ::HIR::TypeRef( ::HIR::CoreType::Char ); + case CORETYPE_CHAR: return ::HIR::TypeRef( ::HIR::CoreType::Char ); + case CORETYPE_STR : return ::HIR::TypeRef( ::HIR::CoreType::Str ); case CORETYPE_F32: return ::HIR::TypeRef( ::HIR::CoreType::F32 ); case CORETYPE_F64: return ::HIR::TypeRef( ::HIR::CoreType::F64 ); diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index f5e9b31a..b26b7874 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -265,6 +265,7 @@ struct LowerHIR_ExprNode_Visitor: v.m_label, LowerHIR_ExprNode_Inner(*v.m_code) ) ); + assert( m_rv->m_res_type.m_data.is_Tuple() ); break; case ::AST::ExprNode_Loop::WHILE: { ::std::vector< ::HIR::ExprNodeP> code; @@ -280,6 +281,7 @@ struct LowerHIR_ExprNode_Visitor: v.m_label, ::HIR::ExprNodeP(new ::HIR::ExprNode_Block(false, mv$(code))) ) ); + assert( m_rv->m_res_type.m_data.is_Tuple() ); break; } case ::AST::ExprNode_Loop::WHILELET: { ::std::vector< ::HIR::ExprNode_Match::Arm> arms; @@ -304,12 +306,67 @@ struct LowerHIR_ExprNode_Visitor: mv$(arms) )) ) ); + assert( m_rv->m_res_type.m_data.is_Tuple() ); break; } case ::AST::ExprNode_Loop::FOR: // NOTE: This should already be desugared (as a pass before resolve) BUG(v.get_pos(), "Encountered still-sugared for loop"); break; } + + // TODO: Iterate the constructed loop and determine if there are any `break` statements pointing to it + { + struct LoopVisitor: + public ::HIR::ExprVisitorDef + { + const ::std::string& top_label; + bool top_is_broken; + ::std::vector< const ::std::string*> name_stack; + + LoopVisitor(const ::std::string& top_label): + top_label(top_label), + top_is_broken(false), + name_stack() + {} + + void visit(::HIR::ExprNode_Loop& node) override { + if( node.m_label != "" ) { + this->name_stack.push_back( &node.m_label ); + } + ::HIR::ExprVisitorDef::visit(node); + if( node.m_label != "" ) { + this->name_stack.pop_back( ); + } + } + void visit(::HIR::ExprNode_LoopControl& node) override { + ::HIR::ExprVisitorDef::visit(node); + + if( node.m_continue ) { + } + else { + for( auto it = this->name_stack.rbegin(); it != this->name_stack.rend(); ++ it ) + { + if( node.m_label == **it ) + return ; + } + if( node.m_label == this->top_label ) { + this->top_is_broken = true; + } + else { + // break is for a higher loop + } + } + } + }; + + auto& loop_node = dynamic_cast< ::HIR::ExprNode_Loop&>(*m_rv);; + LoopVisitor lv { loop_node.m_label }; + loop_node.m_code->visit(lv); + if( ! lv.top_is_broken ) { + // If the loop never hit a 'break', the loop yields ! not () + loop_node.m_res_type.m_data = ::HIR::TypeRef::Data::make_Diverge({}); + } + } } virtual void visit(::AST::ExprNode_Match& v) override { ::std::vector< ::HIR::ExprNode_Match::Arm> arms; diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp new file mode 100644 index 00000000..64b132a3 --- /dev/null +++ b/src/hir/pattern.cpp @@ -0,0 +1,118 @@ + +#include "pattern.hpp" + +namespace HIR { + ::std::ostream& operator<<(::std::ostream& os, const Pattern::Value& x) { + TU_MATCH(Pattern::Value, (x), (e), + (Integer, + // TODO: Print with type + os << e.value; + ), + (String, + os << "\"" << e << "\""; + ), + (Named, + os << e; + ) + ) + return os; + } + ::std::ostream& operator<<(::std::ostream& os, const Pattern& x) { + if( x.m_binding.is_valid() ) { + if( x.m_binding.m_mutable ) + os << "mut "; + switch(x.m_binding.m_type) + { + case PatternBinding::Type::Move: break; + case PatternBinding::Type::Ref: os << "ref "; break; + case PatternBinding::Type::MutRef: os << "ref mut "; break; + } + os << x.m_binding.m_name << " @ "; + } + TU_MATCH(Pattern::Data, (x.m_data), (e), + (Any, + os << "_"; + ), + (Box, + os << "box " << *e.sub; + ), + (Ref, + switch(e.type) + { + case BorrowType::Shared: os << "&"; break; + case BorrowType::Unique: os << "&mut "; break; + case BorrowType::Owned: os << "&move "; break; + } + os << *e.sub; + ), + (Tuple, + os << "("; + for(const auto& s : e.sub_patterns) + os << s << ", "; + os << ")"; + ), + (StructTuple, + os << e.path; + os << "("; + for(const auto& s : e.sub_patterns) + os << s << ", "; + os << ")"; + ), + (StructTupleWildcard, + os << e.path; + ), + (Struct, + os << e.path; + os << "{ "; + for(const auto& ns : e.sub_patterns) + os << ns.first << ": " << ns.second << ", "; + os << "}"; + ), + + (Value, + os << e.val; + ), + (Range, + os << e.start << " ... " << e.end; + ), + + (EnumTuple, + os << e.path; + os << "("; + for(const auto& s : e.sub_patterns) + os << s << ", "; + os << ")"; + ), + (EnumTupleWildcard, + os << e.path; + ), + (EnumStruct, + os << e.path; + os << "{ "; + for(const auto& ns : e.sub_patterns) + os << ns.first << ": " << ns.second << ", "; + os << "}"; + ), + (Slice, + os << "["; + for(const auto& s : e.sub_patterns) + os << s << ", "; + os << "]"; + ), + (SplitSlice, + os << "["; + for(const auto& s : e.leading) + os << s << ", "; + if( e.extra_bind.is_valid() ) { + os << e.extra_bind.m_name << " @ "; + } + os << ".. "; + for(const auto& s : e.trailing) + os << s << ", "; + os << "]"; + ) + ) + return os; + } +} + diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index c7b0fe7d..4eefa181 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -52,6 +52,7 @@ struct Pattern (String, ::std::string), (Named, Path) ); + friend ::std::ostream& operator<<(::std::ostream& os, const Pattern::Value& x); TAGGED_UNION(Data, Any, // Irrefutable / destructuring @@ -108,6 +109,8 @@ struct Pattern PatternBinding m_binding; Data m_data; + + friend ::std::ostream& operator<<(::std::ostream& os, const Pattern& x); }; } diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 5ee00cfd..17da7c4c 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -64,7 +64,12 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const os << ")"; ), (Array, - os << "[" << *e.inner << "; " << "/*sz*/" << "]"; + os << "[" << *e.inner << "; "; + if( e.size_val != ~0u ) + os << e.size_val; + else + os << "/*sz*/"; + os << "]"; ), (Slice, os << "[" << *e.inner << "]"; @@ -124,7 +129,7 @@ namespace { { TU_MATCH(::HIR::TypeRef::Data, (m_data), (e), (Infer, - return ::HIR::TypeRef( Data::make_Infer({}) ); + return ::HIR::TypeRef( Data::make_Infer(e) ); ), (Diverge, return ::HIR::TypeRef( Data::make_Diverge({}) ); diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 8db8d406..9fe13872 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -114,6 +114,10 @@ struct TypeRef TypeRef& operator=(TypeRef&& ) = default; TypeRef& operator=(const TypeRef&) = delete; + struct TagUnit {}; + TypeRef(TagUnit ): + m_data( Data::make_Tuple({}) ) + {} TypeRef(::std::vector< ::HIR::TypeRef> sts): m_data( Data::make_Tuple(mv$(sts)) ) {} diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 23acf4e4..d2ee9f74 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -88,26 +88,32 @@ void ::HIR::Visitor::visit_module(::HIR::Module& mod) void ::HIR::Visitor::visit_type_impl(::HIR::TypeImpl& impl) { + TRACE_FUNCTION_F("impl.m_type=" << impl.m_type); this->visit_params(impl.m_params); this->visit_type(impl.m_type); for(auto& method : impl.m_methods) { + DEBUG("method " << method.first); this->visit_function(method.second); } } void ::HIR::Visitor::visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) { + TRACE_FUNCTION_F("trait_path=" << trait_path); this->visit_params(impl.m_params); this->visit_path_params(impl.m_trait_args); this->visit_type(impl.m_type); for(auto& ent : impl.m_methods) { + DEBUG("method " << ent.first); this->visit_function(ent.second); } for(auto& ent : impl.m_constants) { + DEBUG("const " << ent.first); this->visit_expr(ent.second); } for(auto& ent : impl.m_types) { + DEBUG("type " << ent.first); this->visit_type(ent.second); } } @@ -125,11 +131,13 @@ void ::HIR::Visitor::visit_type_alias(::HIR::TypeAlias& item) } void ::HIR::Visitor::visit_trait(::HIR::Trait& item) { + TRACE_FUNCTION; this->visit_params(item.m_params); for(auto& par : item.m_parent_traits) { this->visit_generic_path(par, ::HIR::Visitor::PathContext::TYPE); } for(auto& i : item.m_types) { + DEBUG("type " << i.first); this->visit_params(i.second.m_params); this->visit_type(i.second.m_default); } @@ -137,12 +145,15 @@ void ::HIR::Visitor::visit_trait(::HIR::Trait& item) TU_MATCH(::HIR::TraitValueItem, (i.second), (e), (None, ), (Constant, + DEBUG("constant " << i.first); this->visit_constant(e); ), (Static, + DEBUG("static " << i.first); this->visit_static(e); ), (Function, + DEBUG("method " << i.first); this->visit_function(e); ) ) diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index 2a00406d..cd1ceccb 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -738,11 +738,12 @@ namespace { // Adds a rule that two types must be equal void apply_equality(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right) { - assert( !left.m_data.is_Infer() || left.m_data.as_Infer().index != ~0u ); + TRACE_FUNCTION_F(left << ", " << right); + assert( ! left.m_data.is_Infer() || left.m_data.as_Infer().index != ~0u ); assert( !right.m_data.is_Infer() || right.m_data.as_Infer().index != ~0u ); - DEBUG("apply_equality(" << left << ", " << right << ")"); const auto& l_t = this->get_type(left); const auto& r_t = this->get_type(right); + DEBUG("- l_t = " << l_t << ", r_t = " << r_t); TU_IFLET(::HIR::TypeRef::Data, r_t.m_data, Infer, r_e, TU_IFLET(::HIR::TypeRef::Data, l_t.m_data, Infer, l_e, // Both are infer, unify the two @@ -769,6 +770,7 @@ namespace { ) else { root_ivar.type = box$( left.clone() ); + DEBUG("Set IVar " << r_e.index << " = " << *root_ivar.type); } } ) @@ -793,7 +795,11 @@ namespace { ) else { // Neither are infer - both should be of the same form - // TODO: What if one of these is `!`? + // - If either side is `!`, return early (diverging type, matches anything) + if( l_t.m_data.is_Diverge() || r_t.m_data.is_Diverge() ) { + return ; + } + // - If tags don't match, error if( l_t.m_data.tag() != r_t.m_data.tag() ) { // Type error this->dump(); @@ -829,10 +835,20 @@ namespace { TODO(sp, "Recurse in apply_equality Slice - " << l_t << " and " << r_t); ), (Tuple, - TODO(sp, "Recurse in apply_equality Tuple - " << l_t << " and " << r_t); + if( l_e.size() != r_e.size() ) { + ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - Tuples are of different length"); + } + for(unsigned int i = 0; i < l_e.size(); i ++) + { + this->apply_equality(sp, l_e[i], r_e[i]); + } ), (Borrow, - TODO(sp, "Recurse in apply_equality Borrow - " << l_t << " and " << r_t); + if( l_e.type != r_e.type ) { + // TODO: This could be allowed (using coercions) + ERROR(sp, E0000, "Type mismatch between " << l_t << " and " << r_t << " - Borrow classes differ"); + } + this->apply_equality(sp, *l_e.inner, *r_e.inner); ), (Pointer, TODO(sp, "Recurse in apply_equality Pointer - " << l_t << " and " << r_t); @@ -906,28 +922,41 @@ namespace { void visit_node(::HIR::ExprNode& node) override { this->context.add_ivars(node.m_res_type); + DEBUG(typeid(node).name() << " : " << node.m_res_type); } void visit(::HIR::ExprNode_Block& node) override { ::HIR::ExprVisitorDef::visit(node); - assert( node.m_nodes.size() > 0 ); - this->context.apply_equality(node.span(), node.m_res_type, node.m_nodes.back()->m_res_type); + TRACE_FUNCTION_F("{ }"); + + if( node.m_nodes.size() ) { + this->context.apply_equality(node.span(), node.m_res_type, node.m_nodes.back()->m_res_type); + } + else { + this->context.apply_equality(node.span(), node.m_res_type, ::HIR::TypeRef( ::HIR::TypeRef::TagUnit() )); + } } void visit(::HIR::ExprNode_Let& node) override { ::HIR::ExprVisitorDef::visit(node); + TRACE_FUNCTION_F("let " << node.m_pattern << ": " << node.m_type); this->context.add_ivars(node.m_type); this->context.add_binding(node.m_pattern, node.m_type); + if( node.m_value ) { + this->context.apply_equality(node.span(), node.m_type, node.m_value->m_res_type); + } } void visit(::HIR::ExprNode_Match& node) override { ::HIR::ExprVisitorDef::visit(node); + TRACE_FUNCTION_F("match ..."); for(auto& arm : node.m_arms) { + DEBUG("ARM " << arm.m_patterns); for(auto& pat : arm.m_patterns) { this->context.add_binding(pat, node.m_value->m_res_type); @@ -939,6 +968,7 @@ namespace { void visit(::HIR::ExprNode_If& node) override { ::HIR::ExprVisitorDef::visit(node); + TRACE_FUNCTION_F("if ..."); this->context.apply_equality(node.span(), node.m_res_type, node.m_true->m_res_type); if( node.m_false ) { this->context.apply_equality(node.span(), node.m_res_type, node.m_false->m_res_type); @@ -979,7 +1009,9 @@ void Typecheck_Code(TypecheckContext context, const ::HIR::TypeRef& result_type, ExprVisitor_Enum visitor { context }; root_node.visit( visitor ); } - context.apply_equality(root_node.span(), root_node.m_res_type, result_type); + DEBUG("- Apply RV"); + context.apply_equality(root_node.span(), result_type, root_node.m_res_type); + context.dump(); // 2. Iterate through nodes applying rules until nothing changes { ExprVisitor_Run visitor { context }; @@ -1106,6 +1138,7 @@ namespace { for( auto& arg : item.m_args ) { typeck_context.add_binding( arg.first, arg.second ); } + DEBUG("Function code"); Typecheck_Code( mv$(typeck_context), item.m_return, *item.m_code ); } } @@ -1114,6 +1147,7 @@ namespace { if( &*item.m_value ) { TypecheckContext typeck_context { }; + DEBUG("Static value"); Typecheck_Code( mv$(typeck_context), item.m_type, *item.m_value ); } } @@ -1122,6 +1156,7 @@ namespace { if( &*item.m_value ) { TypecheckContext typeck_context { }; + DEBUG("Const value"); Typecheck_Code( mv$(typeck_context), item.m_type, *item.m_value ); } } @@ -1136,6 +1171,7 @@ namespace { { TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, TypecheckContext typeck_context { }; + DEBUG("Enum value"); Typecheck_Code( mv$(typeck_context), enum_type, *e ); ) } |