diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_conv/constant_evaluation.cpp | 150 | ||||
-rw-r--r-- | src/hir_expand/const_eval_full.cpp | 808 | ||||
-rw-r--r-- | src/hir_expand/main_bindings.hpp | 1 | ||||
-rw-r--r-- | src/hir_typeck/common.cpp | 17 | ||||
-rw-r--r-- | src/hir_typeck/common.hpp | 18 | ||||
-rw-r--r-- | src/hir_typeck/expr_visit.cpp | 1 | ||||
-rw-r--r-- | src/main.cpp | 11 | ||||
-rw-r--r-- | src/mir/cleanup.cpp | 2 | ||||
-rw-r--r-- | src/mir/mir.cpp | 28 | ||||
-rw-r--r-- | src/trans/enumerate.cpp | 29 |
10 files changed, 1040 insertions, 25 deletions
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 38b24f64..4e15f2d5 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -1,7 +1,9 @@ /* - * Evaluate constants + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) * - * HACK - Should be replaced with a reentrant typeck/mir pass + * hir_conv/constant_evaluation.cpp + * - Minimal (integer only) constant evaluation */ #include "main_bindings.hpp" #include <hir/hir.hpp> @@ -10,6 +12,7 @@ #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; @@ -18,13 +21,29 @@ namespace { 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) + name_prefix(prefix), + next_item_idx(0) { } + + ::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 { + false, + mv$(type), + ::HIR::ExprPtr(), + mv$(value) + } ) ); + return rv; + } }; ::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={}); @@ -434,6 +453,8 @@ namespace { } void visit(::HIR::ExprNode_Borrow& node) override { + badnode(node); + 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); @@ -1011,6 +1032,9 @@ namespace { { TRACE_FUNCTION; + StaticTraitResolve resolve { crate }; + ::MIR::TypeResolve state { sp, resolve, FMT_CB(), exp, {}, fcn }; + ::HIR::Literal retval; ::std::vector< ::HIR::Literal> locals; ::std::vector< ::HIR::Literal> temps; @@ -1078,10 +1102,14 @@ namespace { 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); + //BUG(sp, "Non-assign statement - drop " << stmt.as_Drop().slot); + continue ; } ::HIR::Literal val; @@ -1133,7 +1161,20 @@ namespace { val = ::HIR::Literal::make_List( mv$(vals) ); ), (Borrow, - TODO(sp, "RValue::Borrow"); + if( e.type != ::HIR::BorrowType::Shared ) { + MIR_BUG(state, "Only shared borrows are allowed in constants"); + } + + 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 + auto item_path = newval_state.new_static( mv$(inner_ty), mv$(inner_val) ); + val = ::HIR::Literal::make_BorrowOf( mv$(item_path) ); ), (Cast, auto inval = read_lval(e.val); @@ -1161,6 +1202,8 @@ namespace { if(0) case ::HIR::CoreType::I64: case ::HIR::CoreType::U64: + case ::HIR::CoreType::Usize: + case ::HIR::CoreType::Isize: mask = 0xFFFFFFFFFFFFFFFF; TU_IFLET( ::HIR::Literal, inval, Integer, i, @@ -1173,6 +1216,18 @@ namespace { BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); } 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); } @@ -1182,6 +1237,9 @@ namespace { TU_IFLET( ::HIR::Literal, inval, Integer, i, val = ::HIR::Literal(i); ) + else TU_IFLET( ::HIR::Literal, inval, BorrowOf, i, + val = mv$(inval); + ) else { BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); } @@ -1196,6 +1254,35 @@ namespace { ( 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) { @@ -1233,7 +1320,18 @@ namespace { { case ::MIR::eUniOp::INV: val = ::HIR::Literal( ~i ); - break; + 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; @@ -1250,7 +1348,14 @@ namespace { TODO(sp, "RValue::DstPtr"); ), (MakeDst, - TODO(sp, "RValue::MakeDst"); + auto ptr = read_lval(e.ptr_val); + auto meta = read_lval(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; @@ -1281,6 +1386,7 @@ namespace { auto& dst = 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); @@ -1319,12 +1425,12 @@ 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) { - if( expr ) { - return evaluate_constant_hir(sp, crate, mv$(newval_state), *expr, mv$(exp), mv$(args)); - } - else if( expr.m_mir ) { + 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)); + } else { BUG(sp, "Attempting to evaluate constant expression with no associated code"); } @@ -1446,26 +1552,21 @@ namespace { } void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override { - visit_type(item.m_type); + ::HIR::Visitor::visit_constant(p, item); + + //visit_type(item.m_type); if( item.m_value ) { + if( ! item.m_type.m_data.is_Primitive() ) + 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(), {}); 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 ) - { - item.m_value_res = evaluate_constant(item.m_value->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }, item.m_value, item.m_type.clone(), {}); - DEBUG("static: " << item.m_type << " = " << item.m_value_res); - visit_expr(item.m_value); + //visit_expr(item.m_value); } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { @@ -1512,7 +1613,8 @@ namespace { void visit(::HIR::ExprNode_ArraySized& node) override { assert( node.m_size ); - auto val = evaluate_constant_hir(node.span(), m_exp.m_crate, NewvalState { m_exp.m_new_values, *m_exp.m_mod_path, FMT("array_" << &node << "$") }, *node.m_size, ::HIR::CoreType::Usize, {}); + 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, {}); if( !val.is_Integer() ) ERROR(node.span(), E0000, "Array size isn't an integer"); node.m_size_val = val.as_Integer(); diff --git a/src/hir_expand/const_eval_full.cpp b/src/hir_expand/const_eval_full.cpp new file mode 100644 index 00000000..9411e1c7 --- /dev/null +++ b/src/hir_expand/const_eval_full.cpp @@ -0,0 +1,808 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * hir_expand/const_eval_full.cpp + * - More-complete constant evaluation + */ +#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) + { + } + + ::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 { + false, + mv$(type), + ::HIR::ExprPtr(), + mv$(value) + } ) ); + return rv; + } + }; + + ::HIR::Literal evaluate_constant(const Span& sp, const ::StaticTraitResolve& resolve, NewvalState newval_state, 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, + ::std::vector< ::HIR::Literal> vals; + for(const auto& val : e.vals) { + vals.push_back( clone_literal(val) ); + } + return ::HIR::Literal::make_Variant({ e.idx, mv$(vals) }); + ), + (Integer, + return ::HIR::Literal(e); + ), + (Float, + return ::HIR::Literal(e); + ), + (BorrowOf, + return ::HIR::Literal(e.clone()); + ), + (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, + for(auto& val : e.vals) { + monomorph_literal_inplace(sp, val, ms); + } + ), + (Integer, + ), + (Float, + ), + (BorrowOf, + DEBUG(e); + e = ms.monomorph(sp, e); + // TODO: expand associated types + ), + (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; + if( path.m_crate_name != "" ) { + ASSERT_BUG(sp, crate.m_ext_crates.count(path.m_crate_name) > 0, "Crate '" << path.m_crate_name << "' not loaded"); + mod = &crate.m_ext_crates.at(path.m_crate_name)->m_root_module; + } + else { + mod = &crate.m_root_module; + } + + for( unsigned int i = 0; i < path.m_components.size() - 1; i ++ ) + { + const auto& pc = path.m_components[i]; + auto it = mod->m_mod_items.find( pc ); + if( it == mod->m_mod_items.end() ) { + BUG(sp, "Couldn't find component " << i << " of " << path); + } + TU_MATCH_DEF( ::HIR::TypeItem, (it->second->ent), (e2), + ( + BUG(sp, "Node " << i << " of path " << path << " wasn't a module"); + ), + (Module, + mod = &e2; + ) + ) + } + + 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, const ::MIR::Function& fcn, MonomorphState ms, ::std::vector< ::HIR::Literal> args) + { + TRACE_FUNCTION; + + ::MIR::TypeResolve state { sp, resolve, FMT_CB(), ::HIR::TypeRef(), {}, fcn }; + + ::HIR::Literal retval; + ::std::vector< ::HIR::Literal> locals; + ::std::vector< ::HIR::Literal> temps; + locals.resize( fcn.named_variables.size() ); + temps.resize( fcn.temporaries.size() ); + + auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { + TU_MATCHA( (lv), (e), + (Variable, + if( e >= locals.size() ) + BUG(sp, "Local index out of range - " << e << " >= " << locals.size()); + return locals[e]; + ), + (Temporary, + if( e.idx >= temps.size() ) + BUG(sp, "Temp index out of range - " << e.idx << " >= " << temps.size()); + return temps[e.idx]; + ), + (Argument, + return args[e.idx]; + ), + (Static, + TODO(sp, "LValue::Static"); + ), + (Return, + return retval; + ), + (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 lvalue with Literal::Invalid - " << lv); + ), + (BorrowOf, + return ::HIR::Literal(e.clone()); + ), + (Integer, + return ::HIR::Literal(e); + ), + (Float, + return ::HIR::Literal(e); + ) + ) + }; + + 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, + TU_MATCH(::MIR::Constant, (e), (e2), + (Int, + val = ::HIR::Literal(static_cast<uint64_t>(e2)); + ), + (Uint, + val = ::HIR::Literal(e2); + ), + (Float, + val = ::HIR::Literal(e2); + ), + (Bool, + val = ::HIR::Literal(static_cast<uint64_t>(e2)); + ), + (Bytes, + val = ::HIR::Literal::make_String({e2.begin(), e2.end()}); + ), + (StaticString, + val = ::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()); + val = clone_literal( ent.as_Constant()->m_value_res ); + if( val.is_Invalid() ) { + val = evaluate_constant(sp, resolve, newval_state, ent.as_Constant()->m_value, {}, {}); + } + // Monomorphise the value according to `const_ms` + monomorph_literal_inplace(sp, val, const_ms); + ), + (ItemAddr, + val = ::HIR::Literal::make_BorrowOf( ms.monomorph(sp, e2) ); + ) + ) + ), + (SizedArray, + ::std::vector< ::HIR::Literal> vals; + if( e.count > 0 ) + { + vals.reserve( e.count ); + val = read_lval(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"); + } + + 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 + auto item_path = newval_state.new_static( mv$(inner_ty), mv$(inner_val) ); + val = ::HIR::Literal::make_BorrowOf( 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, + uint64_t mask; + switch(te) + { + // Integers mask down + case ::HIR::CoreType::I8: + case ::HIR::CoreType::U8: + mask = 0xFF; + if(0) + case ::HIR::CoreType::I16: + case ::HIR::CoreType::U16: + mask = 0xFFFF; + if(0) + case ::HIR::CoreType::I32: + case ::HIR::CoreType::U32: + mask = 0xFFFFFFFF; + if(0) + case ::HIR::CoreType::I64: + case ::HIR::CoreType::U64: + case ::HIR::CoreType::Usize: + case ::HIR::CoreType::Isize: + mask = 0xFFFFFFFFFFFFFFFF; + + TU_IFLET( ::HIR::Literal, inval, Integer, i, + val = ::HIR::Literal(i & mask); + ) + else TU_IFLET( ::HIR::Literal, inval, Float, i, + val = ::HIR::Literal( static_cast<uint64_t>(i) & mask); + ) + else { + BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); + } + 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 TU_IFLET( ::HIR::Literal, inval, BorrowOf, i, + val = mv$(inval); + ) + else { + BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); + } + ) + ) + ), + (BinOp, + auto inval_l = read_lval(e.val_l); + auto inval_r = read_lval(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_lval(e.ptr_val); + auto meta = read_lval(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_lval(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_lval(v) ); + val = ::HIR::Literal::make_List( mv$(vals) ); + ), + (Variant, + TODO(sp, "MIR _Variant"); + ), + (Struct, + ::std::vector< ::HIR::Literal> vals; + vals.reserve( e.vals.size() ); + for(const auto& v : e.vals) + vals.push_back( read_lval(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_lval(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, fcn.m_code, 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, const ::HIR::ExprPtr& expr, MonomorphState ms, ::std::vector< ::HIR::Literal> args) + { + if( expr.m_mir ) { + return evaluate_constant_mir(sp, resolve, mv$(newval_state), *expr.m_mir, ms, mv$(args)); + } + else { + BUG(sp, "Attempting to evaluate constant expression with no associated code"); + } + } + + 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 ) + { + 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_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, item.m_value, {}, {}); + + 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, mv$(nvs), 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 { + for(auto& var : item.m_variants) + { + TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, + auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.first << "$") }; + e.val = evaluate_constant(e.expr->span(), m_resolve, mv$(nvs), e.expr, {}, {}); + DEBUG("enum variant: " << p << "::" << var.first << " = " << e.val); + ) + } + ::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 4a3ac160..6b9d5bab 100644 --- a/src/hir_expand/main_bindings.hpp +++ b/src/hir_expand/main_bindings.hpp @@ -17,3 +17,4 @@ extern void HIR_Expand_Closures(::HIR::Crate& crate); 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); diff --git a/src/hir_typeck/common.cpp b/src/hir_typeck/common.cpp index bed6b0f4..0751d5a1 100644 --- a/src/hir_typeck/common.cpp +++ b/src/hir_typeck/common.cpp @@ -373,6 +373,23 @@ namespace { }, false); } +t_cb_generic MonomorphState::get_cb(const Span& sp) const +{ + return monomorphise_type_get_cb(sp, this->self_ty, this->pp_impl, this->pp_method); +} +::std::ostream& operator<<(::std::ostream& os, const MonomorphState& ms) +{ + os << "MonomorphState {"; + if(ms.self_ty) + os << " self=" << *ms.self_ty; + if(ms.pp_impl) + os << " I=" << *ms.pp_impl; + if(ms.pp_method) + os << " M=" << *ms.pp_method; + os << " }"; + return os; +} + void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct) { switch(ic) diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index 07ad9ff5..d6bf30c1 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -38,6 +38,24 @@ typedef ::std::function<bool(const ::HIR::TypeRef&, ::HIR::TypeRef&)> t_cb_clo /// Clones a type, calling the provided callback on every type (optionally providing a replacement) extern ::HIR::TypeRef clone_ty_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_clone_ty callback); +// Helper for passing a group of params around +struct MonomorphState +{ + const ::HIR::TypeRef* self_ty; + const ::HIR::PathParams* pp_impl; + const ::HIR::PathParams* pp_method; + + t_cb_generic get_cb(const Span& sp) const; + + ::HIR::TypeRef monomorph(const Span& sp, const ::HIR::TypeRef& ty, bool allow_infer=true) const { + return monomorphise_type_with(sp, ty, this->get_cb(sp), allow_infer); + } + ::HIR::Path monomorph(const Span& sp, const ::HIR::Path& tpl, bool allow_infer=true) const { + return monomorphise_path_with(sp, tpl, this->get_cb(sp), allow_infer); + } +}; +extern ::std::ostream& operator<<(::std::ostream& os, const MonomorphState& ms); + static inline t_cb_generic monomorphise_type_get_cb(const Span& sp, const ::HIR::TypeRef* self_ty, const ::HIR::PathParams* params_i, const ::HIR::PathParams* params_m, const ::HIR::PathParams* params_p=nullptr) { return [=](const auto& gt)->const auto& { diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp index 9713e862..83036720 100644 --- a/src/hir_typeck/expr_visit.cpp +++ b/src/hir_typeck/expr_visit.cpp @@ -11,6 +11,7 @@ namespace { Typecheck_Code_CS(ms, args, result_type, expr); } + class OuterVisitor: public ::HIR::Visitor { diff --git a/src/main.cpp b/src/main.cpp index 9d003537..96d05f29 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -64,6 +64,7 @@ void init_debug_list() g_debug_disable_map.insert( "Lower MIR" );
g_debug_disable_map.insert( "MIR Validate" );
g_debug_disable_map.insert( "Dump MIR" );
+ g_debug_disable_map.insert( "Constant Evaluate Full" );
g_debug_disable_map.insert( "HIR Serialise" );
g_debug_disable_map.insert( "Trans Enumerate" );
@@ -384,6 +385,16 @@ 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);
+ });
+
+ CompilePhaseV("Dump HIR", [&]() {
+ ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
+ HIR_Dump( os, *hir_crate );
+ });
+
// Optimise the MIR
// TODO: MIR Optimisation
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index c5a8c5b9..4268b288 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -74,6 +74,8 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR if( pe.m_params.m_types.size() != 0 ) TODO(sp, "Generic constants - " << path); out_ty = constant.m_type.clone(); + if( constant.m_value_res.is_Invalid() ) + return nullptr; return &constant.m_value_res; ), (UfcsUnknown, diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 2dd911ec..d7ae41cc 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -104,7 +104,33 @@ namespace MIR { os << "Cast(" << e.val << " as " << e.type << ")"; ), (BinOp, - os << "BinOp(" << e.val_l << " " << static_cast<int>(e.op) << " " << e.val_r << ")"; + os << "BinOp(" << e.val_l << " "; + switch(e.op) + { + case ::MIR::eBinOp::ADD: os << "ADD"; break; + case ::MIR::eBinOp::SUB: os << "SUB"; break; + case ::MIR::eBinOp::MUL: os << "MUL"; break; + case ::MIR::eBinOp::DIV: os << "DIV"; break; + case ::MIR::eBinOp::MOD: os << "MOD"; break; + case ::MIR::eBinOp::ADD_OV: os << "ADD_OV"; break; + case ::MIR::eBinOp::SUB_OV: os << "SUB_OV"; break; + case ::MIR::eBinOp::MUL_OV: os << "MUL_OV"; break; + case ::MIR::eBinOp::DIV_OV: os << "DIV_OV"; break; + + case ::MIR::eBinOp::BIT_OR : os << "BIT_OR" ; break; + case ::MIR::eBinOp::BIT_AND: os << "BIT_AND"; break; + case ::MIR::eBinOp::BIT_XOR: os << "BIT_XOR"; break; + case ::MIR::eBinOp::BIT_SHL: os << "BIT_SHL"; break; + case ::MIR::eBinOp::BIT_SHR: os << "BIT_SHR"; break; + + case ::MIR::eBinOp::EQ: os << "EQ"; break; + case ::MIR::eBinOp::NE: os << "NE"; break; + case ::MIR::eBinOp::GT: os << "GT"; break; + case ::MIR::eBinOp::GE: os << "GE"; break; + case ::MIR::eBinOp::LT: os << "LT"; break; + case ::MIR::eBinOp::LE: os << "LE"; break; + } + os << " " << e.val_r << ")"; ), (UniOp, os << "UniOp(" << e.val << " " << static_cast<int>(e.op) << ")"; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 62f6648e..85bb7474 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -499,6 +499,31 @@ void Trans_Enumerate_FillFrom_MIR(TransList& out, const ::HIR::Crate& crate, con } } +void Trans_Enumerate_FillFrom_Literal(TransList& out, const ::HIR::Crate& crate, const ::HIR::Literal& lit, const Trans_Params& pp) +{ + TU_MATCHA( (lit), (e), + (Invalid, + ), + (List, + for(const auto& v : e) + Trans_Enumerate_FillFrom_Literal(out, crate, v, pp); + ), + (Variant, + for(const auto& v : e.vals) + Trans_Enumerate_FillFrom_Literal(out, crate, v, pp); + ), + (Integer, + ), + (Float, + ), + (BorrowOf, + Trans_Enumerate_FillFrom_Path(out, crate, e, pp); + ), + (String, + ) + ) +} + void Trans_Enumerate_FillFrom(TransList& out, const ::HIR::Crate& crate, const ::HIR::Function& function, TransList_Function& out_fcn, Trans_Params pp) { TRACE_FUNCTION_F("Function pp=" << pp.pp_method<<"+"<<pp.pp_impl); @@ -516,6 +541,10 @@ void Trans_Enumerate_FillFrom(TransList& out, const ::HIR::Crate& crate, const : { Trans_Enumerate_FillFrom_MIR(out, crate, *item.m_value.m_mir, pp); } + else if( ! item.m_value_res.is_Invalid() ) + { + Trans_Enumerate_FillFrom_Literal(out, crate, item.m_value_res, pp); + } out_stat.ptr = &item; out_stat.pp = mv$(pp); } |