summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.hpp4
-rw-r--r--src/ast/attrs.hpp1
-rw-r--r--src/ast/path.hpp4
-rw-r--r--src/expand/assert.cpp89
-rw-r--r--src/expand/file_line.cpp9
-rw-r--r--src/expand/lang_item.cpp42
-rw-r--r--src/expand/mod.cpp44
-rw-r--r--src/hir/dump.cpp33
-rw-r--r--src/hir/from_ast.cpp21
-rw-r--r--src/hir/hir.hpp3
-rw-r--r--src/hir/visitor.cpp11
-rw-r--r--src/hir/visitor.hpp3
-rw-r--r--src/hir_conv/constant_evaluation.cpp4
-rw-r--r--src/hir_expand/ufcs_everything.cpp8
-rw-r--r--src/hir_typeck/expr_check.cpp8
-rw-r--r--src/hir_typeck/expr_cs.cpp12
-rw-r--r--src/hir_typeck/helpers.cpp357
-rw-r--r--src/hir_typeck/helpers.hpp7
-rw-r--r--src/hir_typeck/outer.cpp35
-rw-r--r--src/hir_typeck/static.cpp114
-rw-r--r--src/hir_typeck/static.hpp5
-rw-r--r--src/include/main_bindings.hpp1
-rw-r--r--src/include/target_version.hpp11
-rw-r--r--src/macro_rules/eval.cpp4
-rw-r--r--src/macro_rules/parse.cpp14
-rw-r--r--src/main.cpp7
-rw-r--r--src/mir/from_hir.cpp8
-rw-r--r--src/mir/mir_ptr.hpp9
-rw-r--r--src/parse/eTokenType.enum.h1
-rw-r--r--src/parse/expr.cpp9
-rw-r--r--src/parse/lex.cpp8
-rw-r--r--src/parse/pattern.cpp5
-rw-r--r--src/parse/root.cpp73
-rw-r--r--src/parse/token.cpp11
-rw-r--r--src/parse/tokenstream.hpp2
-rw-r--r--src/parse/types.cpp36
-rw-r--r--src/trans/auto_impls.cpp130
-rw-r--r--src/trans/codegen_c.cpp109
-rw-r--r--src/trans/enumerate.cpp11
-rw-r--r--src/trans/main_bindings.hpp2
-rw-r--r--src/trans/trans_list.hpp6
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 == &params_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;