diff options
author | John Hodge <tpg@ucc.asn.au> | 2017-11-01 20:46:36 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2017-11-01 20:46:36 +0800 |
commit | cb271f8ea98d1a5c65a5e636a0e73a85710027b4 (patch) | |
tree | 9694427c074c0e0d581cde6e01b6167016e0f844 | |
parent | 8306f43ccdf0414b48891aa5eb04d8901899c052 (diff) | |
download | mrust-cb271f8ea98d1a5c65a5e636a0e73a85710027b4.tar.gz |
HIR - Refactor enums to only embed a single field (and give variants types)
37 files changed, 917 insertions, 962 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index b9d87bfa..968cf8d3 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -424,7 +424,6 @@ namespace { }) _(Struct, { deserialise_genericpath(), - static_cast<unsigned int>( m_in.read_count() ), deserialise_vec< ::MIR::Param>() }) #undef _ @@ -619,7 +618,8 @@ namespace { ::HIR::Enum deserialise_enum(); - ::HIR::Enum::Variant deserialise_enumvariant(); + ::HIR::Enum::DataVariant deserialise_enumdatavariant(); + ::HIR::Enum::ValueVariant deserialise_enumvaluevariant(); ::HIR::Struct deserialise_struct(); ::HIR::Union deserialise_union(); @@ -685,7 +685,8 @@ namespace { template<> DEF_D( ::HIR::ValueItem, return d.deserialise_valueitem(); ) template<> DEF_D( ::HIR::TypeItem, return d.deserialise_typeitem(); ) - template<> DEF_D( ::HIR::Enum::Variant, return d.deserialise_enumvariant(); ) + template<> DEF_D( ::HIR::Enum::ValueVariant, return d.deserialise_enumvaluevariant(); ) + template<> DEF_D( ::HIR::Enum::DataVariant, return d.deserialise_enumdatavariant(); ) template<> DEF_D( ::HIR::Literal, return d.deserialise_literal(); ) template<> DEF_D( ::HIR::AssociatedType, return d.deserialise_associatedtype(); ) @@ -878,31 +879,47 @@ namespace { ::HIR::Enum HirDeserialiser::deserialise_enum() { TRACE_FUNCTION; + struct H { + static ::HIR::Enum::Class deserialise_enumclass(HirDeserialiser& des) { + switch( des.m_in.read_tag() ) + { + case ::HIR::Enum::Class::TAG_Data: + return ::HIR::Enum::Class::make_Data( des.deserialise_vec<::HIR::Enum::DataVariant>() ); + case ::HIR::Enum::Class::TAG_Value: + return ::HIR::Enum::Class::make_Value({ + static_cast< ::HIR::Enum::Repr>(des.m_in.read_tag()), + des.deserialise_vec<::HIR::Enum::ValueVariant>() + }); + default: + throw ""; + } + } + }; return ::HIR::Enum { deserialise_genericparams(), - static_cast< ::HIR::Enum::Repr>(m_in.read_tag()), - deserialise_vec< ::std::pair< ::std::string, ::HIR::Enum::Variant> >(), + H::deserialise_enumclass(*this), deserialise_markings() }; } - ::HIR::Enum::Variant HirDeserialiser::deserialise_enumvariant() + ::HIR::Enum::DataVariant HirDeserialiser::deserialise_enumdatavariant() { - switch( m_in.read_tag() ) - { - case ::HIR::Enum::Variant::TAG_Unit: - return ::HIR::Enum::Variant::make_Unit({}); - case ::HIR::Enum::Variant::TAG_Value: - return ::HIR::Enum::Variant::make_Value({ - ::HIR::ExprPtr {}, - deserialise_literal() - }); - case ::HIR::Enum::Variant::TAG_Tuple: - return ::HIR::Enum::Variant( deserialise_vec< ::HIR::VisEnt< ::HIR::TypeRef> >() ); - case ::HIR::Enum::Variant::TAG_Struct: - return ::HIR::Enum::Variant( deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >() ); - default: - throw ""; - } + auto name = m_in.read_string(); + DEBUG("Enum::DataVariant " << name); + return ::HIR::Enum::DataVariant { + mv$(name), + m_in.read_bool(), + deserialise_type() + }; + } + ::HIR::Enum::ValueVariant HirDeserialiser::deserialise_enumvaluevariant() + { + auto name = m_in.read_string(); + DEBUG("Enum::ValueVariant " << name); + return ::HIR::Enum::ValueVariant { + mv$(name), + ::HIR::ExprPtr {}, + m_in.read_u64() + }; } ::HIR::Union HirDeserialiser::deserialise_union() { @@ -975,7 +992,7 @@ namespace { _(List, deserialise_vec< ::HIR::Literal>() ) _(Variant, { static_cast<unsigned int>(m_in.read_count()), - deserialise_vec< ::HIR::Literal>() + box$( deserialise_literal() ) }) _(Integer, m_in.read_u64() ) _(Float, m_in.read_double() ) diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index 75dde59f..3bbbdd95 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -158,38 +158,27 @@ namespace { } m_os << indent() << "{\n"; inc_indent(); - for(const auto& var : item.m_variants) + if(const auto* e = item.m_data.opt_Value()) { - m_os << indent() << var.first; - TU_MATCHA( (var.second), (e), - (Unit, - ), - (Value, - m_os << " = "; - if( e.val.is_Invalid() ) { - m_os << "?"; - } - else { - m_os << e.val; + for(const auto& var : e->variants) + { + m_os << indent() << var.name; + } + } + else + { + for(const auto& var : item.m_data.as_Data()) + { + m_os << indent() << var.name; + if( var.type == ::HIR::TypeRef::new_unit() ) + { + } - ), - (Tuple, - m_os << "("; - for(const auto& fld : e) - m_os << fld.ent << ", "; - m_os << ")"; - ), - (Struct, - m_os << "{\n"; - inc_indent(); - for(const auto& fld : e) + else { - m_os << indent() << fld.first << ": " << fld.second.ent << ",\n"; + m_os << " " << var.type << (var.is_struct ? "/*struct*/" : ""); } - m_os << indent() << "}"; - dec_indent(); - ) - ) + } m_os << ",\n"; } dec_indent(); diff --git a/src/hir/expr_ptr.hpp b/src/hir/expr_ptr.hpp index 5bedd1da..97991bf2 100644 --- a/src/hir/expr_ptr.hpp +++ b/src/hir/expr_ptr.hpp @@ -8,6 +8,7 @@ #pragma once #include <memory> #include <vector> +#include <cassert> #include <mir/mir_ptr.hpp> @@ -47,10 +48,10 @@ public: this->ptr = p; } - ::HIR::ExprNode& operator*() { return *ptr; } - const ::HIR::ExprNode& operator*() const { return *ptr; } - ::HIR::ExprNode* operator->() { return ptr; } - const ::HIR::ExprNode* operator->() const { return ptr; } + ::HIR::ExprNode& operator*() { assert(ptr); return *ptr; } + const ::HIR::ExprNode& operator*() const { assert(ptr); return *ptr; } + ::HIR::ExprNode* operator->() { assert(ptr); return ptr; } + const ::HIR::ExprNode* operator->() const { assert(ptr); return ptr; } }; class ExprPtr diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 0f29f9b5..8c072cc5 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -217,8 +217,12 @@ field_count = var.as_Tuple().m_sub_types.size(); } else { - const auto& var = pb.hir->m_variants.at(pb.idx).second; - field_count = var.as_Tuple().size(); + const auto& var = pb.hir->m_data.as_Data().at(pb.idx); + // Need to be able to look up the type's actual definition + // - Either a name lookup, or have binding be done before this pass. + const auto& str = g_crate_ptr->get_struct_by_path(pat.span(), var.type.m_data.as_Path().path.m_data.as_Generic().m_path); + field_count = str.m_data.as_Tuple().size(); + //field_count = var.type.m_data.as_Path().binding.as_Struct()->m_data.as_Tuple().size(); } ::std::vector<HIR::Pattern> sub_patterns; @@ -862,48 +866,139 @@ namespace { }; } -::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& f) +::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::MetaItems& attrs, ::std::function<void(::std::string, ::HIR::Struct)> push_struct) { - ::std::vector< ::std::pair< ::std::string, ::HIR::Enum::Variant> > variants; - for(const auto& var : f.variants()) + // 1. Figure out what sort of enum this is (value or data) + bool has_value = false; + bool has_data = false; + for(const auto& var : ent.variants()) { - TU_MATCH(::AST::EnumVariantData, (var.m_data), (e), - (Value, - if( e.m_value.is_valid() ) + if( TU_TEST1(var.m_data, Value, .m_value.is_valid()) ) + { + has_value = true; + } + else if( var.m_data.is_Tuple() || var.m_data.is_Struct() ) + { + has_data = true; + } + else + { + // Unit-like + assert(var.m_data.is_Value()); + } + } + + if( has_value && has_data ) + { + ERROR(Span(), E0000, "Enum " << path << " has both value and data variants"); + } + + ::HIR::Enum::Class data; + if( ent.variants().size() > 0 && !has_data ) + { + ::std::vector<::HIR::Enum::ValueVariant> variants; + for(const auto& var : ent.variants()) + { + const auto& ve = var.m_data.as_Value(); + // TODO: Quick consteval on the expression? + variants.push_back({ + var.m_name, LowerHIR_Expr(ve.m_value), 0 + }); + } + + auto repr = ::HIR::Enum::Repr::Rust; + if( const auto* attr_repr = attrs.get("repr") ) + { + ASSERT_BUG(Span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(Span(), attr_repr->items().size() == 1, "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(Span(), attr_repr->items()[0].has_noarg(), "#[repr] attribute malformed, " << *attr_repr); + const auto& repr_str = attr_repr->items()[0].name(); + if( repr_str == "C" ) { + repr = ::HIR::Enum::Repr::C; + } + else { + // TODO: Other repr types + } + } + data = ::HIR::Enum::Class::make_Value({ repr, mv$(variants) }); + } + // NOTE: empty enums are encoded as empty Data enums + else + { + ::std::vector<::HIR::Enum::DataVariant> variants; + for(const auto& var : ent.variants()) + { + if( var.m_data.is_Value() ) { - variants.push_back( ::std::make_pair(var.m_name, ::HIR::Enum::Variant::make_Value({ - LowerHIR_Expr(e.m_value), - ::HIR::Literal {} - }) ) ); + // TODO: Should this make its own unit-like struct? + variants.push_back({ var.m_name, false, ::HIR::TypeRef::new_unit() }); } + //else if( TU_TEST1(var.m_data, Tuple, m_sub_types.size() == 0) ) + //{ + // variants.push_back({ var.m_name, false, ::HIR::TypeRef::new_unit() }); + //} + //else if( TU_TEST1(var.m_data, Tuple, m_sub_types.size() == 1) ) + //{ + // const auto& ty = var.m_data.as_Tuple().m_sub_types[0]; + // variants.push_back({ var.m_name, false, LowerHIR_Type(ty) }); + //} else { - variants.push_back( ::std::make_pair(var.m_name, ::HIR::Enum::Variant::make_Unit({})) ); + ::HIR::Struct::Data data; + if( const auto* ve = var.m_data.opt_Tuple() ) + { + ::HIR::Struct::Data::Data_Tuple fields; + for(const auto& field : ve->m_sub_types) + fields.push_back( new_visent(true, LowerHIR_Type(field)) ); + data = ::HIR::Struct::Data::make_Tuple( mv$(fields) ); + } + else if( const auto* ve = var.m_data.opt_Struct() ) + { + ::HIR::Struct::Data::Data_Named fields; + for(const auto& field : ve->m_fields) + fields.push_back( ::std::make_pair( field.m_name, new_visent(true, LowerHIR_Type(field.m_type)) ) ); + data = ::HIR::Struct::Data::make_Named( mv$(fields) ); + } + else + { + throw ""; + } + + auto ty_name = FMT(path.name << "#" << var.m_name); + push_struct( + ty_name, + ::HIR::Struct { + LowerHIR_GenericParams(ent.params(), nullptr), + ::HIR::Struct::Repr::Rust, + mv$(data) + } + ); + auto ty_ipath = path; + ty_ipath.name = ty_name.c_str(); + auto ty_path = ty_ipath.get_full_path(); + // Add type params + { + auto& params = ty_path.m_data.as_Generic().m_params; + unsigned int i = 0; + for(const auto& typ : ent.params().ty_params()) + params.m_types.push_back( ::HIR::TypeRef/*::new_generic*/(typ.name(), i++) ); + } + variants.push_back({ var.m_name, var.m_data.is_Struct(), ::HIR::TypeRef::new_path( mv$(ty_path), {} ) }); } - ), - (Tuple, - ::HIR::Enum::Variant::Data_Tuple types; - for(const auto& st : e.m_sub_types) - types.push_back( new_visent(true, LowerHIR_Type(st)) ); - variants.push_back( ::std::make_pair(var.m_name, ::HIR::Enum::Variant::make_Tuple(mv$(types))) ); - ), - (Struct, - ::HIR::Enum::Variant::Data_Struct ents; - for( const auto& ent : e.m_fields ) - ents.push_back( ::std::make_pair( ent.m_name, new_visent(true, LowerHIR_Type(ent.m_type)) ) ); - variants.push_back( ::std::make_pair(var.m_name, ::HIR::Enum::Variant::make_Struct(mv$(ents))) ); - ) - ) - } + } - auto repr = ::HIR::Enum::Repr::Rust; - // TODO: Get repr from attributes + if( /*const auto* attr_repr =*/ attrs.get("repr") ) + { + // NOTE: librustc_llvm has `#[repr(C)] enum AttributePlace { Argument(u32), Function }` + //ERROR(Span(), E0000, "#[repr] not allowed on enums with data"); + } + data = ::HIR::Enum::Class::make_Data( mv$(variants) ); + } return ::HIR::Enum { - LowerHIR_GenericParams(f.params(), nullptr), - repr, - mv$(variants) + LowerHIR_GenericParams(ent.params(), nullptr), + mv$(data) }; } ::HIR::Union LowerHIR_Union(::HIR::ItemPath path, const ::AST::Union& f, const ::AST::MetaItems& attrs) @@ -1252,7 +1347,8 @@ 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, LowerHIR_Struct(item_path, e) ); ), (Enum, - _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Enum(item_path, e) ); + auto enm = LowerHIR_Enum(item_path, e, item.data.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, item.is_pub, mv$(str)); }); + _add_mod_ns_item( mod, item.name, item.is_pub, mv$(enm) ); ), (Union, _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Union(item_path, e, item.data.attrs) ); diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index a98140d7..ef20f08d 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -629,14 +629,19 @@ struct LowerHIR_ExprNode_Visitor: else { const auto& enm = *e.hir; - auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); - assert(it != enm.m_variants.end()); + auto idx = enm.find_variant(var_name); + assert(idx != SIZE_MAX); - var_idx = static_cast<unsigned int>(it - enm.m_variants.begin()); - if( it->second.is_Struct() ) { - ERROR(v.span(), E0000, "Named value referring to an enum that isn't tuple-like or unit-like - " << v.m_path); + var_idx = idx; + if( const auto* ee = enm.m_data.opt_Data() ) + { + if( ee->at(idx).type == ::HIR::TypeRef::new_unit() ) { + } + // TODO: Assert that it's not a struct-like + else { + is_tuple_constructor = true; + } } - is_tuple_constructor = it->second.is_Tuple(); } (void)var_idx; // TODO: Save time later by saving this. if( is_tuple_constructor ) { diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index ed6230d5..99fac517 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -25,10 +25,7 @@ namespace HIR { os << " ]"; ), (Variant, - os << "#" << e.idx << ":["; - for(const auto& val : e.vals) - os << " " << val << ","; - os << " ]"; + os << "#" << e.idx << ":" << *e.val; ), (Integer, os << e; @@ -66,11 +63,7 @@ namespace HIR { (Variant, if( le.idx != re.idx ) return false; - if( le.vals.size() != re.vals.size() ) - return false; - for(unsigned int i = 0; i < le.vals.size(); i ++) - if( le.vals[i] != re.vals[i] ) - return false; + return *le.val == *re.val; ), (Integer, return le == re; @@ -92,36 +85,43 @@ namespace HIR { } } -const ::HIR::Enum::Variant* ::HIR::Enum::get_variant(const ::std::string& name) const +size_t ::HIR::Enum::find_variant(const ::std::string& name) const { - auto it = ::std::find_if(m_variants.begin(), m_variants.end(), [&](const auto& x){ return x.first == name; }); - if( it == m_variants.end() ) - return nullptr; - return &it->second; + if( m_data.is_Value() ) + { + const auto& e = m_data.as_Value(); + auto it = ::std::find_if(e.variants.begin(), e.variants.end(), [&](const auto& x){ return x.name == name; }); + if( it == e.variants.end() ) + return SIZE_MAX; + return it - e.variants.begin(); + } + else + { + const auto& e = m_data.as_Data(); + + auto it = ::std::find_if(e.begin(), e.end(), [&](const auto& x){ return x.name == name; }); + if( it == e.end() ) + return SIZE_MAX; + return it - e.begin(); + } } bool HIR::Enum::is_value() const { - return this->m_repr != ::HIR::Enum::Repr::Rust || ::std::all_of(m_variants.begin(), m_variants.end(), [](const auto& x){return x.second.is_Unit() || x.second.is_Value();}); + return this->m_data.is_Value(); } uint32_t HIR::Enum::get_value(size_t idx) const { - assert(idx < m_variants.size()); - - if( const auto* e = m_variants[idx].second.opt_Value() ) + if( m_data.is_Value() ) { - return e->val.as_Integer(); - } + const auto& e = m_data.as_Value(); + assert(idx < e.variants.size()); - uint32_t val = 0; - for(size_t i = 0; i < idx; i ++) + return e.variants[idx].val; + } + else { - if( const auto* e = m_variants[i].second.opt_Value() ) - { - val = e->val.as_Integer(); - } - val ++; + assert(!"TODO: Enum::get_value on non-value enum?"); } - return val; } namespace { @@ -1214,7 +1214,7 @@ const ::HIR::Function& ::HIR::Crate::get_function_by_path(const Span& sp, const return e; ) else { - BUG(sp, "Enum path " << path << " didn't point to an enum"); + BUG(sp, "Function path " << path << " didn't point to an function"); } } diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index cc34c227..f13b1860 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -54,7 +54,7 @@ TAGGED_UNION(Literal, Invalid, // Variant = Enum variant (Variant, struct { unsigned int idx; - ::std::vector<Literal> vals; + ::std::unique_ptr<Literal> val; }), // Literal values (Integer, uint64_t), @@ -213,33 +213,43 @@ struct StructMarkings class Enum { public: - TAGGED_UNION(Variant, Unit, - (Unit, struct{}), - (Value, struct { - ::HIR::ExprPtr expr; - Literal val; - }), - (Tuple, t_tuple_fields), - (Struct, t_struct_fields) - ); + struct DataVariant { + ::std::string name; + bool is_struct; // Indicates that the variant does not show up in the value namespace + ::HIR::TypeRef type; + }; enum class Repr { Rust, C, U8, U16, U32, }; + struct ValueVariant { + ::std::string name; + ::HIR::ExprPtr expr; + uint64_t val; + }; + TAGGED_UNION(Class, Data, + (Data, ::std::vector<DataVariant>), + (Value, struct { + Repr repr; + ::std::vector<ValueVariant> variants; + }) + ); GenericParams m_params; - Repr m_repr; - ::std::vector< ::std::pair< ::std::string, Variant > > m_variants; + Class m_data; TraitMarkings m_markings; - const Variant* get_variant(const ::std::string& ) const; + size_t num_variants() const { + return (m_data.is_Data() ? m_data.as_Data().size() : m_data.as_Value().variants.size()); + } + size_t find_variant(const ::std::string& ) const; /// Returns true if this enum is a C-like enum (has values only) bool is_value() const; - /// Returns the value for the given variant + /// Returns the value for the given variant (onlu for value enums) uint32_t get_value(size_t variant) const; }; class Struct diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index cac6b3c9..e200a39e 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -436,7 +436,7 @@ namespace { ), (Variant, m_out.write_count(e.idx); - serialise_vec(e.vals); + serialise(*e.val); ), (Integer, m_out.write_u64(e); @@ -685,7 +685,6 @@ namespace { ), (Struct, serialise_genericpath(e.path); - m_out.write_count(e.variant_idx); serialise_vec(e.vals); ) ) @@ -852,30 +851,35 @@ namespace { void serialise(const ::HIR::Enum& item) { serialise_generics(item.m_params); - m_out.write_tag( static_cast<int>(item.m_repr) ); - - serialise_vec( item.m_variants ); + serialise( item.m_data ); serialise(item.m_markings); } - void serialise(const ::HIR::Enum::Variant& v) + void serialise(const ::HIR::Enum::Class& v) { m_out.write_tag( v.tag() ); TU_MATCHA( (v), (e), - (Unit, - ), (Value, - // NOTE: e.expr skipped as it's not needed anymore - serialise(e.val); - ), - (Tuple, - serialise_vec(e); + m_out.write_tag( static_cast<int>(e.repr) ); + serialise_vec(e.variants); ), - (Struct, + (Data, serialise_vec(e); ) ) } + void serialise(const ::HIR::Enum::ValueVariant& v) + { + m_out.write_string(v.name); + // NOTE: No expr, no longer needed + m_out.write_u64(v.val); + } + void serialise(const ::HIR::Enum::DataVariant& v) + { + m_out.write_string(v.name); + m_out.write_bool(v.is_struct); + serialise(v.type); + } void serialise(const ::HIR::TraitMarkings& m) { diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index ed448cb4..2e03990a 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -213,26 +213,20 @@ void ::HIR::Visitor::visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) void ::HIR::Visitor::visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) { this->visit_params(item.m_params); - for(auto& var : item.m_variants) - { - TU_MATCH(::HIR::Enum::Variant, (var.second), (v), - (Unit, - ), - (Value, - this->visit_expr(v.expr); - ), - (Tuple, - for(auto& ty : v) { - this->visit_type(ty.ent); - } - ), - (Struct, - for(auto& field : v) { - this->visit_type(field.second.ent); - } - ) + TU_MATCHA( (item.m_data), (e), + (Value, + for(auto& var : e.variants) + { + this->visit_expr(var.expr); + } + ), + (Data, + for(auto& var : e) + { + this->visit_type(var.type); + } ) - } + ) } void ::HIR::Visitor::visit_union(::HIR::ItemPath p, ::HIR::Union& item) { diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 2deaac9d..11a6ac1c 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -80,8 +80,8 @@ namespace { ::std::pair< const ::HIR::Enum*, unsigned int> get_enum_ptr(const Span& sp, const ::HIR::Crate& crate, ::HIR::GenericPath& path) { const auto& enm = *reinterpret_cast< const ::HIR::Enum*>( get_type_pointer(sp, crate, path.m_path, Target::EnumVariant) ); const auto& des_name = path.m_path.m_components.back(); - unsigned int idx = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x) { return x.first == des_name; }) - enm.m_variants.begin(); - if( idx == enm.m_variants.size() ) { + auto idx = enm.find_variant(des_name); + if( idx == SIZE_MAX ) { ERROR(sp, E0000, "Couldn't find enum variant " << path); } @@ -119,9 +119,7 @@ namespace { } ), (Variant, - for(auto& val : e.vals) { - visit_literal(sp, val); - } + visit_literal(sp, *e.val); ), (Integer, ), @@ -161,17 +159,16 @@ namespace { } // Enum variant - auto it = ::std::find_if( enm->m_variants.begin(), enm->m_variants.end(), [&](const auto&v){ return v.first == pc; }); - if( it == enm->m_variants.end() ) { + auto idx = enm->find_variant(pc); + if( idx == SIZE_MAX ) { BUG(sp, "'" << pc << "' isn't a variant in path " << path); } - unsigned int index = it - enm->m_variants.begin(); auto path = mv$(pe); fix_type_params(sp, enm->m_params, path.m_params); pat.m_data = ::HIR::Pattern::Data::make_EnumValue({ mv$(path), enm, - index + static_cast<unsigned>(idx) }); } else if( (mod = ti.opt_Module()) ) @@ -263,27 +260,21 @@ namespace { ), (EnumTuple, auto p = get_enum_ptr(sp, m_crate, e.path); - const auto& var = p.first->m_variants[p.second].second; - if( var.is_Tuple() ) { - } - else { + if( !p.first->m_data.is_Data() ) + ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path); + const auto& var = p.first->m_data.as_Data()[p.second]; + if( var.is_struct ) ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path); - } e.binding_ptr = p.first; e.binding_idx = p.second; ), (EnumStruct, auto p = get_enum_ptr(sp, m_crate, e.path); - const auto& var = p.first->m_variants[p.second].second; - if( var.is_Struct() ) { - } - else if( var.is_Unit() && e.sub_patterns.empty() ) { - } - else if( var.is_Tuple() && var.as_Tuple().empty() && e.sub_patterns.empty() ) { - } - else { + if( !p.first->m_data.is_Data() ) + ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path); + const auto& var = p.first->m_data.as_Data()[p.second]; + if( !var.is_struct ) ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path); - } e.binding_ptr = p.first; e.binding_idx = p.second; ) diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 0b54331c..f23d8e65 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -63,11 +63,7 @@ namespace { return ::HIR::Literal( mv$(vals) ); ), (Variant, - ::std::vector< ::HIR::Literal> vals; - for(const auto& val : e.vals) { - vals.push_back( clone_literal(val) ); - } - return ::HIR::Literal::make_Variant({ e.idx, mv$(vals) }); + return ::HIR::Literal::make_Variant({ e.idx, box$(clone_literal(*e.val)) }); ), (Integer, return ::HIR::Literal(e); @@ -595,11 +591,11 @@ namespace { ASSERT_BUG(node.span(), ent.is_Enum(), "_TupleVariant with m_is_struct clear pointing to " << ent.tag_str()); const auto& enm = ent.as_Enum(); - auto it = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == varname; } ); - ASSERT_BUG(node.span(), it != enm.m_variants.end(), "_TupleVariant points to unknown variant - " << node.m_path); - unsigned int var_idx = it - enm.m_variants.begin(); + auto var_idx = enm.find_variant(varname); + ASSERT_BUG(node.span(), var_idx != SIZE_MAX, "_TupleVariant points to unknown variant - " << node.m_path); - m_rv = ::HIR::Literal::make_Variant({var_idx, mv$(vals)}); + auto inner = box$( ::HIR::Literal::make_List(mv$(vals)) ); + m_rv = ::HIR::Literal::make_Variant({ static_cast<unsigned>(var_idx), mv$(inner) }); m_rv_type = ::HIR::TypeRef::new_path( mv$(tmp_path), ::HIR::TypeRef::TypePathBinding(&enm) ); } } @@ -766,11 +762,10 @@ namespace { ASSERT_BUG(node.span(), ent.is_Enum(), "_UnitVariant with m_is_struct clear pointing to " << ent.tag_str()); const auto& enm = ent.as_Enum(); - auto it = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == varname; } ); - ASSERT_BUG(node.span(), it != enm.m_variants.end(), "_UnitVariant points to unknown variant - " << node.m_path); - unsigned int var_idx = it - enm.m_variants.begin(); + auto var_idx = enm.find_variant(varname); + ASSERT_BUG(node.span(), var_idx != SIZE_MAX, "_UnitVariant points to unknown variant - " << node.m_path); - m_rv = ::HIR::Literal::make_Variant({var_idx, {}}); + m_rv = ::HIR::Literal::make_Variant({ static_cast<unsigned>(var_idx), box$(::HIR::Literal::make_List({})) }); m_rv_type = ::HIR::TypeRef::new_path( mv$(tmp_path), ::HIR::TypeRef::TypePathBinding(&enm) ); } } @@ -1604,12 +1599,20 @@ namespace { } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { - for(auto& var : item.m_variants) + if( auto* e = item.m_data.opt_Value() ) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - e.val = evaluate_constant(e.expr->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.first << "$") }, e.expr, {}); - DEBUG("enum variant: " << p << "::" << var.first << " = " << e.val); - ) + uint64_t i = 0; + for(auto& var : e->variants) + { + if( var.expr ) + { + auto val = evaluate_constant(var.expr->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") }, var.expr, {}); + DEBUG("enum variant: " << p << "::" << var.name << " = " << val); + i = val.as_Integer(); + } + var.val = i; + i ++; + } } ::HIR::Visitor::visit_enum(p, item); } diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index dbcd6b13..805eac4e 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -354,19 +354,24 @@ namespace { void visit(::HIR::ExprNode_StructLiteral& node) override { + const auto& sp = node.span(); if( node.m_base_value ) { bool is_moved = false; const auto& tpb = node.m_base_value->m_res_type.m_data.as_Path().binding; - const ::HIR::t_struct_fields* fields_ptr; + const ::HIR::Struct* str; if( tpb.is_Enum() ) { - const auto* var = tpb.as_Enum()->get_variant( node.m_path.m_path.m_components.back() ); - ASSERT_BUG(node.span(), var, ""); - fields_ptr = &var->as_Struct(); + const auto& enm = *tpb.as_Enum(); + auto idx = enm.find_variant(node.m_path.m_path.m_components.back()); + ASSERT_BUG(sp, idx != SIZE_MAX, ""); + const auto& var_ty = enm.m_data.as_Data()[idx].type; + str = var_ty.m_data.as_Path().binding.as_Struct(); } else { - fields_ptr = &tpb.as_Struct()->m_data.as_Named(); + str = tpb.as_Struct(); } - const auto& fields = *fields_ptr; + ASSERT_BUG(sp, str->m_data.is_Named(), ""); + const auto& fields = str->m_data.as_Named(); + ::std::vector<bool> provided_mask( fields.size() ); for( const auto& fld : node.m_values ) { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == fld.first; }) - fields.begin(); @@ -529,8 +534,11 @@ namespace { ), (EnumTuple, const auto& enm = *pe.binding_ptr; - const auto& var = enm.m_variants.at(pe.binding_idx); - const auto& flds = var.second.as_Tuple(); + ASSERT_BUG(sp, enm.m_data.is_Data(), ""); + const auto& var = enm.m_data.as_Data().at(pe.binding_idx); + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Tuple(), ""); + const auto& flds = str.m_data.as_Tuple(); assert(pe.sub_patterns.size() == flds.size()); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); @@ -543,8 +551,11 @@ namespace { ), (EnumStruct, const auto& enm = *pe.binding_ptr; - const auto& var = enm.m_variants.at(pe.binding_idx); - const auto& flds = var.second.as_Struct(); + ASSERT_BUG(sp, enm.m_data.is_Data(), ""); + const auto& var = enm.m_data.as_Data().at(pe.binding_idx); + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Named(), ""); + const auto& flds = str.m_data.as_Named(); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); auto rv = ::HIR::ValueUsage::Borrow; diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index 3b0fb6a4..8a90c037 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -1121,16 +1121,19 @@ namespace { void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { //auto _ = this->m_ms.set_item_generics(item.m_params); - //auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); - for(auto& var : item.m_variants) + /* + if(const auto* e = item.m_data.opt_Value()) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - //DEBUG("Enum value " << p << " - " << var.first); - //::std::vector< ::HIR::TypeRef> tmp; - //ExprVisitor_Extract ev(m_resolve, tmp, m_new_trait_impls); - //ev.visit_root(*e); - ) + auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); + for(auto& var : e->variants) + { + DEBUG("Enum value " << p << " - " << var.name); + ::std::vector< ::HIR::TypeRef> tmp; + ExprVisitor_Extract ev(m_resolve, tmp, m_new_trait_impls); + ev.visit_root(var.expr); + } } + */ } void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override diff --git a/src/hir_expand/const_eval_full.cpp b/src/hir_expand/const_eval_full.cpp index 619bc9a2..749f043a 100644 --- a/src/hir_expand/const_eval_full.cpp +++ b/src/hir_expand/const_eval_full.cpp @@ -66,11 +66,7 @@ namespace { return ::HIR::Literal( mv$(vals) ); ), (Variant, - ::std::vector< ::HIR::Literal> vals; - for(const auto& val : e.vals) { - vals.push_back( clone_literal(val) ); - } - return ::HIR::Literal::make_Variant({ e.idx, mv$(vals) }); + return ::HIR::Literal::make_Variant({ e.idx, box$(clone_literal(*e.val)) }); ), (Integer, return ::HIR::Literal(e); @@ -102,9 +98,7 @@ namespace { } ), (Variant, - for(auto& val : e.vals) { - monomorph_literal_inplace(sp, val, ms); - } + monomorph_literal_inplace(sp, *e.val, ms); ), (Integer, ), @@ -722,17 +716,15 @@ namespace { val = ::HIR::Literal::make_List( mv$(vals) ); ), (Variant, - TODO(sp, "MIR _Variant"); + auto ival = read_param(e.val); + val = ::HIR::Literal::make_Variant({ e.index, box$(ival) }); ), (Struct, ::std::vector< ::HIR::Literal> vals; vals.reserve( e.vals.size() ); for(const auto& v : e.vals) vals.push_back( read_param(v) ); - if( e.variant_idx == ~0u ) - val = ::HIR::Literal::make_List( mv$(vals) ); - else - val = ::HIR::Literal::make_Variant({ e.variant_idx, mv$(vals) }); + val = ::HIR::Literal::make_List( mv$(vals) ); ) ) @@ -932,13 +924,19 @@ namespace { } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { - for(auto& var : item.m_variants) + if(auto* e = item.m_data.opt_Value()) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.first << "$") }; - e.val = evaluate_constant(e.expr->span(), m_resolve, mv$(nvs), FMT_CB(ss, ss << p;), e.expr, {}, {}); - DEBUG("enum variant: " << p << "::" << var.first << " = " << e.val); - ) + for(auto& var : e->variants) + { + if( var.expr ) + { + auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") }; + auto val = evaluate_constant(var.expr->span(), m_resolve, mv$(nvs), FMT_CB(ss, ss << p;), var.expr, {}, {}); + DEBUG("Enum value " << p << " - " << var.name << " = " << val); + // TODO: Save this value? Or just do the above to + // validate? + } + } } ::HIR::Visitor::visit_enum(p, item); } diff --git a/src/hir_expand/reborrow.cpp b/src/hir_expand/reborrow.cpp index d1b08f54..d276f57d 100644 --- a/src/hir_expand/reborrow.cpp +++ b/src/hir_expand/reborrow.cpp @@ -209,14 +209,18 @@ namespace { } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { - for(auto& var : item.m_variants) + if(auto* e = item.m_data.opt_Value()) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - DEBUG("Enum value " << p << " - " << var.first); + for(auto& var : e->variants) + { + DEBUG("Enum value " << p << " - " << var.name); - ExprVisitor_Mutate ev(m_crate); - ev.visit_node_ptr(e.expr); - ) + if( var.expr ) + { + ExprVisitor_Mutate ev(m_crate); + ev.visit_node_ptr(var.expr); + } + } } } }; diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index adae855c..629dd284 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -795,14 +795,18 @@ namespace { } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { - for(auto& var : item.m_variants) + if(auto* e = item.m_data.opt_Value()) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - DEBUG("Enum value " << p << " - " << var.first); + for(auto& var : e->variants) + { + DEBUG("Enum value " << p << " - " << var.name); - ExprVisitor_Mutate ev(m_crate); - ev.visit_node_ptr(e.expr); - ) + if( var.expr ) + { + ExprVisitor_Mutate ev(m_crate); + ev.visit_node_ptr(var.expr); + } + } } } }; diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index d9cbc957..febe8190 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -426,10 +426,11 @@ namespace { (Enum, const auto& var_name = node.m_path.m_path.m_components.back(); const auto& enm = *e; - auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); - assert(it != enm.m_variants.end()); - ASSERT_BUG(sp, it->second.is_Tuple(), "Pointed variant of TupleVariant (" << node.m_path << ") isn't a Tuple"); - fields_ptr = &it->second.as_Tuple(); + size_t idx = enm.find_variant(var_name); + const auto& var_ty = enm.m_data.as_Data()[idx].type; + const auto& str = *var_ty.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Tuple(), "Pointed variant of TupleVariant (" << node.m_path << ") isn't a Tuple"); + fields_ptr = &str.m_data.as_Tuple(); ), (Union, BUG(sp, "Union in TupleVariant"); @@ -480,9 +481,14 @@ namespace { (Enum, const auto& var_name = node.m_path.m_path.m_components.back(); const auto& enm = *e; - auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); - assert(it != enm.m_variants.end()); - fields_ptr = &it->second.as_Struct(); + auto idx = enm.find_variant(var_name); + ASSERT_BUG(sp, idx != SIZE_MAX, ""); + ASSERT_BUG(sp, enm.m_data.is_Data(), ""); + const auto& var = enm.m_data.as_Data()[idx]; + + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, var.is_struct, "Struct literal for enum on non-struct variant"); + fields_ptr = &str.m_data.as_Named(); ), (Union, TODO(sp, "Union in StructLiteral"); @@ -566,9 +572,12 @@ namespace { (Enum, const auto& var_name = node.m_path.m_path.m_components.back(); const auto& enm = *e; - auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); - assert(it != enm.m_variants.end()); - assert( it->second.is_Unit() || it->second.is_Value() ); + if(const auto* e = enm.m_data.opt_Data()) + { + auto idx = enm.find_variant(var_name); + ASSERT_BUG(sp, idx != SIZE_MAX, ""); + ASSERT_BUG(sp, (*e)[idx].type == ::HIR::TypeRef::new_unit(), ""); + } ), (Union, BUG(sp, "Union with _UnitVariant"); @@ -1133,18 +1142,22 @@ namespace { } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { //auto _ = this->m_ms.set_item_generics(item.m_params); - // TODO: Use a different type depding on repr() - auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); - for(auto& var : item.m_variants) + if( auto* e = item.m_data.opt_Value() ) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - DEBUG("Enum value " << p << " - " << var.first); + // TODO: Use a different type depding on repr() + auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); + for(auto& var : e->variants) + { + DEBUG("Enum value " << p << " - " << var.name); - t_args tmp; - ExprVisitor_Validate ev(m_resolve, tmp, enum_type); - ev.visit_root(e.expr); - ) + if( var.expr ) + { + t_args tmp; + ExprVisitor_Validate ev(m_resolve, tmp, enum_type); + ev.visit_root(var.expr); + } + } } } diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index c6f060f5..47b83356 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1088,10 +1088,11 @@ namespace { (Enum, const auto& var_name = node.m_path.m_path.m_components.back(); const auto& enm = *e; - auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); - assert(it != enm.m_variants.end()); - ASSERT_BUG(sp, it->second.is_Tuple(), "Pointed variant of TupleVariant (" << node.m_path << ") isn't a Tuple"); - fields_ptr = &it->second.as_Tuple(); + size_t idx = enm.find_variant(var_name); + const auto& var_ty = enm.m_data.as_Data()[idx].type; + const auto& str = *var_ty.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Tuple(), "Pointed variant of TupleVariant (" << node.m_path << ") isn't a Tuple"); + fields_ptr = &str.m_data.as_Tuple(); ), (Struct, ASSERT_BUG(sp, e->m_data.is_Tuple(), "Pointed struct in TupleVariant (" << node.m_path << ") isn't a Tuple"); @@ -1146,6 +1147,7 @@ namespace { } void visit(::HIR::ExprNode_StructLiteral& node) override { + const auto& sp = node.span(); TRACE_FUNCTION_F(&node << " " << node.m_path << "{...} [" << (node.m_is_struct ? "struct" : "enum") << "]"); this->add_ivars_generic_path(node.span(), node.m_path); for( auto& val : node.m_values ) { @@ -1170,15 +1172,22 @@ namespace { (Enum, const auto& var_name = node.m_path.m_path.m_components.back(); const auto& enm = *e; - auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); - assert(it != enm.m_variants.end()); - if( it->second.is_Unit() || it->second.is_Value() || it->second.is_Tuple() ) { + auto idx = enm.find_variant(var_name); + ASSERT_BUG(sp, idx != SIZE_MAX, ""); + ASSERT_BUG(sp, enm.m_data.is_Data(), ""); + const auto& var = enm.m_data.as_Data()[idx]; + if( var.type == ::HIR::TypeRef::new_unit() ) { ASSERT_BUG(node.span(), node.m_values.size() == 0, "Values provided for unit-like variant"); ASSERT_BUG(node.span(), ! node.m_base_value, "Values provided for unit-like variant"); return ; } - ASSERT_BUG(node.span(), it->second.is_Struct(), "_StructLiteral for non-struct variant - " << node.m_path); - fields_ptr = &it->second.as_Struct(); + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + /* + if( it->second.is_Unit() || it->second.is_Value() || it->second.is_Tuple() ) { + } + */ + ASSERT_BUG(sp, var.is_struct, "Struct literal for enum on non-struct variant"); + fields_ptr = &str.m_data.as_Named(); generics = &enm.m_params; ), (Union, @@ -1612,8 +1621,12 @@ namespace { enum_path.m_components.pop_back(); const auto& enm = this->context.m_crate.get_enum_by_path(sp, enum_path); fix_param_count(sp, this->context, ::HIR::TypeRef(), false, e, enm.m_params, e.m_params); - const auto& var = *::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == var_name; }); - const auto& var_data = var.second.as_Tuple(); + size_t idx = enm.find_variant(var_name); + ASSERT_BUG(sp, idx != SIZE_MAX, "Missing variant - " << e.m_path); + ASSERT_BUG(sp, enm.m_data.is_Data(), "Enum " << enum_path << " isn't a data-holding enum"); + const auto& var_ty = enm.m_data.as_Data()[idx].type; + const auto& str = *var_ty.m_data.as_Path().binding.as_Struct(); + const auto& var_data = str.m_data.as_Tuple(); ::HIR::FunctionType ft { false, @@ -3879,8 +3892,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type assert(e.binding_ptr); const auto& enm = *e.binding_ptr; - const auto& var = enm.m_variants[e.binding_idx].second; - assert(var.is_Value() || var.is_Unit()); + if( enm.m_data.is_Data() ) + { + //const auto& var = enm.m_data.as_Data()[e.binding_idx]; + //assert(var.is_Value() || var.is_Unit()); + } ), (EnumTuple, this->add_ivars_params( e.path.m_params ); @@ -3892,9 +3908,8 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type } assert(e.binding_ptr); const auto& enm = *e.binding_ptr; - const auto& var = enm.m_variants[e.binding_idx].second; - assert(var.is_Tuple()); - const auto& tup_var = var.as_Tuple(); + const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct(); + const auto& tup_var = str.m_data.as_Tuple(); const auto& params = e.path.m_params; @@ -3927,9 +3942,8 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type assert(e.binding_ptr); const auto& enm = *e.binding_ptr; - const auto& var = enm.m_variants[e.binding_idx].second; - assert(var.is_Struct()); - const auto& tup_var = var.as_Struct(); + const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct(); + const auto& tup_var = str.m_data.as_Named(); const auto& params = e.path.m_params; for( auto& field_pat : e.sub_patterns ) diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp index 95e0c29c..b82e8f23 100644 --- a/src/hir_typeck/expr_visit.cpp +++ b/src/hir_typeck/expr_visit.cpp @@ -125,17 +125,20 @@ namespace { void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { auto _ = this->m_ms.set_item_generics(item.m_params); - // TODO: Use a different type depding on repr() - auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); - - // TODO: Check types too? - for(auto& var : item.m_variants) + if( auto* e = item.m_data.opt_Value() ) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - DEBUG("Enum value " << p << " - " << var.first); - t_args tmp; - Typecheck_Code(m_ms, tmp, enum_type, e.expr); - ) + // TODO: Use a different type depding on repr() + auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); + + for(auto& var : e->variants) + { + DEBUG("Enum value " << p << " - " << var.name); + if( var.expr ) + { + t_args tmp; + Typecheck_Code(m_ms, tmp, enum_type, var.expr); + } + } } } }; diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index d340514b..9f72483b 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2599,37 +2599,16 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ) ), (Enum, - const auto& enm = *tpb; - - for(const auto& var : enm.m_variants) + if( const auto* e = tpb->m_data.opt_Data() ) { - TU_MATCH(::HIR::Enum::Variant, (var.second), (ve), - (Unit, - ), - (Value, - ), - (Tuple, - for(const auto& fld : ve) - { - const auto& fld_ty_mono = monomorph_get(fld.ent); - DEBUG("Enum '" << var.first << "'::Tuple " << fld_ty_mono); - res &= type_impls_trait(fld_ty_mono); - if( res == ::HIR::Compare::Unequal ) - return ::HIR::Compare::Unequal; - } - ), - (Struct, - for(const auto& fld : ve) - { - const auto& fld_ty_mono = monomorph_get(fld.second.ent); - DEBUG("Enum '" << var.first << "'::Struct '" << fld.first << "' " << fld_ty_mono); - - res &= type_impls_trait(fld_ty_mono); - if( res == ::HIR::Compare::Unequal ) - return ::HIR::Compare::Unequal; - } - ) - ) + for(const auto& var : *e) + { + const auto& fld_ty_mono = monomorph_get(var.type); + DEBUG("Enum '" << var.name << "'" << fld_ty_mono); + res &= type_impls_trait(fld_ty_mono); + if( res == ::HIR::Compare::Unequal ) + return ::HIR::Compare::Unequal; + } } ), (Union, diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 8d6ff052..3629c6e4 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -785,37 +785,16 @@ bool StaticTraitResolve::find_impl__check_crate( ) ), (Enum, - const auto& enm = *tpb; - - for(const auto& var : enm.m_variants) + if( const auto* e = tpb->m_data.opt_Data() ) { - TU_MATCH(::HIR::Enum::Variant, (var.second), (ve), - (Unit, - ), - (Value, - ), - (Tuple, - for(const auto& fld : ve) - { - const auto& fld_ty_mono = monomorph_get(fld.ent); - DEBUG("Enum '" << var.first << "'::Tuple " << fld_ty_mono); - res &= type_impls_trait(fld_ty_mono); - if( res == ::HIR::Compare::Unequal ) - return ::HIR::Compare::Unequal; - } - ), - (Struct, - for(const auto& fld : ve) - { - const auto& fld_ty_mono = monomorph_get(fld.second.ent); - DEBUG("Enum '" << var.first << "'::Struct '" << fld.first << "' " << fld_ty_mono); - - res &= type_impls_trait(fld_ty_mono); - if( res == ::HIR::Compare::Unequal ) - return ::HIR::Compare::Unequal; - } - ) - ) + for(const auto& var : *e ) + { + const auto& fld_ty_mono = monomorph_get(var.type); + DEBUG("Enum '" << var.name << "' " << fld_ty_mono); + res &= type_impls_trait(fld_ty_mono); + if( res == ::HIR::Compare::Unequal ) + return ::HIR::Compare::Unequal; + } } ), (Union, @@ -1804,28 +1783,13 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR return false; ), (Enum, - for(const auto& e : pbe->m_variants) + if(const auto* e = pbe->m_data.opt_Data()) { - TU_MATCHA( (e.second), (ve), - (Unit, - ), - (Value, - ), - (Tuple, - for(const auto& e : ve) - { - if( type_needs_drop_glue(sp, monomorph(e.ent)) ) - return true; - } - ), - (Struct, - for(const auto& e : ve) - { - if( type_needs_drop_glue(sp, monomorph(e.second.ent)) ) - return true; - } - ) - ) + for(const auto& var : *e) + { + if( type_needs_drop_glue(sp, monomorph(var.type)) ) + return true; + } } return false; ), diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 9718f046..455eef43 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -289,7 +289,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR } ) ) - return ::MIR::RValue::make_Struct({ te.path.m_data.as_Generic().clone(), ~0u, mv$(lvals) }); + return ::MIR::RValue::make_Struct({ te.path.m_data.as_Generic().clone(), mv$(lvals) }); } else if( te.binding.is_Enum() ) { @@ -298,33 +298,19 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR auto monomorph = [&](const auto& tpl) { return monomorphise_type(state.sp, enm.m_params, te.path.m_data.as_Generic().m_params, tpl); }; - ::std::vector< ::MIR::Param> lvals; - MIR_ASSERT(state, lit_var.idx < enm.m_variants.size(), "Variant index out of range"); - TU_MATCHA( (enm.m_variants[lit_var.idx].second), (ve), - (Unit, - ), - (Value, - ), - (Tuple, - MIR_ASSERT(state, lit_var.vals.size() == ve.size(), "Value count mismatch in literal for " << ty << " #" << lit_var.idx << " - exp " << ve.size() << ", " << lit); - for(unsigned int i = 0; i < ve.size(); i ++) - { - auto ent_ty = monomorph(ve[i].ent); - auto rval = MIR_Cleanup_LiteralToRValue(state, mutator, lit_var.vals[i], ent_ty.clone(), ::HIR::GenericPath()); - lvals.push_back( mutator.in_temporary(mv$(ent_ty), mv$(rval)) ); - } - ), - (Struct, - MIR_ASSERT(state, lit_var.vals.size() == ve.size(), "Value count mismatch in literal for " << ty << " #" << lit_var.idx << " - exp " << ve.size() << ", " << lit); - for(unsigned int i = 0; i < ve.size(); i ++) - { - auto ent_ty = monomorph(ve[i].second.ent); - auto rval = MIR_Cleanup_LiteralToRValue(state, mutator, lit_var.vals[i], ent_ty.clone(), ::HIR::GenericPath()); - lvals.push_back( mutator.in_temporary(mv$(ent_ty), mv$(rval)) ); - } - ) - ) - return ::MIR::RValue::make_Struct({ te.path.m_data.as_Generic().clone(), lit_var.idx, mv$(lvals) }); + MIR_ASSERT(state, lit_var.idx < enm.num_variants(), "Variant index out of range"); + ::MIR::Param p; + if( const auto* e = enm.m_data.opt_Data() ) + { + auto ty = monomorph( e->at(lit_var.idx).type ); + auto rval = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_var.val, ty.clone(), ::HIR::GenericPath()); + p = mutator.in_temporary(mv$(ty), mv$(rval)); + } + else + { + p = mutator.in_temporary(::HIR::TypeRef::new_unit(), ::MIR::RValue::make_Tuple({})); + } + return ::MIR::RValue::make_Variant({ te.path.m_data.as_Generic().clone(), lit_var.idx, mv$(p) }); } else { @@ -540,7 +526,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR ) auto new_path = ty_path.clone(); - return mutator.in_temporary( mv$(ty), ::MIR::RValue::make_Struct({ mv$(new_path), ~0u, mv$(vals) }) ); + return mutator.in_temporary( mv$(ty), ::MIR::RValue::make_Struct({ mv$(new_path), mv$(vals) }) ); } else if( ty.m_data.is_Pointer() ) { @@ -820,7 +806,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } ) ) - return ::MIR::RValue::make_Struct({ dte.path.m_data.as_Generic().clone(), ~0u, mv$(ents) }); + return ::MIR::RValue::make_Struct({ dte.path.m_data.as_Generic().clone(), mv$(ents) }); } if( dst_ty.m_data.is_Borrow() ) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 2a02b166..06a70d49 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -261,14 +261,14 @@ namespace { ), (EnumValue, const auto& enm = *e.binding_ptr; - if( enm.m_variants.size() > 1 ) + if( enm.num_variants() > 1 ) { ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat); } ), (EnumTuple, const auto& enm = *e.binding_ptr; - ASSERT_BUG(sp, enm.m_variants.size() == 1 || allow_refutable, "Refutable pattern not expected - " << pat); + ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat); auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { @@ -277,8 +277,11 @@ namespace { ), (EnumStruct, const auto& enm = *e.binding_ptr; - ASSERT_BUG(sp, enm.m_variants.size() == 1 || allow_refutable, "Refutable pattern not expected - " << pat); - const auto& fields = enm.m_variants[e.binding_idx].second.as_Struct(); + ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat); + ASSERT_BUG(sp, enm.m_data.is_Data(), "Expected struct variant - " << pat); + const auto& var = enm.m_data.as_Data()[e.binding_idx];; + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + const auto& fields = str.m_data.as_Named(); auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); for(const auto& fld_pat : e.sub_patterns) { @@ -1691,25 +1694,47 @@ namespace { values.push_back( m_builder.get_result_in_param(arg->span(), arg->m_res_type) ); } - unsigned int variant_index = ~0u; - if( !node.m_is_struct ) + if( node.m_is_struct ) + { + m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + mv$(values) + }) ); + } + else { // Get the variant index from the enum. auto enum_path = node.m_path.m_path; enum_path.m_components.pop_back(); const auto& var_name = node.m_path.m_path.m_components.back(); const auto& enm = m_builder.crate().get_enum_by_path(sp, enum_path); - auto var_it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); - ASSERT_BUG(sp, var_it != enm.m_variants.end(), "Variant " << node.m_path.m_path << " isn't present"); - variant_index = var_it - enm.m_variants.begin(); - } + size_t idx = enm.find_variant(var_name); + ASSERT_BUG(sp, idx != SIZE_MAX, "Variant " << node.m_path.m_path << " isn't present"); - m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ - node.m_path.clone(), - variant_index, - mv$(values) - }) ); + // TODO: Validation? + ASSERT_BUG(sp, enm.m_data.is_Data(), "TupleVariant on non-data enum - " << node.m_path.m_path); + const auto& var_ty = enm.m_data.as_Data()[idx].type; + + // Take advantage of the identical generics to cheaply clone/monomorph the path. + const auto& str = *var_ty.m_data.as_Path().binding.as_Struct(); + ::HIR::GenericPath struct_path = node.m_path.clone(); + struct_path.m_path = var_ty.m_data.as_Path().path.m_data.as_Generic().m_path; + + // Create struct instance + m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ + struct_path.clone(), + mv$(values) + }) ); + + auto ty = ::HIR::TypeRef::new_path( mv$(struct_path), &str ); + auto v = m_builder.get_result_in_param(node.span(), ty); + m_builder.set_result(node.span(), ::MIR::RValue::make_Variant({ + mv$(enum_path), + static_cast<unsigned>(idx), + mv$(v) + }) ); + } } ::std::vector< ::MIR::Param> get_args(/*const*/ ::std::vector<::HIR::ExprNodeP>& args) @@ -1949,24 +1974,40 @@ namespace { { const Span& sp = node.span(); TRACE_FUNCTION_F("_UnitVariant"); - unsigned int variant_index = ~0u; if( !node.m_is_struct ) { // Get the variant index from the enum. auto enum_path = node.m_path.m_path; enum_path.m_components.pop_back(); const auto& var_name = node.m_path.m_path.m_components.back(); + const auto& enm = m_builder.crate().get_enum_by_path(sp, enum_path); - auto var_it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); - ASSERT_BUG(sp, var_it != enm.m_variants.end(), "Variant " << node.m_path.m_path << " isn't present"); - variant_index = var_it - enm.m_variants.begin(); + auto idx = enm.find_variant(var_name); + ASSERT_BUG(sp, idx != SIZE_MAX, "Variant " << node.m_path.m_path << " isn't present"); + + // VALIDATION + if( const auto* e = enm.m_data.opt_Data() ) + { + const auto& var = (*e)[idx]; + ASSERT_BUG(sp, !var.is_struct, "Variant " << node.m_path.m_path << " isn't a unit variant"); + } + + m_builder.set_result( node.span(), ::MIR::RValue::make_Tuple({}) ); + auto v = m_builder.get_result_in_param(node.span(), ::HIR::TypeRef::new_unit()); + m_builder.set_result( node.span(), ::MIR::RValue::make_Variant({ + mv$(enum_path), + static_cast<unsigned>(idx), + mv$(v) + }) ); + } + else + { + m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + {} + }) ); } - m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ - node.m_path.clone(), - variant_index, - {} - }) ); } void visit(::HIR::ExprNode_PathValue& node) override { @@ -1974,18 +2015,23 @@ namespace { TRACE_FUNCTION_F("_PathValue - " << node.m_path); TU_MATCH( ::HIR::Path::Data, (node.m_path.m_data), (pe), (Generic, + // Enum variant constructor. if( node.m_target == ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR ) { auto enum_path = pe.m_path; enum_path.m_components.pop_back(); const auto& var_name = pe.m_path.m_components.back(); + // Validation only. const auto& enm = m_builder.crate().get_enum_by_path(sp, enum_path); - auto var_it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); - ASSERT_BUG(sp, var_it != enm.m_variants.end(), "Variant " << pe.m_path << " isn't present"); - const auto& var = var_it->second; - ASSERT_BUG(sp, var.is_Tuple(), "Variant " << pe.m_path << " isn't a tuple variant"); - - // TODO: Ideally, the creation of the wrapper function would happen somewhere before this? + ASSERT_BUG(sp, enm.m_data.is_Data(), "Getting variant constructor of value varianta"); + size_t idx = enm.find_variant(var_name); + ASSERT_BUG(sp, idx != SIZE_MAX, "Variant " << pe.m_path << " isn't present"); + const auto& var = enm.m_data.as_Data()[idx]; + ASSERT_BUG(sp, var.type.m_data.is_Path(), "Variant " << pe.m_path << " isn't a tuple"); + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Tuple(), "Variant " << pe.m_path << " isn't a tuple"); + + // TODO: Ideally, the creation of the wrapper function would happen somewhere before trans? auto tmp = m_builder.new_temporary( node.m_res_type ); m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); m_builder.set_result( sp, mv$(tmp) ); @@ -2008,7 +2054,6 @@ namespace { // TODO: Why is this still a PathValue? m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ pe.clone(), - ~0u, {} }) ); ), @@ -2115,9 +2160,13 @@ namespace { m_builder.set_result( node.span(), m_builder.get_variable(node.span(), node.m_slot) ); } - void visit(::HIR::ExprNode_StructLiteral& node) override + void visit_sl_inner(::HIR::ExprNode_StructLiteral& node, const ::HIR::Struct& str, const ::HIR::GenericPath& path) { - TRACE_FUNCTION_F("_StructLiteral"); + const Span& sp = node.span(); + + ASSERT_BUG(sp, str.m_data.is_Named(), ""); + const ::HIR::t_struct_fields& fields = str.m_data.as_Named(); + ::MIR::LValue base_val; if( node.m_base_value ) { @@ -2126,37 +2175,6 @@ namespace { base_val = m_builder.get_result_in_lvalue(node.m_base_value->span(), node.m_base_value->m_res_type); } - unsigned int variant_index = ~0u; - const ::HIR::t_struct_fields* fields_ptr = nullptr; - TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e), - (Unbound, ), - (Opaque, ), - (Enum, - const auto& var_name = node.m_path.m_path.m_components.back(); - const auto& enm = *e; - auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); - assert(it != enm.m_variants.end()); - variant_index = it - enm.m_variants.begin(); - fields_ptr = &it->second.as_Struct(); - ), - (Union, - BUG(node.span(), "_StructLiteral Union"); - ), - (Struct, - if(e->m_data.is_Unit()) { - m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ - node.m_path.clone(), - variant_index, - {} - }) ); - return ; - } - fields_ptr = &e->m_data.as_Named(); - ) - ) - assert(fields_ptr); - const ::HIR::t_struct_fields& fields = *fields_ptr; - ::std::vector<bool> values_set; ::std::vector< ::MIR::Param> values; values.resize( fields.size() ); @@ -2198,11 +2216,63 @@ namespace { } m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ - node.m_path.clone(), - variant_index, + path.clone(), mv$(values) }) ); } + + void visit(::HIR::ExprNode_StructLiteral& node) override + { + TRACE_FUNCTION_F("_StructLiteral"); + + TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e), + (Unbound, ), + (Opaque, ), + (Enum, + auto enum_path = node.m_path.m_path; + enum_path.m_components.pop_back(); + const auto& var_name = node.m_path.m_path.m_components.back(); + + const auto& enm = *e; + size_t idx = enm.find_variant(var_name); + ASSERT_BUG(node.span(), idx != SIZE_MAX, ""); + ASSERT_BUG(node.span(), enm.m_data.is_Data(), ""); + const auto& var_ty = enm.m_data.as_Data()[idx].type; + const auto& str = *var_ty.m_data.as_Path().binding.as_Struct(); + + // Take advantage of the identical generics to cheaply clone/monomorph the path. + ::HIR::GenericPath struct_path = node.m_path.clone(); + struct_path.m_path = var_ty.m_data.as_Path().path.m_data.as_Generic().m_path; + + this->visit_sl_inner(node, str, struct_path); + + // Create type of result from the above path + auto ty = ::HIR::TypeRef::new_path( mv$(struct_path), &str ); + // Obtain in a param + auto v = m_builder.get_result_in_param(node.span(), ty); + // And create Variant + m_builder.set_result( node.span(), ::MIR::RValue::make_Variant({ + mv$(enum_path), + static_cast<unsigned>(idx), + mv$(v) + }) ); + ), + (Union, + BUG(node.span(), "_StructLiteral Union isn't valid?"); + ), + (Struct, + if(e->m_data.is_Unit()) { + m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + {} + }) ); + return ; + } + + this->visit_sl_inner(node, *e, node.m_path); + ) + ) + } void visit(::HIR::ExprNode_UnionLiteral& node) override { TRACE_FUNCTION_F("_UnionLiteral " << node.m_path); @@ -2281,7 +2351,6 @@ namespace { m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ node.m_obj_path.clone(), - ~0u, mv$(vals) }) ); } diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 55d7377e..61548fd2 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -806,57 +806,24 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal (Enum, ASSERT_BUG(sp, lit.is_Variant(), "Matching enum non-variant literal - " << lit); auto var_idx = lit.as_Variant().idx; - const auto& list = lit.as_Variant().vals; + const auto& subval = *lit.as_Variant().val; 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); return rv; }; - ASSERT_BUG(sp, var_idx < pbe->m_variants.size(), "Literal refers to a variant out of range"); - const auto& var_def = pbe->m_variants.at(var_idx); - + ASSERT_BUG(sp, var_idx < pbe->num_variants(), "Literal refers to a variant out of range"); PatternRulesetBuilder sub_builder { this->m_resolve }; - sub_builder.m_field_path = m_field_path; - sub_builder.m_field_path.push_back(var_idx); - sub_builder.m_field_path.push_back(0); - - TU_MATCH( ::HIR::Enum::Variant, (var_def.second), (fields_def), - (Unit, - ), - (Value, - ), - (Tuple, - ASSERT_BUG(sp, fields_def.size() == list.size(), ""); - - for( unsigned int i = 0; i < list.size(); i ++ ) - { - sub_builder.m_field_path.back() = i; - const auto& val = list[i]; - const auto& ty_tpl = fields_def[i].ent; - - ::HIR::TypeRef tmp; - const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); - - sub_builder.append_from_lit( sp, val, subty ); - } - ), - (Struct, - ASSERT_BUG(sp, fields_def.size() == list.size(), ""); - - for( unsigned int i = 0; i < list.size(); i ++ ) - { - sub_builder.m_field_path.back() = i; - const auto& val = list[i]; - const auto& ty_tpl = fields_def[i].second.ent; + if( const auto* e = pbe->m_data.opt_Data() ) + { + const auto& var_def = e->at(var_idx); - ::HIR::TypeRef tmp; - const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); + sub_builder.m_field_path = m_field_path; + sub_builder.m_field_path.push_back(var_idx); - sub_builder.append_from_lit( sp, val, subty ); - } - ) - ) + sub_builder.append_from_lit(sp, subval, monomorph(var_def.type)); + } this->push_rule( PatternRule::make_Variant({ var_idx, mv$(sub_builder.m_rules) }) ); ) @@ -1253,9 +1220,12 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa this->push_rule( PatternRule::make_Variant( {pe.binding_idx, {} } ) ); ), (EnumTuple, - const auto& var_def = pe.binding_ptr->m_variants.at(pe.binding_idx); + const auto& variants = pe.binding_ptr->m_data.as_Data(); + const auto& var_def = variants.at(pe.binding_idx); + const auto& str = *var_def.type.m_data.as_Path().binding.as_Struct(); + const auto& fields_def = str.m_data.as_Tuple(); - const auto& fields_def = var_def.second.as_Tuple(); + // TODO: Unify with the struct pattern code? PatternRulesetBuilder sub_builder { this->m_resolve }; sub_builder.m_field_path = m_field_path; sub_builder.m_field_path.push_back(pe.binding_idx); @@ -1276,8 +1246,11 @@ 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) }) ); ), (EnumStruct, - const auto& var_def = pe.binding_ptr->m_variants.at(pe.binding_idx); - const auto& fields_def = var_def.second.as_Struct(); + const auto& variants = pe.binding_ptr->m_data.as_Data(); + const auto& var_def = variants.at(pe.binding_idx); + const auto& str = *var_def.type.m_data.as_Path().binding.as_Struct(); + const auto& fields_def = str.m_data.as_Named(); + // 1. Create a vector of pattern indexes for each field in the variant. ::std::vector<unsigned int> tmp; tmp.resize( fields_def.size(), ~0u ); @@ -1807,32 +1780,13 @@ namespace { return &ty; } }; - ASSERT_BUG(sp, idx < pbe->m_variants.size(), "Variant index (" << idx << ") out of range (" << pbe->m_variants.size() << ") for enum " << *cur_ty); - const auto& var = pbe->m_variants[idx]; - - i++; - assert(i < field_path.data.size()); - unsigned fld_idx = field_path.data[i]; + ASSERT_BUG(sp, pbe->m_data.is_Data(), "Value enum being destructured - " << *cur_ty); + const auto& variants = pbe->m_data.as_Data(); + ASSERT_BUG(sp, idx < variants.size(), "Variant index (" << idx << ") out of range (" << variants.size() << ") for enum " << *cur_ty); + const auto& var = variants[idx]; - TU_MATCHA( (var.second), (e), - (Unit, - BUG(sp, "Unit variant being destructured"); - ), - (Value, - BUG(sp, "Value variant being destructured"); - ), - (Tuple, - ASSERT_BUG(sp, fld_idx < e.size(), "Variant field index (" << fld_idx << ") out of range (" << e.size() << ") for enum " << *cur_ty << "::" << var.first); - cur_ty = monomorph_to_ptr(e[fld_idx].ent); - ), - (Struct, - ASSERT_BUG(sp, fld_idx < e.size(), "Variant field index (" << fld_idx << ") out of range (" << e.size() << ") for enum " << *cur_ty << "::" << var.first); - cur_ty = monomorph_to_ptr(e[fld_idx].second.ent); - ) - ) - DEBUG("*cur_ty = " << *cur_ty); + cur_ty = monomorph_to_ptr(var.type); lval = ::MIR::LValue::make_Downcast({ box$(lval), idx }); - lval = ::MIR::LValue::make_Field({ box$(lval), fld_idx }); ) ) ), @@ -2206,7 +2160,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& unsigned int var_idx = re.idx; auto next_bb = builder.new_bb_unlinked(); - auto var_count = pbe->m_variants.size(); + auto var_count = pbe->num_variants(); // Generate a switch with only one option different. ::std::vector< ::MIR::BasicBlockId> arms(var_count, fail_bb); @@ -2217,49 +2171,18 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& if( re.sub_rules.size() > 0 ) { - const auto& var_data = pbe->m_variants.at(re.idx).second; - TU_MATCHA( (var_data), (ve), - (Unit, - // Nothing to recurse - ), - (Value, - // Nothing to recurse - ), - (Tuple, - // Create a dummy tuple to contain the inner types. - ::std::vector< ::HIR::TypeRef> fake_ty_ents; - fake_ty_ents.reserve( ve.size() ); - for(unsigned int i = 0; i < ve.size(); i ++) - { - fake_ty_ents.push_back( monomorph(ve[i].ent) ); - } - ::HIR::TypeRef fake_tup = ::HIR::TypeRef( mv$(fake_ty_ents) ); - - // Recurse with the new ruleset - MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, - re.sub_rules.data(), re.sub_rules.size(), - fake_tup, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1, - fail_bb - ); - ), - (Struct, - // Create a dummy tuple to contain the inner types. - ::std::vector< ::HIR::TypeRef> fake_ty_ents; - fake_ty_ents.reserve( ve.size() ); - for(unsigned int i = 0; i < ve.size(); i ++) - { - fake_ty_ents.push_back( monomorph(ve[i].second.ent) ); - } - ::HIR::TypeRef fake_tup = ::HIR::TypeRef( mv$(fake_ty_ents) ); - - // Recurse with the new ruleset - MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, - re.sub_rules.data(), re.sub_rules.size(), - fake_tup, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1, - fail_bb - ); - ) - ) + ASSERT_BUG(sp, pbe->m_data.is_Data(), "Sub-rules present for non-data enum"); + const auto& variants = pbe->m_data.as_Data(); + const auto& var_ty = variants.at(re.idx).type; + ::HIR::TypeRef tmp; + const auto& var_ty_m = (monomorphise_type_needed(var_ty) ? tmp = monomorph(var_ty) : var_ty); + + // 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, + fail_bb + ); } ) // TypePathBinding::Enum ) @@ -3098,7 +3021,7 @@ void MatchGenGrouped::gen_dispatch__enum(::HIR::TypeRef ty, ::MIR::LValue val, c auto decison_arm = m_builder.pause_cur_block(); - auto var_count = pbe->m_variants.size(); + auto var_count = pbe->num_variants(); ::std::vector< ::MIR::BasicBlockId> arms(var_count, def_blk); size_t arm_idx = 0; for(size_t i = 0; i < rules.size(); i ++) diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index ddab9317..1e43e361 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -200,34 +200,20 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c if( te.binding.is_Enum() ) { const auto& enm = *te.binding.as_Enum(); - const auto& variants = enm.m_variants; - MIR_ASSERT(*this, e.variant_index < variants.size(), "Variant index out of range"); + 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]; - // TODO: Make data variants refer to associated types (unify enum and struct handling) - TU_MATCHA( (variant.second), (ve), - (Value, - ), - (Unit, - ), - (Tuple, - // HACK! Create tuple. - ::std::vector< ::HIR::TypeRef> tys; - for(const auto& fld : ve) - tys.push_back( monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, fld.ent) ); - tmp = ::HIR::TypeRef( mv$(tys) ); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - ), - (Struct, - // HACK! Create tuple. - ::std::vector< ::HIR::TypeRef> tys; - for(const auto& fld : ve) - tys.push_back( monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, fld.second.ent) ); - tmp = ::HIR::TypeRef( mv$(tys) ); + + const auto& var_ty = variant.type; + if( monomorphise_type_needed(var_ty) ) { + tmp = monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, var_ty); m_resolve.expand_associated_types(sp, tmp); return tmp; - ) - ) + } + else { + return var_ty; + } } else { diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 6af64001..18557304 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -384,8 +384,6 @@ namespace MIR { (Struct, if( are.path != bre.path ) return false; - if( are.variant_idx != bre.variant_idx ) - return false; return are.vals == bre.vals; ) ) @@ -610,13 +608,13 @@ namespace MIR { (Variant, return ::MIR::RValue::make_Variant({ e.path.clone(), e.index, e.val.clone() }); ), - // Create a new instance of a struct (or enum) + // Create a new instance of a struct (Struct, decltype(e.vals) ret; ret.reserve(e.vals.size()); for(const auto& v : e.vals) ret.push_back( v.clone() ); - return ::MIR::RValue::make_Struct({ e.path.clone(), e.variant_idx, mv$(ret) }); + return ::MIR::RValue::make_Struct({ e.path.clone(), mv$(ret) }); ) ) throw ""; diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 987e0498..3ce115b8 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -187,10 +187,9 @@ TAGGED_UNION_EX(RValue, (), Use, ( unsigned int index; Param val; }), - // Create a new instance of a struct (or enum) + // Create a new instance of a struct (Struct, struct { ::HIR::GenericPath path; - unsigned int variant_idx; // if ~0, it's a struct ::std::vector<Param> vals; }) ), (),(), ( diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 1e72282a..5776ebcf 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -1722,41 +1722,22 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: BUG(sp, "Downcast on unexpected type - " << ty); ), (Path, - // TODO: Union? if( const auto* pbe = te.binding.opt_Enum() ) { const auto& enm = **pbe; - const auto& variants = enm.m_variants; + 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]; - // TODO: Make data variants refer to associated types (unify enum and struct handling) - TU_MATCHA( (variant.second), (ve), - (Value, - DEBUG(""); - cb(::HIR::TypeRef::new_unit()); - ), - (Unit, - cb(::HIR::TypeRef::new_unit()); - ), - (Tuple, - // HACK! Create tuple. - ::std::vector< ::HIR::TypeRef> tys; - for(const auto& fld : ve) - tys.push_back( monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, fld.ent) ); - ::HIR::TypeRef tup( mv$(tys) ); - m_resolve.expand_associated_types(sp, tup); - cb(tup); - ), - (Struct, - // HACK! Create tuple. - ::std::vector< ::HIR::TypeRef> tys; - for(const auto& fld : ve) - tys.push_back( monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, fld.second.ent) ); - ::HIR::TypeRef tup( mv$(tys) ); - m_resolve.expand_associated_types(sp, tup); - cb(tup); - ) - ) + + 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); + } } else if( const auto* pbe = te.binding.opt_Union() ) { @@ -2070,7 +2051,7 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) if( pb.is_Enum() ) { const auto& enm = *pb.as_Enum(); - var_count = enm.m_variants.size(); + var_count = enm.num_variants(); } else if( const auto* pbe = pb.opt_Union() ) { diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 9ed889d9..dc3967b4 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1120,7 +1120,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool return ::MIR::RValue::make_Variant({ this->monomorph(se.path), se.index, this->clone_param(se.val) }); ), (Struct, - return ::MIR::RValue::make_Struct({ this->monomorph(se.path), se.variant_idx, this->clone_param_vec(se.vals) }); + return ::MIR::RValue::make_Struct({ this->monomorph(se.path), this->clone_param_vec(se.vals) }); ) ) throw ""; diff --git a/src/mir/visit_crate_mir.cpp b/src/mir/visit_crate_mir.cpp index 93d5f6ea..79d2e32a 100644 --- a/src/mir/visit_crate_mir.cpp +++ b/src/mir/visit_crate_mir.cpp @@ -72,14 +72,17 @@ void MIR::OuterVisitor::visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) { auto _ = this->m_resolve.set_item_generics(item.m_params); - // TODO: Use a different type depding on repr() - auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); - - for(auto& var : item.m_variants) + if( auto* e = item.m_data.opt_Value() ) { - TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, - m_cb(m_resolve, p + var.first, e.expr, {}, enum_type); - ) + // TODO: Use a different type depding on repr() + auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); + + for(auto& var : e->variants) + { + if( var.expr ) { + m_cb(m_resolve, p + var.name, var.expr, {}, enum_type); + } + } } } diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index e9cf274e..18412c27 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -702,10 +702,9 @@ namespace { ERROR(sp, E0000, "Enum as path component in unexpected location - " << p); } const auto& varname = p.m_components.back(); - auto it = ::std::find_if( e.m_variants.begin(), e.m_variants.end(), [&](const auto&x){return x.first == varname;} ); - ASSERT_BUG(sp, it != e.m_variants.end(), "Extern crate import path points to non-present variant - " << p); - unsigned int var_idx = it - e.m_variants.begin(); - auto pb = ::AST::PathBinding::make_EnumVar({nullptr, var_idx, &e}); + auto var_idx = e.find_variant(varname); + ASSERT_BUG(sp, var_idx != SIZE_MAX, "Extern crate import path points to non-present variant - " << p); + auto pb = ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned>(var_idx), &e}); // Construct output path (with same set of parameters) AST::Path rv( p.m_crate_name, {} ); @@ -901,22 +900,20 @@ namespace { (Enum, const auto& last_node = path_abs.nodes.back(); // If this refers to an enum variant, return the full path - for( const auto& var : e.m_variants ) + auto idx = e.find_variant(last_node.name()); + if( idx != SIZE_MAX ) { - if( var.first == last_node.name() ) { - - if( i != path_abs.nodes.size() - 2 ) { - ERROR(sp, E0000, "Unexpected enum in path " << path); - } - // NOTE: Type parameters for enums go after the _variant_ - if( ! n.args().is_empty() ) { - ERROR(sp, E0000, "Type parameters were not expected here (enum params go on the variant)"); - } - - path.bind( ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned int>(&var - &*e.m_variants.begin()), &e}) ); - path = split_into_crate(sp, mv$(path), start, crate.m_name); - return; + if( i != path_abs.nodes.size() - 2 ) { + ERROR(sp, E0000, "Unexpected enum in path " << path); + } + // NOTE: Type parameters for enums go after the _variant_ + if( ! n.args().is_empty() ) { + ERROR(sp, E0000, "Type parameters were not expected here (enum params go on the variant)"); } + + path.bind( ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned int>(idx), &e}) ); + path = split_into_crate(sp, mv$(path), start, crate.m_name); + return; } path = split_into_crate(sp, mv$(path), start, crate.m_name); path = split_into_ufcs_ty(sp, mv$(path), i-start); diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index 2f4ece59..458aed5e 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -223,8 +223,8 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) is_struct = e.enum_->variants().at(e.idx).m_data.is_Struct(); } else { - ASSERT_BUG(sp, e.idx < e.hir->m_variants.size(), "Variant out of range for " << i_data.path); - is_struct = e.hir->m_variants.at(e.idx).second.is_Struct(); + //ASSERT_BUG(sp, e.idx < e.hir->m_variants.size(), "Variant out of range for " << i_data.path); + is_struct = TU_TEST1(e.hir->m_data, Data, .at(e.idx).is_struct); } if( is_struct ) _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); @@ -457,19 +457,36 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst { DEBUG("Glob enum " << i_data.path << " (HIR)"); unsigned int idx = 0; - for( const auto& ev : e.hir->m_variants ) + if( e.hir->m_data.is_Value() ) { - ::AST::Path p = i_data.path + ev.first; - p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) ); + const auto* de = e.hir->m_data.opt_Value(); + for(const auto& ev : de->variants) + { + ::AST::Path p = i_data.path + ev.name; + p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) ); - if( ev.second.is_Struct() ) { - _add_item_type ( sp, dst_mod, ev.first, is_pub, mv$(p), false ); - } - else { - _add_item_value( sp, dst_mod, ev.first, is_pub, mv$(p), false ); + _add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false ); + + idx += 1; } + } + else + { + const auto* de = &e.hir->m_data.as_Data(); + for(const auto& ev : *de) + { + ::AST::Path p = i_data.path + ev.name; + p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) ); - idx += 1; + if( ev.is_struct ) { + _add_item_type ( sp, dst_mod, ev.name, is_pub, mv$(p), false ); + } + else { + _add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false ); + } + + idx += 1; + } } } ) diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 01a5d22c..e36e40a0 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -463,13 +463,10 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path } else { const auto& enm = *e.hir; - unsigned int i = 0; - for(const auto& var : enm.m_variants) + auto idx = enm.find_variant(des_item_name); + if( idx != SIZE_MAX ) { - if( var.first == des_item_name ) { - return ::AST::PathBinding::make_EnumVar({ nullptr, i, &enm }); - } - i ++; + return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned>(idx), &enm }); } } ) @@ -564,11 +561,11 @@ namespace { } const auto& name = nodes[i].name(); - auto it2 = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == name; } ); - if( it2 == enm.m_variants.end() ) { + auto idx = enm.find_variant(name); + if( idx == SIZE_MAX ) { ERROR(span, E0000, "Unable to find variant " << path); } - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(it2 - enm.m_variants.begin()), &enm }); + return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &enm }); } else { hmod = reinterpret_cast<const ::HIR::Module*>(ptr); @@ -584,11 +581,11 @@ namespace { } const auto& name = nodes[i].name(); - auto it2 = ::std::find_if( e.m_variants.begin(), e.m_variants.end(), [&](const auto& x){ return x.first == name; } ); - if( it2 == e.m_variants.end() ) { + auto idx = e.find_variant(name); + if(idx == SIZE_MAX) { ERROR(span, E0000, "Unable to find variant " << path); } - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(it2 - e.m_variants.begin()), &e }); + return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast<unsigned int>(idx), &e }); ) ) } @@ -606,7 +603,7 @@ namespace { auto p = e.path; p.m_components.pop_back(); const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum(); - assert(e.idx < enm.m_variants.size()); + assert(e.idx < enm.num_variants()); return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm }); } if( e.path.m_components.empty() ) @@ -653,7 +650,7 @@ namespace { auto p = e.path; p.m_components.pop_back(); const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum(); - assert(e.idx < enm.m_variants.size()); + assert(e.idx < enm.num_variants()); return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm }); } item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp index e7cea40d..e95ff08e 100644 --- a/src/trans/codegen.cpp +++ b/src/trans/codegen.cpp @@ -65,8 +65,7 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const const auto& nse = crate.get_typeitem_by_path(sp, path.m_path, false, true); if(const auto* e = nse.opt_Enum()) { - auto it = ::std::find_if(e->m_variants.begin(), e->m_variants.end(), [&](const auto& x){ return x.first == path.m_path.m_components.back(); }); - auto var_idx = it - e->m_variants.begin(); + auto var_idx = e->find_variant(path.m_path.m_components.back()); codegen->emit_constructor_enum(sp, path, *e, var_idx); continue ; } diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index b751a933..f338f502 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -982,6 +982,49 @@ namespace { ( return false; ), + (Path, + if( te.binding.is_Struct() ) + { + const auto& str = *te.binding.as_Struct(); + const auto& p = te.path.m_data.as_Generic(); + ::HIR::TypeRef tmp; + auto monomorph = [&](const auto& ty)->const auto& { + if( monomorphise_type_needed(ty) ) { + tmp = monomorphise_type(sp, str.m_params, p.m_params, ty); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return ty; + } + }; + TU_MATCHA( (str.m_data), (se), + (Unit, + ), + (Tuple, + for(size_t i = 0; i < se.size(); i ++) + { + if( get_nonzero_path(sp, monomorph(se[i].ent), out) ) + { + out.push_back(i); + return true; + } + } + ), + (Named, + for(size_t i = 0; i < se.size(); i ++) + { + if( get_nonzero_path(sp, monomorph(se[i].second.ent), out) ) + { + out.push_back(i); + return true; + } + } + ) + ) + } + return false; + ), (Borrow, if( metadata_type(*te.inner) != MetadataType::None ) { @@ -1031,21 +1074,22 @@ namespace { ::std::vector<unsigned> nonzero_path; { // Detect Option (and similar enums) - if( item.m_variants.size() == 2 && item.m_variants[0].second.is_Unit() && item.m_variants[1].second.is_Tuple() ) + // - Matches two-variant enums where the first variant is unit-like, and the second is not + if( item.m_data.is_Data() && item.m_data.as_Data().size() == 2 + && item.m_data.as_Data()[0].type == ::HIR::TypeRef::new_unit() + && item.m_data.as_Data()[1].type != ::HIR::TypeRef::new_unit() + ) { - const auto& data_ents = item.m_variants[1].second.as_Tuple(); - if( data_ents.size() == 1 ) + const auto& data_type = monomorph(item.m_data.as_Data()[1].type); + if( get_nonzero_path(sp, data_type, nonzero_path) ) { - const auto& data_type = monomorph(data_ents[0].ent); - if( get_nonzero_path(sp, data_type, nonzero_path) ) - { - nonzero_path.push_back(0); - ::std::reverse( nonzero_path.begin(), nonzero_path.end() ); - } - else - { - assert(nonzero_path.size() == 0); - } + ::std::reverse( nonzero_path.begin(), nonzero_path.end() ); + DEBUG("Correct format for NonZero to apply, and field found at " << nonzero_path); + } + else + { + DEBUG("Correct format for NonZero to apply, but no field"); + assert(nonzero_path.size() == 0); } } } @@ -1053,21 +1097,20 @@ namespace { m_of << "// enum " << p << "\n"; if( nonzero_path.size() > 0 ) { - MIR_ASSERT(*m_mir_res, nonzero_path[0] == 0, ""); - MIR_ASSERT(*m_mir_res, item.m_variants.size() == 2, ""); - MIR_ASSERT(*m_mir_res, item.m_variants[0].second.is_Unit(), ""); - const auto& data_var = item.m_variants[1]; - MIR_ASSERT(*m_mir_res, data_var.second.is_Tuple(), ""); - MIR_ASSERT(*m_mir_res, data_var.second.as_Tuple().size() == 1, ""); - const auto& data_type = monomorph(data_var.second.as_Tuple()[0].ent); + //MIR_ASSERT(*m_mir_res, item.num_variants() == 2, ""); + //MIR_ASSERT(*m_mir_res, item.m_variants[0].second.is_Unit(), ""); + //const auto& data_var = item.m_variants[1]; + //MIR_ASSERT(*m_mir_res, data_var.second.is_Tuple(), ""); + //MIR_ASSERT(*m_mir_res, data_var.second.as_Tuple().size() == 1, ""); + const auto& data_type = monomorph(item.m_data.as_Data()[1].type); m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - m_of << "\t"; emit_ctype(data_type, FMT_CB(s, s << "_0";)); m_of << ";\n"; + m_of << "\t"; emit_ctype(data_type, FMT_CB(s, s << "_1";)); m_of << ";\n"; m_of << "};\n"; } - else if( item.m_repr != ::HIR::Enum::Repr::Rust || ::std::all_of(item.m_variants.begin(), item.m_variants.end(), [](const auto& x){return x.second.is_Unit() || x.second.is_Value();}) ) + else if( item.m_data.is_Value() ) { m_of << "struct e_" << Trans_Mangle(p) << " {\n"; - switch(item.m_repr) + switch(item.m_data.as_Value().repr) { case ::HIR::Enum::Repr::Rust: case ::HIR::Enum::Repr::C: @@ -1087,41 +1130,15 @@ namespace { } else { + const auto& variants = item.m_data.as_Data(); m_of << "struct e_" << Trans_Mangle(p) << " {\n"; m_of << "\tunsigned int TAG;\n"; m_of << "\tunion {\n"; - for(unsigned int i = 0; i < item.m_variants.size(); i ++) + for(unsigned int i = 0; i < variants.size(); i ++) { - TU_MATCHA( (item.m_variants[i].second), (e), - (Unit, - //m_of << "\t\tstruct {} var_" << i << ";\n"; - ), - (Value, - //m_of << "\t\tstruct {} var_" << i << ";\n"; - ), - (Tuple, - m_of << "\t\tstruct {\n"; - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i]; - m_of << "\t\t\t"; - emit_ctype( monomorph(fld.ent) ); - m_of << " _" << i << ";\n"; - } - m_of << "\t\t} var_" << i << ";\n"; - ), - (Struct, - m_of << "\t\tstruct {\n"; - for(unsigned int i = 0; i < e.size(); i ++) - { - const auto& fld = e[i]; - m_of << "\t\t\t"; - emit_ctype( monomorph(fld.second.ent) ); - m_of << " _" << i << ";\n"; - } - m_of << "\t\t} var_" << i << ";\n"; - ) - ) + m_of << "\t\t"; + emit_ctype( monomorph(variants[i].type) ); + m_of << " var_" << i << ";\n"; } m_of << "\t} DATA;\n"; m_of << "};\n"; @@ -1153,60 +1170,30 @@ namespace { if( nonzero_path.size() > 0 ) { - auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); // TODO: Fat pointers? - m_of << "\tif( ! (*rv)"; emit_nonzero_path(nonzero_path); m_of << " ) {\n"; - for(const auto& fld : item.m_variants[1].second.as_Tuple()) - { - emit_destructor_call(fld_lv, monomorph(fld.ent), false, 2); - fld_lv.as_Field().field_index ++; - } + m_of << "\tif( (*rv)._1"; emit_nonzero_path(nonzero_path); m_of << " ) {\n"; + emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), 1 }), monomorph(item.m_data.as_Data()[1].type), false, 2 ); m_of << "\t}\n"; } - else if( item.m_repr != ::HIR::Enum::Repr::Rust || ::std::all_of(item.m_variants.begin(), item.m_variants.end(), [](const auto& x){return x.second.is_Unit() || x.second.is_Value();}) ) - { - // Glue does nothing (except call the destructor, if there is one) - } - else + else if( const auto* e = item.m_data.opt_Data() ) { - auto fld_lv = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Downcast({ box$(self), 0 })), 0 }); + auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 }); m_of << "\tswitch(rv->TAG) {\n"; - for(unsigned int var_idx = 0; var_idx < item.m_variants.size(); var_idx ++) + for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++) { - fld_lv.as_Field().val->as_Downcast().variant_index = var_idx; - TU_MATCHA( (item.m_variants[var_idx].second), (e), - (Unit, - m_of << "\tcase " << var_idx << ": break;\n"; - ), - (Value, - m_of << "\tcase " << var_idx << ": break;\n"; - ), - (Tuple, - m_of << "\tcase " << var_idx << ":\n"; - for(unsigned int i = 0; i < e.size(); i ++) - { - fld_lv.as_Field().field_index = i; - const auto& fld = e[i]; - - emit_destructor_call(fld_lv, monomorph(fld.ent), false, 2); - } - m_of << "\tbreak;\n"; - ), - (Struct, - m_of << "\tcase " << var_idx << ":\n"; - for(unsigned int i = 0; i < e.size(); i ++) - { - fld_lv.as_Field().field_index = i; - const auto& fld = e[i]; - emit_destructor_call(fld_lv, monomorph(fld.second.ent), false, 2); - } - m_of << "\tbreak;\n"; - ) - ) + var_lv.as_Downcast().variant_index = var_idx; + m_of << "\tcase " << var_idx << ":\n"; + emit_destructor_call(var_lv, monomorph( (*e)[var_idx].type ), false, 2); + m_of << "\tbreak;\n"; } m_of << "\t}\n"; } + else + { + // Value enum + // Glue does nothing (except call the destructor, if there is one) + } m_of << "}\n"; m_mir_res = nullptr; @@ -1233,9 +1220,13 @@ namespace { auto p = path.clone(); p.m_path.m_components.pop_back(); - const auto& var = item.m_variants[var_idx]; - ASSERT_BUG(sp, var.second.is_Tuple(), ""); - const auto& e = var.second.as_Tuple(); + + ASSERT_BUG(sp, item.m_data.is_Data(), ""); + const auto& var = item.m_data.as_Data().at(var_idx); + ASSERT_BUG(sp, var.type.m_data.is_Path(), ""); + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Tuple(), ""); + const auto& e = str.m_data.as_Tuple(); m_of << "struct e_" << Trans_Mangle(p) << " " << Trans_Mangle(path) << "("; @@ -1249,7 +1240,7 @@ namespace { auto it = m_enum_repr_cache.find(p); if( it != m_enum_repr_cache.end() ) { - m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { ._0 = _0 };\n"; + m_of << "\tstruct e_" << Trans_Mangle(p) << " rv = { _0 };\n"; } else { @@ -1435,21 +1426,9 @@ namespace { MIR_TODO(*m_mir_res, "Union literals"); ), (Enum, - const auto& evar = pbe->m_variants.at(var); - TU_MATCHA( (evar.second), (se), - (Unit, - MIR_BUG(*m_mir_res, "Unit enum var " << ty << " #" << var << " - fld " << idx); - ), - (Value, - MIR_BUG(*m_mir_res, "Value enum var " << ty << " #" << var << " - fld " << idx); - ), - (Tuple, - return monomorph_with(pp, se.at(idx).ent); - ), - (Struct, - return monomorph_with(pp, se.at(idx).second.ent); - ) - ) + MIR_ASSERT(*m_mir_res, pbe->m_data.is_Data(), ""); + const auto& evar = pbe->m_data.as_Data().at(var); + return monomorph_with(pp, evar.type); ) ) throw ""; @@ -1489,36 +1468,20 @@ namespace { m_of << "{0}"; } else { - m_of << "{"; - emit_literal(get_inner_type(e.idx, 0), e.vals[0], params); - m_of << "}"; + emit_literal(get_inner_type(e.idx, 0), *e.val, params); } } else if( enm.is_value() ) { - MIR_ASSERT(*m_mir_res, e.vals.empty(), "Value-only enum with fields"); + MIR_ASSERT(*m_mir_res, TU_TEST1((*e.val), List, .empty()), "Value-only enum with fields"); m_of << "{" << enm.get_value(e.idx) << "}"; } else { m_of << "{" << e.idx; - if( e.vals.empty() ) - { - if( m_options.disallow_empty_structs && !enm.m_variants.at(e.idx).second.is_Unit() ) - { - m_of << ", { .var_" << e.idx << " = {0} }"; - } - } - else - { - m_of << ", { .var_" << e.idx << " = {"; - for(unsigned int i = 0; i < e.vals.size(); i ++) { - if(i != 0) m_of << ","; - m_of << " "; - emit_literal(get_inner_type(e.idx, i), e.vals[i], params); - } - m_of << "} }"; - } + m_of << ", { .var_" << e.idx << " = "; + emit_literal(get_inner_type(e.idx, 0), *e.val, params); + m_of << " }"; m_of << "}"; } ), @@ -2017,7 +1980,7 @@ namespace { if( it != m_enum_repr_cache.end() ) { MIR_ASSERT(mir_res, e.targets.size() == 2, "Non-zero optimised type a variant count that isn't 2"); - m_of << "\tif("; emit_lvalue(e.val); emit_nonzero_path(it->second); m_of << ")\n"; + m_of << "\tif("; emit_lvalue(e.val); m_of << "._1"; emit_nonzero_path(it->second); m_of << ")\n"; m_of << "\t\tgoto bb" << e.targets[1] << ";\n"; m_of << "\telse\n"; m_of << "\t\tgoto bb" << e.targets[0] << ";\n"; @@ -2537,42 +2500,20 @@ namespace { } else if( const auto* enm_p = tyi.opt_Enum() ) { - MIR_TODO(mir_res, "Construct enum with RValue::Variant"); - if( enm_p->is_value() ) - { - emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << ""; - } - else - { - emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA"; - m_of << ".var_" << ve.index << " = "; emit_param(ve.val); - } - } - else - { - BUG(mir_res.sp, "Unexpected type in Variant"); - } - ), - (Struct, - bool is_val_enum = false; - if(ve.variant_idx != ~0u) - { ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); - const auto* enm_p = ty.m_data.as_Path().binding.as_Enum(); auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); if( it != m_enum_repr_cache.end() ) { - if( ve.variant_idx == 0 ) { + if( ve.index == 0 ) { // TODO: Use nonzero_path m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))"; } - else if( ve.variant_idx == 1 ) { + else if( ve.index == 1 ) { emit_lvalue(e.dst); - m_of << "._0 = "; - emit_param(ve.vals[0]); + m_of << "._1 = "; + emit_param(ve.val); } else { } @@ -2580,30 +2521,28 @@ namespace { } else if( enm_p->is_value() ) { - is_val_enum = true; - emit_lvalue(e.dst); - m_of << ".TAG = " << enm_p->get_value(ve.variant_idx); - assert(ve.vals.size() == 0); + emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << ""; } else { - is_val_enum = enm_p->m_variants.at(ve.variant_idx).second.is_Unit(); - emit_lvalue(e.dst); - m_of << ".TAG = " << ve.variant_idx; + emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA"; + m_of << ".var_" << ve.index << " = "; emit_param(ve.val); } - if(ve.vals.size() > 0) - m_of << ";\n" << indent; } + else + { + BUG(mir_res.sp, "Unexpected type in Variant"); + } + ), + (Struct, + bool is_val_enum = false; if( ve.vals.empty() ) { if( m_options.disallow_empty_structs && !is_val_enum) { - if(ve.variant_idx != ~0u) - m_of << ";\n" << indent; emit_lvalue(e.dst); - if(ve.variant_idx != ~0u) - m_of << ".DATA.var_" << ve.variant_idx; m_of << "._d = 0"; } } @@ -2618,8 +2557,6 @@ namespace { if( j != 0 ) m_of << ";\n" << indent; emit_lvalue(e.dst); - if(ve.variant_idx != ~0u) - m_of << ".DATA.var_" << ve.variant_idx; m_of << "._" << j << " = "; emit_param(ve.vals[j]); } @@ -2804,7 +2741,7 @@ namespace { { //MIR_ASSERT(mir_res, e.targets.size() == 2, "NonZero optimised representation for an enum without two variants"); MIR_ASSERT(mir_res, n_arms == 2, "NonZero optimised switch without two arms"); - m_of << indent << "if("; emit_lvalue(val); emit_nonzero_path(it->second); m_of << ")\n"; + m_of << indent << "if("; emit_lvalue(val); m_of << "._1"; emit_nonzero_path(it->second); m_of << ")\n"; m_of << indent; cb(1); m_of << "\n"; @@ -3523,7 +3460,7 @@ namespace { auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); if( it != m_enum_repr_cache.end() ) { - emit_param(e.args.at(0)); emit_nonzero_path(it->second); m_of << " != 0"; + emit_param(e.args.at(0)); m_of << "->_1"; emit_nonzero_path(it->second); m_of << " != 0"; } else { @@ -4073,21 +4010,9 @@ namespace { MIR_TODO(*m_mir_res, "Union literals"); ), (Enum, - const auto& evar = pbe->m_variants.at(var); - TU_MATCHA( (evar.second), (se), - (Unit, - MIR_BUG(*m_mir_res, "Unit enum var " << ty << " #" << var << " - fld " << idx); - ), - (Value, - MIR_BUG(*m_mir_res, "Value enum var " << ty << " #" << var << " - fld " << idx); - ), - (Tuple, - return monomorph_with(pp, se.at(idx).ent); - ), - (Struct, - return monomorph_with(pp, se.at(idx).second.ent); - ) - ) + MIR_ASSERT(*m_mir_res, pbe->m_data.is_Data(), ""); + const auto& evar = pbe->m_data.as_Data().at(var); + return monomorph_with(pp, evar.type); ) ) throw ""; @@ -4131,21 +4056,19 @@ namespace { m_of << " = 0"; } else { - assign_from_literal([&](){ emit_dst(); m_of << "._0"; }, get_inner_type(e.idx, 0), e.vals[0]); + assign_from_literal([&](){ emit_dst(); }, get_inner_type(e.idx, 0), *e.val); } } else if( enm.is_value() ) { - MIR_ASSERT(*m_mir_res, e.vals.empty(), "Value-only enum with fields"); + MIR_ASSERT(*m_mir_res, TU_TEST1((*e.val), List, .empty()), "Value-only enum with fields"); emit_dst(); m_of << ".TAG = " << enm.get_value(e.idx); } else { emit_dst(); m_of << ".TAG = " << e.idx; - for(unsigned int i = 0; i < e.vals.size(); i ++) { - m_of << ";\n\t"; - assign_from_literal([&](){ emit_dst(); m_of << ".DATA.var_" << e.idx << "._" << i; }, get_inner_type(e.idx, i), e.vals[i]); - } + m_of << ";\n\t"; + assign_from_literal([&](){ emit_dst(); m_of << ".DATA.var_" << e.idx; }, get_inner_type(e.idx, 0), *e.val); } ), (Integer, @@ -4313,7 +4236,7 @@ namespace { { MIR_ASSERT(*m_mir_res, e.variant_index == 1, ""); // NOTE: Downcast returns a magic tuple - //m_of << "._0"; + m_of << "._1"; break ; } else diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 283617f2..757b368d 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -424,22 +424,12 @@ namespace { return x; } }; - for(const auto& variant : item.m_variants) + if( const auto* e = item.m_data.opt_Data() ) { - TU_MATCHA( (variant.second), (e), - (Unit, - ), - (Value, - ), - (Tuple, - for(const auto& ty : e) - visit_type( monomorph(ty.ent) ); - ), - (Struct, - for(const auto& fld : e) - visit_type( monomorph(fld.second.ent) ); - ) - ) + for(const auto& variant : *e) + { + visit_type( monomorph(variant.type) ); + } } } @@ -810,30 +800,16 @@ void Trans_Enumerate_Types(EnumState& state) tv.m_resolve.expand_associated_types(sp, rv); return rv; }; - const auto& variants = enm.m_variants; + ASSERT_BUG(Span(), enm.m_data.is_Data(), ""); + const auto& variants = enm.m_data.as_Data(); ASSERT_BUG(Span(), e.variant_index < variants.size(), "Variant index out of range"); - const auto& variant = variants[e.variant_index]; - // TODO: Make data variants refer to associated types (unify enum and struct handling) - TU_MATCHA( (variant.second), (ve), - (Value, - ), - (Unit, - ), - (Tuple, - // HACK! Create tuple. - ::std::vector< ::HIR::TypeRef> tys; - for(const auto& fld : ve) - tys.push_back( monomorph(fld.ent) ); - return *tmp_ty_ptr = ::HIR::TypeRef( mv$(tys) ); - ), - (Struct, - // HACK! Create tuple. - ::std::vector< ::HIR::TypeRef> tys; - for(const auto& fld : ve) - tys.push_back( monomorph(fld.second.ent) ); - return *tmp_ty_ptr = ::HIR::TypeRef( mv$(tys) ); - ) - ) + const auto& raw_ty = variants[e.variant_index].type; + if( monomorphise_type_needed(raw_ty) ) { + return *tmp_ty_ptr = monomorph(raw_ty); + } + else { + return raw_ty; + } } else { @@ -1553,8 +1529,7 @@ void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& li Trans_Enumerate_FillFrom_Literal(state, v, pp); ), (Variant, - for(const auto& v : e.vals) - Trans_Enumerate_FillFrom_Literal(state, v, pp); + Trans_Enumerate_FillFrom_Literal(state, *e.val, pp); ), (Integer, ), diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index b752a5bc..fd05c85b 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -234,7 +234,6 @@ namespace { (Struct, rval = ::MIR::RValue::make_Struct({ params.monomorph(resolve, se.path), - se.variant_idx, monomorph_Param_list(resolve, params, se.vals) }); ) |