diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | src/hir/expr.cpp | 2 | ||||
-rw-r--r-- | src/hir/expr.hpp | 5 | ||||
-rw-r--r-- | src/hir/expr_ptr.cpp | 54 | ||||
-rw-r--r-- | src/hir/expr_ptr.hpp | 44 | ||||
-rw-r--r-- | src/hir/expr_state.hpp | 42 | ||||
-rw-r--r-- | src/hir/hir.cpp | 64 | ||||
-rw-r--r-- | src/hir/hir.hpp | 13 | ||||
-rw-r--r-- | src/hir/item_path.hpp | 20 | ||||
-rw-r--r-- | src/hir_conv/bind.cpp | 133 | ||||
-rw-r--r-- | src/hir_conv/constant_evaluation.cpp | 1168 | ||||
-rw-r--r-- | src/hir_expand/annotate_value_usage.cpp | 11 | ||||
-rw-r--r-- | src/hir_expand/closures.cpp | 5 | ||||
-rw-r--r-- | src/hir_expand/const_eval_full.cpp | 952 | ||||
-rw-r--r-- | src/hir_expand/main_bindings.hpp | 6 | ||||
-rw-r--r-- | src/hir_expand/reborrow.cpp | 5 | ||||
-rw-r--r-- | src/hir_expand/ufcs_everything.cpp | 5 | ||||
-rw-r--r-- | src/hir_typeck/expr_visit.cpp | 9 | ||||
-rw-r--r-- | src/hir_typeck/expr_visit.hpp | 6 | ||||
-rw-r--r-- | src/main.cpp | 10 | ||||
-rw-r--r-- | src/mir/check.cpp | 2 | ||||
-rw-r--r-- | src/mir/cleanup.cpp | 2 | ||||
-rw-r--r-- | src/mir/dump.cpp | 6 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 33 | ||||
-rw-r--r-- | src/mir/main_bindings.hpp | 6 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 1 | ||||
-rw-r--r-- | src/mir/optimise.cpp | 141 |
27 files changed, 823 insertions, 1923 deletions
@@ -106,7 +106,6 @@ OBJ += hir_typeck/expr_check.o OBJ += hir_expand/annotate_value_usage.o hir_expand/closures.o OBJ += hir_expand/ufcs_everything.o OBJ += hir_expand/reborrow.o hir_expand/erased_types.o hir_expand/vtable.o -OBJ += hir_expand/const_eval_full.o OBJ += mir/mir.o mir/mir_ptr.o OBJ += mir/dump.o mir/helpers.o mir/visit_crate_mir.o OBJ += mir/from_hir.o mir/from_hir_match.o mir/mir_builder.o diff --git a/src/hir/expr.cpp b/src/hir/expr.cpp index 47f13052..07504ea7 100644 --- a/src/hir/expr.cpp +++ b/src/hir/expr.cpp @@ -172,7 +172,7 @@ DEF_VISIT(ExprNode_ArrayList, node, ) DEF_VISIT(ExprNode_ArraySized, node, visit_node_ptr(node.m_val); - visit_node_ptr(node.m_size); + //visit_node_ptr(node.m_size); ) DEF_VISIT(ExprNode_Closure, node, diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 37efac31..55a4eaf2 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -758,14 +758,15 @@ struct ExprNode_ArrayList: NODE_METHODS(); }; +// TODO: Might want a second variant for dynamically-sized arrays struct ExprNode_ArraySized: public ExprNode { ::HIR::ExprNodeP m_val; - ::HIR::ExprNodeP m_size; // TODO: Has to be constant + ::HIR::ExprPtr m_size; size_t m_size_val; - ExprNode_ArraySized(Span sp, ::HIR::ExprNodeP val, ::HIR::ExprNodeP size): + ExprNode_ArraySized(Span sp, ::HIR::ExprNodeP val, ::HIR::ExprPtr size): ExprNode(mv$(sp)), m_val( mv$(val) ), m_size( mv$(size) ), diff --git a/src/hir/expr_ptr.cpp b/src/hir/expr_ptr.cpp index 1f4cb1c3..fcef34bd 100644 --- a/src/hir/expr_ptr.cpp +++ b/src/hir/expr_ptr.cpp @@ -7,6 +7,7 @@ */ #include <hir/expr_ptr.hpp> #include <hir/expr.hpp> +#include <hir/expr_state.hpp> ::HIR::ExprPtr::ExprPtr(::std::unique_ptr< ::HIR::ExprNode> v): node( mv$(v) ) @@ -32,3 +33,56 @@ this->ptr = nullptr; return rv; } + +::HIR::ExprStatePtr::ExprStatePtr(ExprState x): + ptr(new ExprState( ::std::move(x) )) +{ +} +::HIR::ExprStatePtr::~ExprStatePtr() +{ + delete ptr; + ptr = nullptr; +} + + +const ::MIR::Function* HIR::ExprPtr::get_mir_opt() const +{ + if(!this->m_mir) + return nullptr; + return &*this->m_mir; +} +const ::MIR::Function& HIR::ExprPtr::get_mir_or_error(const Span& sp) const +{ + if(!this->m_mir) + BUG(sp, "No MIR"); + return *this->m_mir; +} +::MIR::Function& HIR::ExprPtr::get_mir_or_error_mut(const Span& sp) +{ + if(!this->m_mir) + BUG(sp, "No MIR"); + return *this->m_mir; +} +const ::MIR::Function* HIR::ExprPtr::get_ext_mir() const +{ + if(this->node) + return nullptr; + if(!this->m_mir) + return nullptr; + return &*this->m_mir; +} +::MIR::Function* HIR::ExprPtr::get_ext_mir_mut() +{ + if(this->node) + return nullptr; + if(!this->m_mir) + return nullptr; + return &*this->m_mir; +} +void HIR::ExprPtr::set_mir(::MIR::FunctionPointer mir) +{ + assert( !this->m_mir ); + m_mir = ::std::move(mir); +} + + diff --git a/src/hir/expr_ptr.hpp b/src/hir/expr_ptr.hpp index 97991bf2..b510e737 100644 --- a/src/hir/expr_ptr.hpp +++ b/src/hir/expr_ptr.hpp @@ -12,10 +12,14 @@ #include <mir/mir_ptr.hpp> +class Span; + namespace HIR { class TypeRef; class ExprNode; +class Crate; +class ExprState; class ExprPtrInner { @@ -53,20 +57,49 @@ public: ::HIR::ExprNode* operator->() { assert(ptr); return ptr; } const ::HIR::ExprNode* operator->() const { assert(ptr); return ptr; } }; +class ExprStatePtr +{ + ::HIR::ExprState* ptr; +public: + ExprStatePtr(): ptr(nullptr) {} + ExprStatePtr(ExprState ); + ExprStatePtr(const ExprStatePtr&) = delete; + ExprStatePtr(ExprStatePtr&& x): ptr(x.ptr) { x.ptr = nullptr; } + ~ExprStatePtr(); + + ExprStatePtr& operator=(const ExprStatePtr&) = delete; + ExprStatePtr& operator=(ExprStatePtr&& x) { this->~ExprStatePtr(); ptr = x.ptr; x.ptr = nullptr; return *this; } + + operator bool () const { return ptr != nullptr; } + + ::HIR::ExprState& operator*() { assert(ptr); return *ptr; } + const ::HIR::ExprState& operator*() const { assert(ptr); return *ptr; } + ::HIR::ExprState* operator->() { assert(ptr); return ptr; } + const ::HIR::ExprState* operator->() const { assert(ptr); return ptr; } +}; class ExprPtr { + //::HIR::Path m_path; ::HIR::ExprPtrInner node; + public: ::std::vector< ::HIR::TypeRef> m_bindings; ::std::vector< ::HIR::TypeRef> m_erased_types; + + // Public because too much relies on access to it ::MIR::FunctionPointer m_mir; + ::HIR::ExprStatePtr m_state; + public: ExprPtr() {} ExprPtr(::std::unique_ptr< ::HIR::ExprNode> _); + ExprPtr(const ExprPtr&) = delete; + ExprPtr(ExprPtr&&) = default; + /// Take the innards and turn into a unique_ptr - used so typecheck can edit the root node. ::std::unique_ptr< ::HIR::ExprNode> into_unique(); operator bool () const { return node; } ::HIR::ExprNode* get() const { return node.get(); } @@ -76,6 +109,17 @@ public: const ::HIR::ExprNode& operator*() const { return *node; } ::HIR::ExprNode* operator->() { return &*node; } const ::HIR::ExprNode* operator->() const { return &*node; } + + //void ensure_typechecked(const ::HIR::Crate& crate) const; + /// Get MIR (checks if the MIR should be available) + const ::MIR::Function* get_mir_opt() const; + const ::MIR::Function& get_mir_or_error(const Span& sp) const; + ::MIR::Function& get_mir_or_error_mut(const Span& sp); + /// Get external MIR, returns nullptr if none + const ::MIR::Function* get_ext_mir() const; + ::MIR::Function* get_ext_mir_mut(); + + void set_mir(::MIR::FunctionPointer mir); }; } // namespace HIR diff --git a/src/hir/expr_state.hpp b/src/hir/expr_state.hpp new file mode 100644 index 00000000..5491b4d3 --- /dev/null +++ b/src/hir/expr_state.hpp @@ -0,0 +1,42 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * hir/expr_state.hpp + * - Extra state for expression pointers + */ +#pragma once +#include <hir/hir.hpp> + +namespace HIR { + +struct ExprState +{ + ::HIR::SimplePath m_mod_path; + const ::HIR::Module& m_module; + + ::HIR::GenericParams* m_impl_generics; + ::HIR::GenericParams* m_item_generics; + + ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; + + enum class Stage { + Created, + TypecheckRequest, + Typecheck, + MirRequest, + Mir, + }; + mutable Stage stage; + + ExprState(const ::HIR::Module& mod_ptr, ::HIR::SimplePath mod_path): + m_mod_path(::std::move(mod_path)), + m_module(mod_ptr), + m_impl_generics(nullptr), + m_item_generics(nullptr), + stage(Stage::Created) + { + } +}; + +} diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index ee66ed5b..9f9bc1c3 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -10,6 +10,11 @@ #include "hir.hpp" #include <algorithm> #include <hir_typeck/common.hpp> +#include <hir_typeck/expr_visit.hpp> // for invoking typecheck +#include "item_path.hpp" +#include "expr_state.hpp" +#include <hir_expand/main_bindings.hpp> +#include <mir/main_bindings.hpp> namespace HIR { ::std::ostream& operator<<(::std::ostream& os, const ::HIR::Literal& v) @@ -1282,3 +1287,62 @@ bool ::HIR::Crate::find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type } return false; } + +const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const +{ + if( !ep ) + { + return &*ep.m_mir; + } + else + { + if( !ep.m_mir ) + { + ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip); + + auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep); + + // Ensure typechecked + if( ep.m_state->stage < ::HIR::ExprState::Stage::Typecheck ) + { + if( ep.m_state->stage == ::HIR::ExprState::Stage::TypecheckRequest ) + ERROR(Span(), E0000, "Loop in constant evaluation"); + ep.m_state->stage = ::HIR::ExprState::Stage::TypecheckRequest; + + // TODO: Set debug/timing stage + //Debug_SetStagePre("HIR Typecheck"); + // - Can store that on the Expr, OR get it from the item path + typeck::ModuleState ms { const_cast<::HIR::Crate&>(*this) }; + ms.m_impl_generics = ep.m_state->m_impl_generics; + ms.m_item_generics = ep.m_state->m_item_generics; + ms.m_traits = ep.m_state->m_traits; + Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut); + //Debug_SetStagePre("Expand HIR Annotate"); + HIR_Expand_AnnotateUsage_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR Closures"); + HIR_Expand_Closures_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR Calls"); + HIR_Expand_UfcsEverything_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR Reborrows"); + HIR_Expand_Reborrows_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR ErasedType"); + //HIR_Expand_ErasedType(*this, ep_mut); // - Maybe? + //Typecheck_Expressions_Validate(*hir_crate); + + ep.m_state->stage = ::HIR::ExprState::Stage::Typecheck; + } + // Generate MIR + if( ep.m_state->stage < ::HIR::ExprState::Stage::Mir ) + { + if( ep.m_state->stage == ::HIR::ExprState::Stage::MirRequest ) + ERROR(Span(), E0000, "Loop in constant evaluation"); + ep.m_state->stage = ::HIR::ExprState::Stage::MirRequest; + //Debug_SetStage("Lower MIR"); + HIR_GenerateMIR_Expr(*this, ip, ep_mut, args, ret_ty); + ep.m_state->stage = ::HIR::ExprState::Stage::Mir; + } + assert(ep.m_mir); + } + return &*ep.m_mir; + } +} diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 20b9ad58..8024e1c0 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -38,6 +38,8 @@ class Static; class ValueItem; class TypeItem; +class ItemPath; + template<typename Ent> struct VisEnt { @@ -343,6 +345,8 @@ public: // Contains types, traits, and modules ::std::unordered_map< ::std::string, ::std::unique_ptr<VisEnt<TypeItem>> > m_mod_items; + ::std::vector< ::std::pair<::std::string, Static> > m_inline_statics; + Module() {} Module(const Module&) = delete; Module(Module&& x) = default; @@ -533,6 +537,15 @@ public: bool find_trait_impls(const ::HIR::SimplePath& path, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback) const; bool find_auto_trait_impls(const ::HIR::SimplePath& path, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback) const; bool find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback) const; + + const ::MIR::Function* get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const; + const ::MIR::Function* get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::Function& fcn) const { + return get_or_gen_mir(ip, fcn.m_code, fcn.m_args, fcn.m_return); + } + const ::MIR::Function* get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::TypeRef& exp_ty) const { + static ::HIR::Function::args_t s_args; + return get_or_gen_mir(ip, ep, s_args, exp_ty); + } }; } // namespace HIR diff --git a/src/hir/item_path.hpp b/src/hir/item_path.hpp index 11e3b0f4..d19435eb 100644 --- a/src/hir/item_path.hpp +++ b/src/hir/item_path.hpp @@ -18,12 +18,17 @@ public: const ::HIR::PathParams* trait_params = nullptr; const char* name = nullptr; const char* crate_name = nullptr; + const ::HIR::Path* wrapped = nullptr; ItemPath(const ::std::string& crate): crate_name(crate.c_str()) {} ItemPath(const ItemPath& p, const char* n): parent(&p), name(n) {} + ItemPath(const ::HIR::Path& p): + wrapped(&p) + { + } ItemPath(const ::HIR::TypeRef& type): ty(&type) {} @@ -40,7 +45,14 @@ public: const ::HIR::PathParams* trait_args() const { return trait_params; } ::HIR::SimplePath get_simple_path() const { - if( parent ) { + if( wrapped ) { + assert(wrapped->m_data.is_Generic()); + return wrapped->m_data.as_Generic().m_path; + } + else if( trait && !name ) { + return trait->clone(); + } + else if( parent ) { assert(name); return parent->get_simple_path() + name; } @@ -51,6 +63,9 @@ public: } } ::HIR::Path get_full_path() const { + if( wrapped ) { + return wrapped->clone(); + } assert(parent); assert(name); @@ -95,6 +110,9 @@ public: } friend ::std::ostream& operator<<(::std::ostream& os, const ItemPath& x) { + if( x.wrapped ) { + return os << *x.wrapped; + } if( x.parent ) { os << *x.parent; } diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 5418da85..227ccd9f 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -13,6 +13,8 @@ #include <algorithm> // std::find_if #include <hir_typeck/static.hpp> +#include <hir_typeck/expr_visit.hpp> // For ModuleState +#include <hir/expr_state.hpp> void ConvertHIR_Bind(::HIR::Crate& crate); @@ -95,10 +97,35 @@ namespace { { const ::HIR::Crate& m_crate; + typeck::ModuleState m_ms; + + struct CurMod { + const ::HIR::Module* ptr; + const ::HIR::ItemPath* path; + } m_cur_module; + public: Visitor(const ::HIR::Crate& crate): - m_crate(crate) - {} + m_crate(crate), + m_ms(crate) + { + static ::HIR::ItemPath root_path(""); + m_cur_module.ptr = &crate.m_root_module; + m_cur_module.path = &root_path; + } + + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override + { + auto parent_mod = m_cur_module; + m_cur_module.ptr = &mod; + m_cur_module.path = &p; + + m_ms.push_traits(mod); + ::HIR::Visitor::visit_module(p, mod); + m_ms.pop_traits(mod); + + m_cur_module = parent_mod; + } void visit_trait_path(::HIR::TraitPath& p) override { @@ -400,17 +427,86 @@ namespace { ::HIR::Visitor::visit_type(ty); } - void visit_static(::HIR::ItemPath p, ::HIR::Static& i) override + void visit_type_impl(::HIR::TypeImpl& impl) override { - ::HIR::Visitor::visit_static(p, i); - visit_literal(Span(), i.m_value_res); + TRACE_FUNCTION_F("impl " << impl.m_type); + auto _ = this->m_ms.set_impl_generics(impl.m_params); + + const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr); + if(mod) + m_ms.push_traits(*mod); + ::HIR::Visitor::visit_type_impl(impl); + if(mod) + m_ms.pop_traits(*mod); } - void visit_constant(::HIR::ItemPath p, ::HIR::Constant& i) override + void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { - ::HIR::Visitor::visit_constant(p, i); - visit_literal(Span(), i.m_value_res); + TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type); + auto _ = this->m_ms.set_impl_generics(impl.m_params); + + const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr); + if(mod) + m_ms.push_traits(*mod); + m_ms.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) ); + ::HIR::Visitor::visit_trait_impl(trait_path, impl); + m_ms.m_traits.pop_back( ); + if(mod) + m_ms.pop_traits(*mod); + } + void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override + { + TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type << " { }"); + auto _ = this->m_ms.set_impl_generics(impl.m_params); + + const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr); + if(mod) + m_ms.push_traits(*mod); + ::HIR::Visitor::visit_marker_impl(trait_path, impl); + if(mod) + m_ms.pop_traits(*mod); } + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override + { + auto _ = this->m_ms.set_impl_generics(item.m_params); + ::HIR::Visitor::visit_trait(p, item); + } + // TODO: Are generics for types "item" or "impl"? + void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override + { + auto _ = this->m_ms.set_item_generics(item.m_params); + ::HIR::Visitor::visit_enum(p, item); + } + void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override + { + auto _ = this->m_ms.set_item_generics(item.m_params); + ::HIR::Visitor::visit_struct(p, item); + } + void visit_union(::HIR::ItemPath p, ::HIR::Union& item) override + { + auto _ = this->m_ms.set_item_generics(item.m_params); + ::HIR::Visitor::visit_union(p, item); + } + + void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override + { + auto _ = this->m_ms.set_item_generics(item.m_params); + ::HIR::Visitor::visit_function(p, item); + } + void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override + { + //auto _ = this->m_ms.set_item_generics(item.m_params); + ::HIR::Visitor::visit_static(p, item); + visit_literal(Span(), item.m_value_res); + } + void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override + { + auto _ = this->m_ms.set_item_generics(item.m_params); + ::HIR::Visitor::visit_constant(p, item); + visit_literal(Span(), item.m_value_res); + } + + // Actual expressions void visit_expr(::HIR::ExprPtr& expr) override { struct ExprVisitor: @@ -473,6 +569,11 @@ namespace { upper_visitor.visit_generic_path(node.m_path, ::HIR::Visitor::PathContext::TYPE); ::HIR::ExprVisitorDef::visit(node); } + void visit(::HIR::ExprNode_ArraySized& node) override + { + upper_visitor.visit_expr(node.m_size); + ::HIR::ExprVisitorDef::visit(node); + } void visit(::HIR::ExprNode_Closure& node) override { @@ -488,12 +589,22 @@ namespace { for(auto& ty : expr.m_erased_types) visit_type(ty); + // Set up the module state + { + expr.m_state = ::HIR::ExprStatePtr(::HIR::ExprState(*m_cur_module.ptr, m_cur_module.path->get_simple_path())); + expr.m_state->m_traits = m_ms.m_traits; // TODO: Only obtain the current module's set + expr.m_state->m_impl_generics = m_ms.m_impl_generics; + expr.m_state->m_item_generics = m_ms.m_item_generics; + } + + // Local expression if( expr.get() != nullptr ) { ExprVisitor v { *this }; (*expr).visit(v); } - else if( expr.m_mir ) + // External expression (has MIR) + else if( auto* mir = expr.get_ext_mir_mut() ) { struct H { static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv) @@ -546,9 +657,9 @@ namespace { ) } }; - for(auto& ty : expr.m_mir->locals) + for(auto& ty : mir->locals) this->visit_type(ty); - for(auto& block : expr.m_mir->blocks) + for(auto& block : mir->blocks) { for(auto& stmt : block.statements) { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 5a41e954..ec313e4a 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -14,18 +14,17 @@ #include <hir_typeck/common.hpp> // Monomorph #include <mir/helpers.hpp> #include <trans/target.hpp> +#include <hir/expr_state.hpp> namespace { - typedef ::std::vector< ::std::pair< ::std::string, ::HIR::Static> > t_new_values; - struct NewvalState { - t_new_values& newval_output; + const ::HIR::Module& mod; const ::HIR::ItemPath& mod_path; ::std::string name_prefix; unsigned int next_item_idx; - NewvalState(t_new_values& newval_output, const ::HIR::ItemPath& mod_path, ::std::string prefix): - newval_output(newval_output), + NewvalState(const ::HIR::Module& mod, const ::HIR::ItemPath& mod_path, ::std::string prefix): + mod(mod), mod_path(mod_path), name_prefix(prefix), next_item_idx(0) @@ -36,8 +35,9 @@ namespace { { auto name = FMT(name_prefix << next_item_idx); next_item_idx ++; - auto rv = (mod_path + name.c_str()).get_simple_path(); - newval_output.push_back( ::std::make_pair( mv$(name), ::HIR::Static { + DEBUG("mod_path = " << mod_path); + auto rv = mod_path.get_simple_path() + name.c_str(); + const_cast<::HIR::Module&>(mod).m_inline_statics.push_back( ::std::make_pair( mv$(name), ::HIR::Static { ::HIR::Linkage {}, false, mv$(type), @@ -47,8 +47,23 @@ namespace { return rv; } }; + struct Evaluator + { + const Span& root_span; + StaticTraitResolve resolve; + NewvalState nvs; + + Evaluator(const Span& sp, const ::HIR::Crate& crate, NewvalState nvs): + root_span(sp), + resolve(crate), + nvs( ::std::move(nvs) ) + { + } + + ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp); - ::HIR::Literal evaluate_constant(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args={}); + ::HIR::Literal evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args); + }; ::HIR::Literal clone_literal(const ::HIR::Literal& v) { @@ -155,10 +170,12 @@ namespace { } throw ""; } - EntPtr get_ent_fullpath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path, EntNS ns) + EntPtr get_ent_fullpath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path, EntNS ns, MonomorphState& out_ms) { TU_MATCH(::HIR::Path::Data, (path.m_data), (e), (Generic, + out_ms = MonomorphState {}; + out_ms.pp_method = &e.m_params; return get_ent_simplepath(sp, crate, e.m_path, ns); ), (UfcsInherent, @@ -191,6 +208,9 @@ namespace { } return false; }); + out_ms = MonomorphState {}; + out_ms.pp_method = &e.params; + out_ms.pp_impl = &e.impl_params; return rv; ), (UfcsKnown, @@ -225,6 +245,9 @@ namespace { } return false; }); + out_ms = MonomorphState {}; + out_ms.pp_method = &e.params; + // TODO: How to get pp_impl here? Needs specialisation magic. return rv; ), (UfcsUnknown, @@ -234,9 +257,9 @@ namespace { ) throw ""; } - const ::HIR::Function& get_function(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path) + const ::HIR::Function& get_function(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path, MonomorphState& out_ms) { - auto rv = get_ent_fullpath(sp, crate, path, EntNS::Value); + auto rv = get_ent_fullpath(sp, crate, path, EntNS::Value, out_ms); TU_IFLET( EntPtr, rv, Function, e, return *e; ) @@ -245,845 +268,114 @@ namespace { } } - ::HIR::Literal evaluate_constant_hir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprNode& expr, ::HIR::TypeRef exp_type, ::std::vector< ::HIR::Literal> args) + ::HIR::Literal Evaluator::evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) { - // TODO: Force this function/tree through the entire pipeline so we can MIR it? - // - Requires a HUGE change to the way the compiler operates. - struct Visitor: - public ::HIR::ExprVisitor - { - const ::HIR::Crate& m_crate; - NewvalState m_newval_state; - - ::std::vector< ::HIR::Literal> m_values; - - ::HIR::TypeRef m_exp_type; - ::HIR::TypeRef m_rv_type; - ::HIR::Literal m_rv; - - Visitor(const ::HIR::Crate& crate, NewvalState newval_state, ::HIR::TypeRef exp_ty): - m_crate(crate), - m_newval_state( mv$(newval_state) ), - m_exp_type( mv$(exp_ty) ) - {} - - void badnode(const ::HIR::ExprNode& node) const { - ERROR(node.span(), E0000, "Node " << typeid(node).name() << " not allowed in constant expression"); - } - - void visit(::HIR::ExprNode_Block& node) override { - TRACE_FUNCTION_F("_Block"); - - for(const auto& e : node.m_nodes) - { - e->visit(*this); - } - if( node.m_value_node ) - node.m_value_node->visit(*this); - else - ; - } - void visit(::HIR::ExprNode_Asm& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_Return& node) override { - TODO(node.span(), "ExprNode_Return"); - } - void visit(::HIR::ExprNode_Let& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_Loop& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_LoopControl& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_Match& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_If& node) override { - badnode(node); - } - - void visit(::HIR::ExprNode_Assign& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_BinOp& node) override { - TRACE_FUNCTION_F("_BinOp"); - - node.m_left->visit(*this); - auto left = mv$(m_rv); - auto ret_type = mv$(m_rv_type); - - node.m_right->visit(*this); - auto right = mv$(m_rv); - - if( left.tag() != right.tag() ) { - ERROR(node.span(), E0000, "ExprNode_BinOp - Types mismatched - " << left.tag_str() << " != " << right.tag_str()); - } - - // Keep m_rv_type - 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: - ERROR(node.span(), E0000, "ExprNode_BinOp - Comparisons"); - break; - case ::HIR::ExprNode_BinOp::Op::BoolAnd: - case ::HIR::ExprNode_BinOp::Op::BoolOr: - ERROR(node.span(), E0000, "ExprNode_BinOp - Logicals"); - break; + // TODO: Full-blown miri + TRACE_FUNCTION_F("exp=" << exp << ", args=" << args); - case ::HIR::ExprNode_BinOp::Op::Add: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le + re); ), - (Float, m_rv = ::HIR::Literal(le + re); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Sub: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le - re); ), - (Float, m_rv = ::HIR::Literal(le - re); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Mul: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le * re); ), - (Float, m_rv = ::HIR::Literal(le * re); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Div: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le / re); ), - (Float, m_rv = ::HIR::Literal(le / re); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Mod: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le % re); ), - (Float, ERROR(node.span(), E0000, "modulo operator on float in constant"); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::And: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le % re); ), - (Float, ERROR(node.span(), E0000, "bitwise and operator on float in constant"); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Or: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le | re); ), - (Float, ERROR(node.span(), E0000, "bitwise or operator on float in constant"); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Xor: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le ^ re); ), - (Float, ERROR(node.span(), E0000, "bitwise xor operator on float in constant"); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Shr: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le >> re); ), - (Float, ERROR(node.span(), E0000, "bitwise shift right operator on float in constant"); ) - ) - break; - case ::HIR::ExprNode_BinOp::Op::Shl: - TU_MATCH_DEF(::HIR::Literal, (left, right), (le, re), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(le << re); ), - (Float, ERROR(node.span(), E0000, "bitwise shift left operator on float in constant"); ) - ) - break; - } + ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(,), exp, {}, fcn }; - m_rv_type = mv$(ret_type); - } - void visit(::HIR::ExprNode_UniOp& node) override { - TRACE_FUNCTION_FR("_UniOp", m_rv); + ::HIR::Literal retval; + ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); - auto exp_type = m_exp_type.clone(); - node.m_value->visit(*this); - auto val = mv$(m_rv); + struct LocalState { + typedef ::std::vector< ::HIR::Literal> t_vec_lit; + ::MIR::TypeResolve& state; + ::HIR::Literal& retval; + ::std::vector< ::HIR::Literal>& args; + ::std::vector< ::HIR::Literal>& locals; - // Keep m_rv_type - switch(node.m_op) - { - case ::HIR::ExprNode_UniOp::Op::Invert: - TU_MATCH_DEF(::HIR::Literal, (val), (e), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal::make_Integer(~e); ), - (Float, ERROR(node.span(), E0000, "not operator on float in constant"); ) - ) - break; - case ::HIR::ExprNode_UniOp::Op::Negate: - TU_MATCH_DEF(::HIR::Literal, (val), (e), - ( throw ""; ), - (Integer, m_rv = ::HIR::Literal(static_cast<uint64_t>(-static_cast<int64_t>(e))); ), - (Float, m_rv = ::HIR::Literal(-e); ) - ) - break; - } - m_rv_type = mv$(exp_type); - } - void visit(::HIR::ExprNode_Borrow& node) override { + LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& args, t_vec_lit& locals): + state(state), + retval(retval), + args(args), + locals(locals) + {} - ::HIR::TypeRef exp_ty_inner; - TU_MATCH_DEF( ::HIR::TypeRef::Data, (m_exp_type.m_data), (te), - ( - //ERROR(node.span(), E0000, "Invalid expected type for a &-ptr - " << m_exp_type); - DEBUG("_Borrow: Unknown " << m_exp_type); - exp_ty_inner = m_exp_type.clone(); + ::HIR::Literal& get_lval(const ::MIR::LValue& lv) + { + TU_MATCHA( (lv), (e), + (Return, + return retval; ), - (Infer, + (Local, + if( e >= locals.size() ) + MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size()); + return locals[e]; ), - (Borrow, - exp_ty_inner = mv$( *te.inner ); - DEBUG("_Borrow: borrow expecting inner " << exp_ty_inner); - ) - ) - - m_exp_type = exp_ty_inner.clone(); - node.m_value->visit(*this); - auto val = mv$(m_rv); - - if( node.m_type != ::HIR::BorrowType::Shared ) { - ERROR(node.span(), E0000, "Only shared borrows are allowed in constants"); - } - - if( visit_ty_with(m_rv_type, [&](const auto& x){ return x.m_data.is_Infer(); }) ) { - if( visit_ty_with(exp_ty_inner, [&](const auto& x){ return x.m_data.is_Infer(); }) ) { - ERROR(node.span(), E0000, "Could not trivially infer type of referenced static - " << m_rv_type << ", lit = " << val << ", exp=&" << exp_ty_inner); - } - else { - m_rv_type = mv$(exp_ty_inner); - } - } - - m_rv_type = ::HIR::TypeRef::new_borrow( node.m_type, mv$(m_rv_type) ); - m_rv = ::HIR::Literal::make_BorrowData( box$(val) ); - } - void visit(::HIR::ExprNode_Cast& node) override { - TRACE_FUNCTION_F("_Cast"); - - m_exp_type = ::HIR::TypeRef(); // Can't know. - - node.m_value->visit(*this); - auto val = mv$(m_rv); - //DEBUG("ExprNode_Cast - val = " << val << " as " << node.m_type); - TU_MATCH_DEF( ::HIR::TypeRef::Data, (node.m_res_type.m_data), (te), - ( - m_rv = mv$(val); + (Argument, + if( e.idx >= args.size() ) + MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size()); + return args[e.idx]; ), - (Primitive, - switch(te) - { - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - TU_MATCH_DEF( ::HIR::Literal, (val), (ve), - ( BUG(node.span(), "Cast to float, bad literal " << val.tag_str()); ), - (Float, - m_rv = mv$(val); - ), - (Integer, - m_rv = ::HIR::Literal(static_cast<double>(ve)); - ) - ) - break; - case ::HIR::CoreType::I8: case ::HIR::CoreType::U8: - case ::HIR::CoreType::I16: case ::HIR::CoreType::U16: - case ::HIR::CoreType::I32: case ::HIR::CoreType::U32: - case ::HIR::CoreType::I64: case ::HIR::CoreType::U64: - case ::HIR::CoreType::I128: case ::HIR::CoreType::U128: - case ::HIR::CoreType::Isize: case ::HIR::CoreType::Usize: - TU_MATCH_DEF( ::HIR::Literal, (val), (ve), - ( BUG(node.span(), "Cast to float, bad literal " << val.tag_str()); ), - (Integer, - m_rv = mv$(val); - ), - (Float, - m_rv = ::HIR::Literal(static_cast<uint64_t>(ve)); - ) - ) - break; - default: - m_rv = mv$(val); - break; - } - ) - ) - m_rv_type = node.m_res_type.clone(); - } - void visit(::HIR::ExprNode_Unsize& node) override { - TRACE_FUNCTION_F("_Unsize"); - m_exp_type = ::HIR::TypeRef(); // Can't know. - node.m_value->visit(*this); - //auto val = mv$(m_rv); - //DEBUG("ExprNode_Unsize - val = " << val << " as " << node.m_type); - m_rv_type = node.m_res_type.clone(); - } - void visit(::HIR::ExprNode_Index& node) override { - - auto exp_ty = mv$(m_exp_type); - // Index - m_exp_type = ::HIR::TypeRef(::HIR::CoreType::Usize); - node.m_index->visit(*this); - if( !m_rv.is_Integer() ) - ERROR(node.span(), E0000, "Array index isn't an integer - got " << m_rv.tag_str()); - auto idx = static_cast<size_t>( m_rv.as_Integer() ); - - // Value - m_exp_type = ::HIR::TypeRef::new_slice( mv$(exp_ty) ); - node.m_value->visit(*this); - if( !m_rv.is_List() ) - ERROR(node.span(), E0000, "Indexed value isn't a list - got " << m_rv.tag_str()); - auto v = mv$( m_rv.as_List() ); - - // -> Perform - if( idx >= v.size() ) - ERROR(node.span(), E0000, "Constant array index " << idx << " out of range " << v.size()); - m_rv = mv$(v[idx]); - - TU_MATCH_DEF( ::HIR::TypeRef::Data, (m_rv_type.m_data), (e), - ( - ERROR(node.span(), E0000, "Indexing non-array - " << m_rv_type); + (Static, + MIR_TODO(state, "LValue::Static - " << e); ), - (Array, - auto tmp = mv$(e.inner); - m_rv_type = mv$(*tmp); - ) - ) - } - void visit(::HIR::ExprNode_Deref& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_Emplace& node) override { - badnode(node); - } - - void visit(::HIR::ExprNode_TupleVariant& node) override { - m_exp_type = ::HIR::TypeRef(); - - ::std::vector< ::HIR::Literal> vals; - for(const auto& vn : node.m_args ) { - vn->visit(*this); - assert( !m_rv.is_Invalid() ); - vals.push_back( mv$(m_rv) ); - } - - if( node.m_is_struct ) - { - const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); - ASSERT_BUG(node.span(), ent.is_Struct(), "_TupleVariant with m_is_struct set pointing to " << ent.tag_str()); - const auto& str = ent.as_Struct(); - - m_rv = ::HIR::Literal::make_List(mv$(vals)); - m_rv_type = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding(&str) ); - } - else - { - const auto& varname = node.m_path.m_path.m_components.back(); - auto tmp_path = node.m_path.m_path; - tmp_path.m_components.pop_back(); - const auto& ent = m_crate.get_typeitem_by_path(node.span(), tmp_path); - ASSERT_BUG(node.span(), ent.is_Enum(), "_TupleVariant with m_is_struct clear pointing to " << ent.tag_str()); - const auto& enm = ent.as_Enum(); - - auto var_idx = enm.find_variant(varname); - ASSERT_BUG(node.span(), var_idx != SIZE_MAX, "_TupleVariant points to unknown variant - " << node.m_path); - - auto inner = box$( ::HIR::Literal::make_List(mv$(vals)) ); - m_rv = ::HIR::Literal::make_Variant({ static_cast<unsigned>(var_idx), mv$(inner) }); - m_rv_type = ::HIR::TypeRef::new_path( mv$(tmp_path), ::HIR::TypeRef::TypePathBinding(&enm) ); - } - } - void visit(::HIR::ExprNode_CallPath& node) override - { - - TRACE_FUNCTION_FR("_CallPath - " << node.m_path, m_rv); - auto& fcn = get_function(node.span(), m_crate, node.m_path); - - // TODO: Set m_const during parse - //if( ! fcn.m_const ) { - // ERROR(node.span(), E0000, "Calling non-const function in const context - " << node.m_path); - //} - - if( fcn.m_args.size() != node.m_args.size() ) { - ERROR(node.span(), E0000, "Incorrect argument count for " << node.m_path << " - expected " << fcn.m_args.size() << ", got " << node.m_args.size()); - } - auto exp_ret_type = mv$( m_exp_type ); - - ::std::vector< ::HIR::Literal> args; - args.reserve( fcn.m_args.size() ); - for(unsigned int i = 0; i < fcn.m_args.size(); i ++ ) - { - const auto& pattern = fcn.m_args[i].first; - if( monomorphise_type_needed(fcn.m_args[i].second) ) { - m_exp_type = ::HIR::TypeRef(); - } - else { - m_exp_type = fcn.m_args[i].second.clone(); - } - TU_IFLET(::HIR::Pattern::Data, pattern.m_data, Any, e, - // Good - ) - else { - ERROR(node.span(), E0000, "Constant functions can't have destructuring pattern argments"); - } - - node.m_args[i]->visit(*this); - args.push_back( mv$(m_rv) ); - } - - exp_ret_type = fcn.m_return.clone(); - - // Call by invoking evaluate_constant on the function - { - TRACE_FUNCTION_F("Call const fn " << node.m_path << " args={ " << args << " }"); - m_rv = evaluate_constant(node.span(), m_crate, m_newval_state, fcn.m_code, mv$(exp_ret_type), mv$(args)); - } - } - void visit(::HIR::ExprNode_CallValue& node) override { - badnode(node); - } - void visit(::HIR::ExprNode_CallMethod& node) override { - // TODO: const methods - badnode(node); - } - void visit(::HIR::ExprNode_Field& node) override { - const auto& sp = node.span(); - TRACE_FUNCTION_FR("_Field", m_rv); - - m_exp_type = ::HIR::TypeRef(); - - node.m_value->visit(*this); - auto val = mv$( m_rv ); - - if( !val.is_List() ) - ERROR(sp, E0000, "Field access on invalid literal type - " << val.tag_str()); - auto& vals = val.as_List(); - - ::HIR::TypeRef ty = mv$(m_rv_type); - TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (e), - ( - ERROR(sp, E0000, "Field access on invalid type - " << ty); + (Field, + auto& val = get_lval(*e.val); + MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); + auto& vals = val.as_List(); + MIR_ASSERT(state, e.field_index < vals.size(), "LValue::Field index out of range"); + return vals[ e.field_index ]; ), - (Path, - TU_MATCHA( (e.binding), (pbe), - (Unbound, - ERROR(sp, E0000, "Field access on invalid type - " << ty); - ), - (Opaque, - ERROR(sp, E0000, "Field access on invalid type - " << ty); - ), - (Struct, - auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &e.path.m_data.as_Generic().m_params, nullptr); - const auto& str = *pbe; - unsigned int idx=0; - TU_MATCHA( (str.m_data), (se), - (Unit, - ERROR(sp, E0000, "Field access on invalid type - " << ty << " - Unit-like"); - ), - (Tuple, - idx = ::std::atoi( node.m_field.c_str() ); - ASSERT_BUG(sp, idx < se.size(), "Index out of range in tuple struct"); - m_rv_type = monomorphise_type_with(sp, se[idx].ent, monomorph_cb); - ), - (Named, - idx = ::std::find_if(se.begin(), se.end(), [&](const auto&x){return x.first==node.m_field;}) - se.begin(); - ASSERT_BUG(sp, idx < se.size(), "Field no found in struct"); - m_rv_type = monomorphise_type_with(sp, se[idx].second.ent, monomorph_cb); - ) - ) - ASSERT_BUG(sp, idx < vals.size(), "Index out of range in literal"); - m_rv = mv$( vals[idx] ); + (Deref, + auto& val = get_lval(*e.val); + TU_MATCH_DEF( ::HIR::Literal, (val), (ve), + ( + MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }"); ), - (Enum, - TODO(sp, "Field access on enum variant - " << ty); + (BorrowData, + return *ve; ), - (Union, - TODO(sp, "Field access on union - " << ty); + (String, + // Just clone the string (hack) + // - TODO: Create a list? + return val; ) ) ), - (Tuple, - unsigned int idx = ::std::atoi( node.m_field.c_str() ); - ASSERT_BUG(sp, idx < e.size(), "Index out of range in tuple"); - ASSERT_BUG(sp, idx < vals.size(), "Index out of range in literal"); - - m_rv = mv$( vals[idx] ); - m_rv_type = mv$( e[idx] ); - ) - ) - } - - void visit(::HIR::ExprNode_Literal& node) override { - TRACE_FUNCTION_FR("_Literal", m_rv); - TU_MATCH(::HIR::ExprNode_Literal::Data, (node.m_data), (e), - (Integer, - m_rv = ::HIR::Literal(e.m_value); - m_rv_type = mv$(m_exp_type); - ), - (Float, - m_rv = ::HIR::Literal(e.m_value); - m_rv_type = mv$(m_exp_type); - ), - (Boolean, - m_rv = ::HIR::Literal(static_cast<uint64_t>(e)); - m_rv_type = ::HIR::CoreType::Bool; + (Index, + auto& val = get_lval(*e.val); + MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv); + auto& idx = get_lval(*e.idx); + MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv); + auto& vals = val.as_List(); + auto idx_v = static_cast<size_t>( idx.as_Integer() ); + MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range"); + return vals[ idx_v ]; ), - (String, - m_rv = ::HIR::Literal(e); - m_rv_type = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::CoreType::Str ); - ), - (ByteString, - m_rv = ::HIR::Literal::make_String({e.begin(), e.end()}); - m_rv_type = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef::new_array(::HIR::CoreType::U8, e.size()) ); + (Downcast, + MIR_TODO(state, "LValue::Downcast - " << lv); ) ) + throw ""; } - void visit(::HIR::ExprNode_UnitVariant& node) override { - if( node.m_is_struct ) - { - const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); - ASSERT_BUG(node.span(), ent.is_Struct(), "_UnitVariant with m_is_struct set pointing to " << ent.tag_str()); - const auto& str = ent.as_Struct(); - - m_rv = ::HIR::Literal::make_List({}); - m_rv_type = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding(&str) ); - } - else - { - const auto& varname = node.m_path.m_path.m_components.back(); - auto tmp_path = node.m_path.m_path; - tmp_path.m_components.pop_back(); - const auto& ent = m_crate.get_typeitem_by_path(node.span(), tmp_path); - ASSERT_BUG(node.span(), ent.is_Enum(), "_UnitVariant with m_is_struct clear pointing to " << ent.tag_str()); - const auto& enm = ent.as_Enum(); - - auto var_idx = enm.find_variant(varname); - ASSERT_BUG(node.span(), var_idx != SIZE_MAX, "_UnitVariant points to unknown variant - " << node.m_path); - - m_rv = ::HIR::Literal::make_Variant({ static_cast<unsigned>(var_idx), box$(::HIR::Literal::make_List({})) }); - m_rv_type = ::HIR::TypeRef::new_path( mv$(tmp_path), ::HIR::TypeRef::TypePathBinding(&enm) ); - } - } - void visit(::HIR::ExprNode_PathValue& node) override { - TRACE_FUNCTION_FR("_PathValue - " << node.m_path, m_rv); - auto ep = get_ent_fullpath(node.span(), m_crate, node.m_path, EntNS::Value); - TU_MATCH_DEF( EntPtr, (ep), (e), + ::HIR::Literal read_lval(const ::MIR::LValue& lv) + { + auto& v = get_lval(lv); + DEBUG(lv << " = " << v); + TU_MATCH_DEF(::HIR::Literal, (v), (e), ( - BUG(node.span(), "Path value with unsupported value type - " << ep.tag_str()); - ), - (Static, - // TODO: Should be a more complex path to support associated paths - ASSERT_BUG(node.span(), node.m_path.m_data.is_Generic(), "Static path not Path::Generic - " << node.m_path); - m_rv = ::HIR::Literal(node.m_path.m_data.as_Generic().m_path); - m_rv_type = e->m_type.clone(); + return mv$(v); ), - (Function, - // TODO: Should be a more complex path to support associated paths - ASSERT_BUG(node.span(), node.m_path.m_data.is_Generic(), "Function path not Path::Generic - " << node.m_path); - m_rv = ::HIR::Literal(node.m_path.m_data.as_Generic().m_path); - ::HIR::FunctionType fcn; - fcn.m_rettype = box$( e->m_return.clone() ); - m_rv_type = ::HIR::TypeRef( mv$(fcn) ); // TODO: Better type + (Invalid, + MIR_BUG(state, "Read of " << lv << " yielded Invalid"); ), - (Constant, - // TODO: Associated constants - const auto& c = *e; - if( c.m_value_res.is_Invalid() ) { - const_cast<HIR::ExprNode&>(*c.m_value).visit(*this); - } - else { - m_rv = clone_literal(c.m_value_res); - } - m_rv_type = e->m_type.clone(); - ) - ) - } - void visit(::HIR::ExprNode_Variable& node) override { - TRACE_FUNCTION_FR("_Variable - " << node.m_name, m_rv); - // TODO: use the binding? - if( node.m_slot >= m_values.size() ) { - ERROR(node.span(), E0000, "Couldn't find variable #" << node.m_slot << " " << node.m_name); - } - auto& v = m_values.at( node.m_slot ); - TU_MATCH_DEF(::HIR::Literal, (v), (e), - ( - m_rv = mv$(v); + (BorrowPath, + return ::HIR::Literal(e.clone()); ), (Integer, - m_rv = ::HIR::Literal(e); + return ::HIR::Literal(e); ), (Float, - m_rv = ::HIR::Literal(e); - ) - ) - m_rv_type = ::HIR::TypeRef(); // TODO: - } - - void visit(::HIR::ExprNode_StructLiteral& node) override { - TRACE_FUNCTION_FR("_StructLiteral - " << node.m_path, m_rv); - - if( node.m_is_struct ) - { - const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); - ASSERT_BUG(node.span(), ent.is_Struct(), "_StructLiteral with m_is_struct set pointing to a " << ent.tag_str()); - const auto& str = ent.as_Struct(); - const auto& fields = str.m_data.as_Named(); - - auto rv_type = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding(&str) ); - - ::std::vector< ::HIR::Literal> vals; - if( node.m_base_value ) - { - m_exp_type = rv_type.clone(); - - node.m_base_value->visit(*this); - auto base_val = mv$(m_rv); - if( !base_val.is_List() || base_val.as_List().size() != fields.size() ) { - BUG(node.span(), "Struct literal base value had an incorrect field count"); - } - vals = mv$(base_val.as_List()); - } - else { - vals.resize( fields.size() ); - } - for( const auto& val_set : node.m_values ) { - unsigned int idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& v) { return v.first == val_set.first; } ) - fields.begin(); - if( idx == fields.size() ) { - ERROR(node.span(), E0000, "Field name " << val_set.first << " isn't a member of " << node.m_path); - } - - if( monomorphise_type_needed(fields[idx].second.ent) ) { - m_exp_type = ::HIR::TypeRef(); - } - else { - m_exp_type = fields[idx].second.ent.clone(); - } - - val_set.second->visit(*this); - vals[idx] = mv$(m_rv); - } - for( unsigned int i = 0; i < vals.size(); i ++ ) { - const auto& val = vals[i]; - if( val.is_Invalid() ) { - ERROR(node.span(), E0000, "Field " << fields[i].first << " wasn't set"); - } - } - - m_rv = ::HIR::Literal::make_List(mv$(vals)); - m_rv_type = mv$(rv_type); - } - else - { - const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); - ASSERT_BUG(node.span(), ent.is_Enum(), "_StructLiteral with m_is_struct clear pointing to a " << ent.tag_str()); - - TODO(node.span(), "Handle Enum _UnitVariant - " << node.m_path); - } - } - void visit(::HIR::ExprNode_UnionLiteral& node) override { - TRACE_FUNCTION_FR("_UnionLiteral - " << node.m_path, m_rv); - TODO(node.span(), "_UnionLiteral"); - } - void visit(::HIR::ExprNode_Tuple& node) override - { - TRACE_FUNCTION_FR("_Tuple", m_rv); - ::std::vector< ::HIR::TypeRef> exp_tys; - TU_MATCH_DEF(::HIR::TypeRef::Data, (m_exp_type.m_data), (te), - ( - ), - (Infer, - ), - (Tuple, - exp_tys = mv$( te ); - ASSERT_BUG(node.span(), exp_tys.size() == node.m_vals.size(), "Tuple literal size mismatches with expected type"); - ) - ) - - ::std::vector< ::HIR::Literal> vals; - ::std::vector< ::HIR::TypeRef> tys; - for(unsigned int i = 0; i < node.m_vals.size(); i ++) - { - if( exp_tys.size() > 0 ) - m_exp_type = mv$(exp_tys[i]); - - node.m_vals[i]->visit(*this); - assert( !m_rv.is_Invalid() ); - - vals.push_back( mv$(m_rv) ); - tys.push_back( mv$(m_rv_type) ); - } - - m_rv = ::HIR::Literal::make_List(mv$(vals)); - m_rv_type = ::HIR::TypeRef( mv$(tys) ); - } - void visit(::HIR::ExprNode_ArrayList& node) override - { - TRACE_FUNCTION_F("_ArrayList: " << m_exp_type); - ::HIR::TypeRef exp_inner_ty; - TU_MATCH_DEF(::HIR::TypeRef::Data, (m_exp_type.m_data), (te), - ( - ), - (Infer, - ), - (Array, - exp_inner_ty = mv$(*te.inner); - // TODO: Check size? - ), - (Slice, - exp_inner_ty = mv$(*te.inner); - ) - ) - - ::std::vector< ::HIR::Literal> vals; - for(const auto& vn : node.m_vals ) - { - m_exp_type = exp_inner_ty.clone(); - vn->visit(*this); - assert( !m_rv.is_Invalid() ); - vals.push_back( mv$(m_rv) ); - } - - m_rv_type = ::HIR::TypeRef::new_array( mv$(m_rv_type), vals.size() ); - m_rv = ::HIR::Literal::make_List(mv$(vals)); - } - void visit(::HIR::ExprNode_ArraySized& node) override - { - ::HIR::TypeRef exp_inner_ty; - TU_MATCH_DEF(::HIR::TypeRef::Data, (m_exp_type.m_data), (te), - ( - ), - (Infer, - ), - (Array, - exp_inner_ty = mv$(*te.inner); - // TODO: Check size? - ), - (Slice, - exp_inner_ty = mv$(*te.inner); + return ::HIR::Literal(e); ) ) - - m_exp_type = ::HIR::CoreType::Usize; - node.m_size->visit(*this); - assert( m_rv.is_Integer() ); - unsigned int count = static_cast<unsigned int>(m_rv.as_Integer()); - - ::std::vector< ::HIR::Literal> vals; - vals.reserve( count ); - if( count > 0 ) - { - m_exp_type = mv$(exp_inner_ty); - node.m_val->visit(*this); - assert( !m_rv.is_Invalid() ); - for(unsigned int i = 0; i < count-1; i ++) - { - vals.push_back( clone_literal(m_rv) ); - } - vals.push_back( mv$(m_rv) ); - } - m_rv = ::HIR::Literal::make_List(mv$(vals)); - m_rv_type = ::HIR::TypeRef::new_array( mv$(m_rv_type), count ); - } - - void visit(::HIR::ExprNode_Closure& node) override { - badnode(node); } }; + LocalState local_state( state, retval, args, locals ); - Visitor v { crate, newval_state, mv$(exp_type) }; - for(auto& arg : args) - v.m_values.push_back( mv$(arg) ); - const_cast<::HIR::ExprNode&>(expr).visit(v); - - if( v.m_rv.is_Invalid() ) { - // NOTE: Removed, because of tricks serde_derive does - //BUG(sp, "Expression did not yeild a literal"); - } - - return mv$(v.m_rv); - } - - ::HIR::Literal evaluate_constant_mir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::MIR::Function& fcn, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) - { - // TODO: Full-blown miri - TRACE_FUNCTION_F("exp=" << exp << ", args=" << args); - - StaticTraitResolve resolve { crate }; - ::MIR::TypeResolve state { sp, resolve, FMT_CB(,), exp, {}, fcn }; - - ::HIR::Literal retval; - ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); - - auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { - TU_MATCHA( (lv), (e), - (Return, - return retval; - ), - (Argument, - ASSERT_BUG(sp, e.idx < args.size(), "Argument index out of range - " << e.idx << " >= " << args.size()); - return args[e.idx]; - ), - (Local, - if( e >= locals.size() ) - BUG(sp, "Local index out of range - " << e << " >= " << locals.size()); - return locals[e]; - ), - (Static, - TODO(sp, "LValue::Static"); - ), - (Field, - TODO(sp, "LValue::Field"); - ), - (Deref, - TODO(sp, "LValue::Deref"); - ), - (Index, - TODO(sp, "LValue::Index"); - ), - (Downcast, - TODO(sp, "LValue::Downcast"); - ) - ) - throw ""; - }; - auto read_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal { - auto& v = get_lval(lv); - TU_MATCH_DEF(::HIR::Literal, (v), (e), - ( - return mv$(v); - ), - (Invalid, - BUG(sp, "Read of invalid lvalue - " << lv); - ), - (BorrowPath, - return ::HIR::Literal(e.clone()); - ), - (Integer, - return ::HIR::Literal(e); - ), - (Float, - return ::HIR::Literal(e); - ) - ) - }; auto const_to_lit = [&](const ::MIR::Constant& c)->::HIR::Literal { TU_MATCH(::MIR::Constant, (c), (e2), (Int, @@ -1105,26 +397,42 @@ namespace { return ::HIR::Literal(e2); ), (Const, - auto ent = get_ent_fullpath(sp, crate, e2.p, EntNS::Value); - ASSERT_BUG(sp, ent.is_Constant(), "MIR Constant::Const("<<e2.p<<") didn't point to a Constant - " << ent.tag_str()); - return clone_literal( ent.as_Constant()->m_value_res ); + auto p = ms.monomorph(state.sp, e2.p); + MonomorphState const_ms; + auto ent = get_ent_fullpath(state.sp, this->resolve.m_crate, p, EntNS::Value, const_ms); + MIR_ASSERT(state, ent.is_Constant(), "MIR Constant::Const(" << p << ") didn't point to a Constant - " << ent.tag_str()); + const auto& c = *ent.as_Constant(); + if( c.m_value_res.is_Invalid() ) + { + auto& item = const_cast<::HIR::Constant&>(c); + // Challenge: Adding items to the module might invalidate an iterator. + ::HIR::ItemPath mod_ip { item.m_value.m_state->m_mod_path }; + auto eval = Evaluator { item.m_value->span(), resolve.m_crate, NewvalState { item.m_value.m_state->m_module, mod_ip, FMT(&c << "$") } }; + DEBUG("- Evaluate " << p); + DEBUG("- " << ::HIR::ItemPath(p)); + item.m_value_res = eval.evaluate_constant(::HIR::ItemPath(p), item.m_value, item.m_type.clone()); + + //check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); + } + return clone_literal( c.m_value_res ); ), (ItemAddr, - return ::HIR::Literal::make_BorrowPath( e2.clone() ); + return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, e2) ); ) ) throw ""; }; - auto read_param = [&](const ::MIR::Param& p) ->::HIR::Literal { - TU_MATCH(::MIR::Param, (p), (e), - (LValue, - return read_lval(e); - ), - (Constant, - return const_to_lit(e); + auto read_param = [&](const ::MIR::Param& p) -> ::HIR::Literal + { + TU_MATCH(::MIR::Param, (p), (e), + (LValue, + return local_state.read_lval(e); + ), + (Constant, + return const_to_lit(e); + ) ) - ) - throw ""; + throw ""; }; unsigned int cur_block = 0; @@ -1135,9 +443,10 @@ namespace { for(const auto& stmt : block.statements) { state.set_cur_stmt(cur_block, next_stmt_idx++); + DEBUG(state << stmt); if( ! stmt.is_Assign() ) { - //BUG(sp, "Non-assign statement - drop " << stmt.as_Drop().slot); + //MIR_BUG(state, "Non-assign statement - drop " << stmt.as_Drop().slot); continue ; } @@ -1145,7 +454,7 @@ namespace { const auto& sa = stmt.as_Assign(); TU_MATCHA( (sa.src), (e), (Use, - val = read_lval(e); + val = local_state.read_lval(e); ), (Constant, val = const_to_lit(e); @@ -1167,17 +476,38 @@ namespace { MIR_BUG(state, "Only shared borrows are allowed in constants"); } - auto inner_val = read_lval(e.val); + if( e.type != ::HIR::BorrowType::Shared ) { + MIR_BUG(state, "Only shared borrows are allowed in constants"); + } + if( const auto* p = e.val.opt_Deref() ) { + if( p->val->is_Deref() ) + MIR_TODO(state, "Undo nested deref coercion - " << *p->val); + val = local_state.read_lval(*p->val); + } + else if( const auto* p = e.val.opt_Static() ) { + // Borrow of a static, emit BorrowPath with the same path + val = ::HIR::Literal::make_BorrowPath( p->clone() ); + } + else { + auto inner_val = local_state.read_lval(e.val); + + ::HIR::TypeRef inner_ty; + const auto& inner_ty_r = state.get_lvalue_type(inner_ty, e.val); + if( &inner_ty_r != &inner_ty ) + inner_ty = inner_ty_r.clone(); - // Create new static containing borrowed data - val = ::HIR::Literal::make_BorrowData( box$(inner_val) ); + // Create new static containing borrowed data + // NOTE: Doesn't use BorrowData + auto item_path = this->nvs.new_static( mv$(inner_ty), mv$(inner_val) ); + val = ::HIR::Literal::make_BorrowPath( mv$(item_path) ); + } ), (Cast, - auto inval = read_lval(e.val); + auto inval = local_state.read_lval(e.val); TU_MATCH_DEF(::HIR::TypeRef::Data, (e.type.m_data), (te), ( // NOTE: Can be an unsizing! - TODO(sp, "RValue::Cast to " << e.type << ", val = " << inval); + MIR_TODO(state, "RValue::Cast to " << e.type << ", val = " << inval); ), (Primitive, uint64_t mask; @@ -1211,7 +541,7 @@ namespace { val = ::HIR::Literal( static_cast<uint64_t>(i) & mask); ) else { - BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); + MIR_BUG(state, "Invalid cast of " << inval.tag_str() << " to " << e.type); } break; case ::HIR::CoreType::F32: @@ -1223,11 +553,11 @@ namespace { val = ::HIR::Literal( i ); ) else { - BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); + MIR_BUG(state, "Invalid cast of " << inval.tag_str() << " to " << e.type); } break; default: - TODO(sp, "RValue::Cast to " << e.type << ", val = " << inval); + MIR_TODO(state, "RValue::Cast to " << e.type << ", val = " << inval); } ), // Allow casting any integer value to a pointer (TODO: Ensure that the pointer is sized?) @@ -1239,7 +569,15 @@ namespace { val = mv$(inval); } else { - BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); + MIR_BUG(state, "Invalid cast of " << inval.tag_str() << " to " << e.type); + } + ), + (Borrow, + if( inval.is_BorrowData() || inval.is_BorrowPath() ) { + val = mv$(inval); + } + else { + MIR_BUG(state, "Invalid cast of " << inval.tag_str() << " to " << e.type); } ) ) @@ -1247,10 +585,10 @@ namespace { (BinOp, auto inval_l = read_param(e.val_l); auto inval_r = read_param(e.val_r); - ASSERT_BUG(sp, inval_l.tag() == inval_r.tag(), "Mismatched literal types in binop - " << inval_l << " and " << inval_r); + MIR_ASSERT(state, inval_l.tag() == inval_r.tag(), "Mismatched literal types in binop - " << inval_l << " and " << inval_r); TU_MATCH_DEF( ::HIR::Literal, (inval_l, inval_r), (l, r), ( - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); + MIR_TODO(state, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); ), (Float, switch(e.op) @@ -1264,14 +602,14 @@ namespace { case ::MIR::eBinOp::SUB_OV: case ::MIR::eBinOp::MUL_OV: case ::MIR::eBinOp::DIV_OV: - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); + MIR_TODO(state, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); case ::MIR::eBinOp::BIT_OR : case ::MIR::eBinOp::BIT_AND: case ::MIR::eBinOp::BIT_XOR: case ::MIR::eBinOp::BIT_SHL: case ::MIR::eBinOp::BIT_SHR: - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); + MIR_TODO(state, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); // TODO: GT/LT are incorrect for signed integers case ::MIR::eBinOp::EQ: val = ::HIR::Literal( static_cast<uint64_t>(l == r) ); break; case ::MIR::eBinOp::NE: val = ::HIR::Literal( static_cast<uint64_t>(l != r) ); break; @@ -1293,7 +631,7 @@ namespace { case ::MIR::eBinOp::SUB_OV: case ::MIR::eBinOp::MUL_OV: case ::MIR::eBinOp::DIV_OV: - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); + MIR_TODO(state, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); case ::MIR::eBinOp::BIT_OR : val = ::HIR::Literal( l | r ); break; case ::MIR::eBinOp::BIT_AND: val = ::HIR::Literal( l & r ); break; @@ -1312,7 +650,7 @@ namespace { ) ), (UniOp, - auto inval = read_lval(e.val); + auto inval = local_state.read_lval(e.val); TU_IFLET( ::HIR::Literal, inval, Integer, i, switch( e.op ) { @@ -1328,7 +666,7 @@ namespace { switch( e.op ) { case ::MIR::eUniOp::INV: - BUG(sp, "Invalid invert of Float"); + MIR_BUG(state, "Invalid invert of Float"); break; case ::MIR::eUniOp::NEG: val = ::HIR::Literal( -i ); @@ -1336,20 +674,20 @@ namespace { } ) else { - BUG(sp, "Invalid invert of " << inval.tag_str()); + MIR_BUG(state, "Invalid invert of " << inval.tag_str()); } ), (DstMeta, - TODO(sp, "RValue::DstMeta"); + MIR_TODO(state, "RValue::DstMeta"); ), (DstPtr, - TODO(sp, "RValue::DstPtr"); + MIR_TODO(state, "RValue::DstPtr"); ), (MakeDst, auto ptr = read_param(e.ptr_val); auto meta = read_param(e.meta_val); if( ! meta.is_Integer() ) { - TODO(sp, "RValue::MakeDst - (non-integral meta) " << ptr << " , " << meta); + MIR_TODO(state, "RValue::MakeDst - (non-integral meta) " << ptr << " , " << meta); } else { val = mv$(ptr); @@ -1370,7 +708,8 @@ namespace { val = ::HIR::Literal::make_List( mv$(vals) ); ), (Variant, - TODO(sp, "MIR _Variant"); + auto ival = read_param(e.val); + val = ::HIR::Literal::make_Variant({ e.index, box$(ival) }); ), (Struct, ::std::vector< ::HIR::Literal> vals; @@ -1381,13 +720,13 @@ namespace { ) ) - auto& dst = get_lval(sa.dst); + auto& dst = local_state.get_lval(sa.dst); dst = mv$(val); } state.set_cur_stmt_term(cur_block); TU_MATCH_DEF( ::MIR::Terminator, (block.terminator), (e), ( - BUG(sp, "Unexpected terminator - " << block.terminator); + MIR_BUG(state, "Unexpected terminator - " << block.terminator); ), (Goto, cur_block = e; @@ -1430,18 +769,20 @@ namespace { case ::HIR::CoreType::Bool: break; case ::HIR::CoreType::Str: - BUG(sp, "Bare str return type"); + MIR_BUG(state, "Bare str return type"); } } return retval; ), (Call, if( !e.fcn.is_Path() ) - BUG(sp, "Unexpected terminator - " << block.terminator); - const auto& fcnp = e.fcn.as_Path(); + MIR_BUG(state, "Unexpected terminator - " << block.terminator); + const auto& fcnp_raw = e.fcn.as_Path(); + auto fcnp = ms.monomorph(state.sp, fcnp_raw); - auto& dst = get_lval(e.ret_val); - auto& fcn = get_function(sp, crate, fcnp); + auto& dst = local_state.get_lval(e.ret_val); + MonomorphState fcn_ms; + auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms); ::std::vector< ::HIR::Literal> call_args; call_args.reserve( e.args.size() ); @@ -1452,7 +793,9 @@ namespace { // Call by invoking evaluate_constant on the function { TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }"); - dst = evaluate_constant(sp, crate, newval_state, fcn.m_code, fcn.m_return.clone(), mv$(call_args)); + const auto* mir = this->resolve.m_crate.get_or_gen_mir( ::HIR::ItemPath(fcnp.clone()), fcn ); + MIR_ASSERT(state, mir, "No MIR for function " << fcnp); + dst = evaluate_constant_mir(*mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args)); } cur_block = e.ret_block; @@ -1461,16 +804,16 @@ namespace { } } - ::HIR::Literal evaluate_constant(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) + ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp) { - if( expr.m_mir ) { - return evaluate_constant_mir(sp, crate, mv$(newval_state), *expr.m_mir, mv$(exp), mv$(args)); - } - else if( expr ) { - return evaluate_constant_hir(sp, crate, mv$(newval_state), *expr, mv$(exp), mv$(args)); + TRACE_FUNCTION_F(ip); + const auto* mir = this->resolve.m_crate.get_or_gen_mir(ip, expr, exp); + + if( mir ) { + return evaluate_constant_mir(*mir, {}, mv$(exp), {}); } else { - BUG(sp, "Attempting to evaluate constant expression with no associated code"); + BUG(this->root_span, "Attempting to evaluate constant expression with no associated code"); } } @@ -1553,30 +896,26 @@ namespace { public ::HIR::Visitor { const ::HIR::Crate& m_crate; + const ::HIR::Module* m_mod; const ::HIR::ItemPath* m_mod_path; - t_new_values m_new_values; public: Expander(const ::HIR::Crate& crate): - m_crate(crate) + m_crate(crate), + m_mod(nullptr), + m_mod_path(nullptr) {} void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { auto saved_mp = m_mod_path; + auto saved_m = m_mod; + m_mod = &mod; m_mod_path = &p; - auto saved = mv$( m_new_values ); ::HIR::Visitor::visit_module(p, mod); - for( auto& item : m_new_values ) - { - mod.m_value_items.insert( ::std::make_pair( - mv$(item.first), - box$(::HIR::VisEnt<::HIR::ValueItem> { false, ::HIR::ValueItem(mv$(item.second)) }) - ) ); - } - m_new_values = mv$(saved); + m_mod = saved_m; m_mod_path = saved_mp; } @@ -1590,8 +929,10 @@ namespace { assert(e.size); assert(*e.size); const auto& expr_ptr = *e.size; - auto nvs = NewvalState { m_new_values, *m_mod_path, FMT("ty_" << &ty << "$") }; - auto val = evaluate_constant(expr_ptr->span(), m_crate, nvs, expr_ptr, ::HIR::CoreType::Usize); + auto ty_name = FMT("ty_" << &ty << "$"); + + auto eval = Evaluator { expr_ptr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, ty_name } }; + auto val = eval.evaluate_constant(::HIR::ItemPath(*m_mod_path, ty_name.c_str()), expr_ptr, ::HIR::CoreType::Usize); if( !val.is_Integer() ) ERROR(expr_ptr->span(), E0000, "Array size isn't an integer"); e.size_val = static_cast<size_t>(val.as_Integer()); @@ -1599,7 +940,6 @@ namespace { DEBUG("Array " << ty << " - size = " << e.size_val); ) } - // TODO: Needs to be visited for MIR match generation to work void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override { ::HIR::Visitor::visit_constant(p, item); @@ -1607,30 +947,39 @@ namespace { // NOTE: Consteval needed here for MIR match generation to work if( item.m_value ) { - //if( item.m_type.m_data.is_Primitive() ) - // ; - //else if( item.m_type.m_data.is_Borrow() && *item.m_type.m_data.as_Borrow().inner == ::HIR::CoreType::Str ) - // ; - //else - // return ; - - auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }; - item.m_value_res = evaluate_constant(item.m_value->span(), m_crate, nvs, item.m_value, item.m_type.clone(), {}); + auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; + item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone()); check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); DEBUG("constant: " << item.m_type << " = " << item.m_value_res); } } + void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override + { + ::HIR::Visitor::visit_static(p, item); + + if( item.m_value ) + { + auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; + item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone()); + + check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); + + DEBUG("static: " << item.m_type << " = " << item.m_value_res); + } + } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { if( auto* e = item.m_data.opt_Value() ) { + ::HIR::TypeRef ty = ::HIR::CoreType::Isize; uint64_t i = 0; for(auto& var : e->variants) { if( var.expr ) { - auto val = evaluate_constant(var.expr->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") }, var.expr, {}); + auto eval = Evaluator { var.expr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") } }; + auto val = eval.evaluate_constant(p, var.expr, ty.clone()); DEBUG("enum variant: " << p << "::" << var.name << " = " << val); i = val.as_Integer(); } @@ -1663,8 +1012,9 @@ namespace { void visit(::HIR::ExprNode_ArraySized& node) override { assert( node.m_size ); - NewvalState nvs { m_exp.m_new_values, *m_exp.m_mod_path, FMT("array_" << &node << "$") }; - auto val = evaluate_constant_hir(node.span(), m_exp.m_crate, mv$(nvs), *node.m_size, ::HIR::CoreType::Usize, {}); + auto name = FMT("array_" << &node << "$"); + auto eval = Evaluator { node.span(), m_exp.m_crate, NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name } }; + auto val = eval.evaluate_constant( ::HIR::ItemPath(*m_exp.m_mod_path, name.c_str()), node.m_size, ::HIR::CoreType::Usize ); if( !val.is_Integer() ) ERROR(node.span(), E0000, "Array size isn't an integer"); node.m_size_val = static_cast<size_t>(val.as_Integer()); @@ -1679,10 +1029,40 @@ namespace { } } }; + + class ExpanderApply: + public ::HIR::Visitor + { + + public: + ExpanderApply() + { + } + + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override + { + if( ! mod.m_inline_statics.empty() ) + { + for(auto& v : mod.m_inline_statics) + { + // ::std::unique_ptr<VisEnt<ValueItem>> + ::std::unique_ptr<::HIR::VisEnt<::HIR::ValueItem>> iv; + iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { false, ::HIR::ValueItem::make_Static(mv$(v.second)) } ); + mod.m_value_items.insert(::std::make_pair( v.first, mv$(iv) )); + } + mod.m_inline_statics.clear(); + } + + ::HIR::Visitor::visit_module(p, mod); + + } + }; } // namespace void ConvertHIR_ConstantEvaluate(::HIR::Crate& crate) { Expander exp { crate }; exp.visit_crate( crate ); + + ExpanderApply().visit_crate(crate); } diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index 58a4604a..693c7745 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -10,6 +10,7 @@ #include <hir_typeck/static.hpp> #include <algorithm> #include "main_bindings.hpp" +#include <hir/expr_state.hpp> namespace { @@ -654,6 +655,16 @@ namespace { }; } +void HIR_Expand_AnnotateUsage_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp) +{ + assert(exp); + StaticTraitResolve resolve { crate }; + if(exp.m_state->m_impl_generics) resolve.set_impl_generics(*exp.m_state->m_impl_generics); + if(exp.m_state->m_item_generics) resolve.set_item_generics(*exp.m_state->m_item_generics); + ExprVisitor_Mark ev { resolve }; + ev.visit_root(exp); +} + void HIR_Expand_AnnotateUsage(::HIR::Crate& crate) { OuterVisitor ov(crate); diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index a0814e49..51b2c638 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -1169,6 +1169,11 @@ namespace { }; } +void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp) +{ + // TODO: +} + void HIR_Expand_Closures(::HIR::Crate& crate) { OuterVisitor ov(crate); diff --git a/src/hir_expand/const_eval_full.cpp b/src/hir_expand/const_eval_full.cpp deleted file mode 100644 index 9cfd83b0..00000000 --- a/src/hir_expand/const_eval_full.cpp +++ /dev/null @@ -1,952 +0,0 @@ -/* - * MRustC - Rust Compiler - * - By John Hodge (Mutabah/thePowersGang) - * - * hir_expand/const_eval_full.cpp - * - More-complete constant evaluation - * - * NOTE: This is run _after_ MIR lowering (not before, as the rest of this - * folder is) - */ -#include "main_bindings.hpp" -#include <hir/hir.hpp> -#include <hir/expr.hpp> -#include <hir/visitor.hpp> -#include <algorithm> -#include <mir/mir.hpp> -#include <hir_typeck/common.hpp> // Monomorph -#include <mir/helpers.hpp> - -namespace { - typedef ::std::vector< ::std::pair< ::std::string, ::HIR::Static> > t_new_values; - - struct NewvalState { - t_new_values& newval_output; - const ::HIR::ItemPath& mod_path; - ::std::string name_prefix; - unsigned int next_item_idx; - - NewvalState(t_new_values& newval_output, const ::HIR::ItemPath& mod_path, ::std::string prefix): - newval_output(newval_output), - mod_path(mod_path), - name_prefix(prefix), - next_item_idx(0) - { - } - NewvalState(const NewvalState&) = delete; - NewvalState(NewvalState&&) = default; - - ::HIR::SimplePath new_static(::HIR::TypeRef type, ::HIR::Literal value) - { - auto name = FMT(name_prefix << next_item_idx); - next_item_idx ++; - auto rv = (mod_path + name.c_str()).get_simple_path(); - newval_output.push_back( ::std::make_pair( mv$(name), ::HIR::Static { - ::HIR::Linkage(), - false, - mv$(type), - ::HIR::ExprPtr(), - mv$(value) - } ) ); - return rv; - } - }; - - ::HIR::Literal evaluate_constant(const Span& sp, const ::StaticTraitResolve& resolve, NewvalState& newval_state, FmtLambda name, const ::HIR::ExprPtr& expr, MonomorphState ms, ::std::vector< ::HIR::Literal> args); - - ::HIR::Literal clone_literal(const ::HIR::Literal& v) - { - TU_MATCH(::HIR::Literal, (v), (e), - (Invalid, - return ::HIR::Literal(); - ), - (List, - ::std::vector< ::HIR::Literal> vals; - for(const auto& val : e) { - vals.push_back( clone_literal(val) ); - } - return ::HIR::Literal( mv$(vals) ); - ), - (Variant, - return ::HIR::Literal::make_Variant({ e.idx, box$(clone_literal(*e.val)) }); - ), - (Integer, - return ::HIR::Literal(e); - ), - (Float, - return ::HIR::Literal(e); - ), - (BorrowPath, - return ::HIR::Literal(e.clone()); - ), - (BorrowData, - return ::HIR::Literal(box$(clone_literal(*e))); - ), - (String, - return ::HIR::Literal(e); - ) - ) - throw ""; - } - - void monomorph_literal_inplace(const Span& sp, ::HIR::Literal& lit, const MonomorphState& ms) - { - TU_MATCH(::HIR::Literal, (lit), (e), - (Invalid, - ), - (List, - for(auto& val : e) { - monomorph_literal_inplace(sp, val, ms); - } - ), - (Variant, - monomorph_literal_inplace(sp, *e.val, ms); - ), - (Integer, - ), - (Float, - ), - (BorrowPath, - DEBUG(e); - e = ms.monomorph(sp, e); - // TODO: expand associated types - ), - (BorrowData, - monomorph_literal_inplace(sp, *e, ms); - ), - (String, - ) - ) - } - - TAGGED_UNION(EntPtr, NotFound, - (NotFound, struct{}), - (Function, const ::HIR::Function*), - (Static, const ::HIR::Static*), - (Constant, const ::HIR::Constant*), - (Struct, const ::HIR::Struct*) - ); - enum class EntNS { - Type, - Value - }; - EntPtr get_ent_simplepath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::SimplePath& path, EntNS ns) - { - const ::HIR::Module& mod = crate.get_mod_by_path(sp, path, /*ignore_last_node=*/true); - - switch( ns ) - { - case EntNS::Value: { - auto it = mod.m_value_items.find( path.m_components.back() ); - if( it == mod.m_value_items.end() ) { - return EntPtr {}; - } - - TU_MATCH( ::HIR::ValueItem, (it->second->ent), (e), - (Import, - ), - (StructConstant, - ), - (StructConstructor, - ), - (Function, - return EntPtr { &e }; - ), - (Constant, - return EntPtr { &e }; - ), - (Static, - return EntPtr { &e }; - ) - ) - BUG(sp, "Path " << path << " pointed to a invalid item - " << it->second->ent.tag_str()); - } break; - case EntNS::Type: { - auto it = mod.m_mod_items.find( path.m_components.back() ); - if( it == mod.m_mod_items.end() ) { - return EntPtr {}; - } - - TU_MATCH( ::HIR::TypeItem, (it->second->ent), (e), - (Import, - ), - (Module, - ), - (Trait, - ), - (Struct, - return &e; - ), - (Union, - ), - (Enum, - ), - (TypeAlias, - ) - ) - BUG(sp, "Path " << path << " pointed to an invalid item - " << it->second->ent.tag_str()); - } break; - } - throw ""; - } - EntPtr get_ent_fullpath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path, EntNS ns, MonomorphState& out_ms) - { - TU_MATCH(::HIR::Path::Data, (path.m_data), (e), - (Generic, - out_ms = MonomorphState {}; - out_ms.pp_method = &e.m_params; - return get_ent_simplepath(sp, crate, e.m_path, ns); - ), - (UfcsInherent, - // Easy (ish) - EntPtr rv; - crate.find_type_impls(*e.type, [](const auto&x)->const auto& { return x; }, [&](const auto& impl) { - switch( ns ) - { - case EntNS::Value: - { - auto fit = impl.m_methods.find(e.item); - if( fit != impl.m_methods.end() ) - { - DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type); - rv = EntPtr { &fit->second.data }; - return true; - } - } - { - auto it = impl.m_constants.find(e.item); - if( it != impl.m_constants.end() ) - { - rv = EntPtr { &it->second.data }; - return true; - } - } - break; - case EntNS::Type: - break; - } - return false; - }); - out_ms = MonomorphState {}; - out_ms.pp_method = &e.params; - out_ms.pp_impl = &e.impl_params; - return rv; - ), - (UfcsKnown, - EntPtr rv; - crate.find_trait_impls(e.trait.m_path, *e.type, [](const auto&x)->const auto& { return x; }, [&](const auto& impl) { - // Hacky selection of impl. - // - TODO: Specialisation - // - TODO: Inference? (requires full typeck) - switch( ns ) - { - case EntNS::Value: - { - auto fit = impl.m_methods.find(e.item); - if( fit != impl.m_methods.end() ) - { - DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type); - rv = EntPtr { &fit->second.data }; - return true; - } - } - { - auto it = impl.m_constants.find(e.item); - if( it != impl.m_constants.end() ) - { - rv = EntPtr { &it->second.data }; - return true; - } - } - break; - case EntNS::Type: - break; - } - return false; - }); - out_ms = MonomorphState {}; - out_ms.pp_method = &e.params; - // TODO: How to get pp_impl here? Needs specialisation magic. - return rv; - ), - (UfcsUnknown, - // TODO: Are these valid at this point in compilation? - TODO(sp, "get_ent_fullpath(path = " << path << ")"); - ) - ) - throw ""; - } - const ::HIR::Function& get_function(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path, MonomorphState& out_ms) - { - auto rv = get_ent_fullpath(sp, crate, path, EntNS::Value, out_ms); - TU_IFLET( EntPtr, rv, Function, e, - return *e; - ) - else { - TODO(sp, "Could not find function for " << path << " - " << rv.tag_str()); - } - } - - ::HIR::Literal evaluate_constant_mir(const Span& sp, const StaticTraitResolve& resolve, NewvalState& newval_state, FmtLambda name, const ::MIR::Function& fcn, MonomorphState ms, ::std::vector< ::HIR::Literal> args) - { - TRACE_FUNCTION; - - ::MIR::TypeResolve state { sp, resolve, name, ::HIR::TypeRef(), {}, fcn }; - - ::HIR::Literal retval; - ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); - - struct LocalState { - typedef ::std::vector< ::HIR::Literal> t_vec_lit; - ::MIR::TypeResolve& state; - ::HIR::Literal& retval; - ::std::vector< ::HIR::Literal>& args; - ::std::vector< ::HIR::Literal>& locals; - - LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& args, t_vec_lit& locals): - state(state), - retval(retval), - args(args), - locals(locals) - {} - - ::HIR::Literal& get_lval(const ::MIR::LValue& lv) - { - TU_MATCHA( (lv), (e), - (Return, - return retval; - ), - (Local, - if( e >= locals.size() ) - MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size()); - return locals[e]; - ), - (Argument, - if( e.idx >= args.size() ) - MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size()); - return args[e.idx]; - ), - (Static, - MIR_TODO(state, "LValue::Static - " << e); - ), - (Field, - auto& val = get_lval(*e.val); - MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); - auto& vals = val.as_List(); - MIR_ASSERT(state, e.field_index < vals.size(), "LValue::Field index out of range"); - return vals[ e.field_index ]; - ), - (Deref, - auto& val = get_lval(*e.val); - TU_MATCH_DEF( ::HIR::Literal, (val), (ve), - ( - MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }"); - ), - (String, - // Just clone the string (hack) - // - TODO: Create a list? - return val; - ) - ) - ), - (Index, - auto& val = get_lval(*e.val); - MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv); - auto& idx = get_lval(*e.idx); - MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv); - auto& vals = val.as_List(); - auto idx_v = static_cast<size_t>( idx.as_Integer() ); - MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range"); - return vals[ idx_v ]; - ), - (Downcast, - MIR_TODO(state, "LValue::Downcast - " << lv); - ) - ) - throw ""; - } - }; - LocalState local_state( state, retval, args, locals ); - - auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { return local_state.get_lval(lv); }; - auto read_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal { - auto& v = get_lval(lv); - TU_MATCH_DEF(::HIR::Literal, (v), (e), - ( - return mv$(v); - ), - (Invalid, - BUG(sp, "Read of lvalue with Literal::Invalid - " << lv); - ), - (BorrowPath, - return ::HIR::Literal(e.clone()); - ), - (Integer, - return ::HIR::Literal(e); - ), - (Float, - return ::HIR::Literal(e); - ) - ) - }; - auto const_to_lit = [&](const ::MIR::Constant& c)->::HIR::Literal { - TU_MATCH(::MIR::Constant, (c), (e2), - (Int, - return ::HIR::Literal(static_cast<uint64_t>(e2.v)); - ), - (Uint, - return ::HIR::Literal(e2.v); - ), - (Float, - return ::HIR::Literal(e2.v); - ), - (Bool, - return ::HIR::Literal(static_cast<uint64_t>(e2.v)); - ), - (Bytes, - return ::HIR::Literal::make_String({e2.begin(), e2.end()}); - ), - (StaticString, - return ::HIR::Literal(e2); - ), - (Const, - MonomorphState const_ms; - // TODO: Monomorph the path? (Not needed... yet) - auto ent = get_ent_fullpath(sp, resolve.m_crate, e2.p, EntNS::Value, const_ms); - ASSERT_BUG(sp, ent.is_Constant(), "MIR Constant::Const("<<e2.p<<") didn't point to a Constant - " << ent.tag_str()); - const auto& c = *ent.as_Constant(); - // Prefer re-evaluating the MIR. - // - Constants insert themselves directly, so this is - // effectively the same thing. - // Avoids _BorrowData leftovers. - if( c.m_value ) { - return evaluate_constant(sp, resolve, newval_state, FMT_CB(ss, ss << e2.p;), ent.as_Constant()->m_value, {}, {}); - } - else { - auto val = clone_literal( ent.as_Constant()->m_value_res ); - ASSERT_BUG(sp, !val.is_Invalid(), "MIR Constant::Const("<<e2.p<<") pointed to invalid Constant - (no mir, no literal)"); - // Monomorphise the value according to `const_ms` - monomorph_literal_inplace(sp, val, const_ms); - return val; - } - ), - (ItemAddr, - return ::HIR::Literal::make_BorrowPath( ms.monomorph(sp, e2) ); - ) - ) - throw ""; - }; - auto read_param = [&](const ::MIR::Param& p) ->::HIR::Literal { - TU_MATCH(::MIR::Param, (p), (e), - (LValue, - return read_lval(e); - ), - (Constant, - return const_to_lit(e); - ) - ) - throw ""; - }; - - unsigned int cur_block = 0; - for(;;) - { - const auto& block = fcn.blocks[cur_block]; - unsigned int next_stmt_idx = 0; - for(const auto& stmt : block.statements) - { - state.set_cur_stmt(cur_block, next_stmt_idx++); - - if( ! stmt.is_Assign() ) { - //BUG(sp, "Non-assign statement - drop " << stmt.as_Drop().slot); - continue ; - } - const auto& sa = stmt.as_Assign(); - - DEBUG(sa.dst << " = " << sa.src); - ::HIR::Literal val; - TU_MATCHA( (sa.src), (e), - (Use, - val = read_lval(e); - ), - (Constant, - val = const_to_lit(e); - ), - (SizedArray, - ::std::vector< ::HIR::Literal> vals; - if( e.count > 0 ) - { - vals.reserve( e.count ); - val = read_param(e.val); - for(unsigned int i = 1; i < e.count; i++) - vals.push_back( clone_literal(val) ); - vals.push_back( mv$(val) ); - } - val = ::HIR::Literal::make_List( mv$(vals) ); - ), - (Borrow, - if( e.type != ::HIR::BorrowType::Shared ) { - MIR_BUG(state, "Only shared borrows are allowed in constants"); - } - if( const auto* p = e.val.opt_Deref() ) { - if( p->val->is_Deref() ) - MIR_TODO(state, "Undo nested deref coercion - " << *p->val); - val = read_lval(*p->val); - } - else if( const auto* p = e.val.opt_Static() ) { - // Borrow of a static, emit BorrowPath with the same path - val = ::HIR::Literal::make_BorrowPath( p->clone() ); - } - else { - auto inner_val = read_lval(e.val); - - ::HIR::TypeRef inner_ty; - const auto& inner_ty_r = state.get_lvalue_type(inner_ty, e.val); - if( &inner_ty_r != &inner_ty ) - inner_ty = inner_ty_r.clone(); - - // Create new static containing borrowed data - // NOTE: Doesn't use BorrowData - auto item_path = newval_state.new_static( mv$(inner_ty), mv$(inner_val) ); - val = ::HIR::Literal::make_BorrowPath( mv$(item_path) ); - } - ), - (Cast, - auto inval = read_lval(e.val); - TU_MATCH_DEF(::HIR::TypeRef::Data, (e.type.m_data), (te), - ( - // NOTE: Can be an unsizing! - TODO(sp, "RValue::Cast to " << e.type << ", val = " << inval); - ), - (Primitive, - auto cast_to_int = [&inval,&e,&sp](bool is_signed, unsigned bits) { - uint64_t mask = (bits >= 64 ? ~0ull : (1ull << bits) - 1); - uint64_t outval; - TU_IFLET( ::HIR::Literal, inval, Integer, i, - outval = i & mask; - if( bits < 64 && is_signed && (outval >> (bits-1)) ) - outval |= ~mask; - ) - else TU_IFLET( ::HIR::Literal, inval, Float, i, - outval = static_cast<uint64_t>(i) & mask; - if( is_signed && i < 0 ) - outval |= ~mask; - ) - else { - BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); - } - return ::HIR::Literal(outval); - }; - switch(te) - { - // Integers mask down - case ::HIR::CoreType::I8: val = cast_to_int(true , 8); break; - case ::HIR::CoreType::U8: val = cast_to_int(false, 8); break; - case ::HIR::CoreType::I16: val = cast_to_int(true , 16); break; - case ::HIR::CoreType::U16: val = cast_to_int(false, 16); break; - case ::HIR::CoreType::I32: val = cast_to_int(true , 32); break; - case ::HIR::CoreType::U32: val = cast_to_int(false, 32); break; - - case ::HIR::CoreType::I64: val = cast_to_int(true , 64); break; - case ::HIR::CoreType::U64: val = cast_to_int(false, 64); break; - case ::HIR::CoreType::I128: val = cast_to_int(true , 64); break; - case ::HIR::CoreType::U128: val = cast_to_int(false, 64); break; - case ::HIR::CoreType::Isize: val = cast_to_int(true , 64); break; - case ::HIR::CoreType::Usize: val = cast_to_int(false, 64); break; - - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - TU_IFLET( ::HIR::Literal, inval, Integer, i, - val = ::HIR::Literal( static_cast<double>(i) ); - ) - else TU_IFLET( ::HIR::Literal, inval, Float, i, - val = ::HIR::Literal( i ); - ) - else { - BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); - } - break; - default: - TODO(sp, "RValue::Cast to " << e.type << ", val = " << inval); - } - ), - // Allow casting any integer value to a pointer (TODO: Ensure that the pointer is sized?) - (Pointer, - TU_IFLET( ::HIR::Literal, inval, Integer, i, - val = ::HIR::Literal(i); - ) - else if( inval.is_BorrowData() || inval.is_BorrowPath() ) { - val = mv$(inval); - } - else { - BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); - } - ), - (Borrow, - if( inval.is_BorrowData() || inval.is_BorrowPath() ) { - val = mv$(inval); - } - else { - BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); - } - ) - ) - ), - (BinOp, - auto inval_l = read_param(e.val_l); - auto inval_r = read_param(e.val_r); - ASSERT_BUG(sp, inval_l.tag() == inval_r.tag(), "Mismatched literal types in binop - " << inval_l << " and " << inval_r); - TU_MATCH_DEF( ::HIR::Literal, (inval_l, inval_r), (l, r), - ( - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - ), - (Float, - switch(e.op) - { - case ::MIR::eBinOp::ADD: val = ::HIR::Literal( l + r ); break; - case ::MIR::eBinOp::SUB: val = ::HIR::Literal( l - r ); break; - case ::MIR::eBinOp::MUL: val = ::HIR::Literal( l * r ); break; - case ::MIR::eBinOp::DIV: val = ::HIR::Literal( l / r ); break; - case ::MIR::eBinOp::MOD: - case ::MIR::eBinOp::ADD_OV: - case ::MIR::eBinOp::SUB_OV: - case ::MIR::eBinOp::MUL_OV: - case ::MIR::eBinOp::DIV_OV: - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - - case ::MIR::eBinOp::BIT_OR : - case ::MIR::eBinOp::BIT_AND: - case ::MIR::eBinOp::BIT_XOR: - case ::MIR::eBinOp::BIT_SHL: - case ::MIR::eBinOp::BIT_SHR: - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - // TODO: GT/LT are incorrect for signed integers - case ::MIR::eBinOp::EQ: val = ::HIR::Literal( static_cast<uint64_t>(l == r) ); break; - case ::MIR::eBinOp::NE: val = ::HIR::Literal( static_cast<uint64_t>(l != r) ); break; - case ::MIR::eBinOp::GT: val = ::HIR::Literal( static_cast<uint64_t>(l > r) ); break; - case ::MIR::eBinOp::GE: val = ::HIR::Literal( static_cast<uint64_t>(l >= r) ); break; - case ::MIR::eBinOp::LT: val = ::HIR::Literal( static_cast<uint64_t>(l < r) ); break; - case ::MIR::eBinOp::LE: val = ::HIR::Literal( static_cast<uint64_t>(l <= r) ); break; - } - ), - (Integer, - switch(e.op) - { - case ::MIR::eBinOp::ADD: val = ::HIR::Literal( l + r ); break; - case ::MIR::eBinOp::SUB: val = ::HIR::Literal( l - r ); break; - case ::MIR::eBinOp::MUL: val = ::HIR::Literal( l * r ); break; - case ::MIR::eBinOp::DIV: val = ::HIR::Literal( l / r ); break; - case ::MIR::eBinOp::MOD: val = ::HIR::Literal( l % r ); break; - case ::MIR::eBinOp::ADD_OV: - case ::MIR::eBinOp::SUB_OV: - case ::MIR::eBinOp::MUL_OV: - case ::MIR::eBinOp::DIV_OV: - TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - - case ::MIR::eBinOp::BIT_OR : val = ::HIR::Literal( l | r ); break; - case ::MIR::eBinOp::BIT_AND: val = ::HIR::Literal( l & r ); break; - case ::MIR::eBinOp::BIT_XOR: val = ::HIR::Literal( l ^ r ); break; - case ::MIR::eBinOp::BIT_SHL: val = ::HIR::Literal( l << r ); break; - case ::MIR::eBinOp::BIT_SHR: val = ::HIR::Literal( l >> r ); break; - // TODO: GT/LT are incorrect for signed integers - case ::MIR::eBinOp::EQ: val = ::HIR::Literal( static_cast<uint64_t>(l == r) ); break; - case ::MIR::eBinOp::NE: val = ::HIR::Literal( static_cast<uint64_t>(l != r) ); break; - case ::MIR::eBinOp::GT: val = ::HIR::Literal( static_cast<uint64_t>(l > r) ); break; - case ::MIR::eBinOp::GE: val = ::HIR::Literal( static_cast<uint64_t>(l >= r) ); break; - case ::MIR::eBinOp::LT: val = ::HIR::Literal( static_cast<uint64_t>(l < r) ); break; - case ::MIR::eBinOp::LE: val = ::HIR::Literal( static_cast<uint64_t>(l <= r) ); break; - } - ) - ) - ), - (UniOp, - auto inval = read_lval(e.val); - TU_IFLET( ::HIR::Literal, inval, Integer, i, - switch( e.op ) - { - case ::MIR::eUniOp::INV: - val = ::HIR::Literal( ~i ); - break; - case ::MIR::eUniOp::NEG: - val = ::HIR::Literal( -i ); - break; - } - ) - else TU_IFLET( ::HIR::Literal, inval, Float, i, - switch( e.op ) - { - case ::MIR::eUniOp::INV: - BUG(sp, "Invalid invert of Float"); - break; - case ::MIR::eUniOp::NEG: - val = ::HIR::Literal( -i ); - break; - } - ) - else { - BUG(sp, "Invalid invert of " << inval.tag_str()); - } - ), - (DstMeta, - TODO(sp, "RValue::DstMeta"); - ), - (DstPtr, - TODO(sp, "RValue::DstPtr"); - ), - (MakeDst, - auto ptr = read_param(e.ptr_val); - auto meta = read_param(e.meta_val); - if( ! meta.is_Integer() ) { - TODO(sp, "RValue::MakeDst - (non-integral meta) " << ptr << " , " << meta); - } - else { - val = mv$(ptr); - } - ), - (Tuple, - ::std::vector< ::HIR::Literal> vals; - vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) - vals.push_back( read_param(v) ); - val = ::HIR::Literal::make_List( mv$(vals) ); - ), - (Array, - ::std::vector< ::HIR::Literal> vals; - vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) - vals.push_back( read_param(v) ); - val = ::HIR::Literal::make_List( mv$(vals) ); - ), - (Variant, - auto ival = read_param(e.val); - val = ::HIR::Literal::make_Variant({ e.index, box$(ival) }); - ), - (Struct, - ::std::vector< ::HIR::Literal> vals; - vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) - vals.push_back( read_param(v) ); - val = ::HIR::Literal::make_List( mv$(vals) ); - ) - ) - - auto& dst = get_lval(sa.dst); - DEBUG("= " << val); - dst = mv$(val); - } - state.set_cur_stmt_term(cur_block); - DEBUG("> " << block.terminator); - TU_MATCH_DEF( ::MIR::Terminator, (block.terminator), (e), - ( - BUG(sp, "Unexpected terminator - " << block.terminator); - ), - (Goto, - cur_block = e; - ), - (Return, - return retval; - ), - (Call, - if( !e.fcn.is_Path() ) - BUG(sp, "Unexpected terminator - " << block.terminator); - const auto& fcnp_raw = e.fcn.as_Path(); - auto fcnp = ms.monomorph(sp, fcnp_raw); - - auto& dst = get_lval(e.ret_val); - MonomorphState fcn_ms; - auto& fcn = get_function(sp, resolve.m_crate, fcnp, fcn_ms); - - ::std::vector< ::HIR::Literal> call_args; - call_args.reserve( e.args.size() ); - for(const auto& a : e.args) - call_args.push_back( read_param(a) ); - // TODO: Set m_const during parse and check here - - // Call by invoking evaluate_constant on the function - { - TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }"); - dst = evaluate_constant(sp, resolve, newval_state, FMT_CB(ss, ss << fcnp;), fcn.m_code, mv$(fcn_ms), mv$(call_args)); - } - - DEBUG("= " << dst); - cur_block = e.ret_block; - ) - ) - } - } - - ::HIR::Literal evaluate_constant(const Span& sp, const StaticTraitResolve& resolve, NewvalState& newval_state, FmtLambda name, const ::HIR::ExprPtr& expr, MonomorphState ms, ::std::vector< ::HIR::Literal> args) - { - if( expr.m_mir ) { - return evaluate_constant_mir(sp, resolve, newval_state, name, *expr.m_mir, mv$(ms), mv$(args)); - } - else { - BUG(sp, "Attempting to evaluate constant expression with no associated code"); - } - } - - void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit) - { - // TODO: Mask down limited size integers - TU_MATCHA( (type.m_data), (te), - (Infer, - ), - (Diverge, - ), - (Generic, - ), - (Slice, - ), - (TraitObject, - ), - (ErasedType, - ), - (Closure, - ), - - (Path, - // List - ), - (Array, - // List - ), - (Tuple, - // List - ), - - (Borrow, - // A whole host of things - ), - (Pointer, - // Integer, or itemaddr? - ), - (Function, - // ItemAddr - ), - - (Primitive, - switch(te) - { - case ::HIR::CoreType::Str: - BUG(sp, "Direct str literal not valid"); - case ::HIR::CoreType::F32: - case ::HIR::CoreType::F64: - ASSERT_BUG(sp, lit.is_Float(), "Bad literal type for " << type << " - " << lit); - break; - default: - ASSERT_BUG(sp, lit.is_Integer(), "Bad literal type for " << type << " - " << lit); - switch(te) - { - case ::HIR::CoreType::U8: lit.as_Integer() &= (1ull<<8)-1; break; - case ::HIR::CoreType::U16: lit.as_Integer() &= (1ull<<16)-1; break; - case ::HIR::CoreType::U32: lit.as_Integer() &= (1ull<<32)-1; break; - - //case ::HIR::CoreType::I8: lit.as_Integer() &= (1ull<<8)-1; break; - //case ::HIR::CoreType::I16: lit.as_Integer() &= (1ull<<16)-1; break; - //case ::HIR::CoreType::I32: lit.as_Integer() &= (1ull<<32)-1; break; - default: - break; - } - break; - } - ) - ) - } - - class Expander: - public ::HIR::Visitor - { - const ::HIR::Crate& m_crate; - StaticTraitResolve m_resolve; - - const ::HIR::ItemPath* m_mod_path; - t_new_values m_new_values; - - public: - Expander(const ::HIR::Crate& crate): - m_crate(crate), - m_resolve(crate) - {} - - void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override - { - auto saved_mp = m_mod_path; - m_mod_path = &p; - auto saved = mv$( m_new_values ); - - ::HIR::Visitor::visit_module(p, mod); - - for( auto& item : m_new_values ) - { - auto boxed_ent = box$(::HIR::VisEnt<::HIR::ValueItem> { false, ::HIR::ValueItem(mv$(item.second)) }); - auto it = mod.m_value_items.find( item.first ); - if( it != mod.m_value_items.end() ) - { - it->second = mv$(boxed_ent); - } - else - { - mod.m_value_items.insert( ::std::make_pair( mv$(item.first), mv$(boxed_ent) ) ); - } - } - m_new_values = mv$(saved); - m_mod_path = saved_mp; - } - - void visit_type(::HIR::TypeRef& ty) override - { - ::HIR::Visitor::visit_type(ty); - - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, - assert( e.size_val != ~0u ); - ) - } - void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override - { - visit_type(item.m_type); - if( item.m_value ) - { - auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }; - item.m_value_res = evaluate_constant(item.m_value->span(), m_resolve, nvs, FMT_CB(ss, ss << p;), item.m_value, {}, {}); - - check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); - DEBUG("constant: " << item.m_type << " = " << item.m_value_res); - visit_expr(item.m_value); - } - } - void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override - { - visit_type(item.m_type); - if( item.m_value ) - { - auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }; - item.m_value_res = evaluate_constant(item.m_value->span(), m_resolve, nvs, FMT_CB(ss, ss << p;), item.m_value, {}, {}); - DEBUG("static: " << item.m_type << " = " << item.m_value_res); - visit_expr(item.m_value); - } - } - void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { - if(auto* e = item.m_data.opt_Value()) - { - for(auto& var : e->variants) - { - if( var.expr ) - { - auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") }; - auto val = evaluate_constant(var.expr->span(), m_resolve, nvs, FMT_CB(ss, ss << p;), var.expr, {}, {}); - DEBUG("Enum value " << p << " - " << var.name << " = " << val); - // TODO: Save this value? Or just do the above to - // validate? - } - } - } - ::HIR::Visitor::visit_enum(p, item); - } - }; -} // namespace - -void ConvertHIR_ConstantEvaluateFull(::HIR::Crate& crate) -{ - Expander exp { crate }; - exp.visit_crate( crate ); -} diff --git a/src/hir_expand/main_bindings.hpp b/src/hir_expand/main_bindings.hpp index 6b9d5bab..5971e714 100644 --- a/src/hir_expand/main_bindings.hpp +++ b/src/hir_expand/main_bindings.hpp @@ -9,6 +9,7 @@ namespace HIR { class Crate; + class ExprPtr; }; extern void HIR_Expand_AnnotateUsage(::HIR::Crate& crate); @@ -18,3 +19,8 @@ extern void HIR_Expand_UfcsEverything(::HIR::Crate& crate); extern void HIR_Expand_Reborrows(::HIR::Crate& crate); extern void HIR_Expand_ErasedType(::HIR::Crate& crate); extern void ConvertHIR_ConstantEvaluateFull(::HIR::Crate& crate); + +extern void HIR_Expand_AnnotateUsage_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp); +extern void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp); +extern void HIR_Expand_UfcsEverything_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp); +extern void HIR_Expand_Reborrows_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp); diff --git a/src/hir_expand/reborrow.cpp b/src/hir_expand/reborrow.cpp index d276f57d..cb466f6f 100644 --- a/src/hir_expand/reborrow.cpp +++ b/src/hir_expand/reborrow.cpp @@ -226,6 +226,11 @@ namespace { }; } // namespace +void HIR_Expand_Reborrows_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp) +{ + ExprVisitor_Mutate ev(crate); + ev.visit_node_ptr( exp ); +} void HIR_Expand_Reborrows(::HIR::Crate& crate) { OuterVisitor ov(crate); diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index 629dd284..ffdc0a77 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -812,6 +812,11 @@ namespace { }; } // namespace +void HIR_Expand_UfcsEverything_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp) +{ + ExprVisitor_Mutate ev { crate }; + ev.visit_node_ptr(exp); +} void HIR_Expand_UfcsEverything(::HIR::Crate& crate) { OuterVisitor ov(crate); diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp index 123f51b3..1a153aaf 100644 --- a/src/hir_typeck/expr_visit.cpp +++ b/src/hir_typeck/expr_visit.cpp @@ -9,12 +9,17 @@ #include <hir/expr.hpp> #include <hir/visitor.hpp> #include "expr_visit.hpp" +#include <hir/expr_state.hpp> -namespace { - void Typecheck_Code(const typeck::ModuleState& ms, t_args& args, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr) { +void Typecheck_Code(const typeck::ModuleState& ms, t_args& args, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr) { + if( expr.m_state->stage < ::HIR::ExprState::Stage::Typecheck ) + { //Typecheck_Code_Simple(ms, args, result_type, expr); Typecheck_Code_CS(ms, args, result_type, expr); } +} + +namespace { class OuterVisitor: diff --git a/src/hir_typeck/expr_visit.hpp b/src/hir_typeck/expr_visit.hpp index 2263a66f..21a775dc 100644 --- a/src/hir_typeck/expr_visit.hpp +++ b/src/hir_typeck/expr_visit.hpp @@ -9,14 +9,14 @@ namespace typeck { struct ModuleState { - ::HIR::Crate& m_crate; + const ::HIR::Crate& m_crate; ::HIR::GenericParams* m_impl_generics; ::HIR::GenericParams* m_item_generics; ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; - ModuleState(::HIR::Crate& crate): + ModuleState(const ::HIR::Crate& crate): m_crate(crate), m_impl_generics(nullptr), m_item_generics(nullptr) @@ -65,5 +65,7 @@ namespace typeck { typedef ::std::vector< ::std::pair<::HIR::Pattern, ::HIR::TypeRef> > t_args; +// Needs to mutate the pattern +extern void Typecheck_Code(const typeck::ModuleState& ms, t_args& args, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr); extern void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr); extern void Typecheck_Code_Simple(const typeck::ModuleState& ms, t_args& args, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr); diff --git a/src/main.cpp b/src/main.cpp index 0e37f4a3..2dd05a05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -513,7 +513,10 @@ int main(int argc, char *argv[]) HIR_Expand_Closures(*hir_crate); }); // - Construct VTables for all traits and impls. - CompilePhaseV("Expand HIR VTables", [&]() { HIR_Expand_VTables(*hir_crate); }); + // TODO: How early can this be done? + CompilePhaseV("Expand HIR VTables", [&]() { + HIR_Expand_VTables(*hir_crate); + }); // - And calls can be turned into UFCS CompilePhaseV("Expand HIR Calls", [&]() { HIR_Expand_UfcsEverything(*hir_crate); @@ -560,11 +563,6 @@ int main(int argc, char *argv[]) MIR_CheckCrate(*hir_crate); }); - // Second shot of constant evaluation (with full type information) - CompilePhaseV("Constant Evaluate Full", [&]() { - ConvertHIR_ConstantEvaluateFull(*hir_crate); - }); - if( params.debug.dump_hir ) { // DUMP after consteval (full HIR again) diff --git a/src/mir/check.cpp b/src/mir/check.cpp index cfcc52d4..b2d86590 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -285,6 +285,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn }; ::std::vector<ToVisit> to_visit_blocks; + // TODO: Check that all used locals are also set (anywhere at all) + auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, auto vs) { for(const auto& b : to_visit_blocks) if( b.bb == idx && b.state == vs) diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 78939f78..37d256df 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -1219,7 +1219,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, void MIR_CleanupCrate(::HIR::Crate& crate) { ::MIR::OuterVisitor ov { crate, [&](const auto& res, const auto& p, auto& expr_ptr, const auto& args, const auto& ty){ - MIR_Cleanup(res, p, *expr_ptr.m_mir, args, ty); + MIR_Cleanup(res, p, expr_ptr.get_mir_or_error_mut(Span()), args, ty); } }; ov.visit_crate(crate); } diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index c390f5b6..90b81d5d 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -515,7 +515,7 @@ namespace { { m_os << indent() << "{\n"; inc_indent(); - dump_mir(m_os, m_indent_level, *item.m_code.m_mir); + dump_mir(m_os, m_indent_level, item.m_code.get_mir_or_error(Span())); dec_indent(); m_os << indent() << "}\n"; } @@ -538,7 +538,7 @@ namespace { inc_indent(); m_os << " = {\n"; inc_indent(); - dump_mir(m_os, m_indent_level, *item.m_value.m_mir); + dump_mir(m_os, m_indent_level, item.m_value.get_mir_or_error(Span())); dec_indent(); m_os << indent() << "} /* = " << item.m_value_res << "*/;\n"; dec_indent(); @@ -562,7 +562,7 @@ namespace { inc_indent(); m_os << " = {\n"; inc_indent(); - dump_mir(m_os, m_indent_level, *item.m_value.m_mir); + dump_mir(m_os, m_indent_level, item.m_value.get_mir_or_error(Span())); dec_indent(); m_os << indent() << "} /* = " << item.m_value_res << "*/;\n"; dec_indent(); diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 66347879..5a629233 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -17,7 +17,7 @@ #include "from_hir.hpp" #include "operations.hpp" #include <mir/visit_crate_mir.hpp> - +#include <hir/expr_state.hpp> namespace { @@ -1037,9 +1037,8 @@ namespace { // Short-circuiting boolean operations if( node.m_op == ::HIR::ExprNode_BinOp::Op::BoolAnd || node.m_op == ::HIR::ExprNode_BinOp::Op::BoolOr ) { - // TODO: Generate a SplitScope to handle the early breaks. - auto split_scope = m_builder.new_scope_split(node.span()); + DEBUG("- ShortCircuit Left"); this->visit_node_ptr(node.m_left); auto left = m_builder.get_result_in_lvalue(node.m_left->span(), ty_l); @@ -1048,12 +1047,16 @@ namespace { auto bb_false = m_builder.new_bb_unlinked(); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(left), bb_true, bb_false }) ); + // Generate a SplitScope to handle the conditional nature of the next code + auto split_scope = m_builder.new_scope_split(node.span()); + if( node.m_op == ::HIR::ExprNode_BinOp::Op::BoolOr ) { + DEBUG("- ShortCircuit ||"); // If left is true, assign result true and return m_builder.set_cur_block( bb_true ); m_builder.push_stmt_assign(node.span(), res.clone(), ::MIR::RValue( ::MIR::Constant::make_Bool({true}) )); - m_builder.end_split_arm(node.m_left->span(), split_scope, true); + m_builder.end_split_arm(node.m_left->span(), split_scope, /*reachable=*/true); m_builder.end_block( ::MIR::Terminator::make_Goto(bb_next) ); // If left is false, assign result to right @@ -1061,22 +1064,24 @@ namespace { } else { + DEBUG("- ShortCircuit &&"); // If left is false, assign result false and return m_builder.set_cur_block( bb_false ); m_builder.push_stmt_assign(node.span(), res.clone(), ::MIR::RValue( ::MIR::Constant::make_Bool({false}) )); - m_builder.end_split_arm(node.m_left->span(), split_scope, true); + m_builder.end_split_arm(node.m_left->span(), split_scope, /*reachable=*/true); m_builder.end_block( ::MIR::Terminator::make_Goto(bb_next) ); // If left is true, assign result to right m_builder.set_cur_block( bb_true ); } + DEBUG("- ShortCircuit Right"); auto tmp_scope = m_builder.new_scope_temp(node.m_right->span()); this->visit_node_ptr(node.m_right); m_builder.push_stmt_assign(node.span(), res.clone(), m_builder.get_result(node.m_right->span())); m_builder.terminate_scope(node.m_right->span(), mv$(tmp_scope)); - m_builder.end_split_arm(node.m_left->span(), split_scope, true); + m_builder.end_split_arm(node.m_right->span(), split_scope, /*reachable=*/true); m_builder.end_block( ::MIR::Terminator::make_Goto(bb_next) ); m_builder.set_cur_block( bb_next ); @@ -2409,10 +2414,24 @@ namespace { // -------------------------------------------------------------------- +void HIR_GenerateMIR_Expr(const ::HIR::Crate& crate, const ::HIR::ItemPath& path, ::HIR::ExprPtr& expr_ptr, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& res_ty) +{ + if( !expr_ptr.m_mir ) + { + StaticTraitResolve resolve { crate }; + if(expr_ptr.m_state->m_impl_generics) resolve.set_impl_generics(*expr_ptr.m_state->m_impl_generics); + if(expr_ptr.m_state->m_item_generics) resolve.set_item_generics(*expr_ptr.m_state->m_item_generics); + expr_ptr.set_mir( LowerMIR(resolve, path, expr_ptr, res_ty, args) ); + } +} + void HIR_GenerateMIR(::HIR::Crate& crate) { ::MIR::OuterVisitor ov { crate, [&](const auto& res, const auto& p, auto& expr_ptr, const auto& args, const auto& ty){ - expr_ptr.m_mir = LowerMIR(res, p, expr_ptr, ty, args); + if( !expr_ptr.get_mir_opt() ) + { + expr_ptr.set_mir( LowerMIR(res, p, expr_ptr, ty, args) ); + } } }; ov.visit_crate(crate); } diff --git a/src/mir/main_bindings.hpp b/src/mir/main_bindings.hpp index cb4f3232..69d5fd90 100644 --- a/src/mir/main_bindings.hpp +++ b/src/mir/main_bindings.hpp @@ -7,10 +7,8 @@ */ #pragma once #include <iostream> +#include <hir/hir.hpp> -namespace HIR { -class Crate; -} class TransList; extern void HIR_GenerateMIR(::HIR::Crate& crate); @@ -21,3 +19,5 @@ extern void MIR_CheckCrate_Full(/*const*/ ::HIR::Crate& crate); extern void MIR_CleanupCrate(::HIR::Crate& crate); extern void MIR_OptimiseCrate(::HIR::Crate& crate, bool minimal_optimisations); extern void MIR_OptimiseCrate_Inlining(const ::HIR::Crate& crate, TransList& list); + +extern void HIR_GenerateMIR_Expr(const ::HIR::Crate& crate, const ::HIR::ItemPath& path, ::HIR::ExprPtr& expr_ptr, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& res_ty); diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index f2b3a246..3e14ce66 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -2193,6 +2193,7 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv) { if( !lvalue_is_copy(sp, lv) ) { auto& vs = get_val_state_mut(sp, lv); + // TODO: If the current state is Optional, set the drop flag to 0 vs = VarState::make_Invalid(InvalidType::Moved); } } diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 06a8e3dd..ef9c5fc9 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -27,7 +27,7 @@ #define CHECK_AFTER_ALL 1 #define DUMP_AFTER_PASS 1 -#define DUMP_AFTER_DONE 0 +#define DUMP_AFTER_DONE 1 #define CHECK_AFTER_DONE 2 // 1 = Check before GC, 2 = check before and after GC // ---- @@ -106,12 +106,14 @@ bool MIR_OptimiseInline(const StaticTraitResolve& resolve, const ::HIR::ItemPath // - Constant propagation (inlining may have lead to some more constant information MIR_Optimise_ConstPropagte(state, fcn); // - Unify non-overlapping locals +#if 0 if(MIR_Optimise_UnifyTemporaries(state, fcn)) { #if CHECK_AFTER_ALL MIR_Validate(resolve, path, fcn, args, ret_type); #endif } +#endif // - Remove no-op statements MIR_Optimise_NoopRemoval(state, fcn); @@ -238,6 +240,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // Run UnifyTemporaries last, then unify blocks, then run some // optimisations that might be affected +#if 0 if(MIR_Optimise_UnifyTemporaries(state, fcn)) { #if CHECK_AFTER_ALL @@ -247,6 +250,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path //MIR_Optimise_ConstPropagte(state, fcn); MIR_Optimise_NoopRemoval(state, fcn); } +#endif #if DUMP_AFTER_DONE @@ -536,10 +540,10 @@ namespace { if( it->second->monomorphised.code ) { return &*it->second->monomorphised.code; } - else if( hir_fcn.m_code.m_mir ) { + else if( const auto* mir = hir_fcn.m_code.get_mir_opt() ) { MIR_ASSERT(state, hir_fcn.m_params.m_types.empty(), "Enumeration failure - Function had params, but wasn't monomorphised - " << path); // TODO: Check for trait methods too? - return &*hir_fcn.m_code.m_mir; + return mir; } else { MIR_ASSERT(state, !hir_fcn.m_code, "LowerMIR failure - No MIR but HIR is present?! - " << path); @@ -551,10 +555,10 @@ namespace { TU_MATCHA( (path.m_data), (pe), (Generic, const auto& fcn = state.m_crate.get_function_by_path(state.sp, pe.m_path); - if( fcn.m_code.m_mir ) + if( const auto* mir = fcn.m_code.get_mir_opt() ) { params.fcn_params = &pe.m_params; - return &*fcn.m_code.m_mir; + return mir; } ), (UfcsKnown, @@ -626,14 +630,14 @@ namespace { { params.impl_params.m_types = mv$(best_impl_params); DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type); - if( fit->second.data.m_code.m_mir ) - return &*fit->second.data.m_code.m_mir; + if( const auto* mir = fit->second.data.m_code.get_mir_opt() ) + return mir; } else { params.impl_params = pe.trait.m_params.clone(); - if( ve.m_code.m_mir ) - return &*ve.m_code.m_mir; + if( const auto* mir = ve.m_code.get_mir_opt() ) + return mir; } return nullptr; ), @@ -653,12 +657,12 @@ namespace { MIR_ASSERT(state, best_impl, "Couldn't find an impl for " << path); auto fit = best_impl->m_methods.find(pe.item); MIR_ASSERT(state, fit != best_impl->m_methods.end(), "Couldn't find method in best inherent impl"); - if( fit->second.data.m_code.m_mir ) + if( const auto* mir = fit->second.data.m_code.get_mir_opt() ) { params.self_ty = &*pe.type; params.fcn_params = &pe.params; params.impl_params = pe.impl_params.clone(); - return &*fit->second.data.m_code.m_mir; + return mir; } return nullptr; ), @@ -3243,36 +3247,97 @@ bool MIR_Optimise_DeadDropFlags(::MIR::TypeResolve& state, ::MIR::Function& fcn) { bool removed_statement = false; TRACE_FUNCTION_FR("", removed_statement); - ::std::vector<bool> read_drop_flags( fcn.drop_flags.size() ); - visit_blocks(state, fcn, [&read_drop_flags](auto , const ::MIR::BasicBlock& block) { - for(const auto& stmt : block.statements) - { - if( const auto* e = stmt.opt_SetDropFlag() ) + ::std::vector<bool> used_drop_flags( fcn.drop_flags.size() ); + { + ::std::vector<bool> read_drop_flags( fcn.drop_flags.size() ); + visit_blocks(state, fcn, [&read_drop_flags,&used_drop_flags](auto , const ::MIR::BasicBlock& block) { + for(const auto& stmt : block.statements) { - if(e->other != ~0u) { - read_drop_flags[e->other] = true; + if( const auto* e = stmt.opt_SetDropFlag() ) + { + if(e->other != ~0u) { + read_drop_flags[e->other] = true; + used_drop_flags[e->other] = true; + } + used_drop_flags[e->idx] = true; + } + else if( const auto* e = stmt.opt_Drop() ) + { + if(e->flag_idx != ~0u) { + read_drop_flags[e->flag_idx] = true; + used_drop_flags[e->flag_idx] = true; + } } } - else if( const auto* e = stmt.opt_Drop() ) + }); + DEBUG("Un-read drop flags:" << FMT_CB(ss, + for(size_t i = 0; i < read_drop_flags.size(); i ++) + if( ! read_drop_flags[i] && used_drop_flags[i] ) + ss << " " << i; + )); + visit_blocks_mut(state, fcn, [&read_drop_flags,&removed_statement](auto _id, auto& block) { + for(auto it = block.statements.begin(); it != block.statements.end(); ) { - if(e->flag_idx != ~0u) { - read_drop_flags[e->flag_idx] = true; + if(it->is_SetDropFlag() && ! read_drop_flags[it->as_SetDropFlag().idx] ) { + removed_statement = true; + it = block.statements.erase(it); + } + else { + ++ it; } } - } - }); - visit_blocks_mut(state, fcn, [&read_drop_flags,&removed_statement](auto _id, auto& block) { - for(auto it = block.statements.begin(); it != block.statements.end(); ) - { - if(it->is_SetDropFlag() && ! read_drop_flags[it->as_SetDropFlag().idx] ) { - removed_statement = true; - it = block.statements.erase(it); + }); + } + + // Find any drop flags that are never assigned with a value other than their default, then remove those dead assignments. + { + ::std::vector<bool> edited_drop_flags( fcn.drop_flags.size() ); + visit_blocks(state, fcn, [&edited_drop_flags,&fcn](auto , const ::MIR::BasicBlock& block) { + for(const auto& stmt : block.statements) + { + if( const auto* e = stmt.opt_SetDropFlag() ) + { + if(e->other != ~0u) { + // If the drop flag is set based on another, assume it's changed + edited_drop_flags[e->idx] = true; + } + else if( e->new_val != fcn.drop_flags[e->idx] ) { + // If the new value is not the default, it's changed + edited_drop_flags[e->idx] = true; + } + else { + // Set to the default, doesn't change the 'edited' state + } + } } - else { - ++ it; + }); + DEBUG("Un-edited drop flags:" << FMT_CB(ss, + for(size_t i = 0; i < edited_drop_flags.size(); i ++) + if( ! edited_drop_flags[i] && used_drop_flags[i] ) + ss << " " << i; + )); + visit_blocks_mut(state, fcn, [&edited_drop_flags,&removed_statement,&fcn](auto _id, auto& block) { + for(auto it = block.statements.begin(); it != block.statements.end(); ) + { + // If this is a SetDropFlag and the target flag isn't edited, remove + if(const auto* e = it->opt_SetDropFlag()) + { + if( ! edited_drop_flags[e->idx] ) { + assert( e->new_val == fcn.drop_flags[e->idx] ); + removed_statement = true; + it = block.statements.erase(it); + } + else { + ++ it; + } + } + else { + ++ it; + } } - } - }); + }); + } + return removed_statement; } @@ -3732,11 +3797,12 @@ void MIR_OptimiseCrate(::HIR::Crate& crate, bool do_minimal_optimisation) if( ! dynamic_cast<::HIR::ExprNode_Block*>(expr.get()) ) { return ; } + auto& mir = expr.get_mir_or_error_mut(Span()); if( do_minimal_optimisation ) { - MIR_OptimiseMin(res, p, *expr.m_mir, args, ty); + MIR_OptimiseMin(res, p, mir, args, ty); } else { - MIR_Optimise(res, p, *expr.m_mir, args, ty); + MIR_Optimise(res, p, mir, args, ty); } } }; @@ -3769,9 +3835,10 @@ void MIR_OptimiseCrate_Inlining(const ::HIR::Crate& crate, TransList& list) { did_inline_on_pass |= MIR_OptimiseInline(resolve, ip, *mono_fcn.code, mono_fcn.arg_tys, mono_fcn.ret_ty, list); } - else if( hir_fcn.m_code.m_mir) + else if( hir_fcn.m_code ) { - did_inline_on_pass |= MIR_OptimiseInline(resolve, ip, *hir_fcn.m_code.m_mir, hir_fcn.m_args, hir_fcn.m_return, list); + auto& mir = hir_fcn.m_code.get_mir_or_error_mut(Span()); + did_inline_on_pass |= MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list); } else { |