diff options
author | John Hodge <tpg@mutabah.net> | 2016-08-13 16:15:15 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-08-13 16:15:15 +0800 |
commit | 51973a64fe30d9481eabe9456982ab50542116f0 (patch) | |
tree | a7f86c13437d4b57c2dde413150d92a78d529b31 /src | |
parent | b8a79dcc476ad85f0c7c0fcf646fcdb4bb357219 (diff) | |
download | mrust-51973a64fe30d9481eabe9456982ab50542116f0.tar.gz |
HIR Expand - Replace assign and boolean operator overloads with calls
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_expand/ufcs_everything.cpp | 282 |
1 files changed, 280 insertions, 2 deletions
diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index 17168fbd..ff45f8d2 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -3,7 +3,7 @@ * - By John Hodge (Mutabah/thePowersGang) * * hir_expand/ufcs_everything.cpp - * - HIR Expansion - All calls (methods, values, ...) as UFCS path calls + * - Expand all function calls (_CallMethod, and _CallValue) and operator overloads to _CallPath */ #include <hir/visitor.hpp> #include <hir/expr.hpp> @@ -50,7 +50,10 @@ namespace { } } - + // ---------- + // _CallValue + // ---------- + // Replace with a UFCS call using the now-known type void visit(::HIR::ExprNode_CallValue& node) override { const auto& sp = node.span(); @@ -136,11 +139,17 @@ namespace { mv$(args) ); + // Populate the cache for later passes auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; arg_types.push_back( mv$(self_arg_type) ); for(auto& ty : node.m_arg_types) arg_types.push_back( mv$(ty) ); } + + // ---------- + // _CallMethod + // ---------- + // Simple replacement void visit(::HIR::ExprNode_CallMethod& node) override { const auto& sp = node.span(); @@ -158,8 +167,277 @@ namespace { mv$(node.m_method_path), mv$(args) ); + // Populate the cache for later passes dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache = mv$(node.m_cache); } + + + static bool is_op_valid_shift(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) + { + // Integer with any other integer is valid, others go to overload resolution + if( ty_l.m_data.is_Primitive() && ty_r.m_data.is_Primitive() ) { + switch(ty_l.m_data.as_Primitive()) + { + case ::HIR::CoreType::Char: + case ::HIR::CoreType::Str: + case ::HIR::CoreType::Bool: + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + break; + default: + switch(ty_r.m_data.as_Primitive()) + { + case ::HIR::CoreType::Char: + case ::HIR::CoreType::Str: + case ::HIR::CoreType::Bool: + case ::HIR::CoreType::F32: + case ::HIR::CoreType::F64: + break; + default: + // RETURN early + return true; + } + break; + } + + } + return false; + } + static bool is_op_valid_bitmask(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) + { + // Equal integers and bool are valid + if( ty_l == ty_r ) { + TU_IFLET(::HIR::TypeRef::Data, ty_l.m_data, Primitive, e, + switch(e) + { + case ::HIR::CoreType::Char: + case ::HIR::CoreType::Str: + break; + default: + // RETURN early + return true; + } + ) + } + return false; + } + static bool is_op_valid_arith(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) + { + // Equal floats/integers are valid, others go to overload + if( ty_l == ty_r ) { + TU_IFLET(::HIR::TypeRef::Data, ty_l.m_data, Primitive, e, + switch(e) + { + case ::HIR::CoreType::Char: + case ::HIR::CoreType::Str: + case ::HIR::CoreType::Bool: + break; + default: + // RETURN early + return true; + } + ) + } + return false; + } + + // ------- + // _Assign + // ------- + // Replace with overload call if not a builtin supported operation + void visit(::HIR::ExprNode_Assign& node) override + { + const auto& sp = node.span(); + ::HIR::ExprVisitorDef::visit(node); + + const auto& ty_slot = node.m_slot->m_res_type; + const auto& ty_val = node.m_value->m_res_type; + + const char* langitem = nullptr; + const char* opname = nullptr; + #define _(opname) case ::HIR::ExprNode_Assign::Op::opname + switch( node.m_op ) + { + _(None): + ASSERT_BUG(sp, ty_slot == ty_val, "Types must equal for non-operator assignment, " << ty_slot << " != " << ty_val); + return ; + _(Shr): {langitem = "shr_assign"; opname = "shr_assign"; } if(0) + _(Shl): {langitem = "shl_assign"; opname = "shl_assign"; } if(0) + ; + if( is_op_valid_shift(ty_slot, ty_val) ) { + return ; + } + break; + + _(And): {langitem = "bitand_assign"; opname = "bitand_assign"; } if(0) + _(Or ): {langitem = "bitor_assign" ; opname = "bitor_assign" ; } if(0) + _(Xor): {langitem = "bitxor_assign"; opname = "bitxor_assign"; } if(0) + ; + if( is_op_valid_bitmask(ty_slot, ty_val) ) { + return ; + } + break; + + _(Add): {langitem = "add_assign"; opname = "add_assign"; } if(0) + _(Sub): {langitem = "sub_assign"; opname = "sub_assign"; } if(0) + _(Mul): {langitem = "mul_assign"; opname = "mul_assign"; } if(0) + _(Div): {langitem = "div_assign"; opname = "div_assign"; } if(0) + _(Mod): {langitem = "rem_assign"; opname = "rem_assign"; } if(0) + ; + if( is_op_valid_arith(ty_slot, ty_val) ) { + return ; + } + // - Fall down to overload replacement + break; + } + #undef _ + assert( langitem ); + assert( opname ); + + // Needs replacement, continue + ::HIR::PathParams trait_params; + trait_params.m_types.push_back( ty_val.clone() ); + ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), mv$(trait_params) }; + + auto slot_type_refmut = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, ty_slot.clone()); + ::std::vector< ::HIR::ExprNodeP> args; + args.push_back( NEWNODE( slot_type_refmut.clone(), UniOp, sp, + ::HIR::ExprNode_UniOp::Op::RefMut, mv$(node.m_slot) + ) ); + args.push_back( mv$(node.m_value) ); + m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, + ::HIR::Path(ty_slot.clone(), mv$(trait), opname), + mv$(args) + ); + + // Populate the cache for later passes + auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; + arg_types.push_back( mv$(slot_type_refmut) ); + arg_types.push_back( ty_val.clone() ); + arg_types.push_back( ::HIR::TypeRef::new_unit() ); + } + + void visit(::HIR::ExprNode_BinOp& node) override + { + const auto& sp = node.span(); + ::HIR::ExprVisitorDef::visit(node); + + const auto& ty_l = node.m_left->m_res_type; + const auto& ty_r = node.m_right->m_res_type; + + const char* langitem = nullptr; + const char* method = nullptr; + switch(node.m_op) + { + case ::HIR::ExprNode_BinOp::Op::CmpEqu: { langitem = "eq"; method = "eq"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpNEqu:{ langitem = "eq"; method = "ne"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLt: { langitem = "ord"; method = "lt"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLtE: { langitem = "ord"; method = "le"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGt: { langitem = "ord"; method = "gt"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGtE: { langitem = "ord"; method = "ge"; } if(0) + ; { + // 1. Check if the types are valid for primitive comparison + if( ty_l == ty_r ) { + TU_MATCH_DEF(::HIR::TypeRef::Data, (ty_l.m_data), (e), + ( + // Unknown - Overload + ), + (Pointer, + // Raw pointer, valid. + return ; + ), + // TODO: Should comparing &str be handled by the overload, or MIR? + (Primitive, + if( e != ::HIR::CoreType::Str ) { + return ; + } + ) + ) + } + // 2. If not, emit a call with params borrowed + ::HIR::PathParams trait_params; + trait_params.m_types.push_back( ty_r.clone() ); + ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), mv$(trait_params) }; + + auto ty_l_ref = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ty_l.clone() ); + auto ty_r_ref = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ty_r.clone() ); + + ::std::vector< ::HIR::ExprNodeP> args; + args.push_back( NEWNODE(ty_l_ref.clone(), UniOp, node.m_left->span(), + ::HIR::ExprNode_UniOp::Op::Ref, mv$(node.m_left) + ) ); + args.push_back( NEWNODE(ty_r_ref.clone(), UniOp, node.m_right->span(), + ::HIR::ExprNode_UniOp::Op::Ref, mv$(node.m_right) + ) ); + + m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, + ::HIR::Path(ty_l.clone(), mv$(trait), method), + mv$(args) + ); + + // Populate the cache for later passes + auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; + arg_types.push_back( mv$(ty_l_ref) ); + arg_types.push_back( mv$(ty_r_ref) ); + arg_types.push_back( ::HIR::TypeRef( ::HIR::CoreType::Bool ) ); + return ; + } break; + + case ::HIR::ExprNode_BinOp::Op::Xor: langitem = method = "bitxor"; if(0) + case ::HIR::ExprNode_BinOp::Op::Or : langitem = method = "bitor" ; if(0) + case ::HIR::ExprNode_BinOp::Op::And: langitem = method = "bitand"; if(0) + ; + if( is_op_valid_bitmask(ty_l, ty_r) ) { + return ; + } + break; + + case ::HIR::ExprNode_BinOp::Op::Shr: langitem = method = "shr"; if(0) + case ::HIR::ExprNode_BinOp::Op::Shl: langitem = method = "shr"; + if( is_op_valid_shift(ty_l, ty_r) ) { + return ; + } + break; + + case ::HIR::ExprNode_BinOp::Op::Add: langitem = method = "add"; if(0) + case ::HIR::ExprNode_BinOp::Op::Sub: langitem = method = "sub"; if(0) + case ::HIR::ExprNode_BinOp::Op::Mul: langitem = method = "mul"; if(0) + case ::HIR::ExprNode_BinOp::Op::Div: langitem = method = "div"; if(0) + case ::HIR::ExprNode_BinOp::Op::Mod: langitem = method = "rem"; + if( is_op_valid_arith(ty_l, ty_r) ) { + return ; + } + break; + + case ::HIR::ExprNode_BinOp::Op::BoolAnd: + case ::HIR::ExprNode_BinOp::Op::BoolOr: + ASSERT_BUG(sp, ty_l == ::HIR::TypeRef(::HIR::CoreType::Bool), "&& operator requires bool"); + ASSERT_BUG(sp, ty_r == ::HIR::TypeRef(::HIR::CoreType::Bool), "&& operator requires bool"); + return ; + } + assert(langitem); + assert(method); + + // Needs replacement, continue + ::HIR::PathParams trait_params; + trait_params.m_types.push_back( ty_r.clone() ); + ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), mv$(trait_params) }; + + ::std::vector< ::HIR::ExprNodeP> args; + args.push_back( mv$(node.m_left) ); + args.push_back( mv$(node.m_right) ); + + m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, + ::HIR::Path(ty_l.clone(), mv$(trait), method), + mv$(args) + ); + + // Populate the cache for later passes + auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; + arg_types.push_back( ty_l.clone() ); + arg_types.push_back( ty_r.clone() ); + arg_types.push_back( m_replacement->m_res_type.clone() ); + } }; class OuterVisitor: public ::HIR::Visitor |