diff options
Diffstat (limited to 'src')
41 files changed, 1091 insertions, 180 deletions
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 0a43cc71..f78d559f 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -8,6 +8,8 @@ #ifndef AST_HPP_INCLUDED #define AST_HPP_INCLUDED +#include <target_version.hpp> + #include <string> #include <vector> #include <stdexcept> @@ -44,6 +46,8 @@ enum eItemType { ITEM_TRAIT, ITEM_STRUCT, + ITEM_ENUM, + ITEM_UNION, ITEM_FN, ITEM_STATIC, }; diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp index 0e1c8149..a15b4175 100644 --- a/src/ast/attrs.hpp +++ b/src/ast/attrs.hpp @@ -77,6 +77,7 @@ class Attribute ::std::string m_name; AttributeData m_data; mutable bool m_is_used; + // TODO: Parse as a TT then expand? public: Attribute(Span sp, ::std::string name): m_span(::std::move(sp)), diff --git a/src/ast/path.hpp b/src/ast/path.hpp index c2d13d73..2693a070 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -271,6 +271,10 @@ public: return Path(*this) += x; } Path& operator+=(const Path& x); + Path& operator+=(PathNode pn) { + this->nodes().push_back( mv$(pn) ); + return *this; + } void append(PathNode node) { assert( !m_class.is_Invalid() ); diff --git a/src/expand/assert.cpp b/src/expand/assert.cpp new file mode 100644 index 00000000..1c057935 --- /dev/null +++ b/src/expand/assert.cpp @@ -0,0 +1,89 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * expand/assert.cpp + * - assert! built-in macro (1.29) + */ +#include <synext_macro.hpp> +#include <synext.hpp> // for Expand_BareExpr +#include <parse/interpolated_fragment.hpp> +#include "../parse/ttstream.hpp" +#include "../parse/common.hpp" +#include "../parse/parseerror.hpp" + +class CExpander_assert: + public ExpandProcMacro +{ + ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + { + Token tok; + + auto lex = TTStream(sp, tt); + lex.parse_state().module = &mod; + if( ident != "" ) + ERROR(sp, E0000, "format_args! doesn't take an ident"); + + // assertion condition + auto n = Parse_Expr0(lex); + ASSERT_BUG(sp, n, "No expression returned"); + + ::std::vector<TokenTree> toks; + + toks.push_back( Token(TOK_RWORD_IF) ); + + GET_TOK(tok, lex); + if( tok == TOK_COMMA ) + { + toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())) ); + toks.push_back( Token(TOK_BRACE_OPEN) ); + // User-provided message + toks.push_back( Token(TOK_IDENT, "panic") ); + toks.push_back( Token(TOK_EXCLAM) ); + toks.push_back( Token(TOK_PAREN_OPEN) ); + while(lex.lookahead(0) != TOK_EOF ) + { + toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, Parse_Expr0(lex).release())) ); + if( lex.lookahead(0) != TOK_COMMA ) + break; + GET_CHECK_TOK(tok, lex, TOK_COMMA); + toks.push_back( Token(TOK_COMMA) ); + } + GET_CHECK_TOK(tok, lex, TOK_EOF); + toks.push_back( Token(TOK_PAREN_CLOSE) ); + } + else if( tok == TOK_EOF ) + { + ::std::stringstream ss; + ss << "assertion failed: "; + n->print(ss); + + toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())) ); + + toks.push_back( Token(TOK_BRACE_OPEN) ); + // Auto-generated message + toks.push_back( Token(TOK_IDENT, "panic") ); + toks.push_back( Token(TOK_EXCLAM) ); + toks.push_back( Token(TOK_PAREN_OPEN) ); + toks.push_back( Token(TOK_STRING, ss.str()) ); + toks.push_back( Token(TOK_PAREN_CLOSE) ); + } + else + { + throw ParseError::Unexpected(lex, tok, {TOK_COMMA, TOK_EOF}); + } + + toks.push_back( Token(TOK_BRACE_CLOSE) ); + + return box$( TTStreamO(sp, TokenTree(Ident::Hygiene::new_scope(), mv$(toks))) ); + } +}; + +void Expand_init_assert() +{ + if( TARGETVER_1_29 ) + { + Register_Synext_Macro("assert", ::std::unique_ptr<ExpandProcMacro>(new CExpander_assert)); + } +} + diff --git a/src/expand/file_line.cpp b/src/expand/file_line.cpp index 7a827ccf..2bf85ffd 100644 --- a/src/expand/file_line.cpp +++ b/src/expand/file_line.cpp @@ -46,6 +46,14 @@ class CExpanderColumn: return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) ); } }; +class CExpanderUnstableColumn: + public ExpandProcMacro +{ + ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + { + return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) ); + } +}; class CExpanderModulePath: public ExpandProcMacro @@ -65,5 +73,6 @@ class CExpanderModulePath: STATIC_MACRO("file", CExpanderFile); STATIC_MACRO("line", CExpanderLine); STATIC_MACRO("column", CExpanderColumn); +STATIC_MACRO("__rust_unstable_column", CExpanderUnstableColumn); STATIC_MACRO("module_path", CExpanderModulePath); diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index 789ad88e..0bdd37e5 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -30,6 +30,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "copy" ) { DEBUG("Bind 'copy' to " << path); } + else if( TARGETVER_1_29 && name == "clone" ) {} // - Trait // ops traits else if( name == "drop" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "add" ) { DEBUG("Bind '"<<name<<"' to " << path); } @@ -67,7 +68,8 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "fn_once" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "eq" ) { DEBUG("Bind '"<<name<<"' to " << path); } - else if( name == "ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } + else if( TARGETVER_1_19 && name == "ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } + else if( TARGETVER_1_29 && name == "partial_ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } // New name for v1.29 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); } @@ -84,6 +86,13 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "range_from" ) { } else if( name == "range_to" ) { } else if( name == "unsafe_cell" ) { } + else if( TARGETVER_1_29 && name == "alloc_layout") { } + else if( TARGETVER_1_29 && name == "panic_info" ) {} // Struct + else if( TARGETVER_1_29 && name == "manually_drop" ) {} // Struct + + // Generators + else if( TARGETVER_1_29 && name == "generator" ) {} // - Trait + else if( TARGETVER_1_29 && name == "generator_state" ) {} // - State enum // Statics else if( name == "msvc_try_filter" ) { } @@ -96,6 +105,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" ) { } + else if( name == "align_offset" ) { } // - builtin `box` support else if( name == "exchange_malloc" ) { } else if( name == "exchange_free" ) { } @@ -105,6 +115,32 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "start" ) { } else if( name == "eh_personality" ) { } + // libcompiler_builtins + // - i128/u128 helpers (not used by mrustc) + else if( name == "i128_add" ) { } + else if( name == "i128_addo" ) { } + else if( name == "u128_add" ) { } + else if( name == "u128_addo" ) { } + else if( name == "i128_sub" ) { } + else if( name == "i128_subo" ) { } + else if( name == "u128_sub" ) { } + else if( name == "u128_subo" ) { } + else if( name == "i128_mul" ) { } + else if( name == "i128_mulo" ) { } + else if( name == "u128_mul" ) { } + else if( name == "u128_mulo" ) { } + else if( name == "i128_div" ) { } + else if( name == "i128_rem" ) { } + else if( name == "u128_div" ) { } + else if( name == "u128_rem" ) { } + else if( name == "i128_shl" ) { } + else if( name == "i128_shlo" ) { } + else if( name == "u128_shl" ) { } + else if( name == "u128_shlo" ) { } + else if( name == "i128_shr" ) { } + else if( name == "i128_shro" ) { } + else if( name == "u128_shr" ) { } + else if( name == "u128_shro" ) { } else { ERROR(sp, E0000, "Unknown language item '" << name << "'"); @@ -148,6 +184,9 @@ public: (Struct, handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_STRUCT); ), + (Enum, + handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_ENUM); + ), (Trait, handle_lang_item(sp, crate, path, attr.string(), AST::ITEM_TRAIT); ) @@ -176,6 +215,7 @@ public: // collections else if( name == "str" ) {} else if( name == "slice" ) {} + else if( TARGETVER_1_29 && name == "slice_u8" ) {} // std - interestingly else if( name == "f32" ) {} else if( name == "f64" ) {} diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 5d6d3234..66a7308a 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -41,6 +41,12 @@ void Register_Synext_Macro_Static(MacroDef* def) { g_macros_list = def; } +void Expand_Init() +{ + // TODO: Initialise all macros here. + void Expand_init_assert(); Expand_init_assert(); +} + void ExpandDecorator::unexpected(const Span& sp, const AST::Attribute& mi, const char* loc_str) const { @@ -86,7 +92,7 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c Expand_Attrs(attrs, stage, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, mod, impl); }); } -::std::unique_ptr<TokenStream> Expand_Macro( +::std::unique_ptr<TokenStream> Expand_Macro_Inner( const ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Module& mod, Span mi_span, const ::std::string& name, const ::std::string& input_ident, TokenTree& input_tt ) @@ -144,6 +150,17 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c // Error - Unknown macro name ERROR(mi_span, E0000, "Unknown macro '" << name << "'"); } +::std::unique_ptr<TokenStream> Expand_Macro( + const ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Module& mod, + Span mi_span, const ::std::string& name, const ::std::string& input_ident, TokenTree& input_tt + ) +{ + auto rv = Expand_Macro_Inner(crate, modstack, mod, mi_span, name, input_ident, input_tt); + assert(rv); + rv->parse_state().module = &mod; + rv->parse_state().crate = &crate; + return rv; +} ::std::unique_ptr<TokenStream> Expand_Macro(const ::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Module& mod, ::AST::MacroInvocation& mi) { return Expand_Macro(crate, modstack, mod, mi.span(), mi.name(), mi.input_ident(), mi.input_tt()); @@ -755,6 +772,7 @@ struct CExpandExpr: case ::AST::ExprNode_BinOp::RANGE_INC: { // NOTE: Not language items auto core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core"); + auto path_None = ::AST::Path(core_crate, { ::AST::PathNode("option"), ::AST::PathNode("Option"), ::AST::PathNode("None") }); auto path_RangeInclusive_NonEmpty = ::AST::Path(core_crate, { ::AST::PathNode("ops"), ::AST::PathNode("RangeInclusive") }); auto path_RangeToInclusive = ::AST::Path(core_crate, { ::AST::PathNode("ops"), ::AST::PathNode("RangeToInclusive") }); @@ -763,6 +781,7 @@ struct CExpandExpr: ::AST::ExprNode_StructLiteral::t_values values; values.push_back({ {}, "start", mv$(node.m_left) }); values.push_back({ {}, "end" , mv$(node.m_right) }); + values.push_back({ {}, "is_empty", ::AST::ExprNodeP(new ::AST::ExprNode_NamedValue(mv$(path_None))) }); replacement.reset( new ::AST::ExprNode_StructLiteral(mv$(path_RangeInclusive_NonEmpty), nullptr, mv$(values)) ); } else @@ -786,12 +805,19 @@ struct CExpandExpr: auto path_Err = ::AST::Path(core_crate, {::AST::PathNode("result"), ::AST::PathNode("Result"), ::AST::PathNode("Err")}); auto path_From = ::AST::Path(core_crate, {::AST::PathNode("convert"), ::AST::PathNode("From")}); path_From.nodes().back().args().m_types.push_back( ::TypeRef(node.span()) ); + // TODO: Lang item (needs lang items enumerated earlier) + //auto it = crate.m_lang_items.find("try"); + //ASSERT_BUG(node.span(), it != crate.m_lang_items.end(), "Can't find the `try` lang item"); + //auto path_Try = it->second; + auto path_Try = ::AST::Path(core_crate, {::AST::PathNode("ops"), ::AST::PathNode("Try")}); + auto path_Try_into_result = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), path_Try, { ::AST::PathNode("into_result") }); + auto path_Try_from_error = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), path_Try, { ::AST::PathNode("from_error") }); // Desugars into // ``` - // match `m_value` { + // match `Try::into_result(m_value)` { // Ok(v) => v, - // Err(e) => return Err(From::from(e)), + // Err(e) => return Try::from_error(From::from(e)), // } // ``` @@ -802,7 +828,7 @@ struct CExpandExpr: nullptr, ::AST::ExprNodeP( new ::AST::ExprNode_NamedValue( ::AST::Path(::AST::Path::TagLocal(), "v") ) ) )); - // `Err(e) => return Err(From::from(e)),` + // `Err(e) => return Try::from_error(From::from(e)),` arms.push_back(::AST::ExprNode_Match_Arm( ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), node.span(), path_Err, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), node.span(), "e") )) ), nullptr, @@ -810,7 +836,7 @@ struct CExpandExpr: ::AST::ExprNode_Flow::RETURN, "", ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( - ::AST::Path(path_Err), + ::AST::Path(path_Try_from_error), ::make_vec1( ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), mv$(path_From), { ::AST::PathNode("from") }), @@ -821,7 +847,13 @@ struct CExpandExpr: )) )); - replacement.reset(new ::AST::ExprNode_Match( mv$(node.m_value), mv$(arms) )); + replacement.reset(new ::AST::ExprNode_Match( + ::AST::ExprNodeP(new AST::ExprNode_CallPath( + mv$(path_Try_into_result), + ::make_vec1( mv$(node.m_value) ) + )), + mv$(arms) + )); } } }; diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index 874a80a7..e607925e 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -89,13 +89,46 @@ namespace { void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override { m_os << indent() << "trait " << p.get_name() << item.m_params.fmt_args() << "\n"; + if( ! item.m_parent_traits.empty() ) + { + m_os << indent() << " " << ": "; + bool is_first = true; + for(auto& bound : item.m_parent_traits) + { + if( !is_first ) + m_os << indent() << " " << "+ "; + m_os << bound << "\n"; + is_first = false; + } + } if( ! item.m_params.m_bounds.empty() ) { m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; } m_os << indent() << "{\n"; inc_indent(); + + for(auto& i : item.m_types) + { + m_os << indent() << "type " << i.first; + if( ! i.second.m_trait_bounds.empty() ) + { + m_os << ": "; + bool is_first = true; + for(auto& bound : i.second.m_trait_bounds) + { + if( !is_first ) + m_os << " + "; + m_os << bound; + is_first = false; + } + } + //this->visit_type(i.second.m_default); + m_os << ";\n"; + } + ::HIR::Visitor::visit_trait(p, item); + dec_indent(); m_os << indent() << "}\n"; } diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 7d1b05a8..40c872fa 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -902,6 +902,9 @@ namespace { else if( repr_str == "simd" ) { is_simd = true; } + else if( repr_str == "transparent" ) { + // TODO: Mark so the C backend knows that it's supposed to be transparent + } else { TODO(a.span(), "Handle struct repr '" << repr_str << "'"); } @@ -1248,13 +1251,29 @@ namespace { else TU_IFLET(::HIR::TypeRef::Data, arg_self_ty.m_data, Path, e, // Box - Compare with `owned_box` lang item TU_IFLET(::HIR::Path::Data, e.path.m_data, Generic, pe, - if( pe.m_path == g_crate_ptr->get_lang_item_path(sp, "owned_box") ) + auto p = g_crate_ptr->get_lang_item_path_opt("owned_box"); + if( pe.m_path == p ) { if( pe.m_params.m_types.size() == 1 && pe.m_params.m_types[0] == self_type ) { receiver = ::HIR::Function::Receiver::Box; } } + // TODO: for other types, support arbitary structs/paths. + // - The path must include Self as a (the only?) type param. + if( receiver == ::HIR::Function::Receiver::Free ) + { + if( pe.m_params.m_types.size() == 0 ) { + ERROR(sp, E0000, "Unsupported receiver type - " << arg_self_ty); + } + if( pe.m_params.m_types.size() != 1 ) { + TODO(sp, "Receiver types with more than one param - " << arg_self_ty); + } + if( pe.m_params.m_types[0] != self_type ) { + ERROR(sp, E0000, "Unsupported receiver type - " << arg_self_ty); + } + receiver = ::HIR::Function::Receiver::Custom; + } ) ) else { diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 8024e1c0..33200e96 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -8,6 +8,7 @@ * Contains the expanded and desugared AST */ #pragma once +#include <target_version.hpp> #include <cassert> #include <unordered_map> @@ -51,6 +52,7 @@ struct VisEnt /// NOTE: Intentionally minimal, just covers the values (not the types) TAGGED_UNION(Literal, Invalid, (Invalid, struct {}), + (Defer, struct {}), // List = Array, Tuple, struct literal (List, ::std::vector<Literal>), // TODO: Have a variant for repetition lists // Variant = Enum variant @@ -124,6 +126,7 @@ public: //PointerMut, //PointerConst, Box, + Custom, }; typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > args_t; diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 2e03990a..87b790ae 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -168,10 +168,9 @@ void ::HIR::Visitor::visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) this->visit_trait_path(par); } for(auto& i : item.m_types) { + auto item_path = ::HIR::ItemPath(trait_ip, i.first.c_str()); DEBUG("type " << i.first); - for(auto& bound : i.second.m_trait_bounds) - this->visit_trait_path(bound); - this->visit_type(i.second.m_default); + this->visit_associatedtype(item_path, i.second); } for(auto& i : item.m_values) { auto item_path = ::HIR::ItemPath(trait_ip, i.first.c_str()); @@ -234,6 +233,12 @@ void ::HIR::Visitor::visit_union(::HIR::ItemPath p, ::HIR::Union& item) for(auto& var : item.m_variants) this->visit_type(var.second.ent); } +void ::HIR::Visitor::visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item) +{ + for(auto& bound : item.m_trait_bounds) + this->visit_trait_path(bound); + this->visit_type(item.m_default); +} void ::HIR::Visitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item) { this->visit_params(item.m_params); diff --git a/src/hir/visitor.hpp b/src/hir/visitor.hpp index dbf759a4..d432b29d 100644 --- a/src/hir/visitor.hpp +++ b/src/hir/visitor.hpp @@ -33,8 +33,9 @@ public: virtual void visit_type_alias(ItemPath p, ::HIR::TypeAlias& item); virtual void visit_trait(ItemPath p, ::HIR::Trait& item); virtual void visit_struct(ItemPath p, ::HIR::Struct& item); - virtual void visit_union(ItemPath p, ::HIR::Union& item); virtual void visit_enum(ItemPath p, ::HIR::Enum& item); + virtual void visit_union(ItemPath p, ::HIR::Union& item); + virtual void visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item); // - Value Items virtual void visit_function(ItemPath p, ::HIR::Function& item); virtual void visit_static(ItemPath p, ::HIR::Static& item); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index ec313e4a..e1fde1bf 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -16,6 +16,8 @@ #include <trans/target.hpp> #include <hir/expr_state.hpp> +#define CHECK_DEFER(var) do { if( var.is_Defer() ) { m_rv = ::HIR::Literal::make_Defer({}); return ; } } while(0) + namespace { struct NewvalState { const ::HIR::Module& mod; @@ -924,6 +926,7 @@ namespace { ::HIR::Visitor::visit_type(ty); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, + TRACE_FUNCTION_FR(ty, ty); if( e.size_val == ~0u ) { assert(e.size); @@ -970,6 +973,7 @@ namespace { } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { + static Span sp; if( auto* e = item.m_data.opt_Value() ) { ::HIR::TypeRef ty = ::HIR::CoreType::Isize; diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index ffdc0a77..79feea32 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -353,10 +353,10 @@ namespace { { case ::HIR::ExprNode_BinOp::Op::CmpEqu: { langitem = "eq"; method = "eq"; } if(0) case ::HIR::ExprNode_BinOp::Op::CmpNEqu:{ langitem = "eq"; method = "ne"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpLt: { langitem = "ord"; method = "lt"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpLtE: { langitem = "ord"; method = "le"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpGt: { langitem = "ord"; method = "gt"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpGtE: { langitem = "ord"; method = "ge"; } + case ::HIR::ExprNode_BinOp::Op::CmpLt: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "lt"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLtE: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "le"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGt: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "gt"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGtE: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "ge"; } { // 1. Check if the types are valid for primitive comparison if( ty_l == ty_r ) { diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 985fe15f..8a199557 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -208,10 +208,10 @@ namespace { { case ::HIR::ExprNode_BinOp::Op::CmpEqu: item_name = "eq"; break; case ::HIR::ExprNode_BinOp::Op::CmpNEqu: item_name = "eq"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; default: break; } assert(item_name); diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 62f50ed9..825df467 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -890,10 +890,10 @@ namespace { { case ::HIR::ExprNode_BinOp::Op::CmpEqu: item_name = "eq"; break; case ::HIR::ExprNode_BinOp::Op::CmpNEqu: item_name = "eq"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; default: break; } assert(item_name); @@ -2153,8 +2153,8 @@ namespace { } ), (Borrow, - // Check class (must be equal) and type - if( s_e.type != e.type ) { + // Check class (destination must be weaker) and type + if( !(s_e.type >= e.type) ) { ERROR(sp, E0000, "Invalid cast from " << src_ty << " to " << tgt_ty); } const auto& src_inner = this->context.get_type(*s_e.inner); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 22291123..1383300f 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1050,8 +1050,10 @@ bool TraitResolution::iterate_bounds( ::std::function<bool(const ::HIR::GenericB bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function<bool(const ::HIR::TraitPath&)> cb) const { ::HIR::GenericPath trait_path; + DEBUG("Checking ATY bounds on " << pe.trait << " :: " << pe.item); if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, trait_path) ) BUG(sp, "Cannot find associated type " << pe.item << " anywhere in trait " << pe.trait); + DEBUG("trait_path=" << trait_path); const auto& trait_ref = m_crate.get_trait_by_path(sp, trait_path.m_path); const auto& aty_def = trait_ref.m_types.find(pe.item)->second; @@ -1087,7 +1089,8 @@ bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data bool TraitResolution::find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& ty, - t_cb_trait_impl_r callback + t_cb_trait_impl_r callback, + bool magic_trait_impls /*=true*/ ) const { static ::HIR::PathParams null_params; @@ -1108,6 +1111,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& lang_Sized = this->m_crate.get_lang_item_path(sp, "sized"); const auto& lang_Copy = this->m_crate.get_lang_item_path(sp, "copy"); + //const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); const auto& lang_Unsize = this->m_crate.get_lang_item_path(sp, "unsize"); const auto& lang_CoerceUnsized = this->m_crate.get_lang_item_path(sp, "coerce_unsized"); const auto& trait_fn = this->m_crate.get_lang_item_path(sp, "fn"); @@ -1116,23 +1120,37 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& trait_index = this->m_crate.get_lang_item_path(sp, "index"); const auto& trait_indexmut = this->m_crate.get_lang_item_path(sp, "index_mut"); - if( trait == lang_Sized ) { - auto cmp = type_is_sized(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); - } - else { - return false; + if( magic_trait_impls ) + { + if( trait == lang_Sized ) { + auto cmp = type_is_sized(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } - } - if( trait == lang_Copy ) { - auto cmp = this->type_is_copy(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + if( trait == lang_Copy ) { + auto cmp = this->type_is_copy(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } - else { - return false; + + if( TARGETVER_1_29 && trait == this->m_crate.get_lang_item_path(sp, "clone") ) + { + auto cmp = this->type_is_clone(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } } @@ -1361,12 +1379,19 @@ bool TraitResolution::find_trait_impls(const Span& sp, ASSERT_BUG(sp, e.path.m_data.is_UfcsKnown(), "Opaque bound type wasn't UfcsKnown - " << type); const auto& pe = e.path.m_data.as_UfcsKnown(); + // TODO: Should Self here be `type` or `*pe.type` + // - Depends... if implicit it should be `type` (as it relates to the associated type), but if explicit it's referring to the trait auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr); auto rv = this->iterate_aty_bounds(sp, pe, [&](const auto& bound) { + DEBUG("Bound on ATY: " << bound); const auto& b_params = bound.m_path.m_params; ::HIR::PathParams params_mono_o; const auto& b_params_mono = (monomorphise_pathparams_needed(b_params) ? params_mono_o = monomorphise_path_params_with(sp, b_params, monomorph_cb, false) : b_params); + // TODO: Monormophise and EAT associated types + ::std::map< ::std::string, ::HIR::TypeRef> b_atys; + for(const auto& aty : bound.m_type_bounds) + b_atys.insert(::std::make_pair( aty.first, monomorphise_type_with(sp, aty.second, monomorph_cb) )); if( bound.m_path.m_path == trait ) { @@ -1375,13 +1400,15 @@ bool TraitResolution::find_trait_impls(const Span& sp, { if( &b_params_mono == ¶ms_mono_o ) { - if( callback( ImplRef(type.clone(), mv$(params_mono_o), {}), cmp ) ) + // TODO: assoc bounds + if( callback( ImplRef(type.clone(), mv$(params_mono_o), mv$(b_atys)), cmp ) ) return true; params_mono_o = monomorphise_path_params_with(sp, b_params, monomorph_cb, false); } else { - if( callback( ImplRef(&type, &bound.m_path.m_params, &null_assoc), cmp ) ) + //if( callback( ImplRef(&type, &bound.m_path.m_params, &null_assoc), cmp ) ) + if( callback( ImplRef(&type, &bound.m_path.m_params, &b_atys), cmp ) ) return true; } } @@ -1405,53 +1432,56 @@ bool TraitResolution::find_trait_impls(const Span& sp, } ) - // Magic Unsize impls to trait objects - if( trait == lang_Unsize ) + if( magic_trait_impls ) { - ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); - const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); + // Magic Unsize impls to trait objects + if( trait == lang_Unsize ) + { + ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); + const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); - if( find_trait_impls_bound(sp, trait, params, type, callback) ) - return true; + if( find_trait_impls_bound(sp, trait, params, type, callback) ) + return true; - bool rv = false; - auto cb = [&](auto new_dst) { - ::HIR::PathParams real_params { mv$(new_dst) }; - rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); - }; - //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) - //{ - // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); - // return rv; - //} - auto cmp = this->can_unsize(sp, dst_ty, type, cb); - if( cmp == ::HIR::Compare::Equal ) - { - assert(!rv); - rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); + bool rv = false; + auto cb = [&](auto new_dst) { + ::HIR::PathParams real_params { mv$(new_dst) }; + rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); + }; + //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) + //{ + // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); + // return rv; + //} + auto cmp = this->can_unsize(sp, dst_ty, type, cb); + if( cmp == ::HIR::Compare::Equal ) + { + assert(!rv); + rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); + } + return rv; } - return rv; - } - // Magical CoerceUnsized impls for various types - if( trait == lang_CoerceUnsized ) { - const auto& dst_ty = params.m_types.at(0); - // - `*mut T => *const T` - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, - TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, - if( de.type < e.type ) { - auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); - if( cmp != ::HIR::Compare::Unequal ) - { - ::HIR::PathParams pp; - pp.m_types.push_back( dst_ty.clone() ); - if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { - return true; + // Magical CoerceUnsized impls for various types + if( trait == lang_CoerceUnsized ) { + const auto& dst_ty = params.m_types.at(0); + // - `*mut T => *const T` + TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, + TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, + if( de.type < e.type ) { + auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); + if( cmp != ::HIR::Compare::Unequal ) + { + ::HIR::PathParams pp; + pp.m_types.push_back( dst_ty.clone() ); + if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { + return true; + } } } - } + ) ) - ) + } } // 1. Search generic params @@ -2219,12 +2249,14 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple // TODO: A bound can imply something via its associated types. How deep can this go? // E.g. `T: IntoIterator<Item=&u8>` implies `<T as IntoIterator>::IntoIter : Iterator<Item=&u8>` return this->iterate_bounds([&](const auto& b)->bool { + DEBUG(b); if( b.is_TraitBound() ) { const auto& e = b.as_TraitBound(); const auto& b_params = e.trait.m_path.m_params; auto cmp = e.type .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer()); + DEBUG("cmp = " << cmp); if( cmp == ::HIR::Compare::Unequal ) return false; @@ -2780,6 +2812,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, if( ty.m_data.is_Infer() && !ty.m_data.as_Infer().is_lit() ) { return ::HIR::Compare::Fuzzy; } + // If the RHS is an unbound UfcsKnown, also fuzzy + if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound() ) { + return ::HIR::Compare::Fuzzy; + } return ::HIR::Compare::Unequal; } }; @@ -2939,14 +2975,14 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, } namespace { - bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::Function::Receiver& receiver) + bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const ::std::string& name, const ::HIR::Function*& out_fcn_ptr) { auto it = trait_ptr.m_values.find(name); if( it != trait_ptr.m_values.end() ) { if( it->second.is_Function() ) { const auto& v = it->second.as_Function(); - receiver = v.m_receiver; + out_fcn_ptr = &v; return true; } } @@ -2954,27 +2990,30 @@ namespace { } } -bool TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::Function::Receiver& out_receiver, ::HIR::GenericPath& out_path) const +const ::HIR::Function* TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::GenericPath& out_path) const { TRACE_FUNCTION_FR("trait_path=" << trait_path << ",name=" << name, out_path); + const ::HIR::Function* rv = nullptr; - if( trait_contains_method_inner(trait_ptr, name, out_receiver) ) + if( trait_contains_method_inner(trait_ptr, name, rv) ) { + assert(rv); out_path = trait_path.clone(); - return true; + return rv; } auto monomorph_cb = monomorphise_type_get_cb(sp, &self, &trait_path.m_params, nullptr); for(const auto& st : trait_ptr.m_all_parent_traits) { - if( trait_contains_method_inner(*st.m_trait_ptr, name, out_receiver) ) + if( trait_contains_method_inner(*st.m_trait_ptr, name, rv) ) { + assert(rv); out_path.m_path = st.m_path.m_path; out_path.m_params = monomorphise_path_params_with(sp, st.m_path.m_params, monomorph_cb, false); - return true; + return rv; } } - return false; + return nullptr; } bool TraitResolution::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 { @@ -3156,6 +3195,97 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa ) ) } +::HIR::Compare TraitResolution::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const +{ + TRACE_FUNCTION_F(ty); + const auto& type = this->m_ivars.get_type(ty); + const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); + TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e), + ( + // NOTE: Don't use find_trait_impls, because that calls this + bool is_fuzzy = false; + bool has_eq = find_trait_impls(sp, lang_Clone, ::HIR::PathParams{}, ty, [&](auto , auto c)->bool{ + switch(c) + { + case ::HIR::Compare::Equal: return true; + case ::HIR::Compare::Fuzzy: + is_fuzzy = true; + return false; + case ::HIR::Compare::Unequal: + return false; + } + throw ""; + }, false); + if( has_eq ) { + return ::HIR::Compare::Equal; + } + else if( is_fuzzy ) { + return ::HIR::Compare::Fuzzy; + } + else { + return ::HIR::Compare::Unequal; + } + ), + (Infer, + switch(e.ty_class) + { + case ::HIR::InferClass::Integer: + case ::HIR::InferClass::Float: + return ::HIR::Compare::Equal; + default: + DEBUG("Fuzzy Clone impl for ivar?"); + return ::HIR::Compare::Fuzzy; + } + ), + (Generic, + // TODO: Store this result - or even pre-calculate it. + return this->iterate_bounds([&](const auto& b)->bool { + TU_IFLET(::HIR::GenericBound, b, TraitBound, be, + if(be.type == ty) + { + if(be.trait.m_path == lang_Clone) + return true; + ::HIR::PathParams pp; + bool rv = this->find_named_trait_in_trait(sp, + lang_Clone,pp, *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, type, + [&](const auto& , const auto&, const auto&)->bool { return true; } + ); + if(rv) + return true; + } + ) + return false; + }) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ; + ), + (Primitive, + if( e == ::HIR::CoreType::Str ) + return ::HIR::Compare::Unequal; + return ::HIR::Compare::Equal; + ), + (Borrow, + return e.type == ::HIR::BorrowType::Shared ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ; + ), + (Pointer, + return ::HIR::Compare::Equal; + ), + (Tuple, + auto rv = ::HIR::Compare::Equal; + for(const auto& sty : e) + rv &= type_is_clone(sp, sty); + return rv; + ), + (Slice, + return ::HIR::Compare::Unequal; + ), + (Function, + return ::HIR::Compare::Equal; + ), + (Array, + // TODO: Clone here? + return type_is_copy(sp, *e.inner); + ) + ) +} // Checks if a type can unsize to another // - Returns Compare::Equal if the unsize is possible and fully known // - Returns Compare::Fuzzy if the unsize is possible, but still unknown. @@ -3594,9 +3724,9 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, // Checks that a given real receiver type matches a desired receiver type (with the correct access) // Returns the pointer to the `Self` type, or nullptr if there's a mismatch -const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::HIR::Function::Receiver receiver, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const +const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, const ::HIR::Function& fcn, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const { - switch(receiver) + switch(fcn.m_receiver) { case ::HIR::Function::Receiver::Free: // Free functions are never usable @@ -3643,6 +3773,24 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H return &this->m_ivars.get_type(*ty.m_data.as_Borrow().inner); } break; + case ::HIR::Function::Receiver::Custom: + // TODO: Handle custom-receiver functions + // - match_test_generics, if it succeeds return the matched Self + { + const ::HIR::TypeRef* detected_self_ty = nullptr; + auto cb_getself = [&](auto idx, const auto& /*name*/, const auto& ty)->::HIR::Compare{ + if( idx == 0xFFFF ) + { + detected_self_ty = &ty; + } + return ::HIR::Compare::Equal; + }; + if( fcn.m_args.front().second .match_test_generics(sp, ty, this->m_ivars.callback_resolve_infer(), cb_getself) ) { + assert(detected_self_ty); + return detected_self_ty; + } + } + return nullptr; case ::HIR::Function::Receiver::Box: if(const auto* ity = this->type_is_owned_box(sp, ty)) { @@ -3682,16 +3830,18 @@ bool TraitResolution::find_method(const Span& sp, assert(e.trait.m_trait_ptr); // 1. Find the named method in the trait. ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, e.type, method_name, receiver, final_trait_path) ) { + const ::HIR::Function* fcn_ptr; + if( !(fcn_ptr = this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, e.type, method_name, final_trait_path)) ) { DEBUG("- Method '" << method_name << "' missing"); continue ; } DEBUG("- Found trait " << final_trait_path << " (bound)"); // 2. Compare the receiver of the above to this type and the bound. - if(const auto* self_ty = check_method_receiver(sp, receiver, ty, access)) + if(const auto* self_ty = check_method_receiver(sp, *fcn_ptr, ty, access)) { + if( self_ty->m_data.is_Infer() ) + return false; // TODO: Do a fuzzy match here? auto cmp = self_ty->compare_with_placeholders(sp, e.type, cb_infer); if( cmp == ::HIR::Compare::Equal ) @@ -3760,12 +3910,11 @@ bool TraitResolution::find_method(const Span& sp, const auto& trait = this->m_crate.get_trait_by_path(sp, e.m_trait.m_path.m_path); ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( this->trait_contains_method(sp, e.m_trait.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) + if( const auto* fcn_ptr = this->trait_contains_method(sp, e.m_trait.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { DEBUG("- Found trait " << final_trait_path); // - If the receiver is valid, then it's correct (no need to check the type again) - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); rv = true; @@ -3783,12 +3932,11 @@ bool TraitResolution::find_method(const Span& sp, const auto& trait = this->m_crate.get_trait_by_path(sp, trait_path.m_path.m_path); ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( this->trait_contains_method(sp, trait_path.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) + if( const auto* fcn_ptr = this->trait_contains_method(sp, trait_path.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { DEBUG("- Found trait " << final_trait_path); - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); rv = true; @@ -3835,21 +3983,22 @@ bool TraitResolution::find_method(const Span& sp, { ASSERT_BUG(sp, bound.m_trait_ptr, "Pointer to trait " << bound.m_path << " not set in " << e.trait.m_path); ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) - continue ; - DEBUG("- Found trait " << final_trait_path); - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if( const auto* fcn_ptr = this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { - if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { - final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); - DEBUG("- Monomorph to " << final_trait_path); - } + DEBUG("- Found trait " << final_trait_path); - // Found the method, return the UFCS path for it - possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); - rv = true; + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) + { + if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { + final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); + DEBUG("- Monomorph to " << final_trait_path); + } + + // Found the method, return the UFCS path for it + possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + rv = true; + } } } @@ -3873,21 +4022,21 @@ bool TraitResolution::find_method(const Span& sp, // Found such a bound, now to test if it is useful ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) - continue ; - DEBUG("- Found trait " << final_trait_path); - - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if( const auto* fcn_ptr = this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { - if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { - final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); - DEBUG("- Monomorph to " << final_trait_path); - } + DEBUG("- Found trait " << final_trait_path); - // Found the method, return the UFCS path for it - possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); - rv = true; + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) + { + if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { + final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); + DEBUG("- Monomorph to " << final_trait_path); + } + + // Found the method, return the UFCS path for it + possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + rv = true; + } } } } @@ -3907,7 +4056,7 @@ bool TraitResolution::find_method(const Span& sp, if( it == impl.m_methods.end() ) return false ; const ::HIR::Function& fcn = it->second.data; - if( const auto* self_ty_p = this->check_method_receiver(sp, fcn.m_receiver, ty, access) ) + if( const auto* self_ty_p = this->check_method_receiver(sp, fcn, ty, access) ) { DEBUG("Found `impl" << impl.m_params.fmt_args() << " " << impl.m_type << "` fn " << method_name/* << " - " << top_ty*/); if( *self_ty_p == *cur_check_ty ) @@ -3943,12 +4092,12 @@ bool TraitResolution::find_method(const Span& sp, break; ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, *trait_ref.first, *trait_ref.second, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) + const ::HIR::Function* fcn_ptr; + if( !(fcn_ptr = this->trait_contains_method(sp, *trait_ref.first, *trait_ref.second, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path)) ) continue ; DEBUG("- Found trait " << final_trait_path); - if( const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access) ) + if( const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access) ) { const auto& self_ty = *self_ty_p; DEBUG("Search for impl of " << *trait_ref.first << " for " << self_ty); diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index 58688d6e..7868b93f 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -207,7 +207,7 @@ public: typedef ::std::function<bool(ImplRef, ::HIR::Compare)> t_cb_trait_impl_r; /// Searches for a trait impl that matches the provided trait name and type - bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const; + bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback, bool magic_trait_impls=true) const; /// Locate a named trait in the provied trait (either itself or as a parent trait) bool find_named_trait_in_trait(const Span& sp, @@ -262,7 +262,7 @@ public: Move, }; private: - const ::HIR::TypeRef* check_method_receiver(const Span& sp, ::HIR::Function::Receiver receiver, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const; + const ::HIR::TypeRef* check_method_receiver(const Span& sp, const ::HIR::Function& fcn, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const; public: enum class AllowedReceivers { All, @@ -278,11 +278,12 @@ public: ) const; /// Locates a named method in a trait, and returns the path of the trait that contains it (with fixed parameters) - 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, ::HIR::Function::Receiver& out_receiver, ::HIR::GenericPath& out_path) const; + const ::HIR::Function* trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::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; + ::HIR::Compare type_is_clone(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 diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index dddb7731..b38511d1 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -201,13 +201,16 @@ namespace { { while( param_vals.m_types.size() < param_def.m_types.size() ) { unsigned int i = param_vals.m_types.size(); - if( param_def.m_types[i].m_default.m_data.is_Infer() ) { + const auto& ty_def = param_def.m_types[i]; + if( ty_def.m_default.m_data.is_Infer() ) { ERROR(sp, E0000, "Unspecified parameter with no default"); } // Replace and expand - param_vals.m_types.push_back( param_def.m_types[i].m_default.clone() ); + param_vals.m_types.push_back( ty_def.m_default.clone() ); auto& ty = param_vals.m_types.back(); + // TODO: Monomorphise? + // Replace `Self` here with the real Self update_self_type(sp, ty); } @@ -220,7 +223,7 @@ namespace { if( param_vals.m_types[i] == ::HIR::TypeRef() ) { //if( param_def.m_types[i].m_default == ::HIR::TypeRef() ) // ERROR(sp, E0000, "Unspecified parameter with no default"); - // TODO: Monomorph? + // TODO: Monomorphise? param_vals.m_types[i] = param_def.m_types[i].m_default.clone(); update_self_type(sp, param_vals.m_types[i]); } @@ -429,6 +432,16 @@ namespace { } return trait_path_g; } + ::HIR::GenericPath get_current_trait_gp() const + { + assert(m_current_trait_path); + assert(m_current_trait); + auto trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() ); + for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) { + trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) ); + } + return trait_path; + } void visit_path_UfcsUnknown(const Span& sp, ::HIR::Path& p, ::HIR::Visitor::PathContext pc) { TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p); @@ -449,10 +462,7 @@ namespace { // If processing a trait, and the type is 'Self', search for the type/method on the trait // - TODO: This could be encoded by a `Self: Trait` bound in the generics, but that may have knock-on issues? if( te.name == "Self" && m_current_trait ) { - auto trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() ); - for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) { - trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) ); - } + auto trait_path = this->get_current_trait_gp(); if( this->locate_in_trait_and_set(sp, pc, trait_path, *m_current_trait, p.m_data) ) { // Success! return ; @@ -616,6 +626,17 @@ namespace { auto _ = m_resolve.set_item_generics(item.m_params); ::HIR::Visitor::visit_enum(p, item); } + void visit_associatedtype(::HIR::ItemPath p, ::HIR::AssociatedType& item) + { + // Push `Self = <Self as CurTrait>::Type` for processing defaults in the bounds. + auto path_aty = ::HIR::Path( ::HIR::TypeRef("Self", 0xFFFF), this->get_current_trait_gp(), p.get_name() ); + auto ty_aty = ::HIR::TypeRef::new_path( mv$(path_aty), ::HIR::TypeRef::TypePathBinding::make_Opaque({}) ); + m_self_types.push_back(&ty_aty); + + ::HIR::Visitor::visit_associatedtype(p, item); + + m_self_types.pop_back(); + } void visit_type_impl(::HIR::TypeImpl& impl) override { diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 8000f5af..84c73bfb 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -104,6 +104,14 @@ bool StaticTraitResolve::find_impl( return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); } } + else if( TARGETVER_1_29 && trait_path == m_lang_Clone ) { + if( type.m_data.is_Tuple() || type.m_data.is_Array() || type.m_data.is_Function() ) + { + if( this->type_is_clone(sp, type) ) { + return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); + } + } + } else if( trait_path == m_lang_Sized ) { if( this->type_is_sized(sp, type) ) { return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); @@ -118,6 +126,16 @@ bool StaticTraitResolve::find_impl( } } + if(const auto* e = type.m_data.opt_Generic() ) + { + if( (e->binding >> 8) == 2 ) + { + // TODO: If the type is a magic placeholder, assume it impls the specified trait. + // TODO: Restructure so this knows that the placehlder impls the impl-provided bounds. + return found_cb( ImplRef(&type, trait_params, &null_assoc), false ); + } + } + // --- MAGIC IMPLS --- // TODO: There should be quite a few more here, but laziness TU_IFLET(::HIR::TypeRef::Data, type.m_data, Function, e, @@ -556,6 +574,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( if( placeholders.size() == 0 ) placeholders.resize(impl_params.size()); placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i); + DEBUG("Placeholder " << placeholders[i] << " for " << impl_params_def.m_types[i].m_name); } } // Callback that matches placeholders to concrete types @@ -571,6 +590,9 @@ bool StaticTraitResolve::find_impl__check_crate_raw( ph = ty.clone(); return ::HIR::Compare::Equal; } + else if( ph == ty ) { + return ::HIR::Compare::Equal; + } else { TODO(sp, "[find_impl__check_crate_raw:cb_match] Compare placeholder " << i << " " << ph << " == " << ty); } @@ -1379,6 +1401,10 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) return true; ), (Closure, + if( TARGETVER_1_29 ) + { + // TODO: Auto-gerated impls + } return false; ), (Infer, @@ -1430,6 +1456,94 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) ) throw ""; } +bool StaticTraitResolve::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const +{ + if( !TARGETVER_1_29 ) BUG(sp, "Calling type_is_clone when not in 1.29 mode"); + + TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e), + (Generic, + { + auto it = m_clone_cache.find(ty); + if( it != m_clone_cache.end() ) + { + return it->second; + } + } + bool rv = this->iterate_bounds([&](const auto& b)->bool { + auto pp = ::HIR::PathParams(); + return this->find_impl__check_bound(sp, m_lang_Clone, &pp, ty, [&](auto , bool ){ return true; }, b); + }); + m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); + return rv; + ), + (Path, + { + auto it = m_clone_cache.find(ty); + if( it != m_clone_cache.end() ) + return it->second; + } + auto pp = ::HIR::PathParams(); + bool rv = this->find_impl(sp, m_lang_Clone, &pp, ty, [&](auto , bool){ return true; }, true); + m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); + return rv; + ), + (Diverge, + // The ! type is kinda Copy/Clone ... + return true; + ), + (Closure, + // TODO: Auto-gerated impls + return false; + ), + (Infer, + // Shouldn't be hit + return false; + ), + (Borrow, + // Only shared &-ptrs are copy/clone + return (e.type == ::HIR::BorrowType::Shared); + ), + (Pointer, + // All raw pointers are Copy/Clone + return true; + ), + (Function, + // All function pointers are Copy/Clone + return true; + ), + (Primitive, + // All primitives (except the unsized `str`) are Copy/Clone + return e != ::HIR::CoreType::Str; + ), + (Array, + return e.size_val == 0 || type_is_clone(sp, *e.inner); + ), + (Slice, + // [T] isn't Sized, so isn't Copy ether + return false; + ), + (TraitObject, + // (Trait) isn't Sized, so isn't Copy ether + return false; + ), + (ErasedType, + for(const auto& trait : e.m_traits) + { + if( find_named_trait_in_trait(sp, m_lang_Clone, {}, *trait.m_trait_ptr, trait.m_path.m_path, trait.m_path.m_params, ty, [](const auto&, auto ){ }) ) { + return true; + } + } + return false; + ), + (Tuple, + for(const auto& ty : e) + if( !type_is_clone(sp, ty) ) + return false; + return true; + ) + ) + throw ""; +} bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const { diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index 8c9cb9a6..ae429a3f 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -23,6 +23,7 @@ public: ::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities; ::HIR::SimplePath m_lang_Copy; + ::HIR::SimplePath m_lang_Clone; // 1.29 ::HIR::SimplePath m_lang_Drop; ::HIR::SimplePath m_lang_Sized; ::HIR::SimplePath m_lang_Unsize; @@ -34,6 +35,7 @@ public: private: mutable ::std::map< ::HIR::TypeRef, bool > m_copy_cache; + mutable ::std::map< ::HIR::TypeRef, bool > m_clone_cache; public: StaticTraitResolve(const ::HIR::Crate& crate): @@ -42,6 +44,8 @@ public: m_item_generics(nullptr) { m_lang_Copy = m_crate.get_lang_item_path_opt("copy"); + if( TARGETVER_1_29 ) + m_lang_Clone = m_crate.get_lang_item_path_opt("clone"); m_lang_Drop = m_crate.get_lang_item_path_opt("drop"); m_lang_Sized = m_crate.get_lang_item_path_opt("sized"); m_lang_Unsize = m_crate.get_lang_item_path_opt("unsize"); @@ -178,6 +182,7 @@ public: // Common bounds // ------------- bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; + bool type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const; // 1.29 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; diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp index c9e573d4..8085eb4c 100644 --- a/src/include/main_bindings.hpp +++ b/src/include/main_bindings.hpp @@ -18,6 +18,7 @@ namespace AST { /// Parse a crate from the given file extern AST::Crate Parse_Crate(::std::string mainfile); +extern void Expand_Init(); extern void Expand(::AST::Crate& crate); extern void Expand_TestHarness(::AST::Crate& crate); extern void Expand_ProcMacro(::AST::Crate& crate); diff --git a/src/include/target_version.hpp b/src/include/target_version.hpp new file mode 100644 index 00000000..dddf69e4 --- /dev/null +++ b/src/include/target_version.hpp @@ -0,0 +1,11 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * include/target_version.hpp + * - mrustc target lanuage version definitions + */ +#pragma once + +#define TARGETVER_1_19 true +#define TARGETVER_1_29 true diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index a393ba46..cda51ebe 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -1189,7 +1189,8 @@ namespace } if(lex.consume_if(TOK_AT)) continue; - if( lex.consume_if(TOK_TRIPLE_DOT) ) + // ... or ..= + if( lex.consume_if(TOK_TRIPLE_DOT) || lex.consume_if(TOK_DOUBLE_DOT_EQUAL) ) { switch(lex.next()) { @@ -1491,6 +1492,7 @@ namespace case TOK_DOUBLE_AMP: case TOK_DOUBLE_PIPE: case TOK_DOUBLE_DOT: + case TOK_DOUBLE_DOT_EQUAL: case TOK_TRIPLE_DOT: lex.consume(); break; diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index b3b1014e..00cf7cf7 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -49,8 +49,7 @@ public: switch( GET_TOK(tok, lex) ) { // TODO: Allow any reserved word - case TOK_RWORD_TYPE: - case TOK_RWORD_PUB: + case TOK_RWORD_PUB ... TOK_RWORD_UNSIZED: case TOK_IDENT: { ::std::string name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok); GET_CHECK_TOK(tok, lex, TOK_COLON); @@ -200,10 +199,13 @@ public: default: throw ParseError::Unexpected(lex, tok); } - + } + else if( tok.type() == TOK_RWORD_CRATE ) + { + ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) ); } //else if( tok.type() == TOK_IDENT || tok_is_rword(tok.type()) ) - else if( tok.type() == TOK_IDENT || tok.type() == TOK_RWORD_TYPE || tok.type() == TOK_RWORD_PUB ) + else if( tok.type() == TOK_IDENT || tok.type() >= TOK_RWORD_PUB ) { // Look up the named parameter in the list of param names for this arm auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok); @@ -222,10 +224,6 @@ public: } ret.push_back( MacroExpansionEnt(idx) ); } - else if( tok.type() == TOK_RWORD_CRATE ) - { - ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) ); - } else { throw ParseError::Unexpected(lex, tok); diff --git a/src/main.cpp b/src/main.cpp index 2dd05a05..7130cf1c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -222,6 +222,8 @@ int main(int argc, char *argv[]) Cfg_SetFlag("test"); } + Expand_Init(); + try { // Parse the crate into AST @@ -654,6 +656,11 @@ int main(int argc, char *argv[]) } throw ::std::runtime_error("Invalid crate_type value"); }); + // - Generate automatic impls (mainly Clone for 1.29) + CompilePhaseV("Trans Auto Impls", [&]() { + // TODO: Drop glue generation? + Trans_AutoImpls(*hir_crate, items); + }); // - Generate monomorphised versions of all functions CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); }); // - Do post-monomorph inlining diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 5a629233..6a96ab64 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1810,6 +1810,14 @@ namespace { mv$(values) })); } + if( fcn.m_abi == "platform-intrinsic" ) + { + m_builder.end_block(::MIR::Terminator::make_Call({ + next_block, panic_block, + res.clone(), ::MIR::CallTarget::make_Intrinsic({ "platform:"+gpath.m_path.m_components.back(), gpath.m_params.clone() }), + mv$(values) + })); + } // 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") ) diff --git a/src/mir/mir_ptr.hpp b/src/mir/mir_ptr.hpp index 9133dd44..27dd6b22 100644 --- a/src/mir/mir_ptr.hpp +++ b/src/mir/mir_ptr.hpp @@ -7,7 +7,6 @@ */ #pragma once - namespace MIR { class Function; @@ -32,10 +31,10 @@ public: void reset(); - ::MIR::Function* operator->() { return ptr; } - ::MIR::Function& operator*() { return *ptr; } - const ::MIR::Function* operator->() const { return ptr; } - const ::MIR::Function& operator*() const { return *ptr; } + ::MIR::Function* operator->() { if(!ptr) throw ""; return ptr; } + const ::MIR::Function* operator->() const { if(!ptr) throw ""; return ptr; } + ::MIR::Function& operator*() { if(!ptr) throw ""; return *ptr; } + const ::MIR::Function& operator*() const { if(!ptr) throw ""; return *ptr; } operator bool() const { return ptr != nullptr; } }; diff --git a/src/parse/eTokenType.enum.h b/src/parse/eTokenType.enum.h index 5104142b..4408c45a 100644 --- a/src/parse/eTokenType.enum.h +++ b/src/parse/eTokenType.enum.h @@ -58,6 +58,7 @@ _(TOK_SLASH) _(TOK_DOT) _(TOK_DOUBLE_DOT) +_(TOK_DOUBLE_DOT_EQUAL) _(TOK_TRIPLE_DOT) _(TOK_EQUAL) diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 5194e1d8..e5d7981d 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -706,7 +706,7 @@ ExprNodeP Parse_Expr1_1(TokenStream& lex) ExprNodeP left, right; // Inclusive range to a value - if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) { + if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT || (TARGETVER_1_29 && tok.type() == TOK_DOUBLE_DOT_EQUAL) ) { right = next(lex); return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, nullptr, mv$(right) ); } @@ -746,6 +746,13 @@ LEFTASSOC(Parse_Expr1_2, Parse_Expr1_5, case TOK_TRIPLE_DOT: rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) ); break; + case TOK_DOUBLE_DOT_EQUAL: + if( TARGETVER_1_29 ) + { + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) ); + break; + } + // Fall through ) // 1: Bool OR LEFTASSOC(Parse_Expr1_5, Parse_Expr2, diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index 8376eeee..0b145379 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -83,8 +83,10 @@ static const struct { TOKENT("-=", TOK_DASH_EQUAL), TOKENT("->", TOK_THINARROW), TOKENT(".", TOK_DOT), + // NOTE: These have special handling when following numbers TOKENT("..", TOK_DOUBLE_DOT), TOKENT("...",TOK_TRIPLE_DOT), + TOKENT("..=",TOK_DOUBLE_DOT_EQUAL), TOKENT("/" , TOK_SLASH), TOKENT("/*", BLOCKCOMMENT), TOKENT("//", LINECOMMENT), @@ -402,9 +404,13 @@ Token Lexer::getTokenInt() // Double/Triple Dot if( ch == '.' ) { - if( this->getc() == '.') { + ch = this->getc(); + if( ch == '.') { this->m_next_tokens.push_back(TOK_TRIPLE_DOT); } + else if( ch == '=') { + this->m_next_tokens.push_back(TOK_DOUBLE_DOT_EQUAL); + } else { this->ungetc(); this->m_next_tokens.push_back(TOK_DOUBLE_DOT); diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp index f6d61728..239bac80 100644 --- a/src/parse/pattern.cpp +++ b/src/parse/pattern.cpp @@ -113,6 +113,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) break; // Known value `IDENT ...` case TOK_TRIPLE_DOT: + case TOK_DOUBLE_DOT_EQUAL: break; // Known binding `ident @` case TOK_AT: @@ -156,7 +157,9 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable) } auto ps = lex.start_span(); AST::Pattern ret = Parse_PatternReal1(lex, is_refutable); - if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) + if( (GET_TOK(tok, lex) == TOK_TRIPLE_DOT) + || (TARGETVER_1_29 && tok.type() == TOK_DOUBLE_DOT_EQUAL) + ) { if( !ret.data().is_Value() ) throw ParseError::Generic(lex, "Using '...' with a non-value on left"); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 68ad570b..ef1fb439 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -18,6 +18,7 @@ #include <expand/cfg.hpp> // check_cfg - for `mod nonexistant;` #include <fstream> // Used by directory path #include "lex.hpp" // New file lexer +#include <parse/interpolated_fragment.hpp> #include <ast/expr.hpp> template<typename T> @@ -649,9 +650,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items // TODO: Just add these as `where Self: <foo>` (would that break typecheck?) do { if( GET_TOK(tok, lex) == TOK_LIFETIME ) { - // TODO: Need a better way of indiciating 'static than just an invalid path - ASSERT_BUG(lex.point_span(), tok.str() == "static", "TODO: Support lifetimes other than 'static in trait bounds"); - supertraits.push_back( make_spanned( Span(tok.get_pos()), Type_TraitPath{ {}, AST::Path() } ) ); + params.add_bound(::AST::GenericBound::make_TypeLifetime({ TypeRef(lex.point_span(), "Self"), ::AST::LifetimeRef(lex.get_ident(tok)) })); } else if( tok.type() == TOK_BRACE_OPEN ) { break; @@ -988,14 +987,26 @@ AST::Attribute Parse_MetaItem(TokenStream& lex) { TRACE_FUNCTION; Token tok; - GET_TOK(tok, lex); - if( tok.type() == TOK_INTERPOLATED_META ) { + if( lex.lookahead(0) == TOK_INTERPOLATED_META ) { + GET_TOK(tok, lex); return mv$(tok.frag_meta()); } auto ps = lex.start_span(); - CHECK_TOK(tok, TOK_IDENT); + GET_TOK(tok, lex); + + switch(tok.type()) + { + case TOK_IDENT: + break; + case TOK_INTEGER: + if( TARGETVER_1_29 ) + return AST::Attribute(lex.end_span(ps), "", tok.to_str()); + default: + throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_INTEGER}); + } + ::std::string name = mv$(tok.str()); switch(GET_TOK(tok, lex)) { @@ -1006,6 +1017,10 @@ AST::Attribute Parse_MetaItem(TokenStream& lex) return AST::Attribute(lex.end_span(ps), name, tok.str()); case TOK_INTERPOLATED_EXPR: { auto n = tok.take_frag_node(); + void Expand_BareExpr(const AST::Crate& , const AST::Module&, ::std::unique_ptr<AST::ExprNode>& n); + assert( lex.parse_state().crate ); + assert( lex.parse_state().module ); + Expand_BareExpr(*lex.parse_state().crate, *lex.parse_state().module, n); if( auto* v = dynamic_cast<::AST::ExprNode_String*>(&*n) ) { return AST::Attribute(lex.end_span(ps), name, mv$(v->m_value)); @@ -1013,9 +1028,15 @@ AST::Attribute Parse_MetaItem(TokenStream& lex) else { // - Force an error. - CHECK_TOK(tok, TOK_STRING); + throw ParseError::Unexpected(lex, Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())), TOK_STRING); } break; } + case TOK_INTEGER: + if( TARGETVER_1_29 ) + return AST::Attribute(lex.end_span(ps), name, tok.to_str()); + case TOK_IDENT: + if( TARGETVER_1_29 ) + return AST::Attribute(lex.end_span(ps), name, tok.to_str()); default: // - Force an error. CHECK_TOK(tok, TOK_STRING); @@ -1311,8 +1332,19 @@ void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_ break ; } else { - CHECK_TOK(tok, TOK_IDENT); - path = base_path + AST::PathNode(tok.str(), {}); + path = ::AST::Path(base_path); + + while(1) + { + CHECK_TOK(tok, TOK_IDENT); + path += AST::PathNode(tok.str(), {}); + if( !TARGETVER_1_29 ) + break; + if( lex.lookahead(0) != TOK_DOUBLE_COLON ) + break; + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); + GET_TOK(tok, lex); + } name = mv$(tok.str()); } @@ -1706,6 +1738,19 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) } return ::AST::Named< ::AST::Item> { "", mv$(impl), false }; } + // `unsafe auto trait` + case TOK_IDENT: + if( TARGETVER_1_29 && tok.str() == "auto" ) { + GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + auto tr = Parse_TraitDef(lex, meta_items); + tr.set_is_unsafe(); + tr.set_is_marker(); + item_data = ::AST::Item( ::std::move(tr) ); + break; + } + //goto default; default: throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL}); } @@ -1742,6 +1787,15 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) item_name = mv$(tok.str()); item_data = ::AST::Item( Parse_Union(lex, meta_items) ); } + // `auto trait` + else if( TARGETVER_1_29 && tok.str() == "auto" ) { + GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + auto tr = Parse_TraitDef(lex, meta_items); + tr.set_is_marker(); + item_data = ::AST::Item( ::std::move(tr) ); + } else { throw ParseError::Unexpected(lex, tok); } @@ -1959,6 +2013,7 @@ AST::Crate Parse_Crate(::std::string mainfile) crate.root_module().m_file_info.path = mainpath; crate.root_module().m_file_info.controls_dir = true; + lex.parse_state().crate = &crate; Parse_ModRoot(lex, crate.root_module(), crate.m_attrs); return crate; diff --git a/src/parse/token.cpp b/src/parse/token.cpp index 115df135..f1471453 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -359,8 +359,9 @@ struct EscapedString { case TOK_SLASH: return "/"; case TOK_DOT: return "."; - case TOK_DOUBLE_DOT: return "..."; - case TOK_TRIPLE_DOT: return ".."; + case TOK_DOUBLE_DOT: return ".."; + case TOK_DOUBLE_DOT_EQUAL: return "..="; + case TOK_TRIPLE_DOT: return "..."; case TOK_EQUAL: return "="; case TOK_PLUS_EQUAL: return "+="; @@ -484,13 +485,13 @@ struct EscapedString { os << ":" << *reinterpret_cast<AST::Path*>(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_EXPR: - os << ":" << *reinterpret_cast<AST::ExprNode*>(tok.m_data.as_Fragment()); + os << ":" << *reinterpret_cast<const AST::ExprNode*>(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_STMT: - os << ":" << *reinterpret_cast<AST::ExprNode*>(tok.m_data.as_Fragment()); + os << ":" << *reinterpret_cast<const AST::ExprNode*>(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_BLOCK: - os << ":" << *reinterpret_cast<AST::ExprNode*>(tok.m_data.as_Fragment()); + os << ":" << *reinterpret_cast<const AST::ExprNode*>(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_META: os << ":" << *reinterpret_cast<AST::Attribute*>(tok.m_data.as_Fragment()); diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp index a9d325c2..25b6a3c1 100644 --- a/src/parse/tokenstream.hpp +++ b/src/parse/tokenstream.hpp @@ -16,6 +16,7 @@ namespace AST { class Module; + class Crate; class AttributeList; } @@ -27,6 +28,7 @@ struct ParseState // A debugging hook that disables expansion of macros bool no_expand_macros = false; + const ::AST::Crate* crate = nullptr; ::AST::Module* module = nullptr; ::AST::AttributeList* parent_attrs = nullptr; diff --git a/src/parse/types.cpp b/src/parse/types.cpp index a07e66f8..db66a77e 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -15,6 +15,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list); TypeRef Parse_Type_Fn(TokenStream& lex, AST::HigherRankedBounds hrbs = {}); TypeRef Parse_Type_Path(TokenStream& lex, AST::HigherRankedBounds hrbs, bool allow_trait_list); +TypeRef Parse_Type_TraitObject(TokenStream& lex, ::AST::HigherRankedBounds hrbs = {}); TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list); // === CODE === @@ -84,6 +85,10 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) // TODO: path macros return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex)); } + if( TARGETVER_1_29 && tok.str() == "dyn" ) + { + return Parse_Type_TraitObject(lex, {}); + } // or a primitive //if( auto ct = coretype_fromstring(tok.str()) ) //{ @@ -311,6 +316,37 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool a } } } +TypeRef Parse_Type_TraitObject(TokenStream& lex, ::AST::HigherRankedBounds hrbs) +{ + Token tok; + auto ps = lex.start_span(); + + ::std::vector<Type_TraitPath> traits; + ::std::vector<AST::LifetimeRef> lifetimes; + + traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); + + while( lex.lookahead(0) == TOK_PLUS ) + { + GET_CHECK_TOK(tok, lex, TOK_PLUS); + if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { + GET_TOK(tok, lex); + lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) )); + } + else + { + if( lex.lookahead(0) == TOK_RWORD_FOR ) + { + hrbs = Parse_HRB(lex); + } + traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); + } + } + + if( lifetimes.empty()) + lifetimes.push_back(AST::LifetimeRef()); + return TypeRef(lex.end_span(ps), mv$(traits), mv$(lifetimes)); +} TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list) { Token tok; diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp new file mode 100644 index 00000000..334d9eae --- /dev/null +++ b/src/trans/auto_impls.cpp @@ -0,0 +1,130 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * trans/auto_impls.cpp + * - Automatic trait/method impls + * + * Handles implementing Clone (when in 1.29 mode) + */ +#include "main_bindings.hpp" +#include "trans_list.hpp" +#include <hir/hir.hpp> +#include <mir/mir.hpp> +#include <hir_typeck/common.hpp> // monomorph +#include <hir_typeck/static.hpp> // StaticTraitResolve +#include <deque> +#include <algorithm> // find_if + +namespace { + struct State + { + ::HIR::Crate& crate; + StaticTraitResolve resolve; + const TransList& trans_list; + ::std::deque<::HIR::TypeRef> todo_list; + ::std::set<::HIR::TypeRef> done_list; + + ::HIR::SimplePath lang_Clone; + + State(::HIR::Crate& crate, const TransList& trans_list): + crate(crate), + resolve( crate ), + trans_list(trans_list) + { + lang_Clone = crate.get_lang_item_path(Span(), "clone"); + } + + void enqueue_type(const ::HIR::TypeRef& ty) { + if( this->trans_list.auto_clone_impls.count(ty) == 0 && this->done_list.count(ty) == 0 ) { + this->done_list.insert( ty.clone() ); + this->todo_list.push_back( ty.clone() ); + } + } + }; +} + +void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) +{ + Span sp; + TRACE_FUNCTION_F(ty); + + // Create MIR + ::MIR::Function mir_fcn; + if( state.resolve.type_is_copy(sp, ty) ) + { + ::MIR::BasicBlock bb; + bb.statements.push_back(::MIR::Statement::make_Assign({ + ::MIR::LValue::make_Return({}), + ::MIR::RValue::make_Use( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) }) ) + })); + bb.terminator = ::MIR::Terminator::make_Return({}); + mir_fcn.blocks.push_back(::std::move( bb )); + } + else + { + TODO(Span(), "auto Clone for " << ty << " - Not Copy"); + } + + // Function + ::HIR::Function fcn { + /*m_save_code=*/false, + ::HIR::Linkage {}, + ::HIR::Function::Receiver::BorrowShared, + /*m_abi=*/ABI_RUST, + /*m_unsafe =*/false, + /*m_const=*/false, + ::HIR::GenericParams {}, + /*m_args=*/::make_vec1(::std::make_pair( + ::HIR::Pattern( ::HIR::PatternBinding(false, ::HIR::PatternBinding::Type::Move, "self", 0), ::HIR::Pattern::Data::make_Any({}) ), + ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()) + )), + /*m_variadic=*/false, + /*m_return=*/ty.clone(), + ::HIR::ExprPtr {} + }; + fcn.m_code.m_mir = ::MIR::FunctionPointer( new ::MIR::Function(mv$(mir_fcn)) ); + + // Impl + ::HIR::TraitImpl impl; + impl.m_type = mv$(ty); + impl.m_methods.insert(::std::make_pair( ::std::string("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } )); + + // Add impl to the crate + state.crate.m_trait_impls.insert(::std::make_pair( state.lang_Clone, ::std::move(impl) )); +} + +void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list) +{ + State state { crate, trans_list }; + + // Generate for all + for(const auto& ty : trans_list.auto_clone_impls) + { + state.done_list.insert( ty.clone() ); + Trans_AutoImpl_Clone(state, ty.clone()); + } + + while( !state.todo_list.empty() ) + { + auto ty = ::std::move(state.todo_list.front()); + state.todo_list.pop_back(); + + Trans_AutoImpl_Clone(state, mv$(ty)); + } + + const auto impl_range = crate.m_trait_impls.equal_range( state.lang_Clone ); + for(const auto& ty : state.done_list) + { + // TODO: Find a way of turning a set into a vector so items can be erased. + + auto p = ::HIR::Path(ty.clone(), ::HIR::GenericPath(state.lang_Clone), "clone"); + //DEBUG("add_function(" << p << ")"); + auto e = trans_list.add_function(::std::move(p)); + + auto it = ::std::find_if( impl_range.first, impl_range.second, [&](const auto& i){ return i.second.m_type == ty; }); + assert( it->second.m_methods.size() == 1 ); + e->ptr = &it->second.m_methods.begin()->second.data; + } +} + diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 0ced3150..86bbdddc 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -308,6 +308,18 @@ namespace { << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" << "}\n" ; + // Atomic hackery + for(int sz = 8; sz <= 64; sz *= 2) + { + m_of + << "static inline uint"<<sz<<"_t __mrustc_atomicloop"<<sz<<"(volatile uint"<<sz<<"_t* slot, uint"<<sz<<"_t param, int ordering, uint"<<sz<<"_t (*cb)(uint"<<sz<<"_t, uint"<<sz<<"_t)) {" + << " for(;;) {" + << " uint"<<sz<<"_t v = atomic_load_explicit((_Atomic uint"<<sz<<"_t*)slot, ordering);" + << " if( atomic_compare_exchange_strong_explicit((_Atomic uint"<<sz<<"_t*)slot, &v, cb(v, param), ordering, ordering) ) return v;" + << " }" + << "}\n" + ; + } break; case Compiler::Msvc: m_of @@ -564,7 +576,32 @@ namespace { << "\t}\n" << "\treturn SIZE_MAX;\n" << "}\n" + // Map of reversed nibbles 0 1 2 3 4 5 6 7 8 9 10 11 12 14 15 + << "static const uint8_t __mrustc_revmap[16] = { 0, 8, 4,12, 2,10, 6,14, 1, 9, 5,13, 3, 7,15};\n" + << "static inline uint8_t __mrustc_bitrev8(uint8_t v) { if(v==0||v==0xFF) return v; uint8_t rv = __mrustc_revmap[v>>4]|(__mrustc_revmap[v&15]<<4); }\n" + << "static inline uint16_t __mrustc_bitrev16(uint16_t v) { if(v==0) return 0; uint16_t rv = ((uint16_t)__mrustc_bitrev8(v>>8))|((uint16_t)__mrustc_bitrev8(v)<<8); }\n" + << "static inline uint32_t __mrustc_bitrev32(uint32_t v) { if(v==0) return 0; uint32_t rv = ((uint32_t)__mrustc_bitrev16(v>>16))|((uint32_t)__mrustc_bitrev16(v)<<16); }\n" + << "static inline uint64_t __mrustc_bitrev64(uint64_t v) { if(v==0) return 0; uint64_t rv = ((uint64_t)__mrustc_bitrev32(v>>32))|((uint64_t)__mrustc_bitrev32(v)<<32); }\n" + // TODO: 128 ; + if( m_options.emulated_i128 ) + { + m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { uint128_t rv = { __mrustc_bitrev64(v>>64)), __mrustc_bitrev64(v) }; return rv; }\n"; + } + else + { + m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { if(v==0) return 0; uint128_t rv = ((uint128_t)__mrustc_bitrev64(v>>64))|((uint128_t)__mrustc_bitrev64(v)<<64); }\n"; + } + for(int sz = 8; sz <= 64; sz *= 2) + { + m_of + << "static inline uint"<<sz<<"_t __mrustc_op_umax"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return (a > b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_umin"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return (a < b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_imax"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ((int"<<sz<<"_t)a > (int"<<sz<<"_t)b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_imin"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ((int"<<sz<<"_t)a < (int"<<sz<<"_t)b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_and_not"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ~(a & b); }\n" + ; + } } ~CodeGenerator_C() {} @@ -4209,8 +4246,8 @@ namespace { emit_lvalue(e.ret_val); m_of << ".META = " << s.size() << ""; } else if( name == "transmute" ) { - const auto& ty_dst = params.m_types.at(0); - const auto& ty_src = params.m_types.at(1); + const auto& ty_src = params.m_types.at(0); + const auto& ty_dst = params.m_types.at(1); auto is_ptr = [](const ::HIR::TypeRef& ty){ return ty.m_data.is_Borrow() || ty.m_data.is_Pointer(); }; if( this->type_is_bad_zst(ty_dst) ) { @@ -4218,7 +4255,7 @@ namespace { } else if( e.args.at(0).is_Constant() ) { - m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << ";"; + m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << "; "; m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &v, sizeof("; emit_ctype(ty_dst); m_of << ")); "; m_of << "}"; } @@ -4250,7 +4287,7 @@ namespace { } else { - m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(params.m_types.at(0)); m_of << "))"; + m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(ty_src); m_of << "))"; } } else if( name == "copy_nonoverlapping" || name == "copy" ) { @@ -4410,6 +4447,22 @@ namespace { m_of << "("; emit_param(e.args.at(0)); m_of << ")"; } } + else if( name == "bitreverse" ) { + const auto& ty = params.m_types.at(0); + MIR_ASSERT(mir_res, ty.m_data.is_Primitive(), "Invalid type passed to bitreverse. Must be a primitive, got " << ty); + emit_lvalue(e.ret_val); m_of << " = "; + switch(get_prim_size(ty)) + { + case 8: m_of << "__mrustc_bitrev8"; break; + case 16: m_of << "__mrustc_bitrev16"; break; + case 32: m_of << "__mrustc_bitrev32"; break; + case 64: m_of << "__mrustc_bitrev64"; break; + case 128: m_of << "__mrustc_bitrev128"; break; + default: + MIR_TODO(mir_res, "bswap<" << ty << ">"); + } + m_of << "("; emit_param(e.args.at(0)); m_of << ")"; + } // > Obtain the discriminane of a &T as u64 else if( name == "discriminant_value" ) { const auto& ty = params.m_types.at(0); @@ -4616,7 +4669,8 @@ namespace { } } // Unchecked Arithmatic - else if( name == "unchecked_div" ) { + // - exact_div is UB to call on a non-multiple + else if( name == "unchecked_div" || name == "exact_div") { emit_lvalue(e.ret_val); m_of << " = "; if( type_is_emulated_i128(params.m_types.at(0)) ) { @@ -4689,7 +4743,7 @@ namespace { // Bit Twiddling // - CounT Leading Zeroes // - CounT Trailing Zeroes - else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" ) { + else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" || name == "cttz_nonzero" ) { auto emit_arg0 = [&](){ emit_param(e.args.at(0)); }; const auto& ty = params.m_types.at(0); emit_lvalue(e.ret_val); m_of << " = ("; @@ -4821,6 +4875,11 @@ namespace { else if( name == "volatile_store" ) { m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1)); } + else if( name == "nontemporal_store" ) { + // TODO: Actually do a non-temporal store + // GCC: _mm_stream_* (depending on input type, which must be `repr(simd)`) + m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1)); + } // --- Atomics! // > Single-ordering atomics else if( name == "atomic_xadd" || name.compare(0, 7+4+1, "atomic_xadd_") == 0 ) { @@ -4835,6 +4894,13 @@ namespace { auto ordering = get_atomic_ordering(name, 7+3+1); emit_atomic_arith(AtomicOp::And, ordering); } + else if( name == "atomic_nand" || name.compare(0, 7+4+1, "atomic_nand_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+4+1); + const auto& ty = params.m_types.at(0); + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_and_not" << get_prim_size(ty); + m_of << ")"; + } else if( name == "atomic_or" || name.compare(0, 7+2+1, "atomic_or_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+2+1); emit_atomic_arith(AtomicOp::Or, ordering); @@ -4843,6 +4909,24 @@ namespace { auto ordering = get_atomic_ordering(name, 7+3+1); emit_atomic_arith(AtomicOp::Xor, ordering); } + else if( name == "atomic_max" || name.compare(0, 7+3+1, "atomic_max_") == 0 + || name == "atomic_min" || name.compare(0, 7+3+1, "atomic_min_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+3+1); + const auto& ty = params.m_types.at(0); + const char* op = (name[7+1] == 'a' ? "imax" : "imin"); // m'a'x vs m'i'n + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); + m_of << ")"; + } + else if( name == "atomic_umax" || name.compare(0, 7+4+1, "atomic_umax_") == 0 + || name == "atomic_umin" || name.compare(0, 7+4+1, "atomic_umin_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+4+1); + const auto& ty = params.m_types.at(0); + const char* op = (name[7+2] == 'a' ? "umax" : "umin"); // m'a'x vs m'i'n + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); + m_of << ")"; + } else if( name == "atomic_load" || name.compare(0, 7+4+1, "atomic_load_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+4+1); emit_lvalue(e.ret_val); m_of << " = "; @@ -4953,6 +5037,11 @@ namespace { else if( name == "atomic_singlethreadfence" || name.compare(0, 7+18, "atomic_singlethreadfence_") == 0 ) { // TODO: Does this matter? } + // -- Platform Intrinsics -- + else if( name.compare(0, 9, "platform:") == 0 ) { + // TODO: Platform intrinsics + m_of << "abort() /* TODO: Platform intrinsic \"" << name << "\" */"; + } else { MIR_BUG(mir_res, "Unknown intrinsic '" << name << "'"); } @@ -5518,10 +5607,16 @@ namespace { // TODO: This should have been eliminated? ("MIR Cleanup" should have removed all inline Const references) ::HIR::TypeRef ty; const auto& lit = get_literal_for_const(c.p, ty); - if(lit.is_Integer() || lit.is_Float() || lit.is_String()) + if(lit.is_Integer() || lit.is_Float()) { emit_literal(ty, lit, {}); } + else if( lit.is_String()) + { + m_of << "make_sliceptr("; + this->print_escaped_string( lit.as_String() ); + m_of << ", " << ::std::dec << lit.as_String().size() << ")"; + } else { // NOTE: GCC hack - statement expressions diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 4e04ddf9..e16f9dcf 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1209,7 +1209,7 @@ namespace { DEBUG("[get_ent_fullpath] Found " << impl_ref); //ASSERT_BUG(sp, !is_fuzz, "Fuzzy match not allowed here"); if( ! impl_ref.m_data.is_TraitImpl() ) { - DEBUG("Trans impl search found an invalid impl type"); + DEBUG("Trans impl search found an invalid impl type - " << impl_ref.m_data.tag_str()); is_dynamic = true; // TODO: This can only really happen if it's a trait object magic impl, which should become a vtable lookup. return true; @@ -1380,6 +1380,14 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co { // Must have been a dynamic dispatch request, just leave as-is } + // <* as Clone>::clone + else if( TARGETVER_1_29 && path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().trait == state.crate.get_lang_item_path_opt("clone") ) + { + const auto& pe = path_mono.m_data.as_UfcsKnown(); + ASSERT_BUG(sp, pe.item == "clone", ""); + // Add this type to a list of types that will have the impl auto-generated + state.rv.auto_clone_impls.insert( pe.type->clone() ); + } else { BUG(sp, "AutoGenerate returned for unknown path type - " << path_mono); @@ -1692,4 +1700,3 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Static& item, Trans out_stat.ptr = &item; out_stat.pp = mv$(pp); } - diff --git a/src/trans/main_bindings.hpp b/src/trans/main_bindings.hpp index b938e8bf..096efe86 100644 --- a/src/trans/main_bindings.hpp +++ b/src/trans/main_bindings.hpp @@ -38,6 +38,8 @@ extern TransList Trans_Enumerate_Public(::HIR::Crate& crate); /// Re-run enumeration on monomorphised functions, removing now-unused items extern void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list); +extern void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list); + extern void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list); extern void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, bool is_executable); diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp index 48274f87..51e8af4b 100644 --- a/src/trans/trans_list.hpp +++ b/src/trans/trans_list.hpp @@ -52,6 +52,10 @@ struct TransList_Function Trans_Params pp; // If `pp.has_types` is true, the below is valid CachedFunction monomorphised; + + TransList_Function(): + ptr(nullptr) + {} }; struct TransList_Static { @@ -75,6 +79,8 @@ public: ::std::set< ::HIR::TypeRef> m_typeids; /// Required struct/enum constructor impls ::std::set< ::HIR::GenericPath> m_constructors; + // Automatic Clone impls + ::std::set< ::HIR::TypeRef> auto_clone_impls; // .second is `true` if this is a from a reference to the type ::std::vector< ::std::pair<::HIR::TypeRef, bool> > m_types; |