summaryrefslogtreecommitdiff
path: root/src/hir_expand/annotate_value_usage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/hir_expand/annotate_value_usage.cpp')
-rw-r--r--src/hir_expand/annotate_value_usage.cpp399
1 files changed, 399 insertions, 0 deletions
diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp
new file mode 100644
index 00000000..ea560bbc
--- /dev/null
+++ b/src/hir_expand/annotate_value_usage.cpp
@@ -0,0 +1,399 @@
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * hir_expand/annotate_value_usage.cpp
+ * - Marks _Variable, _Index, _Deref, and _Field nodes with how the result is used
+ */
+#include <hir/visitor.hpp>
+#include <hir/expr.hpp>
+#include <hir_typeck/static.hpp>
+#include <algorithm>
+#include "main_bindings.hpp"
+
+namespace {
+
+ class ExprVisitor_Mark:
+ public ::HIR::ExprVisitor//Def
+ {
+ const StaticTraitResolve& m_resolve;
+ ::std::vector< ::HIR::ValueUsage> m_usage;
+
+ struct UsageGuard
+ {
+ ExprVisitor_Mark& m_parent;
+ bool m_pop;
+ UsageGuard(ExprVisitor_Mark& parent, bool pop):
+ m_parent(parent),
+ m_pop(pop)
+ {
+ }
+ ~UsageGuard()
+ {
+ if(m_pop) {
+ m_parent.m_usage.pop_back();
+ }
+ }
+ };
+
+ ::HIR::ValueUsage get_usage() const {
+ return (m_usage.empty() ? ::HIR::ValueUsage::Move : m_usage.back());
+ }
+ UsageGuard push_usage(::HIR::ValueUsage u) {
+ if( get_usage() == u ) {
+ return UsageGuard(*this, false);
+ }
+ else {
+ m_usage.push_back( u );
+ return UsageGuard(*this, true);
+ }
+ }
+
+ public:
+ ExprVisitor_Mark(const StaticTraitResolve& resolve):
+ m_resolve(resolve)
+ {}
+
+ void visit_root(::HIR::ExprPtr& root_ptr)
+ {
+ assert(root_ptr);
+ root_ptr->m_usage = this->get_usage();
+ auto expected_size = m_usage.size();
+ root_ptr->visit( *this );
+ assert( m_usage.size() == expected_size );
+ }
+ void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override
+ {
+ assert(node_ptr);
+ node_ptr->m_usage = this->get_usage();
+
+ auto expected_size = m_usage.size();
+ node_ptr->visit( *this );
+ assert( m_usage.size() == expected_size );
+ }
+
+ void visit(::HIR::ExprNode_Block& node) override
+ {
+ auto _ = this->push_usage( ::HIR::ValueUsage::Move );
+
+ for( auto& subnode : node.m_nodes ) {
+ this->visit_node_ptr(subnode);
+ }
+ }
+
+ void visit(::HIR::ExprNode_Return& node) override
+ {
+ auto _ = this->push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr( node.m_value );
+ }
+ void visit(::HIR::ExprNode_Let& node) override
+ {
+ if( node.m_value )
+ {
+ auto _ = this->push_usage( this->get_usage_for_pattern(node.m_pattern, node.m_type) );
+ this->visit_node_ptr( node.m_value );
+ }
+ }
+ void visit(::HIR::ExprNode_Loop& node) override
+ {
+ auto _ = this->push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr( node.m_code );
+ }
+ void visit(::HIR::ExprNode_LoopControl& node) override
+ {
+ // NOTE: Leaf
+ }
+ void visit(::HIR::ExprNode_Match& node) override
+ {
+ {
+ const auto& val_ty = node.m_value->m_res_type;
+ ::HIR::ValueUsage vu = ::HIR::ValueUsage::Unknown;
+ for( const auto& arm : node.m_arms )
+ {
+ for( const auto& pat : arm.m_patterns )
+ vu = ::std::max( vu, this->get_usage_for_pattern(pat, val_ty) );
+ }
+ auto _ = this->push_usage( vu );
+ this->visit_node_ptr( node.m_value );
+ }
+
+ auto _ = this->push_usage( ::HIR::ValueUsage::Move );
+ for(auto& arm : node.m_arms)
+ {
+ if( arm.m_cond ) {
+ this->visit_node_ptr( arm.m_cond );
+ }
+ this->visit_node_ptr( arm.m_code );
+ }
+ }
+ void visit(::HIR::ExprNode_If& node) override
+ {
+ auto _ = this->push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr( node.m_cond );
+ this->visit_node_ptr( node.m_true );
+ if( node.m_false ) {
+ this->visit_node_ptr( node.m_false );
+ }
+ }
+
+ void visit(::HIR::ExprNode_Assign& node) override
+ {
+ {
+ auto _ = this->push_usage( ::HIR::ValueUsage::Mutate );
+ this->visit_node_ptr(node.m_slot);
+ }
+ {
+ auto _ = this->push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr(node.m_value);
+ }
+ }
+ void visit(::HIR::ExprNode_UniOp& node) override
+ {
+ switch(node.m_op)
+ {
+ case ::HIR::ExprNode_UniOp::Op::Invert:
+ case ::HIR::ExprNode_UniOp::Op::Negate:
+ m_usage.push_back( ::HIR::ValueUsage::Move );
+ break;
+ case ::HIR::ExprNode_UniOp::Op::Ref:
+ m_usage.push_back( ::HIR::ValueUsage::Borrow );
+ break;
+ case ::HIR::ExprNode_UniOp::Op::RefMut:
+ m_usage.push_back( ::HIR::ValueUsage::Mutate );
+ break;
+ }
+
+ this->visit_node_ptr(node.m_value);
+
+ m_usage.pop_back();
+ }
+
+ void visit(::HIR::ExprNode_BinOp& node) override
+ {
+ switch(node.m_op)
+ {
+ case ::HIR::ExprNode_BinOp::Op::CmpEqu:
+ case ::HIR::ExprNode_BinOp::Op::CmpNEqu:
+ case ::HIR::ExprNode_BinOp::Op::CmpLt:
+ case ::HIR::ExprNode_BinOp::Op::CmpLtE:
+ case ::HIR::ExprNode_BinOp::Op::CmpGt:
+ case ::HIR::ExprNode_BinOp::Op::CmpGtE:
+ m_usage.push_back( ::HIR::ValueUsage::Borrow );
+ break;
+ default:
+ m_usage.push_back( ::HIR::ValueUsage::Move );
+ break;
+ }
+
+ this->visit_node_ptr(node.m_left);
+ this->visit_node_ptr(node.m_right);
+
+ m_usage.pop_back();
+ }
+ void visit(::HIR::ExprNode_Cast& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr(node.m_value);
+ }
+ void visit(::HIR::ExprNode_Unsize& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr(node.m_value);
+ }
+ void visit(::HIR::ExprNode_Index& node) override
+ {
+ // TODO: Override to ::Borrow if Res: Copy and moving
+ if( this->get_usage() == ::HIR::ValueUsage::Move && type_is_copy(node.m_res_type) ) {
+ auto _ = push_usage( ::HIR::ValueUsage::Borrow );
+ this->visit_node_ptr(node.m_value);
+ }
+ else {
+ this->visit_node_ptr(node.m_value);
+ }
+
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr(node.m_index);
+ }
+ void visit(::HIR::ExprNode_Deref& node) override
+ {
+ if( this->get_usage() == ::HIR::ValueUsage::Move && type_is_copy(node.m_res_type) ) {
+ auto _ = push_usage( ::HIR::ValueUsage::Borrow );
+ this->visit_node_ptr(node.m_value);
+ }
+ else {
+ this->visit_node_ptr(node.m_value);
+ }
+ }
+
+ void visit(::HIR::ExprNode_Field& node) override
+ {
+ // If taking this field by value, but the type is Copy - pretend it's a borrow.
+ if( this->get_usage() == ::HIR::ValueUsage::Move && type_is_copy(node.m_res_type) ) {
+ auto _ = push_usage( ::HIR::ValueUsage::Borrow );
+ this->visit_node_ptr(node.m_value);
+ }
+ else {
+ node.m_value->visit( *this );
+ }
+ }
+
+ void visit(::HIR::ExprNode_TupleVariant& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+
+ for( auto& val : node.m_args )
+ this->visit_node_ptr(val);
+ }
+ void visit(::HIR::ExprNode_CallPath& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+
+ for( auto& val : node.m_args )
+ this->visit_node_ptr(val);
+ }
+ void visit(::HIR::ExprNode_CallValue& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+
+ this->visit_node_ptr(node.m_value);
+ for( auto& val : node.m_args )
+ this->visit_node_ptr(val);
+ }
+ void visit(::HIR::ExprNode_CallMethod& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+
+ this->visit_node_ptr(node.m_value);
+ for( auto& val : node.m_args )
+ this->visit_node_ptr(val);
+ }
+
+ void visit(::HIR::ExprNode_Literal& node) override
+ {
+ }
+ void visit(::HIR::ExprNode_UnitVariant& node) override
+ {
+ }
+ void visit(::HIR::ExprNode_PathValue& node) override
+ {
+ }
+ void visit(::HIR::ExprNode_Variable& node) override
+ {
+ }
+
+ void visit(::HIR::ExprNode_StructLiteral& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+
+ if( node.m_base_value ) {
+ this->visit_node_ptr(node.m_base_value);
+ }
+ for( auto& fld_val : node.m_values ) {
+ this->visit_node_ptr(fld_val.second);
+ }
+ }
+ void visit(::HIR::ExprNode_Tuple& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+ for( auto& val : node.m_vals ) {
+ this->visit_node_ptr(val);
+ }
+ }
+ void visit(::HIR::ExprNode_ArrayList& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+ for( auto& val : node.m_vals ) {
+ this->visit_node_ptr(val);
+ }
+ }
+ void visit(::HIR::ExprNode_ArraySized& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr(node.m_val);
+ }
+
+ void visit(::HIR::ExprNode_Closure& node) override
+ {
+ auto _ = push_usage( ::HIR::ValueUsage::Move );
+ this->visit_node_ptr(node.m_code);
+ }
+
+ private:
+ ::HIR::ValueUsage get_usage_for_pattern( const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty ) const
+ {
+ // TODO: Detect if a by-value binding exists for a non-Copy type
+ return ::HIR::ValueUsage::Move;
+ }
+
+ bool type_is_copy(const ::HIR::TypeRef& ty) const
+ {
+ return m_resolve.type_is_copy(ty);
+ }
+ };
+
+
+ class OuterVisitor:
+ public ::HIR::Visitor
+ {
+ StaticTraitResolve m_resolve;
+ public:
+ OuterVisitor(const ::HIR::Crate& crate):
+ m_resolve(crate)
+ {}
+
+ void visit_expr(::HIR::ExprPtr& exp) override {
+ if( exp )
+ {
+ ExprVisitor_Mark ev { m_resolve };
+ ev.visit_root( exp );
+ }
+ }
+
+ // ------
+ // Code-containing items
+ // ------
+ void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override {
+ auto _ = this->m_resolve.set_item_generics(item.m_params);
+ ::HIR::Visitor::visit_function(p, item);
+ }
+ void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override {
+ // NOTE: No generics
+ ::HIR::Visitor::visit_static(p, item);
+ }
+ void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override {
+ // NOTE: No generics
+ ::HIR::Visitor::visit_constant(p, item);
+ }
+ void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
+ auto _ = this->m_resolve.set_item_generics(item.m_params);
+ ::HIR::Visitor::visit_enum(p, item);
+ }
+
+
+ void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override {
+ auto _ = this->m_resolve.set_impl_generics(item.m_params);
+ ::HIR::Visitor::visit_trait(p, item);
+ }
+
+ void visit_type_impl(::HIR::TypeImpl& impl) override
+ {
+ TRACE_FUNCTION_F("impl " << impl.m_type);
+ auto _ = this->m_resolve.set_impl_generics(impl.m_params);
+
+ ::HIR::Visitor::visit_type_impl(impl);
+ }
+ void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override
+ {
+ TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type);
+ auto _ = this->m_resolve.set_impl_generics(impl.m_params);
+
+ ::HIR::Visitor::visit_trait_impl(trait_path, impl);
+ }
+ };
+}
+
+void HIR_Expand_AnnotateUsage(::HIR::Crate& crate)
+{
+ OuterVisitor ov(crate);
+ ov.visit_crate( crate );
+}