diff options
Diffstat (limited to 'src/hir_conv/constant_evaluation.cpp')
-rw-r--r-- | src/hir_conv/constant_evaluation.cpp | 505 |
1 files changed, 363 insertions, 142 deletions
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index ec313e4a..35669dd9 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -16,8 +16,15 @@ #include <trans/target.hpp> #include <hir/expr_state.hpp> +#include "constant_evaluation.hpp" +#include <trans/monomorphise.hpp> // For handling monomorph of MIR in provided associated constants + +#define CHECK_DEFER(var) do { if( var.is_Defer() ) { m_rv = ::HIR::Literal::make_Defer({}); return ; } } while(0) + namespace { - struct NewvalState { + struct NewvalState + : public HIR::Evaluator::Newval + { const ::HIR::Module& mod; const ::HIR::ItemPath& mod_path; ::std::string name_prefix; @@ -31,9 +38,9 @@ namespace { { } - ::HIR::SimplePath new_static(::HIR::TypeRef type, ::HIR::Literal value) + virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override { - auto name = FMT(name_prefix << next_item_idx); + auto name = RcString::new_interned(FMT(name_prefix << next_item_idx)); next_item_idx ++; DEBUG("mod_path = " << mod_path); auto rv = mod_path.get_simple_path() + name.c_str(); @@ -47,23 +54,6 @@ 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_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args); - }; ::HIR::Literal clone_literal(const ::HIR::Literal& v) { @@ -71,6 +61,9 @@ namespace { (Invalid, return ::HIR::Literal(); ), + (Defer, + return ::HIR::Literal::make_Defer({}); + ), (List, ::std::vector< ::HIR::Literal> vals; for(const auto& val : e) { @@ -162,6 +155,8 @@ namespace { ), (Enum, ), + (ExternType, + ), (TypeAlias, ) ) @@ -267,13 +262,16 @@ namespace { TODO(sp, "Could not find function for " << path << " - " << rv.tag_str()); } } +} // namespace <anon> + +namespace HIR { - ::HIR::Literal Evaluator::evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) + ::HIR::Literal Evaluator::evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) { // TODO: Full-blown miri TRACE_FUNCTION_F("exp=" << exp << ", args=" << args); - ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(,), exp, {}, fcn }; + ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(ss, ss<<ip), exp, {}, fcn }; ::HIR::Literal retval; ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); @@ -295,61 +293,66 @@ namespace { ::HIR::Literal& get_lval(const ::MIR::LValue& lv) { - TU_MATCHA( (lv), (e), + ::HIR::Literal* lit_ptr; + TRACE_FUNCTION_FR(lv, *lit_ptr); + TU_MATCHA( (lv.m_root), (e), (Return, - return retval; + lit_ptr = &retval; ), (Local, - if( e >= locals.size() ) - MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size()); - return locals[e]; + MIR_ASSERT(state, e < locals.size(), "Local index out of range - " << e << " >= " << locals.size()); + lit_ptr = &locals[e]; ), (Argument, - if( e.idx >= args.size() ) - MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size()); - return args[e.idx]; + MIR_ASSERT(state, e < args.size(), "Argument index out of range - " << e << " >= " << args.size()); + lit_ptr = &args[e]; ), (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 << " }"); - ), - (BorrowData, - return *ve; - ), - (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 ""; + + for(const auto& w : lv.m_wrappers) + { + auto& val = *lit_ptr; + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, e) { + 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 < vals.size(), "LValue::Field index out of range"); + lit_ptr = &vals[ e ]; + } + TU_ARMA(Deref, e) { + TU_MATCH_DEF( ::HIR::Literal, (val), (ve), + ( + MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }"); + ), + (BorrowData, + lit_ptr = &*ve; + ), + (String, + // Just clone the string (hack) + // - TODO: Create a list? + lit_ptr = &val; + ) + ) + } + TU_ARMA(Index, e) { + MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv); + MIR_ASSERT(state, e < locals.size(), "LValue::Index index local out of range"); + auto& idx = locals[e]; + 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"); + lit_ptr = &vals[ idx_v ]; + } + TU_ARMA(Downcast, e) { + MIR_TODO(state, "LValue::Downcast - " << lv); + } + } + } + return *lit_ptr; } ::HIR::Literal read_lval(const ::MIR::LValue& lv) { @@ -377,27 +380,28 @@ namespace { LocalState local_state( state, retval, args, locals ); auto const_to_lit = [&](const ::MIR::Constant& c)->::HIR::Literal { - TU_MATCH(::MIR::Constant, (c), (e2), - (Int, + TU_MATCH_HDR( (c), {) + TU_ARM(c, Int, e2) { return ::HIR::Literal(static_cast<uint64_t>(e2.v)); - ), - (Uint, + } + TU_ARM(c, Uint, e2) return ::HIR::Literal(e2.v); - ), - (Float, + TU_ARM(c, Float, e2) return ::HIR::Literal(e2.v); - ), - (Bool, + TU_ARM(c, Bool, e2) return ::HIR::Literal(static_cast<uint64_t>(e2.v)); - ), - (Bytes, + TU_ARM(c, Bytes, e2) return ::HIR::Literal::make_String({e2.begin(), e2.end()}); - ), - (StaticString, + TU_ARM(c, StaticString, e2) return ::HIR::Literal(e2); - ), - (Const, - auto p = ms.monomorph(state.sp, e2.p); + TU_ARM(c, Const, e2) { + auto p = ms.monomorph(state.sp, *e2.p); + // If there's any mention of generics in this path, then return Literal::Defer + if( visit_path_tys_with(p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) ) + { + DEBUG("Return Literal::Defer for constant " << *e2.p << " which references a generic parameter"); + return ::HIR::Literal::make_Defer({}); + } 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()); @@ -407,19 +411,25 @@ namespace { 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 << "$") } }; + auto nvs = NewvalState { item.m_value.m_state->m_module, mod_ip, FMT("const" << &c << "#") }; + auto eval = ::HIR::Evaluator { item.m_value.span(), resolve.m_crate, nvs }; 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); } + auto it = c.m_monomorph_cache.find(*e2.p); + if( it != c.m_monomorph_cache.end() ) + { + MIR_ASSERT(state, !it->second.is_Defer(), "Cached literal for " << *e2.p << " is Defer"); + return clone_literal( it->second ); + } return clone_literal( c.m_value_res ); - ), - (ItemAddr, - return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, e2) ); - ) - ) + } + TU_ARM(c, ItemAddr, e2) + return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, *e2) ); + } throw ""; }; auto read_param = [&](const ::MIR::Param& p) -> ::HIR::Literal @@ -476,17 +486,14 @@ namespace { MIR_BUG(state, "Only shared borrows are allowed in constants"); } - if( e.type != ::HIR::BorrowType::Shared ) { - MIR_BUG(state, "Only shared borrows are allowed in constants"); + if( !e.val.m_wrappers.empty() && e.val.m_wrappers.back().is_Deref() ) { + //if( p->val->is_Deref() ) + // MIR_TODO(state, "Undo nested deref coercion - " << *p->val); + val = local_state.read_lval(e.val.clone_unwrapped()); } - 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() ) { + else if( e.val.m_wrappers.empty() && e.val.m_root.is_Static() ){ // Borrow of a static, emit BorrowPath with the same path - val = ::HIR::Literal::make_BorrowPath( p->clone() ); + val = ::HIR::Literal::make_BorrowPath( e.val.m_root.as_Static().clone() ); } else { auto inner_val = local_state.read_lval(e.val); @@ -504,6 +511,10 @@ namespace { ), (Cast, auto inval = local_state.read_lval(e.val); + if( inval.is_Defer() ) { + val = ::HIR::Literal::make_Defer({}); + } + else TU_MATCH_DEF(::HIR::TypeRef::Data, (e.type.m_data), (te), ( // NOTE: Can be an unsizing! @@ -585,6 +596,8 @@ namespace { (BinOp, auto inval_l = read_param(e.val_l); auto inval_r = read_param(e.val_r); + if( inval_l.is_Defer() || inval_r.is_Defer() ) + return ::HIR::Literal::make_Defer({}); 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), ( @@ -651,6 +664,8 @@ namespace { ), (UniOp, auto inval = local_state.read_lval(e.val); + if( inval.is_Defer() ) + return ::HIR::Literal::make_Defer({}); TU_IFLET( ::HIR::Literal, inval, Integer, i, switch( e.op ) { @@ -685,7 +700,9 @@ namespace { ), (MakeDst, auto ptr = read_param(e.ptr_val); + if(ptr.is_Defer()) return ::HIR::Literal::make_Defer({}); auto meta = read_param(e.meta_val); + if(meta.is_Defer()) return ::HIR::Literal::make_Defer({}); if( ! meta.is_Integer() ) { MIR_TODO(state, "RValue::MakeDst - (non-integral meta) " << ptr << " , " << meta); } @@ -696,26 +713,39 @@ namespace { (Tuple, ::std::vector< ::HIR::Literal> vals; vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) + for(const auto& v : e.vals) { vals.push_back( read_param(v) ); + if( vals.back().is_Defer() ) { + return ::HIR::Literal::make_Defer({}); + } + } val = ::HIR::Literal::make_List( mv$(vals) ); ), (Array, ::std::vector< ::HIR::Literal> vals; vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) + for(const auto& v : e.vals) { vals.push_back( read_param(v) ); + if( vals.back().is_Defer() ) { + return ::HIR::Literal::make_Defer({}); + } + } val = ::HIR::Literal::make_List( mv$(vals) ); ), (Variant, auto ival = read_param(e.val); + if(ival.is_Defer()) return ::HIR::Literal::make_Defer({}); 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) + for(const auto& v : e.vals) { vals.push_back( read_param(v) ); + if( vals.back().is_Defer() ) { + return ::HIR::Literal::make_Defer({}); + } + } val = ::HIR::Literal::make_List( mv$(vals) ); ) ) @@ -724,15 +754,18 @@ namespace { dst = mv$(val); } state.set_cur_stmt_term(cur_block); - TU_MATCH_DEF( ::MIR::Terminator, (block.terminator), (e), - ( + TU_MATCH_HDRA( (block.terminator), {) + default: MIR_BUG(state, "Unexpected terminator - " << block.terminator); - ), - (Goto, + TU_ARMA(Goto, e) { cur_block = e; - ), - (Return, - if( exp.m_data.is_Primitive() ) + } + TU_ARMA(Return, e) { + if( retval.is_Defer() ) + { + // + } + else if( exp.m_data.is_Primitive() ) { switch( exp.m_data.as_Primitive() ) { @@ -773,52 +806,81 @@ namespace { } } return retval; - ), - (Call, - if( !e.fcn.is_Path() ) - MIR_BUG(state, "Unexpected terminator - " << block.terminator); - const auto& fcnp_raw = e.fcn.as_Path(); - auto fcnp = ms.monomorph(state.sp, fcnp_raw); - + } + TU_ARMA(Call, e) { 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); + if( const auto* te = e.fcn.opt_Intrinsic() ) + { + if( te->name == "size_of" ) { + auto ty = ms.monomorph(state.sp, te->params.m_types.at(0)); + size_t size_val; + Target_GetSizeOf(state.sp, this->resolve, ty, size_val); + dst = ::HIR::Literal::make_Integer( size_val ); + } + else { + MIR_TODO(state, "Call intrinsic \"" << te->name << "\" - " << block.terminator); + } + } + else if( const auto* te = e.fcn.opt_Path() ) + { + const auto& fcnp_raw = *te; + auto fcnp = ms.monomorph(state.sp, fcnp_raw); - ::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 + MonomorphState fcn_ms; + auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms); - // Call by invoking evaluate_constant on the function + ::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 << " }"); + auto fcn_ip = ::HIR::ItemPath(fcnp); + const auto* mir = this->resolve.m_crate.get_or_gen_mir( fcn_ip, fcn ); + MIR_ASSERT(state, mir, "No MIR for function " << fcnp); + dst = evaluate_constant_mir(fcn_ip, *mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args)); + } + } + else { - TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << 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)); + MIR_BUG(state, "Unexpected terminator - " << block.terminator); } - cur_block = e.ret_block; - ) - ) + } + } } } - ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp) + ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms/*={}*/) { 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), {}); + ::HIR::TypeRef ty_self { "Self", GENERIC_Self }; + // Might want to have a fully-populated MonomorphState for expanding inside impl blocks + // HACK: Generate a roughly-correct one + const auto& top_ip = ip.get_top_ip(); + if( top_ip.trait && !top_ip.ty ) { + ms.self_ty = &ty_self; + } + return evaluate_constant_mir(ip, *mir, mv$(ms), mv$(exp), {}); } else { BUG(this->root_span, "Attempting to evaluate constant expression with no associated code"); } } +} // namespace HIR + +namespace { void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit) { + if( lit.is_Defer() ) + return ; // TODO: Mask down limited size integers TU_MATCHA( (type.m_data), (te), (Infer, @@ -898,12 +960,15 @@ namespace { const ::HIR::Crate& m_crate; const ::HIR::Module* m_mod; const ::HIR::ItemPath* m_mod_path; + MonomorphState m_monomorph_state; + bool m_recurse_types; public: Expander(const ::HIR::Crate& crate): m_crate(crate), m_mod(nullptr), m_mod_path(nullptr) + ,m_recurse_types(false) {} void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override @@ -918,20 +983,123 @@ namespace { m_mod = saved_m; m_mod_path = saved_mp; } + void visit_function(::HIR::ItemPath p, ::HIR::Function& f) override + { + TRACE_FUNCTION_F(p); + ::HIR::Visitor::visit_function(p, f); + } + + void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override + { + static Span sp; + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type); + const auto& trait = m_crate.get_trait_by_path(sp, trait_path); + + StaticTraitResolve resolve( m_crate ); + // - TODO: Defer this call until first missing item? + resolve.set_impl_generics(impl.m_params); + + auto mp = ::HIR::ItemPath(impl.m_src_module); + m_mod_path = ∓ + m_mod = &m_crate.get_mod_by_path(sp, impl.m_src_module); + + for(const auto& vi : trait.m_values) + { + // Search for any constants that are in the trait itself, but NOT in this impl + // - For each of these, find the lowest parent specialisation with the constant set + // - Ensure that the MIR has been generated for the constant (TODO: This only needs to be done for + // specialisations, not trait-provided) + // - Monomorphise the MIR for this impl, and let expansion happen as usual + if( vi.second.is_Constant() ) + { + if( impl.m_constants.count(vi.first) > 0 ) + continue; + DEBUG("- Constant " << vi.first << " missing, looking for a source"); + // This trait impl doesn't have this constant, need to find the provided version that applies + + MonomorphState ms; + ms.self_ty = &impl.m_type; + ms.pp_impl = &impl.m_trait_args; + + resolve.find_impl(sp, trait_path, impl.m_trait_args, impl.m_type, [&](ImplRef found_impl, bool is_fuzzed)->bool { + ASSERT_BUG(sp, found_impl.m_data.is_TraitImpl(), ""); + // If this found impl is the current one, keep searching + if( found_impl.m_data.as_TraitImpl().impl == &impl ) + return false; + TODO(sp, "Found a possible parent specialisation of " << trait_path << impl.m_trait_args << " for " << impl.m_type << " - " << found_impl); + return false; + }); + const auto& template_const = vi.second.as_Constant(); + if( template_const.m_value_res.is_Defer() ) { + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT("impl" << &impl << "_" << vi.first << "#") }; + auto eval = ::HIR::Evaluator { sp, m_crate, nvs }; + ::HIR::ExprPtr ep; + Trans_Params tp(sp); + tp.self_type = ms.self_ty->clone(); + tp.pp_impl = ms.pp_impl->clone(); + ep.m_mir = Trans_Monomorphise(resolve, mv$(tp), template_const.m_value.m_mir); + ep.m_state = ::HIR::ExprStatePtr( ::HIR::ExprState(*m_mod, m_mod_path->get_simple_path()) ); + DEBUG("TMP TMP " << trait_path << " - " << ep.m_state->m_mod_path); + ep.m_state->stage = ::HIR::ExprState::Stage::Mir; + impl.m_constants.insert(::std::make_pair( + vi.first, + ::HIR::TraitImpl::ImplEnt<::HIR::Constant> { + /*is_specialisable=*/false, + ::HIR::Constant { + template_const.m_params.clone(), + /*m_type=*/ms.monomorph(sp, template_const.m_type), + /*m_value=*/mv$(ep), + ::HIR::Literal() + } + } + )); + } + else { + //TODO(sp, "Assign associated type " << vi.first << " in impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type); + impl.m_constants.insert(::std::make_pair( + vi.first, + ::HIR::TraitImpl::ImplEnt<::HIR::Constant> { + /*is_specialisable=*/false, + ::HIR::Constant { + template_const.m_params.clone(), + /*m_type=*/ms.monomorph(sp, template_const.m_type), + /*m_value=*/::HIR::ExprPtr(), + clone_literal(template_const.m_value_res) + } + } + )); + } + } + } + + ::HIR::PathParams pp_impl; + for(const auto& tp : impl.m_params.m_types) + pp_impl.m_types.push_back( ::HIR::TypeRef(tp.m_name, pp_impl.m_types.size() | 256) ); + m_monomorph_state.pp_impl = &pp_impl; + + ::HIR::Visitor::visit_trait_impl(trait_path, impl); + + m_monomorph_state.pp_impl = nullptr; + + m_mod = nullptr; + m_mod_path = nullptr; + } void visit_type(::HIR::TypeRef& ty) override { ::HIR::Visitor::visit_type(ty); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, + TRACE_FUNCTION_FR(ty, ty); if( e.size_val == ~0u ) { assert(e.size); assert(*e.size); const auto& expr_ptr = *e.size; - auto ty_name = FMT("ty_" << &ty << "$"); + auto ty_name = FMT("ty_" << &ty << "#"); - auto eval = Evaluator { expr_ptr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, ty_name } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, ty_name }; + auto eval = ::HIR::Evaluator { expr_ptr->span(), m_crate, nvs }; 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"); @@ -939,29 +1107,60 @@ namespace { } DEBUG("Array " << ty << " - size = " << e.size_val); ) + + if( m_recurse_types ) + { + m_recurse_types = false; + if( const auto* te = ty.m_data.opt_Path() ) + { + TU_MATCH_HDRA( (te->binding), {) + TU_ARMA(Unbound, _) { + } + TU_ARMA(Opaque, _) { + } + TU_ARMA(Struct, pbe) { + // If this struct hasn't been visited already, visit it + this->visit_struct(te->path.m_data.as_Generic().m_path, const_cast<::HIR::Struct&>(*pbe)); + } + TU_ARMA(Union, pbe) { + } + TU_ARMA(Enum, pbe) { + } + TU_ARMA(ExternType, pbe) { + } + } + } + m_recurse_types = true; + } } void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override { + m_recurse_types = true; ::HIR::Visitor::visit_constant(p, item); + m_recurse_types = false; // NOTE: Consteval needed here for MIR match generation to work - if( item.m_value ) + if( item.m_value || item.m_value.m_mir ) { - 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()); + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "#") }; + auto eval = ::HIR::Evaluator { item.m_value.span(), m_crate, nvs }; + item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone(), m_monomorph_state.clone()); - check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); + 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 { + m_recurse_types = true; ::HIR::Visitor::visit_static(p, item); + m_recurse_types = false; if( item.m_value ) { - auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "#") }; + auto eval = ::HIR::Evaluator { item.m_value->span(), m_crate, nvs }; 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); @@ -970,6 +1169,7 @@ namespace { } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { + static Span sp; if( auto* e = item.m_data.opt_Value() ) { ::HIR::TypeRef ty = ::HIR::CoreType::Isize; @@ -978,7 +1178,8 @@ namespace { { if( var.expr ) { - auto eval = Evaluator { var.expr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "_" << var.name << "#") }; + auto eval = ::HIR::Evaluator { var.expr->span(), m_crate, nvs }; auto val = eval.evaluate_constant(p, var.expr, ty.clone()); DEBUG("enum variant: " << p << "::" << var.name << " = " << val); i = val.as_Integer(); @@ -989,6 +1190,15 @@ namespace { } ::HIR::Visitor::visit_enum(p, item); } + void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override { + if( item.const_eval_state != HIR::ConstEvalState::Complete ) + { + ASSERT_BUG(Span(), item.const_eval_state == HIR::ConstEvalState::None, "Constant evaluation loop involving " << p); + item.const_eval_state = HIR::ConstEvalState::Active; + ::HIR::Visitor::visit_struct(p, item); + item.const_eval_state = HIR::ConstEvalState::Complete; + } + } void visit_expr(::HIR::ExprPtr& expr) override { @@ -1003,6 +1213,7 @@ namespace { void visit_type(::HIR::TypeRef& ty) override { // Need to evaluate array sizes + DEBUG("expr type " << ty); m_exp.visit_type(ty); } void visit_path_params(::HIR::PathParams& pp) override { @@ -1012,8 +1223,9 @@ namespace { void visit(::HIR::ExprNode_ArraySized& node) override { assert( node.m_size ); - 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 name = FMT("array_" << &node << "#"); + auto nvs = NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name }; + auto eval = ::HIR::Evaluator { node.span(), m_exp.m_crate, nvs }; 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"); @@ -1025,7 +1237,9 @@ namespace { if( expr.get() != nullptr ) { Visitor v { *this }; + //m_recurse_types = true; (*expr).visit(v); + //m_recurse_types = false; } } }; @@ -1047,7 +1261,7 @@ namespace { { // ::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)) } ); + iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { ::HIR::Publicity::new_none(), ::HIR::ValueItem::make_Static(mv$(v.second)) } ); mod.m_value_items.insert(::std::make_pair( v.first, mv$(iv) )); } mod.m_inline_statics.clear(); @@ -1066,3 +1280,10 @@ void ConvertHIR_ConstantEvaluate(::HIR::Crate& crate) ExpanderApply().visit_crate(crate); } +void ConvertHIR_ConstantEvaluate_Expr(const ::HIR::Crate& crate, const ::HIR::ItemPath& ip, ::HIR::ExprPtr& expr_ptr) +{ + TRACE_FUNCTION_F(ip); + // Check innards but NOT the value + Expander exp { crate }; + exp.visit_expr( expr_ptr ); +} |