From a0bdedaaed4393236877c45bb56692fe05732a56 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 27 Dec 2018 18:35:54 +0800 Subject: Lower MIR - Match ergonomics (and a little bit of cleanup/fixes). - liballoc building, up to libstd --- src/mir/from_hir_match.cpp | 136 ++++++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 57 deletions(-) (limited to 'src/mir/from_hir_match.cpp') diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index b8fabdc0..8014ea8e 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -886,9 +886,10 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal ) ) } -void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) +void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& top_ty) { - TRACE_FUNCTION_F("pat="<m_data.is_Borrow() ) + BUG(sp, "Deref step " << i << "/" << pat.m_implicit_deref_count << " hit a non-borrow " << *ty_p << " from " << top_ty); + ty_p = &*ty_p->m_data.as_Borrow().inner; + m_field_path.push_back( FIELD_DEREF ); + } + const auto& ty = *ty_p; + // TODO: Outer handling for Value::Named patterns // - Convert them into either a pattern, or just a variant of this function that operates on ::HIR::Literal // > It does need a way of handling unknown-value constants (e.g. ::CONST) @@ -931,6 +942,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa if( pve.binding ) { this->append_from_lit(sp, pve.binding->m_value_res, ty); + for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) + { + m_field_path.pop_back(); + } return ; } else @@ -940,20 +955,23 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) - TU_MATCHA( (ty.m_data), (e), - (Infer, BUG(sp, "Ivar for in match type"); ), - (Diverge, + TU_MATCH_HDR( (ty.m_data), {) + TU_ARM(ty.m_data, Infer, e) { + BUG(sp, "Ivar for in match type"); + } + TU_ARM(ty.m_data, Diverge, e) { // Since ! can never exist, mark this arm as impossible. // TODO: Marking as impossible (and not emitting) leads to exhuaustiveness failure. //this->m_is_impossible = true; - ), - (Primitive, - TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), - ( BUG(sp, "Matching primitive with invalid pattern - " << pat); ), - (Any, + } + TU_ARM(ty.m_data, Primitive, e) { + TU_MATCH_HDR( (pat.m_data), {) + default: + BUG(sp, "Matching primitive with invalid pattern - " << pat); + TU_ARM(pat.m_data, Any, pe) { this->push_rule( PatternRule::make_Any({}) ); - ), - (Range, + } + TU_ARM(pat.m_data, Range, pe) { switch(e) { case ::HIR::CoreType::F32: @@ -994,8 +1012,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa BUG(sp, "Hit match over `str` - must be `&str`"); break; } - ), - (Value, + } + TU_ARM(pat.m_data, Value, pe) { switch(e) { case ::HIR::CoreType::F32: @@ -1035,16 +1053,16 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa BUG(sp, "Hit match over `str` - must be `&str`"); break; } - ) - ) - ), - (Tuple, + } + } + } + TU_ARM(ty.m_data, Tuple, e) { m_field_path.push_back(0); TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching tuple with invalid pattern - " << pat); ), (Any, for(const auto& sty : e) { - this->append_from(sp, pat, sty); + this->append_from(sp, empty_pattern, sty); m_field_path.back() ++; } ), @@ -1070,8 +1088,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) m_field_path.pop_back(); - ), - (Path, + } + TU_ARM(ty.m_data, Path, e) { // This is either a struct destructure or an enum TU_MATCHA( (e.binding), (pbe), (Unbound, @@ -1132,12 +1150,12 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Match not allowed, " << ty << " with " << pat); ), (Any, - // - Recurse into type and use the same pattern again + // - Recurse into type using an empty pattern for(const auto& fld : sd) { ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld.ent) ? tmp = monomorph(fld.ent) : fld.ent); - this->append_from(sp, pat, sty_mono); + this->append_from(sp, empty_pattern, sty_mono); m_field_path.back() ++; } ), @@ -1166,7 +1184,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa { ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld.second.ent) ? tmp = monomorph(fld.second.ent) : fld.second.ent); - this->append_from(sp, pat, sty_mono); + this->append_from(sp, empty_pattern, sty_mono); m_field_path.back() ++; } m_field_path.pop_back(); @@ -1182,8 +1200,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa auto it = ::std::find_if( pe.sub_patterns.begin(), pe.sub_patterns.end(), [&](const auto& x){ return x.first == fld.first; } ); if( it == pe.sub_patterns.end() ) { - ::HIR::Pattern any_pat {}; - this->append_from(sp, any_pat, sty_mono); + this->append_from(sp, empty_pattern, sty_mono); } else { @@ -1289,8 +1306,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) ) - ), - (Generic, + } + TU_ARM(ty.m_data, Generic, e) { // Generics don't destructure, so the only valid pattern is `_` TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Match not allowed, " << ty << " with " << pat); ), @@ -1298,29 +1315,29 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa this->push_rule( PatternRule::make_Any({}) ); ) ) - ), - (TraitObject, + } + TU_ARM(ty.m_data, TraitObject, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a trait object"); } - ), - (ErasedType, + } + TU_ARM(ty.m_data, ErasedType, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over an erased type"); } - ), - (Array, + } + TU_ARM(ty.m_data, Array, e) { // Sequential match just like tuples. m_field_path.push_back(0); TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching array with invalid pattern - " << pat); ), (Any, for(unsigned int i = 0; i < e.size_val; i ++) { - this->append_from(sp, pat, *e.inner); + this->append_from(sp, empty_pattern, *e.inner); m_field_path.back() ++; } ), @@ -1336,8 +1353,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) m_field_path.pop_back(); - ), - (Slice, + } + TU_ARM(ty.m_data, Slice, e) { TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching over [T] with invalid pattern - " << pat); @@ -1393,18 +1410,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa }) ); ) ) - ), - (Borrow, + } + TU_ARM(ty.m_data, Borrow, e) { m_field_path.push_back( FIELD_DEREF ); - TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), - ( BUG(sp, "Matching borrow invalid pattern - " << pat); ), - (Any, - this->append_from( sp, pat, *e.inner ); - ), - (Ref, + TU_MATCH_HDR( (pat.m_data), {) + default: + BUG(sp, "Matching borrow invalid pattern - " << ty << " with " << pat); + TU_ARM(pat.m_data, Any, pe) { + this->append_from( sp, empty_pattern, *e.inner ); + } + TU_ARM(pat.m_data, Ref, pe) { this->append_from( sp, *pe.sub, *e.inner ); - ), - (Value, + } + TU_ARM(pat.m_data, Value, pe) { // TODO: Check type? if( pe.val.is_String() ) { const auto& s = pe.val.as_String(); @@ -1423,32 +1441,36 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa else { BUG(sp, "Matching borrow invalid pattern - " << pat); } - ) - ) + } + } m_field_path.pop_back(); - ), - (Pointer, + } + TU_ARM(ty.m_data, Pointer, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a pointer"); } - ), - (Function, + } + TU_ARM(ty.m_data, Function, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a functon pointer"); } - ), - (Closure, + } + TU_ARM(ty.m_data, Closure, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a closure"); } - ) - ) + } + } + for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) + { + m_field_path.pop_back(); + } } namespace { -- cgit v1.2.3 From 0a47863a680677817631f507ea6f6565b537487e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 11:44:53 +0800 Subject: Misc MIR generation fixes --- src/hir_typeck/expr_cs.cpp | 2 +- src/mir/from_hir.cpp | 4 ++-- src/mir/from_hir_match.cpp | 2 +- src/mir/mir_builder.cpp | 6 +++++- 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src/mir/from_hir_match.cpp') diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 3c3f6e71..e8e0f65c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3881,7 +3881,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } TU_ARM(pattern.m_data, Value, pe) { // no-op? - if( pe.val.is_String() ) { + if( pe.val.is_String() || pe.val.is_ByteString() ) { ASSERT_BUG(sp, pattern.m_implicit_deref_count >= 1, ""); pattern.m_implicit_deref_count -= 1; } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index c3281bd6..38d00a5a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1218,7 +1218,7 @@ namespace { } void visit(::HIR::ExprNode_Cast& node) override { - TRACE_FUNCTION_F("_Cast"); + TRACE_FUNCTION_F("_Cast " << node.m_res_type); this->visit_node_ptr(node.m_value); const auto& ty_out = node.m_res_type; @@ -2009,7 +2009,7 @@ namespace { } void visit(::HIR::ExprNode_Field& node) override { - TRACE_FUNCTION_F("_Field"); + TRACE_FUNCTION_F("_Field \"" << node.m_field << "\""); this->visit_node_ptr(node.m_value); auto val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 8014ea8e..264c74c5 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1119,7 +1119,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa (Any, // _ on a box, recurse into the box type. m_field_path.push_back(FIELD_DEREF); - this->append_from(sp, pat, inner_ty); + this->append_from(sp, empty_pattern, inner_ty); m_field_path.pop_back(); ), (Box, diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index a3650919..ac1b7650 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -290,7 +290,11 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal } ), (Cast, - this->moved_lvalue(sp, e.val); + // TODO: Does this actually move? + if( e.type.m_data.is_Borrow() ) + { + this->moved_lvalue(sp, e.val); + } ), (BinOp, switch(e.op) -- cgit v1.2.3 From 42b9c8704fe4aab25e8f9d0cca15a74b025eee43 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Feb 2019 17:48:32 +0800 Subject: HIR - Minimally-tested support for `extern { type }` --- src/hir/from_ast.cpp | 10 ++++++++ src/hir/hir.hpp | 8 +++++++ src/hir/serialise.cpp | 9 ++++++++ src/hir/type.cpp | 2 ++ src/hir/type.hpp | 2 ++ src/hir/visitor.cpp | 3 +++ src/hir_conv/bind.cpp | 4 ++++ src/hir_conv/constant_evaluation.cpp | 2 ++ src/hir_conv/markings.cpp | 1 + src/hir_typeck/expr_check.cpp | 9 ++++++++ src/hir_typeck/expr_cs.cpp | 18 +++++++++++++++ src/hir_typeck/helpers.cpp | 13 +++++++++++ src/hir_typeck/outer.cpp | 4 ++++ src/hir_typeck/static.cpp | 15 ++++++++++++ src/mir/from_hir.cpp | 3 +++ src/mir/from_hir_match.cpp | 15 ++++++++++++ src/resolve/absolute.cpp | 44 +++++++++++++++++------------------- src/resolve/index.cpp | 13 ++++++++++- src/resolve/use.cpp | 3 +++ src/trans/auto_impls.cpp | 6 ++--- src/trans/codegen.cpp | 3 +++ src/trans/codegen_c.cpp | 11 +++++++++ src/trans/enumerate.cpp | 16 ++++++------- 23 files changed, 178 insertions(+), 36 deletions(-) (limited to 'src/mir/from_hir_match.cpp') diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 768593c4..fb8096f7 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1187,6 +1187,7 @@ namespace { ::std::vector< ::HIR::TraitPath> trait_bounds; ::std::string lifetime_bound; auto gps = LowerHIR_GenericParams(i.params(), &is_sized); + for(auto& b : gps.m_bounds) { TU_MATCH(::HIR::GenericBound, (b), (be), @@ -1463,6 +1464,15 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) ); ), (Type, + if( e.type().m_data.is_Any() ) + { + if( !e.params().lft_params().empty() || !e.params().ty_params().empty() || !e.params().bounds().empty() ) + { + ERROR(item.data.span, E0000, "Generics on extern type"); + } + _add_mod_ns_item(mod, item.name, item.is_pub, ::HIR::ExternType {}); + break; + } _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) ); ), (Struct, diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index fc4a19e8..48787583 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -215,6 +215,13 @@ struct StructMarkings unsigned int coerce_param = ~0u; }; +class ExternType +{ +public: + // TODO: do extern types need any associated data? + TraitMarkings m_markings; +}; + class Enum { public: @@ -367,6 +374,7 @@ TAGGED_UNION(TypeItem, Import, (Import, struct { ::HIR::SimplePath path; bool is_variant; unsigned int idx; }), (Module, Module), (TypeAlias, TypeAlias), // NOTE: These don't introduce new values + (ExternType, ExternType), (Enum, Enum), (Struct, Struct), (Union, Union), diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index c91cf93f..e5fe8ed5 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -834,6 +834,10 @@ (Union, m_out.write_tag(6); serialise(e); + ), + (ExternType, + m_out.write_tag(7); + serialise(e); ) ) } @@ -1020,6 +1024,11 @@ serialise(item.m_markings); } + void serialise(const ::HIR::ExternType& item) + { + TRACE_FUNCTION_F("ExternType"); + serialise(item.m_markings); + } void serialise(const ::HIR::Trait& item) { TRACE_FUNCTION_F("_trait:"); diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 2c24e3e1..981ed0b3 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -85,6 +85,7 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be), (Unbound, os << "/*?*/";), (Opaque, os << "/*O*/";), + (ExternType, os << "/*X*/";), (Struct, os << "/*S*/";), (Union, os << "/*U*/";), (Enum, os << "/*E*/";) @@ -782,6 +783,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x TU_MATCH(::HIR::TypeRef::TypePathBinding, (*this), (e), (Unbound, return ::HIR::TypeRef::TypePathBinding::make_Unbound({}); ), (Opaque , return ::HIR::TypeRef::TypePathBinding::make_Opaque({}); ), + (ExternType, return ::HIR::TypeRef::TypePathBinding(e); ), (Struct, return ::HIR::TypeRef::TypePathBinding(e); ), (Union , return ::HIR::TypeRef::TypePathBinding(e); ), (Enum , return ::HIR::TypeRef::TypePathBinding(e); ) diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 480b32c4..0c98773f 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -19,6 +19,7 @@ namespace HIR { +class ExternType; class Struct; class Union; class Enum; @@ -152,6 +153,7 @@ public: TAGGED_UNION_EX(TypePathBinding, (), Unbound, ( (Unbound, struct {}), // Not yet bound, either during lowering OR during resolution (when associated and still being resolved) (Opaque, struct {}), // Opaque, i.e. An associated type of a generic (or Self in a trait) + (ExternType, const ::HIR::ExternType*), (Struct, const ::HIR::Struct*), (Union, const ::HIR::Union*), (Enum, const ::HIR::Enum*) diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 5c9c0dfa..f23bae88 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -47,6 +47,9 @@ void ::HIR::Visitor::visit_module(::HIR::ItemPath p, ::HIR::Module& mod) DEBUG("type " << name); this->visit_type_alias(p + name, e); ), + (ExternType, + DEBUG("extern type " << name); + ), (Enum, DEBUG("enum " << name); this->visit_enum(p + name, e); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 9b5043f4..b616a64f 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -456,6 +456,10 @@ namespace { (TypeAlias, BUG(sp, "TypeAlias encountered after `Resolve Type Aliases` - " << ty); ), + (ExternType, + e.binding = ::HIR::TypeRef::TypePathBinding::make_ExternType(&e3); + DEBUG("- " << ty); + ), (Struct, fix_param_count(sp, pe, e3.m_params, pe.m_params); e.binding = ::HIR::TypeRef::TypePathBinding::make_Struct(&e3); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 43a64bbb..3d1bf4a5 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -169,6 +169,8 @@ namespace { ), (Enum, ), + (ExternType, + ), (TypeAlias, ) ) diff --git a/src/hir_conv/markings.cpp b/src/hir_conv/markings.cpp index df7fbd36..d43db2b5 100644 --- a/src/hir_conv/markings.cpp +++ b/src/hir_conv/markings.cpp @@ -333,6 +333,7 @@ public: TU_MATCHA( (te.binding), (tpb), (Unbound, ), (Opaque, ), + (ExternType, markings_ptr = &tpb->m_markings; ), (Struct, markings_ptr = &tpb->m_markings; ), (Union , markings_ptr = &tpb->m_markings; ), (Enum , markings_ptr = &tpb->m_markings; ) diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index adb3c426..7d5a9c6f 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -462,6 +462,9 @@ namespace { (Union, BUG(sp, "Union in TupleVariant"); ), + (ExternType, + BUG(sp, "ExternType in TupleVariant"); + ), (Struct, ASSERT_BUG(sp, e->m_data.is_Tuple(), "Pointed struct in TupleVariant (" << node.m_path << ") isn't a Tuple"); fields_ptr = &e->m_data.as_Tuple(); @@ -522,6 +525,9 @@ namespace { (Union, TODO(sp, "Union in StructLiteral"); ), + (ExternType, + BUG(sp, "ExternType in StructLiteral"); + ), (Struct, if( e->m_data.is_Unit() ) { @@ -611,6 +617,9 @@ namespace { (Union, BUG(sp, "Union with _UnitVariant"); ), + (ExternType, + BUG(sp, "ExternType with _UnitVariant"); + ), (Struct, assert( e->m_data.is_Unit() ); ) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 4a53bd4d..291dcd84 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1144,6 +1144,9 @@ namespace { ), (Union, BUG(sp, "TupleVariant pointing to a union"); + ), + (ExternType, + BUG(sp, "TupleVariant pointing to a extern type"); ) ) assert(fields_ptr); @@ -1216,6 +1219,7 @@ namespace { TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e), (Unbound, ), (Opaque, ), + (ExternType, ), // Error? (Enum, const auto& var_name = ty_path.m_path.m_components.back(); const auto& enm = *e; @@ -4900,6 +4904,10 @@ void Context::require_sized(const Span& sp, const ::HIR::TypeRef& ty_) // Already checked by type_is_sized params_def = nullptr; ), + (ExternType, + static ::HIR::GenericParams empty_params; + params_def = &empty_params; + ), (Enum, params_def = &pb->m_params; ), @@ -5551,6 +5559,13 @@ namespace { (Opaque, // Handled above in bounded ), + (ExternType, + // Must be equal + if( sbe == dbe ) + { + return CoerceResult::Equality; + } + ), (Enum, // Must be equal if( sbe == dbe ) @@ -6474,6 +6489,9 @@ namespace { // TODO: Check bounds? return false; ), + (ExternType, + return false; + ), (Struct, if(pbe_a != pbe_b) return false; if( !pbe_a->m_struct_markings.can_unsize ) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 1af269ad..5c0696e3 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2477,6 +2477,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ), (Opaque, ), + (ExternType, + markings = &tpb->m_markings; + ), (Struct, markings = &tpb->m_markings; ), @@ -2710,6 +2713,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ), (Union, TODO(sp, "Check auto trait destructure on union " << type); + ), + (ExternType, + TODO(sp, "Check auto trait destructure on extern type " << type); ) ) DEBUG("- Nothing failed, calling callback"); @@ -3141,6 +3147,10 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa (Opaque, // TODO: Check bounds ), + (ExternType, + // Is it sized? No. + return ::HIR::Compare::Unequal; + ), (Enum, // HAS to be Sized ), @@ -4323,6 +4333,9 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const (Enum, // No fields on enums either ), + (ExternType, + // No fields on extern types + ), (Union, const auto& unm = *be; const auto& params = e.path.m_data.as_Generic().m_params; diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index 63e92d8b..6a8e8b35 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -52,6 +52,10 @@ namespace { (TypeAlias, BUG(sp, "Type path pointed to type alias - " << path); ), + (ExternType, + static ::HIR::GenericParams empty_params; + return empty_params; + ), (Module, BUG(sp, "Type path pointed to module - " << path); ), diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 457bd44e..ce7faf6c 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -851,6 +851,9 @@ bool StaticTraitResolve::find_impl__check_crate( ), (Union, TODO(sp, "Check auto trait destructure on union " << type); + ), + (ExternType, + TODO(sp, "Check auto trait destructure on extern type " << type); ) ) DEBUG("- Nothing failed, calling callback"); @@ -1629,6 +1632,10 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) return false; } ), + (ExternType, + // Extern types aren't Sized + return false; + ), (Enum, ), (Union, @@ -1732,6 +1739,10 @@ bool StaticTraitResolve::type_is_impossible(const Span& sp, const ::HIR::TypeRef (Union, // TODO: Check all variants? Or just one? TODO(sp, "type_is_impossible for union " << ty); + ), + (ExternType, + // Extern types are possible, just not usable + return false; ) ) return true; @@ -2032,6 +2043,10 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR (Union, // Unions don't have drop glue unless they impl Drop return false; + ), + (ExternType, + // Extern types don't have drop glue + return false; ) ) ), diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 9ce40a74..fb214dda 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2405,6 +2405,9 @@ namespace { TU_ARMA(Union, e) { BUG(node.span(), "_StructLiteral Union isn't valid?"); } + TU_ARMA(ExternType, e) { + BUG(node.span(), "_StructLiteral ExternType isn't valid?"); + } TU_ARMA(Struct, e) { if(e->m_data.is_Unit()) { m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 264c74c5..6fb77a3b 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -802,6 +802,9 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal ) ) ), + (ExternType, + TODO(sp, "Match extern type"); + ), (Union, TODO(sp, "Match union"); ), @@ -1217,6 +1220,9 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa (Union, TODO(sp, "Match over union - " << ty); ), + (ExternType, + TODO(sp, "Match over extern type - " << ty); + ), (Enum, auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty); @@ -1738,6 +1744,9 @@ namespace { (Opaque, BUG(sp, "Destructuring an opaque type - " << *cur_ty); ), + (ExternType, + BUG(sp, "Destructuring an extern type - " << *cur_ty); + ), (Struct, // TODO: Should this do a call to expand_associated_types? auto monomorph = [&](const auto& ty) { @@ -2173,6 +2182,9 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& (Union, TODO(sp, "Match over Union"); ), + (ExternType, + TODO(sp, "Match over ExternType"); + ), (Enum, auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, te.path.m_data.as_Generic().m_params, ty); @@ -2827,6 +2839,9 @@ void MatchGenGrouped::gen_dispatch(const ::std::vector& rules, s (Union, TODO(sp, "Match over Union"); ), + (ExternType, + TODO(sp, "Match over ExternType - " << ty); + ), (Enum, ) ) diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index d2609e9e..75a0857f 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -350,7 +350,7 @@ namespace auto v = mod.m_value_items.find(name); if( v != mod.m_value_items.end() ) { const auto& b = v->second.path.m_bindings.value; - if( const auto* be = b.opt_EnumVar() ) { + if( /*const auto* be =*/ b.opt_EnumVar() ) { DEBUG("- TY: Enum variant " << v->second.path); path = ::AST::Path( v->second.path ); return true; @@ -832,6 +832,9 @@ namespace { (TypeAlias, pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); ), + (ExternType, + pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); + ), (Struct, pb.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e}); ), @@ -880,8 +883,8 @@ namespace { if( it == hmod->m_mod_items.end() ) ERROR(sp, E0000, "Couldn't find path component '" << n.name() << "' of " << path); - TU_MATCH(::HIR::TypeItem, (it->second->ent), (e), - (Import, + TU_MATCH_HDRA( (it->second->ent), {) + TU_ARMA(Import, e) { // - Update path then restart auto newpath = AST::Path(e.path.m_crate_name, {}); for(const auto& n : e.path.m_components) @@ -892,11 +895,11 @@ namespace { // TODO: Recursion limit Resolve_Absolute_Path_BindAbsolute(context, sp, mode, path); return ; - ), - (Module, + } + TU_ARMA(Module, e) { hmod = &e; - ), - (Trait, + } + TU_ARMA(Trait, e) { auto trait_path = ::AST::Path( crate.m_name, {} ); for(unsigned int j = start; j <= i; j ++) trait_path.nodes().push_back( path_abs.nodes[j].name() ); @@ -940,23 +943,15 @@ namespace { path = mv$(new_path); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (TypeAlias, - path = split_into_crate(sp, mv$(path), start, crate.m_name); - path = split_into_ufcs_ty(sp, mv$(path), i-start); - return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (Struct, - path = split_into_crate(sp, mv$(path), start, crate.m_name); - path = split_into_ufcs_ty(sp, mv$(path), i-start); - return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (Union, + } + case ::HIR::TypeItem::TAG_ExternType: + case ::HIR::TypeItem::TAG_TypeAlias: + case ::HIR::TypeItem::TAG_Struct: + case ::HIR::TypeItem::TAG_Union: path = split_into_crate(sp, mv$(path), start, crate.m_name); path = split_into_ufcs_ty(sp, mv$(path), i-start); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (Enum, + TU_ARMA(Enum, e) { const auto& last_node = path_abs.nodes.back(); // If this refers to an enum variant, return the full path auto idx = e.find_variant(last_node.name()); @@ -982,8 +977,8 @@ namespace { path = split_into_crate(sp, mv$(path), start, crate.m_name); path = split_into_ufcs_ty(sp, mv$(path), i-start); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ) - ) + } + } } const auto& name = path_abs.nodes.back().name(); @@ -1007,6 +1002,9 @@ namespace { (Module, path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); ), + (ExternType, + path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); + ), (TypeAlias, path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); ), diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index ec1fcd8d..ddeffa0c 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -241,7 +241,15 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) i.is_pub, i_data.name, mv$(path), e.mac }); } - // TODO: Other imports (e.g. derives, which have different naming structures) + TU_ARMA(ProcMacro, e) { + TODO(sp, "ProcMacro import"); + } + TU_ARMA(ProcMacroAttribute, e) { + TODO(sp, "ProcMacroAttribute import"); + } + TU_ARMA(ProcMacroDerive, e) { + TODO(sp, "ProcMacroDerive import"); + } }} } else @@ -318,6 +326,9 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr}); ), (TypeAlias, + p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); + ), + (ExternType, p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); ) ) diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 8c9266a2..95e6d2c1 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -645,6 +645,9 @@ namespace { (TypeAlias, rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); ), + (ExternType, + rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); // Lazy. + ), (Enum, rv.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e}); ), diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index 418a338b..877659b2 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -74,7 +74,7 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone) for(const auto& subty : te) { - auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), values.size() }); + auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast(values.size()) }); if( state.resolve.type_is_copy(sp, subty) ) { values.push_back( ::std::move(fld_lvalue) ); @@ -94,8 +94,8 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) }) })); bb.terminator = ::MIR::Terminator::make_Call({ - mir_fcn.blocks.size() + 2, // return block (after the panic block below) - mir_fcn.blocks.size() + 1, // panic block (next block) + static_cast(mir_fcn.blocks.size() + 2), // return block (after the panic block below) + static_cast(mir_fcn.blocks.size() + 1), // panic block (next block) res_lv.clone(), ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ), ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) ) diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp index 9e93caba..b2b614a9 100644 --- a/src/trans/codegen.cpp +++ b/src/trans/codegen.cpp @@ -43,6 +43,9 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const TU_MATCHA( (te.binding), (tpb), (Unbound, throw ""; ), (Opaque, throw ""; ), + (ExternType, + //codegen->emit_extern_type(sp, te.path.m_data.as_Generic(), *tpb); + ), (Struct, codegen->emit_struct(sp, te.path.m_data.as_Generic(), *tpb); ), diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 2c40c991..979da88d 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1013,6 +1013,9 @@ namespace { (Struct, m_of << "struct s_" << Trans_Mangle(te.path) << ";\n"; ), + (ExternType, + m_of << "struct x_" << Trans_Mangle(te.path) << ";\n"; + ), (Union, m_of << "union u_" << Trans_Mangle(te.path) << ";\n"; ), @@ -1837,6 +1840,7 @@ namespace { TU_MATCHA((te.binding), (pbe), (Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ), (Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ), + (ExternType, MIR_BUG(*m_mir_res, "Extern type literal " << ty); ), (Struct, TU_MATCHA( (pbe->m_data), (se), (Unit, @@ -5351,6 +5355,9 @@ namespace { TU_MATCHA((te.binding), (pbe), (Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ), (Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ), + (ExternType, + MIR_BUG(*m_mir_res, "Extern type literal"); + ), (Struct, TU_MATCHA( (pbe->m_data), (se), (Unit, @@ -5835,6 +5842,10 @@ namespace { (Enum, m_of << "struct e_" << Trans_Mangle(te.path); ), + (ExternType, + m_of << "struct x_" << Trans_Mangle(te.path); + //return ; + ), (Unbound, MIR_BUG(*m_mir_res, "Unbound type path in trans - " << ty); ), diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 6aeb3485..c326d125 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -570,6 +570,9 @@ namespace { (Opaque, BUG(Span(), "Opaque type hit in enumeration - " << ty); ), + (ExternType, + // No innards to visit + ), (Struct, visit_struct(te.path.m_data.as_Generic(), *tpb); ), @@ -1064,15 +1067,10 @@ void Trans_Enumerate_Types(EnumState& state) TU_MATCHA( (te.binding), (tpb), (Unbound, ), (Opaque, ), - (Struct, - markings_ptr = &tpb->m_markings; - ), - (Union, - markings_ptr = &tpb->m_markings; - ), - (Enum, - markings_ptr = &tpb->m_markings; - ) + (ExternType, markings_ptr = &tpb->m_markings; ), + (Struct, markings_ptr = &tpb->m_markings; ), + (Union, markings_ptr = &tpb->m_markings; ), + (Enum, markings_ptr = &tpb->m_markings; ) ) ASSERT_BUG(Span(), markings_ptr, "Path binding not set correctly - " << ty); -- cgit v1.2.3 From e48bf928679b008cdb342420beeb245d44c56ba9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 19:31:57 +0800 Subject: MIR Gen - Handle extern types in match --- src/mir/from_hir_match.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'src/mir/from_hir_match.cpp') diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 6fb77a3b..853e646f 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1094,19 +1094,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa } TU_ARM(ty.m_data, Path, e) { // This is either a struct destructure or an enum - TU_MATCHA( (e.binding), (pbe), - (Unbound, + TU_MATCH_HDRA( (e.binding), {) + TU_ARMA(Unbound, pbe) { BUG(sp, "Encounterd unbound path - " << e.path); - ), - (Opaque, + } + TU_ARMA(Opaque, be) { TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching opaque type with invalid pattern - " << pat); ), (Any, this->push_rule( PatternRule::make_Any({}) ); ) ) - ), - (Struct, + } + TU_ARMA(Struct, pbe) { auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty); this->m_resolve.expand_associated_types(sp, rv); @@ -1216,14 +1216,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) ) - ), - (Union, + } + TU_ARMA(Union, pbe) { TODO(sp, "Match over union - " << ty); - ), - (ExternType, - TODO(sp, "Match over extern type - " << ty); - ), - (Enum, + } + TU_ARMA(ExternType, pbe) { + TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), + ( BUG(sp, "Matching extern type with invalid pattern - " << pat); ), + (Any, + this->push_rule( PatternRule::make_Any({}) ); + ) + ) + } + TU_ARMA(Enum, pbe) { auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty); this->m_resolve.expand_associated_types(sp, rv); @@ -1310,8 +1315,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa this->push_rule( PatternRule::make_Variant({ pe.binding_idx, mv$(sub_builder.m_rules) }) ); ) ) - ) - ) + } + } } TU_ARM(ty.m_data, Generic, e) { // Generics don't destructure, so the only valid pattern is `_` -- cgit v1.2.3 From 85743c7319a9a9b7b44761b77af04957d637bad9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 22 Mar 2019 08:07:32 +0800 Subject: Common - Add another `ord` overload, fix breakage from that --- src/common.hpp | 4 ++++ src/mir/from_hir_match.cpp | 2 +- src/mir/mir.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/mir/from_hir_match.cpp') diff --git a/src/common.hpp b/src/common.hpp index 7521b2de..4cea1633 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -105,6 +105,10 @@ static inline Ordering ord(signed char l, signed char r) { return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess)); } +static inline Ordering ord(int l, int r) +{ + return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess)); +} static inline Ordering ord(short l, short r) { return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess)); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 853e646f..32c97682 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1489,7 +1489,7 @@ namespace { Ordering ord_rule_compatible(const PatternRule& a, const PatternRule& b) { if(a.tag() != b.tag()) - return ::ord( (unsigned)a.tag(), b.tag() ); + return ::ord( (unsigned)a.tag(), (unsigned)b.tag() ); TU_MATCHA( (a, b), (ae, be), (Any, diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 840db1ac..ee6c1a6c 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -55,7 +55,7 @@ namespace MIR { ::Ordering Constant::ord(const Constant& b) const { if( this->tag() != b.tag() ) - return ::ord( static_cast(this->tag()), b.tag() ); + return ::ord( static_cast(this->tag()), static_cast(b.tag()) ); TU_MATCHA( (*this,b), (ae,be), (Int, if( ae.v != be.v ) -- cgit v1.2.3 From 788767f740979632cfeedeb1ac9b5d4f988ac623 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 May 2019 20:55:25 +0800 Subject: Lower MIR - (minor) Replace TU_MATCH with TU_MATCH_HDR --- src/mir/from_hir_match.cpp | 55 ++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'src/mir/from_hir_match.cpp') diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 32c97682..e3ddce30 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -2819,40 +2819,37 @@ void MatchGenGrouped::gen_dispatch(const ::std::vector& rules, s // Matching over a path can only happen with an enum. // TODO: What about `box` destructures? // - They're handled via hidden derefs - if( !te.binding.is_Enum() ) { - TU_MATCHA( (te.binding), (pbe), - (Unbound, - BUG(sp, "Encounterd unbound path - " << te.path); - ), - (Opaque, - BUG(sp, "Attempting to match over opaque type - " << ty); - ), - (Struct, - const auto& str_data = pbe->m_data; - TU_MATCHA( (str_data), (sd), - (Unit, - BUG(sp, "Attempting to match over unit type - " << ty); - ), - (Tuple, - TODO(sp, "Matching on tuple-like struct?"); - ), - (Named, - TODO(sp, "Matching on struct?"); - ) - ) - ), - (Union, - TODO(sp, "Match over Union"); + TU_MATCH_HDR( (te.binding), { ) + TU_ARM(te.binding, Unbound, pbe) { + BUG(sp, "Encounterd unbound path - " << te.path); + } + TU_ARM(te.binding, Opaque, pbe) { + BUG(sp, "Attempting to match over opaque type - " << ty); + } + TU_ARM(te.binding, Struct, pbe) { + const auto& str_data = pbe->m_data; + TU_MATCHA( (str_data), (sd), + (Unit, + BUG(sp, "Attempting to match over unit type - " << ty); ), - (ExternType, - TODO(sp, "Match over ExternType - " << ty); + (Tuple, + TODO(sp, "Matching on tuple-like struct?"); ), - (Enum, + (Named, + TODO(sp, "Matching on struct? - " << ty); ) ) + } + TU_ARM(te.binding, Union, pbe) { + TODO(sp, "Match over Union"); + } + TU_ARM(te.binding, ExternType, pbe) { + TODO(sp, "Match over ExternType - " << ty); + } + TU_ARM(te.binding, Enum, pbe) { + this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk); + } } - - this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk); ), (Generic, BUG(sp, "Attempting to match a generic"); -- cgit v1.2.3 From dab72ad78160ecd2a4d1759174cee837a5bedcbc Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jun 2019 11:55:02 +0800 Subject: MIR - Refactor LValue to reduce size and linked-list-ness (seems to have had a ~10% reduction in memory usage) --- Notes/MIR-PackedLValue.txt | 65 ++++ src/hir/deserialise.cpp | 32 +- src/hir/serialise.cpp | 41 +-- src/hir_conv/bind.cpp | 27 +- src/hir_conv/constant_evaluation.cpp | 112 +++---- src/include/tagged_union.hpp | 7 +- src/mir/check.cpp | 173 +++++----- src/mir/check_full.cpp | 230 ++++++-------- src/mir/cleanup.cpp | 82 +++-- src/mir/dump.cpp | 35 +- src/mir/from_hir.cpp | 76 ++--- src/mir/from_hir.hpp | 15 +- src/mir/from_hir_match.cpp | 112 +++---- src/mir/helpers.cpp | 135 ++++---- src/mir/helpers.hpp | 11 +- src/mir/mir.cpp | 189 ++++------- src/mir/mir.hpp | 402 ++++++++++++++++++----- src/mir/mir_builder.cpp | 597 ++++++++++++++++------------------- src/mir/optimise.cpp | 587 ++++++++++++++++++---------------- src/trans/auto_impls.cpp | 20 +- src/trans/codegen_c.cpp | 287 +++++++++-------- src/trans/codegen_mmir.cpp | 103 +++--- src/trans/enumerate.cpp | 340 ++++++-------------- src/trans/monomorphise.cpp | 40 +-- 24 files changed, 1863 insertions(+), 1855 deletions(-) create mode 100644 Notes/MIR-PackedLValue.txt (limited to 'src/mir/from_hir_match.cpp') diff --git a/Notes/MIR-PackedLValue.txt b/Notes/MIR-PackedLValue.txt new file mode 100644 index 00000000..ce889aee --- /dev/null +++ b/Notes/MIR-PackedLValue.txt @@ -0,0 +1,65 @@ +Problem statement: +- MIR LValues are very common, and suffer from excessive indirection when + dereferences and field accesses are present +- Many MIR analysis passes care most about the inner values +- Pointer chasing ruins cache locality + +Solution: Replace the tagged union tree with a flatteded structure + +Quirk: Indexing takes two LValues to produce one BUT one of those is of a +lesser class, so doesn't need to be treated the same. + + + +Structure proposal: +---- +A LValue is made up of: +- A root value (referencing a local, argument, static, or the return value) +- And a list of wrappers (dereference, field, downcast, index) + +Root values are encoded as a packed pointer/value and tag, with the tag stored in the low 2 bits of the pointer +- This allows a 32-bit pointer to a word to be stored, using the alignment bits as tag +- Arguments and locals are encoded with the argument/local index in the "data" bits +- Return value is encoded as argument `-1` (all 1 bits in data) +- Statics are encoded as a pointer to a `::HIR::Path` + - This adds a new pointer access and allocation vs the existing LValue structure + - HIR::Path already has a bunch of pointers in it, may not hurt that much (and may help by keeping the normal size + of the LValue down) + +Wrappers are stored as a vector of words, packed in a similar way to root values +- Dereference is stored just as an entry (could pack multiple derefs into one, but that would make handling more + difficult) +- Field/Downcast is stored with the field/variant index in the "data" bits +- Indexing is stored as a pointer to a LValue + - ALTERNATIVE: Could require that indexing always uses a local, and just store the local index + - This would vastly reduce complexity in handling the Index wrapper, BUT would add a new statement in some cases + - A quick scan of the MMIR output of libstd crates, shows that the vast majority of indexing cases are with a local + directly. + - Doing so would simplify monomorph/clone/serialise (no need to clone the wrapper list, just copy it). + - Would also improve comparison times + + + +Usecase comparisons +------ +(Using 32-bit architecture) + +NOTES: +- Existing `LValue` structure is 3 words long (1 tag, plus 2 pointers for largest variant) + - WRONG. It's actually far larger due to the ::HIR::Path embedded in it (estimate at least 8 pointers, very likely + more). That should be fixed given the number of LValue-s that exist + - Fixed now, had a slight improvement in compile times (and memory usage?) +- New structure is 4 words long (root value, plus len/cap/ptr for vector) + +- Field access via `&self` + - Old: Field(Deref(Argument(0)), 0) + - 12 + 12 + 12 = 36 bytes w/ 2 pointers + - New: LValue( Argument(0), { Deref, Field(0) } ) + - 16 + 8 = 24 bytes w/ 1 pointer + +- Array stored in `&self` (common in librand) + - `(*arg0).2[var16].0` + - Old: Field( Index(Field(Deref(Argument(0)), 2), Local(16)), 0 ) + - 12 * 5 + 12 = 72 bytes 2/ 5 pointers + - New: LValue( Argument(0), { Deref, Field(2), Index(16), Field(0) } ) + - 16 + 16 = 32 bytes w/ 1 pointer diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 56671a04..35aeacca 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -464,32 +464,15 @@ rv = deserialise_mir_lvalue_(); return rv; } + ::MIR::LValue::Wrapper deserialise_mir_lvalue_wrapper() + { + return ::MIR::LValue::Wrapper::from_inner(m_in.read_count()); + } ::MIR::LValue deserialise_mir_lvalue_() { - switch(auto tag = m_in.read_tag()) - { - #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ ); - _(Return, {}) - _(Argument, { static_cast(m_in.read_count()) } ) - _(Local, static_cast(m_in.read_count()) ) - _(Static, box$(deserialise_path()) ) - _(Field, { - box$( deserialise_mir_lvalue() ), - static_cast(m_in.read_count()) - } ) - _(Deref, { box$( deserialise_mir_lvalue() ) }) - _(Index, { - box$( deserialise_mir_lvalue() ), - box$( deserialise_mir_lvalue() ) - } ) - _(Downcast, { - box$( deserialise_mir_lvalue() ), - static_cast(m_in.read_count()) - } ) - #undef _ - default: - BUG(Span(), "Bad tag for MIR::LValue - " << tag); - } + auto root_v = m_in.read_count(); + auto root = (root_v == 3 ? ::MIR::LValue::Storage::new_Static(deserialise_path()) : ::MIR::LValue::Storage::from_inner(root_v)); + return ::MIR::LValue( mv$(root), deserialise_vec<::MIR::LValue::Wrapper>() ); } ::MIR::RValue deserialise_mir_rvalue() { @@ -827,6 +810,7 @@ template<> DEF_D( ::HIR::TraitValueItem, return d.deserialise_traitvalueitem(); ) template<> DEF_D( ::MIR::Param, return d.deserialise_mir_param(); ) + template<> DEF_D( ::MIR::LValue::Wrapper, return d.deserialise_mir_lvalue_wrapper(); ) template<> DEF_D( ::MIR::LValue, return d.deserialise_mir_lvalue(); ) template<> DEF_D( ::MIR::Statement, return d.deserialise_mir_statement(); ) template<> DEF_D( ::MIR::BasicBlock, return d.deserialise_mir_basicblock(); ) diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index c15630d9..fc53e245 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -722,35 +722,18 @@ void serialise(const ::MIR::LValue& lv) { TRACE_FUNCTION_F("LValue = "<(lv.tag()) ); - TU_MATCHA( (lv), (e), - (Return, - ), - (Argument, - m_out.write_count(e.idx); - ), - (Local, - m_out.write_count(e); - ), - (Static, - serialise_path(*e); - ), - (Field, - serialise(e.val); - m_out.write_count(e.field_index); - ), - (Deref, - serialise(e.val); - ), - (Index, - serialise(e.val); - serialise(e.idx); - ), - (Downcast, - serialise(e.val); - m_out.write_count(e.variant_index); - ) - ) + if( lv.m_root.is_Static() ) { + m_out.write_count(3); + serialise_path(lv.m_root.as_Static()); + } + else { + m_out.write_count( lv.m_root.get_inner() ); + } + serialise_vec(lv.m_wrappers); + } + void serialise(const ::MIR::LValue::Wrapper& w) + { + m_out.write_count(w.get_inner()); } void serialise(const ::MIR::RValue& val) { diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 84854315..e3441157 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -704,30 +704,9 @@ namespace { struct H { static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv) { - TU_MATCHA( (lv), (e), - (Return, - ), - (Local, - ), - (Argument, - ), - (Static, - upper_visitor.visit_path(*e, ::HIR::Visitor::PathContext::VALUE); - ), - (Field, - H::visit_lvalue(upper_visitor, *e.val); - ), - (Deref, - H::visit_lvalue(upper_visitor, *e.val); - ), - (Index, - H::visit_lvalue(upper_visitor, *e.val); - H::visit_lvalue(upper_visitor, *e.idx); - ), - (Downcast, - H::visit_lvalue(upper_visitor, *e.val); - ) - ) + if( lv.m_root.is_Static() ) { + upper_visitor.visit_path(lv.m_root.as_Static(), ::HIR::Visitor::PathContext::VALUE); + } } static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e) { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index b97a6ae0..500ac490 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -293,61 +293,66 @@ namespace HIR { ::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( 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); + MIR_TODO(state, "LValue::Static - " << e); ) ) - 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( 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) { @@ -481,17 +486,14 @@ namespace HIR { 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( 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); + 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()); } - 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); diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index dab7f8ea..5a3359b8 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -28,7 +28,6 @@ #define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__) #define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__) - // Argument iteration #define TU_DISP0(n) #define TU_DISP1(n, _1) n _1 @@ -105,7 +104,7 @@ */ TU_MATCH_ARMS(CLASS, VAR, NAME, __VA_ARGS__)/* */ default: {TU_EXP DEF;} break;/* */} -#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ auto& NAME = (VAR).as_##TAG(); (void)&NAME; +#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)&NAME; #define TU_MATCH_BIND2_(TAG, v1,v2, n1,n2) TU_MATCH_BIND1(TAG, v1, n1) TU_MATCH_BIND1(TAG, v2, n2) #define TU_MATCH_BIND2(...) TU_EXP1( TU_MATCH_BIND2_(__VA_ARGS__) ) // << Exists to cause expansion of the vars #define TU_MATCH_ARM(CLASS, VAR, NAME, TAG, ...) case CLASS::TAG_##TAG: {/* @@ -119,12 +118,12 @@ #define TU_MATCH_HDR(VARS, brace) TU_MATCH_HDR_(::std::remove_reference::type, VARS, brace) #define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) #define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference::type, VARS, brace) #define TU_MATCH_HDRA_(CLASS, VARS, brace) auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype(tu_match_hdr2_v.as_##TAG()) NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 0b032bbc..6ed34563 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -116,6 +116,11 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn { } + explicit ValStates(const ValStates& v) = default; + ValStates(ValStates&& v) = default; + ValStates& operator=(const ValStates& v) = delete; + ValStates& operator=(ValStates&& v) = default; + void fmt(::std::ostream& os) { os << "ValStates { "; switch(ret_state) @@ -159,12 +164,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn return locals.empty() && args.empty(); } + // NOTE: Moves if this state is empty bool merge(unsigned bb_idx, ValStates& other) { DEBUG("bb" << bb_idx << " this=" << FMT_CB(ss,this->fmt(ss);) << ", other=" << FMT_CB(ss,other.fmt(ss);)); if( this->empty() ) { - *this = other; + *this = ValStates(other); return true; } else if( *this == other ) @@ -183,34 +189,38 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn void mark_validity(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv, bool is_valid) { - TU_MATCH_DEF( ::MIR::LValue, (lv), (e), - ( - ), + if( !lv.m_wrappers.empty()) + { + return ; + } + TU_MATCHA( (lv.m_root), (e), (Return, ret_state = is_valid ? State::Valid : State::Invalid; ), (Argument, - MIR_ASSERT(state, e.idx < this->args.size(), "Argument index out of range"); - DEBUG("arg$" << e.idx << " = " << (is_valid ? "Valid" : "Invalid")); - this->args[e.idx] = is_valid ? State::Valid : State::Invalid; + MIR_ASSERT(state, e < this->args.size(), "Argument index out of range " << lv); + DEBUG("arg$" << e << " = " << (is_valid ? "Valid" : "Invalid")); + this->args[e] = is_valid ? State::Valid : State::Invalid; ), (Local, - MIR_ASSERT(state, e < this->locals.size(), "Local index out of range"); + MIR_ASSERT(state, e < this->locals.size(), "Local index out of range - " << lv); DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid")); this->locals[e] = is_valid ? State::Valid : State::Invalid; + ), + (Static, ) ) } void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { - TU_MATCH( ::MIR::LValue, (lv), (e), + TU_MATCHA( (lv.m_root), (e), (Return, if( this->ret_state != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Argument, - MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range"); - if( this->args[e.idx] != State::Valid ) + MIR_ASSERT(state, e < this->args.size(), "Arg index out of range"); + if( this->args[e] != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Local, @@ -219,27 +229,22 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Static, - ), - (Field, - ensure_valid(state, *e.val); - ), - (Deref, - ensure_valid(state, *e.val); - ), - (Index, - ensure_valid(state, *e.val); - ensure_valid(state, *e.idx); - ), - (Downcast, - ensure_valid(state, *e.val); ) ) + + for(const auto& w : lv.m_wrappers) + { + if( w.is_Index() ) + { + if( this->locals[w.as_Index()] != State::Valid ) + MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index())); + } + } } void move_val(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { ensure_valid(state, lv); - ::HIR::TypeRef tmp; - if( ! state.m_resolve.type_is_copy( state.sp, state.get_lvalue_type(tmp, lv) ) ) + if( ! state.lvalue_is_copy(lv) ) { mark_validity(state, lv, false); } @@ -284,20 +289,29 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn ::std::vector path; ValStates state; }; + // TODO: Remove this? The path is useful, but the cloned states are really expensive + // - Option: Keep the paths, but only ever use the pre-set entry state? ::std::vector to_visit_blocks; // TODO: Check that all used locals are also set (anywhere at all) - auto add_to_visit = [&](unsigned int idx, ::std::vector src_path, auto vs) { + auto add_to_visit = [&](unsigned int idx, ::std::vector src_path, ValStates& vs, bool can_move) { for(const auto& b : to_visit_blocks) if( b.bb == idx && b.state == vs) return ; if( block_start_states.at(idx) == vs ) return ; src_path.push_back(idx); - to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } ); + // TODO: Update the target block, and only visit if we've induced a change + to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), (can_move ? mv$(vs) : ValStates(vs)) } ); + }; + auto add_to_visit_move = [&](unsigned int idx, ::std::vector src_path, ValStates vs) { + add_to_visit(idx, mv$(src_path), vs, true); + }; + auto add_to_visit_copy = [&](unsigned int idx, ::std::vector src_path, ValStates& vs) { + add_to_visit(idx, mv$(src_path), vs, false); }; - add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); + add_to_visit_move( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); while( to_visit_blocks.size() > 0 ) { auto block = to_visit_blocks.back().bb; @@ -311,7 +325,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn if( ! block_start_states.at(block).merge(block, val_state) ) { continue ; } - DEBUG("BB" << block << " via [" << path << "]"); + ASSERT_BUG(Span(), val_state.locals.size() == fcn.locals.size(), ""); + DEBUG("BB" << block << " via [" << path << "] " << FMT_CB(ss,val_state.fmt(ss);)); // 2. Using the newly merged state, iterate statements checking the usage and updating state. const auto& bb = fcn.blocks[block]; @@ -411,13 +426,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // 3. Pass new state on to destination blocks state.set_cur_stmt_term(block); DEBUG(state << bb.terminator); - TU_MATCH(::MIR::Terminator, (bb.terminator), (e), - (Incomplete, + TU_MATCH_HDRA( (bb.terminator), { ) + TU_ARMA(Incomplete, e) { // Should be impossible here. - ), - (Return, + } + TU_ARMA(Return, e) { // Check if the return value has been set - val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) ); + val_state.ensure_valid( state, ::MIR::LValue::new_Return() ); // Ensure that no other non-Copy values are valid for(unsigned int i = 0; i < val_state.locals.size(); i ++) { @@ -432,51 +447,51 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // TODO: Error, becuase this has just been leaked } } - ), - (Diverge, + } + TU_ARMA(Diverge, e) { // TODO: Ensure that cleanup has been performed. - ), - (Goto, + } + TU_ARMA(Goto, e) { // Push block with the new state - add_to_visit( e, mv$(path), mv$(val_state) ); - ), - (Panic, + add_to_visit_move( e, mv$(path), mv$(val_state) ); + } + TU_ARMA(Panic, e) { // What should be done here? - ), - (If, + } + TU_ARMA(If, e) { // Push blocks val_state.ensure_valid( state, e.cond ); - add_to_visit( e.bb0, path, val_state ); - add_to_visit( e.bb1, mv$(path), mv$(val_state) ); - ), - (Switch, + add_to_visit_copy( e.bb0, path, val_state ); + add_to_visit_move( e.bb1, mv$(path), mv$(val_state) ); + } + TU_ARMA(Switch, e) { val_state.ensure_valid( state, e.val ); for(const auto& tgt : e.targets) { - add_to_visit( tgt, path, val_state ); + add_to_visit( tgt, path, val_state, (&tgt == &e.targets.back()) ); } - ), - (SwitchValue, + } + TU_ARMA(SwitchValue, e) { val_state.ensure_valid( state, e.val ); for(const auto& tgt : e.targets) { - add_to_visit( tgt, path, val_state ); + add_to_visit_copy( tgt, path, val_state ); + } + add_to_visit_move( e.def_target, path, mv$(val_state) ); } - add_to_visit( e.def_target, path, val_state ); - ), - (Call, + TU_ARMA(Call, e) { if( e.fcn.is_Value() ) val_state.ensure_valid( state, e.fcn.as_Value() ); for(const auto& arg : e.args) val_state.move_val( state, arg ); // Push blocks (with return valid only in one) - add_to_visit(e.panic_block, path, val_state); + add_to_visit_copy(e.panic_block, path, val_state); // TODO: If the function returns !, don't follow the ret_block val_state.mark_validity( state, e.ret_val, true ); - add_to_visit(e.ret_block, mv$(path), mv$(val_state)); - ) - ) + add_to_visit_move(e.ret_block, mv$(path), mv$(val_state)); + } + } } } @@ -838,33 +853,33 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path state.set_cur_stmt_term(bb_idx); DEBUG(state << bb.terminator); - TU_MATCH(::MIR::Terminator, (bb.terminator), (e), - (Incomplete, - ), - (Return, + TU_MATCH_HDRA( (bb.terminator), {) + TU_ARMA(Incomplete, e) { + } + TU_ARMA(Return, e) { // TODO: Check if the function can return (i.e. if its return type isn't an empty type) - ), - (Diverge, - ), - (Goto, - ), - (Panic, - ), - (If, + } + TU_ARMA(Diverge, e) { + } + TU_ARMA(Goto, e) { + } + TU_ARMA(Panic, e) { + } + TU_ARMA(If, e) { // Check that condition lvalue is a bool ::HIR::TypeRef tmp; const auto& ty = state.get_lvalue_type(tmp, e.cond); if( ty != ::HIR::CoreType::Bool ) { MIR_BUG(state, "Type mismatch in `If` - expected bool, got " << ty); } - ), - (Switch, + } + TU_ARMA(Switch, e) { // Check that the condition is an enum - ), - (SwitchValue, + } + TU_ARMA(SwitchValue, e) { // Check that the condition's type matches the values - ), - (Call, + } + TU_ARMA(Call, e) { if( e.fcn.is_Value() ) { ::HIR::TypeRef tmp; @@ -875,8 +890,8 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path } } // Typecheck arguments and return value - ) - ) + } + } } } diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index 24a4930a..0cc83c6f 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -446,68 +446,54 @@ namespace } const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const { - TU_MATCHA( (lv), (e), + const State* state_p = nullptr; + TU_MATCHA( (lv.m_root), (e), (Return, - return return_value; + state_p = &return_value; ), (Argument, - return args.at(e.idx); + state_p = &args.at(e); ), (Local, - return locals.at(e); + state_p = &locals.at(e); ), (Static, static State state_of_static(true); return state_of_static; - ), - (Field, - const auto& vs = get_lvalue_state(mir_res, *e.val); - if( vs.is_composite() ) - { - const auto& states = this->get_composite(mir_res, vs); - MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range"); - return states[e.field_index]; - } - else - { - return vs; + ) + ) + + for(const auto& w : lv.m_wrappers) + { + if( state_p->is_composite() ) { + break; } - ), - (Deref, - const auto& vs = get_lvalue_state(mir_res, *e.val); - if( vs.is_composite() ) - { + const auto& vs = *state_p; + state_p = nullptr; + + TU_MATCHA( (w), (e), + (Field, + const auto& states = this->get_composite(mir_res, vs); + MIR_ASSERT(mir_res, e < states.size(), "Field index out of range"); + state_p = &states[e]; + ), + (Deref, MIR_TODO(mir_res, "Deref with composite state"); - } - else - { - return vs; - } - ), - (Index, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - const auto& vs_i = get_lvalue_state(mir_res, *e.idx); - MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); - MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); - //return State(vs_v.is_valid() && vs_i.is_valid()); - MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value"); - return vs_v; - ), - (Downcast, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - if( vs_v.is_composite() ) - { - const auto& states = this->get_composite(mir_res, vs_v); - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v)); - return states[0]; - } - else - { - return vs_v; - } + ), + (Index, + const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e)); + MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value"); + MIR_BUG(mir_res, "Indexing a composite state"); + ), + (Downcast, + const auto& states = this->get_composite(mir_res, vs); + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs)); + state_p = &states[0]; + ) ) - ) - throw ""; + assert(state_p); + } + return *state_p; } void clear_state(const ::MIR::TypeResolve& mir_res, State& s) { @@ -522,42 +508,47 @@ namespace void set_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv, State new_vs) { TRACE_FUNCTION_F(lv << " = " << StateFmt(*this, new_vs) << " (from " << StateFmt(*this, get_lvalue_state(mir_res, lv)) << ")"); - TU_MATCHA( (lv), (e), + State* state_p = nullptr; + TU_MATCHA( (lv.m_root), (e), (Return, - this->clear_state(mir_res, return_value); - return_value = mv$(new_vs); + state_p = &return_value; ), (Argument, - auto& slot = args.at(e.idx); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + state_p = &args.at(e); ), (Local, - auto& slot = locals.at(e); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + state_p = &locals.at(e); ), (Static, - // Ignore. - ), - (Field, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); + return ; + ) + ) + + for(const auto& w : lv.m_wrappers) + { + auto& cur_vs = *state_p; + + // If this is not a composite, and it matches the new state if( !cur_vs.is_composite() && cur_vs == new_vs ) { - // Not a composite, and no state change + // Early return + return; } - else - { - ::std::vector* states_p; + + state_p = nullptr; + TU_MATCHA( (w), (e), + (Field, + // Current isn't a composite, we need to change that if( !cur_vs.is_composite() ) { ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, *e.val); + const auto& ty = mir_res.get_lvalue_type(tmp, lv, /*wrapper_skip_count=*/(&lv.m_wrappers.back() - &w)); unsigned int n_fields = 0; if( const auto* e = ty.m_data.opt_Tuple() ) { n_fields = e->size(); } + // TODO: Fixed-size arrays else if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() ) { const auto& e = ty.m_data.as_Path().binding.as_Struct(); @@ -573,94 +564,59 @@ namespace ) ) } - else { + else + { MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty); } - auto new_cur_vs = this->allocate_composite(n_fields, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); - } - else - { - states_p = &this->get_composite(mir_res, cur_vs); + cur_vs = State(this->allocate_composite(n_fields, cur_vs)); } // Get composite state and assign into it - auto& states = *states_p; - MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range"); - this->clear_state(mir_res, states[e.field_index]); - states[e.field_index] = mv$(new_vs); - } - ), - (Deref, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); - if( !cur_vs.is_composite() && cur_vs == new_vs ) - { - // Not a composite, and no state change - } - else - { - ::std::vector* states_p; + auto& states = this->get_composite(mir_res, cur_vs); + MIR_ASSERT(mir_res, e< states.size(), "Field index out of range"); + state_p = &states[e]; + ), + (Deref, if( !cur_vs.is_composite() ) { + // TODO: Should this check if the type is Box? //::HIR::TypeRef tmp; //const auto& ty = mir_res.get_lvalue_type(tmp, *e.val); - // TODO: Should this check if the type is Box? - auto new_cur_vs = this->allocate_composite(2, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); - } - else - { - states_p = &this->get_composite(mir_res, cur_vs); + cur_vs = State(this->allocate_composite(2, cur_vs)); } // Get composite state and assign into it - auto& states = *states_p; + auto& states = this->get_composite(mir_res, cur_vs); MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size"); - this->clear_state(mir_res, states[1]); - states[1] = mv$(new_vs); - } - ), - (Index, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - const auto& vs_i = get_lvalue_state(mir_res, *e.idx); - MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); - MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); + state_p = &states[1]; + ), + (Index, + const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e)); + MIR_ASSERT(mir_res, !cur_vs.is_composite(), ""); + MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); - MIR_ASSERT(mir_res, vs_v.is_valid(), "Indexing an invalid value"); - MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index"); + MIR_ASSERT(mir_res, cur_vs.is_valid(), "Indexing an invalid value"); + MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index"); - // NOTE: Ignore - ), - (Downcast, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); - if( !cur_vs.is_composite() && cur_vs == new_vs ) - { - // Not a composite, and no state change - } - else - { - ::std::vector* states_p; + // NOTE: Ignore + return ; + ), + (Downcast, if( !cur_vs.is_composite() ) { - auto new_cur_vs = this->allocate_composite(1, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); + cur_vs = State(this->allocate_composite(1, cur_vs)); } - else - { - states_p = &this->get_composite(mir_res, cur_vs); - } - // Get composite state and assign into it - auto& states = *states_p; - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val)); + auto& states = this->get_composite(mir_res, cur_vs); + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << lv << " - " << StateFmt(*this, cur_vs)); this->clear_state(mir_res, states[0]); states[0] = mv$(new_vs); - } + ) ) - ) + assert(state_p); + } + this->clear_state(mir_res, *state_p); + *state_p = mv$(new_vs); } }; @@ -939,7 +895,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio (Incomplete, ), (Return, - state.ensure_lvalue_valid(mir_res, ::MIR::LValue::make_Return({})); + state.ensure_lvalue_valid(mir_res, ::MIR::LValue::new_Return()); if( ENABLE_LEAK_DETECTOR ) { auto ensure_dropped = [&](const State& s, const ::MIR::LValue& lv) { @@ -955,10 +911,10 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio } }; for(unsigned i = 0; i < state.locals.size(); i ++ ) { - ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i)); + ensure_dropped(state.locals[i], ::MIR::LValue::new_Local(i)); } for(unsigned i = 0; i < state.args.size(); i ++ ) { - ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i})); + ensure_dropped(state.args[i], ::MIR::LValue::new_Argument(i)); } } ), diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 5d32d0c8..b535c7ce 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -33,7 +33,7 @@ struct MirMutator ::MIR::LValue new_temporary(::HIR::TypeRef ty) { - auto rv = ::MIR::LValue::make_Local( static_cast(m_fcn.locals.size()) ); + auto rv = ::MIR::LValue::new_Local( static_cast(m_fcn.locals.size()) ); m_fcn.locals.push_back( mv$(ty) ); return rv; } @@ -493,12 +493,13 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con // Allocate a temporary for the vtable pointer itself auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) ); // - Load the vtable and store it - auto ptr_lv = ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) }); + auto ptr_lv = ::MIR::LValue::new_Deref( receiver_lvp.clone() ); MIR_Cleanup_LValue(state, mutator, ptr_lv); - auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(*ptr_lv.as_Deref().val) }); + ptr_lv.m_wrappers.pop_back(); + auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(ptr_lv) }); mutator.push_statement( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) ); - auto fcn_lval = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx }); + auto fcn_lval = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref( mv$(vtable_lv) ), vtable_idx ); ::HIR::TypeRef tmp; const auto& ty = state.get_lvalue_type(tmp, fcn_lval); @@ -526,23 +527,23 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con ), (Tuple, for(unsigned int i = 0; i < se.size(); i ++ ) { - auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone()); + auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i ); if( i == str.m_struct_markings.coerce_unsized_index ) { - vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), ::MIR::LValue::make_Field({ box$(val), i }) ) ); + vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), mv$(val)) ); } else { - vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) ); + vals.push_back( mv$(val) ); } } ), (Named, for(unsigned int i = 0; i < se.size(); i ++ ) { - auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone()); + auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i ); if( i == str.m_struct_markings.coerce_unsized_index ) { - vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), ::MIR::LValue::make_Field({ box$(val), i }) ) ); + vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), mv$(val) ) ); } else { - vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) ); + vals.push_back( mv$(val) ); } } ) @@ -777,7 +778,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_s, false); - auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i })); + auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i)); auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) ); ents.push_back( mv$(new_lval) ); @@ -793,7 +794,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } else { - ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) ); + ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) ); } } ), @@ -806,7 +807,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_s, false); - auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i })); + auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i)); auto new_lval = mutator.new_temporary( mv$(ty_d) ); mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) ); @@ -823,7 +824,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } else { - ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) ); + ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) ); } } ) @@ -865,7 +866,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::MIR::LValue& lval) { - TU_MATCHA( (lval), (le), + TU_MATCHA( (lval.m_root), (le), (Return, ), (Argument, @@ -873,30 +874,22 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, :: (Local, ), (Static, - ), - (Field, - MIR_Cleanup_LValue(state, mutator, *le.val); - ), - (Deref, - MIR_Cleanup_LValue(state, mutator, *le.val); - ), - (Index, - MIR_Cleanup_LValue(state, mutator, *le.val); - MIR_Cleanup_LValue(state, mutator, *le.idx); - ), - (Downcast, - MIR_Cleanup_LValue(state, mutator, *le.val); ) ) - // If this is a deref of Box, unpack and deref the inner pointer - if( lval.is_Deref() ) + for(size_t i = 0; i < lval.m_wrappers.size(); i ++) { - auto& le = lval.as_Deref(); + if( !lval.m_wrappers[i].is_Deref() ) { + continue ; + } + + // If this is a deref of Box, unpack and deref the inner pointer ::HIR::TypeRef tmp; - const auto& ty = state.get_lvalue_type(tmp, *le.val); + const auto& ty = state.get_lvalue_type(tmp, lval, lval.m_wrappers.size() - i); if( state.m_resolve.is_type_owned_box(ty) ) { + unsigned num_injected_fld_zeros = 0; + // Handle Box by extracting it to its pointer. // - Locate (or remember) which field in Box is the pointer, and replace the inner by that field // > Dumb idea, assume it's always the first field. Keep accessing until located. @@ -924,11 +917,16 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, :: tmp = monomorphise_type(state.sp, str.m_params, te.path.m_data.as_Generic().m_params, *ty_tpl); typ = &tmp; - auto new_lval = ::MIR::LValue::make_Field({ mv$(le.val), 0 }); - le.val = box$(new_lval); + num_injected_fld_zeros ++; } MIR_ASSERT(state, typ->m_data.is_Pointer(), "First non-path field in Box wasn't a pointer - " << *typ); // We have reached the pointer. Good. + + // Inject all of the field zero accesses (before the deref) + while(num_injected_fld_zeros--) + { + lval.m_wrappers.insert( lval.m_wrappers.begin() + i, ::MIR::LValue::Wrapper::new_Field(0) ); + } } } } @@ -1030,9 +1028,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ), (DstMeta, // HACK: Ensure that the box Deref conversion fires here. - auto v = ::MIR::LValue::make_Deref({ box$(re.val) }); - MIR_Cleanup_LValue(state, mutator, v); - re.val = mv$( *v.as_Deref().val ); + re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() ); + MIR_Cleanup_LValue(state, mutator, re.val); + re.val.m_wrappers.pop_back(); // If the type is an array (due to a monomorpised generic?) then replace. ::HIR::TypeRef tmp; @@ -1053,9 +1051,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ), (DstPtr, // HACK: Ensure that the box Deref conversion fires here. - auto v = ::MIR::LValue::make_Deref({ box$(re.val) }); - MIR_Cleanup_LValue(state, mutator, v); - re.val = mv$( *v.as_Deref().val ); + re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() ); + MIR_Cleanup_LValue(state, mutator, re.val); + re.val.m_wrappers.pop_back(); ), (MakeDst, MIR_Cleanup_Param(state, mutator, re.ptr_val); @@ -1218,13 +1216,13 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, e.args.reserve( fcn_ty.m_arg_types.size() ); for(unsigned int i = 0; i < fcn_ty.m_arg_types.size(); i ++) { - e.args.push_back( ::MIR::LValue::make_Field({ box$(args_lvalue.clone()), i }) ); + e.args.push_back( ::MIR::LValue::new_Field(args_lvalue.clone(), i) ); } // If the trait is Fn/FnMut, dereference the input value. if( pe.trait.m_path == resolve.m_lang_FnOnce ) e.fcn = mv$(fcn_lvalue); else - e.fcn = ::MIR::LValue::make_Deref({ box$(fcn_lvalue) }); + e.fcn = ::MIR::LValue::new_Deref( mv$(fcn_lvalue) ); } } ) diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index b02c1e5b..69ffa850 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -176,40 +176,7 @@ namespace { #undef FMT } void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) { - TU_MATCHA( (lval), (e), - (Return, - os << "RETURN"; - ), - (Argument, - os << "arg$" << e.idx; - ), - (Local, - os << "_$" << e; - ), - (Static, - os << *e; - ), - (Field, - os << "("; - fmt_val(os, *e.val); - os << ")." << e.field_index; - ), - (Deref, - os << "*"; - fmt_val(os, *e.val); - ), - (Index, - os << "("; - fmt_val(os, *e.val); - os << ")["; - fmt_val(os, *e.idx); - os << "]"; - ), - (Downcast, - fmt_val(os, *e.val); - os << " as variant" << e.variant_index; - ) - ) + os << lval; } void fmt_val(::std::ostream& os, const ::MIR::Constant& e) { TU_MATCHA( (e), (ce), diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 9e749811..d511a32a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -177,7 +177,7 @@ namespace { for(size_t i = 0; i < pat.m_binding.m_implicit_deref_count; i ++) { - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); } switch( pat.m_binding.m_type ) @@ -215,35 +215,35 @@ namespace { for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) { - lval = ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); } TU_MATCH_HDRA( (pat.m_data), {) TU_ARMA(Any, e) { } TU_ARMA(Box, e) { - destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); + destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable); } TU_ARMA(Ref, e) { - destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); + destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable); } TU_ARMA(Tuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } } TU_ARMA(SplitTuple, e) { assert(e.total_size >= e.leading.size() + e.trailing.size()); for(unsigned int i = 0; i < e.leading.size(); i ++ ) { - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } // TODO: Is there a binding in the middle? unsigned int ofs = e.total_size - e.trailing.size(); for(unsigned int i = 0; i < e.trailing.size(); i ++ ) { - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), ofs+i), allow_refutable); } } TU_ARMA(StructValue, e) { @@ -252,7 +252,7 @@ namespace { TU_ARMA(StructTuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } } TU_ARMA(Struct, e) { @@ -264,7 +264,7 @@ namespace { for(const auto& fld_pat : e.sub_patterns) { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); - destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable); + destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable); } } } @@ -302,10 +302,10 @@ namespace { ERROR(sp, E0000, "Variant " << variants[i].name << " not handled"); } } - auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); + auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx); for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval_var.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval_var.clone(), i), allow_refutable); } } TU_ARMA(EnumStruct, e) { @@ -316,11 +316,11 @@ namespace { const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path); const auto& fields = str.m_data.as_Named(); - auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); + auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx); for(const auto& fld_pat : e.sub_patterns) { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); - destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval_var.clone() ), idx}), allow_refutable); + destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval_var.clone(), idx), allow_refutable); } } TU_ARMA(Slice, e) { @@ -335,7 +335,7 @@ namespace { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++) { const auto& subpat = e.sub_patterns[i]; - destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable ); + destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable ); } } else @@ -346,7 +346,7 @@ namespace { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++) { const auto& subpat = e.sub_patterns[i]; - destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable ); + destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable ); } } } @@ -374,7 +374,7 @@ namespace { for(unsigned int i = 0; i < e.leading.size(); i ++) { unsigned int idx = 0 + i; - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } if( e.extra_bind.is_valid() ) { @@ -383,7 +383,7 @@ namespace { for(unsigned int i = 0; i < e.trailing.size(); i ++) { unsigned int idx = array_size - e.trailing.size() + i; - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } } else @@ -409,13 +409,13 @@ namespace { ::MIR::LValue len_lval; if( e.extra_bind.is_valid() || e.trailing.size() > 0 ) { - len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval).clone() })); + len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval) })); } for(unsigned int i = 0; i < e.leading.size(); i ++) { unsigned int idx = i; - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } if( e.extra_bind.is_valid() ) { @@ -427,7 +427,7 @@ namespace { ::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind); ::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow( bt, inner_type.clone() ), - ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast(e.leading.size()) }) }) + ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::new_Field( lval.clone(), static_cast(e.leading.size()) ) }) ); // TODO: Cast to raw pointer? Or keep as a borrow? @@ -442,7 +442,7 @@ namespace { auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ e.trailing.size() - i, ::HIR::CoreType::Usize })); ::MIR::LValue ofs_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ len_lval.clone(), ::MIR::eBinOp::SUB, mv$(sub_val) }) ); // Recurse with the indexed value - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Index({ box$(lval.clone()), box$(ofs_val) }), allow_refutable); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Index( lval.clone(), ofs_val.m_root.as_Local() ), allow_refutable); } } } @@ -574,7 +574,7 @@ namespace { TRACE_FUNCTION_F("_Return"); this->visit_node_ptr(node.m_value); - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Return({}), m_builder.get_result(node.span()) ); + m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Return(), m_builder.get_result(node.span()) ); m_builder.terminate_scope_early( node.span(), m_builder.fcn_scope() ); m_builder.end_block( ::MIR::Terminator::make_Return({}) ); } @@ -1474,7 +1474,7 @@ namespace { limit_val = ::MIR::Constant::make_Uint({ e.size_val, ::HIR::CoreType::Usize }); ), (Slice, - limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value).clone() }); + limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value) }); ) ) @@ -1508,7 +1508,13 @@ namespace { m_builder.set_cur_block( arm_continue ); } - m_builder.set_result( node.span(), ::MIR::LValue::make_Index({ box$(value), box$(index) }) ); + if( !index.is_Local()) + { + auto local_idx = m_builder.new_temporary(::HIR::CoreType::Usize); + m_builder.push_stmt_assign(node.span(), local_idx.clone(), mv$(index)); + index = mv$(local_idx); + } + m_builder.set_result( node.span(), ::MIR::LValue::new_Index( mv$(value), index.m_root.as_Local() ) ); } void visit(::HIR::ExprNode_Deref& node) override @@ -1591,7 +1597,7 @@ namespace { } } - m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Deref( mv$(val) ) ); } void visit(::HIR::ExprNode_Emplace& node) override @@ -1702,7 +1708,7 @@ namespace { // 3. Get the value and assign it into `place_raw` node.m_value->visit(*this); auto val = m_builder.get_result(node.span()); - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Deref({ box$(place_raw.clone()) }), mv$(val) ); + m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Deref(place_raw.clone()), mv$(val), /*drop_destination=*/false ); // 3. Return a call to `finalize` ::HIR::Path finalize_path(::HIR::GenericPath {}); @@ -1806,9 +1812,7 @@ namespace { auto place = m_builder.new_temporary( place_type ); m_builder.push_stmt_assign(node.span(), place.clone(), ::MIR::RValue::make_Cast({ mv$(place_raw), place_type.clone() })); // 3. Do a non-dropping write into the target location (i.e. just a MIR assignment) - // TODO: This should indicate that the destination shouldn't be dropped, but since drops don't happen on - // reassign currently, that's not yet an issue. - m_builder.push_stmt_assign(node.span(), ::MIR::LValue::make_Deref({box$(place.clone())}), mv$(val)); + m_builder.push_stmt_assign(node.span(), ::MIR::LValue::new_Deref(place.clone()), mv$(val), /*drop_destination=*/false); // 4. Convert the pointer into an `owned_box` auto res_type = ::HIR::TypeRef::new_path(::HIR::GenericPath(lang_owned_box, mv$(trait_params_data)), &m_builder.crate().get_struct_by_path(node.span(), lang_owned_box)); auto res = m_builder.new_temporary(res_type); @@ -2056,20 +2060,20 @@ namespace { unsigned int idx; if( ::std::isdigit(node.m_field.c_str()[0]) ) { ::std::stringstream(node.m_field.c_str()) >> idx; - m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) ); } else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) { const auto& str = **bep; const auto& fields = str.m_data.as_Named(); idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); - m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) ); } else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Union() ) { const auto& unm = **bep; const auto& fields = unm.m_variants; idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); - m_builder.set_result( node.span(), ::MIR::LValue::make_Downcast({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Downcast( mv$(val), idx ) ); } else { BUG(node.span(), "Field access on non-union/struct - " << val_ty); @@ -2202,7 +2206,7 @@ namespace { m_builder.set_result( node.span(), mv$(tmp) ); ), (Static, - m_builder.set_result( node.span(), ::MIR::LValue::make_Static(box$(node.m_path.clone())) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Static(node.m_path.clone()) ); ), (StructConstant, // TODO: Why is this still a PathValue? @@ -2321,7 +2325,7 @@ namespace { ASSERT_BUG(sp, str.m_data.is_Named(), ""); const ::HIR::t_struct_fields& fields = str.m_data.as_Named(); - ::MIR::LValue base_val; + auto base_val = ::MIR::LValue::new_Return(); if( node.m_base_value ) { DEBUG("_StructLiteral - base"); @@ -2362,7 +2366,7 @@ namespace { if( !node.m_base_value) { ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified"); } - values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i }); + values[i] = ::MIR::LValue::new_Field( base_val.clone(), i ); } else { // Partial move support will handle dropping the rest? @@ -2545,7 +2549,7 @@ namespace { else { ev.define_vars_from(ptr->span(), arg.first); - ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::new_Argument(i)); } i ++; } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 194fd0e0..a1f9a10f 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -188,13 +188,10 @@ public: // - Values ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { - // DIASBLED: State tracking doesn't support arguments in loops/splits -#if 1 auto it = m_var_arg_mappings.find(idx); if(it != m_var_arg_mappings.end()) - return ::MIR::LValue::make_Argument({ it->second }); -#endif - return ::MIR::LValue::make_Local( idx ); + return ::MIR::LValue::new_Argument(it->second); + return ::MIR::LValue::new_Local(idx); } ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty); ::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val); @@ -224,7 +221,7 @@ public: // - Statements // Push an assignment. NOTE: This also marks the rvalue as moved - void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val); + void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination=true); // Push a drop (likely only used by scope cleanup) void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u); // Push a shallow drop (for Box) @@ -296,7 +293,7 @@ private: const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const; VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type); - const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0); + VarState* get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv); VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv); void terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop); @@ -306,11 +303,11 @@ private: void complete_scope(ScopeDef& sd); public: - void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const; + void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb, const ::MIR::LValue::Wrapper* stop_wrapper=nullptr) const; bool lvalue_is_copy(const Span& sp, const ::MIR::LValue& lv) const; // Obtain the base fat poiner for a dst reference. Errors if it wasn't via a fat pointer - const ::MIR::LValue& get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const; + ::MIR::LValue get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const; }; class MirConverter: diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index e3ddce30..2bfb1a27 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1732,13 +1732,13 @@ namespace { ), (Tuple, ASSERT_BUG(sp, idx < e.size(), "Tuple index out of range"); - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); cur_ty = &e[idx]; ), (Path, if( idx == FIELD_DEREF ) { // TODO: Check that the path is Box - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref( mv$(lval) ); cur_ty = &e.path.m_data.as_Generic().m_params.m_types.at(0); break; } @@ -1773,7 +1773,7 @@ namespace { else { cur_ty = &fld.ent; } - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); ), (Named, assert( idx < fields.size() ); @@ -1785,7 +1785,7 @@ namespace { else { cur_ty = &fld.ent; } - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); ) ) ), @@ -1804,7 +1804,7 @@ namespace { else { cur_ty = &fld.second.ent; } - lval = ::MIR::LValue::make_Downcast({ box$(lval), idx }); + lval = ::MIR::LValue::new_Downcast(mv$(lval), idx); ), (Enum, auto monomorph_to_ptr = [&](const auto& ty)->const auto* { @@ -1824,7 +1824,7 @@ namespace { const auto& var = variants[idx]; cur_ty = monomorph_to_ptr(var.type); - lval = ::MIR::LValue::make_Downcast({ box$(lval), idx }); + lval = ::MIR::LValue::new_Downcast(mv$(lval), idx); ) ) ), @@ -1841,7 +1841,7 @@ namespace { assert(idx < e.size_val); cur_ty = &*e.inner; if( idx < FIELD_INDEX_MAX ) - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); else { idx -= FIELD_INDEX_MAX; idx = FIELD_INDEX_MAX - idx; @@ -1851,16 +1851,16 @@ namespace { (Slice, cur_ty = &*e.inner; if( idx < FIELD_INDEX_MAX ) - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); else { idx -= FIELD_INDEX_MAX; idx = FIELD_INDEX_MAX - idx; // 1. Create an LValue containing the size of this slice subtract `idx` - auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval).clone() })); + auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval) })); auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ idx, ::HIR::CoreType::Usize })); auto ofs_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ mv$(len_lval), ::MIR::eBinOp::SUB, mv$(sub_val) }) ); // 2. Return _Index with that value - lval = ::MIR::LValue::make_Index({ box$(lval), box$(ofs_val) }); + lval = ::MIR::LValue::new_Index(mv$(lval), ofs_val.as_Local()); } ), (Borrow, @@ -1874,7 +1874,7 @@ namespace { cur_ty = &*e.inner; } DEBUG(i << " " << *cur_ty); - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); ), (Pointer, ERROR(sp, E0000, "Attempting to match over a pointer"); @@ -1978,14 +1978,14 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& DEBUG("ty = " << ity << ", val = " << val); const auto& ty = ity; - TU_MATCHA( (ty.m_data), (te), - (Infer, + TU_MATCH_HDRA( (ty.m_data), {) + TU_ARMA(Infer, _te) { BUG(sp, "Hit _ in type - " << ty); - ), - (Diverge, + } + TU_ARMA(Diverge, _te) { BUG(sp, "Matching over !"); - ), - (Primitive, + } + TU_ARMA(Primitive, te) { switch(te) { case ::HIR::CoreType::Bool: { @@ -2152,17 +2152,20 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& case ::HIR::CoreType::Str: { ASSERT_BUG(sp, rule.is_Value() && rule.as_Value().is_StaticString(), ""); const auto& v = rule.as_Value(); + ASSERT_BUG(sp, val.is_Deref(), ""); + val.m_wrappers.pop_back(); + auto str_val = mv$(val); auto succ_bb = builder.new_bb_unlinked(); auto test_val = ::MIR::Param(::MIR::Constant( v.as_StaticString() )); - auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(*val.as_Deref().val), ::MIR::eBinOp::EQ, mv$(test_val) })); + auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(str_val), ::MIR::eBinOp::EQ, mv$(test_val) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); builder.set_cur_block(succ_bb); } break; } - ), - (Path, + } + TU_ARMA(Path, te) { TU_MATCHA( (te.binding), (pbe), (Unbound, BUG(sp, "Encounterd unbound path - " << te.path); @@ -2221,26 +2224,26 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Recurse with the new ruleset MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), - var_ty_m, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1, + var_ty_m, ::MIR::LValue::new_Downcast(val.clone(), var_idx), rule.field_path.size()+1, fail_bb ); } ) // TypePathBinding::Enum ) - ), // Type::Data::Path - (Generic, + } // Type::Data::Path + TU_ARMA(Generic, _te) { BUG(sp, "Attempting to match a generic"); - ), - (TraitObject, + } + TU_ARMA(TraitObject, te) { BUG(sp, "Attempting to match a trait object"); - ), - (ErasedType, + } + TU_ARMA(ErasedType, te) { BUG(sp, "Attempting to match an erased type"); - ), - (Array, + } + TU_ARMA(Array, te) { TODO(sp, "Match directly on array?"); - ), - (Slice, + } + TU_ARMA(Slice, te) { ASSERT_BUG(sp, rule.is_Slice() || rule.is_SplitSlice() || (rule.is_Value() && rule.as_Value().is_Bytes()), "Can only match slice with Bytes or Slice rules - " << rule); if( rule.is_Value() ) { ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]"); @@ -2249,7 +2252,8 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& auto succ_bb = builder.new_bb_unlinked(); - auto inner_val = val.as_Deref().val->clone(); + ASSERT_BUG(sp, val.is_Deref(), "Slice pattern on non-Deref - " << val); + auto inner_val = val.clone_unwrapped(); auto slice_rval = ::MIR::RValue::make_MakeDst({ mv$(cloned_val), mv$(size_val) }); auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), mv$(slice_rval)); @@ -2262,7 +2266,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Compare length auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.len, ::HIR::CoreType::Usize }) ); - auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() })); + auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_val) })); auto len_succ_bb = builder.new_bb_unlinked(); @@ -2281,7 +2285,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Compare length auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.min_len, ::HIR::CoreType::Usize}) ); - auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() })); + auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_val) })); auto len_succ_bb = builder.new_bb_unlinked(); @@ -2302,23 +2306,23 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& else { BUG(sp, "Invalid rule type for slice - " << rule); } - ), - (Tuple, + } // Type::Data::Array + TU_ARMA(Tuple, te) { TODO(sp, "Match directly on tuple?"); - ), - (Borrow, + } + TU_ARMA(Borrow, te) { TODO(sp, "Match directly on borrow?"); - ), // Type::Data::Borrow - (Pointer, + } // Type::Data::Borrow + TU_ARMA(Pointer, te) { BUG(sp, "Attempting to match a pointer - " << rule << " against " << ty); - ), - (Function, + } + TU_ARMA(Function, te) { BUG(sp, "Attempting to match a function pointer - " << rule << " against " << ty); - ), - (Closure, + } + TU_ARMA(Closure, te) { BUG(sp, "Attempting to match a closure"); - ) - ) + } + } } return 0; } @@ -3035,10 +3039,10 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v } m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) ); } break; - case ::HIR::CoreType::Str: + case ::HIR::CoreType::Str: { // Remove the deref on the &str - auto oval = mv$(val); - auto val = mv$(*oval.as_Deref().val); + ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "&str match on non-Deref lvalue - " << val); + val.m_wrappers.pop_back(); ::std::vector< ::MIR::BasicBlockId> targets; ::std::vector< ::std::string> values; @@ -3062,7 +3066,7 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v m_builder.end_block( ::MIR::Terminator::make_SwitchValue({ mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values)) }) ); - break; + } break; } } @@ -3100,7 +3104,7 @@ void MatchGenGrouped::gen_dispatch__enum(::HIR::TypeRef ty, ::MIR::LValue val, c void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, const ::std::vector& rules, size_t ofs, const ::std::vector<::MIR::BasicBlockId>& arm_targets, ::MIR::BasicBlockId def_blk) { - auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() })); + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) })); // TODO: Re-sort the rules list to interleve Constant::Bytes and Slice @@ -3162,8 +3166,8 @@ void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, m_builder.set_cur_block(succ_blk); // TODO: What if `val` isn't a Deref? - ASSERT_BUG(sp, val.is_Deref(), "TODO: Handle non-Deref matches of byte strings"); - cmp_lval_eq = this->push_compare( val.as_Deref().val->clone(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) ); + ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "TODO: Handle non-Deref matches of byte strings - " << val); + cmp_lval_eq = this->push_compare( val.clone_unwrapped(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], def_blk }) ); m_builder.set_cur_block(next_cmp_blk); @@ -3273,7 +3277,7 @@ void MatchGenGrouped::gen_dispatch_splitslice(const field_path_t& field_path, co ASSERT_BUG(sp, ty.m_data.is_Slice(), "SplitSlice pattern on non-slice - " << ty); // Obtain slice length - auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() })); + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) })); // 1. Check that length is sufficient for the pattern to be used // `IF len < min_len : def_blk, next diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 1453acb3..6f0ef891 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -12,9 +12,12 @@ #include #include // ::std::find -void ::MIR::TypeResolve::fmt_pos(::std::ostream& os) const +void ::MIR::TypeResolve::fmt_pos(::std::ostream& os, bool include_path/*=false*/) const { - os << this->m_path << " BB" << this->bb_idx << "/"; + if( include_path ) { + os << this->m_path << " "; + } + os << "BB" << this->bb_idx << "/"; if( this->stmt_idx == STMT_TERM ) { os << "TERM"; } @@ -27,7 +30,7 @@ void ::MIR::TypeResolve::print_msg(const char* tag, ::std::functionget_lvalue_type(tmp, *e.val); + rv = &get_static_type(tmp, e); + ) + ) + assert(wrapper_skip_count <= val.m_wrappers.size()); + const auto* stop_wrapper = &val.m_wrappers[ val.m_wrappers.size() - wrapper_skip_count ]; + for(const auto& w : val.m_wrappers) + { + if( &w == stop_wrapper ) + break; + rv = &this->get_unwrapped_type(tmp, w, *rv); + } + return *rv; +} +const ::HIR::TypeRef& ::MIR::TypeResolve::get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const +{ + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, field_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Field access on unexpected type - " << ty); @@ -98,14 +115,14 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ), (Tuple, - MIR_ASSERT(*this, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size()); - return te[e.field_index]; + MIR_ASSERT(*this, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size()); + return te[field_index]; ), (Path, if( const auto* tep = te.binding.opt_Struct() ) { const auto& str = **tep; - auto monomorph = [&](const auto& ty)->const auto& { + auto maybe_monomorph = [&](const auto& ty)->const auto& { if( monomorphise_type_needed(ty) ) { tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty); m_resolve.expand_associated_types(sp, tmp); @@ -120,12 +137,12 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c MIR_BUG(*this, "Field on unit-like struct - " << ty); ), (Tuple, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path); - return monomorph(se[e.field_index].ent); + MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in tuple-struct " << te.path); + return maybe_monomorph(se[field_index].ent); ), (Named, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path); - return monomorph(se[e.field_index].second.ent); + MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in struct " << te.path); + return maybe_monomorph(se[field_index].second.ent); ) ) } @@ -142,8 +159,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return t; } }; - MIR_ASSERT(*this, e.field_index < unm.m_variants.size(), "Field index out of range for union"); - return maybe_monomorph(unm.m_variants.at(e.field_index).second.ent); + MIR_ASSERT(*this, field_index < unm.m_variants.size(), "Field index out of range for union"); + return maybe_monomorph(unm.m_variants.at(field_index).second.ent); } else { @@ -151,9 +168,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c } ) ) - ), - (Deref, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Deref, _e) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Deref on unexpected type - " << ty); @@ -174,9 +190,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ) ) - ), - (Index, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Index, index_local) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Index on unexpected type - " << ty); @@ -188,9 +203,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ) ) - ), - (Downcast, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Downcast, variant_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Downcast on unexpected type - " << ty); @@ -202,8 +216,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c const auto& enm = *te.binding.as_Enum(); MIR_ASSERT(*this, enm.m_data.is_Data(), "Downcast on non-data enum - " << ty); const auto& variants = enm.m_data.as_Data(); - MIR_ASSERT(*this, e.variant_index < variants.size(), "Variant index out of range for " << ty); - const auto& variant = variants[e.variant_index]; + MIR_ASSERT(*this, variant_index < variants.size(), "Variant index out of range for " << ty); + const auto& variant = variants[variant_index]; const auto& var_ty = variant.type; if( monomorphise_type_needed(var_ty) ) { @@ -218,12 +232,13 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c else { const auto& unm = *te.binding.as_Union(); - MIR_ASSERT(*this, e.variant_index < unm.m_variants.size(), "Variant index out of range"); - const auto& variant = unm.m_variants[e.variant_index]; + MIR_ASSERT(*this, variant_index < unm.m_variants.size(), "Variant index out of range"); + const auto& variant = unm.m_variants[variant_index]; const auto& var_ty = variant.second.ent; + //return m_resolve.maybe_monomorph(sp, tmp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty); if( monomorphise_type_needed(var_ty) ) { - tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent); + tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty); m_resolve.expand_associated_types(sp, tmp); return tmp; } @@ -233,8 +248,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c } ) ) - ) - ) + } + } throw ""; } const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const @@ -383,6 +398,15 @@ namespace visit { { if( cb(lv, u) ) return true; +#if 1 + for(const auto& w : lv.m_wrappers) + { + if( w.is_Index() ) + { + cb(LValue::new_Local(w.as_Index()), ValUsage::Read); + } + } +#else TU_MATCHA( (lv), (e), (Return, ), @@ -408,6 +432,7 @@ namespace visit { return visit_mir_lvalue(*e.val, u, cb); ) ) +#endif return false; } @@ -625,32 +650,15 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c { auto assigned_lvalue = [&](size_t bb_idx, size_t stmt_idx, const ::MIR::LValue& lv) { // NOTE: Fills the first statement after running, just to ensure that any assigned value has _a_ lifetime - if( const auto* de = lv.opt_Local() ) + if( lv.m_root.is_Local() ) { - if( !mask || mask->at(*de) ) + auto de = lv.m_root.as_Local(); + if( !mask || mask->at(de) ) { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]); - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); + MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[de]); + slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); } } - else - { - // Not a direct assignment of a slot. But check if a slot is mutated as part of this. - ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) { - if( const auto* de = ilv.opt_Local() ) - { - if( vu == ValUsage::Write ) - { - if( !mask || mask->at(*de) ) - { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]); - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); - } - } - } - return false; - }); - } }; const auto& bb = fcn.blocks[bb_idx]; @@ -673,11 +681,12 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c else if( const auto* se = stmt.opt_Drop() ) { // HACK: Mark values as valid wherever there's a drop (prevents confusion by simple validator) - if( const auto* de = se->slot.opt_Local() ) + if( se->slot.m_wrappers.empty() && se->slot.m_root.is_Local() ) { - if( !mask || mask->at(*de) ) + auto de = se->slot.m_root.as_Local(); + if( !mask || mask->at(de) ) { - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); + slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); } } } diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp index 58eee9b9..0296a1c4 100644 --- a/src/mir/helpers.hpp +++ b/src/mir/helpers.hpp @@ -104,7 +104,7 @@ public: } unsigned int get_cur_stmt_ofs() const; - void fmt_pos(::std::ostream& os) const; + void fmt_pos(::std::ostream& os, bool include_path=false) const; void print_bug(::std::function cb) const { print_msg("ERROR", cb); } @@ -116,7 +116,14 @@ public: const ::MIR::BasicBlock& get_block(::MIR::BasicBlockId id) const; const ::HIR::TypeRef& get_static_type(::HIR::TypeRef& tmp, const ::HIR::Path& path) const; - const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const; + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count=0) const; + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::CRef& val) const { + return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count()); + } + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::MRef& val) const { + return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count()); + } + const ::HIR::TypeRef& get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const; const ::HIR::TypeRef& get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const; ::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const; diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 83f7e1f0..8e3045d6 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -91,119 +91,86 @@ namespace MIR { throw ""; } - ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + void LValue::RefCommon::fmt(::std::ostream& os) const { - TU_MATCHA( (x), (e), + TU_MATCHA( (m_lv->m_root), (e), (Return, os << "retval"; ), (Argument, - os << "a" << e.idx; + os << "a" << e; ), (Local, os << "_" << e; ), (Static, - os << "(" << *e << ")"; - ), - (Field, - os << *e.val << "." << e.field_index; - ), - (Deref, - os << *e.val << "*"; - ), - (Index, - os << *e.val << "[" << *e.idx << "]"; - ), - (Downcast, - os << *e.val << "#" << e.variant_index; + os << "(" << e << ")"; ) ) + for(size_t i = 0; i < m_wrapper_count; i ++) + { + const LValue::Wrapper& w = m_lv->m_wrappers.at(i); + TU_MATCHA( (w), (e), + (Field, + os << "." << e; + ), + (Deref, + os << "*"; + ), + (Index, + os << "[_" << e << "]"; + ), + (Downcast, + os << "#" << e; + ) + ) + } + } + + ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + { + LValue::CRef(x).fmt(os); return os; } - bool operator<(const LValue& a, const LValue& b) + + Ordering LValue::Storage::ord(const LValue::Storage& x) const { - if( a.tag() != b.tag() ) - return a.tag() < b.tag(); - TU_MATCHA( (a, b), (ea, eb), - (Return, - return false; - ), - (Argument, - return ea.idx < eb.idx; - ), - (Local, - return ea < eb; - ), - (Static, - return ea < eb; - ), - (Field, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - if( ea.field_index != eb.field_index ) - return ea.field_index < eb.field_index; - return true; - ), - (Deref, - return *ea.val < *eb.val; - ), - (Index, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - return *ea.idx < *eb.idx; - ), - (Downcast, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - return ea.variant_index < eb.variant_index; - ) - ) - throw ""; + if( x.is_Static() ) + { + if( this->is_Static() ) + return this->as_Static().ord( x.as_Static() ); + else + return OrdLess; + } + else + { + if( this->is_Static() ) + return OrdGreater; + } + + return ::ord(this->val, x.val); } - bool operator==(const LValue& a, const LValue& b) + Ordering LValue::ord(const LValue& x) const { - if( a.tag() != b.tag() ) - return false; - TU_MATCHA( (a, b), (ea, eb), - (Return, - return true; - ), - (Argument, - return ea.idx == eb.idx; - ), - (Local, - return ea == eb; - ), - (Static, - return ea == eb; - ), - (Field, - if( *ea.val != *eb.val ) - return false; - if( ea.field_index != eb.field_index ) - return false; - return true; - ), - (Deref, - return *ea.val == *eb.val; - ), - (Index, - if( *ea.val != *eb.val ) - return false; - if( *ea.idx != *eb.idx ) - return false; - return true; - ), - (Downcast, - if( *ea.val != *eb.val ) - return false; - if( ea.variant_index != eb.variant_index ) - return false; - return true; - ) - ) - throw ""; + auto rv = m_root.ord(x.m_root); + if( rv != OrdEqual ) + return rv; + return ::ord(m_wrappers, x.m_wrappers); + } + Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const + { + Ordering rv; + //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv); + rv = m_lv->m_root.ord(x.m_lv->m_root); + if( rv != OrdEqual ) + return rv; + for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++) + { + rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]); + if( rv != OrdEqual ) + return rv; + } + return (rv = ::ord(m_wrapper_count, x.m_wrapper_count)); } ::std::ostream& operator<<(::std::ostream& os, const Param& x) @@ -537,30 +504,14 @@ namespace MIR { } } -::MIR::LValue MIR::LValue::clone() const +::MIR::LValue::Storage MIR::LValue::Storage::clone() const { - TU_MATCHA( (*this), (e), - (Return, return LValue(e); ), - (Argument, return LValue(e); ), - (Local, return LValue(e); ), - (Static, return LValue(box$(e->clone())); ), - (Field, return LValue::make_Field({ - box$( e.val->clone() ), - e.field_index - }); ), - (Deref, return LValue::make_Deref({ - box$( e.val->clone() ) - }); ), - (Index, return LValue::make_Index({ - box$( e.val->clone() ), - box$( e.idx->clone() ) - }); ), - (Downcast, return LValue::make_Downcast({ - box$( e.val->clone() ), - e.variant_index - }); ) - ) - throw ""; + if( is_Static() ) { + return new_Static(as_Static().clone()); + } + else { + return Storage(this->val); + } } ::MIR::Constant MIR::Constant::clone() const { diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 63acf89d..f3d61dfa 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -12,21 +12,27 @@ #include // std::unique_ptr #include +class MonomorphState; + namespace MIR { typedef unsigned int RegionId; typedef unsigned int BasicBlockId; -#if 0 -// TODO: Store LValues as: +// Store LValues as: // - A packed root value (one word, using the low bits as an enum descriminator) // - A list of (inner to outer) wrappers struct LValue { class Storage { + public: + const static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits + private: + uintptr_t val; - static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits + + Storage(uintptr_t v): val(v) {} public: Storage(const Storage&) = delete; Storage& operator=(const Storage&) = delete; @@ -40,41 +46,89 @@ struct LValue this->~Storage(); this->val = x.val; x.val = 0; + return *this; } ~Storage() { if( is_Static() ) { - delete reinterpret_cast<::HIR::Path*>(val & ~3u); + delete reinterpret_cast<::HIR::Path*>(val & ~3ull); val = 0; } } - static Storage new_Return() { return Storage { MAX_ARG << 2 }; } - static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage { idx << 2 }; ) - static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage { (idx << 2) | 1 } }; + static Storage new_Return() { return Storage(0 << 2); } + static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage((idx+1) << 2); } + static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage((idx << 2) | 1); } static Storage new_Static(::HIR::Path p) { ::HIR::Path* ptr = new ::HIR::Path(::std::move(p)); - return Storage { static_cast(ptr) | 2; } + return Storage(reinterpret_cast(ptr) | 2); + } + + Storage clone() const; + + uintptr_t get_inner() const { + assert(!is_Static()); + return val; + } + static Storage from_inner(uintptr_t v) { + assert( (v & 3) < 2 ); + return Storage(v); + } + + enum Tag { + TAG_Argument, + TAG_Local, + TAG_Static, + TAG_Return, + TAGDEAD, + }; + Tag tag() const { + if(val == 0) + return TAG_Return; + return static_cast(val & 3); } - bool is_Return() const { return val == (MAX_ARG << 2) /*&& (val & 3) == 0*/; } - bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; } + bool is_Return() const { return val == 0; } + bool is_Argument() const { return val != 0 && (val & 3) == 0; } bool is_Local() const { return (val & 3) == 1; } bool is_Static() const { return (val & 3) == 2; } - // No as_Return - unsigned as_Argument() const { assert(is_Argument()); return val >> 2; } - unsigned as_Local() const { assert(is_Local()); return val >> 2; } - const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3u); } + const char as_Return () const { assert(is_Return()); return 0; } + const unsigned as_Argument() const { assert(is_Argument()); return (val >> 2) - 1; } + const unsigned as_Local () const { assert(is_Local()); return val >> 2; } + + const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3llu); } + ::HIR::Path& as_Static() { assert(is_Static()); return *reinterpret_cast< ::HIR::Path*>(val & ~3llu); } + + Ordering ord(const Storage& x) const; + bool operator==(const Storage& x) const { return this->ord(x) == OrdEqual; } + bool operator!=(const Storage& x) const { return this->ord(x) != OrdEqual; } }; class Wrapper { - uintptr_t val; + uint32_t val; + Wrapper(uint32_t v): val(v) {} public: - static Wrapper new_Deref() { return Wrapper { 0 }; } - static Wrapepr new_Field (unsigned idx) { return Wrapper { (idx << 2) | 1 }; } - static Wrapepr new_Downcast(unsigned idx) { return Wrapper { (idx << 2) | 2 }; } - static Wrapepr new_Index (unsigned idx) { return Wrapper { (idx << 2) | 3 }; } + static Wrapper new_Deref() { return Wrapper( 0 ); } + static Wrapper new_Field (unsigned idx) { return Wrapper( (idx << 2) | 1 ); } + static Wrapper new_Downcast(unsigned idx) { return Wrapper( (idx << 2) | 2 ); } + static Wrapper new_Index (unsigned idx) { if(idx == ~0u) idx = Storage::MAX_ARG; return Wrapper( (idx << 2) | 3 ); } + + uint32_t get_inner() const { return val; } + static Wrapper from_inner(uint32_t v) { + return Wrapper(v); + } + + enum Tag { + TAG_Deref, + TAG_Field, + TAG_Downcast, + TAG_Index, + TAGDEAD, + }; + Tag tag() const { + return static_cast(val & 3); + } bool is_Deref () const { return (val & 3) == 0; } // Stores the field index @@ -84,79 +138,269 @@ struct LValue // Stores a Local index bool is_Index () const { return (val & 3) == 3; } - // no as_Deref() - const unsigned as_Field() const { assert(is_Field()); return (val >> 2); } + const char as_Deref () const { assert(is_Deref()); return 0; } + const unsigned as_Field () const { assert(is_Field()); return (val >> 2); } const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); } // TODO: Should this return a LValue? - const unsigned as_Index() const { assert(is_Index()); return (val >> 2); } + const unsigned as_Index () const { assert(is_Index()); unsigned rv = (val >> 2); return rv; } + + void inc_Field () { assert(is_Field ()); *this = Wrapper::new_Field (as_Field () + 1); } + void inc_Downcast() { assert(is_Downcast()); *this = Wrapper::new_Downcast(as_Downcast() + 1); } + + Ordering ord(const Wrapper& x) const { return ::ord(val, x.val); } }; Storage m_root; ::std::vector m_wrappers; - static LValue new_Return() { return LValue { Storage::new_Return(), {} }; } - static LValue new_Argument(unsigned idx) { return LValue { Storage::new_Argument(idx), {} }; } - static LValue new_Local(unsigned idx) { return LValue { Storage::new_Local(idx), {} }; } - static LValue new_Static(::HIR::Path p) { return LValue { Storage::new_Static(::std::move(p)), {} }; } + LValue() + :m_root( Storage::new_Return() ) + { + } + LValue(Storage root, ::std::vector wrappers) + :m_root( ::std::move(root) ) + ,m_wrappers( ::std::move(wrappers) ) + { + } + + static LValue new_Return () { return LValue(Storage::new_Return(), {}); } + static LValue new_Argument(unsigned idx ) { return LValue(Storage::new_Argument(idx), {}); } + static LValue new_Local (unsigned idx ) { return LValue(Storage::new_Local(idx), {}); } + static LValue new_Static (::HIR::Path p) { return LValue(Storage::new_Static(::std::move(p)), {}); } + + static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); return lv; } + static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); return lv; } + static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); return lv; } + static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); return lv; } - static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); } - static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); } - static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); } - static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); } + bool is_Return() const { return m_wrappers.empty() && m_root.is_Return(); } + bool is_Local () const { return m_wrappers.empty() && m_root.is_Local(); } + const unsigned as_Local() const { assert(m_wrappers.empty()); return m_root.as_Local(); } + + bool is_Deref () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Deref(); } + bool is_Field () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Field(); } + bool is_Downcast() const { return m_wrappers.size() > 0 && m_wrappers.back().is_Downcast(); } + const unsigned as_Field() const { assert(!m_wrappers.empty()); return m_wrappers.back().as_Field(); } + + void inc_Field () { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Field (); } + void inc_Downcast() { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Downcast(); } + + Ordering ord(const LValue& x) const; LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0); //LValue monomorphise(const TransParams& ms, unsigned local_offset=0); - LValue clone() const; + LValue clone() const { + return LValue(m_root.clone(), m_wrappers); + } + LValue clone_wrapped(::std::vector wrappers) const { + if( this->m_wrappers.empty() ) { + return LValue(m_root.clone(), ::std::move(wrappers)); + } + else { + return clone_wrapped(wrappers.begin(), wrappers.end()); + } + } + template + LValue clone_wrapped(It begin_it, It end_it) const { + ::std::vector wrappers; + wrappers.reserve(m_wrappers.size() + ::std::distance(begin_it, end_it)); + wrappers.insert(wrappers.end(), m_wrappers.begin(), m_wrappers.end()); + wrappers.insert(wrappers.end(), begin_it, end_it); + return LValue(m_root.clone(), ::std::move(wrappers)); + } + + LValue clone_unwrapped(unsigned count=1) const { + assert(count > 0); + assert(count <= m_wrappers.size()); + return LValue(m_root.clone(), ::std::vector(m_wrappers.begin(), m_wrappers.end() - count)); + } + + /// Helper class that represents a LValue unwrapped to a certain degree + class RefCommon + { + protected: + const LValue* m_lv; + size_t m_wrapper_count; + + RefCommon(const LValue& lv, size_t wrapper_count) + :m_lv(&lv) + ,m_wrapper_count(wrapper_count) + { + assert(wrapper_count <= lv.m_wrappers.size()); + } + + public: + LValue clone() const { + return ::MIR::LValue( m_lv->m_root.clone(), ::std::vector(m_lv->m_wrappers.begin(), m_lv->m_wrappers.begin() + m_wrapper_count) ); + } + + const LValue& lv() const { return *m_lv; } + size_t wrapper_count() const { return m_wrapper_count; } + + /// Unwrap one level, returning false if already at the root + bool try_unwrap() { + if( m_wrapper_count == 0 ) { + return false; + } + else { + m_wrapper_count --; + return true; + } + } + + enum Tag { + TAGDEAD, + TAG_Return, + TAG_Argument, + TAG_Local, + TAG_Static, + TAG_Deref, + TAG_Field, + TAG_Downcast, + TAG_Index, + }; + Tag tag() const { + if( m_wrapper_count == 0 ) + { + switch(m_lv->m_root.tag()) + { + case Storage::TAGDEAD: return TAGDEAD; + case Storage::TAG_Return: return TAG_Return; + case Storage::TAG_Argument: return TAG_Argument; + case Storage::TAG_Local: return TAG_Local; + case Storage::TAG_Static: return TAG_Static; + } + } + else + { + switch(m_lv->m_wrappers[m_wrapper_count-1].tag()) + { + case Wrapper::TAGDEAD: return TAGDEAD; + case Wrapper::TAG_Deref: return TAG_Deref; + case Wrapper::TAG_Field: return TAG_Field; + case Wrapper::TAG_Downcast: return TAG_Downcast; + case Wrapper::TAG_Index: return TAG_Index; + } + } + return TAGDEAD; + } + + bool is_Local () const { return m_wrapper_count == 0 && m_lv->m_root.is_Local (); } + bool is_Return () const { return m_wrapper_count == 0 && m_lv->m_root.is_Return (); } + bool is_Argument() const { return m_wrapper_count == 0 && m_lv->m_root.is_Argument(); } + bool is_Static () const { return m_wrapper_count == 0 && m_lv->m_root.is_Static (); } + bool is_Deref () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Deref (); } + bool is_Field () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Field (); } + bool is_Downcast() const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Downcast(); } + bool is_Index () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Index (); } + + const unsigned as_Local () const { assert(is_Local ()); return m_lv->m_root.as_Local (); } + const char as_Return () const { assert(is_Return ()); return m_lv->m_root.as_Return (); } + const unsigned as_Argument() const { assert(is_Argument()); return m_lv->m_root.as_Argument(); } + const HIR::Path& as_Static () const { assert(is_Static ()); return m_lv->m_root.as_Static (); } + const char as_Deref () const { assert(is_Deref ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Deref (); } + const unsigned as_Field () const { assert(is_Field ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Field (); } + const unsigned as_Downcast() const { assert(is_Downcast()); return m_lv->m_wrappers[m_wrapper_count-1].as_Downcast(); } + const unsigned as_Index () const { assert(is_Index ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Index (); } - class Ref + void fmt(::std::ostream& os) const; + Ordering ord(const RefCommon& b) const; + }; + + class CRef: public RefCommon { - LValue& r; - size_t wrapper_idx; - public:: - LValue clone() const; - void replace(LValue x) const; + public: + CRef(const LValue& lv) + :RefCommon(lv, lv.m_wrappers.size()) + { + } + CRef(const LValue& lv, size_t wc) + :RefCommon(lv, wc) + { + } + + /// Unwrap one level + const CRef inner_ref() const { + assert(m_wrapper_count > 0); + auto rv = *this; + rv.m_wrapper_count--; + return rv; + } + + friend ::std::ostream& operator<<(::std::ostream& os, const CRef& x) { + x.fmt(os); + return os; + } + + bool operator<(const CRef& b) const { + return this->ord(b) == OrdLess; + } + bool operator==(const CRef& b) const { + return this->ord(b) == OrdEqual; + } }; + class MRef: public RefCommon + { + public: + MRef(LValue& lv) + :RefCommon(lv, lv.m_wrappers.size()) + { + } + + operator CRef() const { + return CRef(*m_lv, m_wrapper_count); + } + + MRef inner_ref() { + assert(m_wrapper_count > 0); + auto rv = *this; + rv.m_wrapper_count--; + return rv; + } + void replace(LValue x) { + auto& mut_lv = const_cast(*m_lv); + // Shortcut: No wrappers on source/destination (just assign the slot/root) + if( m_wrapper_count == 0 && x.m_wrappers.empty() ) { + mut_lv.m_root = ::std::move(x.m_root); + return ; + } + // If there's wrappers on this value (assigning over inner portion) + if( m_wrapper_count < m_lv->m_wrappers.size() ) { + // Add those wrappers to the end of the new value + x.m_wrappers.insert(x.m_wrappers.end(), m_lv->m_wrappers.begin() + m_wrapper_count, m_lv->m_wrappers.end()); + } + // Overwrite + mut_lv = ::std::move(x); + } + + friend ::std::ostream& operator<<(::std::ostream& os, const MRef& x) { + x.fmt(os); + return os; + } + }; + + Ordering ord(const LValue::CRef& x) const; + Ordering ord(const LValue::MRef& x) const; }; -#endif - -// "LVALUE" - Assignable values -TAGGED_UNION_EX(LValue, (), Return, ( - // Function return - (Return, struct{}), - // Function argument (input) - (Argument, struct { unsigned int idx; }), - // Variable/Temporary - (Local, unsigned int), - // `static` or `static mut` - (Static, ::std::unique_ptr<::HIR::Path>), - // Field access (tuple, struct, tuple struct, enum field, ...) - // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring) - (Field, struct { - ::std::unique_ptr val; - unsigned int field_index; - }), - // Dereference a value - (Deref, struct { - ::std::unique_ptr val; - }), - // Index an array or slice (typeof(val) == [T; n] or [T]) - // NOTE: This is not bounds checked! - (Index, struct { - ::std::unique_ptr val; - ::std::unique_ptr idx; - }), - // Interpret an enum as a particular variant - (Downcast, struct { - ::std::unique_ptr val; - unsigned int variant_index; - }) - ), (),(), ( - LValue clone() const; - ) - ); extern ::std::ostream& operator<<(::std::ostream& os, const LValue& x); -extern bool operator<(const LValue& a, const LValue& b); -extern bool operator==(const LValue& a, const LValue& b); +static inline bool operator<(const LValue& a, const LValue::CRef& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator<(const LValue& a, const LValue::MRef& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator<(const LValue::CRef& a, const LValue& b) { + return b.ord(a) == OrdGreater; +} +static inline bool operator<(const LValue::MRef& a, const LValue& b) { + return b.ord(a) == OrdGreater; +} +static inline bool operator<(const LValue& a, const LValue& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator==(const LValue& a, const LValue& b) { + return a.ord(b) == OrdEqual; +} static inline bool operator!=(const LValue& a, const LValue& b) { return !(a == b); } @@ -224,7 +468,7 @@ TAGGED_UNION_EX(Constant, (), Int, ( /// Parameter - A value used when a rvalue just reads (doesn't require a lvalue) /// Can be either a lvalue (memory address), or a constant -TAGGED_UNION_EX(Param, (), LValue, ( +TAGGED_UNION_EX(Param, (), Constant, ( (LValue, LValue), (Constant, Constant) ), (), (), ( @@ -237,7 +481,7 @@ TAGGED_UNION_EX(Param, (), LValue, ( ) ); -TAGGED_UNION_EX(RValue, (), Use, ( +TAGGED_UNION_EX(RValue, (), Tuple, ( (Use, LValue), (Constant, Constant), (SizedArray, struct { @@ -359,7 +603,7 @@ enum class eDropKind { SHALLOW, DEEP, }; -TAGGED_UNION(Statement, Assign, +TAGGED_UNION(Statement, Asm, // Value assigment (Assign, struct { LValue dst; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 8d534314..a064b67d 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -68,7 +68,7 @@ MirBuilder::~MirBuilder() { if( has_result() ) { - push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) ); + push_stmt_assign( sp, ::MIR::LValue::new_Return(), get_result(sp) ); } terminate_scope_early(sp, fcn_scope()); @@ -176,7 +176,7 @@ void MirBuilder::define_variable(unsigned int idx) auto& tmp_scope = top_scope->data.as_Owning(); assert(tmp_scope.is_temporary); tmp_scope.slots.push_back( rv ); - return ::MIR::LValue::make_Local(rv); + return ::MIR::LValue::new_Local(rv); } ::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val) { @@ -258,12 +258,10 @@ void MirBuilder::set_result(const Span& sp, ::MIR::RValue val) m_result_valid = true; } -void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val) +void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination/*=true*/) { DEBUG(dst << " = " << val); ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, dst.tag() != ::MIR::LValue::TAGDEAD, ""); - ASSERT_BUG(sp, val.tag() != ::MIR::RValue::TAGDEAD, ""); auto moved_param = [&](const ::MIR::Param& p) { if(const auto* e = p.opt_LValue()) { @@ -344,13 +342,15 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal ) // Drop target if populated - mark_value_assigned(sp, dst); + if( drop_destination ) + { + mark_value_assigned(sp, dst); + } this->push_stmt( sp, ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) ); } void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, ""); if( lvalue_is_copy(sp, val) ) { // Don't emit a drop for Copy values @@ -362,7 +362,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, ""); // TODO: Ensure that the type is a Box? @@ -400,22 +399,12 @@ void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt) void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) { - VarState* state_p = nullptr; - // TODO: Tracking of complex asignment states (e.g. assignment of a field) - TU_MATCH_DEF(::MIR::LValue, (dst), (e), - ( - ), - (Return, - // Don't drop. - // No state tracking for the return value - ), - (Argument, - state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument); - ), - (Local, - state_p = &get_slot_state_mut(sp, e, SlotType::Local); - ) - ) + if( dst.m_root.is_Return() ) + { + ASSERT_BUG(sp, dst.m_wrappers.empty(), "Assignment to a component of the return value should be impossible."); + return ; + } + VarState* state_p = get_val_state_mut_p(sp, dst);; if( state_p ) { @@ -425,42 +414,28 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) drop_value_from_state(sp, *state_p, dst.clone()); *state_p = VarState::make_Valid({}); } - // TODO: What about assigning into non-tracked locations? Should still cause a drop + else + { + // Assigning into non-tracked locations still causes a drop + drop_value_from_state(sp, VarState::make_Valid({}), dst.clone()); + } } void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/) { TRACE_FUNCTION_F(val); - TU_MATCH_DEF(::MIR::LValue, (val), (e), - ( + for(const auto& w : val.m_wrappers) + { + if( w.is_Index() ) { + // Raise index temporary + raise_temporaries(sp, ::MIR::LValue::new_Local(w.as_Index()), scope, to_above); + } + } + if( !val.m_root.is_Local() ) { // No raising of these source values? return ; - ), - // TODO: This may not be correct, because it can change the drop points and ordering - // HACK: Working around cases where values are dropped while the result is not yet used. - (Index, - raise_temporaries(sp, *e.val, scope, to_above); - raise_temporaries(sp, *e.idx, scope, to_above); - return ; - ), - (Deref, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - (Field, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - (Downcast, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - // Actual value types - (Local, - ) - ) - ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val); - const auto idx = val.as_Local(); + } + const auto idx = val.m_root.as_Local(); bool is_temp = (idx >= m_first_temp_idx); /* if( !is_temp ) { @@ -833,13 +808,12 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle } auto& src_scope_def = m_scopes.at(source.idx); -#if 1 ASSERT_BUG(sp, src_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (source)"); ASSERT_BUG(sp, src_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (source)"); auto& src_list = src_scope_def.data.as_Owning().slots; for(auto idx : src_list) { - DEBUG("> Raising " << ::MIR::LValue::make_Local(idx)); + DEBUG("> Raising " << ::MIR::LValue::new_Local(idx)); assert(idx >= m_first_temp_idx); } @@ -910,13 +884,6 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle // Move all defined variables from one to the other auto& tgt_list = tgt_scope_def.data.as_Owning().slots; tgt_list.insert( tgt_list.end(), src_list.begin(), src_list.end() ); -#else - auto list = src_scope_def.data.as_Temporaries().temporaries; - for(auto idx : list) - { - this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target); - } -#endif // Scope completed m_scope_stack.pop_back(); @@ -979,7 +946,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, for(size_t i = 0; i < m_arg_states.size(); i ++) { const auto& state = get_slot_state(sp, i, SlotType::Argument); - this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast(i) })); + this->drop_value_from_state(sp, state, ::MIR::LValue::new_Argument(static_cast(i))); } } } @@ -1060,7 +1027,7 @@ namespace }); if( is_box ) { - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); } else { @@ -1086,13 +1053,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } } return; @@ -1168,7 +1135,7 @@ namespace }); if( is_box ) { - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); } else { BUG(sp, "MovedOut on non-Box"); @@ -1192,19 +1159,19 @@ namespace } auto& ose = old_state.as_Partial(); if( is_enum ) { - auto ilv = ::MIR::LValue::make_Downcast({ box$(lv.clone()), 0 }); + auto ilv = ::MIR::LValue::new_Downcast(lv.clone(), 0); for(size_t i = 0; i < ose.inner_states.size(); i ++) { merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]); - ilv.as_Downcast().variant_index ++; + ilv.inc_Downcast(); } } else { - auto ilv = ::MIR::LValue::make_Field({ box$(lv.clone()), 0 }); + auto ilv = ::MIR::LValue::new_Field(lv.clone(), 0); for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]); - ilv.as_Field().field_index ++; + ilv.inc_Field(); } } } return; @@ -1268,13 +1235,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } return; } @@ -1309,7 +1276,7 @@ namespace builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, is_valid); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state); return ; } case VarState::TAG_Optional: { const auto& nse = new_state.as_Optional(); @@ -1334,7 +1301,7 @@ namespace builder.push_stmt_set_dropflag_other(sp, ose.outer_flag, nse); builder.push_stmt_set_dropflag_default(sp, nse); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state); return; } case VarState::TAG_MovedOut: { const auto& nse = new_state.as_MovedOut(); @@ -1342,7 +1309,7 @@ namespace { TODO(sp, "Handle mismatched flags in MovedOut"); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); return; } case VarState::TAG_Partial: BUG(sp, "MovedOut->Partial not valid"); @@ -1366,13 +1333,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], new_state); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], new_state); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], new_state); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], new_state); } } return ; @@ -1384,13 +1351,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } } return ; @@ -1419,8 +1386,8 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type)); } }; - merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local); - merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument); + merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::new_Local, SlotType::Local); + merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::new_Argument(v); }, SlotType::Argument); } else { @@ -1475,7 +1442,7 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r auto it = states.find(idx); const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1)); - auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx})); + auto lv = (type == SlotType::Local ? ::MIR::LValue::new_Local(idx) : ::MIR::LValue::new_Argument(idx)); merge_state(sp, *this, mv$(lv), out_state, src_state); } }; @@ -1565,7 +1532,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::new_Local(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1574,7 +1541,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::new_Argument(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1612,7 +1579,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) for(auto& ent : e->changed_slots) { auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local); - auto lv = ::MIR::LValue::make_Local(ent.first); + auto lv = ::MIR::LValue::new_Local(ent.first); DEBUG(lv << " " << vs << " => " << ent.second); if( vs != ent.second ) { @@ -1630,97 +1597,96 @@ void MirBuilder::complete_scope(ScopeDef& sd) } } -void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const +void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb, const ::MIR::LValue::Wrapper* stop_wrapper/*=nullptr*/) const { - TU_MATCH(::MIR::LValue, (val), (e), + ::HIR::TypeRef tmp; + const ::HIR::TypeRef* ty_p = nullptr; + TU_MATCHA( (val.m_root), (e), (Return, TODO(sp, "Return"); ), (Argument, - cb( m_args.at(e.idx).second ); + ty_p = &m_args.at(e).second; ), (Local, - cb( m_output.locals.at(e) ); + ty_p = &m_output.locals.at(e); ), (Static, - TU_MATCHA( (e->m_data), (pe), + TU_MATCHA( (e.m_data), (pe), (Generic, ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static"); const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path); - cb( s.m_type ); + ty_p = &s.m_type; ), (UfcsKnown, - TODO(sp, "Static - UfcsKnown - " << *e); + TODO(sp, "Static - UfcsKnown - " << e); ), (UfcsUnknown, - BUG(sp, "Encountered UfcsUnknown in Static - " << *e); + BUG(sp, "Encountered UfcsUnknown in Static - " << e); ), (UfcsInherent, - TODO(sp, "Static - UfcsInherent - " << *e); + TODO(sp, "Static - UfcsInherent - " << e); ) ) - ), - (Field, - with_val_type(sp, *e.val, [&](const auto& ty){ + ) + ) + assert(ty_p); + for(const auto& w : val.m_wrappers) + { + if( &w == stop_wrapper ) + { + stop_wrapper = nullptr; // Reset so the below bugcheck can work + break; + } + const auto& ty = *ty_p; + ty_p = nullptr; + auto maybe_monomorph = [&](const ::HIR::GenericParams& params_def, const ::HIR::Path& p, const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { + if( monomorphise_type_needed(t) ) { + tmp = monomorphise_type(sp, params_def, p.m_data.as_Generic().m_params, t); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return t; + } + }; + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, field_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Field access on unexpected type - " << ty); ), (Array, - cb( *te.inner ); + ty_p = &*te.inner; ), (Slice, - cb( *te.inner ); + ty_p = &*te.inner; ), (Path, - ::HIR::TypeRef tmp; if( const auto* tep = te.binding.opt_Struct() ) { const auto& str = **tep; - auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { - if( monomorphise_type_needed(t) ) { - tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, t); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return t; - } - }; TU_MATCHA( (str.m_data), (se), (Unit, BUG(sp, "Field on unit-like struct - " << ty); ), (Tuple, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index]; - cb( maybe_monomorph(fld.ent) ); + ASSERT_BUG(sp, field_index < se.size(), + "Field index out of range in tuple-struct " << ty << " - " << field_index << " > " << se.size()); + const auto& fld = se[field_index]; + ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent); ), (Named, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index].second; - cb( maybe_monomorph(fld.ent) ); + ASSERT_BUG(sp, field_index < se.size(), + "Field index out of range in struct " << ty << " - " << field_index << " > " << se.size()); + const auto& fld = se[field_index].second; + ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent); ) ) } - else if( const auto* tep = te.binding.opt_Union() ) + else if( /*const auto* tep =*/ te.binding.opt_Union() ) { BUG(sp, "Field access on a union isn't valid, use Downcast instead - " << ty); - const auto& unm = **tep; - auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { - if( monomorphise_type_needed(t) ) { - tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return t; - } - }; - ASSERT_BUG(sp, e.field_index < unm.m_variants.size(), "Field index out of range for union"); - cb( maybe_monomorph(unm.m_variants.at(e.field_index).second.ent) ); } else { @@ -1728,14 +1694,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: } ), (Tuple, - ASSERT_BUG(sp, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size()); - cb( te[e.field_index] ); + ASSERT_BUG(sp, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size()); + ty_p = &te[field_index]; ) ) - }); - ), - (Deref, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Deref, _e) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Deref on unexpected type - " << ty); @@ -1743,38 +1707,34 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: (Path, if( const auto* inner_ptr = this->is_type_owned_box(ty) ) { - cb( *inner_ptr ); + ty_p = &*inner_ptr; } else { BUG(sp, "Deref on unexpected type - " << ty); } ), (Pointer, - cb(*te.inner); + ty_p = &*te.inner; ), (Borrow, - cb(*te.inner); + ty_p = &*te.inner; ) ) - }); - ), - (Index, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Index, _index_val) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Index on unexpected type - " << ty); ), (Slice, - cb(*te.inner); + ty_p = &*te.inner; ), (Array, - cb(*te.inner); + ty_p = &*te.inner; ) ) - }); - ), - (Downcast, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Downcast, variant_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Downcast on unexpected type - " << ty); @@ -1785,33 +1745,19 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: const auto& enm = **pbe; ASSERT_BUG(sp, enm.m_data.is_Data(), "Downcast on non-data enum"); const auto& variants = enm.m_data.as_Data(); - ASSERT_BUG(sp, e.variant_index < variants.size(), "Variant index out of range"); - const auto& variant = variants[e.variant_index]; + ASSERT_BUG(sp, variant_index < variants.size(), "Variant index out of range"); + const auto& variant = variants[variant_index]; - if( monomorphise_type_needed(variant.type) ) { - auto tmp = monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, variant.type); - m_resolve.expand_associated_types(sp, tmp); - cb(tmp); - } - else { - cb(variant.type); - } + ty_p = &maybe_monomorph(enm.m_params, te.path, variant.type); } else if( const auto* pbe = te.binding.opt_Union() ) { const auto& unm = **pbe; - ASSERT_BUG(sp, e.variant_index < unm.m_variants.size(), "Variant index out of range"); - const auto& variant = unm.m_variants.at(e.variant_index); + ASSERT_BUG(sp, variant_index < unm.m_variants.size(), "Variant index out of range"); + const auto& variant = unm.m_variants.at(variant_index); const auto& fld = variant.second; - if( monomorphise_type_needed(fld.ent) ) { - auto sty = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, fld.ent); - m_resolve.expand_associated_types(sp, sty); - cb(sty); - } - else { - cb(fld.ent); - } + ty_p = &maybe_monomorph(unm.m_params, te.path, fld.ent); } else { @@ -1819,9 +1765,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: } ) ) - }); - ) - ) + } + } + assert(ty_p); + } + ASSERT_BUG(sp, !stop_wrapper, "A stop wrapper was passed, but not found"); + cb(*ty_p); } bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const @@ -1998,165 +1947,177 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT } } -const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count) -{ - TODO(sp, ""); -} -VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) +VarState* MirBuilder::get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv) { TRACE_FUNCTION_F(lv); - TU_MATCHA( (lv), (e), + VarState* vs; + TU_MATCHA( (lv.m_root), (e), (Return, BUG(sp, "Move of return value"); - return get_slot_state_mut(sp, ~0u, SlotType::Local); + vs = &get_slot_state_mut(sp, ~0u, SlotType::Local); ), (Argument, - return get_slot_state_mut(sp, e.idx, SlotType::Argument); + vs = &get_slot_state_mut(sp, e, SlotType::Argument); ), (Local, - return get_slot_state_mut(sp, e, SlotType::Local); + vs = &get_slot_state_mut(sp, e, SlotType::Local); ), (Static, - BUG(sp, "Attempting to mutate state of a static"); - ), - (Field, - auto& ivs = get_val_state_mut(sp, *e.val); - VarState tpl; - TU_MATCHA( (ivs), (ivse), - (Invalid, - //BUG(sp, "Mutating inner state of an invalidated composite - " << lv); - tpl = VarState::make_Valid({}); - ), - (MovedOut, - BUG(sp, "Field on value with MovedOut state - " << lv); - ), - (Partial, - ), - (Optional, - tpl = ivs.clone(); - ), - (Valid, - tpl = VarState::make_Valid({}); - ) + return nullptr; + //BUG(sp, "Attempting to mutate state of a static"); ) - if( !ivs.is_Partial() ) - { - size_t n_flds = 0; - with_val_type(sp, *e.val, [&](const auto& ty) { - DEBUG("ty = " << ty); - if(const auto* e = ty.m_data.opt_Path()) { - ASSERT_BUG(sp, e->binding.is_Struct(), ""); - const auto& str = *e->binding.as_Struct(); - TU_MATCHA( (str.m_data), (se), - (Unit, - BUG(sp, "Field access of unit-like struct"); - ), - (Tuple, - n_flds = se.size(); - ), - (Named, - n_flds = se.size(); - ) - ) - } - else if(const auto* e = ty.m_data.opt_Tuple()) { - n_flds = e->size(); - } - else if(const auto* e = ty.m_data.opt_Array()) { - n_flds = e->size_val; - } - else { - TODO(sp, "Determine field count for " << ty); - } - }); - ::std::vector inner_vs; inner_vs.reserve(n_flds); - for(size_t i = 0; i < n_flds; i++) - inner_vs.push_back( tpl.clone() ); - ivs = VarState::make_Partial({ mv$(inner_vs) }); - } - return ivs.as_Partial().inner_states.at(e.field_index); - ), - (Deref, - // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop - bool is_box = false; - if( this->m_lang_Box ) - { - with_val_type(sp, *e.val, [&](const auto& ty){ - DEBUG("ty = " << ty); - is_box = this->is_type_owned_box(ty); - }); - } - + ) - if( is_box ) - { - auto& ivs = get_val_state_mut(sp, *e.val); - if( ! ivs.is_MovedOut() ) + for(const auto& w : lv.m_wrappers) + { + auto& ivs = *vs; + vs = nullptr; + TU_MATCH_HDRA( (w), { ) + TU_ARMA(Field, field_index) { + VarState tpl; + TU_MATCHA( (ivs), (ivse), + (Invalid, + //BUG(sp, "Mutating inner state of an invalidated composite - " << lv); + tpl = VarState::make_Valid({}); + ), + (MovedOut, + BUG(sp, "Field on value with MovedOut state - " << lv); + ), + (Partial, + ), + (Optional, + tpl = ivs.clone(); + ), + (Valid, + tpl = VarState::make_Valid({}); + ) + ) + if( !ivs.is_Partial() ) { - ::std::vector inner; - inner.push_back(VarState::make_Valid({})); - unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u); - ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag }); + size_t n_flds = 0; + with_val_type(sp, lv, [&](const auto& ty) { + DEBUG("ty = " << ty); + if(const auto* e = ty.m_data.opt_Path()) { + ASSERT_BUG(sp, e->binding.is_Struct(), ""); + const auto& str = *e->binding.as_Struct(); + TU_MATCHA( (str.m_data), (se), + (Unit, + BUG(sp, "Field access of unit-like struct"); + ), + (Tuple, + n_flds = se.size(); + ), + (Named, + n_flds = se.size(); + ) + ) + } + else if(const auto* e = ty.m_data.opt_Tuple()) { + n_flds = e->size(); + } + else if(const auto* e = ty.m_data.opt_Array()) { + n_flds = e->size_val; + } + else { + TODO(sp, "Determine field count for " << ty); + } + }, &w); + ::std::vector inner_vs; inner_vs.reserve(n_flds); + for(size_t i = 0; i < n_flds; i++) + inner_vs.push_back( tpl.clone() ); + ivs = VarState::make_Partial({ mv$(inner_vs) }); + } + vs = &ivs.as_Partial().inner_states.at(field_index); + } + TU_ARMA(Deref, _e) { + // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop + bool is_box = false; + if( this->m_lang_Box ) + { + with_val_type(sp, lv, [&](const auto& ty){ + DEBUG("ty = " << ty); + is_box = this->is_type_owned_box(ty); + }, &w); } - return *ivs.as_MovedOut().inner_state; - } - else - { - BUG(sp, "Move out of deref with non-Copy values - &move? - " << lv << " : " << FMT_CB(ss, this->with_val_type(sp, lv, [&](const auto& ty){ss<