diff options
Diffstat (limited to 'src')
32 files changed, 1085 insertions, 315 deletions
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 39250a41..df5f4d5a 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -175,6 +175,9 @@ Enum Enum::clone() const Struct Struct::clone() const { TU_MATCHA( (m_data), (e), + (Unit, + return Struct(m_params.clone()); + ), (Tuple, decltype(e.ents) new_fields; for(const auto& f : e.ents) diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index b63cb2e6..c067001a 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -319,6 +319,7 @@ public: TAGGED_UNION_EX(StructData, (), Struct, ( + (Unit, struct {}), (Tuple, struct { ::std::vector<TupleItem> ents; }), @@ -339,6 +340,11 @@ public: StructData m_data; Struct() {} + Struct(GenericParams params): + m_params( mv$(params) ), + m_data( StructData::make_Unit({}) ) + { + } Struct( GenericParams params, ::std::vector<StructItem> fields ): m_params( move(params) ), m_data( StructData::make_Struct({mv$(fields)}) ) diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index a6c298b0..0d77054c 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -991,22 +991,18 @@ void RustPrinter::handle_struct(const AST::Struct& s) print_params(s.params()); TU_MATCH(AST::StructData, (s.m_data), (e), + (Unit, + m_os << " /* unit-like */\n"; + print_bounds(s.params()); + m_os << indent() << ";\n"; + ), (Tuple, - if( e.ents.size() == 0 ) - { - m_os << " /* unit-like */\n"; - print_bounds(s.params()); - m_os << indent() << ";\n"; - } - else - { - m_os << "("; - for( const auto& i : e.ents ) - m_os << i.m_type << ", "; - m_os << ")\n"; - print_bounds(s.params()); - m_os << indent() << ";\n"; - } + m_os << "("; + for( const auto& i : e.ents ) + m_os << i.m_type << ", "; + m_os << ")\n"; + print_bounds(s.params()); + m_os << indent() << ";\n"; ), (Struct, m_os << "\n"; diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index c363b689..f09e9298 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -102,6 +102,8 @@ struct Deriver { ::std::vector<TypeRef> ret; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, for( const auto& fld : e.ents ) { @@ -299,6 +301,13 @@ public: // Generate code for Debug AST::ExprNodeP node; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + node = NEWNODE(NamedValue, AST::Path("f")); + node = NEWNODE(CallMethod, + mv$(node), AST::PathNode("write_str",{}), + vec$( NEWNODE(String, name) ) + ); + ), (Struct, node = NEWNODE(NamedValue, AST::Path("f")); node = NEWNODE(CallMethod, @@ -480,6 +489,8 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, for( const auto& fld : e.ents ) { @@ -685,6 +696,8 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, for( const auto& fld : e.ents ) { @@ -896,6 +909,8 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, for( const auto& fld : e.ents ) { @@ -1049,6 +1064,8 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, for( const auto& fld : e.ents ) { @@ -1265,6 +1282,9 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + nodes.push_back( NEWNODE(NamedValue, AST::Path(ty_path)) ); + ), (Struct, ::std::vector< ::std::pair< ::std::string, AST::ExprNodeP> > vals; for( const auto& fld : e.ents ) @@ -1274,19 +1294,12 @@ public: nodes.push_back( NEWNODE(StructLiteral, ty_path, nullptr, mv$(vals)) ); ), (Tuple, - if( e.ents.size() == 0 ) - { - nodes.push_back( NEWNODE(NamedValue, AST::Path(ty_path)) ); - } - else + ::std::vector<AST::ExprNodeP> vals; + for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) { - ::std::vector<AST::ExprNodeP> vals; - for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) - { - vals.push_back( this->clone_val_ref(core_name, this->field(FMT(idx))) ); - } - nodes.push_back( NEWNODE(CallPath, AST::Path(ty_path), mv$(vals)) ); + vals.push_back( this->clone_val_ref(core_name, this->field(FMT(idx))) ); } + nodes.push_back( NEWNODE(CallPath, AST::Path(ty_path), mv$(vals)) ); ) ) @@ -1428,6 +1441,9 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + nodes.push_back( NEWNODE(NamedValue, AST::Path(ty_path)) ); + ), (Struct, ::std::vector< ::std::pair< ::std::string, AST::ExprNodeP> > vals; for( const auto& fld : e.ents ) @@ -1437,19 +1453,12 @@ public: nodes.push_back( NEWNODE(StructLiteral, ty_path, nullptr, mv$(vals)) ); ), (Tuple, - if( e.ents.size() == 0 ) - { - nodes.push_back( NEWNODE(NamedValue, AST::Path(ty_path)) ); - } - else + ::std::vector<AST::ExprNodeP> vals; + for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) { - ::std::vector<AST::ExprNodeP> vals; - for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) - { - vals.push_back( this->default_call(core_name) ); - } - nodes.push_back( NEWNODE(CallPath, AST::Path(ty_path), mv$(vals)) ); + vals.push_back( this->default_call(core_name) ); } + nodes.push_back( NEWNODE(CallPath, AST::Path(ty_path), mv$(vals)) ); ) ) @@ -1522,6 +1531,8 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, for( const auto& fld : e.ents ) { @@ -1680,6 +1691,8 @@ public: ::std::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, unsigned int idx = 0; for( const auto& fld : e.ents ) @@ -1707,6 +1720,9 @@ public: ::AST::ExprNodeP node; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + node = get_val_ok(core_name); + ), (Struct, node = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_struct", @@ -1917,6 +1933,8 @@ public: AST::ExprNodeP node_v; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + ), (Struct, ::std::vector< ::std::pair< ::std::string, AST::ExprNodeP > > vals; unsigned int idx = 0; @@ -1949,6 +1967,9 @@ public: ::AST::ExprNodeP node; TU_MATCH(AST::StructData, (str.m_data), (e), + (Unit, + node = NEWNODE(NamedValue, mv$(base_path)); + ), (Struct, assert( !args[2] ); args[2] = NEWNODE(Integer, e.ents.size(), CORETYPE_UINT); diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index 988dc0e0..5c92cd76 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -70,6 +70,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "unsize" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "coerce_unsized" ) { DEBUG("Bind '"<<name<<"' to " << path); } + else if( name == "freeze" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "iterator" ) { /* mrustc just desugars? */ } @@ -91,6 +92,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, } else if( name == "str_eq" ) { } + else if( name == "drop_in_place" ) { } // - builtin `box` support else if( name == "exchange_malloc" ) { } else if( name == "exchange_free" ) { } diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 81a3c5b6..01786284 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -906,6 +906,8 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: (Struct, TU_MATCH(AST::StructData, (e.m_data), (sd), + (Unit, + ), (Struct, for(auto it = sd.ents.begin(); it != sd.ents.end(); ) { auto& si = *it; diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 255546e7..c0a3151e 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -819,18 +819,16 @@ namespace { ::HIR::Struct::Data data; TU_MATCH(::AST::StructData, (ent.m_data), (e), + (Unit, + data = ::HIR::Struct::Data::make_Unit({}); + ), (Tuple, - if( e.ents.size() == 0 ) { - data = ::HIR::Struct::Data::make_Unit({}); - } - else { - ::HIR::Struct::Data::Data_Tuple fields; + ::HIR::Struct::Data::Data_Tuple fields; - for(const auto& field : e.ents) - fields.push_back( { field.m_is_public, LowerHIR_Type(field.m_type) } ); + for(const auto& field : e.ents) + fields.push_back( { field.m_is_public, LowerHIR_Type(field.m_type) } ); - data = ::HIR::Struct::Data::make_Tuple( mv$(fields) ); - } + data = ::HIR::Struct::Data::make_Tuple( mv$(fields) ); ), (Struct, ::HIR::Struct::Data::Data_Named fields; @@ -1218,12 +1216,14 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H ), (Struct, /// Add value reference - TU_IFLET( ::AST::StructData, e.m_data, Tuple, e2, - if( e2.ents.size() == 0 ) - _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) ); - else - _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) ); - ) + if( e.m_data.is_Unit() ) { + _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) ); + } + else if( e.m_data.is_Tuple() ) { + _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) ); + } + else { + } _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Struct(item_path, e) ); ), (Enum, diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index cd2b27fa..9085bd3b 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -627,7 +627,7 @@ struct LowerHIR_ExprNode_Visitor: if( e.struct_->m_data.is_Struct() ) { ERROR(v.span(), E0000, "Named value referring to a struct that isn't tuple-like or unit-like - " << v.m_path); } - is_tuple_constructor = e.struct_->m_data.as_Tuple().ents.size() > 0; + is_tuple_constructor = e.struct_->m_data.is_Tuple(); } else { diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index d50c3e49..66070dc7 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -339,6 +339,11 @@ bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_res } namespace { + + struct TypeOrdSpecific_MixedOrdering + { + }; + ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& left, const ::std::vector<::HIR::TypeRef>& right); ::Ordering type_ord_specific(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right) @@ -397,7 +402,22 @@ namespace { TODO(sp, "Path - " << le.path << " and " << right); ), (TraitObject, - TODO(sp, "TraitObject - " << left); + ASSERT_BUG(sp, right.m_data.is_TraitObject(), "Mismatched types - "<< left << " vs " << right); + const auto& re = right.m_data.as_TraitObject(); + ASSERT_BUG(sp, le.m_trait.m_path.m_path == re.m_trait.m_path.m_path, "Mismatched types - "<< left << " vs " << right); + ASSERT_BUG(sp, le.m_markers.size() == re.m_markers.size(), "Mismatched types - "<< left << " vs " << right); + + auto ord = typelist_ord_specific(sp, le.m_trait.m_path.m_params.m_types, re.m_trait.m_path.m_params.m_types); + if( ord != ::OrdEqual ) + return ord; + for(size_t i = 0; i < le.m_markers.size(); i ++) + { + ASSERT_BUG(sp, le.m_markers[i].m_path == re.m_markers[i].m_path, "Mismatched types - " << left << " vs " << right); + ord = typelist_ord_specific(sp, le.m_markers[i].m_params.m_types, re.m_markers[i].m_params.m_types); + if(ord != ::OrdEqual) + return ord; + } + return ::OrdEqual; ), (ErasedType, TODO(sp, "ErasedType - " << left); @@ -464,11 +484,15 @@ namespace { ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& le, const ::std::vector<::HIR::TypeRef>& re) { auto rv = ::OrdEqual; + assert(le.size() == re.size()); for(unsigned int i = 0; i < le.size(); i ++) { auto a = type_ord_specific(sp, le[i], re[i]); if( a != ::OrdEqual ) { if( rv != ::OrdEqual && a != rv ) - BUG(sp, "Inconsistent ordering between type lists"); + { + DEBUG("Inconsistent ordering between type lists - i=" << i << " [" << le << "] vs [" << re << "]"); + throw TypeOrdSpecific_MixedOrdering {}; + } rv = a; } } @@ -525,20 +549,35 @@ bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const { static const Span _sp; const Span& sp = _sp; + TRACE_FUNCTION; + //DEBUG("this = " << *this); + //DEBUG("other = " << other); // >> https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#defining-the-precedence-rules // 1. If this->m_type is less specific than other.m_type: return false - if( type_ord_specific(sp, this->m_type, other.m_type) == ::OrdLess ) { - return false; + try + { + auto ord = type_ord_specific(sp, this->m_type, other.m_type); + if( ord != ::OrdEqual ) { + DEBUG("- Type " << (ord == ::OrdLess ? "less" : "more") << " specific - " << this->m_type << " AND " << other.m_type); + return ord == ::OrdLess; + } + // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false + ord = typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types); + if( ord != ::OrdEqual ) { + DEBUG("- Trait arguments " << (ord == ::OrdLess ? "less" : "more") << " specific"); + return ord == ::OrdLess; + } } - // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false - if( typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types) == ::OrdLess ) { - return false; + catch(const TypeOrdSpecific_MixedOrdering& e) + { + BUG(sp, "Mixed ordering in more_specific_than"); } - if( other.m_params.m_bounds.size() == 0 ) { - return m_params.m_bounds.size() > 0; - } + //if( other.m_params.m_bounds.size() == 0 ) { + // DEBUG("- Params (none in other, some in this)"); + // return m_params.m_bounds.size() > 0; + //} // 3. Compare bound set, if there is a rule in oe that is missing from te; return false // TODO: Cache these lists (calculate after outer typecheck?) auto bounds_t = flatten_bounds(m_params.m_bounds); @@ -549,7 +588,10 @@ bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const // If there are less bounds in this impl, it can't be more specific. if( bounds_t.size() < bounds_o.size() ) + { + DEBUG("Bound count"); return false; + } auto it_t = bounds_t.begin(); auto it_o = bounds_o.begin(); @@ -627,6 +669,7 @@ bool ::HIR::TraitImpl::overlaps_with(const ::HIR::TraitImpl& other) const static bool types_overlap(const ::HIR::TypeRef& a, const ::HIR::TypeRef& b) { static Span sp; + //DEBUG("(" << a << "," << b << ")"); if( a.m_data.is_Generic() || b.m_data.is_Generic() ) return true; // TODO: Unbound/Opaque paths? @@ -665,9 +708,21 @@ bool ::HIR::TraitImpl::overlaps_with(const ::HIR::TraitImpl& other) const TODO(sp, "Path - " << ae.path << " and " << be.path); ), (TraitObject, - if( ae.m_trait.m_path != be.m_trait.m_path ) + if( ae.m_trait.m_path.m_path != be.m_trait.m_path.m_path ) + return false; + if( !H::types_overlap(ae.m_trait.m_path.m_params, be.m_trait.m_path.m_params) ) return false; - TODO(sp, "TraitObject - " << a << " and " << b); + // Marker traits only overlap if the lists are the same (with overlap) + if( ae.m_markers.size() != be.m_markers.size() ) + return false; + for(size_t i = 0; i < ae.m_markers.size(); i++) + { + if( ae.m_markers[i].m_path != be.m_markers[i].m_path ) + return false; + if( !H::types_overlap(ae.m_markers[i].m_params, be.m_markers[i].m_params) ) + return false; + } + return true; ), (ErasedType, TODO(sp, "ErasedType - " << a); @@ -717,16 +772,89 @@ bool ::HIR::TraitImpl::overlaps_with(const ::HIR::TraitImpl& other) const } }; + // Quick Check: If the types are equal, they do overlap + if(this->m_type == other.m_type && this->m_trait_args == other.m_trait_args) + { + return true; + } + // 1. Are the impl types of the same form (or is one generic) if( ! H::types_overlap(this->m_type, other.m_type) ) return false; if( ! H::types_overlap(this->m_trait_args, other.m_trait_args) ) return false; - return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args; + DEBUG("TODO: Handle potential overlap (when not exactly equal)"); + //return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args; + Span sp; + + // TODO: Use `type_ord_specific` but treat any case of mixed ordering as this returning `false` + try + { + type_ord_specific(sp, this->m_type, other.m_type); + typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types); + } + catch(const TypeOrdSpecific_MixedOrdering& /*e*/) + { + return false; + } // TODO: Detect `impl<T> Foo<T> for Bar<T>` vs `impl<T> Foo<&T> for Bar<T>` // > Create values for impl params from the type, then check if the trait params are compatible + // > Requires two lists, and telling which one to use by the end + auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; }; + ::std::vector<const ::HIR::TypeRef*> impl_tys; + auto cb_match = [&](unsigned int idx, const ::HIR::TypeRef& x)->::HIR::Compare { + assert(idx < impl_tys.size()); + if( impl_tys.at(idx) ) + { + DEBUG("Compare " << x << " and " << *impl_tys.at(idx)); + return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal); + } + else + { + impl_tys.at(idx) = &x; + return ::HIR::Compare::Equal; + } + }; + impl_tys.resize( this->m_params.m_types.size() ); + if( ! this->m_type.match_test_generics(sp, other.m_type, cb_ident, cb_match) ) + { + DEBUG("- Type mismatch, try other ordering"); + impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() ); + if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) ) + { + DEBUG("- Type mismatch in both orderings"); + return false; + } + if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) + { + DEBUG("- Params mismatch"); + return false; + } + // Matched with second ording + } + else if( this->m_trait_args.match_test_generics_fuzz(sp, other.m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) + { + DEBUG("- Param mismatch, try other ordering"); + impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() ); + if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) ) + { + DEBUG("- Type mismatch in alt ordering"); + return false; + } + if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) + { + DEBUG("- Params mismatch in alt ordering"); + return false; + } + // Matched with second ordering + } + else + { + // Matched with first ordering + } + return true; } diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp index f51d7990..da6446d7 100644 --- a/src/hir/pattern.cpp +++ b/src/hir/pattern.cpp @@ -126,16 +126,16 @@ namespace HIR { os << "]"; ), (SplitSlice, - os << "["; + os << "[ "; for(const auto& s : e.leading) os << s << ", "; if( e.extra_bind.is_valid() ) { os << e.extra_bind; } - os << ".. "; + os << ".."; for(const auto& s : e.trailing) - os << s << ", "; - os << "]"; + os << ", " << s; + os << " ]"; ) ) return os; diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 20e8f7ca..cf443eb6 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -247,35 +247,42 @@ namespace { ), (Struct, const auto& str = get_struct_ptr(sp, m_crate, e.path); - TU_IFLET(::HIR::Struct::Data, str.m_data, Named, _, - e.binding = &str; - ) + if(str.m_data.is_Named() ) { + } + else if( str.m_data.is_Unit() && e.sub_patterns.size() == 0 ) { + } + else if( str.m_data.is_Tuple() && str.m_data.as_Tuple().empty() && e.sub_patterns.size() == 0 ) { + } else { - ERROR(sp, E0000, "Struct pattern on field-less struct " << e.path); + ERROR(sp, E0000, "Struct pattern `" << pat << "` on field-less struct " << e.path); } + e.binding = &str; ), (EnumTuple, auto p = get_enum_ptr(sp, m_crate, e.path); const auto& var = p.first->m_variants[p.second].second; - TU_IFLET(::HIR::Enum::Variant, var, Tuple, _, - e.binding_ptr = p.first; - e.binding_idx = p.second; - ) + if( var.is_Tuple() ) { + } else { 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; - TU_IFLET(::HIR::Enum::Variant, var, Struct, _, - // All good - e.binding_ptr = p.first; - e.binding_idx = p.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 { - ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path); + 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_expand/closures.cpp b/src/hir_expand/closures.cpp index 82681a47..b58f2398 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -151,6 +151,7 @@ namespace { if( binding_it->second != ::HIR::ValueUsage::Move ) { auto bt = (binding_it->second == ::HIR::ValueUsage::Mutate ? ::HIR::BorrowType::Unique : ::HIR::BorrowType::Shared); + visit_type(m_replacement->m_res_type); m_replacement->m_res_type = ::HIR::TypeRef::new_borrow( bt, mv$(m_replacement->m_res_type) ); m_replacement = NEWNODE(node.m_res_type.clone(), Deref, node.span(), mv$(m_replacement)); } diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 1b4317a6..fe67865f 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -22,12 +22,15 @@ namespace { const ::HIR::TypeRef& ret_type; ::std::vector< const ::HIR::TypeRef*> closure_ret_types; + ::HIR::SimplePath m_lang_Index; + public: ExprVisitor_Validate(const StaticTraitResolve& res, const t_args& args, const ::HIR::TypeRef& ret_type): m_resolve(res), //m_args(args), ret_type(ret_type) { + m_lang_Index = m_resolve.m_crate.get_lang_item_path_opt("index"); } void visit_root(::HIR::ExprPtr& node_ptr) @@ -255,8 +258,7 @@ namespace { { TRACE_FUNCTION_F(&node << " ... [ ... ]"); check_associated_type(node.span(), - node.m_res_type, - this->get_lang_item_path(node.span(), "index"), { node.m_index->m_res_type.clone() }, node.m_value->m_res_type, "Target" + node.m_res_type, m_lang_Index, { node.m_index->m_res_type.clone() }, node.m_value->m_res_type, "Target" ); node.m_value->visit( *this ); @@ -333,7 +335,10 @@ namespace { const auto& src_ty = node.m_value->m_res_type; const auto& dst_ty = node.m_res_type; - if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() ) + if( src_ty == dst_ty ) + { + } + else if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() ) { const auto& se = src_ty.m_data.as_Borrow(); const auto& de = dst_ty.m_data.as_Borrow(); @@ -363,10 +368,20 @@ namespace { void visit(::HIR::ExprNode_Deref& node) override { TRACE_FUNCTION_F(&node << " *..."); - check_associated_type(node.span(), - node.m_res_type, - this->get_lang_item_path(node.span(), "deref"), {}, node.m_value->m_res_type, "Target" - ); + const auto& ty = node.m_value->m_res_type; + + if( ty.m_data.is_Pointer() ) { + check_types_equal(node.span(), node.m_res_type, *ty.m_data.as_Pointer().inner); + } + else if( ty.m_data.is_Borrow() ) { + check_types_equal(node.span(), node.m_res_type, *ty.m_data.as_Borrow().inner); + } + else { + check_associated_type(node.span(), + node.m_res_type, + this->get_lang_item_path(node.span(), "deref"), {}, node.m_value->m_res_type, "Target" + ); + } node.m_value->visit( *this ); } @@ -473,6 +488,14 @@ namespace { TODO(sp, "Union in StructLiteral"); ), (Struct, + if( e->m_data.is_Unit() ) + { + ASSERT_BUG(node.span(), node.m_values.size() == 0, "Values provided for unit-like struct"); + ASSERT_BUG(node.span(), ! node.m_base_value, "Values provided for unit-like struct"); + return ; + } + + ASSERT_BUG(node.span(), e->m_data.is_Named(), "StructLiteral not pointing to a braced struct, instead " << e->m_data.tag_str() << " - " << ty); fields_ptr = &e->m_data.as_Named(); ) ) @@ -704,6 +727,9 @@ namespace { cache.m_monomorph_cb = mv$(monomorph_cb); // Bounds + for(size_t i = 0; i < cache.m_fcn_params->m_types.size(); i ++) + { + } for(const auto& bound : cache.m_fcn_params->m_bounds) { TU_MATCH(::HIR::GenericBound, (bound), (be), @@ -713,7 +739,10 @@ namespace { ), (TraitBound, auto real_type = monomorphise_type_with(sp, be.type, cache.m_monomorph_cb); + m_resolve.expand_associated_types(sp, real_type); auto real_trait = monomorphise_genericpath_with(sp, be.trait.m_path, cache.m_monomorph_cb, false); + for(auto& t : real_trait.m_params.m_types) + m_resolve.expand_associated_types(sp, t); DEBUG("Bound " << be.type << ": " << be.trait); DEBUG("= (" << real_type << ": " << real_trait << ")"); const auto& trait_params = real_trait.m_params; @@ -728,6 +757,7 @@ namespace { ASSERT_BUG(sp, has_ty, "Type " << assoc.first << " not found in chain of " << real_trait); auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true); + m_resolve.expand_associated_types(sp, other_ty); check_associated_type(sp, other_ty, type_trait_path.m_path, type_trait_path.m_params, real_type, assoc.first.c_str()); } @@ -992,10 +1022,29 @@ namespace { const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& ity, const char* name ) const { - // TODO: Actually check. - #if 0 - bool found = m_resolve.find_impl(sp, trait, ¶ms, ity, [&](auto impl, bool fuzzy){ - + if( trait == m_lang_Index && ity.m_data.is_Array() ) { + if(name) + { + if( res != *ity.m_data.as_Array().inner ) { + ERROR(sp, E0000, "Associated type on " << trait << params << " for " << ity << " doesn't match - " << res << " != " << *ity.m_data.as_Array().inner); + } + } + return ; + } + bool found = m_resolve.find_impl(sp, trait, ¶ms, ity, [&](auto impl, bool fuzzy) { + if( name ) + { + auto atyv = impl.get_type(name); + m_resolve.expand_associated_types(sp, atyv); + if( atyv == ::HIR::TypeRef() ) + { + // TODO: Check that `res` is <ity as trait>::name + } + else if( res != atyv ) + { + ERROR(sp, E0000, "Associated type on " << trait << params << " for " << ity << " doesn't match - " << res << " != " << atyv); + } + } return true; }); @@ -1003,7 +1052,6 @@ namespace { { ERROR(sp, E0000, "Cannot find an impl of " << trait << params << " for " << ity); } - #endif } const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 2388d078..eb922414 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1061,6 +1061,7 @@ namespace { for( auto& val : node.m_args ) { this->context.add_ivars( val->m_res_type ); } + this->context.m_ivars.add_ivars_params(node.m_path.m_params); // - Create ivars in path, and set result type const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_path); @@ -1131,6 +1132,7 @@ namespace { void visit(::HIR::ExprNode_StructLiteral& node) override { 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 ) { this->context.add_ivars( val.second->m_res_type ); } @@ -1155,6 +1157,12 @@ namespace { 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() ) { + 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(); generics = &enm.m_params; ), @@ -1162,6 +1170,18 @@ namespace { TODO(node.span(), "StructLiteral of a union - " << ty); ), (Struct, + if( e->m_data.is_Unit() || e->m_data.is_Tuple() ) + { + ASSERT_BUG(node.span(), node.m_values.size() == 0, "Values provided for unit-like struct"); + + if( node.m_base_value ) { + auto _ = this->push_inner_coerce_scoped(false); + node.m_base_value->visit( *this ); + } + return ; + } + + ASSERT_BUG(node.span(), e->m_data.is_Named(), "StructLiteral not pointing to a braced struct, instead " << e->m_data.tag_str() << " - " << ty); fields_ptr = &e->m_data.as_Named(); generics = &e->m_params; ) @@ -1208,7 +1228,7 @@ namespace { } des_ty = &des_ty_cache; } - this->equate_types_inner_coerce(node.span(), *des_ty, val.second); + this->context.equate_types_coerce(node.span(), *des_ty, val.second); } // Convert bounds on the type into rules @@ -3390,7 +3410,8 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type context.equate_types(sp, type, ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef(::HIR::CoreType::Str) )); ), (ByteString, - context.equate_types(sp, type, ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ::HIR::TypeRef::new_slice(::HIR::CoreType::U8) )); + // NOTE: Matches both &[u8] and &[u8; N], so doesn't provide type information + // TODO: Check the type. ), (Named, // TODO: Get type of the value and equate it @@ -3730,10 +3751,14 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type this->add_ivars_params( e.path.m_params ); this->equate_types( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); + if( e.sub_patterns.empty() ) + return ; + assert(e.binding); const auto& str = *e.binding; + // - assert check from earlier pass - assert( str.m_data.is_Named() ); + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct"); const auto& sd = str.m_data.as_Named(); const auto& params = e.path.m_params; @@ -3806,6 +3831,9 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); } + if( e.sub_patterns.empty() ) + return ; + assert(e.binding_ptr); const auto& enm = *e.binding_ptr; const auto& var = enm.m_variants[e.binding_idx].second; @@ -4123,22 +4151,35 @@ namespace { //} context.possible_equate_type_unsize_to(r_e.index, ty_dst); context.possible_equate_type_unsize_from(l_e.index, ty_src); - DEBUG("- Infer, add possibility"); + DEBUG("- Both infer, add possibility"); return false; } // If the source is '_', we can't know yet TU_IFLET(::HIR::TypeRef::Data, ty_src.m_data, Infer, r_e, - // TODO: If the source is a literal, and the destination isn't a TraitObject, equate. - // - Except if it's known to be a primitive - //if( r_e.ty_class != ::HIR::InferClass::None ) { - // context.equate_types(sp, ty_dst, ty_src); - // return true; - //} - context.possible_equate_type_unsize_to(r_e.index, ty_dst); - DEBUG("- Infer, add possibility"); - return false; + // No avaliable information, add a possible unsize + if( r_e.ty_class == ::HIR::InferClass::None || r_e.ty_class == ::HIR::InferClass::Diverge ) + { + // Possibility + context.possible_equate_type_unsize_to(r_e.index, ty_dst); + DEBUG("- Infer, add possibility"); + return false; + } + // Destination is infer, fall through to next TU_IFLET + else if( ty_dst.m_data.is_Infer() ) + { + } + // Destination is a TraitObject, fall through to doing an impl search + else if( ty_dst.m_data.is_TraitObject() ) + { + } + // Otherwise, they have to be equal + else + { + context.equate_types(sp, ty_dst, ty_src); + return true; + } ) TU_IFLET(::HIR::TypeRef::Data, ty_dst.m_data, Infer, l_e, @@ -4155,8 +4196,16 @@ namespace { return true; } + // If the source can't unsize, equate + if( const auto* te = ty_src.m_data.opt_Slice() ) + { + (void)te; + context.equate_types(sp, ty_dst, ty_src); + return true; + } + context.possible_equate_type_unsize_from(l_e.index, ty_src); - DEBUG("- Infer, add possibility"); + DEBUG("- Dest infer, add possibility"); return false; ) @@ -4702,12 +4751,15 @@ namespace { } // TODO: Can this can unsize as well as convert to raw? + // - It _can_ unsize, TODO: context.equate_types(sp, *l_e.inner, *s_e.inner); // Add downcast auto span = node_ptr->span(); node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Cast( mv$(span), mv$(node_ptr), ty_dst.clone() )); node_ptr->m_res_type = ty_dst.clone(); + // TODO: Add a coerce of src->&dst_inner + context.m_ivars.mark_change(); return true; ) @@ -4908,8 +4960,28 @@ namespace { else { // No equivalence added } - // - Fall through and search for the impl - DEBUG("- Unsize, no ivar equivalence"); + + // TODO: If this was a compiler-inserted bound (from a coercion rule), then do deref checks +#if 0 + { + ::HIR::TypeRef tmp_ty; + const ::HIR::TypeRef* ty_ptr = &src_ty; + while( (ty_ptr = context.m_resolve.autoderef(sp, *ty_ptr, tmp_ty)) ) + { + const auto& cur_ty = context.m_ivars.get_type(*ty_ptr); + if( cur_ty.m_data.is_Infer() ) { + break; + } + auto cmp = dst_ty.compare_with_placeholders(sp, cur_ty, context.m_ivars.callback_resolve_infer()); + if( cmp != ::HIR::Compare::Unequal ) + { + // TODO: This is a deref coercion, so what can actually be done? + TODO(sp, "Handle Unsize with deref - " << src_ty << " -> " << dst_ty); + } + } + } +#endif + DEBUG("- Unsize, no deref or ivar"); } if( v.trait == context.m_crate.get_lang_item_path(sp, "coerce_unsized") ) { @@ -4974,7 +5046,7 @@ namespace { // > This makes `let v: usize = !0;` work without special cases auto cmp2 = v.left_ty.compare_with_placeholders(sp, out_ty, context.m_ivars.callback_resolve_infer()); if( cmp2 == ::HIR::Compare::Unequal ) { - DEBUG("- (fail) known result can't match (" << context.m_ivars.fmt_type(v.left_ty) << " and " << context.m_ivars.fmt_type(out_ty) << ")"); + DEBUG("[check_associated] - (fail) known result can't match (" << context.m_ivars.fmt_type(v.left_ty) << " and " << context.m_ivars.fmt_type(out_ty) << ")"); return false; } // if solid or fuzzy, leave as-is @@ -4993,9 +5065,10 @@ namespace { } else { count += 1; - DEBUG("- (possible) " << impl); + DEBUG("[check_associated] - (possible) " << impl); if( possible_impl_ty == ::HIR::TypeRef() ) { + DEBUG("[check_associated] First - " << impl); possible_impl_ty = impl.get_impl_type(); possible_params = impl.get_trait_params(); best_impl = mv$(impl); @@ -5006,27 +5079,33 @@ namespace { // NOTE: `overlaps_with` (should be) reflective else if( impl.overlaps_with(best_impl) ) { - DEBUG("- overlaps with " << best_impl); + DEBUG("[check_associated] - Overlaps with existing - " << best_impl); + // if not more specific than the existing best, ignore. if( ! impl.more_specific_than(best_impl) ) { + DEBUG("[check_associated] - Less specific than existing"); + // NOTE: This picks the _least_ specific impl possible_impl_ty = impl.get_impl_type(); possible_params = impl.get_trait_params(); best_impl = mv$(impl); count -= 1; } + // If the existing best is not more specific than the new one, use the new one else if( ! best_impl.more_specific_than(impl) ) { - // Ignore + DEBUG("[check_associated] - More specific than existing - " << impl); count -= 1; } else { - DEBUG("> Neither is more specific. Error?"); + // Supposedly, `more_specific_than` should be reflexive... + DEBUG("[check_associated] > Neither is more specific. Error?"); } } else { // Disjoint impls. + DEBUG("[check_associated] Disjoint impl -" << impl); } #endif @@ -5602,6 +5681,31 @@ namespace { // TODO: Monomorphise this type replacing mentions of the current ivar with the replacement? +#if 0 // NOTE: The following shouldn't happen + if( bound.trait == context.m_crate.get_lang_item_path(sp, "unsize") /* && bound.is_from_coerce*/ ) + { + bool possible = false; + + ::HIR::TypeRef tmp_ty; + const ::HIR::TypeRef* ty_ptr = &new_ty; + while( (ty_ptr = context.m_resolve.autoderef(sp, *ty_ptr, tmp_ty)) ) + { + const auto& cur_ty = context.get_type(*ty_ptr); + if( cur_ty.m_data.is_Infer() ) { + break; + } + auto cmp = ty_l.compare_with_placeholders(sp, cur_ty, context.m_ivars.callback_resolve_infer()); + if( cmp != ::HIR::Compare::Unequal ) + { + possible = true; + break; + } + } + if( possible ) + continue ; + } +#endif + // Search for any trait impl that could match this, bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;}); if( !has ) { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index a1c64bec..a3fe9b1c 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -469,6 +469,8 @@ void HMTypeInferrence::add_ivars(::HIR::TypeRef& type) (TraitObject, // Iterate all paths this->add_ivars_params(e.m_trait.m_path.m_params); + for(auto& aty : e.m_trait.m_type_bounds) + this->add_ivars(aty.second); for(auto& marker : e.m_markers) this->add_ivars_params(marker.m_params); ), @@ -1079,25 +1081,13 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& trait_indexmut = this->m_crate.get_lang_item_path(sp, "index_mut"); if( trait == lang_Sized ) { - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e), - ( - // Any unknown - it's sized - ), - (Primitive, - if( e == ::HIR::CoreType::Str ) - return false; - ), - (Slice, - return false; - ), - (Path, - // ... TODO (Search the innards or bounds) - ), - (TraitObject, + auto cmp = type_is_sized(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { return false; - ) - ) - return callback( ImplRef(&type, &null_params, &null_assoc), ::HIR::Compare::Equal ); + } } if( trait == lang_Copy ) { @@ -2155,7 +2145,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple if( e.trait.m_path.m_path == trait ) { // Check against `params` - DEBUG("Checking " << params << " vs " << b_params); + DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params); auto ord = cmp; ord &= this->compare_pp(sp, b_params, params); if( ord == ::HIR::Compare::Unequal ) @@ -2163,6 +2153,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple if( ord == ::HIR::Compare::Fuzzy ) { DEBUG("Fuzzy match"); } + DEBUG("[find_trait_impls_bound] Match " << b); // Hand off to the closure, and return true if it does // TODO: The type bounds are only the types that are specified. if( callback( ImplRef(&e.type, &e.trait.m_path.m_params, &e.trait.m_type_bounds), ord) ) { @@ -2814,6 +2805,23 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ) } + for(size_t i = 0; i < impl_params_def.m_types.size(); i ++) + { + if( impl_params_def.m_types.at(i).m_is_sized ) + { + if( impl_params[i] ) { + auto cmp = type_is_sized(sp, *impl_params[i]); + if( cmp == ::HIR::Compare::Unequal ) + { + return ::HIR::Compare::Unequal; + } + } + else { + // TODO: Set match to fuzzy? + } + } + } + return match; } @@ -2897,6 +2905,66 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa return false; } +::HIR::Compare TraitResolution::type_is_sized(const Span& sp, const ::HIR::TypeRef& type) const +{ + TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e), + ( + // Any unknown - it's sized + ), + (Infer, + switch(e.ty_class) + { + case ::HIR::InferClass::Integer: + case ::HIR::InferClass::Float: + return ::HIR::Compare::Equal; + default: + return ::HIR::Compare::Fuzzy; + } + ), + (Primitive, + if( e == ::HIR::CoreType::Str ) + return ::HIR::Compare::Unequal; + ), + (Slice, + return ::HIR::Compare::Unequal; + ), + (Path, + // ... TODO (Search the innards or bounds) + TU_MATCHA( (e.binding), (pb), + (Unbound, + // + ), + (Opaque, + // TODO: Check bounds + ), + (Enum, + // HAS to be Sized + ), + (Union, + // Pretty sure unions are Sized + ), + (Struct, + // Possibly not sized + switch( pb->m_markings.dst_type ) + { + case ::HIR::TraitMarkings::DstType::None: + break; + case ::HIR::TraitMarkings::DstType::Possible: + // TODO: Check sized-ness of the unsized param/field + break; + case ::HIR::TraitMarkings::DstType::Slice: + case ::HIR::TraitMarkings::DstType::TraitObject: + return ::HIR::Compare::Unequal; + } + ) + ) + ), + (TraitObject, + return ::HIR::Compare::Unequal; + ) + ) + return ::HIR::Compare::Equal; +} ::HIR::Compare TraitResolution::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const { const auto& type = this->m_ivars.get_type(ty); @@ -3284,6 +3352,12 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty else { bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "deref"), ::HIR::PathParams {}, ty, [&](auto impls, auto match) { tmp_type = impls.get_type("Target"); + if( tmp_type == ::HIR::TypeRef() ) + { + tmp_type = ::HIR::Path( ty.clone(), this->m_crate.get_lang_item_path(sp, "deref"), "Target" ); + tmp_type.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); + } + DEBUG("Deref " << ty << " into " << tmp_type); return true; }); if( succ ) { diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index b7e6ca38..d715905c 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -265,7 +265,9 @@ public: bool trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, AllowedReceivers ar, ::HIR::GenericPath& out_path) const; bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const; + ::HIR::Compare type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; ::HIR::Compare type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; + // If `new_type_callback` is populated, it will be called with the actual/possible dst_type // If `infer_callback` is populated, it will be called when either side is an ivar ::HIR::Compare can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty, ::std::function<void(::HIR::TypeRef new_dst)> new_type_callback) const { diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 8baa2557..d8b692c9 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -109,11 +109,13 @@ bool StaticTraitResolve::find_impl( return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); } } - //else if( trait_path == m_lang_Unsize ) { - // if( true ) { - // return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); - // } - //} + else if( trait_path == m_lang_Unsize ) { + ASSERT_BUG(sp, trait_params, "TODO: Support no params for Unzie"); + const auto& dst_ty = trait_params->m_types.at(0); + if( this->can_unsize(sp, dst_ty, type) ) { + return found_cb( ImplRef(&type, trait_params, &null_assoc), false ); + } + } } // --- MAGIC IMPLS --- @@ -1204,6 +1206,43 @@ bool StaticTraitResolve::iterate_bounds( ::std::function<bool(const ::HIR::Gener } return false; } + + +bool StaticTraitResolve::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const +{ + const auto& trait_ref = m_crate.get_trait_by_path(sp, pe.trait.m_path); + ASSERT_BUG(sp, trait_ref.m_types.count( pe.item ) != 0, "Trait " << pe.trait.m_path << " doesn't contain an associated type " << pe.item); + const auto& aty_def = trait_ref.m_types.find(pe.item)->second; + + for(const auto& bound : aty_def.m_trait_bounds) + { + if( cb(bound) ) + return true; + } + // Search `<Self as Trait>::Name` bounds on the trait itself + for(const auto& bound : trait_ref.m_params.m_bounds) + { + if( ! bound.is_TraitBound() ) continue ; + const auto& be = bound.as_TraitBound(); + + if( ! be.type.m_data.is_Path() ) continue ; + if( ! be.type.m_data.as_Path().binding.is_Opaque() ) continue ; + + const auto& be_type_pe = be.type.m_data.as_Path().path.m_data.as_UfcsKnown(); + if( *be_type_pe.type != ::HIR::TypeRef("Self", 0xFFFF) ) + continue ; + if( be_type_pe.trait.m_path != pe.trait.m_path ) + continue ; + if( be_type_pe.item != pe.item ) + continue ; + + if( cb(be.trait) ) + return true; + } + + return false; +} + // ------------------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------- @@ -1435,6 +1474,194 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) throw ""; } +bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty) const +{ + TRACE_FUNCTION_F(dst_ty << " <- " << src_ty); + + ASSERT_BUG(sp, !dst_ty.m_data.is_Infer(), "_ seen after inferrence - " << dst_ty); + ASSERT_BUG(sp, !src_ty.m_data.is_Infer(), "_ seen after inferrence - " << src_ty); + + { + //ASSERT_BUG(sp, dst_ty != src_ty, "Equal types for can_unsize - " << dst_ty << " <-" << src_ty ); + if( dst_ty == src_ty ) + return true; + } + + { + bool found_bound = this->iterate_bounds([&](const auto& gb){ + if(!gb.is_TraitBound()) + return false; + const auto& be = gb.as_TraitBound(); + if(be.trait.m_path.m_path != m_lang_Unsize) + return false; + const auto& be_dst = be.trait.m_path.m_params.m_types.at(0); + + if( src_ty != be.type ) return false; + if( dst_ty != be_dst ) return false; + return true; + }); + if( found_bound ) + { + return ::HIR::Compare::Equal; + } + } + + // Associated types, check the bounds in the trait. + if( src_ty.m_data.is_Path() && src_ty.m_data.as_Path().path.m_data.is_UfcsKnown() ) + { + const auto& pe = src_ty.m_data.as_Path().path.m_data.as_UfcsKnown(); + auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr); + auto found_bound = this->iterate_aty_bounds(sp, pe, [&](const ::HIR::TraitPath& bound) { + if( bound.m_path.m_path != m_lang_Unsize ) + return false; + const auto& be_dst_tpl = bound.m_path.m_params.m_types.at(0); + ::HIR::TypeRef tmp_ty; + const auto& be_dst = (monomorphise_type_needed(be_dst_tpl) ? tmp_ty = monomorphise_type_with(sp, be_dst_tpl, monomorph_cb) : be_dst_tpl); + + if( dst_ty != be_dst ) return false; + return true; + }); + if( found_bound ) + { + return true; + } + } + + // Struct<..., T, ...>: Unsize<Struct<..., U, ...>> + if( dst_ty.m_data.is_Path() && src_ty.m_data.is_Path() ) + { + bool dst_is_unsizable = dst_ty.m_data.as_Path().binding.is_Struct() && dst_ty.m_data.as_Path().binding.as_Struct()->m_markings.can_unsize; + bool src_is_unsizable = src_ty.m_data.as_Path().binding.is_Struct() && src_ty.m_data.as_Path().binding.as_Struct()->m_markings.can_unsize; + if( dst_is_unsizable || src_is_unsizable ) + { + DEBUG("Struct unsize? " << dst_ty << " <- " << src_ty); + const auto& str = *dst_ty.m_data.as_Path().binding.as_Struct(); + const auto& dst_gp = dst_ty.m_data.as_Path().path.m_data.as_Generic(); + const auto& src_gp = src_ty.m_data.as_Path().path.m_data.as_Generic(); + + if( dst_gp == src_gp ) + { + DEBUG("Can't Unsize, destination and source are identical"); + return false; + } + else if( dst_gp.m_path == src_gp.m_path ) + { + DEBUG("Checking for Unsize " << dst_gp << " <- " << src_gp); + // Structures are equal, add the requirement that the ?Sized parameter also impl Unsize + const auto& dst_inner = dst_gp.m_params.m_types.at(str.m_markings.unsized_param); + const auto& src_inner = src_gp.m_params.m_types.at(str.m_markings.unsized_param); + return this->can_unsize(sp, dst_inner, src_inner); + } + else + { + DEBUG("Can't Unsize, destination and source are different structs"); + return false; + } + } + } + + // (Trait) <- Foo + if( const auto* de = dst_ty.m_data.opt_TraitObject() ) + { + // TODO: Check if src_ty is !Sized + // - Only allowed if the source is a trait object with the same data trait and lesser bounds + + DEBUG("TraitObject unsize? " << dst_ty << " <- " << src_ty); + + // (Trait) <- (Trait+Foo) + if( const auto* se = src_ty.m_data.opt_TraitObject() ) + { + // 1. Data trait must be the same + if( de->m_trait != se->m_trait ) + { + return ::HIR::Compare::Unequal; + } + + // 2. Destination markers must be a strict subset + for(const auto& mt : de->m_markers) + { + bool found = false; + for(const auto& omt : se->m_markers) { + if( omt == mt ) { + found = true; + break; + } + } + if( !found ) { + // Return early. + return false; + } + } + + return true; + } + + bool good; + + ::HIR::TypeRef::Data::Data_TraitObject tmp_e; + tmp_e.m_trait.m_path = de->m_trait.m_path.m_path; + + // Check data trait first. + if( de->m_trait.m_path.m_path == ::HIR::SimplePath() ) { + ASSERT_BUG(sp, de->m_markers.size() > 0, "TraitObject with no traits - " << dst_ty); + good = true; + } + else { + good = false; + find_impl(sp, de->m_trait.m_path.m_path, de->m_trait.m_path.m_params, src_ty, + [&](const auto impl, auto fuzz) { + //ASSERT_BUG(sp, !fuzz, "Fuzzy match in can_unsize - " << dst_ty << " <- " << src_ty << " - " << impl); + good = true; + for(const auto& aty : de->m_trait.m_type_bounds) { + auto atyv = impl.get_type(aty.first.c_str()); + if( atyv == ::HIR::TypeRef() ) + { + // Get the trait from which this associated type comes. + // Insert a UfcsKnown path for that + auto p = ::HIR::Path( src_ty.clone(), de->m_trait.m_path.clone(), aty.first ); + // Run EAT + atyv = ::HIR::TypeRef::new_path( mv$(p), {} ); + } + this->expand_associated_types(sp, atyv); + if( aty.second != atyv ) { + good = false; + DEBUG("ATY " << aty.first << " mismatch - " << aty.second << " != " << atyv); + } + } + return true; + }); + } + + // Then markers + auto cb = [&](const auto impl, auto ){ + tmp_e.m_markers.back().m_params = impl.get_trait_params(); + return true; + }; + for(const auto& marker : de->m_markers) + { + if(!good) break; + tmp_e.m_markers.push_back( marker.m_path ); + good &= this->find_impl(sp, marker.m_path, marker.m_params, src_ty, cb); + } + + return good; + } + + // [T] <- [T; n] + if( const auto* de = dst_ty.m_data.opt_Slice() ) + { + if( const auto* se = src_ty.m_data.opt_Array() ) + { + DEBUG("Array unsize? " << *de->inner << " <- " << *se->inner); + return *se->inner == *de->inner; + } + } + + DEBUG("Can't unsize, no rules matched"); + return ::HIR::Compare::Unequal; + +} + bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const { // If `T: Copy`, then it can't need drop glue diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index 16302218..4c094218 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -170,6 +170,7 @@ public: ) const; /// bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const; + bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const; // -------------- @@ -177,6 +178,7 @@ public: // ------------- bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; bool type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; + bool can_unsize(const Span& sp, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) const; /// Returns `true` if the passed type either implements Drop, or contains a type that implements Drop bool type_needs_drop_glue(const Span& sp, const ::HIR::TypeRef& ty) const; diff --git a/src/main.cpp b/src/main.cpp index 8616ff2f..ec4e9f38 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -483,6 +483,7 @@ int main(int argc, char *argv[]) // - MIR Exportable (public generic, #[inline], or used by a either of those) // - Require codegen (public or used by an exported function) TransOptions trans_opt; + trans_opt.opt_level = params.opt_level; for(const char* libdir : params.lib_search_dirs ) { trans_opt.library_search_dirs.push_back( libdir ); } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index ceda0a87..d9796aed 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1723,6 +1723,16 @@ namespace { })); } + // rustc has drop_in_place as a lang item, mrustc uses an intrinsic + if( gpath.m_path == m_builder.crate().get_lang_item_path_opt("drop_in_place") ) + { + m_builder.end_block(::MIR::Terminator::make_Call({ + next_block, panic_block, + res.clone(), ::MIR::CallTarget::make_Intrinsic({ "drop_in_place", gpath.m_params.clone() }), + mv$(values) + })); + } + if( fcn.m_return.m_data.is_Diverge() ) { unconditional_diverge = true; @@ -1814,19 +1824,22 @@ namespace { ::std::stringstream(node.m_field) >> idx; m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); } - else if( val_ty.m_data.as_Path().binding.is_Struct() ) { - const auto& str = *node.m_value->m_res_type.m_data.as_Path().binding.as_Struct(); + else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) { + const auto& str = **bep; const auto& fields = str.m_data.as_Named(); idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); } - else { - const auto& unm = *node.m_value->m_res_type.m_data.as_Path().binding.as_Union(); + else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Union() ) { + const auto& unm = **bep; const auto& fields = unm.m_variants; idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); m_builder.set_result( node.span(), ::MIR::LValue::make_Downcast({ box$(val), idx }) ); } + else { + BUG(node.span(), "Field access on non-union/struct - " << val_ty); + } } void visit(::HIR::ExprNode_Literal& node) override { @@ -2075,6 +2088,14 @@ namespace { 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(); ) ) diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 9242ccb7..c38e73e9 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -106,31 +106,53 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return te[e.field_index]; ), (Path, - MIR_ASSERT(*this, te.binding.is_Struct(), "Field on non-Struct - " << ty); - const auto& str = *te.binding.as_Struct(); - auto monomorph = [&](const auto& ty)->const auto& { - if( monomorphise_type_needed(ty) ) { - tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return ty; - } - }; - TU_MATCHA( (str.m_data), (se), - (Unit, - MIR_BUG(*this, "Field on unit-like struct - " << ty); - ), - (Tuple, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path); - return monomorph(se[e.field_index].ent); - ), - (Named, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path); - return monomorph(se[e.field_index].second.ent); + if( const auto* tep = te.binding.opt_Struct() ) + { + const auto& str = **tep; + auto monomorph = [&](const auto& ty)->const auto& { + if( monomorphise_type_needed(ty) ) { + tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return ty; + } + }; + TU_MATCHA( (str.m_data), (se), + (Unit, + MIR_BUG(*this, "Field on unit-like struct - " << ty); + ), + (Tuple, + MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path); + return monomorph(se[e.field_index].ent); + ), + (Named, + MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path); + return monomorph(se[e.field_index].second.ent); + ) ) - ) + } + else if( const auto* tep = te.binding.opt_Union() ) + { + const auto& unm = **tep; + auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { + if( monomorphise_type_needed(t) ) { + tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return t; + } + }; + MIR_ASSERT(*this, e.field_index < unm.m_variants.size(), "Field index out of range for union"); + return maybe_monomorph(unm.m_variants.at(e.field_index).second.ent); + } + else + { + MIR_BUG(*this, "Field access on invalid type - " << ty); + } ) ) ), diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 8cb8c088..478146e8 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -814,6 +814,7 @@ void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cl drop_scope_values(scope_def); // Emit ScopeEnd for all controlled values + #if 0 ::MIR::Statement::Data_ScopeEnd se; if(const auto* e = scope_def.data.opt_Variables() ) { se.vars = e->vars; @@ -827,6 +828,7 @@ void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cl if( !se.vars.empty() || !se.tmps.empty() ) { this->push_stmt(sp, ::MIR::Statement( mv$(se) )); } + #endif } // 3. Pop scope (last because `drop_scope_values` uses the stack) @@ -1638,39 +1640,59 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: cb( *te.inner ); ), (Path, - ASSERT_BUG(sp, te.binding.is_Struct(), "Field on non-Struct - " << ty); - const auto& str = *te.binding.as_Struct(); - TU_MATCHA( (str.m_data), (se), - (Unit, - BUG(sp, "Field on unit-like struct - " << ty); - ), - (Tuple, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index]; - if( monomorphise_type_needed(fld.ent) ) { - auto sty = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, fld.ent); - m_resolve.expand_associated_types(sp, sty); - cb(sty); - } - else { - cb(fld.ent); - } - ), - (Named, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index].second; - if( monomorphise_type_needed(fld.ent) ) { - auto sty = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, fld.ent); - m_resolve.expand_associated_types(sp, sty); - cb(sty); - } - else { - cb(fld.ent); - } + ::HIR::TypeRef tmp; + if( const auto* tep = te.binding.opt_Struct() ) + { + const auto& str = **tep; + auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { + if( monomorphise_type_needed(t) ) { + tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, t); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return t; + } + }; + TU_MATCHA( (str.m_data), (se), + (Unit, + BUG(sp, "Field on unit-like struct - " << ty); + ), + (Tuple, + ASSERT_BUG(sp, e.field_index < se.size(), + "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size()); + const auto& fld = se[e.field_index]; + cb( maybe_monomorph(fld.ent) ); + ), + (Named, + ASSERT_BUG(sp, e.field_index < se.size(), + "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size()); + const auto& fld = se[e.field_index].second; + cb( maybe_monomorph(fld.ent) ); + ) ) - ) + } + else if( const auto* tep = te.binding.opt_Union() ) + { + BUG(sp, "Field access on a union isn't valid, use Downcast instead - " << ty); + const auto& unm = **tep; + auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { + if( monomorphise_type_needed(t) ) { + tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return t; + } + }; + ASSERT_BUG(sp, e.field_index < unm.m_variants.size(), "Field index out of range for union"); + cb( maybe_monomorph(unm.m_variants.at(e.field_index).second.ent) ); + } + else + { + BUG(sp, "Field acess on unexpected type - " << ty); + } ), (Tuple, ASSERT_BUG(sp, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size()); @@ -2196,8 +2218,10 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR ), (Partial, bool is_enum = false; + bool is_union = false; with_val_type(sp, lv, [&](const auto& ty){ is_enum = ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum(); + is_union = ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Union(); }); if(is_enum) { @@ -2207,6 +2231,10 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR // drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) })); //} } + else if( is_union ) + { + // NOTE: Unions don't drop inner items. + } else { for(size_t i = 0; i < vse.inner_states.size(); i ++) diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 3b5fa036..8e350c45 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -390,6 +390,58 @@ namespace { ) return nullptr; } + + + void visit_blocks_mut(::MIR::TypeResolve& state, ::MIR::Function& fcn, ::std::function<void(::MIR::BasicBlockId, ::MIR::BasicBlock&)> cb) + { + ::std::vector<bool> visited( fcn.blocks.size() ); + ::std::vector< ::MIR::BasicBlockId> to_visit; + to_visit.push_back( 0 ); + while( to_visit.size() > 0 ) + { + auto bb = to_visit.back(); to_visit.pop_back(); + if( visited[bb] ) continue; + visited[bb] = true; + auto& block = fcn.blocks[bb]; + + cb(bb, block); + + TU_MATCHA( (block.terminator), (e), + (Incomplete, + ), + (Return, + ), + (Diverge, + ), + (Goto, + if( !visited[e] ) + to_visit.push_back(e); + ), + (Panic, + ), + (If, + if( !visited[e.bb0] ) + to_visit.push_back(e.bb0); + if( !visited[e.bb1] ) + to_visit.push_back(e.bb1); + ), + (Switch, + for(auto& target : e.targets) + if( !visited[target] ) + to_visit.push_back(target); + ), + (Call, + if( !visited[e.ret_block] ) + to_visit.push_back(e.ret_block); + if( !visited[e.panic_block] ) + to_visit.push_back(e.panic_block); + ) + ) + } + } + void visit_blocks(::MIR::TypeResolve& state, const ::MIR::Function& fcn, ::std::function<void(::MIR::BasicBlockId, const ::MIR::BasicBlock&)> cb) { + visit_blocks_mut(state, const_cast<::MIR::Function&>(fcn), [cb](auto id, auto& blk){ cb(id, blk); }); + } } bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn); @@ -398,6 +450,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_DeadDropFlags(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn); @@ -445,6 +498,9 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // >> Combine Duplicate Blocks change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); + // >> Remove assignments of unsed drop flags + change_happened |= MIR_Optimise_DeadDropFlags(state, fcn); + if( change_happened ) { #if DUMP_AFTER_PASS @@ -2231,6 +2287,45 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F return replacement_happend; } +// ---------------------------------------- +// Clear all drop flags that are never read +// ---------------------------------------- +bool MIR_Optimise_DeadDropFlags(::MIR::TypeResolve& state, ::MIR::Function& fcn) +{ + ::std::vector<bool> read_drop_flags( fcn.drop_flags.size() ); + visit_blocks(state, fcn, [&read_drop_flags](auto , const ::MIR::BasicBlock& block) { + for(const auto& stmt : block.statements) + { + if( const auto* e = stmt.opt_SetDropFlag() ) + { + if(e->other != ~0u) { + read_drop_flags[e->other] = true; + } + } + else if( const auto* e = stmt.opt_Drop() ) + { + if(e->flag_idx != ~0u) { + read_drop_flags[e->flag_idx] = true; + } + } + } + }); + bool removed_statement = false; + visit_blocks_mut(state, fcn, [&read_drop_flags,&removed_statement](auto _id, auto& block) { + for(auto it = block.statements.begin(); it != block.statements.end(); ) + { + if(it->is_SetDropFlag() && ! read_drop_flags[it->as_SetDropFlag().idx] ) { + removed_statement = true; + it = block.statements.erase(it); + } + else { + ++ it; + } + } + }); + return removed_statement; +} + // -------------------------------------------------------------------- // Clear all unused blocks @@ -2238,47 +2333,10 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn) { ::std::vector<bool> visited( fcn.blocks.size() ); - ::std::vector< ::MIR::BasicBlockId> to_visit; - to_visit.push_back( 0 ); - while( to_visit.size() > 0 ) - { - auto bb = to_visit.back(); to_visit.pop_back(); - if( visited[bb] ) continue; - visited[bb] = true; - const auto& block = fcn.blocks[bb]; - - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, - if( !visited[e] ) - to_visit.push_back(e); - ), - (Panic, - ), - (If, - if( !visited[e.bb0] ) - to_visit.push_back(e.bb0); - if( !visited[e.bb1] ) - to_visit.push_back(e.bb1); - ), - (Switch, - for(auto& target : e.targets) - if( !visited[target] ) - to_visit.push_back(target); - ), - (Call, - if( !visited[e.ret_block] ) - to_visit.push_back(e.ret_block); - if( !visited[e.panic_block] ) - to_visit.push_back(e.panic_block); - ) - ) - } + visit_blocks(state, fcn, [&visited](auto bb, const auto& _blokc) { + assert( !visited[bb] ); + visited[bb] = true; + }); bool rv = false; for(unsigned int i = 0; i < visited.size(); i ++) { @@ -2301,13 +2359,9 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn ::std::vector<bool> used_vars( fcn.named_variables.size() ); ::std::vector<bool> used_dfs( fcn.drop_flags.size() ); ::std::vector<bool> visited( fcn.blocks.size() ); - ::std::vector< ::MIR::BasicBlockId> to_visit; - to_visit.push_back( 0 ); - while( to_visit.size() > 0 ) - { - auto bb = to_visit.back(); to_visit.pop_back(); + + visit_blocks(state, fcn, [&](auto bb, const auto& block) { visited[bb] = true; - const auto& block = fcn.blocks[bb]; auto assigned_lval = [&](const ::MIR::LValue& lv) { if(const auto* le = lv.opt_Temporary() ) @@ -2339,40 +2393,11 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn } } - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, - if( !visited[e] ) - to_visit.push_back(e); - ), - (Panic, - ), - (If, - if( !visited[e.bb0] ) - to_visit.push_back(e.bb0); - if( !visited[e.bb1] ) - to_visit.push_back(e.bb1); - ), - (Switch, - for(auto& target : e.targets) - if( !visited[target] ) - to_visit.push_back(target); - ), - (Call, - if( !visited[e.ret_block] ) - to_visit.push_back(e.ret_block); - if( !visited[e.panic_block] ) - to_visit.push_back(e.panic_block); - - assigned_lval(e.ret_val); - ) - ) - } + if( const auto* te = block.terminator.opt_Call() ) + { + assigned_lval(te->ret_val); + } + }); ::std::vector<unsigned int> block_rewrite_table; for(unsigned int i = 0, j = 0; i < fcn.blocks.size(); i ++) diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index bc17ea9e..28729b93 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -999,9 +999,18 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path) while( GET_TOK(tok, lex) == TOK_IDENT ) { auto name = mv$(tok.str()); - GET_CHECK_TOK(tok, lex, TOK_COLON); - ExprNodeP val = Parse_Stmt(lex); - items.push_back( ::std::make_pair(::std::move(name), ::std::move(val)) ); + + if( lex.lookahead(0) != TOK_COLON ) + { + ExprNodeP val = NEWNODE( AST::ExprNode_NamedValue, ::AST::Path(name) ); + items.push_back( ::std::make_pair(::std::move(name), ::std::move(val)) ); + } + else + { + GET_CHECK_TOK(tok, lex, TOK_COLON); + ExprNodeP val = Parse_Stmt(lex); + items.push_back( ::std::make_pair(::std::move(name), ::std::move(val)) ); + } if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE ) break; diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index a92753d8..0587e443 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -466,11 +466,13 @@ Token Lexer::getTokenInt() else if(suffix == "i16") num_type = CORETYPE_I16; else if(suffix == "i32") num_type = CORETYPE_I32; else if(suffix == "i64") num_type = CORETYPE_I64; + else if(suffix == "i128") num_type = CORETYPE_I128; else if(suffix == "isize") num_type = CORETYPE_INT; else if(suffix == "u8") num_type = CORETYPE_U8; else if(suffix == "u16") num_type = CORETYPE_U16; else if(suffix == "u32") num_type = CORETYPE_U32; else if(suffix == "u64") num_type = CORETYPE_U64; + else if(suffix == "u128") num_type = CORETYPE_U128; else if(suffix == "usize") num_type = CORETYPE_UINT; else if(suffix == "f32") num_type = CORETYPE_F32; else if(suffix == "f64") num_type = CORETYPE_F64; diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 3bdd34b1..5f8ed0a3 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -563,7 +563,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items) else if(tok.type() == TOK_SEMICOLON) { // Unit-like struct - return AST::Struct(mv$(params), ::std::vector<AST::TupleItem>()); + return AST::Struct(mv$(params)); } else if(tok.type() == TOK_BRACE_OPEN) { @@ -594,7 +594,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items) } //if( items.size() == 0 ) // WARNING( , W000, "Use 'struct Name;' instead of 'struct Nam { };' ... ning-nong"); - return AST::Struct(::std::move(params), ::std::move(items)); + return AST::Struct(mv$(params), mv$(items)); } else { @@ -824,6 +824,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items) CHECK_TOK(tok, TOK_IDENT); ::std::string name = mv$(tok.str()); + // Tuple-like variants if( GET_TOK(tok, lex) == TOK_PAREN_OPEN ) { ::std::vector<TypeRef> types; @@ -850,6 +851,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items) GET_TOK(tok, lex); variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(types)) ); } + // Struct-like variants else if( tok.type() == TOK_BRACE_OPEN ) { ::std::vector<::AST::StructItem> fields; @@ -880,12 +882,14 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items) variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(fields)) ); } + // Value variants else if( tok.type() == TOK_EQUAL ) { auto node = Parse_Expr(lex); variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(node)) ); GET_TOK(tok, lex); } + // Unit variants else { variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), ::AST::Expr()) ); diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index db85ed3f..26a45a1e 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1020,7 +1020,7 @@ namespace { } break; } - ERROR(sp, E0000, "Couldn't find path component '" << path_abs.nodes.back().name() << "' of " << path); + ERROR(sp, E0000, "Couldn't find " << Context::lookup_mode_msg(mode) << " '" << path_abs.nodes.back().name() << "' of " << path); } } @@ -1946,6 +1946,8 @@ void Resolve_Absolute_Struct(Context& item_context, ::AST::Struct& e) Resolve_Absolute_Generic(item_context, e.params()); TU_MATCH(::AST::StructData, (e.m_data), (s), + (Unit, + ), (Tuple, for(auto& field : s.ents) { Resolve_Absolute_Type(item_context, field.m_type); diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index 7b988bc0..f57fc3e6 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -149,7 +149,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) (Struct, p.bind( ::AST::PathBinding::make_Struct({&e}) ); // - If the struct is a tuple-like struct (or unit-like), it presents in the value namespace - if( e.m_data.is_Tuple() ) { + if( ! e.m_data.is_Struct() ) { _add_item_value(i.data.span, mod, i.name, i.is_pub, p); } _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p)); @@ -209,15 +209,9 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); // - If the struct is a tuple-like struct, it presents in the value namespace assert(e.struct_ || e.hir); - if( e.struct_ ) { - if( e.struct_->m_data.is_Tuple() ) { - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); - } - } - else { - if( ! e.hir->m_data.is_Named() ) { - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); - } + if( !(e.struct_ ? e.struct_->m_data.is_Struct() : e.hir->m_data.is_Named()) ) + { + _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); } ), (Static , _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ), diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp index 7989981b..a571b5e4 100644 --- a/src/trans/codegen.cpp +++ b/src/trans/codegen.cpp @@ -87,16 +87,18 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const { DEBUG("FUNCTION " << ent.first); assert( ent.second->ptr ); - if( ent.second->ptr->m_code.m_mir ) { - codegen->emit_function_proto(ent.first, *ent.second->ptr, ent.second->pp); + const auto& fcn = *ent.second->ptr; + bool is_extern = ! static_cast<bool>(fcn.m_code); + if( fcn.m_code.m_mir ) { + codegen->emit_function_proto(ent.first, fcn, ent.second->pp, is_extern); } else { // TODO: Why would an intrinsic be in the queue? // - If it's exported it does. - if( ent.second->ptr->m_abi == "rust-intrinsic" ) { + if( fcn.m_abi == "rust-intrinsic" ) { } else { - codegen->emit_function_ext(ent.first, *ent.second->ptr, ent.second->pp); + codegen->emit_function_ext(ent.first, fcn, ent.second->pp); } } } @@ -148,7 +150,8 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const const auto& pp = ent.second->pp; TRACE_FUNCTION_F(path); DEBUG("FUNCTION CODE " << path); - // TODO: If this is a provided trait method, it needs to be monomorphised too. + bool is_extern = ! static_cast<bool>(fcn.m_code); + // If this is a provided trait method, it needs to be monomorphised too. bool is_method = ( fcn.m_args.size() > 0 && visit_ty_with(fcn.m_args[0].second, [&](const auto& x){return x == ::HIR::TypeRef("Self",0xFFFF);}) ); if( pp.has_types() || is_method ) { @@ -164,11 +167,14 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const MIR_Cleanup(resolve, ip, *mir, args, ret_type); MIR_Optimise(resolve, ip, *mir, args, ret_type); MIR_Validate(resolve, ip, *mir, args, ret_type); - codegen->emit_function_code(path, fcn, ent.second->pp, mir); + // TODO: Flag that this should be a weak (or weak-er) symbol? + // - If it's from an external crate, it should be weak + codegen->emit_function_code(path, fcn, ent.second->pp, is_extern, mir); } // TODO: Detect if the function was a #[inline] function from another crate, and don't emit if that is the case? + // - Emiting is nice, but it should be emitted as a weak symbol else { - codegen->emit_function_code(path, fcn, pp, fcn.m_code.m_mir); + codegen->emit_function_code(path, fcn, pp, is_extern, fcn.m_code.m_mir); } } } diff --git a/src/trans/codegen.hpp b/src/trans/codegen.hpp index b317e632..65135d18 100644 --- a/src/trans/codegen.hpp +++ b/src/trans/codegen.hpp @@ -50,8 +50,8 @@ public: virtual void emit_static_local(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) {} virtual void emit_function_ext(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) {} - virtual void emit_function_proto(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) {} - virtual void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, const ::MIR::FunctionPointer& code) {} + virtual void emit_function_proto(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, bool is_extern_def) {} + virtual void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, bool is_extern_def, const ::MIR::FunctionPointer& code) {} }; diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 2d7a521d..946c7fac 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -119,13 +119,13 @@ namespace { auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start"); if( c_start_path == ::HIR::SimplePath() ) { - m_of << "\t" << Trans_Mangle( ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "start")) ) << "(" + m_of << "\treturn " << Trans_Mangle( ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "start")) ) << "(" << "(uint8_t*)" << Trans_Mangle( ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "mrustc-main")) ) << ", argc, (uint8_t**)argv" << ");\n"; } else { - m_of << "\t" << Trans_Mangle(::HIR::GenericPath(c_start_path)) << "(argc, argv);\n"; + m_of << "\treturn " << Trans_Mangle(::HIR::GenericPath(c_start_path)) << "(argc, argv);\n"; } m_of << "}\n"; } @@ -195,7 +195,8 @@ namespace { // TODO: use a formatter specific to shell escaping cmd_ss << "\"" << FmtEscaped(arg) << "\" "; } - DEBUG("- " << cmd_ss.str()); + //DEBUG("- " << cmd_ss.str()); + ::std::cout << "Running comamnd - " << cmd_ss.str() << ::std::endl; if( system(cmd_ss.str().c_str()) ) { abort(); @@ -425,6 +426,8 @@ namespace { ::std::vector< ::std::pair<::HIR::Pattern,::HIR::TypeRef> > args; if( item.m_markings.has_drop_impl ) { + if( p.m_path.m_crate_name != m_crate.m_crate_name ) + m_of << "static "; m_of << "tUNIT " << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n"; } else if( m_resolve.is_type_owned_box(struct_ty) ) @@ -1062,7 +1065,15 @@ namespace { } ), (Float, - m_of << e; + if( ::std::isnan(e) ) { + m_of << "NAN"; + } + else if( ::std::isinf(e) ) { + m_of << "INFINITY"; + } + else { + m_of << e; + } ), (BorrowOf, TU_MATCHA( (e.m_data), (pe), @@ -1246,7 +1257,7 @@ namespace { m_mir_res = nullptr; } - void emit_function_proto(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) override + void emit_function_proto(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, bool is_extern_def) override { ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "/*proto*/ fn " << p;), ::HIR::TypeRef(), {}, *(::MIR::Function*)nullptr }; m_mir_res = &top_mir_res; @@ -1256,12 +1267,16 @@ namespace { { m_of << "#define " << Trans_Mangle(p) << " " << item.m_linkage.name << "\n"; } + if( is_extern_def ) + { + m_of << "static "; + } emit_function_header(p, item, params); m_of << ";\n"; m_mir_res = nullptr; } - void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, const ::MIR::FunctionPointer& code) override + void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, bool is_extern_def, const ::MIR::FunctionPointer& code) override { TRACE_FUNCTION_F(p); @@ -1276,6 +1291,9 @@ namespace { m_mir_res = &mir_res; m_of << "// " << p << "\n"; + if( is_extern_def ) { + m_of << "static "; + } emit_function_header(p, item, params); m_of << "\n"; m_of << "{\n"; @@ -2186,18 +2204,23 @@ namespace { switch( ty.m_data.as_Primitive() ) { case ::HIR::CoreType::U8: + case ::HIR::CoreType::I8: emit_lvalue(e.ret_val); m_of << " = "; emit_param(e.args.at(0)); break; case ::HIR::CoreType::U16: + case ::HIR::CoreType::I16: emit_lvalue(e.ret_val); m_of << " = __builtin_bswap16("; emit_param(e.args.at(0)); m_of << ")"; break; case ::HIR::CoreType::U32: + case ::HIR::CoreType::I32: emit_lvalue(e.ret_val); m_of << " = __builtin_bswap32("; emit_param(e.args.at(0)); m_of << ")"; break; case ::HIR::CoreType::U64: + case ::HIR::CoreType::I64: emit_lvalue(e.ret_val); m_of << " = __builtin_bswap64("; emit_param(e.args.at(0)); m_of << ")"; break; case ::HIR::CoreType::U128: + case ::HIR::CoreType::I128: emit_lvalue(e.ret_val); m_of << " = __builtin_bswap128("; emit_param(e.args.at(0)); m_of << ")"; break; default: @@ -2273,6 +2296,12 @@ namespace { else if( name == "unchecked_rem" ) { emit_lvalue(e.ret_val); m_of << " = "; emit_param(e.args.at(0)); m_of << " % "; emit_param(e.args.at(1)); } + else if( name == "unchecked_shl" ) { + emit_lvalue(e.ret_val); m_of << " = "; emit_param(e.args.at(0)); m_of << " << "; emit_param(e.args.at(1)); + } + else if( name == "unchecked_shr" ) { + emit_lvalue(e.ret_val); m_of << " = "; emit_param(e.args.at(0)); m_of << " >> "; emit_param(e.args.at(1)); + } // Bit Twiddling // - CounT Leading Zeroes // - CounT Trailing Zeroes @@ -2463,6 +2492,9 @@ namespace { auto ordering = H::get_atomic_ordering(mir_res, name, 7+6); m_of << "atomic_thread_fence(" << ordering << ")"; } + else if( name == "atomic_singlethreadfence" || name.compare(0, 7+18, "atomic_singlethreadfence_") == 0 ) { + // TODO: Does this matter? + } else { MIR_BUG(mir_res, "Unknown intrinsic '" << name << "'"); } @@ -2718,7 +2750,8 @@ namespace { emit_literal(ty, lit, {}); ), (Float, - emit_dst(); m_of << " = " << e; + emit_dst(); m_of << " = "; + emit_literal(ty, lit, {}); ), (BorrowOf, if( ty.m_data.is_Function() ) diff --git a/src/trans/mangling.cpp b/src/trans/mangling.cpp index 4ea56581..0f3acfd9 100644 --- a/src/trans/mangling.cpp +++ b/src/trans/mangling.cpp @@ -148,7 +148,7 @@ namespace { ), (Tuple, return FMT_CB(ss, - ss << "$T"; + ss << "$T" << te.size(); for(const auto& t : te) ss << "_" << Trans_Mangle(t); ); |